2009-03-14

Things I didn't know in C

I've been creating an interpreter in C99 for the last six weeks. This is the largest project I've done in C, as normally I get paid for writing C++. I've also read the C99 spec, as I was taught C in '91, and things change.

Here are a couple of things I've discovered which I didn't know before:

You can use field names in struct initialisers, such as
( foo_t ) { .bar = 3, .baz = 8 }
which give you an automatic struct with the named fields filled in. Unfortunately, astyle makes a pig's ear of formatting it.

Unlike all the other printf family, the return value of the snprintf function is not the number of bytes written, but the number of bytes which would have been written had there been space in the buffer. That caused a few bugs in some string building code I'd written before I RTFM. I'd assumed the maximum value returned would be the buffer length, which meant I was assuming this is safe:

size_t max = sizeof(buf);
size_t offs = snprintf ( buf, max, "foo" );
offs += snprintf ( buf + offs, max - offs, "foo" );

But when offs > max, max - offs is a large value.

I also have given up using splint as a checker, as that was exactly the sort of error I was hoping to get detected. The amount of annotation necessary to get splint to work with my allocation scheme was too painful to justify.

Labels: ,

2009-01-25

SciTE and ctags

I've been using SciTE as editor of choice for some time, and spent a little time today getting a few extra things working for C99 projects. This year I'm refreshing my C a bit, as I haven't done anything which has specifically used C99.

There's support in SciTE for autocompletion of words within the file by hitting Ctrl+Enter, but you can also add .api files which list function prototypes for an API, giving autocompletion via Ctrl+I. You can either use the files provided for C and Java, or use ctags and a bit of Python to build your own.

The C.api file on scintilla.org is a bit small, but I couldn't get ctags to find most of the prototypes from /usr/include/*.h and /usr/include/sys/*.h. So I made a little bash script to pass each header through cpp, then extract it, which worked OK.

This seems to work to generate tags file for conversion to SciTE api file:

ctags -f - --c-kinds=+p-d --excmd=number /usr/include/*.h | grep -E "^[^~_]" > tags

or from the kin project folder:

ctags -f - --c-kinds=+p-d --excmd=number src/core/*.h | grep -E "^([^_~]|_[^_])" > tags

without --excmd=number the python script fails to convert the tags to api, as it uses patterns rather than line numbers.


Also changed some of user properties - to break it up a bit more with files into the ~/.SciTE/ folder. This moves the c and asm highlighing into separate files, a machine.properties file for machine specifics (such as where to put the window and whether to show tabs and status, which depends on screen size).

I also created a 'workbook.sh' script to write the date to today's workbook file and open it.

To get directory properties working, enable them in user properties with

properties.directory.enable=1

Then the SciTEDirectory.properties file has its local settings for the project. This defines

# project home
ProjectHome=$(SciteDirectoryHome)

# make
make.command=cd $(ProjectHome); make $(FileName)

# go
command.go.*.c=cd $(ProjectHome);bin/$(FileName)

# Extend C API with project API
api.*.c=/home/pete/.SciTE/c99.api;project.api

# Retag
command.name.1.*=Retag
command.subsystem.1.*=2
command.1.*=cd $(ProjectHome);\
ctags -f - --c-kinds=+p --excmd=number src/core/*.h | grep -E "^(kini?|opcode)_" > project.tags; \
python ~/.SciTE/tags2api.py project.tags > project.api\
rm project.tags

# Apropos
command.name.2.*=Apropos
command.subsystem.2.*=1
command.2.*=grep -E $(CurrentWord) /home/pete/.SciTE/c99.api $(ProjectHome)/project.api

# Info
command.name.3.*=Info
command.subsystem.3.*=1
command.3.*=firefox http://www.opengroup.org/onlinepubs/000095399/functions/$(CurrentWord).html


This means build and run are performed in the project folder, and adds three extra commands - the first runs ctags to rebuild the project's tag index. The second searches the tag index for a highlighted word as a substring (rather than the built-in popup, which you type the first few letters). The third opens the unix spec for the highlighted function, which includes the C standard library functions too.

I've put the contents of my ~/.SciTE folder here, along with my .SciTEUser.properties file. There's the generated C99.api, asm and cpp properties without bold fonts (which mess up formatting), a version of cleanup.cc which will compile with gcc, protags.sh which preprocesses and ctags include files, and workbook.sh which creates a workbook/TODAY.log file and opens it in SciTE.

Labels: , , ,