Coverage Report

Created: 2026-03-31 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dcmtk/ofstd/libsrc/ofcmdln.cc
Line
Count
Source
1
/*
2
 *
3
 *  Copyright (C) 1998-2024, OFFIS e.V.
4
 *  All rights reserved.  See COPYRIGHT file for details.
5
 *
6
 *  This software and supporting documentation were developed by
7
 *
8
 *    OFFIS e.V.
9
 *    R&D Division Health
10
 *    Escherweg 2
11
 *    D-26121 Oldenburg, Germany
12
 *
13
 *
14
 *  Module:  ofstd
15
 *
16
 *  Author:  Joerg Riesmeier
17
 *
18
 *  Purpose: Handle command line arguments (Source)
19
 *
20
 */
21
22
23
#include "dcmtk/config/osconfig.h"
24
25
#include "dcmtk/ofstd/ofcmdln.h"
26
#include "dcmtk/ofstd/ofstd.h"
27
#include "dcmtk/ofstd/ofcast.h"
28
#include "dcmtk/ofstd/ofchrenc.h"
29
30
#if defined(HAVE_WINDOWS_H) && !defined(__MINGW32__)
31
#define WIN32_LEAN_AND_MEAN
32
#include <windows.h>
33
#endif
34
35
/*---------------------*
36
 *  macro definitions  *
37
 *---------------------*/
38
39
0
#define COMMAND_FILE_PREFIX '@'
40
41
#ifdef DCMTK_USE_WCHAR_T
42
#define WIDE_COMMAND_FILE_PREFIX L'@'
43
#endif
44
45
46
/*----------------------------*
47
 *  constant initializations  *
48
 *----------------------------*/
49
50
const int OFCommandLine::PF_ExpandWildcards = 0x0001;  // not used anymore
51
const int OFCommandLine::PF_NoCommandFiles  = 0x0002;
52
53
const int OFCommandLine::AF_Exclusive       = 0x0001;
54
const int OFCommandLine::AF_Internal        = 0x0002;
55
const int OFCommandLine::AF_NoWarning       = 0x0004;
56
57
/*-----------------------*
58
 *  struct declarations  *
59
 *-----------------------*/
60
61
/*  Internal structure to store valid command line options.
62
 *  Options are command line arguments to use optional functions and to specify optional properties of a program.
63
 *  They are all starting with one or more special characters and can therefore be detected.
64
 */
65
struct OFCmdOption
66
{
67
68
    /** constructor
69
     *
70
     ** @param  longOpt     long option name
71
     *  @param  shortOpt    short option name
72
     *  @param  valueCount  number of additional values
73
     *  @param  valueDescr  description of optional values
74
     *  @param  optDescr    description of command line option
75
     *  @param  flags       flags (see AF_xxx)
76
     */
77
    OFCmdOption(const char *longOpt,
78
                const char *shortOpt,
79
                const int valueCount,
80
                const char *valueDescr,
81
                const char *optDescr,
82
                const int flags)
83
0
      : LongOption(longOpt),
84
0
        ShortOption(shortOpt),
85
0
        ValueCount(valueCount),
86
0
        ValueDescription(valueDescr),
87
0
        OptionDescription(optDescr),
88
0
        Flags(flags),
89
0
        Checked(OFFalse)
90
0
    {
91
0
    }
92
93
    /** destructor
94
     */
95
    ~OFCmdOption()
96
0
    {
97
#ifdef DEBUG
98
        if (!Checked && !(Flags & (OFCommandLine::AF_Exclusive | OFCommandLine::AF_NoWarning)) && !LongOption.empty())
99
        {
100
            ofConsole.lockCerr() << "WARNING: option " << LongOption << " has possibly never been checked !" << OFendl;
101
            ofConsole.unlockCerr();
102
        }
103
#endif
104
0
    }
105
106
    /// long option name
107
    const OFString LongOption;
108
    /// short option name
109
    const OFString ShortOption;
110
    /// number of additional values
111
    const int ValueCount;
112
    /// description of optional values
113
    const OFString ValueDescription;
114
    /// description of command line option
115
    const OFString OptionDescription;
116
    /// flags (see AF_xxx)
117
    const int Flags;
118
    /// OFTrue if findOption has been applied to this option
119
    OFBool Checked;
120
121
private:
122
123
    /// private undefined copy assignment operator
124
    OFCmdOption& operator=(const OFCmdOption& arg);
125
};
126
127
128
/*  Internal structure to handle position of command line parameters.
129
 *  Parameters are all command line arguments which are no options (e.g. file names).
130
 */
131
struct OFCmdParamPos
132
{
133
134
    /** constructor
135
     *
136
     ** @param  parIter    iterator pointing to a specific parameter
137
     *  @param  optIter    iterator pointing to first option iterator in front of the parameter
138
     *  @param  optCount   number of options in front of the parameter
139
     *  @param  directOpt  number of options which are direct predecessor in the argument list
140
     */
141
    OFCmdParamPos(const OFListIterator(OFString) &parIter,
142
                  const OFListIterator(OFListIterator_OFString) &optIter,
143
                  const int optCount,
144
                  const int directOpt)
145
0
      : ParamIter(parIter),
146
0
        OptionIter(optIter),
147
0
        OptionCount(optCount),
148
0
        DirectOption(directOpt)
149
0
    {
150
0
    }
151
152
    /// iterator pointing to a specific parameter
153
    const OFListIterator(OFString) ParamIter;
154
    /// iterator pointing to first option iterator in front of the parameter
155
    const OFListIterator(OFListIterator_OFString) OptionIter;
156
    /// number of options in front of the parameter
157
    const int OptionCount;
158
    /// number of options which are direct predecessor in the argument list
159
    const int DirectOption;
160
161
private:
162
163
    /// private undefined copy assignment operator
164
    OFCmdParamPos& operator=(const OFCmdParamPos& arg);
165
};
166
167
168
/*------------------*
169
 *  implementation  *
170
 *------------------*/
171
172
OFCommandLine::OFCommandLine()
173
0
  : ProgramName(),
174
0
    ValidOptionList(),
175
0
    ValidParamList(),
176
0
    ArgumentList(),
177
0
    ArgumentIterator(),
178
0
    ParamPosList(),
179
0
    ParamPosNumber(0),
180
0
    ParamPosIterator(),
181
0
    OptionPosList(),
182
0
    OptionPosIterator(),
183
0
    OptionBlockIterator(),
184
0
    OptionBlockMode(OFFalse),
185
0
    OptionChars("+-"),
186
0
    ExclusiveOption(OFFalse),
187
0
    WideCharMode(OFFalse),
188
0
    LongColumn(0),
189
0
    ShortColumn(0),
190
0
    ParamColumn(0),
191
0
    MinParamCount(0),
192
0
    MaxParamCount(0),
193
0
    LastParamMode(OFCmdParam::PM_Mandatory)
194
0
{
195
0
}
196
197
198
OFCommandLine::~OFCommandLine()
199
0
{
200
0
    OFListIterator(OFCmdOption *) first_o = ValidOptionList.begin();
201
0
    const OFListIterator(OFCmdOption *) last_o = ValidOptionList.end();
202
0
    while (first_o != last_o)
203
0
    {
204
        /* avoid wrong warning message */
205
0
        if (ExclusiveOption)
206
0
            (*first_o)->Checked = OFTrue;
207
        /* delete object and remove from list */
208
0
        delete (*first_o);
209
0
        first_o = ValidOptionList.erase(first_o);
210
0
    }
211
0
    OFListIterator(OFCmdParam *) first_p = ValidParamList.begin();
212
0
    const OFListIterator(OFCmdParam *) last_p = ValidParamList.end();
213
0
    while (first_p != last_p)
214
0
    {
215
0
        delete (*first_p);
216
0
        first_p = ValidParamList.erase(first_p);
217
0
    }
218
0
    OFListIterator(OFCmdParamPos *) first_pp = ParamPosList.begin();
219
0
    const OFListIterator(OFCmdParamPos *) last_pp = ParamPosList.end();
220
0
    while (first_pp != last_pp)
221
0
    {
222
0
        delete (*first_pp);
223
0
        first_pp = ParamPosList.erase(first_pp);
224
0
    }
225
0
}
226
227
228
void OFCommandLine::setOptionChars(const char *chars)
229
0
{
230
0
    OptionChars = chars;
231
0
}
232
233
234
void OFCommandLine::setOptionColumns(const int longCols,
235
                                     const int shortCols)
