The scale factor has to be considered in the multiplication because
many algorithms will depend of the precision configured in the scale,
that, until now, was considered only for division. BSD and Plan9
dc differ about how to handle this, and plan9 always use only the
scale factor, while BSD uses the maximun of the scale factor or the
bigger scale of the operands. The second seems more sensible and
produces output that user would expect, for example 0k 0.5 0.5*p would
produce 0.2 with the BSD criteria, but it would generate 0 with the
plan9 criteria.
Different libcsuse different criteria about buffering stderr
and it created problems in tests merging stdout and stderr.
To avoid the problem just redirect stderr to a different file
and merge them later using cat in a subshell.
As dc supports extended identifiers and we already had
the option -s in bc that modifies the standard behaviour
we can extend bc in the -s mode to support longer names.
The lower case restriction is maintained just for
simplicity but it is possible to extend bc to support
full utf8 identifers.
Divscale uses the function muln() that is not prepared to handle
negative numbers. The solution is to convert them to positive
numbers and handle the sign in divnum() and modnum(). We don't
need a copy of the parameters because they are used directly
with values from the stack, or from the expnum() function that
discards the input parameters when it calls divnum().
When a value was assigned to a register using the 's'
command we were assigning the full value from execution
stack, overwriting the next pointer of the register
stack with the next pointer of the execution stack.
The commit c00921a fixed a segfault happening when no parameters
or auto variables happened, moving the initialization of the
unwind string to the moment when the macro is initialized, but
a dummy initialization remained for every declaration making that
variables were not poped (and of course a memory leak).
Without these changes, dc can undergo segfaults in a variety of
situations (list of cases that segfault, one for changed line):
1. echo 'e(5)' | bc -lc | dc
2. echo 'la sa sa sa' | dc
3. echo '5p' > a.dc; dc a.dc
Classical dc implementations only apply tail recursion optimization
but we were applying tail call recursion, removing one frame even
when no recursion was involved. This creates problems with bc that
does not track this optimization and it generates values for the Q
command without caring about this optimization.
Truncate() is a function since POSIX 2008, and even it should
be exposed only if unistd.h is included, OpenBSD exposes it
even when we are using only c90 headers. Renamed to numtrunc()
to avoid the name collision.
The support for lower case hexa digits was introduced to be compatible
with the plan9 dc as described in the man page, but this was not
actually implemented because it creates many problems with almost
everything (and specially with bc) and the man page was not
updated.
Using an EXEC variable for every test make easy to run tools to
debug issues like for example using EXEC=valgrind ./0025-ed.sh.
Some tests for ed had a wrong path to the ed binary and they
were not testing the actual ed but the system one.
Scc fixed a race condition hapenning while forking and execing the command
and receiving a signal that could keep make waiting forever. Signals
are correctly masked now to avoid this problems.
Some shells keep a variable LINES with the number of lines of the terminal
updated in every SIGWINCH. Using that variable makes easier to get a
full listing.
These are extensions to the POSIX standard but very useful
in situations like writing a commit message where the exit
status can discard the full edit session.
Setting modflag unconditionally in the Q command could
produce that after an error happening dealing with the Q
command then unsaved files were silently ignored.
Setting modflag unconditionally in the E command could
produce that after an error happening dealing with the E
command then unsaved files were silently ignored.
Testing can be done using directly the path to the bc.library
file, and get rid of the ugly function that we had to build
dynamically the path to the library.
Statements already deal with the cleaning of the stack, but the
init and increment part of for loops are expressions without the
cleaning, and for that reason we have to care about the stack.
These functions only differentiate in a single letter, so it
was a good opportunity to merge them. Also, it was a good idea
to add the values in reverse order to make the output more
similar to other bc implementations.