Wednesday, April 30, 2008

Syntax

This link has a bunch of different pages on syntax for different languages, going all of the way back to BCPL and Fortran. Unfortunately, some of the pages are nearly empty, and not due to the lack of syntax.

fibo.hs

My first Haskell program! The recursive functions and induction from CSE321 inspired me to write a simple Fibonacci sequence generator:

fibo.hs

import System.Environment

-- The almighty Fibonacci generator!
fibo :: Integer -> Integer
fibo 0 = 1
fibo 1 = 1
fibo n | n > 1 = fibo(n - 2) + fibo(n - 1)


-- Generates a list of the appropriate numbers
fibosequence :: Integer -> [Integer]
fibosequence 0 = [1]
fibosequence n | n > 0 = fibosequence(n - 1) ++ [fibo(n)]


str2int :: String -> Integer
str2int = read


-- For generating a single number per argument
fibolist :: [String] -> String
fibolist [] = ""
fibolist (x:xs) = x ++ ": " ++ show(fibo(str2int(x))) ++ "\n" ++ fibolist(xs)


-- For generating a list per argument
fiboslist :: [String] -> String
fiboslist [] = ""
fiboslist (x:xs) = x ++ ": " ++ show(fibosequence(str2int(x))) ++ "\n" ++ fiboslist(xs)




main = do x <- getArgs
putStr(fiboslist(x))
% ./fibo 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0: [1]
1: [1,1]
2: [1,1,2]
3: [1,1,2,3]
4: [1,1,2,3,5]
5: [1,1,2,3,5,8]
6: [1,1,2,3,5,8,13]
7: [1,1,2,3,5,8,13,21]
8: [1,1,2,3,5,8,13,21,34]
9: [1,1,2,3,5,8,13,21,34,55]
10: [1,1,2,3,5,8,13,21,34,55,89]
11: [1,1,2,3,5,8,13,21,34,55,89,144]
12: [1,1,2,3,5,8,13,21,34,55,89,144,233]
13: [1,1,2,3,5,8,13,21,34,55,89,144,233,377]
14: [1,1,2,3,5,8,13,21,34,55,89,144,233,377,610]
15: [1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987]

Tuesday, April 29, 2008

二隻の舟 - 中島みゆき

二隻の舟 (Nisou no fune, "Two Ships") came to me in an interesting way: on two different albums with slightly different mixes for this song. The later one is much more piano-intensive, yet the earlier one is a lot more mellow. I thought they were the same, until I listened to them more carefully today. Even more interesting is that the first song continues into another (糸: ito, "Thread") that I already knew.

時は 全てを連れてゆくものらしい
なのに どうして 寂しさを置き忘れてゆくの
いくつになれば 人懐かしさを
うまく捨てられるようになるの

難しいこと望んじゃいない
有り得ないこと望んじゃいない

時よ 最後に残してくれるなら
寂しさの分だけ 愚かさをください

おまえとわたしは たとえば二隻の舟
暗い海を渡ってゆく ひとつひとつの舟
互いの姿は波に隔てられても
同じ歌を歌いながらゆく 二隻の舟

時流を泳ぐ海鳥たちは
むごい摂理をささやくばかり
いつかちぎれる絆 見たさに
高く高く高く

敢えなくわたしが 波に砕ける日には
どこかでおまえの舟が かすかにきしむだろう
それだけのことで わたしは海をゆけるよ
たとえ舫い網は切れて 嵐に飲まれても
きこえてくるよ どんな時も

おまえの悲鳴が 胸にきこえてくるよ
越えてゆけ と叫ぶ声が ゆくてを照らすよ

おまえの悲鳴が 胸にきこえてくるよ
越えてゆけ と叫ぶ声が ゆくてを照らす

難しいこと望んじゃいない
有り得ないこと望んじゃいないのに

風は強く波は高く 闇は深く 星も見えない
風は強く波は高く 暗い海は果てるともなく
風の中で波の中で たかが愛は 木の葉のように

わたしたちは二隻の舟 ひとつずつの そしてひとつの
わたしたちは二隻の舟 ひとつずつの そしてひとつの
わたしたちは二隻の舟

Monday, April 28, 2008

jdic.bz2

I've decided to be nice, and am providing a database dump for the PostgreSQL search scripts for the EDICT. Here it is: jdic.bz2

What's interesting is that it's only a little bit larger than the edict.gz file from which it is generated.

Sunday, April 27, 2008

nlaunch3.1

Here's another release of nlaunch: nlaunch3.1-20080427.tar.bz2

I'm wondering if I should create a page specifically for this purpose, but then I realize nobody would even bother to look. At least someone looks at this blog every now and then.

Saturday, April 26, 2008

Linuxfest Northwest!

Icy Tux

I just got back from LinuxFest Northwest today, and boy was it a blast. I took the Pogo Express (this year an articulated Gray Lines bus) to BTC, and even the bus ride was a lot of fun. I've never found myself so social. I attended talks on networking protocols, natural language processing, and Jabber. For the last session, I even got to explore the OLPC XO-1 with friends, using its mesh networking features.

Icy Tux

While there, I also picked up large amounts of mainly free things, but a few things that cost money. For $30, I also bought this at a used parts section of the meet, and it looks like it turns on, but I can't do much with this until I get the proper adapters.

I can say I had fun, and I can't wait until next year.

Dominic Deegan and lolcats

It looks like Dominic Deegan: Oracle for Hire, one of the first webcomics I've ever read (and am still reading), has gotten into the lolcat spirit. The third panel here shows it all. That one gave me a big laugh, too.

Friday, April 25, 2008

夢のダンス - aiko

夢のダンス (yume no dansu, "Dream Dance") is the last of aiko's very jazzy songs, at least until I get her new album (it's been ordered and should get here in two weeks at most). Like 17の月, this song is more relaxed, but is so in a different way.

今日は風がとても良いから 窓を開けて熱を逃す
いつからかな?どうしてかな?解らない
上を向く事忘れたあたし

日々共に息を吸うのはあなたと決まっている気がしてた
どの道何があっても諦める気もさらさらなかったし

※そばにいたいのに 強く手を握ってたいのに
あなたは近くて遠い人 悔しかった
初めて感じたこの気持ち 胸がつぶれそう※

風邪を引いたりしてませんか?
つまらぬ事で痛みを持ち 大きな溜め息をついていませんか?
そんな事すら知らないあたし
—あなたはあたしの一番星よ—
不意に涙出る位
両手差し出しても溢れる程の幸せと夢をくれた

照らす宵の月 湿った心を乾かす
あなたとダンスをもう一度 永久に歌った
陰る事のないこの気持ち胸はつぶれそう

(※くり返し)

明日もいつも通りに - aiko

I consider 明日もいつも通りに (ashita mo itsumo toori ni, "Tomorrow as Always" (or something close to that)) to be the counterpart to 17の月, as they are both slow, jazzy songs that are in 6/8 time. However, this song is a little more powerful, and shows off more of aiko's jazzy tendencies.

I tend to enjoy the other song more due to its more peaceful demeanor, but this one is also good.

部屋の灯りも 匂いも何もかもいつも通り
あたしの髪が伸びた位…
今日は天気が悪いけど明日は解らないけど
ここに来てやっと解った事…

あたしの声はあなたには届かない
悪口叫んだとしても もう聞こえない

だけど一生想うだろう本当は大好きなの
キスする感覚を忘れても
指の間絡ませて繋いでたこの手が
大人な握手に変わっても

謝らないで そんな事言うのならばいっそ
受話器のままでさようなら…

出の悪い水道直し方も解らない
今は些細な事すらも軽く拭えない

時が経って知ったでしょ?何気なく過ぎてゆく
毎日に生まれてた愛情が
「つまんない」と呟いた白く煙る日々でも
心の隅っこで生きてた事

