w11 - cpp 0.794
Backend server for Rlink and w11
Loading...
Searching...
No Matches
RtclBvi.cpp
Go to the documentation of this file.
1// $Id: RtclBvi.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-18 1089 1.0.3 use c++ style casts
8// 2018-12-02 1076 1.0.2 use nullptr
9// 2011-11-28 434 1.0.1 DoCmd(): use intptr_t cast for lp64 compatibility
10// 2011-03-27 374 1.0 Initial version
11// 2011-02-13 361 0.1 First draft
12// ---------------------------------------------------------------------------
13
18#include <ctype.h>
19#include <stdlib.h>
20#include <string.h>
21
22#include <iostream>
23
24#include "RtclBvi.hpp"
26
27using namespace std;
28
34// all method definitions in namespace Retro
35namespace Retro {
36
37static const int kOK = TCL_OK;
38static const int kERR = TCL_ERROR;
39
40//------------------------------------------+-----------------------------------
42
43void RtclBvi::CreateCmds(Tcl_Interp* interp)
44{
45 Tcl_CreateObjCommand(interp, "bvi", DoCmd,
46 reinterpret_cast<ClientData>(kStr2Int), nullptr);
47 Tcl_CreateObjCommand(interp, "pbvi", DoCmd,
48 reinterpret_cast<ClientData>(kInt2Str), nullptr);
49 return;
50}
51
52//------------------------------------------+-----------------------------------
54
55int RtclBvi::DoCmd(ClientData cdata, Tcl_Interp* interp, int objc,
56 Tcl_Obj* const objv[])
57{
58 bool list = false;
59 char form = 0;
60 int nbit = 0;
61 if (!CheckFormat(interp, objc, objv, list, form, nbit)) return kERR;
62
63 //ConvMode mode = (ConvMode)((int) cdata);
64 ConvMode mode = static_cast<ConvMode>(intptr_t(cdata));
65
66 if (list) {
67 int lobjc = 0;
68 Tcl_Obj** lobjv = nullptr;
69 if (Tcl_ListObjGetElements(interp, objv[2], &lobjc, &lobjv) != kOK) {
70 return kERR;
71 }
72
73 RtclOPtr rlist(Tcl_NewListObj(0, nullptr));
74
75 for (int i=0; i<lobjc; i++) {
76 RtclOPtr rval(DoConv(interp, mode, lobjv[i], form, nbit));
77 if (!rval) return kERR;
78 if (Tcl_ListObjAppendElement(interp, rlist, rval) != kOK) return kERR;
79 }
80
81 Tcl_SetObjResult(interp, rlist);
82
83 } else {
84 Tcl_Obj* rval = DoConv(interp, mode, objv[2], form, nbit);
85 if (rval==0) return kERR;
86 Tcl_SetObjResult(interp, rval);
87 }
88
89 return kOK;
90}
91
92//------------------------------------------+-----------------------------------
94
95Tcl_Obj* RtclBvi::DoConv(Tcl_Interp* interp, ConvMode mode, Tcl_Obj* val,
96 char form, int nbit)
97{
98 if (mode == kStr2Int) {
99 const char* pval = Tcl_GetString(val);
100 int lval = strlen(pval);
101
102 // strip leading blanks
103 while (pval[0]!=0 && ::isblank(pval[0])) {
104 pval++;
105 lval--;
106 }
107 // strip trailing blanks
108 while (lval>0 && ::isblank(pval[lval-1])) {
109 lval--;
110 }
111
112 // check for c"ddd" format
113 if (lval>3 && pval[1]=='"' && pval[lval-1]=='"') {
114 if (strchr("bBoOdDxX", pval[0]) == 0) {
115 Tcl_AppendResult(interp, "-E: bad prefix in c'dddd' format string",
116 nullptr);
117 return nullptr;
118 }
119 form = pval[0];
120 pval += 2;
121 lval -= 3;
122 // check for 0xddd format
123 } else if (lval>2 && pval[0]=='0' && (pval[1]=='x' || pval[1]=='X')) {
124 form = 'x';
125 pval += 2;
126 lval -= 2;
127 }
128
129 int base = 0;
130 switch (form) {
131 case 'b': case 'B': base = 2; break;
132 case 'o': case 'O': base = 8; break;
133 case 'd': case 'D': base = 10; break;
134 case 'x': case 'X': base = 16; break;
135 }
136
137 unsigned long lres=0;
138 char* eptr=0;
139
140 if (base==10 && pval[0]=='-') {
141 lres = static_cast<unsigned long>(::strtol(pval, &eptr, base));
142 if (nbit<32) lres &= (1ul<<nbit)-1;
143 } else {
144 lres = ::strtoul(pval, &eptr, base);
145 }
146
147 if (eptr != pval+lval) {
148 Tcl_AppendResult(interp, "-E: conversion error in '",
149 Tcl_GetString(val), "'", nullptr);
150 return nullptr;
151 }
152
153 if (lres > (1ul<<nbit)-1) {
154 Tcl_AppendResult(interp, "-E: too many bits defined in '",
155 Tcl_GetString(val), "'", nullptr);
156 return nullptr;
157 }
158
159 return Tcl_NewIntObj(int(lres));
160
161 } else if (mode == kInt2Str) {
162 int val_int;
163 if (Tcl_GetIntFromObj(interp, val, &val_int) != kOK) return nullptr;
164 unsigned int val_uint = val_int;
165
166 int nwidth = 1;
167 if (form=='o' || form=='O') nwidth = 3;
168 if (form=='x' || form=='X') nwidth = 4;
169 unsigned int nmask = (1<<nwidth)-1;
170
171 char buf[64];
172 char* pbuf = buf;
173 if (form=='B' || form=='O' || form=='X') {
174 *pbuf++ = tolower(form);
175 *pbuf++ = '"';
176 }
177
178 int ndig = (nbit+nwidth-1)/nwidth;
179 for (int i=ndig-1; i>=0; i--) {
180 unsigned int nibble = ((val_uint)>>(i*nwidth)) & nmask;
181 nibble += (nibble <= 9) ? '0' : ('a'-10);
182 *pbuf++ = char(nibble);
183 }
184
185 if (form=='B' || form=='O' || form=='X') {
186 *pbuf++ = '"';
187 }
188
189 return Tcl_NewStringObj(buf, pbuf-buf);
190
191 } else {
192 Tcl_AppendResult(interp, "-E: BUG! bad cdata in RtclBvi::DoConv() call",
193 nullptr);
194 }
195 return nullptr;
196}
197
198//------------------------------------------+-----------------------------------
200
201bool RtclBvi::CheckFormat(Tcl_Interp* interp, int objc, Tcl_Obj* const objv[],
202 bool& list, char& form, int& nbit)
203{
204 list = false;
205 form = 'b';
206 nbit = 0;
207
208 if (objc != 3) {
209 Tcl_WrongNumArgs(interp, 1, objv, "form arg");
210 return false;
211 }
212
213 const char* opt = Tcl_GetString(objv[1]);
214
215 while(*opt != 0) {
216 switch (*opt) {
217 case 'b':
218 case 'B':
219 case 'o':
220 case 'O':
221 case 'x':
222 case 'X':
223 form = *opt;
224 break;
225
226 case 'l':
227 list = true;
228 break;
229
230 default:
231 if (*opt>='0' && *opt<='9') {
232 nbit = 10*nbit + ((*opt) - '0');
233 if (nbit > 32) {
234 Tcl_AppendResult(interp, "-E: invalid bvi format '", opt, "'",
235 " bit count > 32", nullptr);
236 return false;
237 }
238 } else {
239 Tcl_AppendResult(interp, "-E: invalid bvi format '", opt, "'",
240 " allowed: [bBoOxXl][0-9]*", nullptr);
241 return false;
242 }
243 break;
244 }
245 opt++;
246 }
247
248 if (nbit==0) nbit=8;
249
250 return true;
251}
252
253} // end namespace Retro
static int DoCmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
FIXME_docs.
Definition: RtclBvi.cpp:55
static bool CheckFormat(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], bool &list, char &form, int &nbit)
FIXME_docs.
Definition: RtclBvi.cpp:201
static Tcl_Obj * DoConv(Tcl_Interp *interp, ConvMode mode, Tcl_Obj *val, char form, int nbit)
FIXME_docs.
Definition: RtclBvi.cpp:95
static void CreateCmds(Tcl_Interp *interp)
FIXME_docs.
Definition: RtclBvi.cpp:43
Implemenation (inline) of RtclOPtr.
Definition: RtclOPtr.hpp:23
Declaration of class ReventLoop.
Definition: ReventLoop.cpp:47
static const int kERR
Definition: RtclBvi.cpp:38
static const int kOK
Definition: RtclBvi.cpp:37