Related
char * lpbitmap = NULL;
BITMAPFILEHEADER bmfHeader;
BITMAPINFOHEADER bi;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bmpScreen.bmWidth;
bi.biHeight = bmpScreen.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = 24;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight;
hDIB = GlobalAlloc(GHND, dwBmpSize);
lpbitmap = (char*)GlobalLock(hDIB);
I am using the windows GDI header file to create a bitmap, the goal is to convert the lpbitmap buffer to a base64 string so that it can be represented as such data:image/bmp;base64,Qk06
as far as I understand the bitmap is 24bit where every 3 chars represent RGB values example
How to convert each RGB value into a base64 value
Update
I changed the bitcount to 24
Below is my conversion of LihO's C++ answer to C: Base64 decode snippet in C++
As I mentioned in the comments, I thought it would be simple. But,there wasn't a simple cookbook to give to someone not familiar with C++. So, to do the conversion properly, I did it myself.
And, there were a few issues:
The answer did a lot of unnecessary buffer copying.
Using std::string and std::vector, although pretty fast, are somewhat slower than using raw byte buffers.
Using base64_chars.find is O(n) but if an inverse table is created/used, it can be O(1).
The answer did not support line breaks (e.g. \n) as most base64 programs do.
Anyway, below are the source files I came up with. They can be compiled with:
cc -I. -o b64test b64test.c base64.c dbgcom.c
Note that the mmap mode (i.e. -m) is untested.
FILE: base64.h
// base64.h -- base64 definitions
#ifndef _base64_h_
#define _base64_h_
#include <dbgcom.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
typedef struct {
u32 buf_opt; // buffer options
const char *buf_tag; // buffer name
byte *buf_base; // buffer pointer
size_t buf_len; // buffer length
int buf_fdmap; // mmap file descriptor
} b64buf_t;
#define B64BUFDEF(_sym) \
b64buf_t _sym = { .buf_tag = #_sym }
typedef struct {
//u32 ctl_opt; // options
const char *ctl_tag; // control name
b64buf_t ctl_inb; // input buffer
b64buf_t ctl_out; // output buffer
int ctl_wrapnow; // last output char was newline
int ctl_wraplen; // output wrap length
int ctl_wrapmax; // output wrap max
int ctl_fdchk; // file cross check
} b64ctl_t;
#define B64CTLDEF(_sym) \
b64ctl_t _sym = { .ctl_tag = #_sym }
#define B64MMAP (1u << 0) // 1=use mmap on output
#define B64TRIM (1u << 1) // 1=trim output file
// b64encode -- encode raw data to base64
// RETURNS actual output length
size_t
b64encode(b64ctl_t *ctl);
// b64decode -- decode base64 into raw binary
// RETURNS: actual output length
size_t
b64decode(b64ctl_t *ctl);
// b64bufdup -- safe buffer duplicate
void
b64bufdup(b64buf_t *dst,const b64buf_t *src);
// b64bufput -- output buffer to file
void
b64bufput(const b64buf_t *bufp,const char *ofile);
// b64bufget -- input file to buffer
void
b64bufget(b64buf_t *bufp,const char *ifile);
// b64setup -- passive setup
void
b64setup(b64ctl_t *ctl,u32 opt,const char *tag);
// b64init_encode -- initialize for encode
// RETURNS: 0=okay, -1=error
int
b64init_encode(b64ctl_t *ctl,const b64buf_t *inb,int wrapmax);
// b64init_decode -- initialize for decode
// RETURNS: 0=okay, -1=error
int
b64init_decode(b64ctl_t *ctl,b64buf_t *inb);
// b64destroy -- destroy/deinit output buffer
void
b64destroy(b64ctl_t *ctl);
// b64bufrls -- destroy/deinit output buffer
void
b64bufrls(b64buf_t *buf,const char *who);
#endif
FILE: base64.c
// base64.c -- base 64 encoder/decoder
#include <base64.h>
#include <ctype.h>
#include <sys/stat.h>
#include <sys/mman.h>
static const char *base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
#ifndef B64DECODE_FAST
#define B64DECODE_FAST 1
#endif
#if B64DECODE_FAST
static byte decode_fast[256];
#endif
#define FMT "%2.2X/%c"
#define PRT(_c) _c,PRTABLE(_c)
#define PUT4(_idx,_val) \
arr4[_idx] = _val
#define PUTE(_idx,_val) \
arr4[_idx] = base64_chars[_val]
#define OUTLEN(_buf,_ptr) \
(_ptr - (byte *) (_buf)->buf_base)
// encode_xcheck -- cross-check encoding
#if B64ENCODE_XCHECK
#define encode_xcheck(_ctl,_arr4,_a4siz,_arr3,_a3siz,_pad) \
_encode_xcheck(_ctl,_arr4,_a4siz,_arr3,_a3siz,_pad)
static void
_encode_xcheck(b64ctl_t *ctl,
const byte *arr4,int a4siz,
const byte *arr3,int a3siz,int pad)
{
int xlen;
int oidx;
byte buf[a4siz];
dbgprt(ZPXHOWCHR,"encode_xcheck: ENTER a4siz=%d a3siz=%d pad=%d\n",
a4siz,a3siz,pad);
xlen = read(ctl->ctl_fdchk,buf,a4siz);
if (xlen != a4siz)
sysfault("encode_xcheck: read error -- a4siz=%d xlen=%d\n",
a4siz,xlen);
// check for error/mismatch
int errany = 0;
for (oidx = 0; oidx < a4siz; ++oidx) {
errany = (arr4[oidx] != buf[oidx]);
if (errany)
break;
}
do {
// only print if verbose mode or we have an error
if (! XVERBOSE) {
if (! errany)
break;
}
int totsiz = a4siz;
if (a3siz > totsiz)
totsiz = a3siz;
for (oidx = 0; oidx < totsiz; ++oidx) {
byte bp = 0;
byte a4 = 0;
byte a3 = 0;
size_t o4off = 0;
size_t o3off = 0;
if (oidx < a4siz) {
bp = buf[oidx];
a4 = arr4[oidx];
o4off = OUTLEN(&ctl->ctl_out,arr4);
}
if (oidx < a3siz) {
a3 = arr3[oidx];
o3off = OUTLEN(&ctl->ctl_inb,arr3);
}
int errcur = (arr4[oidx] != buf[oidx]);
printf("encode_xcheck: arr=%8.8zX/",o4off);
if (pad)
printf("censored");
else
printf("%8.8zX",o3off);
printf(" oidx=%d exp=" FMT " act=" FMT " arr3=" FMT,
oidx,PRT(bp),PRT(a4),PRT(a3));
if (errany)
printf(" ANY");
if (errcur)
printf("/CUR");
printf("\n");
}
if (errany)
sysfault("encode_xcheck: fault\n");
} while (0);
dbgprt(ZPXHOWCHR,"encode_xcheck: EXIT\n");
}
#else
#define encode_xcheck(_ctl,_arr4,_a4siz,_arr3,_a3siz,_pad) \
do { } while (0)
#endif
// encode_wrap -- perform encoding and inject newline
static inline_nodebug byte *
encode_wrap(b64ctl_t *ctl,byte *arr4)
{
dbgprt(ZPXHOWCHR,"encode_wrap: ENTER ctl_wraplen=%d ctl_wrapmax=%d\n",
ctl->ctl_wraplen,ctl->ctl_wrapmax);
do {
// bug out if wrap disabled
if (ctl->ctl_wrapmax <= 0)
break;
// wait for wrap
ctl->ctl_wraplen += 4;
ctl->ctl_wrapnow = 0;
if (ctl->ctl_wraplen < ctl->ctl_wrapmax)
break;
ctl->ctl_wraplen = 0;
ctl->ctl_wrapnow = 1;
PUT4(0,'\n');
encode_xcheck(ctl,arr4,1,NULL,0,-1);
++arr4;
} while (0);
dbgprt(ZPXHOWCHR,"encode_wrap: EXIT ctl_wraplen=%d ctl_wrapnow=%d\n",
ctl->ctl_wraplen,ctl->ctl_wrapnow);
return arr4;
}
// encode_putx -- perform encoding
static inline_nodebug byte *
encode_putx(b64ctl_t *ctl,byte *arr4,const byte *arr3,int padlen)
{
dbgprt(ZPXHOWCHR,"b64encode: LOOP arr3=(" FMT " " FMT " " FMT ") padlen=%d\n",
PRT(arr3[0]),PRT(arr3[1]),PRT(arr3[2]),padlen);
PUTE(0,(arr3[0] & 0xfc) >> 2);
PUTE(1,((arr3[0] & 0x03) << 4) + ((arr3[1] & 0xf0) >> 4));
PUTE(2,((arr3[1] & 0x0f) << 2) + ((arr3[2] & 0xc0) >> 6));
PUTE(3,arr3[2] & 0x3f);
switch (padlen) {
case 2:
PUT4(2,'=');
// fall through
case 1:
PUT4(3,'=');
break;
}
encode_xcheck(ctl,arr4,4,arr3,3,padlen);
arr4 += 4;
return arr4;
}
// is_base64 -- ensure char is a valid base64 encoding char
#if ! B64DECODE_FAST
static inline int
is_base64(byte c)
{
return (isalnum(c) || (c == '+') || (c == '/'));
}
#endif
// decode_find -- convert encoded base64 char into binary byte
static inline byte
decode_find(byte chr)
{
byte out;
#if B64DECODE_FAST
out = decode_fast[chr];
#else
const char *find = strchr(base64_chars,chr);
out = find - base64_chars;
#endif
dbgprt(ZPXHOWCHR,"decode_find: XLAT out=" FMT " chr=" FMT "\n",
PRT(out),PRT(chr));
if (out == 0xFF)
sysfault("b64decode: NONBASE64 chr=" FMT "\n",PRT(chr));
return out;
}
// decode_put -- convert 4 byte encoded base64 cell into 3 binary bytes
static inline_nodebug byte *
decode_put(byte *arr3,byte *arr4,int a4len)
{
int idx;
int a3len;
dbgprt(ZPXHOWCHR,"decode_put: ENTER a4len=%d\n",a4len);
// convert to binary codes
idx = 0;
for (; idx < a4len; ++idx)
arr4[idx] = decode_find(arr4[idx]);
// add zero padding
#if 0
for (; idx < 4; ++idx)
arr4[idx] = 0;
#endif
a3len = (a4len * 3) / 4;
// store 3 binary chars for 4 byte cell
arr3[0] = (arr4[0] << 2) + ((arr4[1] & 0x30) >> 4);
arr3[1] = ((arr4[1] & 0xf) << 4) + ((arr4[2] & 0x3c) >> 2);
arr3[2] = ((arr4[2] & 0x3) << 6) + arr4[3];
#if B64VERBOSE
for (idx = 0; idx < a3len; ++idx)
dbgprt(ZPXHOWCHR,"decode_put: arr3[%d]=" FMT "\n",PRT(arr3[idx]));
#endif
// advance output pointer
arr3 += a3len;
dbgprt(ZPXHOWCHR,"decode_put: EXIT a3len=%d\n",a3len);
return arr3;
}
// finish -- finish an operation
static size_t
finish(b64ctl_t *ctl,byte *out)
{
b64buf_t *buf = &ctl->ctl_out;
size_t outlen = OUTLEN(buf,out);
if (outlen > buf->buf_len)
sysfault("finish: buffer overflow -- buf_len=%zu outlen=%zu\n",
buf->buf_len,outlen);
buf->buf_len = outlen;
return outlen;
}
// b64encode -- encode raw data to base64
// RETURNS actual output length
size_t
b64encode(b64ctl_t *ctl)
{
const byte *inb = ctl->ctl_inb.buf_base;
ssize_t inblen = ctl->ctl_inb.buf_len;
byte *arr4 = ctl->ctl_out.buf_base;
int anyflg = (inblen > 0);
dbgprt(ZPXHOWB64,"b64encode: ENTER inb=%p inblen=%zu\n",inb,inblen);
for (; inblen >= 3; inblen -= 3, inb += 3) {
arr4 = encode_putx(ctl,arr4,inb,0);
arr4 = encode_wrap(ctl,arr4);
}
if (inblen) {
byte arr3[3];
u32 j = 0;
int padlen = 3 - inblen;
dbgprt(ZPXHOWB64,"b64encode: POST inblen=%zu padlen=%d\n",
inblen,padlen);
// copy over valid bytes
for (; inblen > 0; --inblen, ++j)
arr3[j] = inb[j];
// add zeroes as padding?
for (; j < 3; ++j)
arr3[j] = 0;
// add final padding
arr4 = encode_putx(ctl,arr4,arr3,padlen);
arr4 = encode_wrap(ctl,arr4);
}
// sequence should end with newline
do {
dbgprt(ZPXHOWB64,"b64encode: WRAP anyflg=%d ctl_wrapnow=%d\n",
anyflg,ctl->ctl_wrapnow);
// no newline generation
if (ctl->ctl_wrapmax <= 0)
break;
// no legit data
if (! anyflg)
break;
// don't double up newlines if we just did a newline
if (ctl->ctl_wrapnow)
break;
PUT4(0,'\n');
encode_xcheck(ctl,arr4,1,NULL,0,0);
++arr4;
} while (0);
// always add EOS
#if 0
*arr4 = 0;
#endif
size_t outlen = finish(ctl,arr4);
dbgprt(ZPXHOWB64,"b64encode: EXIT outlen=%zu\n",outlen);
return outlen;
}
// b64decode -- decode base64 into raw binary
// RETURNS: actual output length
size_t
b64decode(b64ctl_t *ctl)
{
const char *inb = (const char *) ctl->ctl_inb.buf_base;
size_t inblen = ctl->ctl_inb.buf_len;
size_t inbidx = 0;
byte *arr3 = ctl->ctl_out.buf_base;
int outidx = 0;
byte arr4[4];
dbgprt(ZPXHOWB64,"b64decode: ENTER inb=%p\n",inb);
for (inbidx = 0; inbidx < inblen; ++inbidx) {
int chr = inb[inbidx];
dbgprt(ZPXHOWCHR,"b64decode: LOOP chr=" FMT "\n",PRT(chr));
// stop when we hit a pad char
if (chr == '=')
break;
// ignore newlines
if (chr == '\n')
continue;
// not a valid char
#if ! B64DECODE_FAST
if (! is_base64(chr)) {
sysfault("b64decode: NONBASE64 chr=" FMT "\n",PRT(chr));
break;
}
#endif
arr4[outidx++] = chr;
if (outidx == 4) {
arr3 = decode_put(arr3,arr4,4);
outidx = 0;
}
}
if (outidx > 0) {
dbgprt(ZPXHOWB64,"b64decode: POST outidx=%d inblen=%zu\n",
outidx,inblen);
// fill remainder with pad/zeroes
for (inbidx = outidx; inbidx < 4; ++inbidx)
arr4[inbidx] = 0;
arr3 = decode_put(arr3,arr4,outidx);
}
size_t outlen = finish(ctl,arr3);
dbgprt(ZPXHOWB64,"b64decode: EXIT outlen=%zu\n",outlen);
return outlen;
}
// b64bufdup -- safe buffer duplicate
void
b64bufdup(b64buf_t *dst,const b64buf_t *src)
{
const char *tag = dst->buf_tag;
dbgprt(ZPXHOWB64,"b64bufdup: ENTER dst=%s/%p src=%s/%p\n",
dst->buf_tag,dst->buf_base,src->buf_tag,src->buf_base);
if (dst->buf_base != NULL)
sysfault("b64bufdup: non-null -- dst=%s buf_base=%p src=%s\n",
tag,dst->buf_base,src->buf_tag);
*dst = *src;
dst->buf_tag = tag;
dbgprt(ZPXHOWB64,"b64bufdup: EXIT\n");
}
// b64bufput -- output buffer to file
void
b64bufput(const b64buf_t *bufp,const char *ofile)
{
int fd;
b64buf_t buf_;
b64buf_t *buf = &buf_;
ssize_t xlen;
*buf = *bufp;
printf("b64bufput: %s buf_base=%p buf_len=%zu\n",
ofile,buf->buf_base,buf->buf_len);
do {
if (buf->buf_opt & B64MMAP)
break;
fd = open(ofile,O_WRONLY | O_TRUNC | O_CREAT,0644);
if (fd < 0)
sysfault("b64bufput: unable to open '%s' -- %s\n",
ofile,strerror(errno));
for (; buf->buf_len > 0;
buf->buf_len -= xlen, buf->buf_base += xlen) {
xlen = write(fd,buf->buf_base,buf->buf_len);
if (xlen < 0)
sysfault("bufput: write error -- %s\n",strerror(errno));
}
CLOSEME(fd);
} while (0);
}
// b64bufget -- input file to buffer
void
b64bufget(b64buf_t *buf,const char *ifile)
{
struct stat st;
size_t cap;
int fd;
const char *etag = NULL;
ssize_t xlen;
do {
fd = open(ifile,O_RDONLY);
if (fd < 0) {
etag = "open";
break;
}
if (buf->buf_opt & B64MMAP) {
buf->buf_fdmap = fd;
// get file size
if (fstat(fd,&st) < 0) {
etag = "fstat";
break;
}
buf->buf_len = st.st_size;
buf->buf_base = mmap(NULL,buf->buf_len,PROT_READ,
MAP_SHARED,buf->buf_fdmap,0);
if (buf->buf_base == MAP_FAILED) {
etag = "mmap";
break;
}
break;
}
cap = 0;
buf->buf_len = 0;
buf->buf_base = NULL;
while (1) {
if (buf->buf_len >= cap) {
cap += 4096;
buf->buf_base = realloc(buf->buf_base,cap + 1);
if (buf->buf_base == NULL) {
etag = "realloc";
break;
}
}
xlen = read(fd,&buf->buf_base[buf->buf_len],cap - buf->buf_len);
if (xlen < 0) {
etag = "read";
break;
}
if (xlen == 0)
break;
buf->buf_len += xlen;
}
} while (0);
if (etag != NULL)
sysfault("b64bufget: unable to %s '%s' -- %s\n",
etag,ifile,strerror(errno));
do {
if (buf->buf_opt & B64MMAP)
break;
CLOSEME(buf->buf_fdmap);
cap = buf->buf_len;
buf->buf_base[cap] = 0;
buf->buf_base = realloc(buf->buf_base,cap + 1);
if (buf->buf_base == NULL)
sysfault("b64bufget: realloc fail -- %s\n",strerror(errno));
} while (0);
printf("b64bufget: %s buf_base=%p buf_len=%zu\n",
ifile,buf->buf_base,buf->buf_len);
}
// b64setup -- passive setup
void
b64setup(b64ctl_t *ctl,u32 opt,const char *tag)
{
b64buf_t *buf;
memset(ctl,0,sizeof(*ctl));
ctl->ctl_tag = tag;
buf = &ctl->ctl_out;
buf->buf_fdmap = -1;
buf->buf_opt = opt;
buf->buf_tag = "ctl_out";
buf = &ctl->ctl_inb;
buf->buf_fdmap = -1;
buf->buf_opt = opt;
buf->buf_tag = "ctl_inb";
ctl->ctl_fdchk = -1;
}
// init_outbuf -- initialize output buffer
static int
init_outbuf(b64ctl_t *ctl,size_t outlen)
{
b64buf_t *buf = &ctl->ctl_out;
int err = -1;
dbgprt(ZPXHOWB64,"init_outbuf: ENTER ctl=%s buf=%s buf_base=%p buf_len=%zu outlen=%zu\n",
ctl->ctl_tag,buf->buf_tag,buf->buf_base,buf->buf_len,outlen);
buf->buf_len = outlen;
do {
if (! (buf->buf_opt & B64MMAP)) {
buf->buf_base = realloc(buf->buf_base,outlen);
if (buf->buf_base == NULL)
break;
err = 0;
break;
}
if (ftruncate(buf->buf_fdmap,outlen) < 0)
break;
buf->buf_base = mmap(NULL,outlen,PROT_READ | PROT_WRITE,
MAP_SHARED,buf->buf_fdmap,0);
if (buf->buf_base == MAP_FAILED) {
buf->buf_base = NULL;
break;
}
err = 0;
} while (0);
dbgprt(ZPXHOWB64,"init_outbuf: EXIT err=%d\n",err);
return err;
}
// b64init_encode -- initialize for encode
// RETURNS: 0=okay, -1=error
int
b64init_encode(b64ctl_t *ctl,const b64buf_t *inb,int wrapmax)
{
size_t outlen;
// copy in the buffer
b64bufdup(&ctl->ctl_inb,inb);
// we need for 4 bytes of output for each 3 bytes of input
outlen = inb->buf_len;
outlen *= 4;
outlen /= 3;
outlen += 4;
// space for padding
outlen += 4;
// we wrap with newline every N bytes
if (wrapmax == 0)
wrapmax = 76;
ctl->ctl_wrapmax = wrapmax;
if (wrapmax > 0)
outlen += (outlen + wrapmax) / wrapmax;
return init_outbuf(ctl,outlen);
}
#if B64DECODE_FAST
// init_fast -- initialize fast decode lookup
static void
init_fast(void)
{
const char *cp = base64_chars;
memset(decode_fast,0xFF,sizeof(decode_fast));
for (int chr = *cp; chr != 0; ++cp, chr = *cp) {
size_t off = cp - base64_chars;
decode_fast[chr] = off;
dbgprt(ZPXHOWB64,"init_fast: FASTINIT chr='%c' off=%zu\n",
chr,off);
}
}
#endif
// b64init_decode -- initialize for decode
// RETURNS: 0=okay, -1=error
int
b64init_decode(b64ctl_t *ctl,b64buf_t *inb)
{
size_t outlen;
int err;
dbgprt(ZPXHOWB64,"b64init_decode: ENTER buf_len=%zu\n",inb->buf_len);
#if B64DECODE_FAST
if (decode_fast['B'] == 0)
init_fast();
#endif
if (inb != &ctl->ctl_inb)
ctl->ctl_inb = *inb;
inb = &ctl->ctl_inb;
// caller may already know the input length, but ...
#if 0
if (inb->buf_len == 0) {
inb->buf_len = strlen(inb->buf_base);
dbgprt(ZPXHOWB64,"b64init_decode: STRLEN buf_len=%zu\n",inb->buf_len);
}
#endif
// we need for 3 bytes of output for each 4 bytes of input
outlen = inb->buf_len;
outlen *= 3;
outlen += 3;
outlen /= 4;
err = init_outbuf(ctl,outlen);
dbgprt(ZPXHOWB64,"b64init_decode: EXIT err=%d outlen=%zu\n",err,outlen);
return err;
}
// b64destroy -- destroy/deinit output buffer
void
b64destroy(b64ctl_t *ctl)
{
b64bufrls(&ctl->ctl_out,"ctl_out");
b64bufrls(&ctl->ctl_inb,"ctl_inb");
}
// b64bufrls -- destroy/deinit output buffer
void
b64bufrls(b64buf_t *buf,const char *who)
{
size_t outlen = buf->buf_len;
int err = -1;
dbgprt(ZPXHOWB64,"b64bufrls: ENTER buf_opt=%8.8X buf_base=%p outlen=%zu (from %s)\n",
buf->buf_opt,buf->buf_base,outlen,who);
do {
if (! (buf->buf_opt & B64MMAP)) {
FREEME(buf->buf_base);
err = 0;
break;
}
if (munmap(buf->buf_base,outlen) < 0)
break;
if (buf->buf_opt & B64TRIM) {
if (ftruncate(buf->buf_fdmap,outlen) < 0)
break;
}
CLOSEME(buf->buf_fdmap);
} while (0);
if (err < 0)
exit(1);
buf->buf_base = NULL;
buf->buf_len = 0;
dbgprt(ZPXHOWB64,"b64bufrls: EXIT\n");
}
FILE: b64test.c
// b64test.c -- test program for base64
#include <base64.h>
int opt_a; // exhaustive test
int opt_L; // binary file length
int opt_k; // keep temp files
int opt_m; // use mmap
u32 opt_R = 1; // random seed
int opt_T; // number of tests
int opt_W; // wrap length
int tstno = 1; // current test number
#define ALLFILES(_cmd) \
_cmd(bin) \
_cmd(encexp) \
_cmd(encact) \
_cmd(dcdexp) \
_cmd(dcdact)
#define FILEDEF(_pre) \
const char *_pre##_file = #_pre ".TMP";
ALLFILES(FILEDEF)
#define FILERM(_pre) \
unlink(_pre##_file);
// initial random binary buffer
B64BUFDEF(binbuf);
// encoding control
B64BUFDEF(encbuf);
B64CTLDEF(ctlenc);
// decoding control
B64BUFDEF(dcdbuf);
B64CTLDEF(ctldcd);
int
doexec(const char *cmd)
{
printf("DOEXEC: %s\n",cmd);
int ignflg = (cmd[0] == '!');
if (ignflg)
++cmd;
int code = system(cmd);
if (code && (! ignflg))
exit(1);
return code;
}
int
xrand(void)
{
return rand_r(&opt_R);
}
// doclean -- remove temp files
void
doclean(void)
{
do {
if (opt_k)
break;
ALLFILES(FILERM);
} while (0);
}
void
dotest(int binlen)
{
int err;
u32 opt = 0;
b64ctl_t *ctl;
b64buf_t *buf;
char cmd[1000];
printf("\n");
for (int col = 1; col <= 80; ++col)
putchar('-');
printf("\n");
dbgprt(ZPXHOWB64,"dotest: ENTER binlen=%d\n",binlen);
buf = &binbuf;
if (binlen <= 0)
buf->buf_len = -binlen;
else
buf->buf_len = xrand() % binlen;
printf("dotest: %d -- R=%u L=%8.8zX/%zu\n",
tstno,opt_R,buf->buf_len,buf->buf_len);
doclean();
if (opt_m) {
opt |= B64MMAP;
opt |= B64TRIM;
}
// NOTE: this gets freed in the b64destroy for ctlenc below
buf->buf_base = NULL;
buf->buf_base = realloc(buf->buf_base,buf->buf_len);
if (buf->buf_base == NULL)
sysfault("dotest: realloc failure -- %s\n",strerror(errno));
// get a random buffer
for (size_t bufidx = 0; bufidx < buf->buf_len; ++bufidx)
buf->buf_base[bufidx] = xrand();
// dump it for base64 program
b64bufput(buf,bin_file);
// have base64 encode it
sprintf(cmd,"base64 %s > %s",bin_file,encexp_file);
doexec(cmd);
ctl = &ctlenc;
b64setup(ctl,opt,"ctlenc");
err = b64init_encode(ctl,buf,opt_W);
if (err < 0)
sysfault("dotest: b64init_encode failure -- %s\n",strerror(errno));
#if B64ENCODE_XCHECK
ctl->ctl_fdchk = open(encexp_file,O_RDONLY);
#endif
// have our routine encode it
b64encode(ctl);
#if B64ENCODE_XCHECK
CLOSEME(ctl->ctl_fdchk);
#endif
// save it to a file
b64bufput(&ctl->ctl_out,encact_file);
b64destroy(ctl);
// compare them
sprintf(cmd,"diff -u %s %s",encexp_file,encact_file);
doexec(cmd);
// decode it
sprintf(cmd,"base64 -d %s > %s",encexp_file,dcdexp_file);
doexec(cmd);
// passive setup
ctl = &ctldcd;
b64setup(ctl,opt,"ctldcd");
// load up the encoded file into the decode input buffer
b64bufget(&dcdbuf,encact_file);
// decode the data
err = b64init_decode(ctl,&dcdbuf);
if (err < 0)
sysfault("dotest: b64init_decode failure -- %s\n",strerror(errno));
// have our routine decode it
b64decode(ctl);
b64bufput(&ctl->ctl_out,dcdact_file);
b64destroy(ctl);
// compare them
sprintf(cmd,"cmp %s %s",dcdexp_file,dcdact_file);
doexec(cmd);
// final temp file cleanup
doclean();
printf("dotest: complete\n");
dbgprt(ZPXHOWB64,"dotest: EXIT\n");
}
int
main(int argc,char **argv)
{
char *cp;
--argc;
++argv;
setlinebuf(stdout);
// use a special output directory
do {
cp = getenv("GENDIR");
if (cp == NULL)
break;
printf("GENDIR = %s\n",cp);
if (chdir(cp) < 0)
sysfault("main: chdir fault -- %s\n",strerror(errno));
} while (0);
// parse options
for (; argc > 0; --argc, ++argv) {
cp = *argv;
if (*cp != '-')
break;
cp += 2;
switch (cp[-1]) {
case 'a':
opt_a = (*cp != 0) ? atoi(cp) : 1;
break;
case 'L':
opt_L = (*cp != 0) ? atoi(cp) : 1000;
break;
case 'k':
opt_k = ! opt_k;
break;
case 'm':
opt_m = ! opt_m;
break;
case 'R':
opt_R = (*cp != 0) ? atoi(cp) : 1;
break;
case 'T':
opt_T = (*cp != 0) ? atoi(cp) : 100;
break;
case 'W':
opt_W = atoi(cp);
break;
}
}
// ensure at least one test
if (opt_T <= 0)
opt_T = 1;
do {
// ensure we have a non-zero length
if (opt_L == 0)
opt_L = 100;
// do random testing
if (opt_a < 0) {
for (; tstno <= opt_T; ++tstno)
dotest(opt_L);
break;
}
// get absolute value
if (opt_L < 0)
opt_L = -opt_L;
// ensure we get at least one test
if (opt_L < opt_a)
opt_L = opt_a;
// do a range of explicit lengths
for (int binlen = opt_a; binlen <= opt_L; ++binlen, ++tstno)
dotest(-binlen);
} while (0);
printf("%d tests completed\n",tstno);
return 0;
}
FILE: dbgcom.h
// dbgflg.h -- base/debug definitions
#ifndef _dbgflg_h_
#define _dbgflg_h_
#include <stdio.h>
#include <stdlib.h>
typedef unsigned char byte;
typedef unsigned int u32;
#define ZPXHOWALL(_cmd) \
_cmd(ZPXHOWB64) \
_cmd(ZPXHOWCHR) \
_cmd(ZPXHOWTST)
#define _DBGENUM(_sym) \
_sym,
enum {
ZPXHOWANY,
ZPXHOWALL(_DBGENUM)
ZPXHOWMAX
};
byte dbgflg[ZPXHOWMAX];
static inline byte
dbgok(int lvl)
{
return dbgflg[lvl];
}
#if DEBUG || _USE_ZPRT_
#define XVERBOSE 1
#define dbgprt(_lvl,_fmt...) \
do { \
if (! dbgok(_lvl)) \
break; \
int sverr = errno; \
printf(_fmt); \
errno = sverr; \
} while (0)
#define inline_nodebug /**/
#else
#define XVERBOSE 0
#define inline_nodebug inline
#define dbgprt(_fmt...) \
do { } while (0)
#endif
#define sysfault(_fmt...) \
do { \
printf(_fmt); \
exit(1); \
} while (0)
#define RNGE(_val,_lo,_hi) \
(((_val) >= (_lo)) && ((_val) <= (_hi)))
#define PRTABLE(_val) \
RNGE(_val,0x20,0x7E) ? (_val) : '.'
#define CLOSEME(_fd) \
do { \
if (_fd < 0) \
break; \
dbgprt(ZPXHOWB64,"CLOSEME: fd=%d (from %d)\n",_fd,__LINE__); \
close(_fd); \
_fd = -1; \
} while (0)
#define FREEME(_ptr) \
do { \
dbgprt(ZPXHOWB64,"FREEME: ptr=%p (from %d)\n",_ptr,__LINE__); \
free(_ptr); \
_ptr = NULL; \
} while (0)
#endif
FILE: dbgcom.c
// dbgcom.c -- tracing setup
#include <dbgcom.h>
struct dbgdef {
int dbg_lvl;
const char *dbg_sym;
};
#define _ZPXDEF(_sym) \
{ .dbg_lvl = _sym, .dbg_sym = #_sym },
struct dbgdef dbgdef[] = {
ZPXHOWALL(_ZPXDEF)
{ .dbg_sym = NULL }
};
void __attribute__((constructor))
dbginit(void)
{
struct dbgdef *dbg = dbgdef;
for (; dbg->dbg_sym != NULL; ++dbg) {
char *cp = getenv(dbg->dbg_sym);
if (cp == NULL)
continue;
if (! atoi(cp))
continue;
dbgflg[dbg->dbg_lvl] = 1;
dbgflg[ZPXHOWANY] = 1;
}
}
iv tried a lot of solutions to try to get this working (i.e using memcpy etc) I cant seem to find the issue, depending on what I try I either end up with gibberish or SEGV
iv spent a lot of time already googling and trying different ways, i still cant figure out why the arrays won't combine successfully
#include <stdio.h>
#include <stdint.h>
#include <dirent.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/syscall.h>
#include <unistd.h>
#define log_info printf
typedef struct
{
char* name;
//size_t size;
} entry_t;
/* qsort struct comparison function (C-string field) */
static int struct_cmp_by_name(const void* a, const void* b)
{
entry_t* ia = (entry_t*)a;
entry_t* ib = (entry_t*)b;
return strcmp(ia->name, ib->name);
/* strcmp functions works exactly as expected from comparison function */
}
entry_t* get_item_entries(const char* dirpath, int* count)
{
struct dirent* dent;
char buffer[512]; // fixed buffer
int dfd = 0,
n, r = 1; // item counter, rounds to loop
entry_t* p = NULL; // we fill this struct with items
loop:
n = 0;
printf("loop: %d, count:%d\n", r, *count);
// try to open dir
dfd = open(dirpath, O_RDONLY, 0);
if (dfd < 0)
{
printf("Invalid directory. (%s)\n", dirpath);
*count = -1;
return NULL;
}
else
{
printf("open(%s)\n", dirpath);
}
memset(buffer, 0, sizeof(buffer));
while (syscall(SYS_getdents, dfd, buffer, sizeof(buffer)) != 0)
{
dent = (struct dirent*)buffer;
while (dent->d_fileno)
{ // skip `.` and `..`
if (!strncmp(dent->d_name, "..", 2)
|| !strncmp(dent->d_name, ".", 1)) goto skip_dent;
// deal with filtering outside of this function, we just skip .., .
switch (r)
{ // first round: just count items
case 1:
{
// skip special cases
if (dent->d_fileno == 0) goto skip_dent;
break;
}
// second round: store filenames
case 0: p[n].name = strdup(dent->d_name); break;
}
n++;
skip_dent:
dent = (struct dirent*)((void*)dent + dent->d_reclen);
if (dent == (void*)&buffer[512]) break; // refill buffer
}
memset(buffer, 0, sizeof(buffer));
}
close(dfd);
// on first round, calloc for our list
if (!p)
{ // now n holds total item count, note it
p = calloc(n, sizeof(entry_t));
*count = n;
}
// first round passed, loop
r--; if (!r) goto loop;
// report count
printf("%d items at %p, from 1-%d\n", *count, (void*)p, *count);
/* resort using custom comparision function */
qsort(p, *count, sizeof(entry_t), struct_cmp_by_name);
// report items
//for (int i = 0; i < num; ++i) log_error( "%s", p[i].name);
return p;
}
int main(int argc, char* argv[])
{
int HDD_count = -1;
uint32_t total = -1;
int ext_count = -1;
entry_t* e = NULL;
entry_t *HDD = get_item_entries("/mnt/f/n", &HDD_count);
entry_t* ext = get_item_entries("/mnt/f/dls", &ext_count);
total = ext_count + HDD_count;
e = (entry_t*)malloc(sizeof *e * total);
if (e != NULL)
{
for (int i = 1; i < HDD_count; i++)
{
log_info("HDD[%i].name %s\n", i, HDD[i].name);
e[i].name = strdup(HDD[i].name);
}
for (int i = 1; i < ext_count; i++)
{
log_info("ext[%i].name %s\n", i, ext[i].name);
e[i + HDD_count].name = strdup(ext[i].name);
}
}
else
printf("Failed to Allocate the Array");
char tmp[256];
int i = 1, j;
for(j = 1; j <= total; j++)
{
snprintf(&tmp[0], 255, "%s", e[ j].name);
log_info("%i:%s\n", j , tmp);
}
return 0;
}
Here is a rewrite of a snippet of main() that I mentioned in my comment above:
#define CHECK(p, msg) if(!(p)) { printf("%s:%d: %s", __FILE__, __LINE__, msg); return 1;}
...
entry_t *HDD = get_item_entries("/mnt/f/n", &HDD_count);
CHECK(HDD, "HDD failed to get entries");
entry_t *ext = get_item_entries("/mnt/f/dls", &ext_count);
CHECK(ext, "ext failed to get entries");
uint32_t total = HDD_count + ext_count;
entry_t *e = malloc(total * sizeof(*e));
CHECK(e, "malloc failed");
for(int i = 0; i < HDD_count; i++) {
log_info("HDD[%i].name %s\n", i, HDD[i].name);
e[i].name = strdup(HDD[i].name);
}
// write a function instead of duplicating code?
for (int i = 0; i < ext_count; i++) {
log_info("ext[%i].name %s\n", i, ext[i].name);
e[HDD_count + i].name = strdup(ext[i].name);
}
It looks like a short lived program, but I would still free the values from strdup() and e itself.
i have the program below. i wanted to practice linked lists and tried to build an app which can save flags entered to the program into a linked list all my controls are working fine about the flags but when i enter everything correct instead of listing the flags i get a core dumped error
--UPDATE--
The program is supposed to check the flags provided to program whether they are valid or require any value and if everything is ok its supposed to print key value pairs to console which are stored in a linked list
i compile the program by invoking gcc test.c init.c and run as ./a.out -test someParam
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "init.h"
//f for false t for true
const char *flgs[3][2] = {{"-test", "t"}, {"-hey", "f"}, {"-heydehey", "f"}};
int forEach(FLAGS *flags, void (*cb)(char *flag, char *vl)) {
FLAGS *current = flags;
if (current == NULL) {
return -1;
}
while (current != NULL) {
cb(current->flag, current->value);
current = current->next;
}
return 0;
}
FLAGS *initArgs(int argc, char **argv) {
if (argc < 2) {
return NULL;
}
int flagsNum = 3;
FLAGS *rtr = malloc(sizeof(FLAGS));
if (rtr == NULL) {
fprintf(stderr, "unable to allocate memory\n");
exit(-1);
}
FLAGS *current = NULL;
rtr->next = current;
bool invalidFlag = true;
bool skipNext = false;
for (int i = 1; i < argc; i++) {
if (skipNext) {
skipNext = false;
continue;
}
invalidFlag = true;
if (argv[i][0] == '-') {
// if flag
current = malloc(sizeof(FLAGS));
for (int f = 0; f < 3; f++) {
if (!strcmp(argv[i], flgs[f][0])) {
invalidFlag = false;
if (flgs[f][1] == "t") {
if (i + 1 == argc || argv[i + 1][0] == '-') {
fprintf(stderr, "flag %s requires a value ,none given\n", argv[i]);
exit(-1);
}
current->value = argv[i + 1];
current->next = NULL;
current = current->next;
skipNext = true;
}
current->flag = argv[i];
}
}
if (invalidFlag) {
fprintf(stderr, "\x1B[31minvalid flag %s\n", argv[i]);
exit(-1);
}
}
}
return rtr;
}
and here are my init.h and test.c files
test.c
#include <stdio.h>
#include <stdlib.h>
#include "init.h"
void cb(char *, char *);
int main(int argc, char **argv) {
FLAGS *entered = initArgs(argc, argv);
if (entered == NULL) {
fprintf(stderr, "an error occured\n");
return -1;
}
forEach(entered, &cb);
return 0;
}
void cb(char *fl, char *val) { printf("flag=%s; value=%s;\name", fl, val);
}
init.h
#define true 1
#define false 0
typedef int bool;
typedef struct values {
char *flag;
char *value;
struct values *next;
} FLAGS;
extern const char *flgs[3][2];
int forEach(FLAGS *, void (*cb)(char *, char *));
FLAGS *initArgs(int argc, char **argv);
Look at these lines and my comments:
current->next = NULL; // Here current->next becomes NULL
current = current->next; // so here current becomes NULL
skipNext = true;
}
current->flag = argv[i]; // So here you dereference NULL
consequently you get a core dump.
I am writing an algorithm that requires me to search nearest neighbors of points. I found the kdtree library from this post (Using Google's C KD Tree Library) but it does not have a function to delete individual nodes from the tree. So I started to implement my own using
www (dot) geeksforgeeks.org/k-dimensional-tree-set-3-delete/
as a template. It all runs through but unfortunately sometimes nodes get duplicated.
My test case is the following:
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <math.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include "kdtree.h"
/* (hopefully) platform independent directory creation */
#if defined(_WIN32) || defined(WIN32) /* this should be defined under windows, regardless of 64 or 32 bit*/
#include <direct.h>
#include <sys/stat.h>
#define GetWorkingDir _getcwd
#define MakeDir(str) _mkdir(str)
#else /* unix based system */
#include <unistd.h>
#include <sys/stat.h>
#define GetWorkingDir getcwd
#define MakeDir(str) mkdir(str, 0777)
#endif
#ifndef MAX_PATH
#define MAX_PATH 260
#endif
void GetLogDir(char* strPath, int nBufSize)
{
if(GetWorkingDir(strPath, nBufSize))
{
strncat(strPath, "/log/", 5);
MakeDir(strPath);
}
else
{
fprintf(stderr, "Could not get working directory");
exit(ENOENT);
}
}
FILE* GetOpenFileHandle(const char* strFilenamePlusPath, const char* strOpenMode)
{
if(strOpenMode == NULL) // too bad we dont have default arguments in C :(
{
strOpenMode = "a+";
}
return(fopen(strFilenamePlusPath, strOpenMode));
}
int CloseFile(FILE* pFile)
{
if(pFile != NULL)
{
fprintf(pFile, "\r\n"); // append a new line before closing!
return(fclose(pFile));
}
fprintf(stderr, "Invalid file handle");
exit(EFAULT);
}
void NodeLabelToFile(FILE* pFile, kdnode* node, const char* strName)
{
fprintf(pFile, "%s [label=\"(%.3f, %.3f)\"] \n", strName, node->pos[0], node->pos[1]);
}
char* NodeToString(kdnode* node, int* num)
{
char* strName = (char*) malloc(MAX_PATH);
if(*num == 0)
{
sprintf(strName, "%s","root");
}
else
{
sprintf(strName, "node%d", *num);
}
return strName;
}
void NodesToFile(FILE* pFile, kdnode* node, const char* strParentname, int* num)
{
if(node && pFile)
{
char* strLeft = NULL;
char* strRight = NULL;
if(node->left)
{
(*num)++;
strLeft = NodeToString(node->left, num);
NodeLabelToFile(pFile, node->left, strLeft);
fprintf(pFile, "%s -> %s \n", strParentname, strLeft);
}
if(node->right)
{
(*num)++;
strRight = NodeToString(node->right, num); // name of the current node
NodeLabelToFile(pFile, node->right, strRight);
fprintf(pFile, "%s -> %s \n", strParentname, strRight);
}
if(strLeft)
{
NodesToFile(pFile, node->left, strLeft, num);
free(strLeft);
}
if(strRight)
{
// (*num)++;
NodesToFile(pFile, node->right, strRight, num);
free(strRight);
}
}
}
FILE* MakeOpenLogFile(const char* strFilename, const char* strOpenMode)
{
if(strOpenMode == NULL)
{
strOpenMode = "a+";
}
char* strFilenamePlusPath = (char*) malloc(MAX_PATH);
GetLogDir(strFilenamePlusPath, MAX_PATH);
strncat(strFilenamePlusPath, strFilename, strlen(strFilename));
FILE* pFile = GetOpenFileHandle(strFilenamePlusPath, strOpenMode);
free(strFilenamePlusPath);
return(pFile);
}
void KDTreeToDotFile(kdtree* Tree, const char* strFilename)
{
if(Tree)
{
FILE* pFile = MakeOpenLogFile(strFilename, "w");
fprintf(pFile, "%s", "digraph d { \n"); // print opening statement for the graph in dot language
// traverse the tree and print the nodes
int* num = (int*) malloc(sizeof(int)); // make this a unique location to make sure numbers can't occur twice
*num = 0;
char* strRoot = NodeToString(Tree->root, num);
NodeLabelToFile(pFile, Tree->root, strRoot);
NodesToFile(pFile, Tree->root, "root", num);
if(strRoot)
{
free(strRoot);
}
free(num);
fprintf(pFile,"%s", "}"); // close the digraph environment
CloseFile(pFile);
}
}
int main(int argc, const char * argv[])
{
int numel = 20;
int toRemove = 19;
double dMax = 3000;
int nNumDim = 2;
printf("init rng");
srand(1234); // seed the rng // srand((unsigned) time(&t));
printf("creating kdtree");
kdtree* TreeRoot = kd_create(nNumDim); // construct the kd tree for the nearest neighbor search
kd_data_destructor(TreeRoot, free); // set free as data destructor
double* pos = (double*) malloc(nNumDim * numel * sizeof(double));
int retval;
for (int ii = 0; ii < numel; ii++)
{
pos[nNumDim * ii] = floor((double)rand()/(double)(RAND_MAX/dMax));
pos[nNumDim * ii + 1] = floor((double)rand()/(double)(RAND_MAX/dMax));
int* randint = (int*) malloc(sizeof(int));
*randint = rand();
retval = kd_insert2(TreeRoot,
pos[nNumDim * ii],
pos[nNumDim * ii + 1],
randint, sizeof(int));
assert(retval == 0);
}
KDTreeToDotFile(TreeRoot, "original.dot");
double* dRemovePos = (double*) malloc(sizeof(double)*nNumDim);
for (int ii = 0; ii < toRemove; ii++)
{
dRemovePos[0] = pos[2*ii];
dRemovePos[1] = pos[2*ii + 1];
kd_remove(TreeRoot, dRemovePos);
}
KDTreeToDotFile(TreeRoot, "removed.dot");
kd_free(TreeRoot); // free kdtree
return 0;
}
and the functions to remove the nodes are implemented like this:
(I don't think if it is too much code, so I only will post my changes to the kd library. If I should add the rest of the code, which is more than 1000 lines unfortunately, just tell me in the comments.)
int kd_remove(kdtree* tree, const double* pos)
{
printf("removing node %.3f, %.3f \n", pos[0], pos[1]);
if(tree->root != NULL)
{
assert(tree->dim != 0); // prevent division by 0 (error code 136)
assert(pos != NULL); // make sure a valid position is passed
tree->root = remove_rec(tree->root, pos, tree->dim, tree->destr, 0);
}
return(0);
}
kdnode* remove_rec(kdnode* node, const double* pos, int dim, void (*destr)(void*), int depth)
{
if(node == NULL)
{
return(NULL);
}
int curdim = depth % dim;
if(same_pos(node->pos, pos, dim))
{
// we found the droid we're looking for
if(node->right)
{
// find the minimum in the right subtree
kdnode* node_min = find_min(node->right, curdim, dim);
if(node_min)
{
copy_node_data(node_min, node, dim);
node->right = remove_rec(node->right, node_min->pos, dim, destr, depth + 1);
}
}
else if(node->left)
{
// find the minimum in the left subtree
kdnode* node_min = find_min(node->left, curdim, dim);
if(node_min)
{
copy_node_data(node_min, node, dim);
node->left = remove_rec(node->left, node_min->pos, dim, destr, depth + 1);
}
}
else
{
// no subtrees -> delete the found node
clear_rec(node, destr);
return(NULL);
}
return node; // return the newly filled node to the recursion step one "above"
}
else
{
// points are not the same, look further
if(pos[curdim] < node->pos[curdim])
{
// position we're looking for is smaller -> go left
node->left = remove_rec(node->left, pos, dim, destr, depth + 1);
}
else
{
// go right, position we're looking for is greater
node->right = remove_rec(node->right, pos, dim, destr, depth + 1);
}
return node;
}
}
void copy_node_data(const kdnode* src, kdnode* dst, int dim)
{
if(src && dst)
{
int nNumBytes = dim * sizeof(double);
memcpy(dst->pos, src->pos, nNumBytes);
if(dst->data != NULL)
{
free(dst->data);
dst->data = malloc(src->databytes);
}
memcpy(dst->data, src->data, src->databytes);
dst->databytes = src->databytes;
}
}
int same_pos(const double* pos1, const double* pos2, int dim)
{
for (int i = 0; i < dim; ++i)
{
if(pos1[i] != pos2[i])
{
return 0; // false
}
}
return 1; // true
}
kdnode* find_min(kdnode* node, int dir, int numdim)
{
return find_min_rec(node, dir, 0, numdim);
}
kdnode* find_min_rec(kdnode* node, int dir, int depth, int numdim)
{
if(!node)
{
return NULL;
}
if(node->left == NULL && node->right == NULL)
{
return node; // is leaf node
}
int curdim = depth % numdim;
if(curdim == numdim)
{
if(node->left == NULL)
{
// no smaller node in tree
return node;
}
else
{
// left subtree is populated -> we need to go deeper
return find_min_rec(node->left, node->dir, depth + 1, numdim);;
}
}
// we have to search both subtrees and find the smallest value compared to the current node
return min_node(node, find_min_rec(node->left, node->dir, depth + 1, numdim),
find_min_rec(node->right, node->dir, depth + 1, numdim), node->dir);
}
kdnode* min_node(kdnode* a, kdnode* left, kdnode* right, int dir)
{
if(a == NULL)
{
// node a is the only one that can't be NULL!
fprintf(stderr, "Error: invalid node passed! \n");
exit(EFAULT);
}
kdnode* result = a;
if(left != NULL)
{
if(left->pos[dir] < result->pos[dir])
{
result = left;
}
}
if(right != NULL)
{
if(right->pos[dir] < result->pos[dir])
{
result = right;
}
}
return result;
}
original.dot looks like this and removed.dot like that.
I've been debugging this since yesterday and I have the feeling it is something really obvious that I am missing here...
Thanks in advance to anyone willing to help :)
You are creating 40 elements
int numel = 20;
int nNumDim = 2;
double* pos = (double*) malloc(nNumDim * numel * sizeof(double)); // Don't cast
but removing only 38
int toRemove = 19;
for (int ii = 0; ii < toRemove; ii++)
{
dRemovePos[0] = pos[nNumDim * ii];
dRemovePos[1] = pos[nNumDim * ii + 1];
kd_remove(TreeRoot, dRemovePos);
}
In the last iteration:
pos[nNumDim * ii]; = pos[2 * 18]; = pos[36];
pos[nNumDim * ii + 1]; = pos[2 * 18 + 1]; = pos[37];
pos[38] and pos[39] are still there.
Change to int toRemove = 20;.
Your code is obfuscated due to the flat array, why don't you declare some type like
struct data {
double el1;
double el2;
};
or
typedef double data[2];
and then
data *value = malloc(numel * sizeof(*value));
So, I know this probably won't be read by anyone but I found the bug after not touching the code for a while and for completeness here is how:
In the find_min() function I start the recursion with depth = 0.
This can cause the split dimension to get messed up and therefore not access all the nodes.
I modified the function to take depth as an argument and pass the recursion depth of remove_rec() like this:
kdnode* node_min = find_min(node->right, curdim, dim, depth + 1);
and
kdnode* node_min = find_min(node->left, curdim, dim, depth + 1);
respectively.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
I am working on a school project which is basically creating a simple shell in UNIX.
But I'm stuck with history part of my project.The explanation which is about history part is explained below:
history – This command is for maintaining a history of commands previously issued.
o history - print up to the 10 most recently entered commands in your shell.
o ! number - A user should be able to repeat a previously issued command by
typing ! number, where number indicates which command to repeat.
Note that ! 1 is for repeating the command numbered 1 in the list of commands returned by
history, and ! -1 is for repeating the last command.
And my code till history part is here :
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <limits.h>
#include <malloc.h>
#include <string.h>
#include <termios.h>
#include <errno.h>
#define CREATE_FLAGS (O_WRONLY | O_CREAT | O_APPEND)
#define CREATE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
#define CREATE_FLAG (O_WRONLY| O_CREAT| O_TRUNC)
#define MAXCHARNUM 128
#define MAXARGNUM 32
char *argsexec[MAXARGNUM];
char str[MAXCHARNUM];
char *path;
char *name;
struct Node
{
pid_t pid;
char *pname;
int index;
struct Node *nextPtr;
};
typedef struct Node Node;
typedef struct Node *NodePtr;
NodePtr list = NULL;
void addJob(NodePtr *currentPtr, pid_t pid, char *name, int indx)
{
NodePtr newPtr, prePtr, curPtr;
newPtr = malloc(sizeof(Node));
if (newPtr != NULL )
{
newPtr->pid = pid;
newPtr->pname = name;
newPtr->index = indx;
newPtr->nextPtr = NULL;
prePtr = NULL;
curPtr = *currentPtr;
while (curPtr != NULL )
{
prePtr = curPtr;
curPtr = curPtr->nextPtr;
}
if (prePtr == NULL )
{
newPtr->nextPtr = *currentPtr;
*currentPtr = newPtr;
}
else
{
prePtr->nextPtr = newPtr;
newPtr->nextPtr = curPtr;
}
}
}
void printJob(NodePtr curPtr)
{
if (curPtr == NULL )
{
printf("Running: List is empty.\n");
printf("Terminated: List is empty.\n");
}
else
{
printf("Running:\n");
while (curPtr != NULL )
{
printf("[%d] --> %s\n", curPtr->index, curPtr->pname);
curPtr = curPtr->nextPtr;
}
printf("Finished:\n");
while (curPtr != NULL )
{
printf("[%d] --> %s (pid = %d)\n", curPtr->index, curPtr->pname,
curPtr->pid);
curPtr = curPtr->nextPtr;
}
}
}
void ioredirection()
{
int input = -1, output = -1, append = -1;
int k, d, fdinput, fdoutput;
for (k = 0; argsexec[k] != NULL ; k++)
{
if (strcmp(argsexec[k], "<") == 0)
{
argsexec[k] = NULL;
input = k;
d = 1;
}
else if (strcmp(argsexec[k], ">") == 0)
{
argsexec[k] = NULL;
output = k;
d = 2;
}
else if (strcmp(argsexec[k], ">>") == 0)
{
argsexec[k] = NULL;
append = k;
d = 3;
}
if (d == 1)
{
fdinput = open(argsexec[input + 1], O_RDONLY, 0);
dup2(fdinput, STDIN_FILENO);
close(fdinput);
execvp(argsexec[0], argsexec);
}
if (d == 2)
{
int x, y;
char buffer[1024];
fdinput = open(argsexec[output - 1], O_RDONLY);
fdoutput = open(argsexec[output + 1], CREATE_FLAG, CREATE_MODE);
dup2(fdoutput, STDOUT_FILENO);
x = read(fdinput, buffer, 1024);
write(fdoutput, buffer, x);
close(fdinput);
close(fdoutput);
for (y = output; y < MAXARGNUM - 2; y++)
argsexec[y] = argsexec[y + 2];
argsexec[MAXARGNUM - 2] = NULL;
}
if (d == 3)
{
int x, y;
char buffer[1024];
fdinput = open(argsexec[output - 1], O_RDONLY);
fdoutput = open(argsexec[output + 1], CREATE_FLAGS, CREATE_MODE);
x = read(fdinput, buffer, 1024);
write(fdoutput, buffer, x);
close(fdinput);
close(fdoutput);
}
}
}
void add_path(char **dir, const char *begin, const char *end) //do the memory allocations, and add to the specified arrays.
{
if (end == begin)
{
begin = " ";
end = begin + 1;
}
size_t len = end - begin;
*dir = malloc(len + 1);
memmove(*dir, begin, len);
(*dir)[len] = '\0';
}
size_t tokenize(const char *path, char **dirs, size_t max_dirs, char delim) //tokenize the given input, with the given delimiter
{ //returns the size of the splitted parts of the string.
const char *begin = path;
const char *end;
size_t num_dirs = 0;
while (num_dirs < max_dirs && (end = strchr(begin, delim)) != 0)
{
add_path(&dirs[num_dirs++], begin, end);
begin = end + 1;
}
if (num_dirs < max_dirs && *begin != '\0')
add_path(&dirs[num_dirs++], begin, begin + strlen(begin));
return num_dirs;
}
void clearArgs()
{
int i;
for (i = 0; i < MAXARGNUM; ++i)
{
argsexec[i] = NULL;
}
}
int Ampersand()
{
int i;
for (i = 0; argsexec[i] != NULL ; i++)
{
if (strcmp(argsexec[i], "&") == 0)
{
return 1;
}
else
{
return 0;
}
}
}
void Setup()
{
while (1)
{
path = malloc((MAXCHARNUM + 1) * sizeof(char));
clearArgs();
fprintf(stderr, "333sh: ", NULL );
gets(str); //get the next commands
while (strlen(str) == 0)
{ //if the user enters empty string or space, ignore this input, read again.
fprintf(stderr, "333sh: ", NULL );
gets(str);
}
size_t commands = tokenize(str, argsexec, MAXARGNUM, ' ');
const char *path = getenv("PATH"); //get the system's path
ioredirection();
char * const arguments[] =
{ argsexec[0], argsexec[1], argsexec[2], argsexec[3], argsexec[4],
argsexec[5], argsexec[6], argsexec[7], (void*) NULL };
name = argsexec[0];
pid_t pid = fork();
wait(NULL );
if (Ampersand())
{
if (pid == 0)
{
int in = 1;
addJob(&list, pid, name, in);
}
}
if (pid == 0)
{
if (!Ampersand())
{
if (path == NULL )
{ //execl part
execl(path, argsexec[0], argsexec[1], argsexec[2], argsexec[3],
argsexec[4], argsexec[5], argsexec[6], argsexec[7], NULL );
}
else if (strcmp(argsexec[0], "dir") == 0 && argsexec[1] == NULL )
{
system("ls");
}
else if (strcmp(argsexec[0], "clr") == 0)
{
system("clear");
}
else if (strcmp(argsexec[0], "cd") == 0 && argsexec[1] == NULL )
{
system("pwd");
}
else if (strcmp(argsexec[0], "list_jobs") == 0 && argsexec[1] == NULL )
{
printJob(list);
}
else
{ //execvp part
execvp(argsexec[0], arguments);
}
}
}
}
}
int main(int argc, char const *argv[])
{
Setup();
return 0;
}
So how can i design a history part of this project ? Any idea would be appreciated.And sorry for asking that much long code.
Thanks
One way would be to create an array of 10 pointers to NULL initially. Add a routine update_history(<cmd issued>) or such that you call after every command you allow in your shell. It should:
(1) 1st call: malloc() space for the first command issued, and store the pointer to the
heap area in the array's first position
(2) Later calls: check the array for the first position with a NULL pointer, and store a pointer to the command there (using malloc() again). If you find no NULL pointer in the array (history is 10 commands long), go to (3)
(3) execute another new routine move_history(cmd issued). It moves the second array position (pointer) to the first, the 3rd to the 2nd, ..., the 10th to the 9th, and inserts a pointer to where <cmd_issued> is stored on the heap (using another malloc()) into the last array position. Don't forget to free() the heap memory that was allocated for the formerly first element that is no longer tracked.
You could then very easily print out the entire history (print through the array of pointers until you find a NULL pointer, but no more than 10 p/os; and print the command history numbers 1-10 (or 0-9) before the strings); and to print a particular command, you know in which array row the pointer to it is (if 1-based numbering, in row i-1). You can then read it and re-issue the command (don't forget to make that part of your history too).