だけど一生想うだろう本当は大好きなの
キスする感覚を忘れても
指の間絡ませて繋いでたこの手が
大人な握手に変わっても

時が経って知ったでしょ?何気なく過ぎてゆく
毎日に生まれてた愛情が
「つまんない」と呟いた白く煙る日々でも
心の隅っこで生きてた事

Wednesday, April 23, 2008

fpath

Being bored as I often am, I wrote this small C program. It functions almost identically to the Perl findpath script I wrote before, but is much lighter:

fpath.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>


typedef struct {
int splitlen;
char ** split;
char * merged;
} splitstore;
splitstore * splitchr(const char split, const char * str);
void splitstore_delete(splitstore * del);
splitstore * splitstr(const char * split, const char * str);
int execpermissions(uid_t uid, gid_t gid, const struct stat * info) {
return S_IXOTH & info->st_mode || (info->st_gid == gid && S_IXGRP & info->st_mode) || (info->st_uid == uid && S_IXUSR & info->st_mode);
}

int main(int argc, char ** argv) {
const char * path = getenv("PATH");
char * current;
DIR * dirinfo;
char * term = NULL;
struct dirent * file;
struct stat info;
int i;
const char help[1024];
sprintf(help, "Usage: %s exname\n", argv[0]);
if(argc < 2) {
fputs(help, stderr);
return 2;
}
term = argv[1];

uid_t uid = getuid();
gid_t gid = getegid();
splitstore * splitpath = splitchr(':', path);
if(!splitpath)
return 1;
for(i = 0; i < splitpath->splitlen; i++) {
current = splitpath->split[i];
if(!stat(current, &info)) {
if(S_ISDIR(info.st_mode)) {
chdir(current);
dirinfo = opendir(current);
while((file = readdir(dirinfo)) != NULL) {
if(!stat(file->d_name, &info) && S_ISREG(info.st_mode) && execpermissions(uid, gid, &info) && strstr(file->d_name, term))
printf("%s/%s\n", current, file->d_name);
}
closedir(dirinfo);
}
else {
fprintf(stderr, "Not a directory: %s\n", current);
}
}
else
fprintf(stderr, "Unable to stat: %s\n", current);
}
splitstore_delete(splitpath);
return 0;
}

splitstore * splitchr(const char split, const char * str) {
if(!str)
return NULL;
splitstore * ret = (splitstore *) malloc(sizeof(splitstore));
if(!ret)
return NULL;
ret->splitlen = 0;
int len = strlen(str);
char * c = NULL, * start;
ret->merged = (char *) malloc(len + 1);
strcpy(ret->merged, str);
ret->split = NULL;
if(!ret->merged) {
free(ret);
return NULL;
}
ret->split = (char **) malloc(sizeof(char *));
ret->split[ret->splitlen++] = ret->merged;
if(!ret->split) {
free(ret->merged);
free(ret);
return NULL;
}
start = ret->merged;
while((c = strchr(start, split)) != NULL) {
*c = '\0';
ret->split = (char **) realloc(ret->split, sizeof(char *) * (ret->splitlen + 1));
if(!ret->split) {
free(ret->merged);
free(ret);
return NULL;
}
ret->split[ret->splitlen++] = ++c;
start = c;
}
return ret;
}
splitstore * splitstr(const char * split, const char * str) {
if(!str)
return NULL;
splitstore * ret = (splitstore *) malloc(sizeof(splitstore));
if(!ret)
return NULL;
ret->splitlen = 0;
int len = strlen(str);
int slen = strlen(split);
char * c = NULL, * start;
ret->merged = (char *) malloc(len + 1);
strcpy(ret->merged, str);
ret->split = NULL;
if(!ret->merged) {
free(ret);
return NULL;
}
ret->split = (char **) malloc(sizeof(char *));
ret->split[ret->splitlen++] = ret->merged;
if(!ret->split) {
free(ret->merged);
free(ret);
return NULL;
}
start = ret->merged;
while((c = strstr(start, split)) != NULL) {
*c = '\0';
ret->split = (char **) realloc(ret->split, sizeof(char *) * (ret->splitlen + 1));
if(!ret->split) {
free(ret->merged);
free(ret);
return NULL;
}
c += slen;
ret->split[ret->splitlen++] = c;
start = c;
}
return ret;
}
void splitstore_delete(splitstore * del) {
if(del) {
if(del->split)
free(del->split);
if(del->merged)
free(del->merged);
free(del);
}
}

