source: trunk/src/cppbase/bs_config.cpp@ 249

Last change on this file since 249 was 249, checked in by umoeller, 23 years ago

Build updates, moved files from warpin.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 75.2 KB
Line 
1
2/*
3 *@@sourcefile bs_config.cpp:
4 * this has the code for the classes which manipulate CONFIG.SYS,
5 * the WPS class list, create WPS objects, or do other
6 * WarpIN system configuration.
7 *
8 * These classes are designed to work independently of WarpIN
9 * and could be used in any program.
10 * I have attempted to design these classes for easy, yet flexible use.
11 *
12 * All system config classes are derived from BSConfigBase.
13 * This allows for maintaining a list of all system changes
14 * with each WarpIN package, which have a somewhat uniform
15 * interface. Each config class has in turn a special method
16 * which will actually perform the system configuration change.
17 *
18 * This special method will usually take a logger instance
19 * as a parameter, which logs the changes that were actually
20 * made to the system. This logger can then be used later to
21 * undo the change.
22 * See BSCfgSysManip::BSCfgSysManip for an example usage.
23 *
24 * The loggers are all direct, unmodified descendants of the
25 * BSMemLoggerBase class (bs_logger.cpp) and only defined to
26 * use C++ type checking.
27 *
28 * Some config methods throw instances of the BSConfigExcpt
29 * class def'd in bs_config.h, which you should handle.
30 *
31 * These are the classes implemented here:
32 *
33 * -- BSCfgSysManip:
34 * a "manipulator" object of this class holds information
35 * for a CONFIG.SYS change, which is passed to BSConfigSys::Manipulate.
36 * See BSCfgSysManip::BSCfgSysManip for a description.
37 *
38 * -- BSConfigSys:
39 * the actual class which holds the CONFIG.SYS text file
40 * and allows changes to be made.
41 * This class does not have a corresponding "Undo" class.
42 * Instead, use BSCfgSysManip::AddToUndoList.
43 *
44 * -- BSRegisterClass:
45 * this allows registering classes with the WPS.
46 * See BSRegisterClass::Register for an example usage.
47 *
48 * -- BSDeregisterClass:
49 * the "Undo" class to the previous.
50 *
51 * -- BSReplaceClass:
52 * this allows WPS classes to be replaced.
53 * See BSReplaceClass::Replace for an example usage.
54 *
55 * -- BSUnreplaceClass:
56 * the "Undo" class to the previous.
57 *
58 * -- BSCreateWPSObject:
59 * for creating a WPS object.
60 *
61 * -- BSDeleteWPSObject:
62 * the "Undo" class for the previous, to delete a WPS object again.
63 *
64 * See bs_config.h for the declarations of these classes.
65 *
66 *@@header "base\bs_config.h"
67 *@@header "base\bs_config_impl.h"
68 */
69
70/*
71 * This file Copyright (C) 1999-2001 Ulrich M”ller.
72 * This program is free software; you can redistribute it and/or modify
73 * it under the terms of the GNU General Public License as published by
74 * the Free Software Foundation, in version 2 as it comes in the COPYING
75 * file of this distribution.
76 * This program is distributed in the hope that it will be useful,
77 * but WITHOUT ANY WARRANTY; without even the implied warranty of
78 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
79 * GNU General Public License for more details.
80 */
81
82#define OS2EMX_PLAIN_CHAR
83 // this is needed for "os2emx.h"; if this is defined,
84 // emx will define PSZ as _signed_ char, otherwise
85 // as unsigned char
86
87#define INCL_DOSSEMAPHORES
88#define INCL_DOSERRORS
89#define INCL_WINWINDOWMGR
90#define INCL_WINMESSAGEMGR
91#define INCL_WINDIALOGS
92#define INCL_WINSTDCNR
93#define INCL_WININPUT
94#define INCL_WINSYS
95#define INCL_WINSHELLDATA
96#define INCL_WINWORKPLACE
97#include <os2.h>
98
99#include <stdio.h>
100#include <stdlib.h>
101#include <string.h>
102#include <stdarg.h>
103
104#include "setup.h"
105
106// include's from helpers
107#include "helpers\dosh.h"
108#include "helpers\winh.h"
109#include "helpers\prfh.h"
110#include "helpers\stringh.h"
111#include "helpers\xstring.h"
112
113#include "helpers\configsys.h"
114
115// front-end includes
116#include "cppbase\bs_base.h"
117#include "cppbase\bs_list.h"
118#include "cppbase\bs_string.h"
119#include "cppbase\bs_errors.h"
120
121#include "cppbase\bs_logger.h"
122#include "cppbase\bs_config.h"
123#include "cppbase\bs_config_impl.h"
124
125#pragma hdrstop
126
127DEFINE_CLASS(BSConfigBase, BSRoot);
128
129DEFINE_CLASS(BSCfgSysManip, BSConfigBase);
130DEFINE_CLASS(BSConfigSys, BSRoot);
131DEFINE_CLASS(BSRegisterClass, BSConfigBase);
132DEFINE_CLASS(BSDeregisterClass, BSConfigBase);
133DEFINE_CLASS(BSReplaceClassBase, BSConfigBase);
134 DEFINE_CLASS(BSReplaceClass, BSReplaceClassBase);
135 DEFINE_CLASS(BSUnreplaceClass, BSReplaceClassBase);
136DEFINE_CLASS(BSCreateWPSObject, BSConfigBase);
137DEFINE_CLASS(BSDeleteWPSObject, BSConfigBase);
138DEFINE_CLASS(BSProfileBase, BSConfigBase);
139 DEFINE_CLASS(BSClearProfile, BSProfileBase);
140 DEFINE_CLASS(BSWriteProfile, BSProfileBase);
141DEFINE_CLASS(BSExecute, BSConfigBase);
142 DEFINE_CLASS(BSDeExecute, BSExecute);
143DEFINE_CLASS(BSKillProcess, BSConfigBase);
144
145 #define CONVERT(c, s) string str ## s(c, _ustr ## s); \
146 PCSZ pcsz ## s = str ## s.c_str()
147
148/* ******************************************************************
149 *
150 * BSCfgSysManip class
151 *
152 ********************************************************************/
153
154/*
155 *@@ BSCfgSysManip(char* pszConfigSys):
156 * this constructor translates a CONFIGSYS attribute (as used
157 * in the PCK tag and stored in the database) into a CONFIGSYSITEM
158 * structure.
159 *
160 * The BSCfgSysManip class is designed for use with the
161 * BSConfigSys class and describes manipulations to be done upon
162 * the CONFIG.SYS file (represented by the BSConfigSys class).
163 *
164 * Manipulating CONFIG.SYS works just as follows:
165 *
166 * 1) Create an instance of BSConfigSys:
167 *
168 + BSConfigSys *pConfigSys = new BSConfigSys;
169 *
170 * This will load your CONFIG.SYS file into the instance's memory.
171 *
172 * 2) Create an instance of BSCfgSysManip and specify the manipulation
173 * in the constructor:
174 *
175 + BSCfgSysManip *pManip = new BSCfgSysManip("SET TEST=YES | UNIQUE");
176 *
177 * The BSCfgSysManip class has a single constructor which takes a PSZ
178 * (char*) as input. This input string has exactly the format like
179 * with the CONFIGSYS attribute to the PCK tag in WarpIN installation
180 * scripts, like this (see the WarpIN Programmer's Reference for details):
181 *
182 + statement [| modifiers]
183 *
184 * "modifiers" can be one of the following:
185 + [UNIQUE[(xxx)]] [vertical]
186 + ADDRIGHT [vertical]
187 + ADDLEFT [vertical]
188 + REMOVELINE
189 + REMOVEPART
190 * with "xxx" being a search string.
191 *
192 * "vertical" can be one of the following:
193 + ADDTOP
194 + ADDAFTER(xxx)
195 + ADDBEFORE(xxx)
196 * with "xxx" being a search string.
197 *
198 * Examples:
199 + "BASEDEV=NEWDRIVR.SYS /WHATEVER | UNIQUE ADDAFTER(IBM1S506.ADD)"
200 + "SET PATH=C:\BLAH | ADDRIGHT"
201 *
202 * After this constructor has successfully converted pszConfigSys,
203 * all the instance data is valid (see cfgsys.h).
204 *
205 * However, this does _not_ handle macro resultion like in WarpIn
206 * scripts (which is done in warpin.cpp before calling the Manipulate
207 * method), because in this file scope we know nothing about the
208 * PackageInfo instances.
209 *
210 * 3) Create a CfgSysDone logger instance:
211 + BSCfgSysDoneLogger logger;
212 *
213 * 4) Invoke the BSConfigSys::Manipulate method with the BSCfgSysManip
214 * instance (this will add data to the logger):
215 + pConfigSys->Manipulate(logger, pManip);
216 *
217 * 5) Write CONFIG.SYS back to disk and clean up.
218 + pConfigSys->Flush(TRUE);
219 + delete pBSCfgSysManip;
220 + delete pConfigSys;
221 *
222 * Now, if you want to undo the changes later, call the static
223 * BSCfgSysManip::AddToUndoList method with the logger passed to
224 * to the various constructor calls (above), which will create
225 * a list of BSCfgSysManip instance which will be able to undo
226 * the changes again:
227 *
228 + list<BSCfgSysManip*> UndoList;
229 + BSCfgSysManip::AddToUndoList(UndoList, logger);
230 *
231 * and iterate over the list and call BSConfigSys::Manipulate with
232 * the objects on that list to undo the changes.
233 *
234 * Throws:
235 * -- BSConfigExcpt.
236 *
237 *@@changed V0.9.1 (2000-01-06) [umoeller]: added UNIQUE(xxx) support
238 *@@changed V0.9.5 (2000-08-26) [umoeller]: fixed UNIQUE(xxx) and REMOVELINE, which deleted wrong lines
239 */
240
241BSCfgSysManip::BSCfgSysManip(const ustring &ustrConfigSys)
242 : BSConfigBase(CFGT_CFGSYS, tBSCfgSysManip)
243{
244 PCSZ pcszConfigSys;
245
246 if (!(pcszConfigSys = ustrConfigSys.GetBuffer()))
247 throw BSConfigExcpt(CFGEXCPT_SYNTAX, 0);
248
249 // initialize all fields to zero
250 // memset(&_ConfigManip, 0, sizeof(_ConfigManip));
251 // V0.9.12 (2001-05-22) [umoeller]
252
253 // now check if we have modifiers
254 PSZ pSep;
255 if (!(pSep = strchr(pcszConfigSys, '|')))
256 // no modifiers: just copy
257 _ustrNewLine = ustrConfigSys;
258 else
259 {
260 // we do have modifiers:
261 BOOL fVerticalsAllowed = TRUE;
262
263 // get rid of spaces before '|'
264 PSZ pSep2 = pSep-1;
265 while (*pSep2 == ' ')
266 pSep2--;
267
268 // get the "statement" part
269 _ustrNewLine.assignUtf8(pcszConfigSys, pSep2 + 1);
270
271 // remember the modifiers position
272 PSZ pModifiers = pSep + 1;
273 BOOL fReplaceModeFound = FALSE;
274 // now check for the replace mode;
275 // the default is 0 (CFGRPL_ADD)
276 _iReplaceMode = CFGRPL_ADD;
277 fVerticalsAllowed = TRUE;
278
279 PSZ pszUnique;
280 if ((pszUnique = strhistr(pModifiers, "UNIQUE")))
281 {
282 _iReplaceMode = CFGRPL_UNIQUE;
283 fVerticalsAllowed = TRUE;
284 fReplaceModeFound = TRUE; // block future replacement modifiers
285
286 // check if we have a "UNIQUE(xxx)" syntax
287 PSZ psz;
288 if (psz = strhExtract(pszUnique, '(', ')', NULL))
289 {
290 // if found, this extracts the stuff between ( and );
291 // if not, this returns NULL
292 _ustrUniqueSearchString2.assignUtf8(psz);
293 free(psz);
294 }
295 }
296 if (strhistr(pModifiers, "ADDRIGHT"))
297 {
298 if (!fReplaceModeFound)
299 {
300 _iReplaceMode = CFGRPL_ADDRIGHT;
301 fVerticalsAllowed = TRUE;
302 fReplaceModeFound = TRUE; // block future replacement modifiers
303 }
304 else
305 {
306 // double replace mode found:
307 throw BSConfigExcpt(CFGEXCPT_DOUBLEREPLACEMODE,
308 ustrConfigSys);
309 }
310 }
311 if (strhistr(pModifiers, "ADDLEFT"))
312 {
313 if (!fReplaceModeFound)
314 {
315 _iReplaceMode = CFGRPL_ADDLEFT;
316 fVerticalsAllowed = TRUE;
317 fReplaceModeFound = TRUE; // block future replacement modifiers
318 }
319 else
320 // double replace mode found:
321 throw BSConfigExcpt(CFGEXCPT_DOUBLEREPLACEMODE,
322 ustrConfigSys);
323 }
324 if (strhistr(pModifiers, "REMOVELINE"))
325 {
326 if (!fReplaceModeFound)
327 {
328 _iReplaceMode = CFGRPL_REMOVELINE;
329 fVerticalsAllowed = FALSE;
330 fReplaceModeFound = TRUE; // block future replacement modifiers
331
332 // check also for stuff after "="
333 PSZ p;
334 if (p = strchr(_ustrNewLine.GetBuffer(), '='))
335 _ustrUniqueSearchString2.assignUtf8(p + 1);
336 }
337 else
338 // double replace mode found:
339 throw BSConfigExcpt(CFGEXCPT_DOUBLEREPLACEMODE,
340 ustrConfigSys);
341 }
342 if (strhistr(pModifiers, "REMOVEPART"))
343 {
344 if (!fReplaceModeFound)
345 {
346 _iReplaceMode = CFGRPL_REMOVEPART;
347 fVerticalsAllowed = FALSE;
348 fReplaceModeFound = TRUE;
349 }
350 else
351 // double replace mode found:
352 throw BSConfigExcpt(CFGEXCPT_DOUBLEREPLACEMODE,
353 ustrConfigSys);
354 }
355
356 // now parse vertical modifiers
357 _iVertical = CFGVRT_BOTTOM; // default
358 BOOL fVerticalFound = FALSE;
359 if (strhistr(pModifiers, "ADDTOP"))
360 {
361 _iVertical = CFGVRT_TOP;
362 fVerticalFound = TRUE;
363 }
364 PSZ p2;
365 if ((p2 = strhistr(pModifiers, "ADDAFTER(")))
366 {
367 if (!fVerticalFound)
368 {
369 PSZ pEndOfSearch;
370 if (!(pEndOfSearch = strchr(p2, ')')))
371 {
372 ustring ustr;
373 ustr.assignUtf8(p2);
374 throw BSConfigExcpt(CFGEXCPT_INVALIDSEARCH, ustr);
375 }
376
377 _ustrVerticalSearchString.assignUtf8(
378 p2 + 9, // strlen("ADDAFTER(")
379 pEndOfSearch); // excluding that char
380
381 _iVertical = CFGVRT_AFTER;
382 fVerticalFound = TRUE;
383 }
384 else
385 {
386 ustring ustr;
387 ustr.assignUtf8(p2);
388 throw BSConfigExcpt(CFGEXCPT_INVALIDVERTICAL, ustr);
389 }
390 }
391 if ((p2 = strhistr(pModifiers, "ADDBEFORE(")))
392 {
393 if (!fVerticalFound)
394 {
395 PSZ pEndOfSearch;
396 if (!(pEndOfSearch = strchr(p2, ')')))
397 {
398 ustring ustr;
399 ustr.assignUtf8(p2);
400 throw BSConfigExcpt(CFGEXCPT_INVALIDSEARCH, ustr);
401 }
402
403 _ustrVerticalSearchString.assignUtf8(p2 + 10, // strlen("ADDBEFORE(")
404 pEndOfSearch); // excluding that char
405
406 _iVertical = CFGVRT_BEFORE;
407 fVerticalFound = TRUE;
408 }
409 else
410 {
411 ustring ustr;
412 ustr.assignUtf8(p2);
413 throw BSConfigExcpt(CFGEXCPT_INVALIDVERTICAL, ustr);
414 }
415 }
416
417 // finally check if vertical modifier is allowed at all
418 if ( (fVerticalFound) && (!fVerticalsAllowed) )
419 throw BSConfigExcpt(CFGEXCPT_INVALIDVERTICAL, ustrConfigSys);
420
421 } // end elseif (!pSep)
422}
423
424/*
425 *@@ DescribeType:
426 * describes the current manipulator type to the GUI.
427 *
428 *@@added V0.9.2 (2000-02-19) [umoeller]
429 */
430
431const char* BSCfgSysManip::DescribeType()
432{
433 return ("CONFIG.SYS manipulation");
434}
435
436/*
437 *@@ DescribeData:
438 * describes the current manipulator data to the GUI.
439 *
440 *@@added V0.9.2 (2000-02-19) [umoeller]
441 *@@changed V0.9.5 (2000-08-26) [umoeller]: UNIQUE wasn't reported right
442 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
443 */
444
445ustring BSCfgSysManip::DescribeData()
446{
447 ustring str;
448 BOOL fAddSpace = TRUE;
449
450 switch (_iReplaceMode)
451 {
452 case CFGRPL_UNIQUE:
453 str.appendUtf8("UNIQUE");
454 if (_ustrUniqueSearchString2())
455 {
456 str.appendUtf8("(");
457 str.append(_ustrUniqueSearchString2);
458 str.appendUtf8(")");
459 }
460 break;
461
462 case CFGRPL_ADDLEFT: str.appendUtf8("ADDLEFT"); break;
463 case CFGRPL_ADDRIGHT: str.appendUtf8("ADDRIGHT"); break;
464 case CFGRPL_REMOVELINE: str.appendUtf8("REMOVELINE"); break;
465 case CFGRPL_REMOVEPART: str.appendUtf8("REMOVEPART"); break;
466
467 default:
468 fAddSpace = FALSE;
469 break;
470 }
471
472 if (fAddSpace)
473 str.appendUtf8(" ");
474
475 switch (_iVertical)
476 {
477 case CFGVRT_TOP: str.appendUtf8("ADDTOP "); break;
478
479 case CFGVRT_BEFORE:
480 str.appendUtf8("BEFORE(");
481 str.append(_ustrVerticalSearchString);
482 str.appendUtf8(") ");
483 break;
484
485 case CFGVRT_AFTER:
486 str.appendUtf8("AFTER ");
487 str.append(_ustrVerticalSearchString);
488 str.appendUtf8(") ");
489 break;
490 }
491
492 str.append(_ustrNewLine);
493
494 return (str);
495}
496
497/*
498 *@@ AddToUndoList:
499 * static helper method to create BSCfgSysManip
500 * instances from the logger instance that was
501 * previously used with BSConfigSys::Manipulate.
502 *
503 * The new BSCfgSysManip objects are appended to
504 * the specified list and are exact opposites
505 * to the BSCfgSysManip objects that were stored
506 * in the logger. That is, if the logger registered
507 * that something was added to CONFIG.SYS, we
508 * create an object which removes that text again,
509 * and vice versa.
510 *
511 * Use this method to undo CONFIG.SYS changes
512 * and pass the objects on the list to BSConfigSys::Manipulate,
513 * since there is no corresponding "undo" class
514 * for BSConfigSys.
515 *
516 * See BSCfgSysManip::BSCfgSysManip for an example usage.
517 *
518 * This returns the number of items created.
519 *
520 * Throws:
521 * -- BSConfigExcpt.
522 */
523
524int BSCfgSysManip::AddToUndoList(list<BSConfigBase*> &List,
525 BSCfgSysDoneLogger &logger)
526{
527 // the logger in this case has a list of special PSZs,
528 // where the first three characters of each entry
529 // signify to us what was changed in CONFIG.SYS
530
531 PSZ pszLogStart = logger._pabLogString,
532 pszLogThis = pszLogStart;
533 int iCount = 0;
534
535 while (pszLogThis < pszLogStart + logger._cbLogString)
536 {
537 ULONG cbLogThis = strlen(pszLogThis);
538 string strNewModifiers;
539
540 // now check what we have in the log; the
541 // first three characters (followed by a
542 // space) signify what happened:
543 // -- "DLL": deleted line
544 // -- "DLP": deleted part of line
545 // -- "NWL": added an all new line
546 // -- "NWP": added a new part to an existing line
547
548 if (memicmp(pszLogThis, "DLL ", 4) == 0)
549 {
550 // line was deleted: re-insert that line (UNIQUE mode)
551 // strNewModifiers = "UNIQUE";
552 }
553 else if (memicmp(pszLogThis, "DLP ", 4) == 0)
554 {
555 // part of line was deleted: re-insert that line (ADDRIGHT mode)
556 strNewModifiers = "ADDRIGHT";
557 }
558 else if (memicmp(pszLogThis, "NWL ", 4) == 0)
559 {
560 // line was added: remove that whole line
561 strNewModifiers = "REMOVELINE";
562 // #### no, no, no!!! this removes an entire line...
563 }
564 else if (memicmp(pszLogThis, "NWP ", 4) == 0)
565 // part of line was added: remove that part
566 strNewModifiers = "REMOVEPART";
567 else
568 {
569 // none of the above: error
570 ustring ustr;
571 ustr.assignUtf8(pszLogThis);
572 throw BSConfigExcpt(CFGEXCPT_PARSELOG, ustr);
573 }
574
575 // something found: compose attribute string for manipulator
576 PSZ pszNewAttrs = (PSZ)malloc(strlen(pszLogThis)
577 + strNewModifiers.size()
578 + 30);
579 sprintf(pszNewAttrs, "%s | %s",
580 pszLogThis + 4, // stuff after "DLL " or whatever
581 strNewModifiers.c_str());
582
583 // add the undo manipulator to the _front_ of the
584 // list so that items are undone in reverse order
585 // (because if a line was replaced originally,
586 // we first have a "delete line" and then an
587 // "add line" entry in the log)
588 ustring ustr;
589 ustr.assignUtf8(pszNewAttrs);
590 List.push_front(new BSCfgSysManip(ustr));
591 free(pszNewAttrs);
592
593 pszLogThis += cbLogThis + 1; // go beyond null byte
594 iCount++;
595 }
596
597 return (iCount);
598}
599
600/* ******************************************************************
601 *
602 * BSConfigSys class
603 *
604 ********************************************************************/
605
606/*
607 *@@ BSConfigSys:
608 * the constructor, which loads the current CONFIG.SYS
609 * file from OS/2 boot drive into instance memory.
610 *
611 * Throws:
612 * -- BSConfigExcpt.
613 *
614 *@@changed V0.9.7 (2001-01-15) [umoeller]: now using csysLoadConfigSys
615 */
616
617BSConfigSys::BSConfigSys() : BSRoot(tBSConfigSys)
618{
619 _pszContent = NULL;
620
621 /* sprintf(_szFilename, "%c:\\config.sys", doshQueryBootDrive());
622 // now read CONFIG.SYS file to initialize the dlg items
623 APIRET arc = doshLoadTextFile(_szFilename, &_pszContent); */
624
625 APIRET arc = csysLoadConfigSys(NULL, // default CONFIG.SYS
626 &_pszContent);
627
628 if (arc != NO_ERROR)
629 throw BSConfigExcpt(CFGEXCPT_OPEN, arc);
630
631 _fDirty = FALSE;
632}
633
634/*
635 *@@ ~ConfigSys:
636 * the destructor.
637 *
638 * This does _not_ write the file. Use BSConfigSys::Flush()
639 * before deleting an instance of this.
640 */
641
642BSConfigSys::~BSConfigSys()
643{
644 if (_pszContent)
645 free(_pszContent);
646}
647
648/*
649 *@@ Manipulate:
650 * this monster method changes the data in our memory copy of
651 * CONFIG.SYS according to the BSCfgSysManip object, which you must
652 * have created before. See BSCfgSysManip::BSCfgSysManip for a
653 * description of this usage.
654 *
655 * This also takes a BSCfgSysDoneLogger as input where all the
656 * changes made to the CONFIG.SYS memory copy are logged. This
657 * logger can then be passed to BSConfigSys::Undo to have the
658 * changes undone again.
659 *
660 * Call BSConfigSys::Flush to have CONFIG.SYS written back to disk.
661 *
662 * Returns NO_ERROR if everything was OK or an error code.
663 *
664 *@@changed V0.9.18 (2002-03-08) [umoeller]: adjusted for Unicode; added codec
665 */
666
667int BSConfigSys::Manipulate(BSUniCodec &codecProcess, // in: codec for process codepage
668 BSCfgSysManip &Manip, // in: manipulator object
669 BSCfgSysDoneLogger *pLogger, // in: logger object to append items to (can be NULL)
670 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
671{
672 int irc = 0;
673
674 XSTRING strLogger;
675 xstrInit(&strLogger, 0);
676
677 CONFIGMANIP cm;
678 memset(&cm, 0, sizeof(cm));
679
680 cm.iReplaceMode = Manip._iReplaceMode;
681
682 string strUniqueSearchString2(&codecProcess, Manip._ustrUniqueSearchString2);
683 cm.pszUniqueSearchString2 = strUniqueSearchString2.c_str();
684
685 cm.iVertical = Manip._iVertical;
686
687 string strVerticalSearchString(&codecProcess, Manip._ustrVerticalSearchString);
688 cm.pszVerticalSearchString = strVerticalSearchString.c_str();
689
690 string strNewLine(&codecProcess, Manip._ustrNewLine);
691 cm.pszNewLine = strNewLine.c_str();
692
693 irc = csysManipulate(&_pszContent,
694 &cm,
695 &_fDirty,
696 &strLogger);
697
698 // now parse the logger...
699 if (strLogger.ulLength)
700 {
701 // something to be logged:
702 PSZ p = strLogger.psz;
703
704 while (p)
705 {
706 PSZ pEOL;
707 if ( (pEOL = strhFindEOL(p, NULL))
708 && (*pEOL)
709 )
710 {
711 string strTemp(p, pEOL);
712
713 if (strTemp())
714 {
715 if (pLogFile)
716 // write to log file
717 pLogFile->Write("Updated CONFIG.SYS: \"%s\"",
718 strTemp.c_str());
719
720 if (pLogger)
721 {
722 // write to "done" logger:
723 ustring ustr(&codecProcess, strTemp);
724 pLogger->Append(ustr);
725 }
726 }
727 else
728 break;
729
730 p = pEOL + 1;
731 }
732 else
733 break;
734 }
735 }
736
737 xstrClear(&strLogger);
738
739 return (irc);
740}
741
742/*
743 *@@ Flush:
744 * this rewrites the CONFIG.SYS file on disk with the
745 * data we have in memory.
746 *
747 * This makes a backup copy in "CONFIG.003" style if
748 * (pszBackup != NULL). See doshCreateBackupFileName
749 * for details.
750 *
751 * Returns:
752 *
753 * -- 0: contents were dirty, written back to disk.
754 *
755 * -- 1: no error, but contents were clean, so no write-back
756 * was needed.
757 *
758 * Throws:
759 * -- BSConfigExcpt(CFGEXCPT_WRITE, APIRET).
760 *
761 *@@changed V0.9.3 (2000-05-03) [umoeller]: added more error checking
762 *@@changed V0.9.3 (2000-05-12) [umoeller]: added pszBackup
763 *@@changed V0.9.6 (2000-10-27) [umoeller]: added check if contents are dirty
764 */
765
766int BSConfigSys::Flush(string *pstrBackup, // in/out: create backup?
767 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
768 const
769{
770 int irc = 0;
771
772 if (_fDirty)
773 {
774 PSZ pszBackup = NULL;
775 CHAR szBackup[CCHMAXPATH];
776 if (pstrBackup)
777 pszBackup = szBackup;
778
779 APIRET arc = csysWriteConfigSys(NULL, // default _szFilename,
780 _pszContent,
781 pszBackup); // create backup
782
783 if (arc)
784 {
785 if (pLogFile)
786 pLogFile->Write("Error %d occured writing CONFIG.SYS back to disk",
787 arc);
788
789 throw BSConfigExcpt(CFGEXCPT_WRITE, arc);
790 }
791
792 if (pLogFile)
793 pLogFile->Write("CONFIG.SYS file written back to disk, backup is \"%s\"",
794 pszBackup);
795
796 if (pstrBackup)
797 pstrBackup->assign(szBackup);
798 }
799 else
800 irc = 1;
801
802 return (irc);
803}
804
805/* ******************************************************************
806 *
807 * BSRegisterClass class
808 *
809 ********************************************************************/
810
811/*
812 *@@ BSRegisterClass:
813 * this constructor translates a REGISTERCLASS attribute (as used
814 * in the PCK tag and stored in the database) into the BSRegisterClass
815 * instance data.
816 *
817 * Syntax:
818 *
819 + REGISTERCLASS="classname|dllpath"
820 *
821 * Throws:
822 * -- BSConfigExcpt.
823 */
824
825BSRegisterClass::BSRegisterClass(const ustring &ustrRegisterClass)
826 : BSConfigBase(CFGT_REGISTERCLASS, tBSRegisterClass)
827{
828 // find separator
829 PCSZ pcszRegisterClass = ustrRegisterClass.GetBuffer();
830 PCSZ pBegin;
831 if (!(pBegin = pcszRegisterClass))
832 throw BSConfigExcpt(REGEXCPT_SYNTAX, ustrRegisterClass);
833
834 PCSZ pEnd;
835 if (!(pEnd = strchr(pBegin, '|')))
836 throw BSConfigExcpt(REGEXCPT_SYNTAX, ustrRegisterClass);
837
838 // strip trailing spaces
839 PCSZ pEnd2 = pEnd;
840 while ((*pEnd2 == ' ') && (pEnd2 > pcszRegisterClass))
841 pEnd2--;
842
843 _ustrClassName.assignUtf8(pBegin, pEnd2);
844 if (!_ustrClassName())
845 throw BSConfigExcpt(REGEXCPT_SYNTAX, ustrRegisterClass);
846
847 pBegin = pEnd + 1;
848 // strip leading spaces
849 while ((*pBegin) && (*pBegin == ' '))
850 pBegin++;
851 _ustrModule.assignUtf8(pBegin);
852 if (!_ustrModule())
853 throw BSConfigExcpt(REGEXCPT_SYNTAX, ustrRegisterClass);
854}
855
856/*
857 *@@ DescribeType:
858 * describes the current manipulator type to the GUI.
859 *
860 *@@added V0.9.9 (2001-03-27) [umoeller]
861 */
862
863const char* BSRegisterClass::DescribeType()
864{
865 return ("WPS class registration");
866}
867
868/*
869 *@@ DescribeData:
870 * describes the current manipulator data to the GUI.
871 *
872 *@@added V0.9.9 (2001-03-27) [umoeller]
873 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
874 */
875
876ustring BSRegisterClass::DescribeData()
877{
878 ustring str = _ustrClassName;
879 str.appendUtf8(" in ");
880 str += _ustrModule;
881
882 return (str);
883}
884
885/*
886 *@@ IsRegistered:
887 * this returns TRUE if a class of the same WPS class name
888 * as this instance is already registered with the WPS.
889 * In that case, the module of the registered class is
890 * copied into strModule.
891 *
892 * This throws a BSConfigExcpt with REGEXCPT_QUERYCLASSLIST
893 * if the class list could not be queried.
894 *
895 *@@changed V0.9.18 (2002-03-08) [umoeller]: now using string for buffer, added codec
896 */
897
898bool BSRegisterClass::IsRegistered(BSUniCodec &codecProcess, // in: codec for process codepage
899 ustring &ustrModule)
900 const
901{
902 BOOL fInstalled = FALSE;
903 PBYTE pClassList,
904 pClassThis = 0;
905 if (pClassList = winhQueryWPSClassList())
906 {
907 string strClassName(&codecProcess, _ustrClassName);
908 if ((pClassThis = winhQueryWPSClass(pClassList, strClassName.c_str())))
909 {
910 fInstalled = TRUE;
911 ustrModule.assignCP(&codecProcess, ((POBJCLASS)pClassThis)->pszModName);
912 }
913
914 free(pClassList);
915 }
916 else
917 throw BSConfigExcpt(REGEXCPT_QUERYCLASSLIST, 0);
918
919 return (fInstalled);
920}
921
922/*
923 *@@ Register:
924 * this attempts to register the class.
925 *
926 * If (fReplace == TRUE), we do not call
927 * BSRegisterClass::IsRegistered before registering
928 * this, i.e. we will always register the class,
929 * even if it's already registered.
930 *
931 * If (fReplace == FALSE) and BSRegisterClass::IsRegistered
932 * returned TRUE, we throw a BSConfigExcpt with
933 * REGEXCPT_ALREADYREGISTERED and pszSubstr set to the
934 * file name of the registered DLL. Note that IsRegistered might
935 * in turn throw BSConfigExcpt with REGEXCPT_QUERYCLASSLIST.
936 *
937 * If registering the class failed, this throws a
938 * BSConfigExcpt with REGEXCPT_REGISTER and iData set
939 * to the APIRET of winhRegisterClass.
940 *
941 * This method can take a BSDoneLoggerBase object as input, which
942 * can later be used with the BSDeregisterClass::AddToUndoList
943 * static class method to easily create a list of BSDeregisterClass
944 * objects to undo the changes made.
945 *
946 * Example usage (exception handling omitted):
947 + BSRegisterDoneLogger logger;
948 + // create logger instance
949 + BSRegisterClass RegClass("XFolder|C:\XFOLDER\XFLDR.DLL");
950 + // create BSRegisterClass instance:
951 + RegClass.Register(TRUE, logger);
952 + ... // register more classes with the same logger
953 +
954 + // now create undo list
955 + list<BSDeregisterClass*> List;
956 + BSDeregisterClass::AddToUndoList(List, logger);
957 + list<BSDeregisterClass*>::iterator DeregStart = List.begin(),
958 + DeregEnd = List.end();
959 + for (; DeregStart != DeregEnd; DeregStart++)
960 + (**DeregStart).Deregister;
961 *
962 *@@changed V0.9.18 (2002-03-08) [umoeller]: added codec
963 *@@changed V0.9.18 (2002-03-08) [umoeller]: added missing log file entry
964 */
965
966int BSRegisterClass::Register(BSUniCodec &codecProcess, // in: codec for process codepage
967 bool fReplace,
968 BSRegisterDoneLogger *pLogger, // in: logger object to append items to (can be NULL)
969 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
970 const
971{
972 int irc = 0;
973
974 if (fReplace == FALSE)
975 {
976 ustring ustrModule;
977 if (IsRegistered(codecProcess, ustrModule))
978 throw BSConfigExcpt(REGEXCPT_ALREADYREGISTERED, ustrModule);
979 }
980
981 CONVERT(&codecProcess, ClassName);
982 CONVERT(&codecProcess, Module);
983
984 CHAR szBuf[1000];
985 APIRET arc = winhRegisterClass(pcszClassName,
986 pcszModule,
987 szBuf,
988 sizeof(szBuf));
989 // always record in logger, even if failed,
990 // because the class is in the class list anyway
991 if (pLogger)
992 pLogger->Append(_ustrClassName);
993
994 if (arc != NO_ERROR)
995 {
996 // this was missing V0.9.18 (2002-03-08) [umoeller]
997 if (pLogFile)
998 pLogFile->Write("Error %d registering WPS class \"%s\"",
999 arc,
1000 pcszClassName);
1001
1002 throw BSConfigExcpt(REGEXCPT_REGISTER, arc);
1003 }
1004
1005 // this was missing V0.9.18 (2002-03-08) [umoeller]
1006 if (pLogFile)
1007 pLogFile->Write("Registered WPS class \"%s\"",
1008 pcszClassName);
1009
1010 return (irc);
1011}
1012
1013/* ******************************************************************
1014 *
1015 * BSDeregisterClass class
1016 *
1017 ********************************************************************/
1018
1019/*
1020 *@@ BSDeregisterClass:
1021 * the constructor, which in this case takes a simple
1022 * PSZ class name as input.
1023 */
1024
1025BSDeregisterClass::BSDeregisterClass(const ustring &ustrDeregisterClass)
1026 : BSConfigBase(CFGT_DEREGISTERCLASS, tBSDeregisterClass)
1027{
1028 _ustrClassName = ustrDeregisterClass;
1029}
1030
1031/*
1032 *@@ DescribeType:
1033 * describes the current manipulator type to the GUI.
1034 *
1035 *@@added V0.9.2 (2000-02-19) [umoeller]
1036 */
1037
1038const char* BSDeregisterClass::DescribeType()
1039{
1040 return ("WPS class deregistration");
1041}
1042
1043/*
1044 *@@ DescribeData:
1045 * describes the current manipulator data to the GUI.
1046 *
1047 *@@added V0.9.2 (2000-02-19) [umoeller]
1048 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
1049 */
1050
1051ustring BSDeregisterClass::DescribeData()
1052{
1053 return (_ustrClassName);
1054}
1055
1056/*
1057 *@@ Deregister:
1058 * this attempts to deregister the class.
1059 *
1060 * Throws:
1061 * -- BSConfigExcpt.
1062 *
1063 *@@changed V0.9.18 (2002-03-08) [umoeller]: added codec
1064 */
1065
1066int BSDeregisterClass::Deregister(BSUniCodec &codecProcess, // in: codec for process codepage
1067 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
1068 const
1069{
1070 int irc = 0;
1071
1072 CONVERT(&codecProcess, ClassName); // creates local string strXXX, PCSZ pcszXXX
1073
1074 if (!WinDeregisterObjectClass(pcszClassName))
1075 {
1076 if (pLogFile)
1077 pLogFile->Write("An error occured deregistering WPS class \"%s\"",
1078 pcszClassName);
1079
1080 throw BSConfigExcpt(REGEXCPT_DEREGISTER, _ustrClassName);
1081 }
1082
1083 if (pLogFile)
1084 pLogFile->Write("Deregistered WPS class \"%s\"",
1085 pcszClassName);
1086
1087 return (irc);
1088}
1089
1090/*
1091 *@@ AddToUndoList:
1092 * static helper method to create BSDeregisterClass
1093 * instances from the logger instance that was
1094 * previously used with BSRegisterClass::Register.
1095 *
1096 * The new BSDeregisterClass objects are appended to
1097 * the specified list.
1098 *
1099 * See BSRegisterClass::Register for an example usage.
1100 *
1101 * This returns the number of items created.
1102 */
1103
1104int BSDeregisterClass::AddToUndoList(list<BSConfigBase*> &List,
1105 BSRegisterDoneLogger &logger)
1106{
1107 // the logger in this case has a simple list of PSZs with all
1108 // the class names that were registered, each of which is terminated
1109 // with a null character
1110
1111 PSZ pszLogStart = logger._pabLogString,
1112 pszLogThis = pszLogStart;
1113 int iCount = 0;
1114
1115 while (pszLogThis < pszLogStart + logger._cbLogString)
1116 {
1117 ULONG cbLogThis = strlen(pszLogThis);
1118 ustring ustr;
1119 ustr.assignUtf8(pszLogThis);
1120 List.push_back(new BSDeregisterClass(ustr));
1121 pszLogThis += cbLogThis + 1; // go beyond null byte
1122 iCount++;
1123 }
1124
1125 return (iCount);
1126}
1127
1128/* ******************************************************************
1129 *
1130 * BSReplaceClass class
1131 *
1132 ********************************************************************/
1133
1134/*
1135 *@@ BSReplaceClassBase:
1136 * this constructor translates a REPLACECLASS attribute (as used
1137 * in the PCK tag and stored in the database) into the BSReplaceClass
1138 * instance data.
1139 *
1140 * Syntax:
1141 *
1142 + REPLACECLASS="oldclassname|newclassname"
1143 *
1144 *@@changed V0.9.19 (2002-05-07) [umoeller]: changed inheritance hierarchy here
1145 */
1146
1147BSReplaceClassBase::BSReplaceClassBase(const ustring &ustrReplaceClass,
1148 ULONG cfgt,
1149 BSClassID &Class)
1150 : BSConfigBase(cfgt, Class)
1151{
1152 PCSZ pcszReplaceClass = ustrReplaceClass.GetBuffer();
1153
1154 // find separator
1155 PCSZ pBegin;
1156 if (!(pBegin = pcszReplaceClass))
1157 throw BSConfigExcpt(REGEXCPT_SYNTAX, ustrReplaceClass);
1158
1159 PCSZ pEnd;
1160 if (!(pEnd = strchr(pBegin, '|')))
1161 throw BSConfigExcpt(REGEXCPT_SYNTAX, ustrReplaceClass);
1162
1163 // strip trailing spaces
1164 PCSZ pEnd2 = pEnd;
1165 while ((*pEnd2 == ' ') && (pEnd2 > pcszReplaceClass))
1166 pEnd2--;
1167
1168 _ustrOldClassName.assignUtf8(pBegin, pEnd2);
1169 if (!_ustrOldClassName())
1170 throw BSConfigExcpt(REGEXCPT_SYNTAX, ustrReplaceClass);
1171
1172 pBegin = pEnd + 1;
1173 // strip leading spaces
1174 while ((*pBegin) && (*pBegin == ' '))
1175 pBegin++;
1176 _ustrNewClassName.assignUtf8(pBegin);
1177 if (!_ustrNewClassName())
1178 throw BSConfigExcpt(REGEXCPT_SYNTAX, ustrReplaceClass);
1179}
1180
1181/*
1182 *@@ DescribeType:
1183 * describes the current manipulator type to the GUI.
1184 *
1185 *@@added V0.9.2 (2000-02-19) [umoeller]
1186 */
1187
1188const char* BSReplaceClass::DescribeType()
1189{
1190 return ("WPS class replacement");
1191}
1192
1193/*
1194 *@@ DescribeData:
1195 * describes the current manipulator data to the GUI.
1196 *
1197 *@@added V0.9.2 (2000-02-19) [umoeller]
1198 *@@changed V0.9.5 (2000-08-26) [umoeller]: UNIQUE wasn't reported right
1199 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
1200 */
1201
1202ustring BSReplaceClass::DescribeData()
1203{
1204 ustring str = _ustrOldClassName;
1205 str.appendUtf8(" with ");
1206 str += _ustrNewClassName;
1207
1208 return (str);
1209}
1210
1211/*
1212 *@@ Replace:
1213 * this attempts to replace the class or undo
1214 * an existing replacement (if fReplace == FALSE).
1215 *
1216 * If replacing the class failed, this throws a
1217 * BSConfigExcpt with REGEXCPT_REPLACE.
1218 *
1219 * Example usage (exception handling omitted):
1220 + BSReplaceDoneLogger logger;
1221 + // create logger instance
1222 + BSReplaceClass ReplClass("WPFolder;XFolder");
1223 + // create BSReplaceClass instance:
1224 + ReplClass.Replace(TRUE, logger);
1225 + ... // replace more classes with the same logger
1226 +
1227 + // now create undo list
1228 + list<BSUnreplaceClass*> List;
1229 + BSUnreplaceClass::AddToUndoList(List, logger);
1230 + list<BSUnreplaceClass*>::iterator UnrplStart = List.begin(),
1231 + UnrplEnd = List.end();
1232 + for (; UnrplStart != UnrplEnd; UnrplStart++)
1233 + (**UnrplStart).Unreplace;
1234 *
1235 *@@changed V0.9.1 (2000-01-05) [umoeller]: finally added logging, which was missing
1236 *@@changed V0.9.9 (2001-03-30) [umoeller]: fixed wrong logging if replace failed
1237 *@@changed V0.9.18 (2002-03-08) [umoeller]: added codec
1238 */
1239
1240int BSReplaceClass::Replace(BSUniCodec &codecProcess, // in: codec for process codepage
1241 BSReplaceDoneLogger *pLogger, // in: logger object to append items to (can be NULL)
1242 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
1243 const
1244{
1245 int irc = 0;
1246
1247 CONVERT(&codecProcess, OldClassName);
1248 CONVERT(&codecProcess, NewClassName);
1249
1250 BOOL brc = WinReplaceObjectClass(pcszOldClassName,
1251 pcszNewClassName,
1252 TRUE); // replace
1253 // always record in logger, even if failed,
1254 // because the class is in the class list anyway
1255 // V0.9.9 (2001-03-30) [umoeller]
1256 if (pLogger)
1257 {
1258 ustring ustr2Append(_ustrOldClassName);
1259 ustr2Append.appendUtf8("|");
1260 ustr2Append += _ustrNewClassName;
1261 pLogger->Append(ustr2Append);
1262 }
1263
1264
1265 if (!brc)
1266 {
1267 if (pLogFile)
1268 pLogFile->Write("An error occured replacing WPS class \"%s\" with \"%s\"",
1269 pcszOldClassName,
1270 pcszNewClassName);
1271
1272 throw BSConfigExcpt(REGEXCPT_REPLACE, 0);
1273 }
1274
1275 // success:
1276 if (pLogFile)
1277 pLogFile->Write("Replaced WPS class \"%s\" with \"%s\"",
1278 pcszOldClassName,
1279 pcszNewClassName);
1280
1281 return (irc);
1282}
1283
1284/* ******************************************************************
1285 *
1286 * BSUnreplaceClass class
1287 *
1288 ********************************************************************/
1289
1290/*
1291 *@@ DescribeType:
1292 * describes the current manipulator type to the GUI.
1293 *
1294 *@@added V0.9.2 (2000-02-19) [umoeller]
1295 */
1296
1297const char* BSUnreplaceClass::DescribeType()
1298{
1299 return ("WPS class un-replacement");
1300}
1301
1302/*
1303 *@@ DescribeData:
1304 * describes the current manipulator data to the GUI.
1305 *
1306 *@@added V0.9.2 (2000-02-19) [umoeller]
1307 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
1308 */
1309
1310ustring BSUnreplaceClass::DescribeData()
1311{
1312 ustring ustr = _ustrOldClassName;
1313 ustr.appendUtf8(" with ");
1314 ustr += _ustrNewClassName;
1315
1316 return (ustr);
1317}
1318
1319/*
1320 *@@ Unreplace:
1321 * this attempts to unreplace the class.
1322 * Throws a BSConfigExcpt upon failure.
1323 *
1324 *@@changed V0.9.18 (2002-03-08) [umoeller]: added codec
1325 */
1326
1327int BSUnreplaceClass::Unreplace(BSUniCodec &codecProcess, // in: codec for process codepage,
1328 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
1329 const
1330{
1331 int irc = 0;
1332
1333 CONVERT(&codecProcess, OldClassName);
1334 CONVERT(&codecProcess, NewClassName);
1335
1336 if (!WinReplaceObjectClass(pcszOldClassName,
1337 pcszNewClassName,
1338 FALSE))
1339 {
1340 if (pLogFile)
1341 pLogFile->Write("Error undoing WPS class replacement of \"%s\" with \"%s\"",
1342 pcszOldClassName,
1343 pcszNewClassName);
1344
1345 throw BSConfigExcpt(REGEXCPT_UNREPLACE, 0);
1346 }
1347
1348 // success:
1349 if (pLogFile)
1350 pLogFile->Write("Undid WPS class replacement of \"%s\" with \"%s\"",
1351 pcszOldClassName,
1352 pcszNewClassName);
1353
1354 return (irc);
1355}
1356
1357/*
1358 *@@ AddToUndoList:
1359 * static helper method to create BSUnreplaceClass
1360 * instances from the logger instance that was
1361 * previously used with BSRegisterClass::Register.
1362 *
1363 * The new BSUnreplaceClass objects are appended to
1364 * the specified list.
1365 *
1366 * See BSReplaceClass::Replace for an example usage.
1367 *
1368 * This returns the number of items created.
1369 */
1370
1371int BSUnreplaceClass::AddToUndoList(list<BSConfigBase*> &List,
1372 BSReplaceDoneLogger &logger)
1373{
1374 // the logger in this case has a simple list of PSZs with all
1375 // the class names that were registered, each of which is terminated
1376 // with a null character
1377
1378 PSZ pszLogStart = logger._pabLogString,
1379 pszLogThis = pszLogStart;
1380 int iCount = 0;
1381
1382 while (pszLogThis < pszLogStart + logger._cbLogString)
1383 {
1384 ULONG cbLogThis = strlen(pszLogThis);
1385 ustring ustr;
1386 ustr.assignUtf8(pszLogThis);
1387 List.push_back(new BSUnreplaceClass(ustr));
1388 // this calls the inherited BSReplaceClass
1389 // constructor, which will parse the thing
1390 pszLogThis += cbLogThis + 1; // go beyond null byte
1391 iCount++;
1392 }
1393
1394 return (iCount);
1395}
1396
1397/* ******************************************************************
1398 *
1399 * BSCreateWPSObject class
1400 *
1401 ********************************************************************/
1402
1403/*
1404 *@@ BSCreateWPSObject:
1405 * this constructor translates a CREATEOBJECT attribute (as used
1406 * in the PCK tag and stored in the database) into the BSCreateWPSObject
1407 * instance data.
1408 *
1409 * Syntax:
1410 *
1411 + CREATEOBJECT="[REPLACE] classname|title|location[|config]]"
1412 *
1413 * Throws:
1414 * -- BSConfigExcpt.
1415 *
1416 *@@changed V0.9.3 (2000-04-08) [umoeller]: "REPLACE" wasn't evaluated; fixed. Thanks, Cornelis Bockemhl.
1417 *@@changed V0.9.15 (2001-08-26) [umoeller]: added WPOEXCPT_INVALIDLOCATION checks
1418 *@@changed V0.9.19 (2002-04-14) [umoeller]: REPLACE was never detected, fixed
1419 */
1420
1421BSCreateWPSObject::BSCreateWPSObject(const ustring &ustrCreateObject)
1422 : BSConfigBase(CFGT_CREATEOBJECT, tBSCreateWPSObject)
1423{
1424 PCSZ pcszCreateObject = ustrCreateObject.GetBuffer();
1425
1426 // extract class name
1427 PCSZ pBegin;
1428 if (!(pBegin = pcszCreateObject))
1429 throw BSConfigExcpt(WPOEXCPT_NOCLASS, ustrCreateObject);
1430
1431 // if (!strcmp(pBegin, "REPLACE ")) BUZZZZ WRONG V0.9.19 (2002-04-14) [umoeller]
1432 if (!memcmp(pBegin, "REPLACE ", 8))
1433 {
1434 // added V0.9.3 (2000-04-08) [umoeller]
1435 _fReplace = TRUE;
1436 pBegin += 7;
1437 while (*pBegin == ' ')
1438 pBegin++;
1439 }
1440 else
1441 _fReplace = FALSE;
1442
1443 PSZ pEnd;
1444 if (pEnd = strchr(pBegin, '|'))
1445 {
1446 _ustrClassName.assignUtf8(pBegin, pEnd);
1447
1448 // extract title
1449 pBegin = pEnd + 1;
1450 if (pEnd = strchr(pBegin, '|'))
1451 {
1452 _ustrTitle.assignUtf8(pBegin, pEnd);
1453
1454 // extract location
1455 pBegin = pEnd + 1;
1456 if (pEnd = strchr(pBegin, '|'))
1457 {
1458 // yet another separator found: we then have a config parameter
1459 _ustrLocation.assignUtf8(pBegin, pEnd);
1460
1461 // extract config (rest of pszCreateObject)
1462 pBegin = pEnd + 1;
1463 _ustrSetupString.assignUtf8(pBegin);
1464 }
1465 else
1466 // no separator after "location" found:
1467 // duplicate whole string
1468 _ustrLocation.assignUtf8(pBegin);
1469
1470 if (!_ustrLocation())
1471 throw BSConfigExcpt(WPOEXCPT_NOLOCATION, ustrCreateObject);
1472
1473 // check if the location is correctly in <> brackets
1474 // V0.9.15 (2001-08-26) [umoeller]
1475 PCSZ pcszLocation = _ustrLocation.GetBuffer();
1476 if ( (pcszLocation[0] == '<')
1477 && (pcszLocation[_ustrLocation.length() - 1] != '>')
1478 )
1479 throw BSConfigExcpt(WPOEXCPT_INVALIDLOCATIONSTRING, ustrCreateObject);
1480 }
1481 else
1482 throw BSConfigExcpt(WPOEXCPT_NOTITLE, ustrCreateObject);
1483 }
1484 else
1485 throw BSConfigExcpt(WPOEXCPT_NOCLASS, ustrCreateObject);
1486}
1487
1488/*
1489 *@@ DescribeType:
1490 * describes the current manipulator type to the GUI.
1491 *
1492 *@@added V0.9.9 (2001-03-27) [umoeller]
1493 */
1494
1495const char* BSCreateWPSObject::DescribeType()
1496{
1497 return ("WPS object");
1498}
1499
1500/*
1501 *@@ DescribeData:
1502 * describes the current manipulator data to the GUI.
1503 *
1504 *@@added V0.9.9 (2001-03-27) [umoeller]
1505 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
1506 */
1507
1508ustring BSCreateWPSObject::DescribeData()
1509{
1510 ustring ustr = _ustrClassName;
1511 ustr.appendUtf8(" ");
1512 ustr += _ustrTitle;
1513 ustr.appendUtf8(" ");
1514 ustr += _ustrLocation;
1515 ustr.appendUtf8(" ");
1516 ustr += _ustrSetupString;
1517
1518 return (ustr);
1519}
1520
1521/*
1522 *@@ CreateObject:
1523 * this attempts to create the WPS object
1524 * with the instance data.
1525 *
1526 * Throws a BSConfigExcpt with WPOEXCPT_CREATE
1527 * if this fails.
1528 *
1529 *@@changed V0.9.18 (2002-03-08) [umoeller]: added codec
1530 */
1531
1532void BSCreateWPSObject::CreateObject(BSUniCodec &codecProcess, // in: codec for process codepage,
1533 BSWPSObjectsDoneLogger *pLogger, // in: logger object to append items to (can be NULL)
1534 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
1535{
1536 CONVERT(&codecProcess, ClassName); // creates local string strXXX, PCSZ pcszXXX
1537 CONVERT(&codecProcess, Title); // creates local string strXXX, PCSZ pcszXXX
1538 CONVERT(&codecProcess, SetupString); // creates local string strXXX, PCSZ pcszXXX
1539 CONVERT(&codecProcess, Location); // creates local string strXXX, PCSZ pcszXXX
1540
1541 // check if the target folder exists, this is the most common problem
1542 // if WinCreateObject fails
1543 // V0.9.19 (2002-06-15) [umoeller]
1544
1545 if (!WinQueryObject(pcszLocation))
1546 {
1547 if (pLogFile)
1548 pLogFile->Write("Error creating WPS object \"%s\", class \"%s\", location \"%s\", setup \"%s\": Invalid target folder",
1549 pcszTitle,
1550 pcszClassName,
1551 pcszLocation,
1552 pcszSetupString);
1553
1554 throw BSConfigExcpt(WPOEXCPT_CREATE_BADLOCATION, _ustrTitle);
1555 }
1556
1557 if (!(_hobj = WinCreateObject(pcszClassName,
1558 pcszTitle,
1559 pcszSetupString,
1560 pcszLocation,
1561 (_fReplace)
1562 ? CO_REPLACEIFEXISTS
1563 : CO_UPDATEIFEXISTS)))
1564 {
1565 if (pLogFile)
1566 pLogFile->Write("Error creating WPS object \"%s\", class \"%s\", location \"%s\", setup \"%s\"",
1567 pcszTitle,
1568 pcszClassName,
1569 pcszLocation,
1570 pcszSetupString);
1571
1572 throw BSConfigExcpt(WPOEXCPT_CREATE, _ustrTitle);
1573 }
1574
1575 if (pLogFile)
1576 {
1577 pLogFile->Write("Created WPS object \"%s\", class \"%s\", location \"%s\", setup \"%s\"",
1578 pcszTitle,
1579 pcszClassName,
1580 pcszLocation,
1581 pcszSetupString);
1582 pLogFile->Write("HOBJECT is 0x%lX", _hobj);
1583 }
1584
1585 // store the object ID in the logger
1586 PCSZ pObjectID;
1587 if ( // do we have a setup string at all?
1588 (pObjectID = _ustrSetupString.GetBuffer())
1589 // does it contain an object ID?
1590 && (pObjectID = strhistr(pObjectID,
1591 "OBJECTID=<"))
1592 )
1593 {
1594 PCSZ pBegin = pObjectID + 9; // points to '<' now
1595 PCSZ pEnd;
1596 if (pEnd = strchr(pBegin, '>'))
1597 {
1598 ustring ustrObjectID;
1599 ustrObjectID.assignUtf8(pBegin, pEnd + 1);
1600 if (pLogger)
1601 pLogger->Append(ustrObjectID);
1602 }
1603 }
1604}
1605
1606/* ******************************************************************
1607 *
1608 * BSDeleteWPSObject class
1609 *
1610 ********************************************************************/
1611
1612/*
1613 *@@ BSDeleteWPSObject:
1614 * the constructor, which in this case takes a simple
1615 * PSZ object ID as input.
1616 */
1617
1618BSDeleteWPSObject::BSDeleteWPSObject(const ustring &ustrID2Delete)
1619 : BSConfigBase(CFGT_DELETEOBJECT, tBSDeleteWPSObject)
1620{
1621 _ustrObjectID = ustrID2Delete;
1622}
1623
1624/*
1625 *@@ DescribeType:
1626 * describes the current manipulator type to the GUI.
1627 *
1628 *@@added V0.9.2 (2000-02-19) [umoeller]
1629 */
1630
1631const char* BSDeleteWPSObject::DescribeType()
1632{
1633 return ("WPS object deletion");
1634}
1635
1636/*
1637 *@@ DescribeData:
1638 * describes the current manipulator data to the GUI.
1639 *
1640 *@@added V0.9.2 (2000-02-19) [umoeller]
1641 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
1642 */
1643
1644ustring BSDeleteWPSObject::DescribeData()
1645{
1646 return (_ustrObjectID);
1647}
1648
1649/*
1650 *@@ Delete:
1651 * this attempts to delete the object.
1652 * Throws a BSConfigExcpt upon failure.
1653 *
1654 *@@changed V0.9.18 (2002-03-08) [umoeller]: added codec
1655 */
1656
1657int BSDeleteWPSObject::Delete(BSUniCodec &codecProcess,
1658 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
1659 const
1660{
1661 int irc = 0;
1662
1663 CONVERT(&codecProcess, ObjectID); // creates local string strXXX, PCSZ pcszXXX
1664
1665 HOBJECT hobj;
1666 if (!(hobj = WinQueryObject(pcszObjectID)))
1667 {
1668 if (pLogFile)
1669 pLogFile->Write("Error deleting WPS object \"%s\"",
1670 pcszObjectID);
1671
1672 throw BSConfigExcpt(WPOEXCPT_DELETEOBJECT, 0);
1673 }
1674
1675 if (!WinDestroyObject(hobj))
1676 {
1677 if (pLogFile)
1678 pLogFile->Write("Error deleting WPS object \"%s\", HOBJECT was 0x%lX",
1679 pcszObjectID,
1680 hobj);
1681
1682 throw BSConfigExcpt(WPOEXCPT_DELETEOBJECT, 0);
1683 }
1684
1685 return (irc);
1686}
1687
1688/*
1689 *@@ AddToUndoList:
1690 * static helper method to create BSDeleteWPSObject
1691 * instances from the logger instance that was
1692 * previously used with BSRegisterClass::Register.
1693 *
1694 * The new BSDeleteWPSObject objects are appended to
1695 * the specified list.
1696 *
1697 * This returns the number of items created.
1698 */
1699
1700int BSDeleteWPSObject::AddToUndoList(list<BSConfigBase*> &List,
1701 BSWPSObjectsDoneLogger &logger)
1702{
1703 // the logger in this case has a simple list of PSZs with all
1704 // the object IDs that were created, each of which is terminated
1705 // with a null character
1706
1707 PSZ pszLogStart = logger._pabLogString,
1708 pszLogThis = pszLogStart;
1709 int iCount = 0;
1710
1711 while (pszLogThis < pszLogStart + logger._cbLogString)
1712 {
1713 ULONG cbLogThis = strlen(pszLogThis);
1714 ustring ustr;
1715 ustr.assignUtf8(pszLogThis);
1716 List.push_back(new BSDeleteWPSObject(ustr));
1717 pszLogThis += cbLogThis + 1; // go beyond null byte
1718 iCount++;
1719 }
1720
1721 return (iCount);
1722}
1723
1724/* ******************************************************************
1725 *
1726 * BSClearProfile class
1727 *
1728 ********************************************************************/
1729
1730/*
1731 *@@ DescribeType:
1732 * describes the current manipulator type to the GUI.
1733 *
1734 *@@added V0.9.2 (2000-02-19) [umoeller]
1735 */
1736
1737const char* BSProfileBase::DescribeType()
1738{
1739 return ("Profile data");
1740}
1741
1742/*
1743 *@@ DescribeData:
1744 * describes the current manipulator data to the GUI.
1745 *
1746 *@@added V0.9.2 (2000-02-19) [umoeller]
1747 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
1748 */
1749
1750ustring BSProfileBase::DescribeData()
1751{
1752 return (DescribePrfKey());
1753}
1754
1755/*
1756 *@@ DescribePrfKey:
1757 * returns a descriptive string describing the
1758 * member fields, a la "USER\app\key".
1759 *
1760 *@@added V0.9.1 (2000-02-12) [umoeller]
1761 */
1762
1763ustring BSProfileBase::DescribePrfKey() const
1764{
1765 ustring str(_ustrProfile);
1766 if (_ustrApplication())
1767 {
1768 str.appendUtf8("\\");
1769 str += _ustrApplication;
1770
1771 if (_ustrKey())
1772 {
1773 str.appendUtf8("\\");
1774 str += _ustrKey;
1775 }
1776 }
1777
1778 return (str);
1779}
1780
1781/*
1782 *@@ DescribePrfKey:
1783 *
1784 *@@added V0.9.18 (2002-03-08) [umoeller]
1785 */
1786
1787string BSProfileBase::DescribePrfKey(BSUniCodec &codecProcess) const
1788{
1789 string str(&codecProcess, DescribePrfKey());
1790 return str;
1791}
1792
1793/*
1794 *@@ BSClearProfile:
1795 *
1796 * Syntax:
1797 *
1798 + CLEARPROFILE="profile[\application[\key]]"
1799 *
1800 *@@added V0.9.1 (2000-02-07) [umoeller]
1801 */
1802
1803BSClearProfile::BSClearProfile(const ustring &ustrClearProfile)
1804 : BSProfileBase(CFGT_CLEARPROFILE, tBSClearProfile)
1805{
1806 PCSZ pcszClearProfile = ustrClearProfile.GetBuffer();
1807
1808 // get profile
1809 PCSZ pFirstBackslash;
1810 if (pFirstBackslash = strchr(pcszClearProfile, '\\'))
1811 {
1812 // extract profile
1813 _ustrProfile.assignUtf8(pcszClearProfile, pFirstBackslash);
1814
1815 // get application
1816 PCSZ pSecondBackslash;
1817 if (pSecondBackslash = strchr(pFirstBackslash + 2, '\\'))
1818 {
1819 // key specified:
1820 // extract application up to key
1821 _ustrApplication.assignUtf8(pFirstBackslash + 1, pSecondBackslash);
1822
1823 // extract key (all the rest)
1824 _ustrKey.assignUtf8(pSecondBackslash + 1);
1825 }
1826 else
1827 // key not specified:
1828 _ustrApplication.assignUtf8(pFirstBackslash + 1);
1829 }
1830
1831 if ( (!_ustrProfile())
1832 || (!_ustrApplication())
1833 )
1834 // any error:
1835 throw BSConfigExcpt(PRFEXCPT_SYNTAX, ustrClearProfile);
1836}
1837
1838/*
1839 *@@ Clear:
1840 * deletes the corresponding profile entry.
1841 *
1842 *@@added V0.9.5 (2000-08-26) [umoeller]
1843 *@@changed V0.9.18 (2002-03-08) [umoeller]: added codec
1844 */
1845
1846int BSClearProfile::Clear(BSUniCodec &codecProcess, // in: codec for process codepage,
1847 HAB hab,
1848 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
1849 const
1850{
1851 BOOL fOK = FALSE;
1852 HINI hini = NULLHANDLE,
1853 hini2Close = NULLHANDLE;
1854
1855 if (!_ustrProfile.compareUtf8("USER"))
1856 hini = HINI_USER;
1857 else if (!_ustrProfile.compareUtf8("SYSTEM"))
1858 hini = HINI_SYSTEM;
1859 else
1860 {
1861 CONVERT(&codecProcess, Profile);
1862 hini = PrfOpenProfile(hab,
1863 pcszProfile);
1864 hini2Close = hini;
1865 }
1866
1867 if (hini)
1868 {
1869 CONVERT(&codecProcess, Application);
1870 CONVERT(&codecProcess, Key);
1871
1872 ULONG cb = 0;
1873 // does key exist?
1874 if (PrfQueryProfileSize(hini,
1875 pcszApplication,
1876 pcszKey, // can be NULL
1877 &cb))
1878 {
1879 // key exists:
1880 if (PrfWriteProfileString(hini,
1881 pcszApplication,
1882 pcszKey, // can be NULL
1883 NULL))
1884 fOK = TRUE;
1885 }
1886 else
1887 // key does not exist:
1888 fOK = TRUE;
1889 }
1890
1891 if (!fOK)
1892 {
1893 string strClear = DescribePrfKey(codecProcess);
1894 if (pLogFile)
1895 pLogFile->Write("Error deleting profile key \"%s\"",
1896 strClear.c_str());
1897
1898 // error:
1899 throw BSConfigExcpt(PRFEXCPT_PRFERROR, DescribePrfKey());
1900 }
1901
1902 if (pLogFile)
1903 {
1904 string strClear = DescribePrfKey(codecProcess);
1905 pLogFile->Write("Deleted profile key \"%s\"",
1906 strClear.c_str());
1907 }
1908
1909 return (1);
1910}
1911
1912/*
1913 *@@ AddToUndoList:
1914 * static helper method to create BSClearProfile
1915 * instances from the specified logger instance.
1916 * Note that this class method will be used both
1917 * for "CLEARPROFILE" tags specified in the script
1918 * as well as "WRITEPROFILE" tags which were actually
1919 * executed (written to a profile).
1920 *
1921 * The new BSClearProfile objects are appended to
1922 * the specified list.
1923 *
1924 * This returns the number of items created.
1925 */
1926
1927int BSClearProfile::AddToUndoList(list<BSConfigBase*> &List,
1928 BSClearPrfAttrsLogger &logger)
1929{
1930 // the logger in this case has a simple list of PSZs with all
1931 // the profile keys that were created, each of which is terminated
1932 // with a null character
1933
1934 PSZ pszLogStart = logger._pabLogString,
1935 pszLogThis = pszLogStart;
1936 int iCount = 0;
1937
1938 while (pszLogThis < pszLogStart + logger._cbLogString)
1939 {
1940 ULONG cbLogThis = strlen(pszLogThis);
1941 ustring ustr;
1942 ustr.assignUtf8(pszLogThis);
1943 List.push_back(new BSClearProfile(ustr));
1944 pszLogThis += cbLogThis + 1; // go beyond null byte
1945 iCount++;
1946 }
1947
1948 return (iCount);
1949}
1950
1951/* ******************************************************************
1952 *
1953 * BSWriteProfile class
1954 *
1955 ********************************************************************/
1956
1957/*
1958 *@@ BSWriteProfile:
1959 *
1960 * Syntax:
1961 *
1962 + WRITEPROFILE="profile\application\key|string"
1963 *
1964 *@@added V0.9.1 (2000-02-07) [umoeller]
1965 *@@changed V0.9.19 (2002-05-07) [umoeller]: added missing class init, now writeprofiles work again
1966 */
1967
1968BSWriteProfile::BSWriteProfile(const ustring &ustrWriteProfile)
1969 : BSProfileBase(CFGT_WRITEPROFILE, tBSWriteProfile)
1970{
1971 PCSZ pcszWriteProfile = ustrWriteProfile.GetBuffer();
1972
1973 // override class, this was still BSClearProfile due
1974 // to the constructor; this is also why writeprofiles
1975 // never worked V0.9.19 (2002-05-07) [umoeller]
1976 _Class = tBSWriteProfile;
1977
1978 PCSZ pSlash;
1979 if (pSlash = strchr(pcszWriteProfile, '|'))
1980 {
1981 // copy write data (after '|')
1982 _ustrWriteString.assignUtf8(pSlash + 1);
1983
1984 // get profile
1985 PCSZ pFirstBackslash;
1986 if (pFirstBackslash = strchr(pcszWriteProfile, '\\'))
1987 {
1988 // extract profile
1989 _ustrProfile.assignUtf8(pcszWriteProfile, pFirstBackslash);
1990
1991 // get application
1992 PCSZ pSecondBackslash;
1993 if (pSecondBackslash = strchr(pFirstBackslash + 2, '\\'))
1994 {
1995 // extract application
1996 _ustrApplication.assignUtf8(pFirstBackslash + 1, pSecondBackslash);
1997
1998 // extract key (up to '|')
1999 _ustrKey.assignUtf8(pSecondBackslash + 1, pSlash);
2000 }
2001 }
2002 }
2003
2004 if (!_ustrKey())
2005 // any error:
2006 throw BSConfigExcpt(PRFEXCPT_SYNTAX, ustrWriteProfile);
2007}
2008
2009/*
2010 *@@ Write:
2011 * this actually writes data to a profile, all
2012 * as specified by the member variables.
2013 *
2014 * Note that this stores the "done" stuff in
2015 * a BSClearPrfAttrsLogger for undoing later.
2016 *
2017 * Throws:
2018 * -- BSConfigExcpt.
2019 *
2020 *@@added V0.9.1 (2000-02-07) [umoeller]
2021 *@@changed V0.9.18 (2002-03-08) [umoeller]: added codec
2022 */
2023
2024int BSWriteProfile::Write(BSUniCodec &codecProcess, // in: codec for process codepage,
2025 HAB hab, // in: anchor block (for PrfOpenProfile)
2026 BSClearPrfAttrsLogger *pLogger,
2027 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
2028 const
2029{
2030 BOOL fOK = FALSE;
2031 HINI hini = NULLHANDLE,
2032 hini2Close = NULLHANDLE;
2033
2034 if (!_ustrProfile.compareUtf8("USER"))
2035 hini = HINI_USER;
2036 else if (!_ustrProfile.compareUtf8("SYSTEM"))
2037 hini = HINI_SYSTEM;
2038 else
2039 {
2040 CONVERT(&codecProcess, Profile);
2041 if (!(hini = PrfOpenProfile(hab,
2042 pcszProfile)))
2043 throw BSConfigExcpt(PRFEXCPT_PRFOPENPROFILE, _ustrProfile);
2044
2045 hini2Close = hini;
2046 }
2047
2048 if (hini)
2049 {
2050 CONVERT(&codecProcess, Application);
2051 CONVERT(&codecProcess, Key);
2052 CONVERT(&codecProcess, WriteString);
2053 if (PrfWriteProfileString(hini,
2054 pcszApplication,
2055 pcszKey,
2056 pcszWriteString))
2057 {
2058 fOK = TRUE;
2059 }
2060 }
2061
2062 // recompose string for BSClearProfile
2063 ustring ustrClear = DescribePrfKey();
2064 string strClear = DescribePrfKey(codecProcess);
2065
2066 if (fOK)
2067 {
2068 if (pLogFile)
2069 pLogFile->Write("Wrote profile key \"%s\"",
2070 strClear.c_str());
2071
2072 if (pLogger)
2073 pLogger->Append(ustrClear);
2074 }
2075 else
2076 {
2077 // error:
2078 if (pLogFile)
2079 pLogFile->Write("Error writing profile key \"%s\"",
2080 strClear.c_str());
2081
2082 throw BSConfigExcpt(PRFEXCPT_PRFERROR, DescribePrfKey());
2083 }
2084
2085 return 1;
2086}
2087
2088/* ******************************************************************
2089 *
2090 * BSExecute class
2091 *
2092 ********************************************************************/
2093
2094/*
2095 *@@ BSExecute:
2096 * this constructor takes an EXECUTE attribute (of the PCK tag)
2097 * as input and sets up the instance data accordingly.
2098 *
2099 * Syntax:
2100 *
2101 + EXECUTE="[ context ] execfile params"
2102 *
2103 * Throws:
2104 * -- BSConfigExcpt.
2105 *
2106 *@@added V0.9.1 (2000-02-07) [umoeller]
2107 *@@changed V0.9.3 (2000-04-08) [umoeller]: "|" was a requirement, contradicting the docs; changed. Thanks, Cornelis Bockemhl.
2108 *@@changed V0.9.4 (2000-07-10) [umoeller]: _ulExecType wasn't always initialized; thanks Yuri Dario
2109 *@@changed V0.9.4 (2000-07-26) [umoeller]: now ORing the flags
2110 *@@changed V0.9.9 (2001-03-27) [umoeller]: fixed EXECUTE parameters
2111 */
2112
2113BSExecute::BSExecute(const ustring &ustrExecute,
2114 BSClassID &Class)
2115 : BSConfigBase(CFGT_EXECUTE, Class)
2116{
2117 BOOL fContextFound = FALSE,
2118 fContinue = TRUE;
2119 PCSZ pcszExecute = ustrExecute.GetBuffer();
2120 PCSZ pSearch = (PSZ)pcszExecute;
2121
2122 _ulExecType = 0;
2123 _arc = 0; // NO_ERROR
2124
2125 while (fContinue)
2126 {
2127 // skip leading spaces
2128 while ( (*pSearch)
2129 && (*pSearch == ' ')
2130 )
2131 pSearch++;
2132
2133 if (strncmp(pSearch, "CONFIGSYS", 9) == 0)
2134 {
2135 _ulExecType |= CFGT_CFGSYS;
2136 fContextFound = TRUE;
2137 pSearch += 9; // strlen("CONFIGSYS");
2138 }
2139 else if (strncmp(pSearch, "REGISTERCLASS", 13) == 0)
2140 {
2141 _ulExecType |= CFGT_REGISTERCLASS;
2142 fContextFound = TRUE;
2143 pSearch += 13; // strlen("REGISTERCLASS");
2144 }
2145 else if (strncmp(pSearch, "CREATEOBJECT", 12) == 0)
2146 {
2147 _ulExecType |= CFGT_CREATEOBJECT;
2148 fContextFound = TRUE;
2149 pSearch += 12; // strlen("CREATEOBJECT");
2150 }
2151 else
2152 // other: stop looping
2153 fContinue = FALSE;
2154 } // end while (fContinue)
2155
2156 if (!(*pSearch))
2157 throw BSConfigExcpt(EXEEXCPT_SYNTAX, ustrExecute);
2158
2159 // pSearch now points to the first non-space
2160 // character which does not introduces a keyword;
2161 // check if this is a "|" separator
2162
2163 if (*pSearch == '|')
2164 // skip '|'
2165 pSearch++;
2166
2167 // skip following spaces
2168 while ( (*pSearch)
2169 && (*pSearch == ' ')
2170 )
2171 pSearch++;
2172
2173 // NOW we finally point to the executable
2174
2175 if (!(*pSearch))
2176 throw BSConfigExcpt(EXEEXCPT_SYNTAX, ustrExecute);
2177
2178 // separate executable and parameters:
2179 // This can be separated by another '|',
2180 // or a space.
2181
2182 // NOTE: The '|' separator is used by the "resolved"
2183 // logger, from which BSDeExecute instances are
2184 // created on de-install. But the documentation states
2185 // spaces should be used... as long as a user doesn't
2186 // use spaces in the (unresolved) filename, we're fine.
2187 // For example we get:
2188 // 1) on install: $(1)\install.cmd PARAMETER
2189 // works nicely, and $(1) may contain spaces.
2190 // 2) Logger stores C:\PATH1 WITH SPACES\install.cmd|PARAMETER
2191 // in database.
2192 // 3) on deinstall, BSDeExecutes get created, and
2193 // we now have nice separation and get PARAMETER
2194 // properly separated.
2195 PCSZ p;
2196 if (!(p = strchr(pSearch, '|')))
2197 p = strchr(pSearch, ' ');
2198 if (p)
2199 {
2200 const char *pSep = p;
2201 // we have a space --> parameters:
2202 while ( (*p)
2203 && (*p == ' ')
2204 )
2205 p++;
2206
2207 if (*p)
2208 {
2209 _ustrParams.assignUtf8(p);
2210 _ustrExecutable.assignUtf8(pSearch, pSep);
2211 }
2212 else
2213 _ustrExecutable.assignUtf8(pSearch);
2214 }
2215 else
2216 _ustrExecutable.assignUtf8(pSearch);
2217}
2218
2219/*
2220 *@@ DescribeType:
2221 * describes the current manipulator type to the GUI.
2222 *
2223 *@@added V0.9.9 (2001-03-27) [umoeller]
2224 */
2225
2226const char* BSExecute::DescribeType()
2227{
2228 return ("Execute program");
2229}
2230
2231/*
2232 *@@ DescribeData:
2233 * describes the current manipulator data to the GUI.
2234 *
2235 *@@added V0.9.9 (2001-03-27) [umoeller]
2236 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
2237 */
2238
2239ustring BSExecute::DescribeData()
2240{
2241 ustring ustr;
2242 ustr._printf("\"%s\"", _ustrExecutable.GetBuffer());
2243
2244 if (_ustrParams())
2245 {
2246 ustr.appendUtf8(" \"");
2247 ustr += _ustrParams;
2248 ustr.appendUtf8("\"");
2249 }
2250
2251 if (_ulExecType == 0)
2252 ustr.appendUtf8(" (no flags)");
2253 else
2254 {
2255 if (_ulExecType & CFGT_CFGSYS)
2256 ustr.appendUtf8(" CONFIGSYS");
2257 if (_ulExecType & CFGT_REGISTERCLASS)
2258 ustr.appendUtf8(" REGISTERCLASS");
2259 if (_ulExecType & CFGT_CREATEOBJECT)
2260 ustr.appendUtf8(" CREATEOBJECT");
2261 }
2262
2263 return (ustr);
2264}
2265
2266/*
2267 *@@ Execute:
2268 * executes the member program. This does not return
2269 * until the program terminates. As a result, do not
2270 * call this on a PM thread, because this gets blocked.
2271 *
2272 * Throws:
2273 * -- BSConfigExcpt.
2274 *
2275 *@@added V0.9.1 (2000-02-07) [umoeller]
2276 *@@changed V0.9.18 (2002-03-08) [umoeller]: added codec
2277 */
2278
2279int BSExecute::Execute(BSUniCodec &codecProcess, // in: codec for process codepage,
2280 BSFileLogger *pLogFile) // in: file logger (log file), can be NULL
2281{
2282 string strParams = "/c ";
2283 strParams.appendUtf8(&codecProcess, _ustrExecutable);
2284 if (_ustrParams())
2285 {
2286 strParams += " ";
2287 strParams.appendUtf8(&codecProcess, _ustrParams);
2288 }
2289
2290 ULONG sid = 0;
2291 PID pid = 0;
2292 if (_arc = doshQuickStartSession("cmd.exe",
2293 (PSZ)strParams.c_str(),
2294 FALSE, // foreground
2295 0, // auto-close, visible
2296 TRUE, // wait
2297 &sid,
2298 &pid,
2299 NULL))
2300 {
2301 if (pLogFile)
2302 pLogFile->Write("Error %d executing \"CMD.EXE %s\"",
2303 _arc,
2304 strParams.c_str());
2305
2306 throw BSConfigExcpt(EXEEXCPT_DOSERROR, _arc);
2307 }
2308
2309 if (pLogFile)
2310 pLogFile->Write("Executed \"CMD.EXE %s\"",
2311 strParams.c_str());
2312
2313 return (0);
2314}
2315
2316/* ******************************************************************
2317 *
2318 * BSDeExecute class
2319 *
2320 ********************************************************************/
2321
2322/*
2323 *@@ BSDeExecute:
2324 * constructor.
2325 *
2326 *@@added V0.9.16 (2001-12-08) [umoeller]
2327 */
2328
2329BSDeExecute::BSDeExecute(const ustring &ustrDeExecute)
2330 : BSExecute(ustrDeExecute, tBSDeExecute)
2331{
2332};
2333
2334/*
2335 *@@ DescribeType:
2336 * describes the current manipulator type to the GUI.
2337 *
2338 *@@added V0.9.2 (2000-02-19) [umoeller]
2339 */
2340
2341const char* BSDeExecute::DescribeType()
2342{
2343 return ("External program for deinstall");
2344}
2345
2346/*
2347 *@@ AddToUndoList:
2348 * static helper method to create BSDeExecute instances from
2349 * the specified logger instance.
2350 *
2351 * The new BSKillProcess objects are appended to
2352 * the specified list.
2353 *
2354 * This returns the number of items created.
2355 *
2356 * This isn't really an "Undo" method like the other
2357 * static AddToUndoList methods (for the other classes),
2358 * but has been named like this for conformity. This
2359 * is during package de-install to create the same
2360 * BSDeExecute list which was initially created from
2361 * the script so that processes can be killed during
2362 * de-install as well.
2363 *
2364 *@@added V0.9.9 (2001-03-27) [umoeller]
2365 */
2366
2367int BSDeExecute::AddToUndoList(list <BSConfigBase*> &List,
2368 BSDeExecuteResolvedLogger &logger)
2369{
2370 PSZ pszLogStart = logger._pabLogString,
2371 pszLogThis = pszLogStart;
2372 int iCount = 0;
2373
2374 while (pszLogThis < pszLogStart + logger._cbLogString)
2375 {
2376 ULONG cbLogThis = strlen(pszLogThis);
2377 ustring ustr;
2378 ustr.assignUtf8(pszLogThis);
2379 List.push_back(new BSDeExecute(ustr));
2380 pszLogThis += cbLogThis + 1; // go beyond null byte
2381 iCount++;
2382 }
2383
2384 return (iCount);
2385}
2386
2387/* ******************************************************************
2388 *
2389 * BSKillProcess class
2390 *
2391 ********************************************************************/
2392
2393/*
2394 *@@ BSKillProcess:
2395 *
2396 * Syntax:
2397 *
2398 + KILLPROCESS="filename"
2399 *
2400 * Throws:
2401 * -- BSConfigExcpt.
2402 *
2403 *@@added V0.9.1 (2000-02-12) [umoeller]
2404 */
2405
2406BSKillProcess::BSKillProcess(const ustring &ustrKillProcess)
2407 : BSConfigBase(CFGT_KILLPROCESS, tBSKillProcess)
2408{
2409 if (!ustrKillProcess())
2410 throw BSConfigExcpt(KILLEXCPT_SYNTAX, ustrKillProcess);
2411
2412 _ustrKillProcess = ustrKillProcess;
2413}
2414
2415/*
2416 *@@ DescribeType:
2417 * describes the current manipulator type to the GUI.
2418 *
2419 *@@added V0.9.4 (2000-07-01) [umoeller]
2420 */
2421
2422const char* BSKillProcess::DescribeType()
2423{
2424 return ("Kill process");
2425}
2426
2427/*
2428 *@@ DescribeData:
2429 * describes the current manipulator data to the GUI.
2430 *
2431 *@@added V0.9.4 (2000-07-01) [umoeller]
2432 *@@changed V0.9.18 (2002-03-08) [umoeller]: now returning ustring
2433 */
2434
2435ustring BSKillProcess::DescribeData()
2436{
2437 return _ustrKillProcess;
2438}
2439
2440/*
2441 *@@ AddToUndoList:
2442 * static helper method to create BSKillProcess
2443 * instances from the specified logger instance.
2444 *
2445 * The new BSKillProcess objects are appended to
2446 * the specified list.
2447 *
2448 * This returns the number of items created.
2449 *
2450 * This isn't really an "Undo" method like the other
2451 * static AddToUndoList methods (for the other classes),
2452 * but has been named like this for conformity. This
2453 * is during package de-install to create the same
2454 * BSKillProcess list which was initially created from
2455 * the script so that processes can be killed during
2456 * de-install as well.
2457 *
2458 *@@added V0.9.4 (2000-07-01) [umoeller]
2459 */
2460
2461int BSKillProcess::AddToUndoList(list<BSConfigBase*> &List,
2462 BSKillProcessAttrsLogger &logger)
2463{
2464 // the logger in this case has a simple list of PSZs with all
2465 // the executable names that were created, each of which is
2466 // terminated with a null character
2467
2468 PSZ pszLogStart = logger._pabLogString,
2469 pszLogThis = pszLogStart;
2470 int iCount = 0;
2471
2472 while (pszLogThis < pszLogStart + logger._cbLogString)
2473 {
2474 ULONG cbLogThis = strlen(pszLogThis);
2475 ustring ustr;
2476 ustr.assignUtf8(pszLogThis);
2477 List.push_back(new BSKillProcess(ustr));
2478 pszLogThis += cbLogThis + 1; // go beyond null byte
2479 iCount++;
2480 }
2481
2482 return (iCount);
2483}
2484
2485
Note: See TracBrowser for help on using the repository browser.