StringUtils.cpp
Go to the documentation of this file.
1 //==============================================================================
2 //
3 // This file is part of GNSSTk, the ARL:UT GNSS Toolkit.
4 //
5 // The GNSSTk is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published
7 // by the Free Software Foundation; either version 3.0 of the License, or
8 // any later version.
9 //
10 // The GNSSTk is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with GNSSTk; if not, write to the Free Software Foundation,
17 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
18 //
19 // This software was developed by Applied Research Laboratories at the
20 // University of Texas at Austin.
21 // Copyright 2004-2022, The Board of Regents of The University of Texas System
22 //
23 //==============================================================================
24 
25 //==============================================================================
26 //
27 // This software was developed by Applied Research Laboratories at the
28 // University of Texas at Austin, under contract to an agency or agencies
29 // within the U.S. Department of Defense. The U.S. Government retains all
30 // rights to use, duplicate, distribute, disclose, or release this software.
31 //
32 // Pursuant to DoD Directive 523024
33 //
34 // DISTRIBUTION STATEMENT A: This software has been approved for public
35 // release, distribution is unlimited.
36 //
37 //==============================================================================
38 
44 #include "StringUtils.hpp"
45 
46 /* The DEBUG_COL macro is used to help debug issues with column
47  * alignment and positioning. If enabled, it will print, to stderr, a
48  * string of characters representing what's being appended to the
49  * stream in each column of text. To use it, rename the first macro
50  * with the cerr statement to DEBUG_COL and the second macro to
51  * DEBUG_COL_NO. To disable, do the opposite. */
52 #define DEBUG_COL_NO(LABEL,ADDED) \
53  if (ADDED > 0) \
54  std::cerr << std::string(ADDED,LABEL) << std::flush;
55 
56 #define DEBUG_COL(LABEL,ADDED)
57 
58 namespace gnsstk
59 {
60  namespace StringUtils
61  {
62  void hexDumpData(const std::string& data, std::ostream& s,
63  const HexDumpDataConfig& cfg)
64  {
65  // save the state in a stream object that doesn't need an
66  // externally defined buffer or any of that crap.
67  std::ostringstream oldState;
68  oldState.copyfmt(s);
69  std::string ascii="";
70  int col = 0;
71  int datasize=data.size();
72  unsigned linesize;
73 
74  if (cfg.groupBy && ((cfg.bytesPerLine % cfg.groupBy) != 0))
75  {
76  s << "hexDumpData: cfg.bytesPerLine % cfg.groupBy != 0"
77  << std::endl;
78  s.copyfmt(oldState);
79  return;
80  }
81  if (cfg.group2By && ((cfg.bytesPerLine % cfg.group2By) != 0))
82  {
83  s << "hexDumpData: cfg.bytesPerLine % cfg.group2By != 0"
84  << std::endl;
85  s.copyfmt(oldState);
86  return;
87  }
88  if (cfg.groupBy && ((cfg.group2By % cfg.groupBy) != 0))
89  {
90  s << "hexDumpData: cfg.group2By % cfg.groupBy != 0"
91  << std::endl;
92  s.copyfmt(oldState);
93  return;
94  }
95 
96  // line format:
97  // <prefix><index><indexSep><group1byte1>...<group1byte[groupBy]><groupSep>...<group[group2By]byte1>...<group[group2By]byte[groupBy]><group2Sep>....<byte[bytesPerLine]><dataEndSep/dataFinal><preText><separator><text><separator>\n
98  // make sure our default formatting options are set
99  s << std::hex << std::internal << std::noshowbase << std::setw(0);
100 
101  unsigned bytesOnLastLine = datasize % cfg.bytesPerLine;
102  if (bytesOnLastLine == 0)
103  bytesOnLastLine = cfg.bytesPerLine;
104  linesize = std::max(
105  cfg.computeLineSize(cfg.bytesPerLine, false),
106  cfg.computeLineSize(bytesOnLastLine, true));
107 
108  for (int i=0; i<datasize; i++)
109  {
110  if (i%cfg.bytesPerLine==0)
111  {
112  // add the prefix text at the beginning of each line
113  s << cfg.prefix;
114  col = cfg.prefix.length();
115  DEBUG_COL('P',cfg.prefix.length());
116  if (cfg.showIndex)
117  {
118  // print the data index in either hex or decimal,
119  // with or without a radix indicator all
120  // according to cfg
121  std::string indexBase(cfg.baseIndex());
122  s << std::setfill('0')
123  << (cfg.upperHex ? std::uppercase : std::nouppercase)
124  << cfg.baseIndex()
125  << (cfg.hexIndex ? std::hex : std::dec)
126  << std::setw(cfg.idxDigits)
127  << i << cfg.indexSep
128  << std::noshowbase << std::dec << std::nouppercase;
129  col += indexBase.length() + cfg.idxDigits +
130  cfg.indexSep.length();
131  DEBUG_COL('I',indexBase.length() + cfg.idxDigits + cfg.indexSep.length());
132  }
133  }
134  unsigned char c=data[i];
135  // construct the ASCII representation using only
136  // printable characters
137  if (isprint(c))
138  ascii += c;
139  else
140  ascii += '.';
141  if (cfg.groupBy && ((i % cfg.groupBy) == 0) && cfg.showBaseData)
142  {
143  // print the hex radix indicator if requested
144  s << cfg.baseData();
145  col += 2;
146  DEBUG_COL('R',2);
147  }
148  // print the byte value in hex
149  s << (cfg.upperHex ? std::uppercase : std::nouppercase)
150  << std::hex << std::setw(2) << std::setfill('0') << (int)c
151  << std::dec << std::nouppercase << std::noshowbase;
152  col += 2;
153  DEBUG_COL('B',2);
154  if (((i % cfg.bytesPerLine) == (cfg.bytesPerLine-1)) ||
155  (i == (datasize-1)))
156  {
157  if (i == (datasize-1))
158  {
159  // this is the very last byte of data, print the
160  // final terminator text dataFinal
161  s << cfg.dataFinal;
162  col += cfg.dataFinal.length();
163  DEBUG_COL('F',cfg.dataFinal.length());
164  }
165  else if ((i % cfg.bytesPerLine) == (cfg.bytesPerLine-1))
166  {
167  // this is the last byte on the line of text,
168  // print the end-of-line terminator text
169  // dataEndSep
170  s << cfg.dataEndSep;
171  col += cfg.dataEndSep.length();
172  DEBUG_COL('E',cfg.dataEndSep.length());
173  }
174  if (cfg.showText)
175  {
176  // print the ASCII representation of the data
177  int extra = linesize-col;
178  std::string space(extra, ' ');
179  s << space << cfg.preText;
180  DEBUG_COL('s', extra);
181  DEBUG_COL('T', cfg.preText.length());
182  s << ascii;
183  DEBUG_COL('A', ascii.length());
184  s << cfg.postText;
185  DEBUG_COL('t', cfg.postText.length());
186  }
187  s << std::endl;
188  DEBUG_COL('\n', 1);
189  ascii.erase();
190  }
191  else if (cfg.group2By && ((i % cfg.group2By) == (cfg.group2By-1)))
192  {
193  // level 2 group separator
194  s << cfg.group2Sep;
195  col += cfg.group2Sep.length();
196  DEBUG_COL('O',cfg.group2Sep.length());
197  }
198  else if (cfg.groupBy && ((i % cfg.groupBy) == (cfg.groupBy-1)))
199  {
200  // level 1 group separator
201  s << cfg.groupSep;
202  col += cfg.groupSep.length();
203  DEBUG_COL('G',cfg.groupSep.length());
204  }
205  }
206  s.copyfmt(oldState);
207  }
208 
209 
210  std::string floatFormat(double d, FFLead lead, unsigned mantissa,
211  unsigned exponent, unsigned width, char expChar,
212  FFSign sign, FFAlign align)
213  {
214  std::ostringstream oss;
215  std::string rv;
216  std::string::size_type pos;
217  switch (sign)
218  {
219  case FFSign::NegOnly:
220  // default behavior for iostream
221  break;
222  case FFSign::NegSpace:
223  if (d >= 0)
224  oss << " ";
225  break;
226  case FFSign::NegPos:
227  oss << std::showpos;
228  break;
229  }
230  switch (lead)
231  {
232  case FFLead::Zero:
233  // because we're shifting the decimal point, we multiply by 10
234  // mantissa-2 because we're adding a digit that
235  // isn't present in std c++ iostream.
236  oss << std::scientific << std::setprecision(mantissa-2)
237  << (d*10);
238  rv = oss.str();
239  // move the decimal
240  pos = rv.find('.');
241  rv[pos] = rv[pos-1];
242  rv[pos-1] = '.';
243  rv.insert(pos-1, 1, '0');
244  break;
245  case FFLead::Decimal:
246  // because we're shifting the decimal point, we multiply by 10
247  oss << std::scientific << std::setprecision(mantissa-1)
248  << (d*10);
249  rv = oss.str();
250  // move the decimal
251  pos = rv.find('.');
252  rv[pos] = rv[pos-1];
253  rv[pos-1] = '.';
254  break;
255  case FFLead::NonZero:
256  // This is the default behavior for C++ iostream.
257  oss << std::scientific << std::setprecision(mantissa-1) << d;
258  rv = oss.str();
259  break;
260  }
261  // change the exponent size if needed
262  pos = rv.find('e');
263  unsigned currentExpSize = rv.length() - (pos+2);
264  if (currentExpSize < exponent)
265  rv.insert(pos+2, exponent - currentExpSize, '0');
266  // change exponent character
267  rv[pos] = expChar;
268  // fill according to alignment request
269  if (rv.length() < width)
270  {
271  switch (align)
272  {
273  case FFAlign::Left:
274  rv.append(width-rv.length(), ' ');
275  break;
276  case FFAlign::Right:
277  rv.insert(0, width-rv.length(), ' ');
278  break;
279  }
280  }
281  return rv;
282  }
283  } // namespace StringUtils
284 } // namespace gnsstk
gnsstk::StringUtils::HexDumpDataConfig
Class for configuring the appearance of hexDumpData() output.
Definition: HexDumpDataConfig.hpp:58
gnsstk::StringUtils::FFAlign::Left
@ Left
Formatted output will be left-aligned.
StringUtils.hpp
cfg
#define cfg(a)
Definition: DiscCorr.cpp:624
gnsstk::max
T max(const SparseMatrix< T > &SM)
Maximum element - return 0 if empty.
Definition: SparseMatrix.hpp:881
gnsstk::StringUtils::FFSign::NegPos
@ NegPos
Prefix output with a minus sign (neg) or plus sign (pos)
gnsstk
For Sinex::InputHistory.
Definition: BasicFramework.cpp:50
gnsstk::StringUtils::FFAlign::Right
@ Right
Formatted output will be right-aligned.
gnsstk::StringUtils::FFLead
FFLead
Leading character for floatFormat(), after any whitespace or sign.
Definition: StringUtils.hpp:109
gnsstk::StringUtils::floatFormat
std::string floatFormat(double d, FFLead lead, unsigned mantissa, unsigned exponent, unsigned width, char expChar, FFSign sign, FFAlign align)
Definition: StringUtils.cpp:210
gnsstk::StringUtils::FFSign::NegOnly
@ NegOnly
Prefix output with a minus sign (neg) or nothing (pos)
gnsstk::StringUtils::FFLead::Zero
@ Zero
Start with zero, e.g. 0.12345.
gnsstk::StringUtils::FFSign::NegSpace
@ NegSpace
Prefix output with a minus sign (neg) or space (pos)
gnsstk::StringUtils::hexDumpData
void hexDumpData(const std::string &data, std::ostream &s, const HexDumpDataConfig &cfg)
Definition: StringUtils.cpp:62
gnsstk::StringUtils::FFLead::Decimal
@ Decimal
Start with decimal, e.g. .12345.
gnsstk::StringUtils::FFLead::NonZero
@ NonZero
Start with the first non-zero digit, e.g. 1.2345.
DEBUG_COL
#define DEBUG_COL(LABEL, ADDED)
Definition: StringUtils.cpp:56
example4.pos
pos
Definition: example4.py:125
example3.data
data
Definition: example3.py:22
gnsstk::StringUtils::FFSign
FFSign
How to handle sign in floatFormat()
Definition: StringUtils.hpp:117
gnsstk::StringUtils::FFAlign
FFAlign
Alignment of data for floatFormat()
Definition: StringUtils.hpp:125


gnsstk
Author(s):
autogenerated on Wed Oct 25 2023 02:40:41