Tuesday, April 22, 2008

Seattle Transit Blog: ST Light Rail Testing

It looks like the Sound Transit Central Link is starting more comprehensive tests of its vehicles. The photos here are pretty good, too.

17の月 - aiko

This (17の月: juunana no tsuki, "Seventeen Moons") is among my favorite jazzy songs; I usually listen to it when I want to relax.

もうあたしに力が残ってない
傷付いたまま癒す事もない
お願い今日はこのまま寝かせて

あなたの丸い爪に射して跳ね返すオレンジの色

帰りたくなかった寄り道をして
迷ってしまえと本当は祈ってた
長い道路の白い線が消えるまで止まらないでと

逢えば逢う程恋は募るもの
あたしおかしくなってしまったの
2度と言わないと決めた事なのに
我慢出来ないあたしを許して

言葉にすると軽くなりそうだけど何度も言うわ「好きよ」

いつも夢見ていたあなたの傍で
声出して髪を結び手を繋ぐ
同じルールの白い線の上向かい合ってキスを

あなたはあたしよりうんと背が高いから
この道もきっと見晴らしがいいのだろう
あなたの丸い爪に射して跳ね返すオレンジの色

帰りたくなかった寄り道をして
迷ってしまえと本当は祈ってた
長い道路の白い線が消えるまで止まらないでと
消えるまで止まらないでと…

Monday, April 21, 2008

nlaunch3 Revision

I've made a few minor changes to nlaunch3, including a $HOME/.nlaunch3/nlaunchconfig.py specific to the user. The first configurable part is the method by which the executables are chosen. By default, it follows the old method ('old_style'), but it can also do by path ('full_path') or by the executable's basename ('basename'). The new styles worry me a bit, so they won't be default: nlaunch3-20080421b.tar.bz2

nlaunchconfig.py

select_command = 'full_path'

This one enables the new full path matching.

Fighting GCC 4.3

Well, my new system is mostly up. However, a few libraries won't build cleanly with GCC 4.3, and 4.2.3 has a tendency to segfault when compiling complex things, such as Boost:

MkDir1 bin.v2/libs/wave/build/gcc-4.2/release/debug-symbols-none/link-static/optimization-none/runtime-link-static/threading-multi
gcc.compile.c++ bin.v2/libs/wave/build/gcc-4.2/release/debug-symbols-none/link-static/optimization-none/runtime-link-static/threading-multi/instantiate_cpp_exprgrammar.o
gcc.compile.c++ bin.v2/libs/wave/build/gcc-4.2/release/debug-symbols-none/link-static/optimization-none/runtime-link-static/threading-multi/instantiate_cpp_grammar.o
gcc.compile.c++ bin.v2/libs/wave/build/gcc-4.2/release/debug-symbols-none/link-static/optimization-none/runtime-link-static/threading-multi/instantiate_cpp_literalgrs.o
gcc.compile.c++ bin.v2/libs/wave/build/gcc-4.2/release/debug-symbols-none/link-static/optimization-none/runtime-link-static/threading-multi/instantiate_defined_grammar.o
gcc.compile.c++ bin.v2/libs/wave/build/gcc-4.2/release/debug-symbols-none/link-static/optimization-none/runtime-link-static/threading-multi/instantiate_predef_macros.o
./boost/graph/detail/read_graphviz_spirit.hpp: In constructor 'boost::detail::graph::dot_grammar::definition<ScannerT>::definition(const boost::detail::graph::dot_grammar&) [with ScannerT = boost::spirit::scanner<boost::spirit::multi_pass<std::istream_iterator<char, char, std::char_traits<char>, long int>, boost::spirit::multi_pass_policies::input_iterator, boost::spirit::multi_pass_policies::ref_counted, boost::spirit::multi_pass_policies::buf_id_check, boost::spirit::multi_pass_policies::std_deque>, boost::spirit::scanner_policies<boost::spirit::skip_parser_iteration_policy<boost::detail::graph::dot_skipper, boost::spirit::iteration_policy>, boost::spirit::match_policy, boost::spirit::action_policy> >]':
./boost/graph/detail/read_graphviz_spirit.hpp:141: internal compiler error: Segmentation fault
Please submit a full bug report,
with preprocessed source if appropriate.
See <URL:http://bugs.gentoo.org/> for instructions.
./boost/graph/detail/read_graphviz_spirit.hpp: In constructor 'boost::detail::graph::dot_grammar::definition<ScannerT>::definition(const boost::detail::graph::dot_grammar&) [with ScannerT = boost::spirit::scanner<boost::spirit::multi_pass<std::istream_iterator<char, char, std::char_traits<char>, long int>, boost::spirit::multi_pass_policies::input_iterator, boost::spirit::multi_pass_policies::ref_counted, boost::spirit::multi_pass_policies::buf_id_check, boost::spirit::multi_pass_policies::std_deque>, boost::spirit::scanner_policies<boost::spirit::skip_parser_iteration_policy<boost::detail::graph::dot_skipper, boost::spirit::iteration_policy>, boost::spirit::match_policy, boost::spirit::action_policy> >]':
./boost/graph/detail/read_graphviz_spirit.hpp:263: internal compiler error: Segmentation fault
Please submit a full bug report,
with preprocessed source if appropriate.
See <URL:http://bugs.gentoo.org/> for instructions.

If this problem persists, I will submit a bug report; this sort of thing shouldn't happen. The current goal, though, is to get the system up and running.

EDIT: I've noticed that compiling GCC 4.2.3 causes the computer to either get stuck with no CPU time or hardlock. It happens when compiling with any GCC version, and makes it to where I can't SSH into the machine, or even use the VGA console. I wonder what could be causing that.

Sunday, April 20, 2008

nlaunch3!

Finally, nlaunch3 is here. However, I've decided to package them into a Tar archive and upload them, since most web browsers don't do well with tabs: nlaunch3.

I've made some usability improvements, but the major improvement is the ability to have a $HOME/.nlaunch/nlaunchuser.py script, like this:

nlaunchuser.py

#!/usr/bin/python
import functions
import os
class Wikipedia(functions.NLaunchFunction):
browser = 'firefox'
def __call__(self, *args):
return functions.forkexec(self.browser, 'http://en.wikipedia.org/wiki/Special:Search?search=' + '+'.join(args).replace(' ', '+') + '&go=Go')
class Kanji(functions.NLaunchFunction):
gs = os.path.join(os.environ['HOME'], 'Documents', 'kanji.ps')
viewer = 'kghostview'
def __call__(self, *args):
print str(self.gs)
return functions.forkexec(self.viewer, self.gs)
def Print(*args):
for i in args: print i,

To add something, one may either define a callable class (not an object), or create a function.

New PC Continued

As it turns out, the machine isn't overheating at all; it's staying below 40 C consistently. However, rebuilding GCC fixed the segfaults in the compiler, but the machine still hardlocks when faced with too much processing stress. Maybe this has to do with the infamous TLB bug present in the CPUs, but it's hard to say.

At the moment, I'm upgrading to GCC 4.3 on the machine, which has some Phenom-specific flags that can be used.

Saturday, April 19, 2008

New PC: Phenom

My father gave me a brand new computer today, with a Phenom 9500 in it. It's a great machine, and I'm very happy to receive it. The case is pretty cool, too: the entire front is a grille, even the covers to the drive bays.

