C++ to mex file: output of system command gets suppressed - c++

I wrote a C++ code which I am converting to a mex file so that I can run from Matlab. My original C++ code displays output of some function declared in third party library. However, when I convert it into mex file, the output seems to be suppressed.
NOTE: output of following command get suppressed
int systemRet = std::system("./genb_test");
Original code:
#include <stdio.h> /* defines FILENAME_MAX */
#include <cstdlib>
#include <iostream>
#ifdef _MSC_VER
#include "direct.h"
#define GetCurrentDir _getcwd // window ??
#else
#include "unistd.h"
#define GetCurrentDir getcwd
#endif
int main()
{
const char *ParentFolder = "/home/dkumar/libtsnnls-2.3.3/tsnnls/";
int res3 = chdir(ParentFolder);
if (res3 == -1){
// The system method failed
std::cout<< "the chdir method has failed \n";
}
char cCurrentPath[FILENAME_MAX];
if (!GetCurrentDir(cCurrentPath, sizeof(cCurrentPath)))
{
printf("Could not find current directory " );
// return errno;
}
cCurrentPath[sizeof(cCurrentPath) - 1] = '\0'; /* not really required */
printf ("The current working directory is %s", cCurrentPath);
printf ("\n");
printf("Now running genb test " );
int systemRet = std::system("./genb_test");
if(systemRet == -1){
// The system method failed
}else{
printf("System command execuated successfully " );
}
return 0;
}
Output from original code:
The current working directory is /home/dkumar/libtsnnls-2.3.3/tsnnls
genb_tests
Creating 100 random test 121 x 89 problems using
the genb algorithm of PJV. Each problem will be given
to the tsnnls method, and the error printed below.
We require an error less than 1e-8 to pass the test.
# M N Error (PJV error) (Spiv error) Result
-----------------------------------------------------------------
1 121 89 1.375271e-15 1.375271e-15 0.000000e+00 pass
2 121 89 1.953126e-15 1.953126e-15 0.000000e+00 pass
3 121 89 4.272569e-15 4.272569e-15 0.000000e+00 pass
4 121 89 1.440234e-15 1.440234e-15 0.000000e+00 pass
5 121 89 2.392671e-15 2.392671e-15 0.000000e+00 pass
.......
.......
98 121 89 4.696796e-15 4.696796e-15 0.000000e+00 pass
99 121 89 1.820247e-15 1.820247e-15 0.000000e+00 pass
100 121 89 1.520109e-15 1.520109e-15 0.000000e+00 pass
100 (of 100) tests passed.
Now running genb test System command execuated successfully
Translated original code to mex file: various input and output (LHS) are left as it is, since I would start using that soon.
#include <matrix.h> // mex
#include <mex.h> // mex
#include <iostream> // Basic I/O
using namespace std; // Basic I/O
/* Definitions to keep compatibility with earlier versions of ML */
#ifndef MWSIZE_MAX
typedef int mwSize;
typedef int mwIndex;
typedef int mwSignedIndex;
#if (defined(_LP64) || defined(_WIN64)) && !defined(MX_COMPAT_32)
/* Currently 2^48 based on hardware limitations */
# define MWSIZE_MAX 281474976710655UL
# define MWINDEX_MAX 281474976710655UL
# define MWSINDEX_MAX 281474976710655L
# define MWSINDEX_MIN -281474976710655L
#else
# define MWSIZE_MAX 2147483647UL
# define MWINDEX_MAX 2147483647UL
# define MWSINDEX_MAX 2147483647L
# define MWSINDEX_MIN -2147483647L
#endif
#define MWSIZE_MIN 0UL
#define MWINDEX_MIN 0UL
#endif
// 'Hello World!' program
#include <stdio.h> /* defines FILENAME_MAX */
#include <cstdlib>
#include <iostream>
#ifdef _MSC_VER
#include "direct.h"
#define GetCurrentDir _getcwd // window ??
#else
#include "unistd.h"
#define GetCurrentDir getcwd
#endif
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
//const char *ParentFolder = "/home/dkumar/All_Matlab_Codes_DKU/";
const char *ParentFolder = "/home/dkumar/libtsnnls-2.3.3/tsnnls/";
//declare variables
mxArray *a_in_m, *b_in_m, *c_out_m, *d_out_m;
const mwSize *dims;
double *a, *b, *c, *d;
int dimx, dimy, numdims;
int i,j;
//associate inputs
a_in_m = mxDuplicateArray(prhs[0]);
b_in_m = mxDuplicateArray(prhs[1]);
//figure out dimensions
dims = mxGetDimensions(prhs[0]);
numdims = mxGetNumberOfDimensions(prhs[0]);
dimy = (int)dims[0]; dimx = (int)dims[1];
//associate outputs
c_out_m = plhs[0] = mxCreateDoubleMatrix(dimy,dimx,mxREAL);
d_out_m = plhs[1] = mxCreateDoubleMatrix(dimy,dimx,mxREAL);
//associate pointers
a = mxGetPr(a_in_m);
b = mxGetPr(b_in_m);
c = mxGetPr(c_out_m);
d = mxGetPr(d_out_m);
std::cout<< "Trying to change the directory "<< "\n";
// COPIED FROM ORIGINAL C++
int res3 = chdir(ParentFolder);
if (res3 == -1){
// The system method failed
std::cout<< "the chdir method has failed \n";
}
char cCurrentPath[FILENAME_MAX];
if (!GetCurrentDir(cCurrentPath, sizeof(cCurrentPath)))
{
printf("Could not find current directory " );
// return errno;
}
cCurrentPath[sizeof(cCurrentPath) - 1] = '\0'; /* not really required */
printf ("The current working directory is %s", cCurrentPath);
printf ("\n");
printf("Now running genb test " );
int systemRet = std::system("./genb_test");
if(systemRet == -1){
// The system method failed
}else{
printf("System command execuated successfully " );
}
// ADDED THIS PART at the suggestion of king_nak
//Capturing the output terminal
FILE * f = popen( "ls -al", "r" );
if ( f == 0 ) {
fprintf( stderr, "Could not execute\n" );
return;
}
const int BUFSIZE = 1000;
char buf[ BUFSIZE ];
while( fgets( buf, BUFSIZE, f ) ) {
fprintf( stdout, "%s", buf );
}
pclose( f );
return;
}
The output is:
>> [c d]=test_snnls_mex(a,b)
Trying to change the directory
The current working directory is /home/dkumar/libtsnnls-2.3.3/tsnnls
Now running genb test
c =
6 7 8
9 10 11
12 13 14
d =
1 4 9
16 25 36
49 64 81
Some help would be appreciated.
Regards,
Dushyant

