K&R – Solution to Exercise 1.23

I’m working my way through The C Programming Language at the moment, and so far I’m loving C’s purity and leanness.

One of my few disappointments with the book is the lack of solutions to the exercises. The exercises are refreshingly challenging because the book isn’t aimed at beginning programmers. Unfortunately this means that the desire to validate one’s solutions is quite strong. Fortunately, Google had a solution to this problem: Richard Heathfield’s solutions site.

I just finished my solution to exercise 1.23 (“Remove all comments from a C program”) and I’m quite chuffed with it so thought I would share it here. Out of the multiple solutions provided on Richard’s site, mine was about the closest to following the guidelines as far as what knowledge one is supposed to have of C by that (early) point in the book (the only thing I cheated with is the use of break and continue – it would have just been quite ugly without those two small additions). Basically the solution is a state machine using if / else instead of more traditional switch methods as switch had not yet been introduced.

My solution deals with all the special cases I could think of, and even deals with the tricky sample input on Richard’s site, provided at the bottom of the solutions page for this exercise.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/*
 * K&R Exercise 1-23
 *
 * "Write a program to remove all comments from a C program. Don't
 *  forget to handle quoted strings and character constants properly.
 *  C comments don't nest."
 *
 */
 
#include <stdio.h>
 
int main()
{
    int c;
    int c2;
    int in_quotes = 0;
    int in_comment = 0;
    int current_quote;
 
    c = getchar();
    while (c != EOF)
    {
        if (!in_comment && !in_quotes)
        {
            if (c == '\'' || c == '"')
            {
                in_quotes = 1;
                current_quote = c;
                putchar(c);
            }
            else if (c == '/')
            {
                c2 = getchar();
                if (c2 != EOF && c2 == '*')
                {
                    in_comment = 1;
                }
                else
                {
                    putchar(c); /* Just a regular '/', so output it. */
                    c = c2;
                    continue;
                }
            }
            else
            {
                putchar(c);
            }
        }
        else if (in_comment)
        {
            /* Check for a closing comment. */
            if (c == '*')
            {
                c2 = getchar();
                if (c2 != EOF && c2 == '/')
                {
                    in_comment = 0;
                }
                else
                {
                    /* Don't advance to next character in stream. */
                    c = c2;
                    continue;
                }
            }
        }
        else if (in_quotes)
        {
            /* Skip over escaped chars. */
            if (c == '\\')
            {
                putchar(c);
                c = getchar();
            }
            else
            {
                /* Check for closing quote. */
                if (c == current_quote)
                    in_quotes = 0;
            }
            putchar(c);
        }
 
        c = getchar();
    }
 
    return 0;
}

Users Are Not Stupid

Really!  And, quite frankly, I’m sick and tired of programmers talking about them like this (not all programmers, some are worse than others, and all the usual disclaimery stuff applies)

I’m a user first, programmer second.  So are you.  Chances are you were using a computer for everyday tasks for a while before you started programming.  The fact is, we will never again be able to see computers in the same way as we did back then.  This is why we have average users test our software, and it’s vital that we do so.

Think about what it means to be a programmer.  Our job is to make computers more accessible to our dear users.  Everything we do, we ultimately do for them.  If we code with the user in mind at all times, and respect their needs, then everybody will ultimately be better off.

Sure, sometimes (hell, often!) a user’s request may not feel like the right thing for the system, and sometimes it won’t feel like the most elegant thing to do, but there are times when a leap of faith is required.  There will always be a balance between what users want and what we feel is good for them, but I’m appealing to you to lean in the direction of the user.

Nobody likes validating input to death, or putting up what seems like endless tooltips and hints all over the place, but users really do appreciate the little things we do to make their experience better.  Unfortunately, it’s more of a case of preventing outrage than garnering actual praise, but that’s what we signed up for, for better or worse.  The more people use the system for its intended purpose and the less we hear back, the better.

Make your error messages friendly.  Let the user feel like they have a more casual relationship with the system and they might feel less frustrated when something goes wrong.

“Don’t you worry about blank, let me worry about blank.”

Customer service rules apply even when the customer isn’t right in front of us.  Think of the system as an extension of yourself.  Build a little bit of your personality into the system for a more personal experience.

Please, please don’t think of your users as < than you, it’s just not fair.  Think of how out of place you would feel in their profession.  Respect the average user, and let’s make the computer experience better.  For them.

Tubecaster 3 UI Mockup

Here’s a mockup of the main window for the upcoming Tubecaster 3.  The release will include support for multiple downloads at once, playlist download support and built-in media conversion tools.  Stay tuned!

Tubecaster 3 main window

Pre-populate Django ModelForm with Specific Queryset

I just had a situation where I was trying to filter the queryset for a ModelMultipleChoiceField based on the currently logged-on user.  I was going crazy trawling through the Django docs and eventually Google.  It seemed like something which should be so simple, but there was no obvious way to do it.  Eventually I found the answer, and it IS simple!  As an example, let’s say you have the following two models as part of a simple photo gallery app:

?View Code PYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Photo(Model):
    name = CharField(max_length=100)
    caption = CharField(max_length = 150)
    user = ForeignKey(User)
    upload_timestamp = DateTimeField(auto_now_add=True)
    image = ImageField(upload_to="user_images/%Y/%m/%d/")
    thumbnail = ImageField(upload_to="user_images/%Y/%m/%d")
    def __unicode__(self):
        return self.name
 
class Album(Model):
    name = CharField(max_length=100)
    caption = CharField(max_length = 150)
    user = ForeignKey(User)
    photos = ManyToManyField(Photo, related_name="albums", blank=True)
    creation_timestamp = DateTimeField(auto_now_add=True)
    cover_photo = ForeignKey(Photo, related_name="cover_photos")
    def __unicode__(self):
        return self.name

We then define a ModelForm based on the Album model, which allows users to create albums with photos they’ve previously uploaded (pretend we’ve already made that possible). We only expose the “name”, “caption” and “photos” fields because we’ll fill in the others automatically as part of our view:

?View Code PYTHON
1
2
3
4
class AlbumCreationForm(ModelForm):
    class Meta:
        model = Album
        fields = ("name", "caption", "photos")

Now here’s the real magic. Ordinarily, when first showing the form (pre-POST) we would create it like this and pass it to the template:

?View Code PYTHON
form = AlbumCreationForm()

The problem here is that by default we’ll get all photo objects, i.e. the result of “Photo.objects.all()”. That’s a problem because in this case we just want to list the photos belonging to the current user. To do this, just add the following line:

?View Code PYTHON
form.fields["photos"].queryset = Photo.objects.filter(user=request.user)

It turns out that form fields can be accessed as a dictionary attached to the form instance, and that if the field is model-related, like “photos” in the example, you can update its queryset dynamically.

Here’s a partial view which uses the last two code samples, to provide some context:

?View Code PYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
def create_album(request):
    if request.method == "POST":
        # Process form.
    else:
        form = AlbumCreationForm()
        # Get just the photos belonging to this user.
        form.fields["photos"].queryset = Photo.objects.filter(user=request.user)
 
    template_vars = RequestContext(request, {
        "form": form,
        "user": request.user
    })
    return render_to_response("create_album.html", template_vars)

That’s it! Adding the one extra line to the view gives us the filtering we need.

Language in the New Millennium

One of my passions has always been the articulate expression of oneself through language.  We have this wonderful, rich language we call English and there is great joy to be found in learning to use it effectively.  The point of this post isn’t to rant about the degradation of the language or our frequent abuse of it – I’ve covered that already – instead, I’d just like to talk about different ways of using the language in different contexts, and that I believe it doesn’t make sense to enforce strict, blanket rules across the board.

Spoken language

With the possible exception of presenting a formal talk or making a speech, I don’t believe we should be pedantic about spoken language.  People are all raised in different environments and have acquired their knowledge and techniques of language usage in different ways.  Everyone’s thought patterns also differ widely and speech is our way of converting those thoughts into a form that we can share with others.  I will never correct someone’s spoken language under any circumstances.  We need to respect each individual’s way of expressing themselves.

Written language

This is really the core of knowledge transfer and has formed the basis for accurate handing down of knowledge through the ages.  Thanks to the digital age this might change to include new mediums such as video, but for now we all still write a tremendous amount in various forms.

Attention to detail and careful thought are required to make sure that our thoughts are interpreted to the reader as clearly as we perceive them in our heads.  Even when writing a simple email there is something about sending away a piece of writing, to be read at the receiver’s leasure, that forces us to be more broad and accomodating with our choice of wording and sentence structure.  We are never quite sure what mood or state of mind the reader may be in when they read it.  Often we may never even have met the person.  This is vastly different to spoken language because when we’re speaking to someone, or even to a group of people, we can update our attitude and try different approaches in real time.

Text messaging, instant messaging, and services like Twitter technically form part of written language but based on their semi-live nature I treat them the same as spoken language.  I can’t help but still make at least a half decent attempt at proper spelling and grammar, but I don’t mind how casual people want to be as long as they’re able to get their point across.

Remember, the reason we have language is for communication.  As long as we can get our point across clearly and effectively then I think we’re doing just fine.