236
0
{
237
0
    LongColumn = longCols;
238
0
    ShortColumn = shortCols;
239
0
}
240
241
242
void OFCommandLine::setParamColumn(const int column)
243
0
{
244
0
    ParamColumn = column;
245
0
}
246
247
248
OFBool OFCommandLine::checkOption(const OFString &option,
249
                                  const OFBool mode) const
250
0
{
251
0
    OFBool result = mode;
252
0
    const size_t optionLen = option.length();
253
0
    if (optionLen > 0)                                                   // empty strings are allowed to support (sub)groups
254
0
    {
255
0
        result = OFFalse;
256
0
        if (optionLen >= 2)
257
0
        {
258
0
            if (OptionChars.find(option.at(0)) != OFString_npos)         // options have to start with one of the defined chars
259
0
            {
260
0
                if (((option.at(0) != '-') && (option.at(0) != '+')) ||  // but when starting with sign character ...
261
0
                    (option.at(1) < '0') || (option.at(1) > '9'))        // ... don't allow a number as the following character
262
0
                {
263
0
                    result = OFTrue;
264
0
                }
265
0
            }
266
0
        }
267
0
    }
268
0
    return result;
269
0
}
270
271
void OFCommandLine::addGeneralOptions(const int longCols,
272
                                      const int shortCols)
273
0
{
274
0
    addGroup("general options:", longCols, shortCols + 2);
275
0
        addOption("--help",    "-h", "print this help text and exit",      OFCommandLine::AF_Exclusive);
276
0
        addOption("--version",       "print version information and exit", OFCommandLine::AF_Exclusive);
277
0
}
278
279
OFBool OFCommandLine::addOption(const char *longOpt,
280
                                const char *shortOpt,
281
                                const int valueCount,
282
                                const char *valueDescr,
283
                                const char *optDescr,
284
                                const int flags)
285
0
{
286
0
    if (checkOption(longOpt) && checkOption(shortOpt))
287
0
    {
288
#ifdef DEBUG
289
        if (strlen(longOpt) > 0)
290
        {
291
            OFListIterator(OFCmdOption *) iter = ValidOptionList.begin();
292
            const OFListIterator(OFCmdOption *) last = ValidOptionList.end();
293
            while (iter != last)
294
            {
295
                if ((*iter)->LongOption == longOpt)
296
                {
297
                    ofConsole.lockCerr() << "WARNING: long option " << longOpt << " already defined ... not added !" << OFendl;
298
                    ofConsole.unlockCerr();
299
                    return OFFalse;
300
                }
301
                if ((strlen(shortOpt) > 0) && ((*iter)->ShortOption == shortOpt))
302
                {
303
                    ofConsole.lockCerr() << "WARNING: short option " << shortOpt << " already defined for " << (*iter)->LongOption
304
                                         << " ..." << OFendl << "         option " << longOpt << " not added !" << OFendl;
305
                    ofConsole.unlockCerr();
306
                    return OFFalse;
307
                }
308
                ++iter;
309
            }
310
        }
311
#endif
312
0
        OFCmdOption *opt = new OFCmdOption(longOpt, shortOpt, valueCount, valueDescr, optDescr, flags);
313
0
        if (opt != NULL)
314
0
        {
315
0
            ValidOptionList.push_back(opt);
316
0
            return OFTrue;
317
0
        }
318
0
    }
319
#ifdef DEBUG
320
    ofConsole.lockCerr() << "WARNING: invalid option " << shortOpt << "/" <<longOpt << " ... not added !" << OFendl;
321
    ofConsole.unlockCerr();
322
#endif
323
0
    return OFFalse;
324
0
}
325
326
327
OFBool OFCommandLine::addOption(const char *longOpt,
328
                                const char *shortOpt,
329
                                const char *optDescr,
330
                                const int flags)
331
0
{
332
0
    return addOption(longOpt, shortOpt, 0, "", optDescr, flags);
333
0
}
334
335
336
OFBool OFCommandLine::addOption(const char *longOpt,
337
                                const int valueCount,
338
                                const char *valueDescr,
339
                                const char *optDescr,
340
                                const int flags)
341
0
{
342
0
    return addOption(longOpt, "", valueCount, valueDescr, optDescr, flags);
343
0
}
344
345
346
OFBool OFCommandLine::addOption(const char *longOpt,
347
                                const char *optDescr,
348
                                const int flags)
349
0
{
350
0
    return addOption(longOpt, "", 0, "", optDescr, flags);
351
0
}
352
353
354
void OFCommandLine::addGroup(const char *name,
355
                             const int longCols,
356
                             const int shortCols)
357
0
{
358
0
    addOption("", "", packColumnValues(longCols, shortCols), "", name);
359
0
}
360
361
362
void OFCommandLine::addSubGroup(const char *name,
363
                                const int longCols,
364
                                const int shortCols)
365
0
{
366
0
    addOption("", "", packColumnValues(longCols, shortCols), name, "");
367
0
}
368
369
370
OFBool OFCommandLine::addParam(const char *param,
371
                               const char *descr,
372
                               const OFCmdParam::E_ParamMode mode)
373
0
{
374
0
    if (param != NULL)
375
0
    {
376
#ifdef DEBUG
377
        switch (LastParamMode)
378
        {
379
            case OFCmdParam::PM_Optional:
380
                if ((mode != OFCmdParam::PM_Optional) && (mode != OFCmdParam::PM_MultiOptional))
381
                {
382
                    ofConsole.lockCerr() << "WARNING: " << ValidParamList.size() << ". parameter is optional => hides "
383
                                         << param << " !" << OFendl;
384
                    ofConsole.unlockCerr();
385
                }
386
                break;
387
/*
388
            case OFCmdParam::PM_MultiMandatory:
389
                {
390
                    ofConsole.lockCerr() << "WARNING: " << ValidParamList.size() << ". parameter is multi-mandatory => hides "
391
                                         << param << " !" << OFendl;
392
                    ofConsole.unlockCerr();
393
                }
394
                break;
395
*/
396
            case OFCmdParam::PM_MultiOptional:
397
                {
398
                    ofConsole.lockCerr() << "WARNING: " << ValidParamList.size() << ". parameter is multi-optional => hides "
399
                                         << param << " !" << OFendl;
400
                    ofConsole.unlockCerr();
401
                }
402
                break;
403
            default:
404
                break;
405
        }
406
        LastParamMode = mode;
407
#endif
408
0
        OFCmdParam *par = new OFCmdParam(param, descr, mode);
409
0
        if (par != NULL)
410
0
        {
411
0
            ValidParamList.push_back(par);
412
0
            return OFTrue;
413
0
        }
414
0
    }
415
0
    return OFFalse;
416
0
}
417
418
419
OFBool OFCommandLine::addParam(const char *param,
420
                               const OFCmdParam::E_ParamMode mode)
421
0
{
422
0
    return addParam(param, "", mode);
423
0
}
424
425
426
OFBool OFCommandLine::gotoFirstArg()
427
0
{
428
0
    ArgumentIterator = ArgumentList.begin();
429
0
    return ArgumentIterator != ArgumentList.end();
430
0
}
431
432
433
OFBool OFCommandLine::gotoNextArg()
434
0
{
435
0
    if (ArgumentIterator != ArgumentList.end())
436
0
        return ++ArgumentIterator != ArgumentList.end();
437
0
    return OFFalse;
438
0
}
439
440
441
OFBool OFCommandLine::getCurrentArg(const char *&arg)
442
0
{
443
0
    if (ArgumentIterator != ArgumentList.end())
444
0
        return strlen(arg = (*ArgumentIterator).c_str()) > 0;
445
0
    return OFFalse;
446
447
0
}
448
449
450
OFBool OFCommandLine::getCurrentArg(OFCmdString &arg)
451
0
{
452
0
    if (ArgumentIterator != ArgumentList.end())
453
0
        return !(arg = *ArgumentIterator).empty();
454
0
    return OFFalse;
455
456
0
}
457
458
459
OFBool OFCommandLine::getLastArg(OFString &arg)
460
0
{
461
0
    if (!ArgumentList.empty())
462
0
        return !(arg = ArgumentList.back()).empty();
463
0
    return OFFalse;
464
0
}
465
466
467
OFBool OFCommandLine::findParam(const int pos)
468
0
{
469
0
    OFListIterator(OFCmdParamPos *) iter;
470
0
    return findParam(pos, iter);
471
0
}
472
473
474
OFBool OFCommandLine::findParam(const int pos,
475
                                OFListIterator(OFCmdParamPos *) &pos_iter)
476
0
{
477
0
    if ((pos > 0) && (pos <= getParamCount()))
478
0
    {
479
0
        int counter;
480
0
        if ((ParamPosNumber > 0) && (pos >= ParamPosNumber))     // can we start from previous position?
481
0
        {
482
0
            counter = pos - ParamPosNumber + 1;
483
0
            pos_iter = ParamPosIterator;
484
0
        } else {                                                 // if not, start from beginning
485
0
            counter = pos;
486
0
            pos_iter = ParamPosList.begin();
487
0
        }
488
0
        const OFListIterator(OFCmdParamPos *) pos_last = ParamPosList.end();
489
0
        while (pos_iter != pos_last)
490
0
        {
491
0
            ArgumentIterator = (*pos_iter)->ParamIter;
492
0
            if (--counter == 0)
493
0
            {
494
0
                ParamPosNumber = pos;                            // if found, store current position
495
0
                ParamPosIterator = pos_iter;
496
0
                return OFTrue;
497
0
            }
498
0
            ++pos_iter;
499
0
        }
500
0
    }
501
0
    return OFFalse;
502
0
}
503
504
505
OFCommandLine::E_ParamValueStatus OFCommandLine::getParam(const int pos,
506
                                                          OFCmdSignedInt &value)
507
0
{
508
0
    if (findParam(pos))
509
0
    {
510
0
        if (sscanf((*ArgumentIterator).c_str(), "%li", &value) == 1)
511
0
            return PVS_Normal;
512
0
        return PVS_Invalid;
513
0
    }
514
0
    return PVS_CantFind;
515
0
}
516
517
518
OFCommandLine::E_ParamValueStatus OFCommandLine::getParamAndCheckMin(const int pos,
519
                                                                     OFCmdSignedInt &value,
520
                                                                     const OFCmdSignedInt low,
521
                                                                     const OFExplicitBool incl)
522
0
{
523
0
    E_ParamValueStatus status = getParam(pos, value);
524
0
    if (status == PVS_Normal)
525
0
    {
526
0
        if ((value < low) || (!incl && (value == low)))
527
0
            return PVS_Underflow;
528
0
    }
529
0
    return status;
530
0
}
531
532
533
OFCommandLine::E_ParamValueStatus OFCommandLine::getParamAndCheckMinMax(const int pos,
534
                                                                        OFCmdSignedInt &value,
535
                                                                        const OFCmdSignedInt low,
536
                                                                        const OFCmdSignedInt high)
537
0
{
538
0
    E_ParamValueStatus status = getParam(pos, value);
539
0
    if (status == PVS_Normal)
540
0
    {
541
0
        if (value < low)
542
0
            return PVS_Underflow;
543
0
        else if (value > high)
544
0
            return PVS_Overflow;
545
0
    }
546
0
    return status;
547
0
}
548
549
550
OFCommandLine::E_ParamValueStatus OFCommandLine::getParam(const int pos,
551
                                                          OFCmdUnsignedInt &value)
552
0
{
553
0
    if (findParam(pos))
554
0
    {
555
0
        if (sscanf((*ArgumentIterator).c_str(), "%lu", &value) == 1)
556
0
            return PVS_Normal;
557
0
        return PVS_Invalid;
558
0
    }
559
0
    return PVS_CantFind;
560
0
}
561
562
563
OFCommandLine::E_ParamValueStatus OFCommandLine::getParamAndCheckMin(const int pos,
564
                                                                     OFCmdUnsignedInt &value,
565
                                                                     const OFCmdUnsignedInt low,
566
                                                                     const OFExplicitBool incl)
567
0
{
568
0
    E_ParamValueStatus status = getParam(pos, value);
569
0
    if (status == PVS_Normal)
570
0
    {
571
0
        if ((value < low) || (!incl && (value == low)))
572
0
            return PVS_Underflow;
573
0
    }
574
0
    return status;
575
0
}
576
577
578
OFCommandLine::E_ParamValueStatus OFCommandLine::getParamAndCheckMinMax(const int pos,
579
                                                                        OFCmdUnsignedInt &value,
580
                                                                        const OFCmdUnsignedInt low,
581
                                                                        const OFCmdUnsignedInt high)
582
0
{
583
0
    E_ParamValueStatus status = getParam(pos, value);
584
0
    if (status == PVS_Normal)
585
0
    {
586
0
        if (value < low)
587
0
            return PVS_Underflow;
588
0
        else if (value > high)
589
0
            return PVS_Overflow;
590
0
    }
591
0
    return status;
592
0
}
593
594
595
OFCommandLine::E_ParamValueStatus OFCommandLine::getParam(const int pos,
596
                                                          OFCmdFloat &value)
597
0
{
598
0
    if (findParam(pos))
599
0
    {
600
0
        OFBool success = OFFalse;
601
0
        value = OFStandard::atof((*ArgumentIterator).c_str(), &success);
602
0
        if (success) return PVS_Normal;
603
0
        return PVS_Invalid;
604
0
    }
605
0
    return PVS_CantFind;
606
0
}
607
608
609
OFCommandLine::E_ParamValueStatus OFCommandLine::getParamAndCheckMin(const int pos,
610
                                                                     OFCmdFloat &value,
611
                                                                     const OFCmdFloat low,
612
                                                                     const OFExplicitBool incl)
613
0
{
614
0
    E_ParamValueStatus status = getParam(pos, value);
615
0
    if (status == PVS_Normal)
616
0
    {
617
0
        if ((value < low) || (!incl && (value == low)))
618
0
            return PVS_Underflow;
619
0
    }
620
0
    return status;
621
0
}
622
623
624
OFCommandLine::E_ParamValueStatus OFCommandLine::getParamAndCheckMinMax(const int pos,
625
                                                                        OFCmdFloat &value,
626
                                                                        const OFCmdFloat low,
627
                                                                        const OFCmdFloat high)
628
0
{
629
0
    E_ParamValueStatus status = getParam(pos, value);
630
0
    if (status == PVS_Normal)
631
0
    {
632
0
        if (value < low)
633
0
            return PVS_Underflow;
634
0
        else if (value > high)
635
0
            return PVS_Overflow;
636
0
    }
637
0
    return status;
638
0
}
639
640
641
OFCommandLine::E_ParamValueStatus OFCommandLine::getParam(const int pos,
642
                                                          const char *&value)
643
0
{
644
0
    if (findParam(pos))
645
0
    {
646
0
        value = (*ArgumentIterator).c_str();
647
0
        if (strlen(value) > 0)
648
0
            return PVS_Normal;
649
0
        return PVS_Empty;
650
0
    }
651
0
    return PVS_CantFind;
652
0
}
653
654
655
OFCommandLine::E_ParamValueStatus OFCommandLine::getParam(const int pos,
656
                                                          OFCmdString &value)
657
0
{
658
0
    if (findParam(pos))
659
0
    {
660
0
        value = *ArgumentIterator;
661
0
        if (!value.empty())
662
0
            return PVS_Normal;
663
0
        return PVS_Empty;
664
0
    }
665
0
    return PVS_CantFind;
666
0
}
667
668
669
OFCommandLine::E_ParamValueStatus OFCommandLine::getParam(const int pos,
670
                                                          OFFilename &filename)
671
0
{
672
0
    OFString value;
673
0
    E_ParamValueStatus status = getParam(pos, value);
674
0
    if (status != PVS_CantFind)
675
0
    {
676
0
        if (status != PVS_Empty)
677
0
            filename.set(value, WideCharMode /* convert */);
678
0
        else
679
0
            filename.clear();
680
0
    }
681
0
    return status;
682
0
}
683
684
685
OFBool OFCommandLine::findOption(const char *longOpt,
686
                                 const signed int pos,
687
                                 const E_FindOptionMode mode)
688
0
{
689
#ifdef DEBUG
690
    OFListIterator(OFCmdOption *) iter = ValidOptionList.begin();
691
    const OFListIterator(OFCmdOption *) last = ValidOptionList.end();
692
    while (iter != last)
693
    {
694
        if ((*iter)->LongOption == longOpt)
695
        {
696
            (*iter)->Checked = OFTrue;
697
            break;
698
        }
699
        ++iter;
700
    }
701
    if (iter == last)
702
    {
703
        ofConsole.lockCerr() << "WARNING: unknown option " << longOpt << " in OFCommandLine::findOption() !" << OFendl;
704
        ofConsole.unlockCerr();
705
        return OFFalse;
706
    }
707
#endif
708
    // reverse direction (left to right)
709
0
    if ((mode == FOM_FirstFromLeft) || (mode == FOM_NextFromLeft))
710
0
    {
711
#ifdef DEBUG
712
        if (pos != 0)
713
        {
714
            ofConsole.lockCerr() << "WARNING: OFCommandLine::findOption() parameter 'pos' (" << pos << ") ignored !" << OFendl;
715
            ofConsole.unlockCerr();
716
        }
717
#endif
718
0
        OFListIterator(OFListIterator_OFString) pos_iter = OptionPosList.begin();
719
0
        const OFListIterator(OFListIterator_OFString) pos_end = OptionPosList.end();
720
0
        if (mode == FOM_NextFromLeft)
721
0
            pos_iter = (OptionPosIterator == pos_end) ? pos_end : ++OptionPosIterator;
722
0
        while (pos_iter != pos_end)
723
0
        {
724
0
            ArgumentIterator = *pos_iter;
725
0
            if (*ArgumentIterator == longOpt)                              // searched option
726
0
            {
727
0
                OptionPosIterator = pos_iter;                              // store option position
728
0
                return OFTrue;
729
0
            }
730
0
            pos_iter++;
731
0
        }
732
0
    } else {
733
        // normal direction (right to left)
734
0
        OFListIterator(OFListIterator_OFString) pos_iter = (mode == FOM_Next) ? OptionPosIterator : OptionPosList.end();
735
0
        const OFListIterator(OFListIterator_OFString) pos_first = OptionPosList.begin();
736
0
        OFListIterator(OFCmdParamPos *) param_iter;
737
0
        int diropt = 0;
738
0
        if (findParam(abs(pos), param_iter))                               // go to specified parameter position
739
0
        {
740
0
            diropt = (*param_iter)->DirectOption;                          // number of direct predecessors
741
0
            if (((*param_iter)->OptionCount == 0) ||                       // no options in front of specified parameter or
742
0
                ((pos < 0) && (diropt == 0)))                              // no 'direct' option ...
743
0
                    return OFFalse;
744
0
            pos_iter = (*param_iter)->OptionIter;                          // first option in front of parameter
745
0
            ++pos_iter;                                                    // goto next to facilitate loop condition
746
0
        }
747
0
        while (pos_iter != pos_first)
748
0
        {
749
0
            ArgumentIterator = *(--pos_iter);
750
0
            if (OptionBlockMode && (pos_iter == OptionBlockIterator))      // new option is in front of alternative block option
751
0
                return OFFalse;
752
0
            else if (*ArgumentIterator == longOpt)                         // searched option
753
0
            {
754
0
                OptionPosIterator = pos_iter;                              // store option position
755
0
                if (mode == FOM_Normal)
756
0
                    OptionBlockIterator = pos_iter;
757
0
                return OFTrue;
758
0
            }
759
0
            else if ((pos < 0) && (--diropt <= 0))                         // search only for the direct predecessor
760
0
                return OFFalse;
761
0
        }
762
0
    }
763
0
    return OFFalse;
764
0
}
765
766
767
OFBool OFCommandLine::gotoFirstOption()
768
0
{
769
0
    OptionPosIterator = OptionPosList.begin();
770
0
    if (OptionPosIterator != OptionPosList.end())
771
0
    {
772
0
        ArgumentIterator = *OptionPosIterator;
773
0
        return OFTrue;
774
0
    }
775
0
    return OFFalse;
776
0
}
777
778
779
OFBool OFCommandLine::gotoNextOption()
780
0
{
781
0
    if (OptionPosIterator != OptionPosList.end())
782
0
    {
783
0
        if (++OptionPosIterator != OptionPosList.end())
784
0
        {
785
0
            ArgumentIterator = *OptionPosIterator;
786
0
            return OFTrue;
787
0
        }
788
0
    }
789
0
    return OFFalse;
790
0
}
791
792
793
OFBool OFCommandLine::getCurrentOption(const char *&opt)
794
0
{
795
0
    if (OptionPosIterator != OptionPosList.end())
796
0
        return (opt = (**OptionPosIterator).c_str())[0] != '\0';
797
0
    return OFFalse;
798
0
}
799
800
801
OFBool OFCommandLine::getCurrentOption(OFCmdString &opt)
802
0
{
803
0
    if (OptionPosIterator != OptionPosList.end())
804
0
        return !(opt = **OptionPosIterator).empty();
805
0
    return OFFalse;
806
0
}
807
808
809
void OFCommandLine::beginOptionBlock()
810
0
{
811
0
    OptionBlockIterator = OptionPosList.end();
812
0
    OptionBlockMode = OFTrue;
813
0
}
814
815
816
void OFCommandLine::endOptionBlock()
817
0
{
818
0
    OptionBlockMode = OFFalse;
819
0
}
820
821
822
OFCommandLine::E_ValueStatus OFCommandLine::getValue(OFCmdSignedInt &value)
823
0
{
824
0
    if (++ArgumentIterator != ArgumentList.end())
825
0
    {
826
0
        if (sscanf((*ArgumentIterator).c_str(), "%li", &value) == 1)
827
0
            return VS_Normal;
828
0
        return VS_Invalid;
829
0
    }
830
0
    return VS_NoMore;
831
0
}
832
833
834
OFCommandLine::E_ValueStatus OFCommandLine::getValueAndCheckMin(OFCmdSignedInt &value,
835
                                                                const OFCmdSignedInt low,
836
                                                                const OFExplicitBool incl)
837
0
{
838
0
    E_ValueStatus status = getValue(value);
839
0
    if (status == VS_Normal)
840
0
    {
841
0
        if ((value < low) || (!incl && (value == low)))
842
0
            return VS_Underflow;
843
0
    }
844
0
    return status;
845
0
}
846
847
848
OFCommandLine::E_ValueStatus OFCommandLine::getValueAndCheckMinMax(OFCmdSignedInt &value,
849
                                                                   const OFCmdSignedInt low,
850
                                                                   const OFCmdSignedInt high)
851
0
{
852
0
    E_ValueStatus status = getValue(value);
853
0
    if (status == VS_Normal)
854
0
    {
855
0
        if (value < low)
856
0
            return VS_Underflow;
857
0
        else if (value > high)
858
0
            return VS_Overflow;
859
0
    }
860
0
    return status;
861
0
}
862
863
864
OFCommandLine::E_ValueStatus OFCommandLine::getValue(OFCmdUnsignedInt &value)
865
0
{
866
0
    if (++ArgumentIterator != ArgumentList.end())
867
0
    {
868
0
        OFString &strVal = *ArgumentIterator;
869
0
        if (sscanf(strVal.c_str(), "%lu", &value) == 1)
870
0
        {
871
            // skip leading spaces
872
0
            size_t strPos = strVal.find_first_not_of(' ');
873
            // check for minus sign (negative number)
874
0
            if ((strPos != OFString_npos) && (strVal.at(strPos) != '-'))
875
0
                return VS_Normal;
876
0
        }
877
0
        return VS_Invalid;
878
0
    }
879
0
    return VS_NoMore;
880
0
}
881
882
883
OFCommandLine::E_ValueStatus OFCommandLine::getValueAndCheckMin(OFCmdUnsignedInt &value,
884
                                                                const OFCmdUnsignedInt low,
885
                                                                const OFExplicitBool incl)
886
0
{
887
0
    E_ValueStatus status = getValue(value);
888
0
    if (status == VS_Normal)
889
0
    {
890
0
        if ((value < low) || (!incl && (value == low)))
891
0
            return VS_Underflow;
892
0
    }
893
0
    return status;
894
0
}
895
896
897
OFCommandLine::E_ValueStatus OFCommandLine::getValueAndCheckMinMax(OFCmdUnsignedInt &value,
898
                                                                   const OFCmdUnsignedInt low,
899
                                                                   const OFCmdUnsignedInt high)
900
0
{
901
0
    E_ValueStatus status = getValue(value);
902
0
    if (status == VS_Normal)
903
0
    {
904
0
        if (value < low)
905
0
            return VS_Underflow;
906
0
        else if (value > high)
907
0
            return VS_Overflow;
908
0
    }
909
0
    return status;
910
0
}
911
912
913
OFCommandLine::E_ValueStatus OFCommandLine::getValue(OFCmdFloat &value)
914
0
{
915
0
    if (++ArgumentIterator != ArgumentList.end())
916
0
    {
917
0
        OFBool success = OFFalse;
918
0
        value = OFStandard::atof((*ArgumentIterator).c_str(), &success);
919
0
        if (success) return VS_Normal;
920
0
        return VS_Invalid;
921
0
    }
922
0
    return VS_NoMore;
923
0
}
924
925
926
OFCommandLine::E_ValueStatus OFCommandLine::getValueAndCheckMin(OFCmdFloat &value,
927
                                                                const OFCmdFloat low,
928
                                                                const OFExplicitBool incl)
929
0
{
930
0
    E_ValueStatus status = getValue(value);
931
0
    if (status == VS_Normal)
932
0
    {
933
0
        if ((value < low) || (!incl && (value == low)))
934
0
            return VS_Underflow;
935
0
    }
936
0
    return status;
937
0
}
938
939
940
OFCommandLine::E_ValueStatus OFCommandLine::getValueAndCheckMinMax(OFCmdFloat &value,
941
                                                                   const OFCmdFloat low,
942
                                                                   const OFCmdFloat high)
943
0
{
944
0
    E_ValueStatus status = getValue(value);
945
0
    if (status == VS_Normal)
946
0
    {
947
0
        if (value < low)
948
0
            return VS_Underflow;
949
0
        else if (value > high)
950
0
            return VS_Overflow;
951
0
    }
952
0
    return status;
953
0
}
954
955
956
OFCommandLine::E_ValueStatus OFCommandLine::getValue(const char *&value)
957
0
{
958
0
    if (++ArgumentIterator != ArgumentList.end())
959
0
    {
960
0
        value = (*ArgumentIterator).c_str();
961
0
        if (strlen(value) > 0)
962
0
            return VS_Normal;
963
0
        return VS_Empty;
964
0
    }
965
0
    return VS_NoMore;
966
0
}
967
968
969
OFCommandLine::E_ValueStatus OFCommandLine::getValue(OFCmdString &value)
970
0
{
971
0
    if (++ArgumentIterator != ArgumentList.end())
972
0
    {
973
0
        value = *ArgumentIterator;
974
0
        if (!value.empty())
975
0
            return VS_Normal;
976
0
        return VS_Empty;
977
0
    }
978
0
    return VS_NoMore;
979
0
}
980
981
982
OFCommandLine::E_ValueStatus OFCommandLine::getValue(OFFilename &filename)
983
0
{
984
0
    if (++ArgumentIterator != ArgumentList.end())
985
0
    {
986
0
        OFString strValue = *ArgumentIterator;
987
0
        if (!strValue.empty())
988
0
        {
989
0
            filename.set(strValue, WideCharMode /* convert */);
990
0
            return VS_Normal;
991
0
        } else
992
0
            filename.clear();
993
0
        return VS_Empty;
994
0
    }
995
0
    return VS_NoMore;
996
0
}
997
998
999
const OFCmdOption *OFCommandLine::findCmdOption(const OFString &option) const
1000
0
{
1001
0
    OFListConstIterator(OFCmdOption *) iter = ValidOptionList.begin();
1002
0
    OFListConstIterator(OFCmdOption *) last = ValidOptionList.end();
1003
0
    while (iter != last)
1004
0
    {
1005
0
        if (((*iter)->LongOption == option) || ((*iter)->ShortOption == option))
1006
0
            return *iter;
1007
0
        ++iter;
1008
0
    }
1009
0
    return NULL;
1010
0
}
1011
1012
1013
void OFCommandLine::storeParameter(const OFString &param,
1014
                                   const int directOpt)
1015
0
{
1016
0
    ArgumentList.push_back(param);
1017
0
    const OFListIterator(OFListIterator_OFString) iter = (OptionPosList.size() == 0) ? OptionPosList.end() : --OptionPosList.end();
1018
0
    OFCmdParamPos *paramPos = new OFCmdParamPos(--ArgumentList.end(), iter, OFstatic_cast(int, OptionPosList.size()), directOpt);
1019
0
    if (paramPos != NULL)
1020
0
        ParamPosList.push_back(paramPos);
1021
0
}
1022
1023
1024
int OFCommandLine::packColumnValues(int longCols,
1025
                                    int shortCols) const
1026
0
{
1027
0
    if (longCols < 0)
1028
0
        longCols = 0;
1029
0
    if (shortCols < 0)
1030
0
        shortCols = 0;
1031
0
    return ((longCols & 0xffff) << 16) | (shortCols & 0xffff);
1032
0
}
1033
1034
1035
void OFCommandLine::unpackColumnValues(const int value,
1036
                                       unsigned int &longCols,
1037
                                       unsigned int &shortCols) const
1038
0
{
1039
0
    longCols = (value == 0) ? LongColumn : (value >> 16) & 0xffff;
1040
0
    shortCols = (value == 0) ? ShortColumn : (value & 0xffff);
1041
0
}
1042
1043
1044
OFCommandLine::E_ParseStatus OFCommandLine::checkParamCount()
1045
0
{
1046
0
    MinParamCount = 0;
1047
0
    MaxParamCount = 0;
1048
0
    OFListIterator(OFCmdParam *) iter = ValidParamList.begin();
1049
0
    const OFListIterator(OFCmdParam *) last = ValidParamList.end();
1050
0
    while (iter != last)
1051
0
    {
1052
0
        if (!(*iter)->ParamName.empty())
1053
0
        {
1054
0
            switch ((*iter)->ParamMode)
1055
0
            {
1056
0
                case OFCmdParam::PM_Mandatory:
1057
0
                    MinParamCount++;
1058
0
                    if (MaxParamCount >= 0)
1059
0
                        MaxParamCount++;
1060
0
                    break;
1061
0
                case OFCmdParam::PM_MultiMandatory:
1062
0
                    MinParamCount++;
1063
0
                    MaxParamCount = -1;
1064
0
                    break;
1065
0
                case OFCmdParam::PM_Optional:
1066
0
                    if (MaxParamCount >= 0)
1067
0
                        MaxParamCount++;
1068
0
                    break;
1069
0
                case OFCmdParam::PM_MultiOptional:
1070
0
                    MaxParamCount = -1;
1071
0
                    break;
1072
0
            }
1073
0
        }
1074
0
        ++iter;
1075
0
    }
1076
0
    if (getArgCount() == 0)
1077
0
        return PS_NoArguments;
1078
0
    else if (hasExclusiveOption())
1079
0
        return PS_ExclusiveOption;
1080
0
    else if (getParamCount() < MinParamCount)
1081
0
        return PS_MissingParameter;
1082
0
    else if ((MaxParamCount >= 0) && (getParamCount() > MaxParamCount))
1083
0
        return PS_TooManyParameters;
1084
0
    return PS_Normal;
1085
0
}
1086
1087
1088
OFCommandLine::E_ParseStatus OFCommandLine::parseCommandFile(const char *argValue,
1089
                                                             OFList<OFString> &argList)
1090
0
{
1091
0
    E_ParseStatus result = PS_NoArguments;
1092
    /* check for command file parameter (syntax: "@filename") */
1093
0
    if ((argValue != NULL) && (argValue[0] == COMMAND_FILE_PREFIX) && (argValue[1] != '\0'))
1094
0
    {
1095
        /* skip '@' symbol in filename */
1096
0
        const char *filename = argValue + 1;
1097
        /* open command file */
1098
0
        STD_NAMESPACE ifstream cmdFile(filename, OFopenmode_in_nocreate);
1099
0
        if (cmdFile)
1100
0
        {
1101
0
            char c, block = 0;
1102
0
            OFString value;
1103
            /* append command file content to the list of arguments */
1104
0
            while (cmdFile.get(c))
1105
0
            {
1106
                /* double or single quote */
1107
0
                if ((c == '"') || (c == '\''))
1108
0
                {
1109
0
                    if (block == c)
1110
0
                    {
1111
                        /* closing current quote block (also empty value) */
1112
0
                        argList.push_back(value);
1113
0
                        value.clear();
1114
0
                        block = 0;
1115
0
                    }
1116
0
                    else if (block == 0)
1117
0
                    {
1118
                        /* starting new quote block */
1119
0
                        block = c;
1120
0
                    } else {
1121
                        /* append character */
1122
0
                        value += c;
1123
0
                    }
1124
0
                }
1125
                /* space, tab, newline or return */
1126
0
                else if ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r'))
1127
0
                {
1128
                    /* outside block quote? */
1129
0
                    if (block == 0)
1130
0
                    {
1131
0
                        if (!value.empty())
1132
0
                        {
1133
                            /* and add current value to the list of arguments */
1134
0
                            argList.push_back(value);
1135
0
                            value.clear();
1136
0
                        }
1137
0
                    } else
1138
0
                        value += c;
1139
0
                } else
1140
0
                    value += c;
1141
0
            }
1142
            /* append remaining argument (if any) */
1143
0
            if (!value.empty())
1144
0
                argList.push_back(value);
1145
#ifdef DEBUG
1146
            if (block != 0)
1147
            {
1148
                ofConsole.lockCerr() << "WARNING: closing quotation mark (" << block << ") missing in command file " << filename << OFendl;
1149
                ofConsole.unlockCerr();
1150
            }
1151
#endif
1152
0
            result = PS_Normal;
1153
0
        } else
1154
0
            result = PS_CannotOpenCommandFile;
1155
0
    }
1156
0
    return result;
1157
0
}
1158
1159
1160
#ifdef DCMTK_USE_WCHAR_T
1161
1162
// Windows-specific version with wide character strings (UTF-16)
1163
#ifdef DEBUG
1164
OFCommandLine::E_ParseStatus OFCommandLine::parseCommandFile(const wchar_t *argValue,
1165
                                                             const OFString &strValue,
1166
                                                             OFList<OFString> &argList)
1167
#else
1168
OFCommandLine::E_ParseStatus OFCommandLine::parseCommandFile(const wchar_t *argValue,
1169
                                                             const OFString & /* strValue */,
1170
                                                             OFList<OFString> &argList)
1171
#endif
1172
{
1173
    E_ParseStatus result = PS_NoArguments;
1174
    /* check for command file parameter (syntax: "@filename") */
1175
    if ((argValue != NULL) && (argValue[0] == WIDE_COMMAND_FILE_PREFIX) && (argValue[1] != L'\0'))
1176
    {
1177
        /* skip '@' symbol in filename */
1178
        const wchar_t *filename = argValue + 1;
1179
        /* open command file */
1180
        STD_NAMESPACE wifstream cmdFile(filename, OFopenmode_in_nocreate);
1181
        if (cmdFile)
1182
        {
1183
            wchar_t c, block = 0;
1184
            STD_NAMESPACE wstring value;
1185
            /* append command file content to the list of arguments */
1186
            while (cmdFile.get(c))
1187
            {
1188
                /* double or single quote */
1189
                if ((c == L'"') || (c == L'\''))
1190
                {
1191
                    if (block == c)
1192
                    {
1193
                        /* closing current quote block (also empty value) */
1194
                        OFString tmpString;
1195
                        /* convert current value to UTF-8 */
1196
                        OFCharacterEncoding::convertFromWideCharString(value.c_str(), value.length(),
1197
                            tmpString, OFCharacterEncoding::CPC_UTF8);
1198
                        /* ... and add it to the list of arguments */
1199
                        argList.push_back(tmpString);
1200
                        value.clear();
1201
                        block = 0;
1202
                    }
1203
                    else if (block == 0)
1204
                    {
1205
                        /* starting new quote block */
1206
                        block = c;
1207
                    } else {
1208
                        /* append character */
1209
                        value += c;
1210
                    }
1211
                }
1212
                /* space, tab, newline or return */
1213
                else if ((c == L' ') || (c == L'\t') || (c == L'\n') || (c == L'\r'))
1214
                {
1215
                    /* outside block quote? */
1216
                    if (block == 0)
1217
                    {
1218
                        if (!value.empty())
1219
                        {
1220
                            OFString tmpString;
1221
                            /* convert current value to UTF-8 */
1222
                            OFCharacterEncoding::convertFromWideCharString(value.c_str(), value.length(),
1223
                                tmpString, OFCharacterEncoding::CPC_UTF8);
1224
                            /* ... and add it to the list of arguments */
1225
                            argList.push_back(tmpString);
1226
                            value.clear();
1227
                        }
1228
                    } else
1229
                        value += c;
1230
                } else
1231
                    value += c;
1232
            }
1233
            /* append remaining argument (if any) */
1234
            if (!value.empty())
1235
            {
1236
                OFString tmpString;
1237
                /* convert current value to UTF-8 */
1238
                OFCharacterEncoding::convertFromWideCharString(value.c_str(), value.length(), tmpString,
1239
                    OFCharacterEncoding::CPC_UTF8);
1240
                /* ... and add it to the list of arguments */
1241
                argList.push_back(tmpString);
1242
            }
1243
#ifdef DEBUG
1244
            if (block != 0)
1245
            {
1246
                // Right now the code below prints the character code of the 'block' wchar_t character instead
1247
                // of the character itself. This is an interim solution until a proper conversion function
1248
                // is added in the future in order to print the original character.
1249
                ofConsole.lockCerr() << "WARNING: closing quotation mark (" << OFstatic_cast(unsigned, block) << ") missing in command file " << strValue << OFendl;
1250
                ofConsole.unlockCerr();
1251
            }
1252
#endif
1253
            result = PS_Normal;
1254
        } else
1255
            result = PS_CannotOpenCommandFile;
1256
    }
1257
    return result;
1258
}
1259
1260
#endif  // DCMTK_USE_WCHAR_T
1261
1262
1263
OFCommandLine::E_ParseStatus OFCommandLine::parseArgumentList(OFList<OFString> &argList,
1264
                                                              const int /*flags*/)
1265
0
{
1266
0
    ArgumentList.clear();                                                // initialize lists/positions
1267
0
    ParamPosList.clear();
1268
0
    OptionPosList.clear();
1269
0
    ParamPosNumber = 0;
1270
0
    ExclusiveOption = OFFalse;
1271
1272
0
    int directOption = 0;                                                // number of direct predecessor
1273
0
    int i = OFstatic_cast(int, argList.size());
1274
0
    OFListIterator(OFString) argIter = argList.begin();
1275
0
    const OFListIterator(OFString) argEnd = argList.end();
1276
    /* iterate over all command line arguments */
1277
0
    while (argIter != argEnd)
1278
0
    {
1279
0
        if (!checkOption(*argIter, OFFalse))                             // arg = parameter
1280
0
        {
1281
0
            storeParameter(*argIter, directOption);
1282
0
            directOption = 0;
1283
0
        } else {                                                         // arg = option
1284
0
            const OFCmdOption *opt = findCmdOption(*argIter);
1285
0
            if (opt != NULL)
1286
0
            {
1287
0
                ArgumentList.push_back(OFstatic_cast(OFString, opt->LongOption)); // convert argument to long format
1288
0
                OptionPosList.push_back(--ArgumentList.end());
1289
0
                if (opt->Flags & AF_Exclusive)                           // check for an "exclusive" option
1290
0
                    ExclusiveOption = OFTrue;
1291
0
                directOption++;
1292
0
                int j = opt->ValueCount;                                 // number of expected values
1293
0
                if (j >= i)
1294
0
                    return PS_MissingValue;                              // expecting more values than present
1295
0
                while (j-- > 0)
1296
0
                {
1297
0
                    ArgumentList.push_back(*(++argIter));                // add values to argument list
1298
0
                    i--;
1299
0
                }
1300
0
            } else {                                                     // unknown
1301
0
                ArgumentList.push_back(*argIter);                        // store argument
1302
0
                return PS_UnknownOption;
1303
0
            }
1304
0
        }
1305
0
        ++argIter;
1306
0
        i--;
1307
0
    }
1308
0
    return checkParamCount();
1309
0
}
1310
1311
1312
OFCommandLine::E_ParseStatus OFCommandLine::parseLine(int argCount,
1313
                                                      char *argValue[],
1314
                                                      const int flags,
1315
                                                      const int startPos)