std::system will start the system's command processor to execute the command. If you have a console app, this will print the output to the current console. This is why you see it in your test program. The output is not passed to the calling program!
In your case, Matlab seems to start the process in the background, where the output is discarded. Try instead opening the process and reading out its output into your program/MEX.
In POSIX, you can use popen (see for example this answer), in Windows you can use ReadPipe (cf. this article)
UPDATE
You have to adjust the code I have linked to. The original code calls ls -al and prints its output to the screen. You have to call your process genb_test!
Use this code to get the output in matlab, instead of your std::system call:
FILE * f = popen( "genb_test", "r" ); // <- call genb_test
if ( f == 0 ) {
fprintf( stderr, "Could not execute\n" );
return;
}
const int BUFSIZE = 1000;
char buf[ BUFSIZE ];
while( fgets( buf, BUFSIZE, f ) ) {
mexPrintf(buf); // <- use mexPrintf to print to matlab
}
pclose( f );

Have you tried the mex-command mexPrintf ?
However, the output won't be printed before the whole mex-program has been executed. Two work-arounds for this are to either use
mexEvalString("disp('Bla')")
or
mexPrintf("Bla")
mexEvalString("drawnow;");

Related

Convert C-Source image dump into original image

I have created with GIMP a C-Source image dump like the following:
/* GIMP RGBA C-Source image dump (example.c) */
static const struct {
guint width;
guint height;
guint bytes_per_pixel; /* 2:RGB16, 3:RGB, 4:RGBA */
guint8 pixel_data[304 * 98 * 2 + 1];
} example= {
304, 98, 2,
"\206\061\206\061..... }
Is there a way to read this in GIMP again in order to get back the original image? because it doesn't seem possible.
Or does it exist a tool that can do this back-conversion?
EDITED
Following some suggestion I tried to write a simple C programme to make the reverse coversion ending up with something very similar to another code found on internet but both dont work:
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "imgs_press.h"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
using namespace std;
int main(int argc, char** argv) {
int fd;
char *name = "orignal_img.pnm";
fd = open(name, O_WRONLY | O_CREAT, 0644);
if (fd == -1) {
perror("open failed");
exit(1);
}
if (dup2(fd, 1) == -1) {
perror("dup2 failed");
exit(1);
}
// file descriptor 1, i.e. stdout, now points to the file
// "helloworld" which is open for writing
// You can now use printf which writes specifically to stdout
printf("P2\n");
printf("%d %d\n", press_high.width, press_high.height);
for(int x=0; x<press_high.width * press_high.height * 2; x++) {
printf("%d ", press_high.pixel_data[x]);
}
}
As suggested by n-1-8e9-wheres-my-share-m, maybe I need to manipulate the pixels usign the correct decode, but I have no idea how to do that, does anybody have other suggestions?
The image I got is indeed distorted:
Updated Answer
If you want to decode the RGB565 and write a NetPBM format PNM file without using ImageMagick, you can do this:
#include <stdint.h> /* for uint8_t */
#include <stdio.h> /* for printf */
/* tell compiler what those GIMP types are */
typedef int guint;
typedef uint8_t guint8;
#include <YOURGIMPIMAGE>
int main(){
int w = gimp_image.width;
int h = gimp_image.height;
int i;
uint16_t* RGB565p = (uint16_t*)&(gimp_image.pixel_data);
/* Print P3 PNM header on stdout */
printf("P3\n%d %d\n255\n",w, h);
/* Print RGB pixels, ASCII, one RGB pixel per line */
for(i=0;i<w*h;i++){
uint16_t RGB565 = *RGB565p++;
uint8_t r = (RGB565 & 0xf800) >> 8;
uint8_t g = (RGB565 & 0x07e0) >> 3;
uint8_t b = (RGB565 & 0x001f) << 3;
printf("%d %d %d\n", r, g ,b);
}
}
Compile with:
clang example.c
And run with:
./a.out > result.pnm
I have not tested it too extensively beyond your sample image, so you may want to make a test image with some reds, greens, blues and shades of grey to ensure that all my bit-twiddling is correct.
Original Answer
The easiest way to get your image back would be... to let ImageMagick do it.
So, take your C file and add a main() to it that simply writes the 304x98x2 bytes starting at &(example.pixel_data) to stdout:
Compile it with something like:
clang example.c -o program # or with GCC
gcc example.c -o program
Then run it, writing to a file for ImageMagick with:
./program > image.bin
And tell ImageMagick its size, type and where it is and what you want as a result:
magick -size 304x98 RGB565:image.bin result.png
I did a quick, not-too-thorough test of the following code and it worked fine for an image I generated with GIMP. Note it doesn't handle alpha/transparency but that could be added if necessary. Save it as program.c:
#include <unistd.h> /* for write() */
#include <stdint.h> /* for uint8_t */
/* tell compiler what those GIMP types are */
typedef int guint;
typedef uint8_t guint8;
<PASTE YOUR GIMP FILE HERE>
int main(){
/* Work out how many bytes to write */
int nbytes = example.width * example.height * 2;
/* Write on stdout for redirection to a file - may need to reopen in binary mode if on Windows */
write(1, &(example.pixel_data), nbytes);
}
If I run this with the file you provided via Google Drive I get:

Too few arguments to function 'int fclose(FILE*)'

Hello I am a beginner of C language for microprocessors. I want to read a ''.bmp'' file in order to apply line detection on it. I have declared a function to read the image. This error occurs when compile button is pushed:
#include "esp_camera.h"
#include "Arduino.h"
#include "FS.h" // SD Card ESP32
#include "SD_MMC.h" // SD Card ESP32
#include "soc/soc.h" // Disable brownour problems
#include "soc/rtc_cntl_reg.h" // Disable brownour problems
#include "driver/rtc_io.h"
#include <EEPROM.h> // read and write from flash memory
#include <SPI.h>
void imageReader(const char *imgName,
int *height,
int *width,
int *bitdepth,
unsigned char *header,
unsigned char *_colortable,
unsigned char *buf
) // READ AN IMAGE
{
int i;
fs::FS &fs = SD_MMC; //
FILE *file;
file = fopen(imgName,"rb"); // read imgName file ( it is a picture in .bmp format )
if(!file){
Serial.printf("Unable to read image");
}
for(i=0 ; i<54 ; i++){
header[i]=getc(file);
}
*width = *(int * )& header[18]; // width information of the image
*height = *(int * )& header[22]; // height information of image
*bitdepth = *(int *)& header[28];
if(*bitdepth<=8){
fread(_colortable,sizeof(unsigned char),1024,file);
}
fread(buf,sizeof(unsigned char),( 1600 * 1200 ) ,file);
fclose();
}
It gives this error. too few arguments to function 'int fclose(FILE*)'
The fclose() function needs to know which file to close. You need to tell it that by supplying "file" as an argument. You want to use fclose(file).

clang: error: linker command failed with exit code 1 (use -v to see invocation) MINIX3

I am trying to run a C/C++ application on MINIX3 which is supposed to send a messages between two processes using msgsnd() and msgget() using msg.h.
This is the error I am getting:
send.cpp:(.text+0x7f): undefined reference to `msgget'
send.cpp:(.text+0x1c1): undefined reference to `msgsnd'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I am using clang++ to compile the code:
clang++ send.cpp -o send.out
This is the send.cpp code:
#include <lib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MSGSZ 128
/*
* Declare the message structure.
*/
typedef struct msgbufer {
long mtype;
char mtext[MSGSZ];
} message_buf;
int main()
{
int msqid;
int msgflg = IPC_CREAT | 0666;
key_t key;
message_buf sbuf;
size_t buf_length;
/*
* Get the message queue id for the
* "name" 1234, which was created by
* the server.
*/
key = 1234;
(void)fprintf(stderr, "\nmsgget: Calling msgget(%i,\
%#o)\n",
key, msgflg);
if ((msqid = msgget(key, msgflg)) < 0) {
perror("msgget");
exit(1);
}
else
(void)fprintf(stderr, "msgget: msgget succeeded: msqid = %d\n", msqid);
/*
* We'll send message type 1
*/
sbuf.mtype = 1;
(void)fprintf(stderr, "msgget: msgget succeeded: msqid = %d\n", msqid);
(void)strcpy(sbuf.mtext, "Hello other process 2.");
(void)fprintf(stderr, "msgget: msgget succeeded: msqid = %d\n", msqid);
buf_length = strlen(sbuf.mtext) + 1;
/*
* Send a message.
*/
if (msgsnd(msqid, &sbuf, buf_length, IPC_NOWAIT) < 0) {
printf("%d, %li, %s, %lu\n", msqid, sbuf.mtype, sbuf.mtext, buf_length);
perror("msgsnd");
exit(1);
}
else
printf("Message: \"%s\" Sent\n", sbuf.mtext);
exit(0);
}
You aren't linking with the library that contains the msgsnd and msgget functions, so your linker step fails. I'm not familiar with Minix so I'm not sure where the library is stored or what it is called. Basically, you need to a -l<msg> flag to your linking step. Where <msg> is the name of the library that contains the implementation.

Is it possible to set a gdb watchpoint programmatically?

I want to set a watchpoint (break on hardware write) temporarily in my C++ program to find memory corruption.
I've seen all the ways to do it manually through gdb, but I would like to actually set the watchpoint via some method in my code so I don't have to break into gdb, find out the address, set the watchpoint and then continue.
Something like:
#define SET_WATCHPOINT(addr) asm ("set break on hardware write %addr")
Set hardware watchpoint from child process.
#include <signal.h>
#include <syscall.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <linux/user.h>
enum {
DR7_BREAK_ON_EXEC = 0,
DR7_BREAK_ON_WRITE = 1,
DR7_BREAK_ON_RW = 3,
};
enum {
DR7_LEN_1 = 0,
DR7_LEN_2 = 1,
DR7_LEN_4 = 3,
};
typedef struct {
char l0:1;
char g0:1;
char l1:1;
char g1:1;
char l2:1;
char g2:1;
char l3:1;
char g3:1;
char le:1;
char ge:1;
char pad1:3;
char gd:1;
char pad2:2;
char rw0:2;
char len0:2;
char rw1:2;
char len1:2;
char rw2:2;
char len2:2;
char rw3:2;
char len3:2;
} dr7_t;
typedef void sighandler_t(int, siginfo_t*, void*);
int watchpoint(void* addr, sighandler_t handler)
{
pid_t child;
pid_t parent = getpid();
struct sigaction trap_action;
int child_stat = 0;
sigaction(SIGTRAP, NULL, &trap_action);
trap_action.sa_sigaction = handler;
trap_action.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER;
sigaction(SIGTRAP, &trap_action, NULL);
if ((child = fork()) == 0)
{
int retval = EXIT_SUCCESS;
dr7_t dr7 = {0};
dr7.l0 = 1;
dr7.rw0 = DR7_BREAK_ON_WRITE;
dr7.len0 = DR7_LEN_4;
if (ptrace(PTRACE_ATTACH, parent, NULL, NULL))
{
exit(EXIT_FAILURE);
}
sleep(1);
if (ptrace(PTRACE_POKEUSER, parent, offsetof(struct user, u_debugreg[0]), addr))
{
retval = EXIT_FAILURE;
}
if (ptrace(PTRACE_POKEUSER, parent, offsetof(struct user, u_debugreg[7]), dr7))
{
retval = EXIT_FAILURE;
}
if (ptrace(PTRACE_DETACH, parent, NULL, NULL))
{
retval = EXIT_FAILURE;
}
exit(retval);
}
waitpid(child, &child_stat, 0);
if (WEXITSTATUS(child_stat))
{
printf("child exit !0\n");
return 1;
}
return 0;
}
int var;
void trap(int sig, siginfo_t* info, void* context)
{
printf("new value: %d\n", var);
}
int main(int argc, char * argv[])
{
int i;
printf("init value: %d\n", var);
watchpoint(&var, trap);
for (i = 0; i < 100; i++) {
var++;
sleep(1);
}
return 0;
}
Based on user512106's great answer, I coded up a little "library" that someone might find useful:
It's on github at https://github.com/whh8b/hwbp_lib. I wish I could have commented directly on his answer, but I don't have enough rep yet.
Based on feedback from the community, I am going to copy/paste the relevant code here:
#include <stdio.h>
#include <stddef.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <sys/prctl.h>
#include <stdint.h>
#include <errno.h>
#include <stdbool.h>
extern int errno;
enum {
BREAK_EXEC = 0x0,
BREAK_WRITE = 0x1,
BREAK_READWRITE = 0x3,
};
enum {
BREAK_ONE = 0x0,
BREAK_TWO = 0x1,
BREAK_FOUR = 0x3,
BREAK_EIGHT = 0x2,
};
#define ENABLE_BREAKPOINT(x) (0x1<<(x*2))
#define ENABLE_BREAK_EXEC(x) (BREAK_EXEC<<(16+(x*4)))
#define ENABLE_BREAK_WRITE(x) (BREAK_WRITE<<(16+(x*4)))
#define ENABLE_BREAK_READWRITE(x) (BREAK_READWRITE<<(16+(x*4)))
/*
* This function fork()s a child that will use
* ptrace to set a hardware breakpoint for
* memory r/w at _addr_. When the breakpoint is
* hit, then _handler_ is invoked in a signal-
* handling context.
*/
bool install_breakpoint(void *addr, int bpno, void (*handler)(int)) {
pid_t child = 0;
uint32_t enable_breakpoint = ENABLE_BREAKPOINT(bpno);
uint32_t enable_breakwrite = ENABLE_BREAK_WRITE(bpno);
pid_t parent = getpid();
int child_status = 0;
if (!(child = fork()))
{
int parent_status = 0;
if (ptrace(PTRACE_ATTACH, parent, NULL, NULL))
_exit(1);
while (!WIFSTOPPED(parent_status))
waitpid(parent, &parent_status, 0);
/*
* set the breakpoint address.
*/
if (ptrace(PTRACE_POKEUSER,
parent,
offsetof(struct user, u_debugreg[bpno]),
addr))
_exit(1);
/*
* set parameters for when the breakpoint should be triggered.
*/
if (ptrace(PTRACE_POKEUSER,
parent,
offsetof(struct user, u_debugreg[7]),
enable_breakwrite | enable_breakpoint))
_exit(1);
if (ptrace(PTRACE_DETACH, parent, NULL, NULL))
_exit(1);
_exit(0);
}
waitpid(child, &child_status, 0);
signal(SIGTRAP, handler);
if (WIFEXITED(child_status) && !WEXITSTATUS(child_status))
return true;
return false;
}
/*
* This function will disable a breakpoint by
* invoking install_breakpoint is a 0x0 _addr_
* and no handler function. See comments above
* for implementation details.
*/
bool disable_breakpoint(int bpno)
{
return install_breakpoint(0x0, bpno, NULL);
}
/*
* Example of how to use this /library/.
*/
int handled = 0;
void handle(int s) {
handled = 1;
return;
}
int main(int argc, char **argv) {
int a = 0;
if (!install_breakpoint(&a, 0, handle))
printf("failed to set the breakpoint!\n");
a = 1;
printf("handled: %d\n", handled);
if (!disable_breakpoint(0))
printf("failed to disable the breakpoint!\n");
return 1;
}
I hope that this helps someone!
Will
In GDB, there are two types of watchpoints, hardware and software.
you can't implement easily software watchpoints: (cf. GDB Internals)
Software watchpoints are very slow, since gdb needs to single-step the program being debugged and test the value of the watched expression(s) after each instruction.
EDIT:
I'm still trying to understand what are hardware watchpoint.
for hardware breakpoints, this article gives some technics:
We want to watch reading from or writing into 1 qword at address 100005120h (address range 100005120h-100005127h)
lea rax, [100005120h]
mov dr0, rax
mov rax, dr7
and eax, not ((1111b shl 16) + 11b) ; mask off all
or eax, (1011b shl 16) + 1 ; prepare to set what we want
mov
dr7, rax ; set it finally
Done, now we can wait until code falls into the trap! After accessing any byte at memory range 100005120h-100005127h, int 1 will occur and DR6.B0 bit will be set to 1.
You can also take a look at GDB low-end files (eg, amd64-linux-nat.c) but it (certainly) involves 2 processes: 1/ the one you want to watch 2/a lightweight debugger who attaches to the first one with ptrace, and uses:
ptrace (PTRACE_POKEUSER, tid, __regnum__offset__, address);
to set and handle the watchpoint.
The program itself can supply commands to the GDB. You'll need a special shell script to run GDB though.
Copy this code into the file named untee, and execute chmod 755 untee
#!/bin/bash
if [ -z "$1" ]; then
echo "Usage: $0 PIPE | COMMAND"
echo "This script will read the input from both stdin and PIPE, and supply it to the COMMAND."
echo "If PIPE does not exist it will be created with mkfifo command."
exit 0
fi
PIPE="$1"
if [ \! -e "$PIPE" ]; then
mkfifo "$PIPE"
fi
if [ \! -p "$PIPE" ]; then
echo "File $PIPE does not exist or is not a named pipe" > /dev/stderr
exit 1
fi
# Open the pipe as a FD 3
echo "Waiting for $PIPE to be opened by another process" > /dev/stderr
exec 3<"$PIPE"
echo "$PIPE opened" > /dev/stderr
OPENED=true
while true; do
read -t 1 INPUT
RET=$?
if [ "$RET" = 0 ]; then
echo "$INPUT"
elif [ "$RET" -lt 128 ]; then
echo "stdin closed, exiting" > /dev/stderr
break
fi
if $OPENED; then
while read -t 1 -u 3 INPUT; do
RET=$?
if [ "$RET" = 0 ]; then
echo "$INPUT"
else
if [ "$RET" -lt 128 ]; then
echo "$PIPE closed, ignoring" > /dev/stderr
OPENED=false
fi
break
fi
done
fi
done
And now the C code:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <unistd.h>
void gdbCommand(const char *c)
{
static FILE * dbgpipe = NULL;
static const char * dbgpath = "/tmp/dbgpipe";
struct stat st;
if( !dbgpipe && stat(dbgpath, &st) == 0 && S_ISFIFO(st.st_mode) )
dbgpipe = fopen(dbgpath, "w");
if( !dbgpipe )
return;
fprintf(dbgpipe, "%s\n", c);
fflush(dbgpipe);
}
void gdbSetWatchpoint(const char *var)
{
char buf[256];
snprintf(buf, sizeof(buf), "watch %s", var);
gdbCommand("up"); /* Go up the stack from the kill() system call - this may vary by the OS, you may need to walk the stack more times */
gdbCommand("up"); /* Go up the stack from the gdbSetWatchpoint() function */
gdbCommand(buf);
gdbCommand("continue");
kill(getpid(), SIGINT); /* Make GDB pause our process and execute commands */
}
int subfunc(int *v)
{
*v += 5; /* GDB should pause after this line, and let you explore stack etc */
return v;
}
int func()
{
int i = 10;
printf("Adding GDB watch for var 'i'\n");
gdbSetWatchpoint("i");
subfunc(&i);
return i;
}
int func2()
{
int j = 20;
return j + func();
}
int main(int argc, char ** argv)
{
func();
func2();
return 0;
}
Copy that to the file named test.c, compile with command gcc test.c -O0 -g -o test then execute ./untee /tmp/dbgpipe | gdb -ex "run" ./test
This works on my 64-bit Ubuntu, with GDB 7.3 (older GDB versions might refuse to read commands from non-terminal)
If you happen to be using Xcode, you can achieve the required effect (automatic setting of watchpoints) by using an action on another breakpoint to set your watchpoint:
Set up a breakpoint somewhere where the variable you want to watch will be in scope that will be hit before you need to start watching the variable,
Right-click on the breakpoint and select Edit Breakpoint...,
Click on Add Action and add a Debugger Command with an LLDB command like: watchpoint set variable <variablename> (or if you're using GDB1, a command like: watch <variablename>),
Check the Automatically continue after evaluating actions checkbox.
1: GDB is no longer supported in more recent versions of Xcode, but I believe it is still possible to set it up manually.

C/C++ API to decode cron-style timings

Does anyone know of a library which will assist in decoding cron style timings, i.e.
30 7 * * 1-5
Which is 7:30am every Monday, Tuesday, Wednesday, Thursday, Friday.
M.
There is a library for PHP, Perl but I never saw one for C++.
The good thing is that Cron's source is freely available and you can reuse its code to parse entries in the cron format.
The entry data structure is defined in "cron.h" file:
typedef struct _entry {
struct _entry *next;
uid_t uid;
gid_t gid;
char **envp;
char *cmd;
bitstr_t bit_decl(minute, MINUTE_COUNT);
bitstr_t bit_decl(hour, HOUR_COUNT);
bitstr_t bit_decl(dom, DOM_COUNT);
bitstr_t bit_decl(month, MONTH_COUNT);
bitstr_t bit_decl(dow, DOW_COUNT);
int flags;
#define DOM_STAR 0x01
#define DOW_STAR 0x02
#define WHEN_REBOOT 0x04
#define MIN_STAR 0x08
#define HR_STAR 0x10
} entry;
And there are two functions you need from "entry.c" file (too large to post code here):
void free_entry (e);
entry *load_entry (file, error_func, pw, envp);
You can compile those files into a shared library or object files and use directly in your project.
This is an example of getting cron source code in Debian (Ubuntu):
apt-get source cron
You can also download it from http://cron.sourcearchive.com/
For those that wish to achieve the same goal as #ScaryAardvark
Dependency:
http://cron.sourcearchive.com/downloads/3.0pl1/cron_3.0pl1.orig.tar.gz
Build:
gcc -o main main.c cron-3.0pl1.orig/entry.c cron-3.0pl1.orig/env.c
cron-3.0pl1.orig/misc.c -I cron-3.0pl1.orig
Source:
#include <pwd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <uuid/uuid.h>
#define MAIN_PROGRAM 1
#include "cron-3.0pl1.orig/cron.h"
void error_handler( char* message )
{
fprintf( stderr, "Error: %s\n", message );
}
void print_entry( const entry* e )
{
fprintf( stdout, "uid: %i\n", e->uid );
fprintf( stdout, "gid: %i\n", e->gid );
fprintf( stdout, "command: %s\n", e->cmd);
//etc...
}
int main( int argc, char** argv, char** envp )
{
const char* filename = "crontab";
const char* username = "bcrowhurst";
//Retreive Crontab File
FILE *file = fopen( filename, "r" );
if ( file == NULL )
{
error_handler( strerror( errno ) );
return EXIT_FAILURE;
}
//Retreive Password Entry
struct passwd *pw = getpwnam( username );
if ( pw == NULL )
{
error_handler( strerror( errno ) );
return EXIT_FAILURE;
}
//Read Entry
entry *e = load_entry( file, &error_handler, pw, envp );
if ( e == NULL )
{
error_handler( "No entry found!" );
return EXIT_FAILURE;
}
print_entry( e );
//Clean-up
fclose( file );
free_entry( e );
return EXIT_SUCCESS;
}
Example Crontab
#yearly /home/bcrowhurst/annual-process
*/10 * * * * /home/bcrowhurst/fschk