mirror of
https://git.gfz-potsdam.de/naaice/iphreeqc.git
synced 2025-12-15 16:18:22 +01:00
81f180a0 Fixed bugs in inverse 6d575967 strcpy_safe and strcat_safe 6d98c4e1 trying different header files 72796f15 added <cstring> e8481607 warnings, strcat, strcpy 988bdee0 Try using goto(s) 9b10ce3f Try updated logical expression 812061be Turn off optimizing on k_temp git-subtree-dir: src git-subtree-split: 81f180a069285bcb4d180c860664b4b2a193854d
1045 lines
23 KiB
C++
1045 lines
23 KiB
C++
#include "Phreeqc.h"
|
|
#include "phqalloc.h"
|
|
#include "Utils.h"
|
|
|
|
#if defined(PHREEQCI_GUI)
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
#endif
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
parse_eq(char* eqn, std::vector<class elt_list>& new_elt_list, int association)
|
|
/* ---------------------------------------------------------------------- */
|
|
/*
|
|
* function to break equation up into component species
|
|
* returns species name, coefficient, and charge in global variable "rxn_list".
|
|
* Also returns pointer to elt_list structure array with list of elements
|
|
* and coefficients in species.
|
|
* rxn_list global variable, output with contiguous rxn_list structures,
|
|
* which is the reaction. Target species is first in
|
|
* list, coefficient is -1.0.
|
|
*
|
|
* Argurments:
|
|
* *eqn input, pointer to equation to be parsed.
|
|
* **elt_ptr output, pointer to contiguous elt_list structures,
|
|
* which is list of elements and coefficients in the
|
|
* target species.
|
|
* association input, TRUE or FALSE if reaction is an association reaction
|
|
*/
|
|
{
|
|
int i;
|
|
LDBLE coef, l_z;
|
|
char c;
|
|
const char* cptr;
|
|
char token[MAX_LENGTH];
|
|
|
|
paren_count = 0;
|
|
/*
|
|
* Remove white space
|
|
*/
|
|
squeeze_white(eqn);
|
|
/*
|
|
* Check for illegal characters
|
|
*/
|
|
for (i = 0; (c = eqn[i]) != '\0'; i++)
|
|
{
|
|
if (islegit(c) == FALSE)
|
|
{
|
|
error_string = sformatf("Character is not allowed,\
|
|
%c (octal: %o).", c, c);
|
|
error_msg(error_string, CONTINUE);
|
|
return (ERROR);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Find coefficients, name, and charge for each species for lhs
|
|
*/
|
|
count_trxn = 0;
|
|
trxn.dz[0] = trxn.dz[1] = trxn.dz[2] = 0.0;
|
|
cptr = eqn;
|
|
c = cptr[0];
|
|
for (;;)
|
|
{
|
|
if (c == '=')
|
|
break;
|
|
if (c == '\0')
|
|
{
|
|
error_string = sformatf("Equation has no equal sign.\n\t%s", eqn);
|
|
error_msg(error_string, CONTINUE);
|
|
return (ERROR);
|
|
}
|
|
if (get_species(&cptr) == ERROR)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
c = cptr[0];
|
|
if (association == FALSE)
|
|
{
|
|
trxn.token[count_trxn].coef *= -1.0;
|
|
}
|
|
count_trxn++;
|
|
}
|
|
/*
|
|
* Get coefficient, name, and charge of species for dissociation reaction
|
|
*/
|
|
cptr++;
|
|
if (association == TRUE)
|
|
{
|
|
if (get_species(&cptr) == ERROR)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
trxn.token[count_trxn].coef *= -1.0;
|
|
/* Swap species into first structure position */
|
|
const char* char_ptr = trxn.token[0].name;
|
|
coef = trxn.token[0].coef;
|
|
l_z = trxn.token[0].z;
|
|
trxn.token[0].name = trxn.token[count_trxn].name;
|
|
trxn.token[0].coef = trxn.token[count_trxn].coef;
|
|
trxn.token[0].z = trxn.token[count_trxn].z;
|
|
trxn.token[count_trxn].name = char_ptr;
|
|
trxn.token[count_trxn].coef = coef;
|
|
trxn.token[count_trxn].z = l_z;
|
|
count_trxn++;
|
|
}
|
|
/*
|
|
* Get reaction species from rhs of equation
|
|
*/
|
|
c = cptr[0];
|
|
for (;;)
|
|
{
|
|
if (c == '\0')
|
|
break;
|
|
if (get_species(&cptr) == ERROR)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
c = cptr[0];
|
|
if (association == TRUE)
|
|
{
|
|
trxn.token[count_trxn].coef *= -1.0;
|
|
}
|
|
count_trxn++;
|
|
}
|
|
/*
|
|
* Sort list of reaction species
|
|
*/
|
|
trxn_sort();
|
|
/*
|
|
* Get elements in species or mineral formula
|
|
*/
|
|
count_elts = 0;
|
|
Utilities::strcpy_safe(token, MAX_LENGTH, trxn.token[0].name);
|
|
replace("(s)", "", token);
|
|
replace("(S)", "", token);
|
|
replace("(g)", "", token);
|
|
replace("(G)", "", token);
|
|
const char* char_ptr = token;
|
|
|
|
if (get_elts_in_species(&char_ptr, trxn.token[0].coef) == ERROR)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
/*
|
|
* Sort elements in reaction and combine
|
|
*/
|
|
if (elt_list_combine() == ERROR)
|
|
return (ERROR);
|
|
/*
|
|
* Malloc space and store element data for return
|
|
*/
|
|
new_elt_list.resize(count_elts + 1);
|
|
for (i = 0; i < count_elts; i++)
|
|
{
|
|
new_elt_list[i].elt = elt_list[i].elt;
|
|
new_elt_list[i].coef = -elt_list[i].coef;
|
|
}
|
|
new_elt_list[count_elts].elt = NULL;
|
|
|
|
/*
|
|
* Debugging print of parsed equation
|
|
trxn_print();
|
|
*/
|
|
return (OK);
|
|
}
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
check_eqn(int association)
|
|
/* ---------------------------------------------------------------------- */
|
|
/*
|
|
* Check that equation is balanced reaction. Uses array "trxn.token" and
|
|
* assumes "count_trxn" is set to number of species in reaction.
|
|
* Charge and elements are checked.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* association input, TRUE or FALSE if reaction is an association reaction.
|
|
*/
|
|
{
|
|
int i;
|
|
int oops = 0;
|
|
LDBLE sumcharge;
|
|
|
|
paren_count = 0;
|
|
count_elts = 0;
|
|
/*
|
|
* Check that coefficient of first species is -1.0
|
|
*/
|
|
if (equal(trxn.token[0].coef, -1.0, TOL) == FALSE)
|
|
{
|
|
if (association == TRUE)
|
|
{
|
|
error_string = sformatf(
|
|
"Coefficient of first species on rhs is not equal to 1.0.");
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
else
|
|
{
|
|
error_string = sformatf(
|
|
"Coefficient of mineral (first on lhs) is not equal to 1.0.");
|
|
error_msg(error_string, CONTINUE);
|
|
}
|
|
return (ERROR);
|
|
}
|
|
/*
|
|
* Go through all species in the reaction; sum the charge and store elements
|
|
*/
|
|
sumcharge = 0.0;
|
|
for (i = 0; i < count_trxn; i++)
|
|
{
|
|
sumcharge += (trxn.token[i].coef) * (trxn.token[i].z);
|
|
const char* t_ptr = trxn.token[i].name;
|
|
if (get_elts_in_species(&t_ptr, trxn.token[i].coef) == ERROR)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
}
|
|
/*
|
|
* Sort elements in reaction and combine
|
|
*/
|
|
if (elt_list_combine() == ERROR)
|
|
return (ERROR);
|
|
/*
|
|
* Check charge
|
|
*/
|
|
if (equal(sumcharge, 0.0, TOL) == FALSE)
|
|
{
|
|
error_string = sformatf( "Equation is not charge balanced, right - left = %7.4f moles charge", sumcharge);
|
|
error_msg(error_string, CONTINUE);
|
|
oops++;
|
|
}
|
|
/*
|
|
* Check mass balance
|
|
*/
|
|
for (i = 0; i < count_elts; i++)
|
|
{
|
|
if ((equal(elt_list[i].coef, 0.0, TOL) == FALSE) &&
|
|
strncmp((elt_list[i].elt)->name, "e", MAX_LENGTH) != 0)
|
|
{
|
|
error_string = sformatf(
|
|
"Equation does not balance for element, %s: right - left = %7.4f moles",
|
|
(elt_list[i].elt)->name, elt_list[i].coef);
|
|
error_msg(error_string, CONTINUE);
|
|
oops++;
|
|
}
|
|
}
|
|
if (oops == 0)
|
|
{
|
|
return (OK);
|
|
}
|
|
else
|
|
{
|
|
return (ERROR);
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
get_charge(char *charge, size_t charge_size, LDBLE * l_z)
|
|
/* ---------------------------------------------------------------------- */
|
|
/*
|
|
* Function takes character string and calculates the charge on
|
|
* the species. Charge can be in two forms: (1) string of "+" or "-"
|
|
* or (2) + or - followed by an integer. Charge is reduced to form (2)
|
|
* and stored in the pointer location *charge.
|
|
*
|
|
* Arguments:
|
|
* *charge input, string containing charge
|
|
* output, string containing charge of the form + or -
|
|
* followed by an integer, if integer greater than 1.
|
|
* *z output, value of charge.
|
|
*
|
|
* Returns:
|
|
* ERROR,
|
|
* OK.
|
|
*/
|
|
{
|
|
int i;
|
|
char* ptr;
|
|
char c, c1;
|
|
/*
|
|
* Charge is zero
|
|
*/
|
|
if ((c = charge[0]) == '\0')
|
|
{
|
|
*l_z = 0.0;
|
|
return (OK);
|
|
}
|
|
/*
|
|
* Error check for + or - at start of string
|
|
*/
|
|
if (c != '+' && c != '-')
|
|
{
|
|
error_string = sformatf(
|
|
"Character string for charge does not start with + or -,\t%s.",
|
|
charge);
|
|
error_msg(error_string, CONTINUE);
|
|
return (ERROR);
|
|
}
|
|
/*
|
|
* Count string of +'s or -'s
|
|
*/
|
|
i = 0;
|
|
while (c == (c1 = charge[i++]));
|
|
i--;
|
|
if (c1 == '\0')
|
|
{
|
|
if (c == '-')
|
|
i = -i;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* + or - followed by a number
|
|
*/
|
|
errno = 0;
|
|
i = strtol(charge, &ptr, 0);
|
|
/*
|
|
* Truncate fractional part of charge if all zeros
|
|
*/
|
|
if (*ptr != '\0')
|
|
{
|
|
if (*ptr == '.')
|
|
{
|
|
while (*(++ptr) != '\0')
|
|
{
|
|
if (*ptr != '0')
|
|
{
|
|
char* ptr;
|
|
*l_z = strtod(charge, &ptr);
|
|
return (OK);
|
|
}
|
|
}
|
|
/*
|
|
* Non-numeric characters
|
|
*/
|
|
}
|
|
else
|
|
{
|
|
error_string = sformatf(
|
|
"Error in character string for charge, %s.", charge);
|
|
error_msg(error_string, CONTINUE);
|
|
return (ERROR);
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* Charge is zero, must have had +0 or -0 in eqn
|
|
*/
|
|
if (i == 0)
|
|
{
|
|
charge[0] = '\0';
|
|
}
|
|
/*
|
|
* Charge is +1 or -1, single + or -
|
|
*/
|
|
if (abs(i) == 1)
|
|
{
|
|
charge[0] = c;
|
|
charge[1] = '\0';
|
|
}
|
|
/*
|
|
* Abs(z)>1, set charge to + or - plus integer
|
|
*/
|
|
if (abs(i) > 1)
|
|
{
|
|
if (snprintf(charge, charge_size, "%-+d", i) == EOF)
|
|
{
|
|
error_string = sformatf(
|
|
"Error converting charge to character string, %s.",
|
|
charge);
|
|
error_msg(error_string, CONTINUE);
|
|
return (ERROR);
|
|
}
|
|
}
|
|
*l_z = i;
|
|
return (OK);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
get_coef(LDBLE * coef, const char **eqnaddr)
|
|
/* ---------------------------------------------------------------------- */
|
|
/*
|
|
* Function reads through eqn and determines the coefficient of the next
|
|
* species.
|
|
*
|
|
* Arguments:
|
|
* *coef output, coefficient of next species.
|
|
*
|
|
* **eqnaddr input, pointer to a position in eqn to start parsing
|
|
* output, pointer to next position after coefficient
|
|
*
|
|
* Returns:
|
|
* ERROR,
|
|
* OK.
|
|
*/
|
|
{
|
|
int i;
|
|
char c, c1;
|
|
const char* cptr;
|
|
const char* rest;
|
|
char* ptr1;
|
|
char token[MAX_LENGTH];;
|
|
|
|
rest = *eqnaddr;
|
|
cptr = *eqnaddr; /* address of a position in eqn */
|
|
c = *cptr; /* character in eqn */
|
|
*coef = 0.0;
|
|
/*
|
|
* No leading sign or number
|
|
*/
|
|
if (isalpha((int) c) ||
|
|
(c == '(') || (c == ')') || (c == '[') || (c == ']'))
|
|
{
|
|
*coef = 1.0;
|
|
return (OK);
|
|
}
|
|
/*
|
|
* Leading +, no digits
|
|
*/
|
|
c1 = *(cptr + 1);
|
|
if (c == '+' &&
|
|
(isalpha((int) c1) ||
|
|
(c1 == '(') || (c1 == ')') || (c1 == '[') || (c1 == ']')))
|
|
{
|
|
*eqnaddr = ++cptr;
|
|
*coef = 1.0;
|
|
return (OK);
|
|
}
|
|
/*
|
|
* Leading -, no digits
|
|
*/
|
|
if (c == '-' &&
|
|
(isalpha((int) c1) ||
|
|
(c1 == '(') || (c1 == ')') || (c1 == '[') || (c1 == ']')))
|
|
{
|
|
*eqnaddr = ++cptr;
|
|
*coef = -1.0;
|
|
return (OK);
|
|
}
|
|
i = 0;
|
|
/*
|
|
* Has number coefficient
|
|
*/
|
|
if (isdigit((int) c) || c == '+' || c == '-' || c == '.')
|
|
{
|
|
while (isdigit((int) c) || c == '+' || c == '-' || c == '.')
|
|
{
|
|
token[i++] = c;
|
|
if (i >= MAX_LENGTH)
|
|
{
|
|
error_string = sformatf(
|
|
"Coefficient has more than MAX_LENGTH characters.");
|
|
error_msg(error_string, CONTINUE);
|
|
return (ERROR);
|
|
}
|
|
c = *(++cptr);
|
|
}
|
|
token[i] = '\0';
|
|
*eqnaddr = cptr;
|
|
errno = 0;
|
|
*coef = strtod(token, &ptr1);
|
|
if ((errno == ERANGE) || (*ptr1 != '\0'))
|
|
{
|
|
error_string = sformatf(
|
|
"Error converting coefficient in get_coef, %s.", token);
|
|
error_msg(error_string, CONTINUE);
|
|
return (ERROR);
|
|
}
|
|
return (OK);
|
|
}
|
|
/*
|
|
* None of the above, unknown construct
|
|
*/
|
|
error_string = sformatf(
|
|
"Illegal equation construct detected in get_coef.\n\t%s.", rest);
|
|
error_msg(error_string, CONTINUE);
|
|
return (ERROR);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
get_elt(const char** t_ptr, std::string& element, int* i)
|
|
/* ---------------------------------------------------------------------- */
|
|
/*
|
|
* Function reads an element name out of the equation string.
|
|
* An element name is composed of a capital letter followed by any number
|
|
* of lower case characters.
|
|
*
|
|
* Arguments:
|
|
* **t_ptr input, points to position in the equation to begin
|
|
* output, points to next character of equation after
|
|
* element name.
|
|
* *element input pointer to place to return element character string
|
|
*/
|
|
{
|
|
char c;
|
|
|
|
element.clear();
|
|
c = *(*t_ptr)++;
|
|
if (c == '\0')
|
|
{
|
|
error_string = sformatf(
|
|
"Empty string in get_elt. Expected an element name.");
|
|
error_msg(error_string, CONTINUE);
|
|
return (ERROR);
|
|
}
|
|
/*
|
|
* Load name into char array element
|
|
*/
|
|
element.push_back(c);
|
|
*i = 1;
|
|
if (c == '[')
|
|
{
|
|
while ((c = (**t_ptr)) != ']')
|
|
{
|
|
element.push_back(c);
|
|
(*i)++;
|
|
(*t_ptr)++;
|
|
if ((c = (**t_ptr)) == ']')
|
|
{
|
|
element.push_back(c);
|
|
(*i)++;
|
|
(*t_ptr)++;
|
|
break;
|
|
}
|
|
else if (**t_ptr == '\0')
|
|
{
|
|
error_msg("No ending bracket (]) for element name", CONTINUE);
|
|
input_error++;
|
|
break;
|
|
}
|
|
}
|
|
while (islower((int)(c = (**t_ptr))) || c == '_')
|
|
{
|
|
element.push_back(c);
|
|
(*i)++;
|
|
(*t_ptr)++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (islower((int)(c = (**t_ptr))) || c == '_')
|
|
{
|
|
element.push_back(c);
|
|
(*i)++;
|
|
(*t_ptr)++;
|
|
}
|
|
}
|
|
return (OK);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
get_elts_in_species(const char **t_ptr, LDBLE coef)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Makes a list of elements with their coefficients, stores elements
|
|
* in elt_list at position count_elts. Global variable count_elts is
|
|
* updated with each stored element. Also uses static global variable
|
|
* paren_count.
|
|
*
|
|
* Arguments:
|
|
* **t_ptr input, point in token string to start looking
|
|
* output, is next position to start looking
|
|
* coef input, coefficient to multiply subscripts by
|
|
*/
|
|
int l;
|
|
size_t count;
|
|
char c, c1;
|
|
LDBLE d;
|
|
std::string element;
|
|
const char** t_ptr_save = t_ptr;
|
|
while (((c = **t_ptr) != '+') && (c != '-') && (c != '\0'))
|
|
{
|
|
/* close parenthesis */
|
|
if (c == ')')
|
|
{
|
|
paren_count--;
|
|
if (paren_count < 0)
|
|
{
|
|
error_string = sformatf( "Too many right parentheses.");
|
|
error_msg(error_string, CONTINUE);
|
|
return (ERROR);
|
|
}
|
|
(*t_ptr)++;
|
|
return (OK);
|
|
}
|
|
c1 = *((*t_ptr) + 1);
|
|
/* beginning of element name */
|
|
if (isupper((int) c) || (c == 'e' && c1 == '-') || (c == '['))
|
|
{
|
|
/*
|
|
* Get new element and subscript
|
|
*/
|
|
if (get_elt(t_ptr, element, &l) == ERROR)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
if (count_elts >= (int)elt_list.size())
|
|
{
|
|
elt_list.resize(count_elts + 1);
|
|
}
|
|
elt_list[count_elts].elt = element_store(element.c_str());
|
|
if (get_num(t_ptr, &d) == ERROR)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
elt_list[count_elts].coef = d * coef;
|
|
count_elts++;
|
|
/*
|
|
* Expand working space for elements if necessary
|
|
*/
|
|
if (count_elts >= (int)elt_list.size())
|
|
{
|
|
elt_list.resize(count_elts + 1);
|
|
}
|
|
continue;
|
|
}
|
|
/*
|
|
* Open parentheses
|
|
*/
|
|
if (c == '(')
|
|
{
|
|
count = count_elts;
|
|
if (c1 == ')')
|
|
{
|
|
error_string = sformatf( "Empty parentheses.");
|
|
warning_msg(error_string);
|
|
}
|
|
paren_count++;
|
|
(*t_ptr)++;
|
|
if (get_elts_in_species(t_ptr, coef) == ERROR)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
if (get_num(t_ptr, &d) == ERROR)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
for (size_t i = count; i < count_elts; i++)
|
|
{
|
|
elt_list[i].coef *= d;
|
|
}
|
|
continue;
|
|
}
|
|
/*
|
|
* Colon
|
|
*/
|
|
if (c == ':')
|
|
{
|
|
count = count_elts;
|
|
(*t_ptr)++;
|
|
if (get_num(t_ptr, &d) == ERROR)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
if (get_elts_in_species(t_ptr, coef) == ERROR)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
for (size_t i = count; i < count_elts; i++)
|
|
{
|
|
elt_list[i].coef *= d;
|
|
}
|
|
continue;
|
|
}
|
|
/*
|
|
* Not beginning of element and not opening paren
|
|
*/
|
|
error_string = sformatf(
|
|
"Parsing error in get_elts_in_species, unexpected character, %c.",
|
|
c);
|
|
error_msg(error_string, CONTINUE);
|
|
input_error++;
|
|
return (ERROR);
|
|
}
|
|
if (paren_count != 0)
|
|
{
|
|
error_string = sformatf( "Unbalanced parentheses: %s", *t_ptr_save);
|
|
error_msg(error_string, CONTINUE);
|
|
input_error++;
|
|
return (ERROR);
|
|
}
|
|
return (OK);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
get_secondary(const char **t_ptr, char *element, int *i)
|
|
/* ---------------------------------------------------------------------- */
|
|
/*
|
|
* Function reads an element name out of the equation string.
|
|
* An element name is composed of a capital letter followed by any number
|
|
* of lower case characters.
|
|
*
|
|
* Arguments:
|
|
* **t_ptr input, points to position in the equation to begin
|
|
* output, points to next character of equation after
|
|
* element name.
|
|
* *element input pointer to place to return element character string
|
|
*/
|
|
{
|
|
int j;
|
|
char c;
|
|
const char* cptr;
|
|
|
|
c = *(*t_ptr)++;
|
|
if (c == '\0')
|
|
{
|
|
error_string = sformatf(
|
|
"Empty string in get_elt. Expected an element name.");
|
|
error_msg(error_string, CONTINUE);
|
|
input_error++;
|
|
return (ERROR);
|
|
}
|
|
/*
|
|
* Load name into char array element
|
|
*/
|
|
element[0] = c;
|
|
*i = 1;
|
|
if (c == '[')
|
|
{
|
|
while ((c = (**t_ptr)) != ']')
|
|
{
|
|
element[*i] = c;
|
|
(*i)++;
|
|
(*t_ptr)++;
|
|
if ((c = (**t_ptr)) == ']')
|
|
{
|
|
element[*i] = c;
|
|
(*i)++;
|
|
(*t_ptr)++;
|
|
c = (**t_ptr);
|
|
break;
|
|
}
|
|
else if ((c = (**t_ptr)) == '\0')
|
|
{
|
|
error_msg("Did not find ending bracket (])", CONTINUE);
|
|
input_error++;
|
|
return (ERROR);
|
|
}
|
|
}
|
|
while (islower((int) (c = (**t_ptr))) || c == '_')
|
|
{
|
|
element[*i] = c;
|
|
(*i)++;
|
|
(*t_ptr)++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (islower((int) (c = (**t_ptr))) || c == '_')
|
|
{
|
|
element[*i] = c;
|
|
(*i)++;
|
|
(*t_ptr)++;
|
|
}
|
|
}
|
|
/*
|
|
* Check if secondary master species element
|
|
*/
|
|
j = *i;
|
|
cptr = *t_ptr;
|
|
if (c == '(')
|
|
{
|
|
/* copy parenthesis */
|
|
element[*i] = c;
|
|
(*i)++;
|
|
(*t_ptr)++;
|
|
/* copy number */
|
|
for (;;)
|
|
{
|
|
c = **t_ptr;
|
|
if (isdigit((int) c) || c == '-' || c == '.')
|
|
{
|
|
element[*i] = c;
|
|
(*i)++;
|
|
(*t_ptr)++;
|
|
}
|
|
else if (c == '+')
|
|
{
|
|
(*t_ptr)++;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
/* go back to before parenthesis */
|
|
if (c != ')')
|
|
{
|
|
*i = j;
|
|
*t_ptr = cptr;
|
|
/* put in closing parenthesis */
|
|
}
|
|
else
|
|
{
|
|
element[*i] = c;
|
|
(*i)++;
|
|
(*t_ptr)++;
|
|
}
|
|
}
|
|
element[*i] = '\0';
|
|
return (OK);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
get_secondary_in_species(const char **t_ptr, LDBLE coef)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/*
|
|
* Makes a list of elements with their coefficients, stores elements
|
|
* in elt_list at position count_elts. Global variable count_elts is
|
|
* updated with each stored element. Also uses static global variable
|
|
* paren_count.
|
|
*
|
|
* Arguments:
|
|
* **t_ptr input, point in token string to start looking
|
|
* output, is next position to start looking
|
|
* coef input, coefficient to multiply subscripts by
|
|
*/
|
|
int l;
|
|
size_t count;
|
|
char c, c1;
|
|
LDBLE d;
|
|
char element[MAX_LENGTH];
|
|
const char** t_ptr_save = t_ptr;
|
|
while (((c = **t_ptr) != '+') && (c != '-') && (c != '\0'))
|
|
{
|
|
/* close parenthesis */
|
|
if (c == ')')
|
|
{
|
|
paren_count--;
|
|
if (paren_count < 0)
|
|
{
|
|
error_string = sformatf( "Too many right parentheses.");
|
|
error_msg(error_string, CONTINUE);
|
|
input_error++;
|
|
return (ERROR);
|
|
}
|
|
(*t_ptr)++;
|
|
return (OK);
|
|
}
|
|
c1 = *((*t_ptr) + 1);
|
|
/* beginning of element name */
|
|
if (isupper((int) c) || c == '[' || (c == 'e' && c1 == '-'))
|
|
{
|
|
/*
|
|
* Get new element and subscript
|
|
*/
|
|
if (get_secondary(t_ptr, element, &l) == ERROR)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
elt_list[count_elts].elt = element_store(element);
|
|
if (get_num(t_ptr, &d) == ERROR)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
elt_list[count_elts].coef = d * coef;
|
|
count_elts++;
|
|
/*
|
|
* Expand working space for elements if necessary
|
|
*/
|
|
if (count_elts >= (int)elt_list.size())
|
|
{
|
|
elt_list.resize(count_elts + 1);
|
|
}
|
|
continue;
|
|
}
|
|
/*
|
|
* Open parentheses
|
|
*/
|
|
if (c == '(')
|
|
{
|
|
count = count_elts;
|
|
if (c1 == ')')
|
|
{
|
|
error_string = sformatf( "Empty parentheses.");
|
|
warning_msg(error_string);
|
|
}
|
|
paren_count++;
|
|
(*t_ptr)++;
|
|
if (get_secondary_in_species(t_ptr, coef) == ERROR)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
if (get_num(t_ptr, &d) == ERROR)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
for (size_t i = count; i < count_elts; i++)
|
|
{
|
|
elt_list[i].coef *= d;
|
|
}
|
|
continue;
|
|
}
|
|
/*
|
|
* Colon
|
|
*/
|
|
if (c == ':')
|
|
{
|
|
count = count_elts;
|
|
(*t_ptr)++;
|
|
if (get_num(t_ptr, &d) == ERROR)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
if (get_secondary_in_species(t_ptr, coef) == ERROR)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
for (size_t i = count; i < count_elts; i++)
|
|
{
|
|
elt_list[i].coef *= d;
|
|
}
|
|
continue;
|
|
}
|
|
/*
|
|
* Not beginning of element and not opening paren
|
|
*/
|
|
error_string = sformatf(
|
|
"Parsing error in get_secondary_in_species, unexpected character, %c.",
|
|
c);
|
|
error_msg(error_string, CONTINUE);
|
|
return (ERROR);
|
|
}
|
|
if (paren_count != 0)
|
|
{
|
|
error_string = sformatf("Unbalanced parentheses: %s", *t_ptr_save);
|
|
error_msg(error_string, CONTINUE);
|
|
return (ERROR);
|
|
}
|
|
return (OK);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
get_num(const char **t_ptr, LDBLE * num)
|
|
/* ---------------------------------------------------------------------- */
|
|
/*
|
|
* Function reads through a string looking for leading numeric field
|
|
* if no numeric field is found, the number is set to 1.0.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* **t_ptr input, points to a position in a character string from which
|
|
* a number is to be extracted.
|
|
* output, points to next position to be parsed.
|
|
* *num address where the number is to be stored.
|
|
*
|
|
* Returns:
|
|
* ERROR,
|
|
* OK.
|
|
*/
|
|
{
|
|
int i, decimal;
|
|
char c;
|
|
char* ptr1;
|
|
char token[MAX_LENGTH];
|
|
|
|
*num = 1.0;
|
|
i = 0;
|
|
c = **t_ptr;
|
|
decimal = 0;
|
|
if (isdigit((int) c) || (c == '.'))
|
|
{
|
|
while (isdigit((int) c) || (c == '.'))
|
|
{
|
|
if (c == '.')
|
|
decimal++;
|
|
if (decimal > 1)
|
|
break;
|
|
token[i++] = c;
|
|
/* check number length */
|
|
if (i >= MAX_LENGTH)
|
|
{
|
|
error_string = sformatf(
|
|
"Number was greater than MAX_LENGTH characters.");
|
|
error_msg(error_string, CONTINUE);
|
|
input_error++;
|
|
return (ERROR);
|
|
}
|
|
c = *(++(*t_ptr));
|
|
}
|
|
token[i] = '\0';
|
|
errno = 0;
|
|
*num = strtod(token, &ptr1);
|
|
if (errno == ERANGE)
|
|
{
|
|
error_string = sformatf( "Converting number in get_num, %s.", token);
|
|
input_error++;
|
|
error_msg(error_string, CONTINUE);
|
|
return (ERROR);
|
|
}
|
|
}
|
|
return (OK);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
int Phreeqc::
|
|
get_species(const char **cptr)
|
|
/* ---------------------------------------------------------------------- */
|
|
{
|
|
/* Function reads next species out of the equation, including optional
|
|
* preceding coefficient and optional trailing charge. Data are
|
|
* store in trxn.token[count].
|
|
*
|
|
* Arguments:
|
|
* **cptr input, points to the position in the equation to pick up the species.
|
|
* output, points to the next character after the species charge.
|
|
*
|
|
*/
|
|
std::string string;
|
|
int l;
|
|
|
|
if ((size_t) count_trxn + 1 > trxn.token.size())
|
|
trxn.token.resize(count_trxn + 1);
|
|
/* coefficient */
|
|
if (get_coef(&(trxn.token[count_trxn].coef), cptr) == ERROR)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
/* name and charge */
|
|
if (get_token(cptr, string, &trxn.token[count_trxn].z, &l) == ERROR)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
trxn.token[count_trxn].name = string_hsave(string.c_str());
|
|
/*
|
|
trxn.token[count_trxn].z = 0;
|
|
trxn.token[count_trxn].s = NULL;
|
|
trxn.token[count_trxn].unknown = NULL;
|
|
*/
|
|
return (OK);
|
|
}
|