Compare commits

...

6 Commits

Author SHA1 Message Date
Landon Curt Noll
f1a4cb6313 update GitHub workflows to use actions/checkout@v5 2025-08-17 12:26:37 -07:00
Landon Curt Noll
59d47e80fb checkpoint test .github/workflows/dependency-review.yml 2025-08-17 12:17:23 -07:00
Landon Curt Noll
95793c3150 checkpoint on string realloc bug fix attempt
In preparation to fix issue #47, we:

Fix a minor typo in `Makefile.config`.

Move `stringindex(char *format, char *test)` from `str.c` into `codegen.c`
as static function.

Expand `STR_TABLECHUNK` from `1<<10` to `1<<16`.

Identify with an XXX comment, a problematic `realloc()` call in the
`addstr(STRINGHEAD *hp, char *str)` function of `str.c`.

Move the `charstr(int ch)` in `str.c` above the only function that uses
it, `addliteral(char *str)`, and make it a static function.

Improved comments about return values for `str.c` functions that
work on STRINGHEAD pointers.
2025-08-17 02:18:10 -07:00
Landon Curt Noll
077ba65285 Release v2.16.0.0
The following are the changes in this release:

    Starting with calc version 2.16.0.0, the ability to perform arithmetic
    on addresses of values in calc objects has been greatly restricted.

    Most arithmetic on of value addresses could easily cause calc to
    crash.  For example, prior to calc version 2.16.0.0, the following
    command was likely to crash calc:

        calc '*((&.)+1e9)'

    Subtracting two value addresses is permitted, however there is NO
    guarantee that the address of a value will remain consistent across
    calc runs.  Addresses of values depend on the circumstances of when
    the calc values were formed.

    The above restrictions and caveats apply to addresses of values.
    Such restrictions and caveats to NOT apply to the addresses of
    octets, NOR to the addresses within strings.  If isptr(x) == 2, then
    x is value-pointer and the above mentioned restrictions and caveats apply.

    See "help address" for more information on value address arithmetic.

    Added E_INVALID_DEREF (10610) error code to indicate the invalid
    dereferencing a non-variable.

    Added E_INVALID_ADDR_OP (10611) error code to indicate an invalid
    arithmetic address operation.

    We plan to let this most recent change settle down before performing
    the calc v2 to calc v3 fork.  Therefore, version 2.16.1.0 will form
    the basis for the calc v2 to calc v3 fork.
2025-08-14 18:34:32 -07:00
Landon Curt Noll
f912da9427 checkpoint adding missing edit to Makefile.config 2025-08-14 18:26:47 -07:00
Landon Curt Noll
753b101e54 prep for 2.16.0.0 release with value address arithmetic restrictions 2025-08-14 18:23:07 -07:00
14 changed files with 297 additions and 119 deletions

View File

@@ -40,7 +40,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Setup node
uses: actions/setup-node@v4
with:

14
.github/workflows/dependency-review.yml vendored Normal file
View File

@@ -0,0 +1,14 @@
name: 'Dependency Review'
on: [pull_request]
permissions:
contents: read
jobs:
dependency-review:
runs-on: ubuntu-latest
steps:
- name: 'Checkout Repository'
uses: actions/checkout@v5
- name: 'Dependency Review'
uses: actions/dependency-review-action@v4

36
CHANGES
View File

@@ -1,3 +1,37 @@
The following are the changes from calc version 2.15.1.2 to 2.16.0.0:
Starting with calc version 2.16.0.0, the ability to perform arithmetic
on addresses of values in calc objects has been greatly restricted.
Most arithmetic on of value addresses could easily cause calc to
crash. For example, prior to calc version 2.16.0.0, the following
command was likely to crash calc:
calc '*((&.)+1e9)'
Subtracting two value addresses is permitted, however there is NO
guarantee that the address of a value will remain consistent across
calc runs. Addresses of values depend on the circumstances of when
the calc values were formed.
The above restrictions and caveats apply to addresses of values.
Such restrictions and caveats to NOT apply to the addresses of
octets, NOR to the addresses within strings. If isptr(x) == 2, then
x is value-pointer and the above mentioned restrictions and caveats apply.
See "help address" for more information on value address arithmetic.
Added E_INVALID_DEREF (10610) error code to indicate the invalid
dereferencing a non-variable.
Added E_INVALID_ADDR_OP (10611) error code to indicate an invalid
arithmetic address operation.
We plan to let this most recent change settle down before performing
the calc v2 to calc v3 fork. Therefore, version 2.16.1.0 will form
the basis for the calc v2 to calc v3 fork.
The following are the changes from calc version 2.15.1.2 to 2.15.1.2:
Removed use of HAVE_MEMMOVE as well have_memmv.c. Removed the
@@ -17,8 +51,6 @@ The following are the changes from calc version 2.15.1.1 to 2.15.1.1:
Put full date range (1989-2025) of calc source into version.h.
Version 2.16.0.0 will form the basis for the calc v2 to calc v3 fork.
The following are the changes from calc version 2.15.0.7 to 2.15.1.0:

View File

@@ -3207,7 +3207,7 @@ prep:
${Q}echo '=-=-=-=-=-= end of ${MAKE} chk =-=-=-=-=-='
${Q}echo
@${Q}if ! ./chk_tree >/dev/null 2>&1; then \
echo almost satifactory except for chk_tree; \
echo almost satisfactory except for chk_tree; \
else \
echo All is OK; \
fi

View File

@@ -1245,11 +1245,11 @@ EXT=
# The calc version in the form of x.y.z.w
#
VERSION= 2.15.1.2
VERSION= 2.16.0.0
# The calc major version in the form of x.y.z
#
VER= 2.15.1
VER= 2.16.0
# Names of shared libraries with versions
#
@@ -1358,7 +1358,7 @@ COMMON_LDFLAGS= ${EXTRA_LDFLAGS}
# For more info see: https://github.com/google/sanitizers/wiki/AddressSanitizer
# See also: https://developer.apple.com/documentation/xcode/diagnosing-memory-thread-and-crash-issues-early
#
# The following Address Sanitizer (ASAN) are common to both REHL9.2 (Linux) and macOS 14.0.
# The following Address Sanitizer (ASAN) are common to both RHEL9.2 (Linux) and macOS 14.0.
#
# By default, the Address Sanitizer is NOT enabled, not compiled into calc.
# To enable the Address Sanitizer, uncomment the appropriate lines in Makefile.local !!!

View File

@@ -7916,7 +7916,7 @@ print '180: define g7500e(a,b) = *a = b'
*/
define test_ptr()
{
local a, b, c, A, B, B1, B2, M, L, p, q, p0, q0;
local a, b, c, A, B, B1, B2, M, L, p, q, r, p0, q0;
print '7500: Beginning test_ptr';
@@ -8042,22 +8042,21 @@ define test_ptr()
p = &M[0], *p = 5;
print '7587: p = &M[0], *p = 5;';
vrfy(M[0] == 5, '7588: M[0] == 5');
*++p = 6;
print '7589: *++p = 6;';
vrfy(M[1] == 6, '7590: M[1] == 6');
q = p++;
print '7591: q = p++;';
q = &M[1], *q = 6;
print '7589: q = &M[1], *q = 6;';
vrfy(M[1] == 6, '7588: M[1] == 6');
vrfy(M[0] == 5, '7588: M[0] == 5');
vrfy(q == &M[1], '7592: q == &M[1]');
vrfy(p == &M[2], '7593: p == &M[2]');
vrfy(p == &M[0], '7593: p == &M[0]');
quomod(17,5,*q,*p);
print '7594: quomod(17,5,*p,*q);';
vrfy(M[1] == 3 && M[2] == 2, '7595: M[1] == 3 && M[2] == 2');
vrfy(M[1] == 3 && M[0] == 2, '7595: M[1] == 3 && M[0] == 2');
swap(*p, *q);
print '7596: swap(*p, *q);';
vrfy(M[1] == 2 && M[2] == 3, '7597: M[1] == 2 && M[2] == 3');
vrfy(M[1] == 2 && M[0] == 3, '7597: M[1] == 2 && M[0] == 3');
A = *M = {7,8};
print '7598: A = *M = {7,8};';
vrfy(M == (mat[4] = {5,2,3,4}), '7599: M == (mat[4] = {5,2,3,4})');
vrfy(M == (mat[4] = {3,2,3,4}), '7599: M == (mat[4] = {3,2,3,4})');
vrfy(A == (mat[4] = {7,8,3,4}), '7600: A == (mat[4] = {7,8,3,4})');
/* Values which point to themselves */
@@ -8069,46 +8068,64 @@ define test_ptr()
print '7603: A = &B, B = &A;';
vrfy(**A == A && ***A == B, '7604: **A == A && ***A == B');
/* Testing functions that return pointers */
/* verify arithmetic value address operation restrictions */
M[3] = 7;
print '7605: M[3] = 7;';
vrfy(*g7500b(&M[1], 2) == 7, '7606: *g7500b(&M[1], 2) == 7');
*g7500b(&M[1], 2) = 8;
print '7607: *g7500b(&M[1], 2) = 8;';
vrfy(M[3] == 8, '7608: M[3] == 8');
M[3] = list(9,10);
print '7609: M[3] = list(9,10);';
vrfy((*g7500b(&M[1], 2))[[1]] == 10,
'7610: (*g7500b(&M[1], 2))[[1]] == 10');
M = mat[10] = {0,1,2,3,4,5,6,7,8,9};
print '7605: M = mat[10] = {0,1,2,3,4,5,6,7,8,9};';
/* NOTE: The next set of tests will trigger 10 errors by design */
ecnt += 10;
print '7606: ecnt += 10';
p = &M[3];
print '7607: p = &M[3]';
++p;
print '7608: ++p';
vrfy(p == error("E_INVALID_ADDR_OP"),
'7609: p == error("E_INVALID_ADDR_OP")');
p = &M[4];
print '7610: p = &M[4]';
p++;
print '7611: p++';
vrfy(p == error("E_INVALID_ADDR_OP"),
'7612: p == error("E_INVALID_ADDR_OP")');
p = &M[5];
print '7613: p = &M[5]';
q = &M[8];
print '7614: q = &M[8]';
vrfy(q+5 == error("E_INVALID_ADDR_OP"),
'7615: q+5 == error("E_INVALID_ADDR_OP")');
vrfy(q-7 == error("E_INVALID_ADDR_OP"),
'7616: q-7 == error("E_INVALID_ADDR_OP")');
vrfy(p+q == error("E_INVALID_ADDR_OP"),
'7617: p+q == error("E_INVALID_ADDR_OP")');
r = p-q;
print '7618: r = p-q;';
/* Testing number and string pointers */
a = 24, b = 4 * 6, c = 4!;
print '7611: a = 24, b = 4 * 6, c= 4!;';
vrfy(isptr(&*a) == 4, '7612: isptr(&*a) == 4');
vrfy(&*a == &24, '7613: &*a == &24');
vrfy(&*a == &*b, '7614: &*a == &*b');
vrfy(&*a != &*c, '7615: &*a != &*c');
print '7619: a = 24, b = 4 * 6, c= 4!;';
vrfy(isptr(&*a) == 4, '7620: isptr(&*a) == 4');
vrfy(&*a == &24, '7621: &*a == &24');
vrfy(&*a == &*b, '7622: &*a == &*b');
vrfy(&*a != &*c, '7623: &*a != &*c');
a = b = "abc", c = strcat("a", "bc");
print '7616: a = b = "abc", c = strcat("a", "bc");';
vrfy(isptr(&*a) == 3, '7617: isptr(&*a) == 3');
vrfy(&*a == &"abc", '7618: &*a == &"abc"');
vrfy(&*a == &*b, '7619: &*a == &*b');
vrfy(&*a != &*c, '7620: &*a != &*c');
print '7624: a = b = "abc", c = strcat("a", "bc");';
vrfy(isptr(&*a) == 3, '7625: isptr(&*a) == 3');
vrfy(&*a == &"abc", '7626: &*a == &"abc"');
vrfy(&*a == &*b, '7627: &*a == &*b');
vrfy(&*a != &*c, '7628: &*a != &*c');
a = c;
print '7621: a = c;';
vrfy(&*a == &*c, '7622: &*a == &*c');
print '7629: a = c;';
vrfy(&*a == &*c, '7630: &*a == &*c');
/* Verifying null-ness of freed numbers */
c = 4!, p = &*c, free(c);
print '7623: c = 4!, p = &*c, free(c)';
vrfy(isnull(*p), '7624: isnull(*p)');
print '7631: c = 4!, p = &*c, free(c)';
vrfy(isnull(*p), '7632: isnull(*p)');
print '7625: Ending test_ptr';
print '7633: Ending test_ptr';
}
print '181: parsed test_ptr()';
@@ -9165,8 +9182,8 @@ read -once "test8900.special";
print '8902: about to run test8900(1,,8903)';
testnum = test8900(1,,8903);
print "8941: ecnt ==", ecnt;
print '8942: ecnt = 214;'
ecnt = 214;
print '8942: ecnt = 224;'
ecnt = 224;
/*

View File

@@ -1,7 +1,7 @@
/*
* codegen - module to generate opcodes from the input tokens
*
* Copyright (C) 1999-2007,2017,2021-2023 David I. Bell and Ernest Bowen
* Copyright (C) 1999-2007,2017,2021-2023,2025 David I. Bell and Ernest Bowen
*
* Primary author: David I. Bell
*
@@ -2425,6 +2425,40 @@ getfilename(char *name, size_t namelen, bool *once)
}
/*
* Useful routine to return the index of one string within another one
* which has the format: "str1\000str2\000str3\000...strn\0\0". Index starts
* at one for the first string. Returns zero if the string being checked
* is not contained in the formatted string.
*
* Be sure to use \000 instead of \0. ANSI-C compilers interpret "foo\0foo..."
* as "foo\017oo...".
*
* given:
* format string formatted into substrings
* test string to be found in formatted string
*/
S_FUNC long
stringindex(char *format, char *test)
{
long index; /* found index */
size_t len; /* length of current piece of string */
size_t testlen; /* length of test string */
testlen = strlen(test);
index = 1;
while (*format) {
len = strlen(format);
if ((len == testlen) && (*format == *test) &&
(strcmp(format, test) == 0))
return index;
format += (len + 1);
index++;
}
return 0;
}
/*
* Read the show command to display useful information
*/

View File

@@ -759,6 +759,8 @@ CONST struct errtbl error_table[] =
{ 10607, "E_LOG_5", "Cannot calculate log of 0" },
{ 10608, "E_LOG2_4", "Cannot calculate log base 2 of 0" },
{ 10609, "E_LOGN_6", "Cannot calculate log base n of 0" },
{ 10610, "E_INVALID_DEREF", "Dereferencing a non-variable" },
{ 10611, "E_INVALID_ADDR_OP", "Invalid arithmetic address operation" },
/* IMPORTANT NOTE: add new entries above here and be sure their errnum numeric value is consecutive! */
/* The next NULL entry must be last */

View File

@@ -113,7 +113,7 @@ DESCRIPTION
(the case of f(0) is exceptional since 27 + 0 simply copies the 27
rather than creating a new number value). Here it is clearly more
efficient to use
efficient to use:
; A = B = C = f(2);
@@ -125,11 +125,74 @@ DESCRIPTION
and number-pointer respectively, and 0 otherwise.
The output when addresses are printed consists of a description (o_ptr,
v_ptr, s_ptr, n_ptr) followed by : and the address printed in
%p format.
v_ptr, s_ptr, n_ptr) followed by : and the address printed in %p format.
Iteration of & is not permitted; &&X causes a "non-variable operand"
scan error.
Iteration of & is not permitted; &(&X) causes a "Addressing
non-addressable type" scan error.
RESTRICTIONS ON VALUE ADDRESS ARITHMETIC
Most arithmetic operations on addresses of values are not permitted.
For example one may not perform arithmetic operations (like +, ++,
-, --, *, /, etc.) on an address of a value with a numeric value.
The reason why most arithmetic operations were removed from calc
because arithmetic on addresses of calc objects could easily cause
calc to crash. Consider this horrific expression that was allowed
in calc prior to version 2.16.0.0:
; *((&.)+1e9) /* INVALID: for calc version >= 2.16.0.0 */
Prior to calc version 2.16.0.0, some arithmetic operations on
addresses of values were permitted. Starting with calc version
2.16.0.0, arithmetic operations between an addresses and an integer
will return an error code:
; ++p; /* INVALID: will be set to E_INVALID_ADDR_OP */
; r = q - 2; /* INVALID: will be set to E_INVALID_ADDR_OP */
Adding two value addresses is NOT permitted:
; mat A[3];
; p = &A[1];
; q = &A[2];
; s = p + q; /* INVALID: will be set to E_INVALID_ADDR_OP */
Subtracting two value addresses is permitted, however there is NO
guarantee that the address of a value will remain consistent across
calc runs. Addresses of values depend on the circumstances of when
the calc values were formed. For example:
; a = 3; pa = &a;
; /* ... stuff happens ... */
; b = 5; pb = &b;
; t = pa - pb; /* permitted: value depends on circumstances */
Subtracting value addresses of components with the same compound
object, such as a matrix, is permitted. For example:
; mat M[10] = {0,1,2,3,4,5,6,7,8,9};
; i = 4; j = 5;
; p = &M[i]; q = &M[j];
; v = p - q; /* permitted: value depends on circumstances */
Comparison between two value addresses is permitted, however the
same caveats apply as to the subtracting of addresses:
; if (p < q) {
;; print "permitted: p is less than q";
;; } else if (p == q) {
;; print "permitted: p is equal to q";
;; } else {
;; print "permitted: p is greater than q";
;; }
PLEASE NOTE:
The above restrictions and caveats apply to addresses of values.
Such restrictions and caveats to NOT apply to the addresses of
octets, NOR to the addresses within strings. If isptr(x) == 2,
then x is value-pointer and the above mentioned restrictions
and caveats apply it.
EXAMPLE
Addresses for particular systems may differ from those displayed here.
@@ -160,7 +223,7 @@ LINK LIBRARY
SEE ALSO
dereference, isptr
## Copyright (C) 1999-2006,2021 Landon Curt Noll
## Copyright (C) 1999-2006,2021,2025 Landon Curt Noll
##
## Calc is open software; you can redistribute it and/or modify it under
## the terms of the version 2.1 of the GNU Lesser General Public License