Although I'm happy with it, things started to turn bad when I began compiling a Gentoo install. It seemed to run well at first, until I got to larger packages, such as Perl and Glibc. Packages began to fail with "internal compiler error: segmentation fault" and mentioning that these errors aren't reproducible, and that they're likely hardware issues (I've had experience like this before, with both overclocking and overheating, but this CPU isn't overclocked to my knowledge). I found out that these problems are reduced by setting the number of parallel Make jobs to one or two, but that increases build time. Hopefully I'll find out the problem if I can ever get a system running.

arglib

Satisfied with the result of PerlArg, I decided to rewrite it for use on my CSE303 homework and any other C applications I happen to write.

arglib.h

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>

typedef struct {
const char * key;
const char * value;
} hashnode;

typedef struct {
hashnode * Long, * LongSynoms, * ShortSynoms;
const char * help;
char ** Anonymous;
size_t LongLen, LongSynomsLen, ShortSynomsLen, AnonymousLen;
} argparser;

argparser * argparser_new(const char ** Long, const char ** LongSynoms, const char ** ShortSynoms, const char * help);
void argparser_delete(argparser * self);
const char * argparser_getValue(argparser * self, const char * key);
const char * argparser_getAnonymous(argparser * self, const int idx);
int argparser_getAnonymousLen(argparser * self);
int argparser_parseArgs(argparser * self, int argc, char ** argv);

arglib.c

#include "arglib.h"
/*
typedef struct {
const char * key;
const char * value;
} hashnode;

typedef struct {
hashnode * Long, * LongSynoms, * ShortSynoms;
const char * help;
char ** Anonymous;
size_t LongLen, LongSynomsLen, ShortSynomsLen, AnonymousLen;
} argparser;
*/

size_t argparser_getLength(const char ** src);
hashnode * argparser_allocateNodes(size_t len, const char ** src);
int strpcmp(char * str1, char * str2, const char * addr);
int fputs_until(FILE * fp, char * str, const char * end);

argparser * argparser_new(const char ** Long, const char ** LongSynoms, const char ** ShortSynoms, const char * help) {
argparser * self = malloc(sizeof(argparser));
const char * help_alloc[] = {"help", "Help", NULL};
if(!self) {
fputs("Error: Unable to allocate memory\n", stderr);
return NULL;
}
memset(self, '\0', sizeof(argparser));
self->LongLen = argparser_getLength(Long);
self->AnonymousLen = 0;
self->Long = NULL; self->LongSynoms = NULL; self->ShortSynoms = NULL; self->help = NULL; self->Anonymous = NULL;
if(LongSynoms)
self->LongSynomsLen = argparser_getLength(LongSynoms);
if(ShortSynoms)
self->ShortSynomsLen = argparser_getLength(ShortSynoms);
if(self->LongLen % 2 || self->LongSynomsLen % 2 || self->ShortSynomsLen % 2) {
fputs("Error: Non-even array provided.\n", stderr);
free(self);
return NULL;
}
self->LongLen /= 2; self->Long = argparser_allocateNodes(self->LongLen, Long);
if(LongSynoms) {
self->LongSynomsLen /= 2;
self->LongSynoms = argparser_allocateNodes(self->LongSynomsLen, LongSynoms);
if(!self->LongSynoms) {
fputs("Error: Unable to allocate memory\n", stderr);
free(self);
return NULL;
}
}
if(help) {
self->help = help;
if(!LongSynoms) {
self->LongSynoms = argparser_allocateNodes(self->LongSynomsLen, help_alloc);
}
else {
self->LongSynoms = (hashnode *)realloc(self->LongSynoms, (self->LongSynomsLen + 1) * sizeof(hashnode));
if(!self->LongSynoms) {
fputs("Error: Unable to allocate memory\n", stderr);
free(self);
return NULL;
}
self->LongSynoms[self->LongSynomsLen].key = help_alloc[0];
self->LongSynoms[self->LongSynomsLen++].value = help_alloc[1];
}
}
if(ShortSynoms) {
self->ShortSynomsLen /= 2;
self->ShortSynoms = argparser_allocateNodes(self->ShortSynomsLen, ShortSynoms);
if(!self->ShortSynoms) {
fputs("Error: Unable to allocate memory\n", stderr);
free(self);
return NULL;
}
}
if(help)
self->help = help;
self->AnonymousLen = 0;
return self;
}
void argparser_delete(argparser * self) {
if(self) {
if(self->Long)
free(self->Long);
if(self->LongSynoms)
free(self->LongSynoms);
if(self->ShortSynoms)
free(self->ShortSynoms);
free(self);
}
}
const char * argparser_getValue(argparser * self, const char * key) {
size_t i;
if(key && self && self->Long) {
for(i = 0; i < self->LongLen; i++)
if(!strcmp(key, self->Long[i].key))
return self->Long[i].value;
}
return NULL;
}
int argparser_parseArgs(argparser * self, int argc, char ** argv) {
int i, j, k;
bool opting = true, found, found2;
char * eq = NULL, * value = NULL;
char * nodashes = NULL;
if(self->Anonymous) {
self->AnonymousLen = 0;
free(self->Anonymous);
self->Anonymous = NULL;
}
for(i = 1; i < argc; i++) {
if(opting && !strcmp("--", argv[i])) // Disables arguments
opting = false;
else if(opting && strstr(argv[i], "--") == argv[i]) { // Gets --long and --long=value
nodashes = argv[i] + 2;
if((eq = strchr(nodashes, '=')) != NULL) { // Gets --long=value
found = false;
for(j = 0; !found && j < self->LongLen; j++) {
if(!strpcmp(nodashes, self->Long[j].key, eq)) {
self->Long[j].value = eq + 1;
found = true;
}
}
if(!found) {
fputs("Unknown argument: ", stderr); fputs_until(stderr, nodashes, eq); fputc('\n', stderr);
return -1;
}
}
else { // Gets --long
found = false;
for(j = 0; !found && j < self->LongSynomsLen; j++) {
if(!strcmp(nodashes, self->LongSynoms[j].key)) {
value = self->LongSynoms[j].value;
if((eq = strchr(value, '=')) != NULL) { // Handles longsynom: long=value
found2 = false;
for(k = 0; !found && k < self->LongLen; k++) {
if(!strpcmp(value, self->Long[k].key, eq)) {
self->Long[k].value = eq + 1;
found2 = true;
}
}
if(!found2) {
fprintf(stderr, "Unknown equivalent: %s\n", value);
return -2;
}
}
else if(self->help && !strcmp("Help", value)) {
fputs(self->help, stderr);
return -4;
}
else if(++i < argc) { // Handles longsynom: long
found2 = false;
for(k = 0; !found && k < self->LongLen; k++) {
if(!strcmp(value, self->Long[k].key)) {
self->Long[k].value = argv[i];
found2 = true;
}
}
if(!found2) {
fprintf(stderr, "Unknown equivalent: %s\n", value);
return -2;
}
}
else {
fprintf(stderr, "Needs a value: %s\n", nodashes);
return -2;
}
found = true;
}
}
if(!found) {
fprintf(stderr, "Unknown argument: %s\n", nodashes);
return -1;
}
}
}
else if(opting && strchr(argv[i], '-') == argv[i]) { // Gets -s
nodashes = argv[i] + 1;
while(*nodashes) {
found = false;
for(j = 0; !found && j < self->ShortSynomsLen; j++) {
if(*nodashes == self->ShortSynoms[j].key[0]) {
value = self->ShortSynoms[j].value;
if((eq = strchr(value, '=')) != NULL) { // Handles shortsynom: long=value
found2 = false;
for(k = 0; !found && k < self->LongLen; k++) {
if(!strpcmp(value, self->Long[k].key, eq)) {
self->Long[k].value = eq + 1;
found2 = true;
}
}
if(!found2) {
fprintf(stderr, "Unknown equivalent: %s\n", value);
return -2;
}
}
else if(*(nodashes + 1) == '\0' && ++i < argc) { // Handles shortsynom: long
found2 = false;
for(k = 0; !found && k < self->LongLen; k++) {
if(!strcmp(value, self->Long[k].key)) {
self->Long[k].value = argv[i];
found2 = true;
}
}
if(!found2) {
fprintf(stderr, "Unknown equivalent: %s\n", value);
return -2;
}
}
else {
fprintf(stderr, "Needs a value: %c\n", *nodashes);
return -2;
}
found = true;
}
}
if(!found) {
fprintf(stderr, "Unknown argument: %c\n", *nodashes);
return -1;
}
nodashes++;
}
}
else { // Gets everything else
self->Anonymous = (char **)realloc(self->Anonymous, (self->AnonymousLen + 1) * sizeof(char *));
if(!self->Anonymous) {
fputs("Error: Unable to allocate memory\n", stderr);
return -1;
}
self->Anonymous[self->AnonymousLen++] = argv[i];
}
}
return 0;
}


const char * argparser_getAnonymous(argparser * self, const int idx) {
if(!self || idx < 0 || idx >= self->AnonymousLen)
return NULL;
return self->Anonymous[idx];
}
int argparser_getAnonymousLen(argparser * self) {
return self->AnonymousLen;
}








// HELPER METHODS
size_t argparser_getLength(const char ** src) {
size_t i;
if(!src)
return 0;
for(i = 0; src[i]; i++);
return i;
}
hashnode * argparser_allocateNodes(size_t len, const char ** src) {
size_t i;
if(!src)
return NULL;
hashnode * ret = (hashnode*)calloc(len, sizeof(hashnode));
if(!ret)
return NULL;
for(i = 0; i < len; i++) {
ret[i].key = src[2 * i];
ret[i].value = src[2 * i + 1];
}
return ret;
}
int strpcmp(char * str1, char * str2, const char * addr) {
while(str1 != addr && str2 != addr) {
if(*str1 > *str2)
return 1;
else if(*str1 < *str2)
return -1;
str1++; str2++;
}
return 0;
}
int fputs_until(FILE * fp, char * str, const char * end) {
int printed = 0;
while(str && str != end) {
fputc(*str, fp);
str++;
end++;
}
return printed;
}

And of course, an example program:

arglibtest.c

#include "arglib.h"


int main(int argc, char ** argv) {
const char * Long[] = {"cow", "say", "foo", "bar", NULL};
const char * LongSynoms[] = {"foo", "foo=FOFOFOFOFO", "car", "cow", NULL};
const char * ShortSynoms[] = {"f", "foo", "k", "cow=ohrecee=eoea", NULL};
const char help[1024];
sprintf(help, "Usage: %s [ --cow=value | --foo=value | --foo | --car=value | -f value -k ]\n", argv[0]);
argparser * argtest = argparser_new(Long, LongSynoms, ShortSynoms, help);
int i, len;
if(argtest) {
if(argparser_parseArgs(argtest, argc, argv) < 0) {
argparser_delete(argtest);
return 1;
}
printf("cow:%s\n", argparser_getValue(argtest, "cow"));
printf("foo:%s\n", argparser_getValue(argtest, "foo"));

len = argparser_getAnonymousLen(argtest);
for(i = 0; i < len; i++)
puts(argparser_getAnonymous(argtest, i));


argparser_delete(argtest);
argtest = NULL;
}
return 0;
}
% ./arglibtest --help
Usage: ./arglibtest [ --cow=value | --foo=value | --foo | --car=value | -f value -k ]
% ./arglibtest --cow=bar --foo -- --car 10 -fk 100
cow:bar
foo:FOFOFOFOFO
--car
10
-fk
100

Aside from being written in C, it essentially has the same result as the Perl version.