Blog archive
This is (or will be) a collection of my ponderings on computer science and life in general.
There is an atom feed here ;)
Clearly, as the site is not dynamic, there's no way to directly comment on the posts here. Your best bet is to send me an email.
Wed, 29 Sep 2010 11:53:16 +0100
Some notes on C#
So I have a job interview on friday for a .NET developer position. Having not really done much with .NET in the past (which the employer doesn't mind so long as I am willing to learn) I decided to brush up on the main differences between this and the other languages I use which these days are; C, C++, assembly and Java. There doesn't seem to be much point comparing C or assembly to the .NET framework, so I'll try and get the main points compared to the other two.
This is written for my own reference more than anything else, so YMMV. If a feature is very similar to that in another language I will just say that rather than explaining it.
Basics, object model etc
Like Java, the object model is rooted in a single class; object, which
is a native type.
Operator overloading is allowed, similar syntax to C++ but without stuff like returning non const references to *this etc. || and && can't be overloaded. == and this->Equals() have different meanings (== is reference equality, Equals() is value equality.)
Class definition is similar to C++, except the default inherited visibility is public (don't seem to be many examples of using protected or private, but then it was rarely used in C++ as well - maybe it doesn't exist?). Same as Java in that it always inherits from System.object. There is no semicolon on the end of the class definition. No multiple inheritance, like Java has a special type of class called an interface (with the same keyword) which only contains pure virtual member functions.
public class Foo : SuperClass, IInterface1, IInterface2 {
}
Strings in C# are immutable in a similar manner to Java. However they can also contain null characters - presumably this is because of the weird double-null-terminated-string-list structure that Win32 loves so much. There is probably some API function to convert between these and collections of strings. .NET strings are UTF-16, which is fine as Windows NT has always used unicode internally (hence all the Ex/A suffixes in the API)
Generics in C# (and .NET in general) are more similar to Java's generics than C++
templates. They essentially cast up to object and back the whole time.
Collections in C# typically inherit from IEnumerable<T>. The for-each syntax
is as follows:
foreach(Thing i in setOfThings) {}
compared to the Java:
for(Thing i : setOfThings) {}
Exceptions
C# has no checked exceptions, like C++. As the standard libraries and the runtime make use of exceptions, you have to make the same assumption as in C++ when working with exceptions. Namely, that any line of code could throw. This makes some sense, as checked exceptions in Java were not always used correctly, for example:
String s = in.readLine();
int x=0;
try {
x=Integer.parseInt(s);
} catch(NumberFormatException e) {
...
}
Where NumberFormatException is not a checked exception,
even though it is likely to be thrown. Of course the argument could be that
this code should not use exceptions in the first place, as an abitrary string
is less than likely to be a valid integer. (of course they added tryparse, but that has
it's own problems.
The syntax for exceptions is pretty much the same as Java, with try,
catch and finally. All exceptions inherit from the base class
Exception.
Naming conventions
C++ doesn't really have a standardised naming convention, with each project defining their own. Java does, so I'll point out the main differences for comparison.
| Usage | Java | C# |
|---|---|---|
| Class names | Starts with a capital, subsequent words also. | The same |
| Member function names | camelCase | PascalCase |
| Member variable names | camelCase | PascalCase |
| Paramter names | camelCase | camelCase |
Will add more later...
Sun, 19 Sep 2010 14:40:17 +0100
Some changes
So I've moved some things around on this site. The intention was to upload some other code, but most of the software I've written the last year or so was for other people so I can't really post that here.
I added the slowdown program, which is of limited utility but it's better than pastebinning it any time somebody wants it. I may try and make it into a more general purpose filter so you can simulate being on a *nix box over an old 300 baud modem (though it'd probably be easier to use a serial console and just set the baud rate.)
I'm going to try and clean up my BrainFuck compiler to upload it - was written in a hurry a good while ago so not very good by way of commented code. It produced the fastest code of any other compiler I could find at the time. That said there are probably a few optimisations that could be made - say buffering IO rather than read()/write()-ing single bytes at a time (as system calls aren't cheap).
Finally I'll try and get some version of my OS up. The problem with that, however, is that most of the ideas in it are proof of concept and testing rather than anything useful. On the other hand there are a number of reasonable features:
- Kernel land:
- Pre-emptive multitasking (not multi-threading, but wouldn't be difficult - not totally convinced shared memory is the best solution for parallelism)
- Basic services - cpio-based FS, simple VFS, pipes etc
- Multiboot compliant - boots via GRUB or PXELINUX.
- Some POSIX-ish system calls; fork, exec, wait,mmap (anonymous memory only atm), read/write/open/close, poll (in leiu of select(). The system is not intended to be POSIX-compliant, but why mess with a good thing.
- Loads ELF executables (staticly linked only)
- Support for user space drivers via message passing - not used apart from a small test of the feature (reimplemented the keyboard driver, but the one at boot time is still the in-kernel one).
- Partial (and probably incorrect) ANSI terminal support.
- User land:
- Minimal shell, supports chaining commands together and backgrounding them.
- Pile of test programs for system calls (e.g. wait/exec, pipes, causing gpf/page fault etc)
- Minimal C library implementation (some stdio calls, some with different semantics). Really more a set of functions likely to be used in a number of apps.
- Simplified C implementation of 2D Turmites (Testing VGA support)
- Nibbles/snake game (testing the terminal emulator). It's actually quite hard - I've not beaten it yet.
But the code in the kernel itself is a bit fragmented, as I didn't know what I was doing when I started. I will get around to writing a new version at some point, but I've other drains on my time at the moment. The User-Mode side is ok though - however chunks of it won't be binary compatible with the rewrite. For the time being, anyone who wants a copy can ask for one, but it's not going on here yet.
Wed, 03 Feb 2010 06:52:38 +0000
well i was foolish
Heh, turns out it wasn't a firefox issue, but a Gentoo one (and in fairness, seeing as it's not the mozilla binaries I shouldn't have mentioned it anyway.) Gentoo uses the system SQLite libraries, which were not compiled with secure delete enabled (or availiable as a use flag).
My bad.
Wed, 03 Feb 2010 05:45:22 +0000
Firefox doesn't really clear your private data
While waiting to head into uni for a lecture, I was clearing out some things in
my /home directory. Poking around in my
Firefox profile directory, I noticed a few
large .sqlite files (places.sqlite, cookies.sqlite etc). Now I set
Firefox to clear private data on exit. It removes all traces of the
history in the user interface, so it was a bit odd.
On opening places.sqlite with a text editor (btw these are binary files, but you can still make it out) , I saw practically every site I had visited since 2004. The same went for the cookies and site preferences. I killed firefox, deleted these files and started it again, clicked round a few sites, cleared private data and quit. Same thing, it had kept my history and cookies.
I have to admit, there were not a small amount of conspiracy theories flying around my head at that point. A simple cron job to delete the data would not suffice, as there are certain things I do want to keep (e.g. which sites to accept cookies from) and if FF is running when the job executes (as is likely to be the case), firefox will hold the lock on the file anyway, and next time it syncs to disk it'll all be restored.
I started thinking about a small tool to do the file wiping, which i could add to my /usr/bin/firefox script. Reading about the sqlite file format it soon became clear what was happening, rather than rebalance the whole B-Tree, sqlite was just adding the deleted nodes to a free list, not actually zapping them from the file. Reading further it says sqlite provides two options to solve this:
- Use the
VACUUMcommand to flush the changes out of the database, compacting it. link - Set the database as auto-vacuum This will do it, and to be honest I'm unsure why Mozilla doesn't do it by default on exit (could maybe argue a performance penalty, but it takes a tiny fraction of a second on my box, and if somebody has set it to erase this data they are not going to moan).
Neither of these would be difficult for the Firefox people to implement. I'm currently compiling the latest firefox and sqlite to verify this is still present (was still on 3.5.2). After which I'll file a bug report.
In the meantime though, you can either just delete the files by hand (with
firefox not running) or VACUUM it yourself, again when firefox
isn't running
This can be done quite easily in the shell, just load the database with
sqlite's interface (sqlite3 in this case) and type
VACUUM; then quit (ctrl+d works fine). Again, if you try
doing this with firefox running, you'll get something like:
richard@armada ~/.mozilla/firefox/k6telub8.default $ sqlite3 places.sqlite SQLite version 3.6.22 Enter ".help" for instructions Enter SQL statements terminated with a ";" sqlite> VACUUM; Error: database is locked sqlite>
An easier way is probably to loop over them all and vacuum them (again from the firefox profile directory):
$ ls *.sqlite | while read > do > echo "VACUUM;" | sqlite3 "$REPLY" > done
It's worth noting that this won't clear out stuff like cookie preferences. If you go onto the options and clear them, then run this script it will remove traces (as they haven't been dropped from the database).
Sat, 23 Jan 2010 20:13:25 +0000
Making ROX-Filer respect folder.jpg thumbs
As you may know, I'm a big fan of ROX filer as it's very easy to use, and fast. However my main workstation also functions as a file server for my media centre downstairs (XBOX running XBMC, which is very nice as well).
In XBMC you can set custom thumbnails for directories, placing a file
folder.jpg inside. Presumably this is for compatibility with
Windows Media Centre/Media Player, but couldn't say tbh (don't use Windows, so
it's irrelevant). It also allows you to set icons for individual files with
filename.tbn.
I wanted ROX to show these icons on my workstation when I viewed said directories, I knew there was a hook somewhere, as ROX has a feature known as 'AppDir's, which is similar to the way RISC-OS (from Acorn) did it.
The hook turned out to be, instead of looking at ./folder.jpg, it
went to ./.DirIcon. So a simple loop in bash suffices:
find -name folder.jpg|while read do ln -s folder.jpg "`dirname "$REPLY"`/.DirIcon" done
Easy eh? Fair enough it uses another inode, but with most of the files being >100mb, I'm not likely to run out.
Sat, 23 Jan 2010 18:53:32 +0000
First semester of MSc
After the summer i started a masters course in Advanced Computer Science (still at Liverpool). To be honest the first month and a half was pretty unbearable, as the university had not confirmed my place until the day i was meant to register. (whilst I was still in Caithness).
This caused a number of problems, the primary one being that I was in desperate need of accomodation. I checked out LSH, but there was nothing hopeful. Also, I've been burnt with LSH accredited landlords and properties in the past so thought it was best to avoid the whole thing. After about 6 weeks of couch surfing (with some surprisingly understanding/generous friends) I found a shared house not far from where I lived two years back.
The MSc itself seems to be going well.. Exams are this week though (but I had another post I wished to make and figured that this one should come first. Privacy and Security (COMP522) is quite enjoyable, and I'll be walking into the exam with 25% already because I got perfect scores on the assessments. Advanced algorithmic techniques is slightly worse, but most of that is due to the practicals being poorly specified, deliverables being misleadingly stated, and the ommision of a number of things (which actually account for most of the work - for example a simple graph algorithm is not difficult, writing something to read in a graph frmo a text file is much more fiddly than the algorithm itself.)
Anyway, later ;)
Mon, 20 Jul 2009 14:27:41 +0100
Initialisation of vtables in static globals
While working on my kernel, I came across an odd problem that had been making me consider rewriting in C (though I may end up doing that anyway to reduce complexity) - Virtual functions did not work, and the results were odd.
extern Console *con;
class Base {
public:
virtual void do_something() {
con->print("\nCalled base class\n");
}
};
class Sub : public Base {
public:
virtual void do_something() {
con->print("\nCalled derived class\n");
}
};
Base b1;
Sub s1;
Base *b2;
void test_it() {
s1.do_something();
b1.do_something();
b2=&s;
b2->do_something();
Sub::Sub(s1);
s1.do_something();
Sub s2;
s2.do_something();
}
The odd thing is that even though the static instances do not have any attributes
you could expect (at least for s1) that the vtable would be set
as static data (or even rodata as the type can not change).
Of these, s2 and b2 perform as expected - on s1 however the vtable is uninitialised. This means that (on bochs/qemu anyway) you are dereferencing a null pointer (which will cause a panic).
Once the constructor is called (Sub::Sub(s1)) it works as you'd expect. Was just
a bit weird when certain things worked and others didn't - I had seriously expected it to
pre-initialise the classes as the data was known at compile time. Should have read the ABI spec more
thoroughly. ;)
Tue, 30 Jun 2009 20:19:20 +0100
Stuff i need to get on this site
Here are a few things I want to get here eventually. Just a case of writing them up.
- Slowdown - for emulating slower bauds on modern terminals, either for nostalgia or watching old tty animations.
- My honors project - OpenGL based turing machine/turmite simulator. It was pretty cool.
- Brainfuck compiler - old project, but it did a good job and the resulting code was faster than that of any other compiler I could find at the time.
Tue, 30 Jun 2009 19:11:18 +0100
Graduated
Well, I'm done with university now. I got a 2:2 which was less than I was expecting. However it is still a degree. The job hunt is occuring and there are a few promising leads - just nothing quite yet.
As a result I have had to relocate this site, there are a few issues here:
Fasthosts subdomains don't work right. They frame the index page - which means you cannot link to somewhere inside a subdomain. Even due to my dislike of javascript I was forced to remedy this with small (2-line) script at the bottom of the page.
Google points to my university site, and having not messed with .htaccess in a long time I couldn't get it right. however it works now
On a different note I've been working on a couple of personal projects, such as a software 3d renderer. It is capable of loading simple (as in triangles only, no textures or normals - but then the normals for triangles are implicit). At the moment the only thing I have been testing with is the Stanford Bunny. I intend to add in at least gouraud shading and possibly texturing.
Relating to this, I'm going to have to write my own filling/shading/texturing system, which could probably be released as a seperate project - at the moment I am using SDL_gfx just so I could concentrate on the mathematical aspects. The other thing I see a lot in code that uses SDL is the number of times people switch(){} on the pixel format of a surface. Wouldn't it be better to write a seperate method for each format rather than doing a comparison each time?
Anyway, that's all for now - I will try and update this more often...
Sun, 21 Dec 2008 02:28:50 +0000
revisiting my OS kernel
So today I decided to try doing a bit more work on my operating system. A few months back I got to the ooint of multitasking and managing memory.
However I stopped as I couldn't quite get the startup code right - the main problem was I wanted to avoid introducing big chunks of assembly language into it (which would hurt portability).
The way I was doing things previously was mapping the entirety of physical memory into the kernel address space. Any page that needed to be copied or zeroed could be done easily - the problem is that this puts a limit on the maximum amount of physical memory accessible.
For those unfamiliar with operating system development, it is common practice to reserve a chunk of the address space for use by the kernel. As you create processes, this part of the page directory is copied for each user-mode task.
This makes it difficult for the kernel to allocate memory after the initial startup because some of the page directories will not include these mappings. This is undesirable because it would mean having to walk the task list and update the relevant address mappings (on x86 this is a 2kb copy per process, assuming a 2g/2g user/kernel split)
So today I go and dig through the linux memory manager (which is surprisingly well written/commented for linux). It turns out that this works exactly the way I was trying to avoid. Shock horror.
The need to map all of memory into the kernel partition does not seem to be all that convincing. Any memory besides internal kernel structures and hardware registers isn't very important. Anything that does need to be touched would only be so when servicing a system call - in which case it is part of the user-mode page directory which is still used while servicing a software interrupt.
So... here's the question - can anyone offer a good reason for doing this, or a simple alternative mechanism. Most of the complexity exists during initialisation where there is only one kernel thread. But as I say, I would like to avoid a lengthy startup procedure written in assembly language - portability is one of the aims I have for this project.
Mon, 29 Sep 2008 01:39:00 +0100
Getting an RT2500 based card working with WPA in Gentoo
For some reason this card doesn't work with wpa_supplicant, so you need to use iwpriv (essentially a command line interface to ioctl for wifi devices) to set the various parameters by hand.
If you read the readme, it says the kernel module will read a file /etc/wireless/RT2500STA/RT2500STA.dat which you should create.
Turns out it does not read this file at all. I wrote a small bash loop to do the relevant work, and tbh it did the job fine.
start_ra0.sh #!/bin/sh GATEWAY="192.168.2.1" IP_ADDR="192.168.2.2" rmmod rt2500 && sleep 5 # load the driver as it's not in the vanilla kernel modprobe rt2500 # the first line of the config file is [Default]. Don't process it. grep -v Default /etc/wireless/RT2500STA/RT2500STA.dat | while read do # do the ioctl's iwpriv ra0 set "$REPLY" done # IP address (replace this with your dhcp client if you use dhcp) ifconfig ra0 up "$IP_ADDR" # default gateway route add default gw "$GATEWAY"
This of course assumes that you read the README in the CVS repository. Some of the commands will error out, don't worry. Also in iwconfig it does not show the correct encryption key. Finally it can sometimes get confused with multiple access points - just bring down the interface, unload the module and reload it.
Wed, 17 Sep 2008 20:53:40 +0100
Abuse of the Ternary operator
A friend of mine asked if some code looked ok:
correct me if i'm wrong, but d[i][j] = (del>ins)?(sub>ins)?ins:sub:(sub<del)?sub:del; will stick the smallest of del, ins and sub in d[i][j] right?
While would appear to be correct, the fact that it needed to be asked should have set off warning bells. If you can't understand your code when you write it, how do you expect to do so a year or more down the line?
I instead suggested to him something like:
d[i][j] = Math.min(del,Math.min(sub,ins));
may be more appropriate. I thought to myself "java has varargs now..."
public <T extends Comparable> T min(T... values) {
T ret = values[0];
for(T i:values) {
if(ret.compareTo(i)>=0)
ret = i;
}
return ret;
}
Fri, 12 Sep 2008 19:27:11 +0100
finally passed math161!
So I passed it.... That is a real load off my mind. I can go back to concentrating on computery stuff rather than stressing about my future.
Granted it might not look good to future employers that I repeatedly failed an introductory module, However that is part of the purpose of this site - to create a portfolio. I will start working on writing a couple of my other projects up. Also I have a few Delphi components to write, which I believe may be useful to a certain company.
The CMS has undergone a major rewrite and documentation update. However I have not yet moved this site to the new system. Mostly because I am still unable to log into the linux farm at CSC. I have confirmed this problem with a number of my peers, and plan on popping into the helpdesk when I get back to the 'pool.
Tue, 09 Sep 2008 16:21:55 +0100
Firefox doesn't do self-closing tags
So turns out that Firefox doesn't respect self-closing tags, leading to all sorts of problems when dealing with anchors. You would presume something like: <a name="foo" /> would be legal, but not as far as the mozilla/netscape people thing.
This is what was causing the odd behaviour of the W3C core styles. I'm going to have to dig through with the DOM inspector and see if it disregards self-closing img tags too.
Thank god I'm not incorporating javascript into this CMS....
Sun, 07 Sep 2008 18:21:29 +0100
Rewrote the CSS
So I bit the bullet and rewrote the CSS for the site. I'm not sure how well it worked out, but will make the site layout more customisable. For those of you who want to stick with tables, there is an option USE_TABLES in the source.
As a result of the new colour scheme, the core styles don't really work any more.. I'd like to find a way to make them override the other styles rather than cascading... idk, it would sort of defeat the point of Cascading style sheets. Maybe I should just create a couple of example themes and work from there.
On a related note, I've come across some ideas on how to improve the presentation of some parts of the site (say, the blog) but it would require a couple of changes I'm not really comfortable with, and seem a bit hacky. Something along the lines of this. I would like to have this as a feature availiable (I don't really like the idea of using actual images), but think this would warrant some refactoring of the CMS source in order to do it in a sane way.
It is probably in need of some refactoring anyway, there're a few other things I would like to support, such as multiple 'blogs' (could be news etc), categories for projects and posts, additional pages which can be user defined.
Sat, 06 Sep 2008 04:36:07 +0100
added a few alternative stylesheets
I've added the W3C's Core Styles as alternative stylesheets. This is mostly because I reckon mine needs some improvement and was looking for an easy way to check out alternative looks.
I'm also thinking I should drop the table-based layout and go for CSS and DIV tags. I'm not sure on this though. I'd presume all the modern browsers support this quite well, however I'm sort of unable to test anything other than Gecko at the moment because I'm on 64 bit gentoo, so no MSIE, Opera seems to have real problems (I think it's because I tried to install the flash plugin :o). Granted I could throw these things on my BSD box, but then it becomes a bit more of a pain.
Anyway to check out these styles, (in firefox this is, presumably the same on other netscape-based browsers) go to View->Page Style and pick one. Personally I don't really like the way they add emphasis onto text seemingly at random (as in, some paragraphs but not others).
Sat, 06 Sep 2008 00:00:28 +0100
ATOM feed support
So I added atom (RFC5023) support to this blog. I thought it would be quite funny as it is technically a static website. Not linked to it from anywhere yet though.
There was an interesting problem when trying to pass the validator, it was falling over on the date strings, even though I was generating them with the --rfc-3339 option to date(1). Turns out either the spec is inaccurate, or there's a bug in the date command.
I ended up solving it with a format string to date:
date --date "1970-01-01 ` stat -c "%X" "$1"` sec" +%FT%T%:z
Which is a bit messy, but I don't see another way to get date to take a time in seconds since the epoc.
Also, I changed the stat call today, as I discovered that on systems with access times disabled, the atime provides the only copy of the creation time (no, surprisingly enough, ctime changes along with mtime :/ )
Going to have to update the README again....
Thu, 04 Sep 2008 16:14:52 +0100
Getting my compiler working on 64 bit
I decided to have a stab at writing up my Brainfuck compiler. I didn't get very far though. It it probably as complex as the logic program, and there are two seperate versions of it (one in C, which produces code which uses the C library) and one in C++ (which produces plain old Linux assembly language).
So I tried running the compiler, I've a couple of handy Makefile macros to make working with it easier:
%.o: %.c %.h $(CC) $(CFLAGS) -c $< %.o: %.asm $(ASM) $(ASMFLAGS) -l $<.lst $< %.asm: %.bf bfc ./bfc $< > $@ %: %.o ld $(LDFLAGS) -o $@ $<
So say there is a bf source file 'mandelbrot.bf' then you can simply do make mandelbrot and it will spew out the binary thanks to these rules. Well, that's the idea anyway.
The problem came when I tried to do this on my new system (64 bit gentoo remember):
ld: i386 architecture of input file `mandelbrot.o' is incompatible with i386:x86-64 output ld: warning: cannot find entry symbol _start; defaulting to 00000000004002b0
This was somewhat annoying, as it was around 4 AM. I knew what the problem was, just couldn't find the solution for ages. I tried -m32 on the LDFLAGS, but that didn't help. It turned out to be -m elf_i386.
Next thing I tried was running it on freebsd 7 (which is running inside virtualbox). Both of the compilers spat out executables (of course the ld flags needed yet another tweak). One segfaulted (the one which was using the C putchar/getchar). The other ran, but did nothing. Both the interpreters worked fine though.
So I fired up ald on the first one to try and find where it was segfaulting, which didn't turn up much of use.... it was somewhere deep inside libc. On a side note I found some quite interesting snippets of assembly in the libraries. Things like xchg eax,eax which is quite obviously spat out by the compiler, but I can't see the use of it.
The C++ one didn't work for a few reasons (actually surprised it didn't cause some sort of nasty behaviour or a protection fault)
- Linux has different system call numbers to freebsd.
FreeBSD is actual UNIX, Linux is not. There are clearly going to be differences in how things work.
Large chunks of Linux (at least to begin with) were written without access to the POSIX documentation, if you read Linus' book "Just for fun" he mentions that it did occur to him afterwards that he should have kept the identifiers the same to maintain binary compatibility. Same with errno.
- Linux has a different calling convention to freebsd.
While linux passes it's arguments to
int 0x80in registers, freebsd uses the stack (supposedly to save pushing/popping values, but it has to do that on the other side anyway, and with a chip like x86 you have to spill to the stack all the time anyway)
The (temporary) solution to this is to brand the resultant executable as a 'Linux' one, and run it through the compatibility layer:
$ brandelf -t Linux name-of-executable
At which point it ran fine. Retargetabiliy is on my list of things for the next version (these were written over the course of a week back in 2007 for a bit of fun.) I have since read a lot more about the ELF format, and have a pretty good idea how to construct an executable. Ideally I'd like to have it work across different processor families as well, even to the likes of VAXen (now I've got one running in emulation, but that's another story)
Wed, 03 Sep 2008 21:18:32 +0100
added requisite management
so I have added management of what I shall call 'requisites' to the CMS. This means it will keep a list of all the files required for the site, and make sure they're included when it is copied to the server. (or at least give an error if one is missing).
This was actually really difficult because of a one-line function.
REQUISITE_FILE="assets.txt"
function add_requisite {
echo "$1" >> "$REQUISITE_FILE"
}
It was only adding the html files and style.css. Can you see why? I spent ages trying to dig to the bottom of this. Shows what happens when you've been up for days.
The problem is because of the use of pushd/popd in the maker script. It was sending the correct strings to the file, just the wrong file. sure enough a find -name assets.txt showed one in each of the subdirectories. Man I felt an idiot, I was almost on the brink of asking for help. :o
The solution was to take a copy of `pwd` when the script was run, and prepend that to the path. Now it all works fine. ;)
Also I added timestamps and anchors to the blog posts. I'll get around to doing an index soon enough.
Finally, I made the display of download/paper/readme optional, so you don't get "sorry not availiable" instead of a link. Should make it more relevant and less cluttered.
Wed, 03 Sep 2008 17:52:10 +0100
So I've upgraded the link handling system....
Firstly, there are three options on how to display the links in the sidebar. TEXT just prints the name of it, and omits the image, IMAGE does the opposite, and BOTH will do both (like you'll see if you look across now).
Additionally I went and grabbed the favicons from the various sites, and resized them with ImageMagick [sic] so they are all pretty uniform now. In the maker script you can now define either the width or height of images (or both) and it'll fix them to that size, however I think having them all the same size to begin with is a better approach.
Finally, there is a links page, which adds a short description to each of them. I'll get around to making the sidebar just show a couple (say the top 5).
Wed, 03 Sep 2008 12:41:17 +0100
Now this site validates as XHTML 1.0 transitional
go on, give it a go ;)
The main change was that I had to make most of the blog posts and project descriptions use the _raw suffix so that they don't go through the paragraphing function in maker.
I had to do this for anything that uses <pre> or list tags, as they are not allowed inside <p>. At some point I will get around to writing a proper HTML sanitizer (I dare say a relatively powerful one could be constructed with sed), as currently I've still got to go through everything and insert the digraphs by hand.
The nice thing was there weren't any major troubles. Just minor presentation errors which were easily fixed.
Anyway, enough. I've had to type this twice now because I accidentally quit without saving the file :/.
Wed, 03 Sep 2008 01:00:51 +0100
Javas: simple java build system
This is a script I wrote a while back, but it comes in useful whenever I'm dealing with any non-trivial java project that doesn't warrant using Ant.
#!/bin/bash
# (C) Richard Whitty 2008
# A few bash functions which will probably come in useful to java programmers.
# finds files with the extention provided.
# $1 the extenstion to look for
# if we are to be verbose
function find_by_extenstion {
find -name \*.$1
}
# gets a list of all class files
function get_class {
find_by_extenstion class
}
# gets a list of all class files
function get_src {
find_by_extenstion java
}
# removes class files
function clean {
get_class | while read
do
rm $OPTIONS "$REPLY"
done
}
# checks if a source file is due for a rebuild.
function needs_rebuild {
local srcfile="$1"
local binfile="${srcfile:0:${#srcfile}-4}class"
if [[ "$srcfile" -nt "$binfile" ]]
then
return 1
else
return 0
fi
}
function get_sources_to_be_updated {
get_src|while read srcfile
do
needs_rebuild "$srcfile"
if (( $? == 1 ))
then
echo $srcfile
fi
done
}
# only does the ones that have been updated
function rebuild {
get_sources_to_be_updated | while read
do
echo "javac $REPLY"
javac "$REPLY" || break;
done
}
# builds the sources starting from the current directory.
function build {
get_src | while read
do
echo "javac $REPLY"
javac "$REPLY" || break;
done
}
function tbuild {
time build
}
# prints a handy word/line/char count for the source files.
function wordcount {
if [[ $VERBOSE == 0 ]]
then
find -name \*.java -print0 |wc -l --files0-from=-
else
find -name \*.java -print0 |wc --files0-from=-
fi
}
VERBOSE=0
for arg in $@
do
if [[ "$arg" == "-v" ]]
then
OPTIONS=" -v "
VERBOSE="1"
else
$arg
fi
done
Tue, 02 Sep 2008 20:10:51 +0100
If you're going to ask for help
Quite often I get people contact me over various channels asking for help. You know who you are. Here are a few pointers for you:
- Either know what your problem is, or be willing to give me a shell Trying to either debug something or talk somebody through a solution to a problem is bad enough. When they can't adequately explain the problem, and don't get what you're saying it just becomes annoying.
- If you get advice and don't take it, don't come moaning when it doesn't work
Quite often a conversation will go like this:
someone: so I've got this problem yadda yadda yadda me: ok, so you need to do x, y, z. someone: ok, I'll do x and z, but I'll also do B instead of y. me: I'm telling you, this is what you need to do. Don't come crying to me when it doesn't work. a while passes, normally by which point it's stupid-o-clock in the morning someone: ok, so I did this and it doesn't work. me: (pastes a copy of the previous conversation) someone: hmm I'm so dumb I can't read simple instructions (keeps bugging me for hours) me: ok, fine give me a shell (log in, fix the problem in like 5 minutes) someone: hey that's really cool, how did you do that? me: same way I told you to do it 6 hours ago. Next time there'll be an invoice coming at you!
What these people don't seem to realise is that this sort of carry on, when it extends to ~7am, makes me less inclined to help you next time, and chances are you'll end up on my ignore list for a few weeks or until I remember to take you off. -
Read the $%^$% manual
I can't stress this enough. if you come to me with a problem involving a pile of technologies I've never heard of, you are going to have to provide at least a basic overview of how it's meant to work. It's quite annoying having to dig through documentation for some product I'm not using, to help someone with something that I'm not being paid for. How do you think I figure these things out. (hint, man pages rock, google rocks - if you ignore the glaring privacy issues).
Tue, 02 Sep 2008 19:20:31 +0100
64 bit portability in general
So I've been thinking for a while about 64 bit code, and now I've got a 64 bit system (on gentoo of course) I can start trying to move all my code over.
To be honest, most of the things that will cause problems I'd already taken care of, because I'm not as sloppy as I once was. There are still a number of things to avoid:
-
Don't assume a pointer can fit into an integer
On 32 bit x86 systems this is the case, you can quite happily do something like:
int *foo = &some_int; printf("%X\n",foo);However on AMD64, a pointer is 64 bits (even though the virtual address space is 41 and the physical address lines only number 36). This means that if you are trying to manipulate pointers as integers, it will either cause a compiler error claiming loss of precision, or it will simply truncate the value at runtime, which is not what you want.
A
longhowever, should be big enough for a pointer (on x86 both long and int are 32 bit. If you want 64 bit on x86, use long long). - Don't assume sizes of types
It's quite common in code to see people using reinterpret_cast and then adding some arbitrary number to it as an integer. Don't do this. You don't even need to use sizeof() just use the C language's own support for pointer arithmetic. for example:
long arr[10]; long* ptr=arr; unsigned long iptr = reinterpret_cast<long>(arr); unsigned long* really_stupid = reinterpret_cast<long>(iptr + 20); unsigned long* middle_l = reinterpret_cast<unsigned long*>(iptr + 5*sizeof(long)); long* middle_p = ptr+5;
The lower two values end up the same, and the last is much clearer. Generally you shouldn't need
reinterpret_castunless you're doing something funky. Thereally_stupidis the one that actually causes all the trouble. long is a different size on different chips (and even different compilers on the same chip). You start doing tricks like this, and you're asking for trouble. If for whatever reason you need a type to be a certain size, use a typedef (I believe C99 even has these predefined in some header file for you).
Tue, 02 Sep 2008 17:37:19 +0100
Porting IVAN to 64-bit Linux
The other day I decided to bite the bullet and port IVAN to 64-bit. Now there were a couple of troubles with this, which I will go through:- The reference counting mechanism. All the shared arrays and strings were allocated including a reference count at the beginning of the array, then storing the pointer as value+4. Strings were allocated like:
char *newString = 4 + new char[length + 5]; REFS(newString)=0;
which isn't good. After some digging (ok,grep -n REFS */*|grep \#definewe find REFS defined as:#define REFS(ptr) reinterpret_cast<ulong*>(ptr)[-1]
So we see the 4 is for the reference count value, and the +5 is the reference count plus the null byte on the string. As long is no longer 32 bits, this causes major corruption. A simple fix would just be to tell REFS to use an int instead (the reference count is only ever accessed through that macro) but in my opinion this wouldn't really solve the problem. These all got replaced with:char *newString = sizeof(ulong) + new char[length + sizeof(ulong)+1];
Then those parts worked. Similar changes were needed for the arrays, but you get the idea. - Once all these had been fixed, there was a problem with the fonts, where each character drawn would draw a lot more than was needed horizontally. This was due to the original developers using
unsigned longs assuming they were also 32 bit. As they are not on 64 bit (long is same size as a pointer) then this was doubling the amount that was being drawn. However this was quite hard to pin down. The game was playable at this point, just most of the text was illegible. Here is the offending code:culong* EndPtr = FontPtr +5;
(culong is a typedef forconst unsigned long) I converted the code block to use integers instead:for(; SrcLine != EndLine; ++SrcLine, ++SrcMaskLine, ++DestLine) { cuint* FontPtr = reinterpret_cast<cuint*>(*SrcLine + B.Src.X); cuint* EndPtr = FontPtr + (20/sizeof(uint)); // this also works with longs, but may as well keep to the original plan. cuint* MaskPtr = reinterpret_cast<cuint*>(*SrcMaskLine + B.Src.X); uint* DestPtr = reinterpret_cast<uint*>(*DestLine + B.Dest.X); for(; FontPtr != EndPtr; ++DestPtr, ++MaskPtr, ++FontPtr) *DestPtr = *DestPtr & *MaskPtr | *FontPtr; }Now we have fonts that are legible, and the system doesn't segfault everywhere. Valgrind still throws up a couple of errors but I'll leave that for another day.
Tue, 02 Sep 2008 17:34:11 +0100
prodigal first post
This is the first blog post ever to be published using this CMS. You should feel damned privelidged that you get to see it.
And paragraph splitting works as well ;)
Or does it?