blob: 9544065dce0ac9f73c684c3c0858fc5cc4aefe18 [file] [log] [blame]
/* Copyright 2015. Los Alamos National Security, LLC. This material was produced
* under U.S. Government contract DE-AC52-06NA25396 for Los Alamos National
* Laboratory (LANL), which is operated by Los Alamos National Security, LLC
* for the U.S. Department of Energy. The U.S. Government has rights to use,
* reproduce, and distribute this software. NEITHER THE GOVERNMENT NOR LOS
* ALAMOS NATIONAL SECURITY, LLC MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR
* ASSUMES ANY LIABILITY FOR THE USE OF THIS SOFTWARE. If software is modified
* to produce derivative works, such modified software should be clearly marked,
* so as not to confuse it with the version available from LANL.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* Under this license, it is required to include a reference to this work. We
* request that each derivative work contain a reference to LANL Copyright
* Disclosure C15076/LA-CC-15-054 so that this work's impact can be roughly
* measured.
*
* This is LANL Copyright Disclosure C15076/LA-CC-15-054
*/
/*
* PowerParser is a general purpose input file parser for software applications.
*
* Authors: Chuck Wingate XCP-2 caw@lanl.gov
* Robert Robey XCP-2 brobey@lanl.gov
*/
// ***************************************************************************
// ***************************************************************************
// This class collects various low level utilities for the parser.
// ***************************************************************************
// ***************************************************************************
#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
#include <vector>
#include <deque>
#include "Parser_utils.hh"
namespace PP
{
using std:: string;
using std::cout;
using std::endl;
using std::stringstream;
using std::setprecision;
using std::vector;
using std::deque;
using std::setw;
static int index_base = 1; // For Fortran, 0 for C/C++style
// ===========================================================================
// Default constructor.
// ===========================================================================
Parser_utils::Parser_utils(int base)
{
index_base = base;
}
// ===========================================================================
// Given an array command like
// cmd(5,3) = 1.0, 3.0, -5.0
// find the starting position in a 1d array.
//
// The indices in cmd are referenced from 1 (i.e. fortran) while the 1d array
// is referenced from 0 (C++).
//
// This function works for any dimension array, 0,1,2,3,...
//
// Example 1: Consider a 1d command
// cmd(5) = 1.0, 3.4
// We start filling the 1d fortran array at position 5 and put in two values.
// Subtract 1 to reference from 0, so this function returns 4.
//
// Example 2: Consider the 2d command above:
// cmd(5,3) = 1.0, 3.0, -5.0
// We also need to know that the max size of the first dimension is say 7.
// Since in fortran, the first index varies fastest, the fortran 1d index
// would be
// 5 + (3-1)*7 = 19
// Subtract 1 to reference from 0, thus the return value is 18.
//
// The istart vector contains the indices, for example 2 this would be 5 and
// 3. The size vector contains the max size of each dimension, for example 2
// this would be 7 and whatever for the second dimension.
// ===========================================================================
int Parser_utils::start_dex(vector<int> &istart, const vector<int> &size)
{
// Get the array dimension, 0,1,2,3,...
int dim = (int)istart.size();
// 0d is a special case.
if (dim == 0) return 0;
// Find the index.
// Adjustment for base 1
int ix = istart[0]-index_base;
for (int i=1; i<dim; i++) {
int t = istart[i]-index_base;
for (int j=0; j<i; j++) {
t *= size[j];
}
ix += t;
}
return ix;
}
// ===========================================================================
// This is the reverse of the start_dex function above.
// Given the 1d index, icdex (from 0 to nvals-1), find the corresponding
// multi dimensional fortran indices (each starting from 1).
//
// Example 1: Consider a 1d array
// var1d(1) = 1 3 5 9 -4 -5 6
// Suppose the user inputs icdex=3, corresponding to array value 9.
// This 1d case is very simple, all we do is add 1 to icdex to get a reference
// from 1, thus returning 4.
//
// Example 1: Consider a 2d array
// $var2d(1,1) = 11. 21. 31. 12. 22. 32. 13. 23. 33.
// Where the max of the first dimension is 3. Suppose the user specifies
// icdex = 5, this corresponds to array value 32. The two indices returned
// would be 3,2 (referenced from 1).
//
// The istart vector contains the output indices, for example 2 this would be 3
// and 2. The size vector contains the max size of each dimension, for example
// 2 this would be 3 and whatever for the second dimension. The number of
// elements in size is normally dim-1, but it does not hurt if it has dim
// elements (in which case the last element is not referenced or used).
// ===========================================================================
void Parser_utils::reverse_dex(int icdex,
int nvals,
vector<int> &istart,
const vector<int> &size)
{
// Get the dimension.
int dim = (int)istart.size();
// Nothing to do for scalars.
if (dim == 0) return;
// Start at 1,1,1,1,1,1,...
for (int i=0; i<dim; i++) {
istart[i] = index_base;
}
// Get the first 1d index (referenced from 0)
int i1 = start_dex(istart, size);
if (i1 == icdex) return;
// Go through all indices until the desired one is found.
// Yes, this is inefficient, but dim is a small integer, like 2,3,4, so
// the efficiency does not really matter.
// Perhaps somebody can devise a better algorithm someday.
for (int i1dex=0; i1dex<nvals; i1dex++) {
for (int i=0; i<dim; i++) {
if (i < dim-1) {
if (istart[i] == size[i]) {
istart[i] = index_base;
}
else {
istart[i] += 1;
break;
}
}
else {
istart[i] += 1;
break;
}
}
i1 = start_dex(istart, size);
if (i1 == icdex) return;
}
}
// ***************************************************************************
// ***************************************************************************
// Utilities for printing to the screen (or to a file).
// ***************************************************************************
// ***************************************************************************
// ===========================================================================
// Line
// Filename Number Command
// ------------ ------ ------------------------------------------------
// test.in 4 some_logical_cmd = false
// test.in 28 some_logical_cmd = false
// test.in 170 some_logical_cmd = false
// test.in 175 some_logical_cmd = true //No space betwe ...
// test_inc1.in 2 some_logical_cmd = true
// test_inc3.in 2 some_logical_cmd = true
//
// test.in 442 strinsert_cmd01 = "test duplicates commands"
// test.in 456 strinsert_cmd01 = "test duplicates commands"
// Given a header row of strings and several data rows of string where each
// row consists of the same number of columns, list all the rows with the
// columns lined up and the headers centered on the columns.
// ===========================================================================
void Parser_utils::print_strings(vector< vector<string> > rows, int n_header_rows,
int offset, int col_spacing, int line_len_max,
stringstream &ss)
{
// Get the number of columns.
int ncol = (int)rows[0].size();
// Find the max number of characters in each column for all the rows.
vector<int> maxc(ncol, 0);
for (int row=0; row<(int)rows.size(); row++) {
for (int c=0; c<ncol; c++) {
string s = rows[row][c];
if ((int)s.size() > maxc[c]) maxc[c] = (int)s.size();
}
}
// Find the column widths.
vector<int> col_width(ncol,0);
for (int c=0; c<ncol; c++) {
if (maxc[c] > col_width[c]) col_width[c] = maxc[c];
}
// Spacing between columns.
vector<int> cspace(ncol, col_spacing);
cspace[0] = offset;
// Limit the lines to a max length.
if (line_len_max > 0) {
int line_len = 0;
for (int c=0; c<ncol; c++) {
line_len += cspace[c] + col_width[c];
}
int excess_c = line_len - line_len_max;
if (excess_c > 0) {
col_width[ncol-1] -= excess_c;
for (int row=0; row<(int)rows.size(); row++) {
int len = 0;
for (int c=0; c<ncol; c++) {
string s = rows[row][c];
if (c < ncol-1) len += cspace[c] + col_width[c];
if (c == ncol-1) len += cspace[c] + (int)s.size();
}
if (len <= line_len_max) continue;
int c = ncol -1;
string s = rows[row][c];
int ec = len - line_len_max;
int start = (int)s.size() - ec - 4;
if (start < 0) start = 0;
int nc = ec+4;
if (nc > (int)s.size()) nc = (int)s.size();
s.erase(start, nc);
rows[row][c] = s + " ...";
}
}
}
// Write the rows.
for (int row=0; row<(int)rows.size(); row++) {
// Insert the line of dashes after the header rows.
if (row == n_header_rows) {
for (int c=0; c<ncol; c++) {
for (int i=0; i<cspace[c]; i++) ss << " ";
for (int i=0; i<col_width[c]; i++) ss << "-";
}
ss << endl;
}
for (int c=0; c<ncol; c++) {
// Use nc to center the headers, but not center the data.
int nc = maxc[c];
if (row < n_header_rows) nc = (int)rows[row][c].size();
int nsp_left = 0;
int nsp_right = 0;
int dsp = col_width[c] - nc;
if (dsp > 0) {
nsp_left = dsp/2;
nsp_right = col_width[c] - nsp_left - nc;
}
for (int i=0; i<cspace[c]; i++) ss << " ";
for (int i=0; i<nsp_left; i++) ss << " ";
if (row >= n_header_rows) {
if (c < ncol-1) ss << setw(maxc[c]) << rows[row][c];
if (c == ncol-1) ss << rows[row][c];
}
else {
ss << rows[row][c];
}
for (int i=0; i<nsp_right; i++) ss << " ";
}
ss << endl;
}
}
} // End of the PP namespace