Skip to content

Commit

Permalink
Enhanced smoke test to report memory leaks.
Browse files Browse the repository at this point in the history
Fixed memory leaks found when memory checks were included with test builds.
Refactored EI command processing, and changed IE1 error to EIE.
  • Loading branch information
Franklin Pierce Johnston committed Feb 15, 2022
1 parent 93f7f67 commit 4360a4b
Show file tree
Hide file tree
Showing 28 changed files with 220 additions and 101 deletions.
3 changes: 2 additions & 1 deletion doc/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ code.
| <nobr>?DPY</nobr> | <nobr>Display mode error</nobr> | Display mode support is either missing or disabled. |
| <nobr>?DTB</nobr> | <nobr>Delete too big</nobr> | A D command attempted to delete text outside the current page. |
| <nobr>?DUP</nobr> | <nobr>Duplicate tag '!foo!'</nobr> | An O command found a duplicate tag within the command string. |
| <nobr>?EIE</nobr> | <nobr>EI command error</nobr> | An invalid EI command has been executed. The user had too many nested EI commands, or tried to execute an old-style EI command while a new-style EI command was being executed (or vice versa). |
| <nobr>?ERR</nobr> | <nobr>(error message)</nobr> | A system call failed. The error message text explains the error. |
| <nobr>?EXT</nobr> | <nobr>Extended feature not enabled</nobr> | A command attempted to use an extended feature which is not currently enabled. |
| <nobr>?FIL</nobr> | <nobr>Invalid file 'foo'</nobr> | An attempt was made to open a directory, FIFO, socket, or similar file specification instead of a regular file. |
| <nobr>?FNF</nobr> | <nobr>File not found 'foo'</nobr> | The requested input file could not be located. If this occurred within a macro, the colon-modified command may be necessary. |
| <nobr>?IAA</nobr> | <nobr>Invalid A argument</nobr> | The argument preceding a :A command is negative or zero. |
| <nobr>?ICE</nobr> | <nobr>Invalid ^E command in search argument</nobr> | A search argument contains a ^E command that is either not defined or incomplete. |
| <nobr>?IE1</nobr> | <nobr>Invalid E1 command</nobr> | An invalid E1 command has been executed. The E1&32 flag bit may not be set while executing an old-style EI command, and may not be reset while executing a new-style EI command. |
| <nobr>?IEC</nobr> | <nobr>Invalid character '*x*' after E</nobr> | An invalid E command has been executed. |
| <nobr>?IFC</nobr> | <nobr>Invalid character '*x*' after F</nobr> | An invalid F command has been executed. |
| <nobr>?IFE</nobr> | <nobr>Ill-formed numeric expression</nobr> | The numeric expression preceding a command doesn't make sense. For example, 5+ isn't a complete expression. |
Expand Down Expand Up @@ -89,6 +89,7 @@ code.
| <nobr>?NFO</nobr> | <nobr>No file for output</nobr> | Before issuing an output command, such as N or or P, it is necessary to open an output file with a command such as EW or EB. |
| <nobr>?NON</nobr> | <nobr>No n argument after m argument</nobr> | An m argument was not followed by an n argument. |
| <nobr>?NOT</nobr> | <nobr>O command has no tag</nobr> | No tag was found for an O command. |
| <nobr>?NPA</nobr> | <nobr>Negative or 0 argument to P</nobr> | A P command was preceded by a negative or 0 argument. |
| <nobr>?NYA</nobr> | <nobr>Numeric argument with Y</nobr> | The Y command must not be preceded by either a numeric argument or a command that returns a numeric value. |
| <nobr>?NYI</nobr> | <nobr>Not yet implemented</nobr> | A command was issued that is not yet implemented in this version of TECO. |
| <nobr>?OFO</nobr> | <nobr>Output file already open</nobr> | A command has been executed which tried to create an output file, but an output file currently is open. It is typically appropriate to use the EC or EK command as the situation calls for to close the output file. |
Expand Down
16 changes: 8 additions & 8 deletions etc/errors.xml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,14 @@
<detail>An O command found a duplicate tag within the</detail>
<detail>command string.</detail>
</error>
<error>
<code>EIE</code>
<message>EI command error</message>
<detail>An invalid EI command has been executed. The user</detail>
<detail>had too many nested EI commands, or tried to execute</detail>
<detail>an old-style EI command while a new-style EI command</detail>
<detail>was being executed (or vice versa).</detail>
</error>
<error>
<code>ERR</code>
<message>%s</message>
Expand Down Expand Up @@ -120,14 +128,6 @@
<detail>A search argument contains a ^E command that</detail>
<detail>is either not defined or incomplete.</detail>
</error>
<error>
<code>IE1</code>
<message>Invalid E1 command</message>
<detail>An invalid E1 command has been executed. The</detail>
<detail>E1&amp;32 flag bit may not be set while executing</detail>
<detail>an old-style EI command, and may not be reset</detail>
<detail>while executing a new-style EI command.</detail>
</error>
<error>
<code>IEC</code>
<message>Invalid character &apos;%c&apos; after E</message>
Expand Down
6 changes: 4 additions & 2 deletions etc/templates/exec.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,6 @@ extern bool append(bool n_set, int_t n_arg, bool colon_set);

extern bool append_line(void);

extern int check_EI(void);

extern bool check_semi(void);

extern void close_files(void);
Expand Down Expand Up @@ -277,6 +275,10 @@ extern void reset_indirect(void);

extern void reset_loop(void);

extern void reset_search(void);

extern void set_EI(bool ei_new);

extern bool skip_cmd(struct cmd *cmd, const char *skip);

extern void scan_texts(struct cmd *cmd, int ntexts, int delim);
Expand Down
2 changes: 1 addition & 1 deletion include/errcodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ enum errcodes
E_DPY, ///< Display mode error
E_DTB, ///< Delete too big
E_DUP, ///< Duplicate tag '!foo!'
E_EIE, ///< EI command error
E_ERR, ///< (error message)
E_EXT, ///< Extended feature not enabled
E_FIL, ///< Invalid file 'foo'
E_FNF, ///< File not found 'foo'
E_IAA, ///< Invalid A argument
E_ICE, ///< Invalid ^E command in search argument
E_IE1, ///< Invalid E1 command
E_IEC, ///< Invalid character 'x' after E
E_IFC, ///< Invalid character 'x' after F
E_IFE, ///< Ill-formed numeric expression
Expand Down
10 changes: 5 additions & 5 deletions include/errtables.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,13 @@ static struct errlist errlist[] =
[E_DPY] = { "DPY", "Display mode error" },
[E_DTB] = { "DTB", "Delete too big" },
[E_DUP] = { "DUP", "Duplicate tag '!%s!'" },
[E_EIE] = { "EIE", "EI command error" },
[E_ERR] = { "ERR", "%s" },
[E_EXT] = { "EXT", "Extended feature not enabled" },
[E_FIL] = { "FIL", "Invalid file '%s'" },
[E_FNF] = { "FNF", "File not found '%s'" },
[E_IAA] = { "IAA", "Invalid A argument" },
[E_ICE] = { "ICE", "Invalid ^E command in search argument" },
[E_IE1] = { "IE1", "Invalid E1 command" },
[E_IEC] = { "IEC", "Invalid character '%s' after E" },
[E_IFC] = { "IFC", "Invalid character '%s' after F" },
[E_IFE] = { "IFE", "Ill-formed numeric expression" },
Expand Down Expand Up @@ -153,6 +153,10 @@ static const char *errhelp[] =
"the current page.",
[E_DUP] = "An O command found a duplicate tag within the "
"command string.",
[E_EIE] = "An invalid EI command has been executed. The user "
"had too many nested EI commands, or tried to execute "
"an old-style EI command while a new-style EI command "
"was being executed (or vice versa).",
[E_ERR] = "A system call failed. The error message text "
"explains the error.",
[E_EXT] = "A command attempted to use an extended feature "
Expand All @@ -167,10 +171,6 @@ static const char *errhelp[] =
"negative or zero.",
[E_ICE] = "A search argument contains a ^E command that "
"is either not defined or incomplete.",
[E_IE1] = "An invalid E1 command has been executed. The "
"E1&32 flag bit may not be set while executing "
"an old-style EI command, and may not be reset "
"while executing a new-style EI command.",
[E_IEC] = "An invalid E command has been executed.",
[E_IFC] = "An invalid F command has been executed.",
[E_IFE] = "The numeric expression preceding a command "
Expand Down
6 changes: 4 additions & 2 deletions include/exec.h
Original file line number Diff line number Diff line change
Expand Up @@ -609,8 +609,6 @@ extern bool append(bool n_set, int_t n_arg, bool colon_set);

extern bool append_line(void);

extern int check_EI(void);

extern bool check_semi(void);

extern void close_files(void);
Expand Down Expand Up @@ -639,6 +637,10 @@ extern void reset_indirect(void);

extern void reset_loop(void);

extern void reset_search(void);

extern void set_EI(bool ei_new);

extern bool skip_cmd(struct cmd *cmd, const char *skip);

extern void scan_texts(struct cmd *cmd, int ntexts, int delim);
Expand Down
120 changes: 81 additions & 39 deletions src/ei_cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,40 +36,53 @@
#include "file.h"


/// @var ei_old
/// @brief Buffer for old-style EI commands

static tbuffer ei_old;
#define EI_MAX 128 ///< Max. depth for EI commands

/// @var ei_depth
/// @brief Nesting depth for new-style EI commands.
/// @brief Nesting depth for new-style EI commands. Note that this can be no
/// greater than 1 if we're processing an old-style EI command.

static uint ei_depth = 0;

/// @var ei_stack
/// @brief EI command buffer array.

static tbuffer ei_stack[EI_MAX];

/// @var ei_old
/// @brief Flag to distinguish between old-style and new-style EI commands.
/// The ei_stack[] array is used for both, but if we're processing
/// an old-style EI command, then ei_old is set to true, and the
/// array can have at most one element (because old-style EI commands
/// cannot be nested).

static bool ei_old = false;


///
/// @brief Check to see if any EI commands are active.
/// @brief Set or clear old-style EI flag. Basically, we verify that we're
/// not already processing a old-style EI command when the user wants
/// to switch to old-style, or vice versa. This is because new-style
/// commands can be nested, whereas old-style commands are more like
/// chaining one indirect command file to another: once an EI command
/// is seen, execution of that file terminates and we open up a new
/// file and start execution of the commands found therein.
///
/// @returns +1 -> New-style EI command is active.
/// -1 -> Old-style EI command is active.
/// 0 -> No EI command is active.
/// @returns Nothing.
///
////////////////////////////////////////////////////////////////////////////////

int check_EI(void)
void set_EI(bool ei_new)
{
if (ei_depth != 0)
{
return 1;
}
else if (cbuf == &ei_old)
{
return -1;
}
else
if (ei_depth > 1) // Have we started nesting?
{
return 0;
if (ei_old && ei_new) // Yes. Changing horses in mid-stream?
{
throw(E_EIE); // EI command error
}
}

ei_old = !ei_new; // Change new to old and old to new
}


Expand Down Expand Up @@ -100,7 +113,7 @@ void exec_EI(struct cmd *cmd)

close_input(stream); // Close any open file

if (f.e0.init || f.e1.new_ei) // New-style EI
if (f.e1.new_ei) // New-style EI
{
if (len == 0)
{
Expand All @@ -119,26 +132,32 @@ void exec_EI(struct cmd *cmd)

if ((name = init_filename(name, len, cmd->colon)) != NULL)
{
tbuffer ei_new;
if (ei_depth == EI_MAX)
{
throw(E_EIE); // EI command error (stack overflow)
}

if (open_command(name, stream, cmd->colon, &ei_new))
if (open_command(name, stream, cmd->colon, &ei_stack[ei_depth]))
{
if (cmd->colon)
{
push_x(SUCCESS, X_OPERAND);
}

if (ei_new.size != 0)
if (ei_stack[ei_depth].size != 0)
{
++ei_depth;
// Incrementing ei_depth is necessary here to deal with any
// nesting that will occur if the macro we are executing
// contains an EI command that will cause another macro to
// be loaded and executed.

exec_macro(&ei_new, cmd);

free_mem(&ei_new.data);
exec_macro(&ei_stack[ei_depth++], cmd);

--ei_depth;
}

free_mem(&ei_stack[ei_depth].data);

return;
}
}
Expand All @@ -152,7 +171,18 @@ void exec_EI(struct cmd *cmd)

if ((name = init_filename(name, len, cmd->colon)) != NULL)
{
if (open_command(name, stream, cmd->colon, &ei_old))
if (ei_depth == 0) // Trying to nest EI command?
{
++ei_depth;
}
else
{
free_mem(&ei_stack[0].data);
}

ei_old = true;

if (open_command(name, stream, cmd->colon, &ei_stack[0]))
{
if (cmd->colon)
{
Expand Down Expand Up @@ -180,15 +210,24 @@ void exec_EI(struct cmd *cmd)

bool read_EI(void)
{
if (ei_old.data == NULL || ei_old.pos == ei_old.len)
if (ei_old)
{
return false;
if (ei_stack[0].data == NULL || ei_stack[0].pos == ei_stack[0].len)
{
ei_old = false;

return false;
}
else
{
cbuf = &ei_stack[0]; // Use our command string

return true;
}
}
else
{
cbuf = &ei_old; // Use our command string

return true;
return false;
}
}

Expand All @@ -202,13 +241,16 @@ bool read_EI(void)

void reset_indirect(void)
{
ei_old.size = 0;
ei_old.len = 0;
ei_old.pos = 0;
ei_old = false;

free_mem(&ei_old.data);
while (ei_depth != 0)
{
free_mem(&ei_stack[--ei_depth].data);

ei_depth = 0;
ei_stack[ei_depth].size = 0;
ei_stack[ei_depth].len = 0;
ei_stack[ei_depth].pos = 0;
}
}


Expand Down
29 changes: 1 addition & 28 deletions src/flag_cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,36 +156,9 @@ void exec_E1(struct cmd *cmd)

check_mn_flag(cmd, &f.e1.flag);

if (f.e0.init) // Initializing?
{
return; // Yes, don't worry about E1 changes
}

if (f.e1.new_ei ^ saved.new_ei) // Did EI bit change?
{
switch (check_EI())
{
case 1: // Processing new-style EI
if (f.e1.new_ei) // Did we just set flag?
{
return; // Yes, that's okay
}

break; // Not okay

case -1: // Processing old-style EI
if (!f.e1.new_ei) // Did we just clear flag?
{
return; // Yes, that's okay
}

break; // Not okay

default: // No change
return;
}

throw(E_IE1); // Invalid E1 command
set_EI((bool)f.e1.new_ei); // Make sure new setting is okay
}
}

Expand Down
Loading

0 comments on commit 4360a4b

Please sign in to comment.