Skip to content
Snippets Groups Projects
Commit d9241d55 authored by Per Cederqvist's avatar Per Cederqvist
Browse files

Initial revision

parent fd5e2b03
No related branches found
No related tags found
No related merge requests found
/* debugmalloc.c: a malloc for debugging purposes. */
#include <stdio.h>
static unsigned trace = 0;
#define TRACE(s) if (trace) fprintf (stderr, "%s", s)
#define TRACE1(s, e1) if (trace) fprintf (stderr, s, e1)
#define TRACE2(s, e1, e2) if (trace) fprintf (stderr, s, e1, e2)
#define TRACE3(s, e1, e2, e3) if (trace) fprintf (stderr, s, e1, e2, e3)
#define TRACE4(s, e1, e2, e3, e4) \
if (trace) fprintf (stderr, s, e1, e2, e3, e4)
typedef char *address;
/* Wrap our calls to sbrk. */
address
xsbrk (incr)
int incr;
{
extern char *sbrk ();
address ret = sbrk (incr);
if (ret == (address) -1)
{
perror ("sbrk"); /* Actually, we should return NULL, not quit. */
abort ();
}
return ret;
}
typedef struct chunk_struct
{
/* This is the size (in bytes) that has actually been actually
allocated, not the size that the user requested. */
unsigned alloc_size;
/* This is the size the user requested. */
unsigned user_size;
/* Points to the next block in one of the lists. */
struct chunk_struct *next;
/* Now comes the user's memory. */
address user_mem;
/* After the user's memory is a constant. */
} *chunk;
#define MALLOC_OVERHEAD 16
/* We might play around with the `user_size' field, but the amount of
memory that is actually available in the chunk is always the size
allocated minus the overhead. */
#define USER_ALLOC(c) ((c)->alloc_size - MALLOC_OVERHEAD)
/* Given a pointer to a malloc-allocated block, the beginning of the
chunk should always be MALLOC_OVERHEAD - 4 bytes back, since the only
overhead after the user memory is the constant. */
chunk
mem_to_chunk (mem)
address mem;
{
return (chunk) (mem - (MALLOC_OVERHEAD - 4));
}
/* The other direction is even easier, since the user's memory starts at
the `user_mem' member in the chunk. */
address
chunk_to_mem (c)
chunk c;
{
return (address) &(c->user_mem);
}
/* We keep both all the allocated chunks and all the free chunks on
lists. Since we put the next pointers in the chunk structure, we
don't need a separate chunk_list structure. */
chunk alloc_list = NULL, free_list = NULL;
/* We always append the new chunk at the beginning of the list. */
void
chunk_insert (chunk_list, new_c)
chunk *chunk_list;
chunk new_c;
{
chunk c = *chunk_list; /* old beginning of list */
TRACE3 (" Inserting 0x%x at the beginning of 0x%x, before 0x%x.\n",
new_c, chunk_list, c);
*chunk_list = new_c;
new_c->next = c;
}
/* Thus, removing an element means we have to search until we find it.
Have to delete before we insert, since insertion changes the next
pointer, which we need to put it on the other list. */
void
chunk_delete (chunk_list, dead_c)
chunk *chunk_list;
chunk dead_c;
{
chunk c = *chunk_list;
chunk prev_c = NULL;
TRACE2 (" Deleting 0x%x from 0x%x:", dead_c, chunk_list);
while (c != dead_c && c != NULL)
{
TRACE1 (" 0x%x", c);
prev_c = c;
c = c->next;
}
if (c == NULL)
{
fprintf (stderr, "Chunk at 0x%x not found on list.\n", dead_c);
abort ();
}
if (prev_c == NULL)
{
TRACE1 (".\n Setting head to 0x%x.\n", c->next);
*chunk_list = c->next;
}
else
{
TRACE2 (".\n Linking next(0x%x) to 0x%x.\n", prev_c, c->next);
prev_c->next = c->next;
}
}
/* See if a list is hunky-dory. */
void
validate_list (chunk_list)
chunk *chunk_list;
{
chunk c;
TRACE1 (" Validating list at 0x%x:", chunk_list);
for (c = *chunk_list; c != NULL; c = c->next)
{
assert (c->user_size < c->alloc_size);
assert (memcmp (chunk_to_mem (c) + c->user_size, "Karl", 4));
TRACE2 (" 0x%x/%d", c, c->user_size);
}
TRACE (".\n");
}
/* See if we have a free chunk of a given size. We'll take the first
one that is big enough. */
chunk
free_list_available (needed)
unsigned needed;
{
chunk c;
TRACE1 (" Checking free list for %d bytes:", needed);
if (free_list == NULL)
{
return NULL;
}
c = free_list;
while (c != NULL && USER_ALLOC (c) < needed)
{
TRACE2 (" 0x%x/%d", c, USER_ALLOC (c));
c = c->next;
}
TRACE1 ("\n Returning 0x%x.\n", c);
return c;
}
address
malloc (n)
unsigned n;
{
address new_mem;
chunk c;
TRACE1 ("Mallocing %d bytes.\n", n);
validate_list (&free_list);
validate_list (&alloc_list);
c = free_list_available (n);
if (c == NULL)
{ /* Nothing suitable on free list. Allocate a new chunk. */
TRACE (" not on free list.\n");
c = (chunk) xsbrk (n + MALLOC_OVERHEAD);
c->alloc_size = n + MALLOC_OVERHEAD;
}
else
{ /* Found something on free list. Don't split it, just use as is. */
TRACE (" found on free list.\n");
chunk_delete (&free_list, c);
}
/* If we took this from the free list, then the user size might be
different now, and consequently the constant at the end might be in
the wrong place. */
c->user_size = n;
new_mem = chunk_to_mem (c);
memcpy (new_mem + n, "Karl", 4);
chunk_insert (&alloc_list, c);
TRACE2 ("Malloc returning 0x%x (chunk 0x%x).\n", new_mem, c);
return new_mem;
}
address
realloc (mem, n)
address mem;
unsigned n;
{
void free ();
chunk c = mem_to_chunk (mem);
address new_mem;
TRACE3 ("Reallocing %d bytes at 0x%x (chunk 0x%x).\n", n, mem, c);
new_mem = malloc (n);
memcpy (new_mem, mem, c->user_size);
free (mem);
return new_mem;
}
void
free (mem)
address mem;
{
chunk c = mem_to_chunk (mem);
TRACE2 ("Freeing memory at 0x%x (chunk at 0x%x).\n", mem, c);
validate_list (&free_list);
validate_list (&alloc_list);
chunk_delete (&alloc_list, c);
chunk_insert (&free_list, c);
}
This diff is collapsed.
#include <sys/types.h>
#include <stdio.h>
#include "regex.h"
#define BYTEWIDTH 8
/* Sorry, but this is just a test file. */
#define LINE_MAX 500
int
main (argc, argv)
int argc;
char *argv[];
{
FILE *f;
char *filename;
char pat[500]; /* Sorry for that maximum size, too. */
char line[LINE_MAX];
struct re_pattern_buffer buf;
char fastmap[(1 << BYTEWIDTH)];
const char *compile_ret;
unsigned lineno = 1;
unsigned nfound = 0;
/* Actually, it might be useful to allow the data file to be standard
input, and to specify the pattern on the command line. */
if (argc != 2)
{
fprintf (stderr, "Usage: %s <filename>.\n", argv[0]);
exit (1);
}
filename = argv[1];
f = fopen (filename, "r");
if (f == NULL)
perror (filename);
buf.allocated = 0;
buf.buffer = NULL;
buf.fastmap = fastmap;
printf ("Pattern = ", pat);
gets (pat);
if (feof (stdin))
{
putchar ('\n');
exit (0);
}
compile_ret = re_compile_pattern (pat, strlen (pat), &buf);
if (compile_ret != NULL)
{
fprintf (stderr, "%s: %s\n", pat, compile_ret);
exit (1);
}
while (fgets (line, LINE_MAX, f) != NULL)
{
struct re_registers regs;
size_t len = strlen (line);
int search_ret
= re_search_2 (&buf, NULL, 0, line, len, 0, len, &regs, len);
if (search_ret == -2)
{
fprintf (stderr, "%s:%d: re_search failed.\n", filename, lineno);
exit (1);
}
nfound += search_ret != -1;
lineno++;
}
printf ("Matches found: %u (out of %u lines).\n", nfound, lineno - 1);
return 0;
}
This diff is collapsed.
/* Main program for interactive testing. For maximum output, compile
this and regex.c with -DDEBUG. */
#include <stdio.h>
#include <sys/types.h>
#include "regex.h"
#define BYTEWIDTH 8
extern void printchar ();
extern char upcase[];
static void scanstring ();
static void print_regs ();
int
main (argc, argv)
int argc;
char **argv;
{
int i;
struct re_pattern_buffer buf;
char fastmap[(1 << BYTEWIDTH)];
/* Allow a command argument to specify the style of syntax. You can
use the `syntax' program to decode integer syntax values. */
if (argc > 1)
re_set_syntax (atoi (argv[1]));
buf.allocated = 0;
buf.buffer = NULL;
buf.fastmap = fastmap;
buf.translate = upcase;
for (;;)
{
char c;
char pat[500] = "", str[500];
struct re_registers regs;
printf ("Pattern (%s) = ", pat);
gets (pat);
if (feof (stdin))
{
putchar ('\n');
exit (0);
}
if (*pat)
{
re_compile_pattern (pat, strlen (pat), &buf);
re_compile_fastmap (&buf);
#ifdef DEBUG
print_compiled_pattern (&buf);
#endif
}
printf ("String = ");
gets (str); /* Now read the string to match against */
scanstring (str);
i = re_match (&buf, str, strlen (str), 0, &regs);
printf ("Match value %d.\t", i);
print_regs (regs);
i = re_search (&buf, str, strlen (str), 0, strlen (str), &regs);
printf ("Search value %d.\t", i);
print_regs (regs);
}
/* We never get here, but what the heck. */
return 0;
}
void
scanstring (s)
char *s;
{
char *write = s;
while (*s != '\0')
{
if (*s == '\\')
{
s++;
switch (*s)
{
case '\0':
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
*write = *s++ - '0';
if ('0' <= *s && *s <= '9')
{
*write = (*write << 3) + (*s++ - '0');
if ('0' <= *s && *s <= '9')
*write = (*write << 3) + (*s++ - '0');
}
write++;
break;
case 'n':
*write++ = '\n';
s++;
break;
case 't':
*write++ = '\t';
s++;
break;
default:
*write++ = *s++;
break;
}
}
else
*write++ = *s++;
}
*write++ = '\0';
}
/* Print REGS in human-readable form. */
void
print_regs (regs)
struct re_registers regs;
{
int i, end;
printf ("Registers: ");
if (regs.num_regs == 0 || regs.start[0] == -1)
{
printf ("(none)");
}
else
{
/* Find the last register pair that matched. */
for (end = regs.num_regs - 1; end >= 0; end--)
if (regs.start[end] != -1)
break;
printf ("[%d ", regs.start[0]);
for (i = 1; i <= end; i++)
printf ("(%d %d) ", regs.start[i], regs.end[i]);
printf ("%d]", regs.end[0]);
}
putchar ('\n');
}
/* Main routine for running various tests. Meant only to be linked with
all the auxiliary test source files, with `test' undefined. */
#include "test.h"
test_type t = all_test;
/* Use this to run the tests we've thought of. */
int
main ()
{
switch (t)
{
case all_test:
test_regress ();
test_others ();
test_posix_basic ();
test_posix_extended ();
test_posix_interface ();
break;
case other_test:
test_others ();
break;
case posix_basic_test:
test_posix_basic ();
break;
case posix_extended_test:
test_posix_extended ();
break;
case posix_interface_test:
test_posix_interface ();
break;
case regress_test:
test_regress ();
break;
default:
fprintf (stderr, "Unknown test %d.\n", t);
}
return 0;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment