Programmer Competency Matrix
Here's a fun page I came across for gauging the skill level of a programmer: Programmer Competency Matrix
Feels good to be a strong Level 3 in systems programming, algorithms and data structures. Where do you stand?
Here's a fun page I came across for gauging the skill level of a programmer: Programmer Competency Matrix
Feels good to be a strong Level 3 in systems programming, algorithms and data structures. Where do you stand?
Here's some C code for how to do this on Linux... mostly posting it for my own reference. I've commented the code extensively. (compile with -std=c99 or -std=gnu99 if using GCC)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#define BUFSIZE 256
void child_process(int pipe_pair[2]){
// closes the child's STDOUT descriptor and replaces it with
// the write pipe linked to the parent's read pipe
if (dup2(pipe_pair[1], STDOUT_FILENO) == -1){
// if dup2 fails, perror writes to stderr so this reports
// appropriately either way as the child and parent share stderr
perror("dup2");
// parent will know if the child failed since we return 1
// (ideally return errno so that calling processes know the error code)
exit(EXIT_FAILURE);
}
// duplicated by dup2 above, no longer needed
close(pipe_pair[1]);
// close read end as we will never read from stdout
close(pipe_pair[0]);
// printf writes to stdout by default
// we could also use fprintf(stdout, ...)
printf("Hello, parent!\n");
// make sure the write buffer is flushed before we exit
fflush(stdout);
// close to make sure read() returns 0 in the parent
close(STDOUT_FILENO);
// child exits
exit(EXIT_SUCCESS);
}
void parent_process(int pipe_pair[2], pid_t cpid){
// cstatus will store the return of the child process
// buf will hold the child's writes to stdout --
// {0} initializes the array elements to 0x00
int cstatus;
char buf[BUFSIZE] = {0};
close(pipe_pair[1]); // we won't write to stdout
// read until closed, or error (0 or -1, respectively)
for (int n = 0; (n = read(pipe_pair[0], buf, BUFSIZE)) > 0;){
printf("Received %d bytes from child process: ", n);
// (needed otherwise write() may output before
// printf since stdio output to stdout is line buffered)
fflush(stdout);
// writes just what we read so no need to reset buf
write(STDOUT_FILENO, buf, n);
printf("\n");
fflush(stdout);
}
// close read pipe
close(pipe_pair[0]);
// waits for child process with pid 'cpid' to
// return and stores the exit code in cstatus
waitpid(cpid, &cstatus, 0);
printf("Child exit status was: %d\n", cstatus);
// terminate parent
exit(EXIT_SUCCESS);
}
int main(int argc, char **argv){
// cpid stores the process id of the child process
// stdout_pipe array = pipe descriptor pair --
// [0] is the read end, [1] is the write end
pid_t cpid;
int stdout_pipe[2];
// call that creates the two unidirectional pipe streams
// and stores the descriptors in the array
if (pipe(stdout_pipe) == -1){
perror("pipe");
exit(EXIT_FAILURE);
}
// fork happens here, cpid will have the child's
// process id or -1 if the call fails
cpid = fork();
if (cpid == -1){
perror("fork");
exit(EXIT_FAILURE);
}
// child (fork returns 0 in the child and the child ID for the parent)
if (cpid == 0)
child_process(stdout_pipe);
// else when cpid is not 0 or -1 we're in the parent
else
parent_process(stdout_pipe, cpid);
// we shouldn't get here, but return int from main for correctness
return 0;
}
This is a cheap and easy way to do interprocess communication, but also useful if you have code that outputs to stdout / takes from stdin and you want to integrate it into your program without rewriting all the output code to use a different write mechanism, or you just don't want to maintain two separate codebases. Simply fork the process and replace STDIN/STDOUT/STDERR in the child before executing the code you need to execute.
In case you ever want to get a raw HTTP request for logging, analysis or filtering reasons, the code is simply:
function http_raw_request(){
$http_request = "";
foreach (getallheaders() as $key => $value){
$http_request .= $key . ': ' . $value . "\n";
}
$http_request .= "\n";
$http_request .= file_get_contents("php://input");
return $http_request;
}
If, like me, you use php-fastcgi and lack the function getallheaders, it can be implemented as followslink:
if (!function_exists('getallheaders')){
function getallheaders(){
$headers = '';
foreach ($_SERVER as $name => $value){
if (substr($name, 0, 5) == 'HTTP_'){
$headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
}
}
return $headers;
}
}
Example capture on a comment for this blog:
Host: heapspray.net + User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0.1+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 + Accept-Language: en-us,en;q=0.5 + Accept-Encoding: gzip, deflate + Connection: keep-alive + Referer: http://heapspray.net/post/added-comments/ + Content-Type: application/x-www-form-urlencoded + Content-Length: 38 + + id=46&poster=test&email=test&text=test
Very useful for anything from site statistics to debugging and filtering spam (most spambots have very different request headers than most browsers).