View File

@@ -959,8 +959,8 @@ o_deref(FUNC *UNUSED(fp))
return;
}
if (stack->v_type != V_ADDR) {
math_error("Dereferencing a non-variable");
not_reached();
*stack = error_value(E_INVALID_DEREF);
return;
}
vp = vp->v_addr;
switch (vp->v_type) {

98
str.c
View File

@@ -1,7 +1,7 @@
/*
* str - string list routines
*
* Copyright (C) 1999-2007,2021-2023 David I. Bell and Ernest Bowen
* Copyright (C) 1999-2007,2021-2023,2025 David I. Bell and Ernest Bowen
*
* Primary author: David I. Bell
*
@@ -42,7 +42,7 @@
#include "banned.h" /* include after system header <> includes */
#define STR_TABLECHUNK (1<<10) /* how often to reallocate string table */
#define STR_TABLECHUNK (1<<16) /* how often to reallocate string literal table */
#define STR_CHUNK (1<<16) /* size of string storage allocation */
#define OCTET_VALUES 256 /* number of different values in a OCTET */
#define STR_UNIQUE (1<<7) /* size of string to allocate separately */
@@ -97,6 +97,10 @@ initstr(STRINGHEAD *hp)
* given:
* hp header of string storage
* str string to be added
*
* returns:
* != NULL ==> pointer to newly added string
* NULL ==> unable to add string
*/
char *
addstr(STRINGHEAD *hp, char *str)
@@ -113,6 +117,10 @@ addstr(STRINGHEAD *hp, char *str)
/* alloc + 1 guard paranoia */
newsize = len + STR_CHUNK + hp->h_used + hp->h_avail + 1;
/* alloc + 1 guard paranoia */
/*
* XXX - doing a realloc can cause problems if the larger list has to be
* relocated due the recalloc() call and stuff point to old location
*/
list = (char *)realloc(hp->h_list, newsize + 1);
if (list == NULL)
return NULL;
@@ -130,35 +138,6 @@ addstr(STRINGHEAD *hp, char *str)
}
/*
* Return a null-terminated string which consists of a single character.
* The table is initialized on the first call.
*/
char *
charstr(int ch)
{
char *cp;
int i;
if (chartable == NULL) {
/* alloc + 1 guard paranoia */
cp = (char *)malloc((OCTET_VALUES + 1)*2);
if (cp == NULL) {
math_error("Cannot allocate character table");
not_reached();
}
for (i = 0; i < OCTET_VALUES; i++) {
*cp++ = (char)i;
*cp++ = '\0';
}
chartable = cp - (OCTET_VALUES*2);
*cp++ = '\0'; /* guard paranoia */
*cp++ = '\0'; /* guard paranoia */
}
return &chartable[(ch & 0xff) * 2];
}
/*
* Find a string with the specified name and return its number in the
* string list. The first string is numbered zero. Minus one is returned
@@ -166,7 +145,11 @@ charstr(int ch)
*
* given:
* hp header of string storage
* str string to be added
* str string to be searched for
*
* returns:
* >= 0 ==> index of string
* -1 ==> unable to find string
*/
int
findstr(STRINGHEAD *hp, char *str)
@@ -200,6 +183,10 @@ findstr(STRINGHEAD *hp, char *str)
* given:
* hp header of string storage
* n string index
*
* returns:
* non-empty string ==> string at index n
* "" ==> no strings or string at index n
*/
char *
namestr(STRINGHEAD *hp, long n)
@@ -219,36 +206,31 @@ namestr(STRINGHEAD *hp, long n)
/*
* Useful routine to return the index of one string within another one
* which has the format: "str1\000str2\000str3\000...strn\0\0". Index starts
* at one for the first string. Returns zero if the string being checked
* is not contained in the formatted string.
*
* Be sure to use \000 instead of \0. ANSI-C compilers interpret "foo\0foo..."
* as "foo\017oo...".
*
* given:
* format string formatted into substrings
* test string to be found in formatted string
* Return a null-terminated string which consists of a single character.
* The table is initialized on the first call.
*/
long
stringindex(char *format, char *test)
S_FUNC char *
charstr(int ch)
{
long index; /* found index */
size_t len; /* length of current piece of string */
size_t testlen; /* length of test string */
char *cp;
int i;
testlen = strlen(test);
index = 1;
while (*format) {
len = strlen(format);
if ((len == testlen) && (*format == *test) &&
(strcmp(format, test) == 0))
return index;
format += (len + 1);
index++;
if (chartable == NULL) {
/* alloc + 1 guard paranoia */
cp = (char *)malloc((OCTET_VALUES + 1)*2);
if (cp == NULL) {
math_error("Cannot allocate character table");
not_reached();
}
for (i = 0; i < OCTET_VALUES; i++) {
*cp++ = (char)i;
*cp++ = '\0';
}
chartable = cp - (OCTET_VALUES*2);
*cp++ = '\0'; /* guard paranoia */
*cp++ = '\0'; /* guard paranoia */
}
return 0;
return &chartable[(ch & 0xff) * 2];
}

4
str.h
View File

@@ -1,7 +1,7 @@
/*
* str - string list routines
*
* Copyright (C) 1999-2007,2014 David I. Bell
* Copyright (C) 1999-2007,2014,2025 David I. Bell
*
* Calc is open software; you can redistribute it and/or modify it under
* the terms of the version 2.1 of the GNU Lesser General Public License
@@ -59,9 +59,7 @@ E_FUNC void initstr(STRINGHEAD *hp);
E_FUNC char *addstr(STRINGHEAD *hp, char *str);
E_FUNC char *namestr(STRINGHEAD *hp, long n);
E_FUNC int findstr(STRINGHEAD *hp, char *str);
E_FUNC char *charstr(int ch);
E_FUNC char *addliteral(char *str);
E_FUNC long stringindex(char *str1, char *str2);
E_FUNC STRING *stralloc(void);
E_FUNC long addstring(char *str, size_t len);
E_FUNC STRING *charstring(int ch);

23
value.c
View File

@@ -434,6 +434,8 @@ addvalue(VALUE *v1, VALUE *v2, VALUE *vres)
*vres = error_value(E_STRADD);
return;
case TWOVAL(V_VPTR, V_NUM):
#if defined(PERMIT_DANGEROUS_ADDRESS_ARITHMETIC)
/* NOTE: Defining PERMIT_DANGEROUS_ADDRESS_ARITHMETIC is NOT supported! */
q = v2->v_num;
if (qisfrac(q)) {
math_error("Adding non-integer to address");
@@ -442,6 +444,12 @@ addvalue(VALUE *v1, VALUE *v2, VALUE *vres)
i = qtoi(q);
vres->v_addr = v1->v_addr + i;
vres->v_type = V_VPTR;
#else /* Disable arithmetic on addresses */
*vres = error_value(E_INVALID_ADDR_OP);
#endif /* Disable arithmetic on addresses */
return;
case TWOVAL(V_VPTR, V_VPTR):
*vres = error_value(E_INVALID_ADDR_OP);
return;
case TWOVAL(V_OPTR, V_NUM):
q = v2->v_num;
@@ -515,6 +523,8 @@ subvalue(VALUE *v1, VALUE *v2, VALUE *vres)
*vres = error_value(E_STRSUB);
return;
case TWOVAL(V_VPTR, V_NUM):
#if defined(PERMIT_DANGEROUS_ADDRESS_ARITHMETIC)
/* NOTE: Defining PERMIT_DANGEROUS_ADDRESS_ARITHMETIC is NOT supported! */
q = v2->v_num;
if (qisfrac(q)) {
math_error("Subtracting non-integer from address");
@@ -523,6 +533,9 @@ subvalue(VALUE *v1, VALUE *v2, VALUE *vres)
i = qtoi(q);
vres->v_addr = v1->v_addr - i;
vres->v_type = V_VPTR;
#else /* Disable arithmetic on addresses */
*vres = error_value(E_INVALID_ADDR_OP);
#endif /* Disable arithmetic on addresses */
return;
case TWOVAL(V_OPTR, V_NUM):
q = v2->v_num;
@@ -1407,7 +1420,12 @@ incvalue(VALUE *vp, VALUE *vres)
vres->v_octet = vp->v_octet + 1;
break;
case V_VPTR:
#if defined(PERMIT_DANGEROUS_ADDRESS_ARITHMETIC)
/* NOTE: Defining PERMIT_DANGEROUS_ADDRESS_ARITHMETIC is NOT supported! */
vres->v_addr = vp->v_addr + 1;
#else /* Disable arithmetic on addresses */
*vres = error_value(E_INVALID_ADDR_OP);
#endif /* Disable arithmetic on addresses */
break;
default:
if (vp->v_type > 0)
@@ -1443,7 +1461,12 @@ decvalue(VALUE *vp, VALUE *vres)
vres->v_octet = vp->v_octet - 1;
break;
case V_VPTR:
#if defined(PERMIT_DANGEROUS_ADDRESS_ARITHMETIC)
/* NOTE: Defining PERMIT_DANGEROUS_ADDRESS_ARITHMETIC is NOT supported! */
vres->v_addr = vp->v_addr - 1;
#else /* Disable arithmetic on addresses */
*vres = error_value(E_INVALID_ADDR_OP);
#endif /* Disable arithmetic on addresses */
break;
default:
if (vp->v_type >= 0)

View File

@@ -62,9 +62,22 @@
* bug fix and improvement updates will cause MINOR_PATCH to increment.
*/
#define MAJOR_VER 2 /* level 1: major library version */
#define MINOR_VER 15 /* level 2: minor library version */
#define MAJOR_PATCH 1 /* level 3: major software version level */
#define MINOR_PATCH 2 /* level 4: minor software version level */
#define MINOR_VER 16 /* level 2: minor library version */
#define MAJOR_PATCH 0 /* level 3: major software version level */
#define MINOR_PATCH 0 /* level 4: minor software version level */
/*
* Defining PERMIT_DANGEROUS_ADDRESS_ARITHMETIC is NOT supported!
*
* If someone were to be a foolish as to permit dangerous address arithmetic, then we
* negate the major version to further "disavow" such a calc compile.
*/
#if defined(PERMIT_DANGEROUS_ADDRESS_ARITHMETIC)
# undef TEMP_MAJOR_VER
# define TEMP_MAJOR_VER MAJOR_VER
# undef MAJOR_VER
# define MAJOR_VER (-TEMP_MAJOR_VER)
# undef TEMP_MAJOR_VER
#endif
#endif /* !INCLUDE_VERSION_H*/