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

Last change on this file since 261 was 254, checked in by umoeller, 22 years ago

Minor fixes.

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