w11 - cpp 0.794
Backend server for Rlink and w11
Loading...
Searching...
No Matches
RtclArgs.cpp
Go to the documentation of this file.
1// $Id: RtclArgs.cpp 1186 2019-07-12 17:49:59Z mueller $
2// SPDX-License-Identifier: GPL-3.0-or-later
3// Copyright 2011-2018 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
4//
5// Revision History:
6// Date Rev Version Comment
7// 2018-12-22 1091 1.0.12 GetArg(float): float cast (-Wdouble-promotion fix)
8// 2018-12-18 1089 1.0.11 use c++ style casts
9// 2018-09-22 1048 1.0.10 BUFFIX: GetArg(): coverity (argument in wrong order)
10// 2018-09-16 1047 1.0.9 coverity fixup (uninitialized scalar)
11// 2014-08-22 584 1.0.8 use nullptr
12// 2013-05-19 521 1.0.7 add NextSubOpt() method, pass optset's as const
13// 2013-02-12 487 1.0.6 add CurrentArg() method
14// 2013-02-03 481 1.0.5 use Rexception
15// 2011-03-26 373 1.0.4 add GetArg(float/double)
16// 2011-03-13 369 1.0.3 add GetArg(vector<unit8_t>); NextOpt clear NOptMiss
17// 2011-03-06 367 1.0.2 add Config() methods;
18// 2011-03-05 366 1.0.1 fObjc,fNDone now size_t; add NDone(), SetResult();
19// add GetArg(Tcl_Obj), PeekArgString();
20// 2011-02-26 364 1.0 Initial version
21// 2011-02-11 360 0.1 First draft
22// ---------------------------------------------------------------------------
23
28//debug
29#include <iostream>
30
31#include <ctype.h>
32#include <stdarg.h>
33
34#include "RtclArgs.hpp"
35
36#include "Rtcl.hpp"
38
39using namespace std;
40
46// all method definitions in namespace Retro
47namespace Retro {
48
49//------------------------------------------+-----------------------------------
51
53 : fpInterp(nullptr),
54 fObjc(0),
55 fObjv(nullptr),
56 fNDone(0),
57 fNOptMiss(0),
58 fNConfigRead(0),
59 fOptErr(false),
60 fArgErr(false)
61{}
62
63//------------------------------------------+-----------------------------------
65
66RtclArgs::RtclArgs(Tcl_Interp* interp, int objc, Tcl_Obj* const objv[],
67 size_t nskip)
68 : fpInterp(interp),
69 fObjc(size_t(objc)),
70 fObjv(objv),
71 fNDone((nskip<=size_t(objc)) ? nskip : size_t(objc)),
72 fNOptMiss(0),
73 fNConfigRead(0),
74 fOptErr(false),
75 fArgErr(false)
76{
77 if (objc < 0)
78 throw Rexception("RtclArgs::<ctor>","Bad args: objc must be >= 0");
79}
80
81//------------------------------------------+-----------------------------------
83
85 : fpInterp(rhs.fpInterp),
86 fObjc(rhs.fObjc),
87 fObjv(rhs.fObjv),
88 fNDone(rhs.fNDone),
89 fNOptMiss(rhs.fNOptMiss),
90 fNConfigRead(rhs.fNConfigRead),
91 fOptErr(rhs.fOptErr),
92 fArgErr(rhs.fArgErr)
93{}
94
95//------------------------------------------+-----------------------------------
97
99{}
100
101//------------------------------------------+-----------------------------------
103
104Tcl_Obj* RtclArgs::Objv(size_t ind) const
105{
106 if (ind >= size_t(fObjc))
107 throw Rexception("RtclArgs::Objv()","Bad args: index out-of-range");
108 return fObjv[ind];
109}
110
111//------------------------------------------+-----------------------------------
113
114bool RtclArgs::GetArg(const char* name, Tcl_Obj*& pval)
115{
116 Tcl_Obj* pobj;
117 if (!NextArg(name, pobj)) return false;
118 if (pobj==0) return true;
119 pval = pobj;
120 return true;
121}
122
123//------------------------------------------+-----------------------------------
125
126bool RtclArgs::GetArg(const char* name, const char*& val)
127{
128 Tcl_Obj* pobj;
129 if (!NextArg(name, pobj)) return false;
130 if (pobj==0) return true;
131 val = Tcl_GetString(pobj);
132 return true;
133}
134
135//------------------------------------------+-----------------------------------
137
138bool RtclArgs::GetArg(const char* name, std::string& val)
139{
140 Tcl_Obj* pobj;
141 if (!NextArg(name, pobj)) return false;
142 if (pobj==0) return true;
143 val = Tcl_GetString(pobj);
144 return true;
145}
146
147//------------------------------------------+-----------------------------------
149
150bool RtclArgs::GetArg(const char* name, int8_t& val, int8_t min, int8_t max)
151{
152 int32_t val32 = int32_t(val);
153 bool ret = GetArg(name, val32, int32_t(min), int32_t(max));
154 val = int8_t(val32);
155 return ret;
156}
157
158//------------------------------------------+-----------------------------------
160
161bool RtclArgs::GetArg(const char* name, uint8_t& val, uint8_t max, uint8_t min)
162{
163 uint32_t val32 = uint32_t(val);
164 bool ret = GetArg(name, val32, uint32_t(max), uint32_t(min));
165 val = uint8_t(val32);
166 return ret;
167}
168
169//------------------------------------------+-----------------------------------
171
172bool RtclArgs::GetArg(const char* name, int16_t& val, int16_t min, int16_t max)
173{
174 int32_t val32 = int32_t(val);
175 bool ret = GetArg(name, val32, int32_t(min), int32_t(max));
176 val = int16_t(val32);
177 return ret;
178}
179
180//------------------------------------------+-----------------------------------
182
183bool RtclArgs::GetArg(const char* name, uint16_t& val, uint16_t max,
184 uint16_t min)
185{
186 uint32_t val32 = uint32_t(val);
187 bool ret = GetArg(name, val32, uint32_t(max), uint32_t(min));
188 val = uint16_t(val32);
189 return ret;
190}
191
192//------------------------------------------+-----------------------------------
194
195bool RtclArgs::GetArg(const char* name, int32_t& val, int32_t min, int32_t max)
196{
197 Tcl_Obj* pobj;
198 if (!NextArg(name, pobj)) return false;
199 if (pobj==0) return true;
200 int objval;
201 if (Tcl_GetIntFromObj(fpInterp, pobj, &objval) != TCL_OK) return false;
202 if (objval < min || objval > max) {
203 ostringstream sos;
204 sos << "-E: value '" << objval << "' for '" << name << "' out of range "
205 << min << "..." << max;
206 AppendResult(sos);
207 return false;
208 }
209 val = int32_t(objval);
210 return true;
211}
212
213//------------------------------------------+-----------------------------------
215
216bool RtclArgs::GetArg(const char* name, uint32_t& val, uint32_t max,
217 uint32_t min)
218{
219 Tcl_Obj* pobj;
220 if (!NextArg(name, pobj)) return false;
221 if (pobj==0) return true;
222 int objval;
223 if (Tcl_GetIntFromObj(fpInterp, pobj, &objval) != TCL_OK) return false;
224 unsigned int objuval = objval;
225 if (objuval < min || objuval > max) {
226 ostringstream sos;
227 sos << "-E: value '" << objuval << "' for '" << name << "' out of range "
228 << min << "..." << max;
229 AppendResult(sos);
230 return false;
231 }
232 val = uint32_t(objval);
233 return true;
234}
235
236//------------------------------------------+-----------------------------------
238
239bool RtclArgs::GetArg(const char* name, float& val, float min, float max)
240{
241 double vald = double(val);
242 bool ret = GetArg(name, vald, double(min), double(max));
243 val = float(vald);
244 return ret;
245}
246
247//------------------------------------------+-----------------------------------
249
250bool RtclArgs::GetArg(const char* name, double& val, double min, double max)
251{
252 Tcl_Obj* pobj;
253 if (!NextArg(name, pobj)) return false;
254 if (pobj==0) return true;
255 double objval;
256 if (Tcl_GetDoubleFromObj(fpInterp, pobj, &objval) != TCL_OK) return false;
257 if (objval < min || objval > max) {
258 ostringstream sos;
259 sos << "-E: value '" << objval << "' for '" << name << "' out of range "
260 << min << "..." << max;
261 AppendResult(sos);
262 return false;
263 }
264 val = objval;
265 return true;
266}
267
268//------------------------------------------+-----------------------------------
270
271bool RtclArgs::GetArg(const char* name, std::vector<uint8_t>& val,
272 size_t lmin, size_t lmax)
273{
274 int objc = 0;
275 Tcl_Obj** objv = nullptr;
276 if (!NextArgList(name, objc, objv, lmin, lmax)) return false;
277 if (objv==0) return true;
278
279 val.clear();
280 val.reserve(objc);
281
282 for (int i=0; i<objc; i++) {
283 int ival;
284 if (Tcl_GetIntFromObj(fpInterp, objv[i], &ival) != TCL_OK) return false;
285 int ivalmsb = ival>>8;
286 if (ivalmsb != 0 && ivalmsb != -1) {
287 ostringstream sos;
288 sos << "-E: list element '" << Tcl_GetString(objv[i])
289 << "' for '" << name
290 << "' out of range " << "0...0xff";
291 AppendResult(sos);
292 return false;
293 }
294 val.push_back(uint8_t(ival));
295 }
296 return true;
297}
298
299//------------------------------------------+-----------------------------------
301
302bool RtclArgs::GetArg(const char* name, std::vector<uint16_t>& val,
303 size_t lmin, size_t lmax)
304{
305 int objc = 0;
306 Tcl_Obj** objv = nullptr;
307 if (!NextArgList(name, objc, objv, lmin, lmax)) return false;
308 if (objv==0) return true;
309
310 val.clear();
311 val.reserve(objc);
312
313 for (int i=0; i<objc; i++) {
314 int ival;
315 if (Tcl_GetIntFromObj(fpInterp, objv[i], &ival) != TCL_OK) return false;
316 int ivalmsb = ival>>16;
317 if (ivalmsb != 0 && ivalmsb != -1) {
318 ostringstream sos;
319 sos << "-E: list element '" << Tcl_GetString(objv[i])
320 << "' for '" << name
321 << "' out of range " << "0...0xffff";
322 AppendResult(sos);
323 return false;
324 }
325 val.push_back(uint16_t(ival));
326 }
327 return true;
328}
329
330//------------------------------------------+-----------------------------------
332
333bool RtclArgs::Config(const char* name, std::string& val)
334{
335 ConfigNameCheck(name);
336 string tmp = val;
337 if (!GetArg(name, tmp)) return false;
338 if (fNOptMiss == 0) { // config write
339 val = tmp;
340 } else { // config read
341 if (!ConfigReadCheck()) return false;
342 SetResult(Tcl_NewStringObj(val.data(), val.length()));
343 }
344 return true;
345}
346
347//------------------------------------------+-----------------------------------
349
350bool RtclArgs::Config(const char* name, uint32_t& val, uint32_t max,
351 uint32_t min)
352{
353 ConfigNameCheck(name);
354 uint32_t tmp = val;
355 if (!GetArg(name, tmp, max, min)) return false;
356 if (fNOptMiss == 0) { // config write
357 val = tmp;
358 } else { // config read
359 if (!ConfigReadCheck()) return false;
360 SetResult(Tcl_NewIntObj(int(val)));
361 }
362 return true;
363}
364
365//------------------------------------------+-----------------------------------
367
368bool RtclArgs::NextOpt(std::string& val)
369{
370 fNOptMiss = 0;
371 val.clear();
372 fOptErr = false;
373
374 if (fNDone == fObjc) return false;
375
376 const char* str = PeekArgString(0);
377
378 if (str[0]=='-' && str[1] && !isdigit(str[1])) {
379 fNDone += 1;
380 // '--' seen (eat it, and say no Opt's found)
381 if (str[1]=='-' && str[2]==0) {
382 return false;
383 }
384 val = str;
385 return true;
386 }
387 return false;
388}
389
390//------------------------------------------+-----------------------------------
392
393bool RtclArgs::NextOpt(std::string& val, const RtclNameSet& optset)
394{
395 val.clear();
396 string opt;
397 if (!NextOpt(opt) || opt.empty()) return false;
398
399 fOptErr = !optset.Check(fpInterp, val, opt);
400 return !fOptErr;
401}
402
403//------------------------------------------+-----------------------------------
405// irc = 1 -> match
406// 0 -> ambiguous match --> tcl err
407// -1 -> no match --> no tcl err
408
409int RtclArgs::NextSubOpt(std::string& val, const RtclNameSet& optset)
410{
411 val.clear();
412 fNOptMiss = 0;
413 fOptErr = false;
414
415 if (fNDone == fObjc) return -1;
416
417 const char* str = PeekArgString(0);
418
419 // does next arg look like an option
420 if (str[0]=='-' && str[1] && str[1]!='-' && !isdigit(str[1])) {
421 // and matches one of optset
422 int irc = optset.CheckMatch(fpInterp, val, string(str), false);
423 if (irc >= 0) {
424 fNDone += 1;
425 fOptErr = (irc == 0);
426 return irc;
427 }
428 }
429 return -1;
430}
431
432//------------------------------------------+-----------------------------------
434
435Tcl_Obj* RtclArgs::CurrentArg() const
436{
437 if (fNDone == 0)
438 throw Rexception("RtclArgs::CurrentArg()",
439 "Bad state: no argument processed yet");
440
441 return fObjv[fNDone-1];
442}
443
444//------------------------------------------+-----------------------------------
446
448{
449 if (fArgErr || fOptErr) return false;
450 if (fNDone < fObjc) {
451 AppendResult("-E: superfluous arguments, first one '",
452 Tcl_GetString(fObjv[fNDone]), "'", nullptr);
453 return false;
454 }
455 return true;
456}
457
458//------------------------------------------+-----------------------------------
460
461const char* RtclArgs::PeekArgString(int rind) const
462{
463 int ind = fNDone + rind;
464 if (ind < 0 || ind >= int(fObjc)) return "";
465 return Tcl_GetString(fObjv[ind]);
466}
467
468//------------------------------------------+-----------------------------------
470
471void RtclArgs::AppendResult(const char* str, ...)
472{
473 Tcl_AppendResult(fpInterp, str, nullptr);
474 va_list ap;
475 va_start (ap, str);
476 Tcl_AppendResultVA(fpInterp, ap);
477 va_end (ap);
478 return;
479}
480
481//------------------------------------------+-----------------------------------
483
484void RtclArgs::AppendResultLines(const std::string& str)
485{
487
488 if (str.length()>0 && str[str.length()-1]=='\n') {
489 Tcl_AppendResult(fpInterp, str.substr(0,str.length()-1).c_str(), nullptr);
490 } else {
491 Tcl_AppendResult(fpInterp, str.c_str(), nullptr);
492 }
493 return;
494}
495
496//------------------------------------------+-----------------------------------
498
499bool RtclArgs::NextArg(const char* name, Tcl_Obj*& pobj)
500{
501 pobj = nullptr;
502
503 bool isopt = name[0] == '?';
504 bool isoptopt = isopt && (name[1] == '?');
505
506 if (!isopt) fNOptMiss = 0;
507
508 if (fNDone == fObjc) {
509 if (!isopt) {
510 AppendResult("-E: required argument '", name, "' missing", nullptr);
511 fArgErr = true;
512 return false;
513 }
514 fNOptMiss += 1;
515 return true;
516 }
517
518 // if %% arg peek in next arg and check that it's not an option
519 if (isoptopt) {
520 const char* nval = Tcl_GetString(fObjv[fNDone]);
521 if (nval[0]=='-' && nval[1] && isalpha(nval[1])) {
522 fNOptMiss += 1;
523 return true;
524 }
525 }
526
527 pobj = fObjv[fNDone++];
528
529 return true;
530}
531
532//------------------------------------------+-----------------------------------
534
535bool RtclArgs::NextArgList(const char* name, int& objc, Tcl_Obj**& objv,
536 size_t lmin, size_t lmax)
537{
538 objc = 0;
539 objv = nullptr;
540 Tcl_Obj* pobj = nullptr;
541 if (!NextArg(name, pobj)) return false;
542 if (pobj==0) return true;
543
544 if (Tcl_ListObjGetElements(fpInterp, pobj, &objc, &objv) != TCL_OK) {
545 return false;
546 }
547
548 if (size_t(objc) < lmin || size_t(objc) > lmax) {
549 ostringstream sos;
550 sos << "-E: list length '" << objc << "' for '" << name << "' out of range "
551 << lmin << "..." << lmax;
552 AppendResult(sos);
553 return false;
554 }
555 return true;
556}
557
558//------------------------------------------+-----------------------------------
560
561void RtclArgs::ConfigNameCheck(const char* name)
562{
563 if (name==0 || name[0]!='?' || name[1]!='?')
564 throw Rexception("RtclArgs::Config()","Bad args: name must start with ??");
565 return;
566}
567
568//------------------------------------------+-----------------------------------
570
572{
573 if (fNConfigRead != 0) {
574 SetResult(Tcl_NewObj());
575 AppendResult("-E: only one config read allowed per command, '",
576 PeekArgString(-1), "' is second", nullptr);
577 return false;
578 }
579 fNConfigRead += 1;
580 return true;
581}
582
583} // end namespace Retro
FIXME_docs.
Definition: Rexception.hpp:29
FIXME_docs.
Definition: RtclArgs.hpp:41
void ConfigNameCheck(const char *name)
FIXME_docs.
Definition: RtclArgs.cpp:561
Tcl_Obj * CurrentArg() const
FIXME_docs.
Definition: RtclArgs.cpp:435
bool NextOpt(std::string &val)
FIXME_docs.
Definition: RtclArgs.cpp:368
const char * PeekArgString(int rind) const
FIXME_docs.
Definition: RtclArgs.cpp:461
void AppendResultLines(const std::string &str)
FIXME_docs.
Definition: RtclArgs.cpp:484
Tcl_Obj *const * Objv() const
FIXME_docs.
Definition: RtclArgs.ipp:44
int NextSubOpt(std::string &val, const RtclNameSet &optset)
FIXME_docs.
Definition: RtclArgs.cpp:409
bool fArgErr
argument processing error flag
Definition: RtclArgs.hpp:143
bool GetArg(const char *name, Tcl_Obj *&pval)
FIXME_docs.
Definition: RtclArgs.cpp:114
RtclArgs()
Default constructor.
Definition: RtclArgs.cpp:52
size_t fNOptMiss
number of missed optional args
Definition: RtclArgs.hpp:140
Tcl_Obj *const * fObjv
original args vector
Definition: RtclArgs.hpp:138
bool Config(const char *name, std::string &val)
FIXME_docs.
Definition: RtclArgs.cpp:333
size_t fNConfigRead
number of read mode config's
Definition: RtclArgs.hpp:141
void AppendResult(const char *str,...)
FIXME_docs.
Definition: RtclArgs.cpp:471
bool fOptErr
option processing error flag
Definition: RtclArgs.hpp:142
bool ConfigReadCheck()
FIXME_docs.
Definition: RtclArgs.cpp:571
void SetResult(const std::string &str)
FIXME_docs.
Definition: RtclArgs.ipp:76
size_t fNDone
number of processed args
Definition: RtclArgs.hpp:139
bool NextArgList(const char *name, int &objc, Tcl_Obj **&objv, size_t lmin=0, size_t lmax=uint32_max)
FIXME_docs.
Definition: RtclArgs.cpp:535
bool NextArg(const char *name, Tcl_Obj *&pobj)
FIXME_docs.
Definition: RtclArgs.cpp:499
~RtclArgs()
Destructor.
Definition: RtclArgs.cpp:98
Tcl_Interp * fpInterp
pointer to tcl interpreter
Definition: RtclArgs.hpp:136
bool AllDone()
FIXME_docs.
Definition: RtclArgs.cpp:447
size_t fObjc
original args count
Definition: RtclArgs.hpp:137
int CheckMatch(Tcl_Interp *interp, std::string &rval, const std::string &tval, bool misserr) const
FIXME_docs.
Definition: RtclNameSet.cpp:85
bool Check(Tcl_Interp *interp, std::string &rval, const std::string &tval) const
FIXME_docs.
Definition: RtclNameSet.cpp:73
void AppendResultNewLines(Tcl_Interp *interp)
Declaration of class ReventLoop.
Definition: ReventLoop.cpp:47