1316
0
{
1317
0
    OFList<OFString> argList;                                            // "expanded" list of arguments
1318
0
    WideCharMode = OFFalse;
1319
0
    if (argCount > 0)                                                    // determine program name
1320
0
        ProgramName = argValue[0];
1321
0
    else
1322
0
        ProgramName.clear();
1323
0
    if (argCount > startPos)                                             // any command line arguments?
1324
0
    {
1325
        /* expand command files (if any) */
1326
0
        for (int i = startPos; i < argCount; i++)                        // skip program name (argValue[0])
1327
0
        {
1328
0
            if (flags & PF_NoCommandFiles)                               // do not try to detect command files
1329
0
                argList.push_back(argValue[i]);
1330
0
            else
1331
0
            {
1332
                /* parse command file content */
1333
0
                E_ParseStatus status = parseCommandFile(argValue[i], argList);
1334
0
                if (status == PS_NoArguments)
1335
0
                    argList.push_back(argValue[i]);                      // store parameter as is
1336
0
                else if (status != PS_Normal)
1337
0
                {
1338
0
                    ArgumentList.push_back(argValue[i] + 1);             // store filename for error message
1339
0
                    return status;
1340
0
                }
1341
0
            }
1342
0
        }
1343
0
    }
1344
    /* call the real function after the preparatory work is done */
1345
0
    return parseArgumentList(argList, flags);
1346
0
}
1347
1348
1349
#ifdef DCMTK_USE_WCHAR_T
1350
1351
// Windows-specific version with wide character strings (UTF-16)
1352
OFCommandLine::E_ParseStatus OFCommandLine::parseLine(int argCount,
1353
                                                      wchar_t *argValue[],
1354
                                                      const int flags,
1355
                                                      const int startPos)
1356
{
1357
    OFList<OFString> argList;                                            // "expanded" list of arguments
1358
    WideCharMode = OFTrue;
1359
    if (argCount > 0)                                                    // determine program name (convert to UTF-8)
1360
    {
1361
        OFCharacterEncoding::convertFromWideCharString(argValue[0], wcslen(argValue[0]),
1362
            ProgramName, OFCharacterEncoding::CPC_UTF8);
1363
    } else
1364
        ProgramName.clear();
1365
    if (argCount > startPos)                                             // any command line arguments?
1366
    {
1367
        OFString strValue;
1368
        /* expand command files (if any) */
1369
        for (int i = startPos; i < argCount; i++)                        // skip program name (argValue[0])
1370
        {
1371
            OFCharacterEncoding::convertFromWideCharString(argValue[i], wcslen(argValue[i]),
1372
                strValue, OFCharacterEncoding::CPC_UTF8, OFTrue /* clearMode */);
1373
            if (flags & PF_NoCommandFiles)                               // do not try to detect command files
1374
                argList.push_back(strValue);
1375
            else
1376
            {
1377
                /* parse command file content */
1378
                E_ParseStatus status = parseCommandFile(argValue[i], strValue, argList);
1379
                if (status == PS_NoArguments)
1380
                    argList.push_back(strValue);                         // store parameter as is
1381
                else if (status != PS_Normal)
1382
                {
1383
                    ArgumentList.push_back(strValue.c_str() + 1);        // store filename for error message
1384
                    return status;
1385
                }
1386
            }
1387
        }
1388
    }
1389
    /* call the real function after the preparatory work is done */
1390
    return parseArgumentList(argList, flags);
1391
}
1392
1393
#endif  // DCMTK_USE_WCHAR_T
1394
1395
1396
void OFCommandLine::getSyntaxString(OFString &syntaxStr) const
1397
0
{
1398
0
    syntaxStr.clear();
1399
0
    if (!ValidOptionList.empty())
1400
0
        syntaxStr += " [options]";
1401
0
    if (!ValidParamList.empty())
1402
0
    {
1403
0
        OFListConstIterator(OFCmdParam *) iter = ValidParamList.begin();
1404
0
        OFListConstIterator(OFCmdParam *) last = ValidParamList.end();
1405
0
        while (iter != last)
1406
0
        {
1407
0
            if (!(*iter)->ParamName.empty())
1408
0
            {
1409
0
                switch ((*iter)->ParamMode)
1410
0
                {
1411
0
                    case OFCmdParam::PM_Mandatory:
1412
0
                        syntaxStr += " ";
1413
0
                        syntaxStr += (*iter)->ParamName;
1414
0
                        break;
1415
0
                    case OFCmdParam::PM_Optional:
1416
0
                        syntaxStr += " [";
1417
0
                        syntaxStr += (*iter)->ParamName;
1418
0
                        syntaxStr += "]";
1419
0
                        break;
1420
0
                    case OFCmdParam::PM_MultiMandatory:
1421
0
                        syntaxStr += " ";
1422
0
                        syntaxStr += (*iter)->ParamName;
1423
0
                        syntaxStr += "...";
1424
0
                        break;
1425
0
                    case OFCmdParam::PM_MultiOptional:
1426
0
                        syntaxStr += " [";
1427
0
                        syntaxStr += (*iter)->ParamName;
1428
0
                        syntaxStr += "...]";
1429
0
                        break;
1430
0
                }
1431
0
            }
1432
0
            ++iter;
1433
0
        }
1434
0
    }
1435
0
}
1436
1437
1438
void OFCommandLine::getOptionString(OFString &optionStr) const
1439
0
{
1440
0
    optionStr.clear();
1441
0
    if (!ValidOptionList.empty())
1442
0
    {
1443
0
        OFListConstIterator(OFCmdOption *) iter = ValidOptionList.begin();
1444
0
        OFListConstIterator(OFCmdOption *) last = ValidOptionList.end();
1445
0
        OFString str;
1446
0
        int newGrp = 1;
1447
0
        unsigned int shortSize = ShortColumn;
1448
0
        unsigned int longSize = LongColumn;
1449
0
        unsigned int lineIndent = 0;
1450
0
        const unsigned int groupIndent = 2;
1451
0
        const unsigned int subGrpIndent = 4;
1452
0
        const unsigned int columnSpace = 2;
1453
0
        while (iter != last)
1454
0
        {
1455
            /* skip internal options */
1456
0
            if (!((*iter)->Flags & OFCommandLine::AF_Internal))
1457
0
            {
1458
0
                if (newGrp)
1459
0
                {
1460
                    /* determine column width per group */
1461
0
                    OFListConstIterator(OFCmdOption *) i = iter;
1462
0
                    while ((i != last) && !(*i)->LongOption.empty())
1463
0
                    {
1464
0
                        if (!((*i)->Flags & OFCommandLine::AF_Internal))
1465
0
                        {
1466
0
                            if ((*i)->ShortOption.length() > shortSize)
1467
0
                                shortSize = OFstatic_cast(unsigned int, (*i)->ShortOption.length());
1468
0
                            if ((*i)->LongOption.length() > longSize)
1469
0
                                longSize = OFstatic_cast(unsigned int, (*i)->LongOption.length());
1470
0
                        }
1471
0
                        i++;
1472
0
                    }
1473
0
                    newGrp = 0;
1474
0
                }
1475
0
                if ((*iter)->LongOption.empty())
1476
0
                {
1477
                    /* group entry */
1478
0
                    newGrp = 1;
1479
0
                    unpackColumnValues((*iter)->ValueCount, longSize, shortSize);
1480
0
                    if (!(*iter)->OptionDescription.empty())                     // new group
1481
0
                    {
1482
0
                        optionStr += (*iter)->OptionDescription;
1483
0
                        lineIndent = groupIndent;
1484
0
                    } else {                                                     // new sub group
1485
0
                        optionStr.append(groupIndent, ' ');
1486
0
                        optionStr += (*iter)->ValueDescription;
1487
0
                        lineIndent = subGrpIndent;
1488
0
                    }
1489
0
                    optionStr += "\n";
1490
0
                } else {
1491
                    /* regular option */
1492
0
                    optionStr.append(lineIndent, ' ');
1493
0
                    if (shortSize > 0)
1494
0
                    {
1495
0
                        str = (*iter)->ShortOption;
1496
0
                        str.resize(shortSize, ' ');
1497
0
                        optionStr += str;
1498
0
                        optionStr.append(columnSpace, ' ');
1499
0
                    }
1500
0
                    str = (*iter)->LongOption;
1501
0
                    str.resize(longSize, ' ');
1502
0
                    optionStr += str;
1503
0
                    optionStr.append(columnSpace, ' ');
1504
0
                    if (!(*iter)->ValueDescription.empty())
1505
0
                    {
1506
0
                        optionStr += (*iter)->ValueDescription;
1507
0
                        optionStr += "\n";
1508
0
                        optionStr.append(lineIndent + shortSize + longSize + columnSpace, ' ');
1509
0
                        if (shortSize > 0)
1510
0
                            optionStr.append(columnSpace, ' ');
1511
0
                    }
1512
0
                    str = (*iter)->OptionDescription;
1513
0
                    size_t pos = 0;
1514
0
                    while (((pos = (str.find('\n', pos))) != OFString_npos) && (pos < str.length()))
1515
0
                        str.insert(++pos, OFString(lineIndent + shortSize + longSize + 2 * columnSpace, ' '));
1516
0
                    optionStr += str;
1517
0
                    optionStr += "\n";
1518
0
                }
1519
0
            }
1520
0
            ++iter;
1521
0
        }
1522
0
    }
1523
0
}
1524
1525
1526
void OFCommandLine::getParamString(OFString &paramStr) const
1527
0
{
1528
0
    paramStr.clear();
1529
0
    if (!ValidParamList.empty())
1530
0
    {
1531
0
        OFListConstIterator(OFCmdParam *) iter = ValidParamList.begin();
1532
0
        OFListConstIterator(OFCmdParam *) last = ValidParamList.end();
1533
0
        OFString str;
1534
0
        unsigned int columnSize = ParamColumn;
1535
0
        const unsigned int lineIndent = 2;
1536
0
        const unsigned int columnSpace = 2;
1537
0
        while ((iter != last) && !(*iter)->ParamDescription.empty())
1538
0
        {
1539
0
            if ((*iter)->ParamName.length() > columnSize)           // determine maximum column width
1540
0
                columnSize = OFstatic_cast(unsigned int, (*iter)->ParamName.length());
1541
0
            ++iter;
1542
0
        }
1543
0
        iter = ValidParamList.begin();                              // reset iterator
1544
0
        while (iter != last)
1545
0
        {
1546
0
            if (!(*iter)->ParamDescription.empty())
1547
0
            {
1548
0
                if (paramStr.empty())
1549
0
                    paramStr += "parameters:\n";
1550
0
                paramStr.append(lineIndent, ' ');
1551
0
                str = (*iter)->ParamName;
1552
0
                str.resize(columnSize, ' ');
1553
0
                paramStr += str;
1554
0
                paramStr.append(columnSpace, ' ');
1555
0
                str = (*iter)->ParamDescription;
1556
0
                size_t pos = 0;
1557
0
                while (((pos = (str.find('\n', pos))) != OFString_npos) && (pos < str.length()))
1558
0
                    str.insert(++pos, OFString(lineIndent + columnSize + columnSpace, ' '));
1559
0
                paramStr += str;
1560
0
                paramStr += "\n";
1561
0
            }
1562
0
            ++iter;
1563
0
        }
1564
0
    }
1565
0
}
1566
1567
1568
OFBool OFCommandLine::getMissingParam(OFString &param)
1569
0
{
1570
0
    if (!ValidParamList.empty() && (getParamCount() < MinParamCount))
1571
0
    {
1572
0
        OFListIterator(OFCmdParam *) iter = ValidParamList.begin();
1573
0
        const OFListIterator(OFCmdParam *) last = ValidParamList.end();
1574
0
        int i = getParamCount();
1575
0
        while ((iter != last) && (i-- > 0))
1576
0
            ++iter;
1577
0
        if (iter != last)
1578
0
        {
1579
0
            param = (*iter)->ParamName;
1580
0
            return OFTrue;
1581
0
        }
1582
0
    }
1583
0
    return OFFalse;
1584
0
}
1585
1586
1587
void OFCommandLine::getStatusString(const E_ParseStatus status,
1588
                                    OFString &statusStr)
1589
0
{
1590
0
    OFString str;
1591
0
    switch (status)
1592
0
    {
1593
0
        case PS_UnknownOption:
1594
0
            statusStr = "Unknown option ";
1595
0
            if (getLastArg(str))
1596
0
                statusStr += str;
1597
0
            break;
1598
0
        case PS_MissingValue:
1599
0
            statusStr = "Missing value for option ";
1600
0
            if (getLastArg(str))
1601
0
                statusStr += str;
1602
0
            break;
1603
0
        case PS_MissingParameter:
1604
0
            statusStr = "Missing parameter ";
1605
0
            if (getMissingParam(str))
1606
0
                statusStr += str;
1607
0
            break;
1608
0
        case PS_TooManyParameters:
1609
0
            statusStr = "Too many parameters";
1610
0
            break;
1611
0
        case PS_CannotOpenCommandFile:
1612
0
            statusStr = "Cannot open command file";
1613
0
            if (getLastArg(str))
1614
0
            {
1615
0
                statusStr += " '";
1616
0
                statusStr += str;
1617
0
                statusStr += "'";
1618
0
            }
1619
0
            break;
1620
0
        default:
1621
0
            statusStr.clear();
1622
0
            break;
1623
0
    }
1624
0
}
1625
1626
1627
void OFCommandLine::getStatusString(const E_ParamValueStatus status,
1628
                                    OFString &statusStr)
1629
0
{
1630
0
    OFString str;
1631
0
    switch (status)
1632
0
    {
1633
0
        case PVS_Invalid:
1634
0
            statusStr = "Invalid parameter value ";
1635
0
            if (getCurrentArg(str))
1636
0
                statusStr += str;
1637
0
            break;
1638
0
        case PVS_CantFind:
1639
0
            statusStr = "Can't find parameter";
1640
0
            break;
1641
0
        case PVS_Underflow:
1642
0
            statusStr = "Invalid parameter value ";
1643
0
            if (getCurrentArg(str))
1644
0
            {
1645
0
                statusStr += str;
1646
0
                statusStr += " (underflow)";
1647
0
            }
1648
0
            break;
1649
0
        case PVS_Overflow:
1650
0
            statusStr = "Invalid parameter value ";
1651
0
            if (getCurrentArg(str))
1652
0
            {
1653
0
                statusStr += str;
1654
0
                statusStr += " (overflow)";
1655
0
            }
1656
0
            break;
1657
0
        default:
1658
0
            statusStr.clear();
1659
0
            break;
1660
0
    }
1661
0
}
1662
1663
1664
void OFCommandLine::getStatusString(const E_ValueStatus status,
1665
                                    OFString &statusStr)
1666
0
{
1667
0
    OFString str;
1668
0
    switch (status)
1669
0
    {
1670
0
        case VS_Normal:
1671
0
            statusStr.clear();
1672
0
            break;
1673
0
        case VS_Invalid:
1674
0
            statusStr = "Invalid value for option ";
1675
0
            if (getCurrentOption(str))
1676
0
            {
1677
0
                statusStr += str;
1678
0
                if (getCurrentArg(str))
1679
0
                {
1680
0
                    statusStr += " (";
1681
0
                    statusStr += str;
1682
0
                    statusStr += ")";
1683
0
                }
1684
0
            }
1685
0
            break;
1686
0
        case VS_Underflow:
1687
0
            statusStr = "Invalid value for option ";
1688
0
            if (getCurrentOption(str))
1689
0
            {
1690
0
                statusStr += str;
1691
0
                if (getCurrentArg(str))
1692
0
                {
1693
0
                    statusStr += " (underflow: ";
1694
0
                    statusStr += str;
1695
0
                    statusStr += ")";
1696
0
                }
1697
0
            }
1698
0
            break;
1699
0
        case VS_Overflow:
1700
0
            statusStr = "Invalid value for option ";
1701
0
            if (getCurrentOption(str))
1702
0
            {
1703
0
                statusStr += str;
1704
0
                if (getCurrentArg(str))
1705
0
                {
1706
0
                    statusStr += " (overflow: ";
1707
0
                    statusStr += str;
1708
0
                    statusStr += ")";
1709
0
                }
1710
0
            }
1711
0
            break;
1712
0
        default:
1713
0
            statusStr.clear();
1714
0
            break;
1715
0
    }
1716
0
}