Hacker News new | past | comments | ask | show | jobs | submit login
Reddit clone in 60 minutes and 4 lines of C (benreeves.co.uk)
49 points by codexon on Feb 5, 2010 | hide | past | favorite | 37 comments



OK, can we officially end the "_ in _ minutes and _ lines" meme now? While we're at it, let's close out the "check out my startup created in _ hours and $_".


Well, I think/hope that he was sort of making fun of the "in n lines of code" part by putting all his code, besides the imports, on 1 line. But yeah, I agree.


Exactly. You can tell a meme is exhausted when it becomes a parody of itself.


Only if you too end using words like "officially".


Touché.


It's kind of a bummer that people feel that these endeavors are worth satire. While the titles may be a bit pithy and perhaps misleading, these X in Y lines tend to be really interesting reading, and let you glimpse into someone else's domain expertise.

It's too bad they didn't just say 210 lines of C and still show it. I would have still checked it out, and been interested.


reproduced without permission: http://pastebin.com/m6a6fda19


Agree...after a long day of frameworks and VMs, I thought a ~210 line reddit+webserver was kinda neato.


Reddit in just a few minutes without writing any code: http://code.reddit.com/

duh.


Next would be a bit.ly link :)

Liked the joke :), what in all these "n lines" codes is missing is lot of things like - filtering (bad words), scaling, backup, etc.


What they're really missing is the community/customers. When you can clone that in 10 minutes, you've really got something.


Olin Shivers on 100% and 80% solutions - http://www.scsh.net/docu/post/sre.html


It just shows how polish is invisible but yet it is everything.


We've had a reddit clone in 100 lines of lisp, 91 lines of clojure, and 4 lines of C.

All we need now is for someone to do it in 1 line of Perl.


It's been done, of course, although it has to be a bit more due to comments (at least #!/usr/bin/perl).

http://gist.github.com/295032


Well, if you can do it in C, and I can see your solution, and it works, then I can do it in a line of perl. But I didn't test his code, so I don't know if this works:

    open( FILE, ">reddit.c"); print FILE '#include <stdio.h>'; print FILE "\n"; print FILE '#include <time.h>'; print FILE "\n"; print FILE '#include <netinet/in.h>';print FILE "\n";print FILE 'typedef struct { int ID; char * title; char * link; char * date; int upVotes; int downVotes; void * next; } Article; Article * root; char * getVal(char * query, char * key) { char * str = malloc(1); int match = 0; int pMatch = 0; char * cur = query; while (*cur != \'\0\') { if (pMatch >= 1 && (*cur == \'&\' || *cur == \'\n\' || *cur == \' \')) { break; } else if (pMatch >= 1) { str = realloc(str, pMatch+1); *(str+pMatch-1) = *cur; ++pMatch; } else if (match == strlen(key)) { pMatch = 1; } else if (*cur == key[match]) { ++match; } else { match = 0; } cur++; } if (pMatch >= 1) { str[pMatch-1] = \'\0\'; return str; } free(str); return NULL; } char from_hex(char ch) { return isdigit(ch) ? ch - \'0\' : tolower(ch) - \'a\' + 10; } char to_hex(char code) { static char hex[] = "0123456789abcdef"; return hex[code & 15]; } char *url_decode(char *str) { char *pstr = str, *buf = malloc(strlen(str) + 1), *pbuf = buf; while (*pstr) { if (*pstr == \'%\') { if (pstr[1] && pstr[2]) { *pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]); pstr += 2; } } else if (*pstr == \'+\') { *pbuf++ = \' \'; } else { *pbuf++ = *pstr; } pstr++; } *pbuf = \'\0\'; return buf; } void send_headers(FILE *f, int status, char *title, char *extra, char *mime, int length) { char timebuf[128]; fprintf(f, "%s %d %s\r\n", "HTTP/1.0", status, title); fprintf(f, "Server: %s\r\n", "redditserver/1.0"); if (extra) fprintf(f, "%s\r\n", extra); if (mime) fprintf(f, "Content-Type: %s\r\n", mime); if (length >= 0) fprintf(f, "Content-Length: %d\r\n", length); fprintf(f, "Connection: close\r\n"); fprintf(f, "\r\n"); } void reddit(FILE *f) { fprintf(f, "<HTML><HEAD><TITLE>Reddit Clone</TITLE></HEAD>\r\n"); fprintf(f, "<BODY><H1>Submit</H1><form action=\"/\" method=\"get\">Title:<input type=\"text\" name=\"title\" /> Link:<input type=\"text\" name=\"link\" /><input type=\"submit\" value=\"Submit\" /></form>\r\n"); if (root) { fprintf(f, "<h1>Articles</h1>"); Article * cur = root; while (cur != NULL) { fprintf(f, "<p><font size=\"5\">%d<b><a href=\"/?up=%d\">&uarr</b></font><a href=\"%s\">%s</a><br /><font size=\"5\">&nbsp;&nbsp;<b><a href=\"/?down=%d\">&darr</a></b></font>%s -- %s</p>", cur->upVotes - cur->downVotes, cur->ID, cur->link, cur->title, cur->ID, cur->link, cur->date); cur = cur->next; } }fprintf(f, "</BODY></HTML>\r\n"); } int fsize(FILE * f) { fseek(f, 0, SEEK_END); int size = ftell(f); fseek(f, 0, SEEK_SET); return size; } int main(int argc, char *argv[]) { int sock; int port = 1337; struct sockaddr_in sin; sock = socket(AF_INET, SOCK_STREAM, 0); sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = htons(port); while (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) { printf("Failed bind\n"); sleep(2); } listen(sock, 5); printf("HTTP server listening on port %d\n", port); root = NULL; while (1) { int s; int size; int hsize; char * buff; FILE * t; FILE * ht; FILE * f; s = accept(sock, NULL, NULL); if (s < 0) break; char * header = calloc(255, 1); size = read(s, header, 255); char * titleEnc = getVal(header, "title"); char * linkEnc = getVal(header, "link"); if (titleEnc && linkEnc) { char * title = url_decode(titleEnc); char * link =  url_decode(linkEnc); free(linkEnc); free(titleEnc); printf("Title: %s -- Link: %s\n", title, link); char  * s = malloc(30); size_t i; struct tm tim; time_t now; now = time(NULL); tim = *(localtime(&now)); i = strftime(s,30,"%b %d, %Y; %H:%M:%S\n",&tim); Article * new = malloc(sizeof(Article)); new->title = title; new->link = link; new->next = NULL; new->date = s; new->upVotes = 0; new->downVotes = 0; if (!root) { root = new; new->ID = 0; } else { int dupe = 0; Article * cur = root; Article * prev = NULL; while (cur != NULL) { if (strcmp(cur->title, new->title) == 0 || strcmp(cur->link, new->link) == 0) { dupe = 1; } prev = cur; cur = cur->next; } if (dupe == 0) { new->ID = prev->ID + 1; prev->next = new; } else free(new); } } char * upID = getVal(header, "up"); if (upID) { int ID = atoi(upID); Article * cur = root; while (cur != NULL) { if (cur->ID == ID) { cur->upVotes++; break; } cur = cur->next; } } char * dID = getVal(header, "down"); if (dID) { int ID = atoi(dID); Article * cur = root;  while (cur != NULL) { if (cur->ID == ID) { cur->downVotes++; break; } cur = cur->next; } } t = tmpfile(); ht = tmpfile(); reddit(t); size = fsize(t); send_headers(ht, 200, "Ok", NULL, "text/html", size); hsize = fsize(ht); buff = malloc(hsize); fread(buff, 1, hsize, ht); write(s,buff,hsize); free(buff); buff = malloc(size); fread(buff, 1, size, t); write(s,buff,size); free(buff); fclose(t); } }';print FILE "\n";`gcc ./reddit.c -o reddit && chmod a+x reddit && ./reddit`;


This is really 200 lines but still pretty cool.


$ astyle reddit.c $ wc -l reddit.c 211


To add to the fun, I present to you the BASH version in 1 line and 14 seconds:

  $ time git clone http://code.reddit.com/repo/reddit.git
Initialized empty Git repository in reddit/.git/

real 0m14.316s

user 0m0.496s

sys 0m0.411s


I don't think clone means what you think it means.

new user creation is broken. new subreddit creation is broken. comments are broken. popular/new/controversial/saved is missing.

search is good though. rimshot


Lisp's unreadable code compression features are obviously superior, and have been since the fifties.

We lispers can express any program in a single line. Some prefer that style because it brings out all the parentheses.

All of this is possible because code is data.


Or because you don't need #include statements separated with newlines in Lisp.


Exactly like Reddit except for the user accounts, markup editor or any other major feature.

Cute though.


Removing all the linefeeds is cheating. Show me one written with only 4 semicolons.


I think that point was to parody all these "X programmed in Y lines of code, but without all the 'hard' stuff like load-balancing, replication, optimized SQL queries that allow it to scale, etc; that's all too 'hard' so I'll do just the easy stuff and then claim that my final product is exactly the same as X"


"Show me one written with only 4 semicolons."

Naah, then you'd say that defining a macro for a semicolon is cheating :)


I understand that this is satire, but I'd like to see the same one-upmanship going on with tokens instead of lines.


Segfaulted on OS X, but looks genuine. Clever bit of work there.


I'm not sure why I don't just quit while I'm behind, but what version of OSX and gcc did you build it with? I can't get it even to compile (10.5.8, gcc version 4.0.1).


Stock 10.6.2 with stock dev tools.. showing GCC 4.2.1.


Is this satire? If not: You know, not that it would mean much anyway but it really doesn't count if you just delete all of the line breaks 'cause you're using a language that doesn't require them.


Is this satire?

I think that's pretty much a given.


on proggit there has been a recent fad to reimplement reddit in X lines of Y in Z minutes where X and Z are minimized and it has devolved into a satire, yes.


4 lines of C in 60 min? He must need to learn how to type.


Alternately, you must need to learn how to RTFA.


Not really, it was more a poor attempt at humor.


The new meme/trend.

"X clone in x minutes and x lines of x."

Bravo on your new "startup".




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: