Voting

Category

real language

Bookmarking

Del.icio.us Digg Diigo DZone Earthlink Google Kick.ie
Windows Live LookLater Ma.gnolia Reddit Rojo StumbleUpon Technorati

Language C

(Linux kernel module)

Date:08/02/05
Author:Stefan Scheler
URL:http://sts.synflood.de/
Comments:15
Info:http://www.tldp.org/LDP/khg/HyperNews/get/khg.html
Score: (3.06 in 289 votes)
/*  The 99 Bottles of Beer Linux Kernel Module v1.1
 *  (supports multiple driver instances)
 *
 *  by Stefan Scheler <sts[at]synflood[dot]de>
 *  August 2nd, 2005 - Ernstthal, Germany
 *
 *  Usage:
 *  1) compile the module
 *  2) create the device: mknod /dev/bottles c 240 0
 *  3) load the module: insmod bottles.ko
 *  4) print the song with: cat /dev/bottles
 */

#include <linux/fs.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <asm/uaccess.h>

#define DRIVER_MAJOR 240
#define BUFFERSIZE 160
#define PLURALS(b) (b>1)?"s":""

MODULE_AUTHOR("Stefan Scheler <sts[at]synflood[dot]de>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("The 99 Bottles of Beer Linux Kernel Module");
MODULE_SUPPORTED_DEVICE("Bottle of Beer");

struct _instance_data {
    int bytes_avail, bytes_sent, bottles;
    char buf[BUFFERSIZE];
};

static void fill_buffer(char *buf, int b) {
    char line[BUFFERSIZE/2];
    if (b>0) {
        sprintf(buf, "%d bottle%s of beer on the wall, %d bottle%s of beer.\n" \
                     "Take one down and pass it around, ", b, PLURALS(b), b, PLURALS(b));
        if (b==1)
            strcat(buf, "no more bottles of beer on the wall.\n");
        else {
            sprintf(line, "%d bottle%s of beer on the wall.\n", b-1, PLURALS(b-1));
            strcat(buf, line);
        }
    } else {
        sprintf(buf, "No more bottles of beer on the wall, no more bottles of beer.\n" \
                     "Go to the store and buy some more, 99 bottles of beer on the wall.\n");
    }
}

static ssize_t driver_read(struct file *instance, char *userbuffer, size_t count, loff_t *offset) {
    struct _instance_data *iptr = (struct _instance_data *)instance->private_data;

    int to_copy;
    int not_copied;

refillbuffer:
    fill_buffer(iptr->buf, iptr->bottles);
    iptr->bytes_avail = strlen(iptr->buf)+1;
    to_copy = iptr->bytes_avail-iptr->bytes_sent;

    if (to_copy>0) {
        if (to_copy> count) to_copy=count;
        not_copied=copy_to_user(userbuffer, iptr->buf+iptr->bytes_sent, to_copy);
        iptr->bytes_sent += to_copy-not_copied;
        return (to_copy-not_copied);
    }

    if ((to_copy==0) && (iptr->bottles>0)) {
        iptr->bytes_sent=0; 
        iptr->bottles--;
        goto refillbuffer;
    }

    return 0;
}

int driver_open(struct inode *devicefile, struct file *instance)  {
    struct _instance_data *iptr;
    iptr = (struct _instance_data *)kmalloc(sizeof(struct _instance_data), GFP_KERNEL);
    
    if (!iptr) 
        return -1;

    iptr->bytes_sent = 0;
    iptr->bottles = 99;
    instance->private_data = iptr;

    return 0;
}

int driver_close(struct inode *devicefile, struct file *instance)  {
    if (instance->private_data)
        kfree(instance->private_data);
    return 0;
}

static struct file_operations fops = {
    .owner   = THIS_MODULE,
    .open    = driver_open,
    .release = driver_close,
    .read    = driver_read,
};

static int __init __init_module(void) {
    if(register_chrdev(DRIVER_MAJOR, "99 Bottles of Beer", &fops) == 0) 
        return 0;
    return -EIO;
}

static void __exit __cleanup_module(void) {
    unregister_chrdev(DRIVER_MAJOR, "99 Bottles of Beer");
}

module_init(__init_module);
module_exit(__cleanup_module);

Download Source | Write Comment

Alternative Versions

VersionAuthorDateCommentsRate
actually produces correct lyrics :PDustshine08/20/050
multithreaded versionStefan Scheler05/11/054
Correct ANSI C containing no semicolonsSteve Checkoway01/15/090
poor StyleMatteo Casati09/01/056
standard versionBill Wein04/20/054

Comments

>>  Rune Berge said on 08/03/05 00:55:56

Rune Berge Ha ha! I love it. Great idea :)

>>  blueaura said on 08/03/06 04:39:02

blueaura isn't there a bug in fill_buffer? if b=2, won't the code

if (b==1)
strcat(buf, "no more bottles of beer on the wall.\n";);
else {
sprintf(line, "%d bottle%s of beer on the wall.\n", b-1, PLURALS);
strcat(buf, line);printk("size %d\n", sizeof(struct _instance_data *));
}

print

"1 bottles of beer on the wall."

since b=2, so b-1 = 1, but the PLURALS macro uses b.

>>  Stefan Scheler said on 08/05/06 16:26:39

Stefan Scheler Yeah, you're right. That's a bug. Hopefully fixed now.

>>  david said on 03/16/07 17:41:50

david I have my own version (to prove anything can be written in a line of C (and then broken into several lines so it can be edited in a terminal (using pico, of course...)))

#include <stdio.h>
int main(){int i=100;while(--i){printf("%i bottle%s of beer in the wall,\n%i bottle%s of beer.\nTake one down, p"
"ass it round,\n""%s%s\n\n",i,i?"s":"",i,i?"s":"",(i-1)?(char[]){(((i-1)/10)?((i-1)/10+'0'):((i-1)%10+'0')),(((i-
1)/10)?((i-1)%10+'0'):' '),(((i-1)/10)?' ':'{TEXT}'),'{TEXT}'}:"",(i-1)?"bottles of beer in the wall":"No more beers");}}

>>  david said on 03/16/07 17:42:51

david Sorry, that code should have been:

#include <stdio.h>
int main(){int i=100;while(--i){printf("%i bottle%s of beer in the wall,\n%i bo"
"ttle%s of beer.\nTake one down, pass it round,\n""%s%s\n\n",i,i?"s":"",i,i?"s":
"",(i-1)?(char[]){(((i-1)/10)?((i-1)/10+'0'):((i-1)%10+'0')),(((i-1)/10)?((i-1)%
10+'0'):' '),(((i-1)/10)?' ':'{TEXT}'),'{TEXT}'}:"",(i-1)?"bottles of beer in the wall":
"No more beers");}}

>>  Vipul said on 04/24/07 05:35:39

Vipul Makefile for interested ppl :D (assuming your file is called beer.c)
<pre>
ifneq ($(KERNELRELEASE),)
obj-m := beer.o

else
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
endif
</pre>

>>  Russell said on 09/10/07 03:17:42

Russell Cool stuff!!!

>>  MOSFET said on 04/20/08 15:43:24

MOSFET I don't understand why people write comments to such an uncommon language... I thought C was a letter.

>>  Don said on 04/26/08 00:23:19

Don Wow. And people say that Cobol is verbose!!

>>  Matt said on 04/13/09 09:00:06

Matt Uncommon language are you kidding?

>>  partha said on 09/03/09 12:38:24

partha Nice Joke
C is an Uncommon language

>>  ken dakin said on 11/13/09 13:46:08

ken dakin This very verbose example could be replaced by a few lines of assembler much more efficiently (and clearly).

>>  Ruslan said on 11/29/09 02:34:59

Ruslan This couldn't be replaced by assembler because of portability.
This couldn't be much shorter because it's kernel module.

>>  Romko said on 02/11/10 21:14:43

Romko And it could be replaced by a few lines of C =)

>>  Russian Perler said on 03/05/10 19:03:21

Russian Perler Nice program.

C is uncommon?! That is so wrong! :D

C will never die! :)

Download Source | Write Comment

Add Comment

Please provide a value for the fields Name, Comment and Security Code.
This is a gravatar-friendly website.
E-mail addresses will never be shown.
Enter your e-mail address to use your gravatar.

Please don't post large portions of code here! Use the form to submit new examples or updates instead!

Name:

eMail:

URL:

Security Code:
  
Comment: