firstworks Programming with Rudiments using the Utility Classes

Programming with Rudiments using the Utility Classes

- Using the Command Line Class
- Using the Date/Time Class
- Using the Random Number Class
- Using the Text Class
- Using the Regular Expression Class
- Using the Signal Classes
- Using the Permissions Class
- Using the Shared Memory Class
- Using the Semaphore Set Class

Using the Command Line Class

Most programs take command line options in the option/value pair format:

program -option value -option value ...

The commandline class makes it easy to deal with command line options of this format. Below is some code illustrating the use of the commandline class.

    #include <rudiments/commandline.h>
    #include <iostream.h>
    #include <unistd.h>
    #include <stdlib.h>

    int     main(int argv, char **argc) {

            commandline     cmdline(argv,argc);

            if (cmdline.found("-help")) {
                    cout << "usage:  divide -divisor number -dividend number" << endl;
                    exit(0);
            }

            if (cmdline.found("-divisor") && cmdline.found("-dividend")) {
                    int     divisor=atoi(cmdline.value("-divisor"));
                    int     dividend=atoi(cmdline.value("-dividend"));
                    cout << divisor/dividend << endl;
            } else {
                    cout << "You must supply a divisor and a dividend." << endl;
            }
    }

Using the Date/Time Class

One of the most difficult things to do in a Unix environment is deal with dates and times. The "standard" functions and structures associated with dates and times are complex and vary widely from platform to platform. The datetime class attempts to rectify this situation. Below is some code illustrating the use of the datetime class.

    #include <rudiments/datetime.h>
    #include <iostream.h>

    main() {

            // get the current date
            datetime        dt;

            // Write out the different parts of the date.
            cout << "Hour                  :" << dt.getHour() << endl;
            cout << "Minutes               :" << dt.getMinutes() << endl;
            cout << "Seconds               :" << dt.getSeconds() << endl;
            cout << "Month                 :" << dt.getMonth() << endl;
            cout << "DayOfMonth            :" << dt.getDayOfMonth() << endl;
            cout << "DayOfWeek             :" << dt.getDayOfWeek() << endl;
            cout << "DayOfYear             :" << dt.getDayOfYear() << endl;
            cout << "Year                  :" << dt.getYear() << endl;
            cout << "Daylight Savings Time :" << dt.isDaylightSavingsTime();
            cout << endl;
            cout << "Time Zone             :" << dt.getTimeZone() << endl;
            cout << "Offset from GMT       :" << dt.getTimeZoneOffset() << endl;
            cout << "Date String           :" << dt.getString() << endl;
            cout << "Seconds since 1970    :" << dt.getEpoch() << endl;
    }

Using the Random Number Class

Functions for generating random numbers vary from platform to platform. The randomnumber class attempts to rectify this situation. Below is some code illustrating the use of the randomnumber class.

    #include <rudiments/datetime.h>
    #include <rudiments/randomnumber.h>
    #include <iostream.h>

    main() {

            // it's common to seed a random number generator with the number of
            // seconds since 1970 (the epoch), so we'll get the current date.
            datetime        dt;

            cout << "A random number between 0 and 2^32: ";
            cout << randomnumber::generateNumber(dt.getEpoch());
            cout << endl;

            cout << "A random number between 100 and 1000: ";
            cout << randomnumber::generateScaledNumber(dt.getEpoch(),100,1000);
            cout << endl;

            cout << "Another random number between 100 and 1000: ";
            int     basenumber=randomnumber::generateNumber(dt.getEpoch());
            int     scalednumber=randomnumber::scaleNumber(basenumber,100,1000);
            cout << scalednumber << endl;
    }

Using the Text Class

The text class contains some commonly needed text manipulation and evaluation functions. Below is some code illustrating the use of the text class.

    #include <rudiments/text.h>
    #include <iostream.h>
    #include <string.h>

    main() {

            // initialize a text buffer and print it out
            char    buffer[100];
            strcpy(buffer,"     hello      ");
            cout << "!" << buffer << "!" << endl;

            // trim the spaces off of the right hand side
            text::rightTrim(buffer);
            cout << "!" << buffer << "!" << endl;

            // trim the spaces off of the left hand side
            text::leftTrim(buffer);
            cout << "!" << buffer << "!" << endl;

            // convert buffer to uppercase
            text::upper(buffer);
            cout << "!" << buffer << "!" << endl;

            // convert buffer to lowercase
            text::lower(buffer);
            cout << "!" << buffer << "!" << endl;

            // http escape the buffer
            char    *escbuffer=text::httpEscape("!@#$%^&*()hello-+");
            cout << "!@#$%^&*()hello-+  http escaped is  " << escbuffer << endl;
            delete escbuffer;

            // evaluate a string to see if it's a number
            if (text::isNumber("-100.5")) {
                    cout << "-100.5 is a number" << endl;
            }
            if (!text::isNumber("-100.5.10")) {
                    cout << "-100.5.10 is not a number" << endl;
            }

            // evaluate a string to see if it's an integer
            if (text::isInteger("-100")) {
                    cout << "-100 is an integer" << endl;
            }
            if (!text::isInteger("-100.5")) {
                    cout << "-100.5.10 is not an integer" << endl;
            }
    }

Using the Regular Expression Class

Regular expressions allow a programmer to perform complex string matching but methods for using regular expressions vary from platform to platform. The regularexpression class attempts to rectify this situation. Below is some code illustrating the use of the regularexpression class.

    #include <rudiments/regularexpression.h>
    #include <iostream.h>

    main() {

            // A quick match...
            if (regularexpression::match("Hello Dave!",".*Dave.*")) {
                    cout << "The string contains .*Dave.*" << endl;
            }

            // If you need to match over and over...
            regularexpression       re(".*Dave.*");
            if (re.match("Hello Dave!")) {
                    cout << "The string contains .*Dave.*" << endl;
            }
            if (re.match("Goodbye Dave!")) {
                    cout << "The string contains .*Dave.*" << endl;
            }
            if (re.match("Dave is a jerk!")) {
                    cout << "The string contains .*Dave.*" << endl;
            }
            if (re.match("Dave writes cool software!")) {
                    cout << "The string contains .*Dave.*" << endl;
            }
            if (re.match("See ya later Dave!")) {
                    cout << "The string contains .*Dave.*" << endl;
            }

    }

Using the Signal Classes

Signals allow processes to interrupt the execution of other processes. Signal handlers allow processes to intercept and react to the signals sent to them.

Rudiments provides 3 classes for working with signals: signalset, signalmanager and signalhandler.

A signalset is just a collection of signals. The signalset class allows a programmer to build up a collection of signals.

The signalmanager class provides methods for sending signals, ignoring signals, waiting for signals and examining blocked signals.

The signalhandler class provides methods for catching and handling signals.

Below is some code illustrating the use of all three classes.

    #include <rudiments/signalclasses.h>
    #include <iostream.h>
    #include <unistd.h>

    void    handleSigusr1() {
            cout << "Got a SIGUSR1!" << endl;
    }

    main() {

            // this program will ignore all signals except SIGUSR1
            signalset       ignoreset;
            ignoreset.addAllSignals();
            ignoreset.removeSignal(SIGUSR1);
            signalmanager::ignoreSignals(ignoreset.getSignalSet());

            // when it gets a SIGUSR1, it will run the handleSigusr1() function
            signalhandler   shandler(SIGUSR1,(void *)&handleSigusr1);
            shandler.handleSignal();

            // Loop forever, each time waiting for a signal not in the ignoreset
            // to be sent. Since SIGUSR1 is the only signal not in the ignoreset,
            // waitForSignals will fall through only when SIGUSR1 is received.
            while(1) {
                    signalmanager::waitForSignals(ignoreset.getSignalSet());
            }
    }

Note that you'll have to kill that program with a -9.

Using the Permissions Class

The permissions class provides simple methods for generating permissions. The output of these methods can be used whenever a function takes an argument of type mode_t. Below is some code illustrating the use of the permissions class.

    #include <rudiments/permissions.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>

    main() {

            // Create a file with rw-r--r-- permissions
            int     fd=open("/tmp/tempfile",O_RDWR|O_CREAT,
                                    permissions::evalPermString("rw-r--r--"));

            // change the permissions to rw-rw-r--
            permissions::setFilePermissions(fd,
                                    permissions::evalPermString("rw-rw-r--"));

            // close and delete the file
            close(fd);
            unlink("/tmp/tempfile");

            // do the same as above using different methods
            fd=open("/tmp/tempfile",O_RDWR|O_CREAT,
                                    permissions::ownerReadWrite()|
                                    permissions::groupRead()|
                                    permissions::othersRead());
            permissions::setFilePermissions(fd,
                                    permissions::ownerReadWrite()|
                                    permissions::groupReadWrite()|
                                    permissions::othersRead());
            close(fd);
            unlink("/tmp/tempfile");
    }

Using the Shared Memory Class

Shared memory allows seperate processes to access a common block of memory. The standard functions and structures for managing shared memory segments are complex. The sharedmemory class attempts to rectify this situation. Below is some code illustrating the use of the sharedmemory class.

This program puts some data into shared memory then goes to sleep, giving another program time to access the segment.

    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <rudiments/sharedmemory.h>
    #include <rudiments/permissions.h>
    #include <unistd.h>
    #include <string.h>

    main() {
            sharedmemory    shm;
            shm.create(ftok("/tmp/shm",0),128,
                                    permissions::evalPermString("rw-------"));

            char    *shmptr=(char *)shm.getPointer();
            strcpy(shmptr,"This string is in shared memory.");

            sleep(1000);
    }

This program reads the data from shared memory.

    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <rudiments/sharedmemory.h>
    #include <rudiments/permissions.h>
    #include <iostream.h>

    main() {
            sharedmemory    shm;
            shm.attach(ftok("/tmp/shm",0));

            char    *shmptr=(char *)shm.getPointer();
            cout << shmptr << endl;
    }

There are other methods in the sharedmemory class that allow you to get and set user/group ownership and permissions of a segment but they are straightforward and rarely used.

Using the Semaphore Set Class

Semaphores allow seperate processes or threads to synchronize activities. The standard functions and structures for managing semaphores are complex. The sempahoreset class attempts to rectify this situation. Below is some code illustrating the use of the semaphoreset class.

The first program prints out 1 and 3, the second program prints out 2 and 4. They use a set of 2 semaphores to synchronize these activities. No matter what order the programs are started in, they will always print out

1
2
3
4
1
2
3
4
etc.

These programs must both be run to the background.

    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <rudiments/semaphoreset.h>
    #include <rudiments/permissions.h>
    #include <iostream.h>

    main() {

            int     vals[2]={0,1,};
            semaphoreset *sem=new semaphoreset();
            sem->create(ftok("/tmp/sem",0),2,vals,
                                    permissions::evalPermString("rw-------"));

            for (int i=0; i<10; i++) {
                    sem->wait(0);
                    cout << "2" << endl;
                    sem->signal(1);

                    sem->wait(0);
                    cout << "4" << endl;
                    sem->signal(1);
            }

            delete sem;
    }

    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <rudiments/semaphoreset.h>
    #include <rudiments/permissions.h>
    #include <iostream.h>

    main() {

            semaphoreset *sem=new semaphoreset();
            sem->attach(ftok("/tmp/sem",0),2);

            for (int i=0; i<10; i++) {
                    sem->wait(1);
                    cout << "0" << endl;
                    sem->signal(0);

                    sem->wait(1);
                    cout << "1" << endl;
                    sem->signal(0);
            }

            delete sem;
    }