Wednesday, October 20, 2010

UCM with SVN

This article describes how to apply UCM with the SVNVCS.

Contents

  • Introduction
    • About VCS
    • About ITS
    • About UCM
    • About SVN
  • How to perform UCM using SVN
    • Projects
    • Streams
    • Components
    • Issue Tracking

Introduction

Proper change tracking and version control is vital for the success of any software project. This article describes the UCM approach to change control and how to implement it using SVN.

About VCS

Version Control Systems are vital for the success of any software project. Programmers must have possibilities to experiment with new ideas without impacting other team members and general development. Changes should be thoroughly tested before they are delivered to a common code base. It must be possible to see when and by whome each change to the software was introduced.
More elaborate environments require even more. Different variants of a product must be developed independently of each other. For instance, while one subteam is preparing the current code for a release and polishes away the last known bugs, another team at the same time continues development for a new version. Changes by the development team shouldn't affect the release team.
A relatively new approach requires that different variants of a product are made up of different components, which are tracked individually by the version control system. This is component based version control.

About ITS

Issue Tracking Systems, also known as Bugtrackers or Change Request Managers (there are slight differences between these terms which are out of scope of this document), allow developers and other participants in projects, like project managers, trackers, testers and quality assurance, to track the state about issues like open bugs or requested features.

About UCM

Unified Change Management is a relatively young approach to version control. It's main attributes are:
  • Stream-oriented development and integration
  • Activities
  • Component oriented version control
  • Close coupling with an issue tracking system
UCM gained much popularity in the context of IBM Rational ClearCase UCM, which is an extension of ClearCase to support the UCM approach of version control.

About SVN

Subversion is a light-weight VCS meant to replace CVSCVS was the most popular VCS in open source development for a very long period of time. CVS is very easy to handle and for a version control system easy to understand. Besides that CVS also is extremely fast, in LAN environments as well as in WAN environments. Even over the Internet, CVS is very fast.
As a replacement for CVSSVN is meant to provide all positive features of CVS as well as several new features. Apart from being more modern in supporting versioning of directories and file attributes, SVN provides three main attributes / advantages over CVS which also significantly differ SVN from most other VCS:
Versions are applied to the repository, not single files or directories.
This makes it extremely easy to identify all matching files and directories for a specific version of a particular file.
SVN has cheap copies.
The cheap copy mechanism replaces previous mechanisms for branching, tagging or labelling. A cheap copy is a copy of a whole directory tree made inside the repository. Branches, tags and labels are implemented using these cheap copies. The cheap copies are named cheap because creating a cheap copy is an operation with very very little overhead. It's nothing else like "I'm a copy of path/to/foo revision n".
This also means that in SVN, attributes like branches, labels or tags merely are directories. This leaves much individual flexibility on how to organize version management to the projects, they can adapt it on their needs.
svn:externals
svn:externals is a property which allows to link to other repositories or other locations in the same repository.

How UCM works in general

First of all, development is no longer parted in a main branch plus lots of changes to it, but changes are grouped in multiple ways. All changes that together make up a single feature or bug fix or similar group are grouped as "activity". An activity appears as issue item in the issue tracker, that means an activity is associated with an issue tracker item and vice versa. Activities are performed on a development stream, which is a copy of the integration stream, and then "delivered" (merged) into that integration stream.

Original UCM concepts

This subchapter describes the original UCM concepts as they were applied in ClearCase UCM. The goal is to be able to apply UCM with any version control system, particularly Subversion. For that, it is necessary to understand the intentions of UCM and its concepts, and why it is implemented in ClearCase the way it is.

ClearCase limitations

ClearCase is a very old-fashioned version control system. Basically ClearCase is RCS with improved multi-user and directory support, a network file system (as if there weren't already enough of them) and database backend. The elementary concepts staid the same over time. That means:
  • Revisions are done on a per-element basis.
  • There is no low-level support for atomic changesets.
  • Conflicts are prevent with locking (reserved checkout).
ClearCase UCM is built on top of ClearCase. ClearCase UCM has to take into account these limitations and live with them. ClearCase UCM has to hide these limitations.

ClearCase UCM glossary

Activity
An activity is a group of changes that belong together. Purpose:
  • They link changes together, putting single checkout / checkin operations into the context of a group called Activity.
  • They link changes with an issue tracker.
Baseline
A baseline is a consistent version state of a component. Purpose:
  • Keep those revisions of files and directories together which belong together.
Component
A component is a group of files and directories which are managable as single unit to be baselined. Purpose:
  • Keep those files and directories together which belong together.
Composite baseline
A composite baseline is the combination of multiple baselines from several components. Usually, a project has a composite baseline which sums up the baselines for all participating components. Purpose:
  • Keep those revisions of components in a project together which belong together.
Delivery
Delivery is the operation of merging changes from a child Stream to a parent Stream (usually the Integration Stream). Purpose:
  • Perform merges on groups of files and directories instead of single files and directories.
  • Keep changesets together.
Integration Stream
An Integration Stream is a Stream with child streams. For a Project, at least one Stream exists, which is its Integration Stream. Purpose:
  • Have a branch on which all changes that are mature enough are available.
Project
A Project is a configuration of an Integration Stream and participating components in specific baselines. A project is configured by a composite baseline. Purpose:
  • Prevent conflicts between different development goals of different projects.
  • Allow the selection of components from a pool.
Rebase
Rebase is the operation of copying changes from a parent Stream (usually the Integration Stream) to a child Stream. Purpose:
  • Perform merges on groups of files and directories instead of single files and directories.
  • Keep changesets together.
Stream
A Stream is an isolated branch of development. Unless it is an integration Stream, a Stream always has a parent. Activities will only affect the stream for which they were performed. Streams are actively synchronized with each other by explicit Delivery and Rebase operations. Purpose:
  • Allow changes under version control but in a controlled manner.
  • Keep changesets together.

Putting UCM on a more abstract level

Many of the concepts which ClearCase UCM puts on top of ClearCase are only explicitely necessary to cope with the limitations of ClearCase. To be able to apply UCM with any version control system, it is necessary to understand the intentions of UCM and its concepts, and why it is implemented in ClearCase the way it is.
Goals on an abstract level:
  • Developers shall be able to perform changes without interfering with other developers.
  • Changes shall be controlled and tracked.
  • Projects shall be setup in a way that they are built on reusable components.
  • The reusable components shall be setup in a way that allows changing them without interfering with other projects.

Simple mapping UCM between ClearCase UCM and Subversion

For most of what is done with ClearCase UCM, the following simple mapping may already be sufficient.
GoalClearCase UCMSubversion
Atomic changesets (small changes)Activitycommit
Atomic changesets (large changes)Activitydirectory copy, merge
Consistent revisionsBaselineimplicit (path + repository revision)
Reusable file groupComponentdirectory copy
Consistent project versionComposite baselineimplicit (path + repository revision)
Integrate developer work (small change)Deliverycommit
Integrate developer work (large change)Deliverymerge --reintegrate
Mature main branchIntegration Streamimplicit (e.g. policy for trunk)
Consistent overall setupProjectdirectory
Up-to-date developer copy (small change)Rebaseupdate
Up-to-date developer copy (large change)Rebasemerge
Create place for independent developer work (small change)create Streamcheckout
Create place for independent developer work (large change)create Streamdirectory copy
Just like having no concept of tags and labels, or branches, Subversion has no concept projects, components, streams and activities. Actually, that's good news. The concept of Subversion is to work with cheap copies. Originally, cheap copies were designed to be the Subversion approach to tagging and branching. Interestingly, the more abstract approach of cheap copies is not only a simple yet superior way to resemble tags and labels, and branches. It also is a simple way to resemble projects, components, streams and activities.
At this point, let me also have a word on whether you should have one large repository or multiple small repositories. Subversion is significantly faster than ClearCase. And because commits are path-based, it can use path-based transaction isolation. That means multiple proceses can safely work on the same repository at the same time. They will only delay each other if they affect the same path.
Also, projects like KDE show that it's possible to use Subversion for very large development projects with large development teams. At the time of this writing, the KDE subversion repository was at revision 969346.

How to perform UCM using ClearCase

As already mentioned above, there's a special version of ClearCase called ClearCase UCM. When applying UCM with ClearCase, you'll notice the following things:
  • Working with ClearCase when the server is offline is near impossible.
  • Dynamic views don't work with the server being offline.
  • Snapshot views work with the server being offline, but this is very limited. Even restoring a file to its original version requires server access.
  • VOB symbolic links don't work properly with snapshot views.
  • Over WANs / Internet and VPNs, ClearCase is awfully slow.
  • When you're working on your own stream anyway, you'll begin to ask yourself why this obsolete checkin / checkout locking mechanism is still required.
  • ClearCase will create new file revisions of all files you've touched, even if you don't actively create new versions. A file, once touched, will grow new versions for every rebase you perform.
  • Activities are somehow lost once they're integrated. They are visible on the development stream but they don't become visible on the integration stream. Instead, Deliveries and Rebases appear as separate activities. The faster the development process, the higher the percentage of these artificial pseudo-activities compared to real development activities.

How to perform UCM using SVN

Most of the UCM concepts can be provided by directories and cheap copies in SVN: projects, components, streams and, if you want to, activities. That means the implementation of UCM on top of Subversion is very flexible. It requires only little discipline, so no additional scripts should be required. Also, subversion is much more likely to forgive errors or mistakes in the setup. And it's easy to restructure the repository afterwards, so you can even turn a non-UCM-repository into a UCM-repository.
The flexibility of Subversion also means that the following is just one out of many possible ways to implement UCM on top of Subversion.

Original Subversion approach: TTB

  • /
    • trunk/
    • tags/
    • branches/
This is the original subversion approach, also known as TTB structure. It already has a lot in common with UCM. Small development activities are separated by commits, large development activities can be performed on separate branches.

Single project / component approach

  • /
    • trunk/
    • tags/
    • branches/
    • streams/ (← This is new compared to the classical approach in subversion)
This is a slightly modified approach, which I call TTBS (you guessed ;-). It separates streams / developer branches from (release) branches.

Distinct Multi-Project approach

  • /
    • projectname
      • trunk/
      • tags/
      • branches/
      • streams/ (← This is new compared to the classical approach in subversion)
Often, multiple projects shall be supported in the same repository. For that, it is a good idea (and common practice) to have the projects on top level and the TTB(S) structure below that.
If your component model works on mature objects only, which is the case for many Java projects, this is enough: If one project depends on the other, it waits for a release (.jar, .war, .ear or so).
However, in some development environments, it takes days or even weeks for a project to make a release for just one minor change. In such an environment, if project A depends on project B, project A might be better off with a copy of project B. That's the next approach.

Establish Reuse

Reuse means to have something available which was created elsewhere. For reuse, subversion offers two possibilities, both of which work fine on directories (and single files, if wanted):
  • cheap copies
  • svn:externals
If you want to reuse something in an unchanged form, the best way of doing that is using svn:externals. If you want to change it, the best way of doing that is using cheap copies (svn cp).

Separate component / project approach

  • /
    • projects/
      • projectname
        • trunk/
        • tags/
        • branches/
        • streams/
    • components/
      • componentname
        • trunk/
        • tags/
        • branches/
        • streams/
A component can be made visible anywhere within a project, either as cheap copy or as external.

How to apply UCM to SVN - The Commands

Creating a Project or Component

As a project or component is just a directory, it's created like trunk: Create the directory, if you start from scratch, or import something that you already have.

Creating a Stream

To create a Stream, create a copy from what you want to create a stream for, and place that copy in streams/.
Synopsis: svn cp parentPath streams/streamName
Example stream from trunk: svn cp -m "Creating Stream barBuzz." http://svn.mynet.local/projectFoo/trunk http://svn.mynet.local/projectFoo/streams/barBuzz

Rebasing a Stream

Starting with Subversion 1.5, rebasing a stream becomes very simple. Use the svn merge command for that.
Synopsis: svn merge parentPath
Example: cd barBuzz; svn merge http://svn.mynet.local/projectFoo/trunk

Delivering a Stream

First you rebase your stream to make sure you deliver a consistent set. Then you go to trunk and deliver using the svn merge --reintegrate command.
Synopsis: cd parentPath ; svn merge --reintegrate streams/streamName
Example: cd ../../trunk ; svn merge --reintegrate http://svn.mynet.local/projectFoo/streams/barBuzz
Once the deliver merge is done, check the delivery and if everything is okay, complete it by performing a commit.
As soon as the delivery is done, the stream should be removed. It is neither possible nor desired from a subversion point of view to reuse a stream once a delivery is done. If you want to continue working on that stream after the delivery, like some developers do in ClearCase UCM, just recreate the stream after deleting it.

Removing a Stream

To remove a stream, simply delete the stream like a normal directory. Removing a stream will not reduce the server load, it will just make the stream invisible, nothing more.

Example

This chapter describes an example of how development could work, and it also shows how a subversion repository can be transformed to the different parts of UCM as needed.
The beginning is an application called "JEduca", an application for creating and running tests based on multiple choice questions. The developers are Alice, Bob and Charly.
Alice creates a repository for them:

svnadmin create /home/alice/svnroot

The developers that begin to work on JEduca, execute:

mkdir ~/svn
cd ~/svn
svn checkout file:///home/alice/svnroot JEduca

Whenever they want to access changes that the others made, they perform a rebase:

svn up

Whenever they have finished an activity, they perform a delivery:

svn commit -m "Activity description."

After a few days, Alice and Bob want to create the first release, while Charly wants to continue working on new features. They decide it's time for a branch. Prior to branching they have to perform a small change to the repository and make it ready for branches: Bob executes:

files=$(echo *)
svn mkdir trunk tags branches
svn mv $files trunk/
svn commit -m "Created TTB structure."

The sandboxes now have should be relocated to trunk, because the position of trunk has virtually changed.
Now that the repository is raedy for branches, Bob creates the branch for the 0.1 release:

svn cp -m "Create release branch for 0.1." file:///home/alice/svnroot/trunk file:///home/alice/svnroot/branches/0.1

The story continues with the next update.

Friday, October 15, 2010

Multi-dimensional Arrays in PERL

Since the advent of reference data type in PERL, it is now relatively easy to create multi-dimensional arrays.

Each element in an array must be scalar. Therefore, the following array is NOT an 2-D array, but actually is a 1-D array.

@onedarray = ((1,2,3),(4,5,6));
which is the same as @onedarray = (1,2,3,4,5,6);

Reference is actually a scalar that points to another data including an array. For example, $ref1 is a reference that points to an array. $ref2 is also a reference that points to another array.

$ref1 = [1,2,3];
$ref2 = [4,5,6];

Now to construct a 2-D array, we can use those two references as follows.

@twodarray = ($ref1,$ref2);

Or as a short cut, we could have used anonymous references. That is, we didn't need to explicitly declare the references before using them such as this.

@twodarray = ([1,2,3],[4,5,6]);

To read an element in the 2-D array, we use subscripts:

print $twodarray[0][0];

will print the content of the first element in the first array, which is 1.

print $twodarray[0][2];

will print the content of the third element in the first array, which is 3.

print $twodarray[1][2];

will print the content of the third element in the second array, which is 6.

We can explore further by creating 3-D array.

For example,

@threedarray = ([[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]);

print $threedarray[0][1][2];
will print 6.

Thursday, June 24, 2010

Character Pointers and Functions

page 104
Since text strings are represented in C by arrays of characters, and since arrays are very often manipulated via pointers, character pointers are probably the most common pointers in C.
Deep sentence:
C does not provide any operators for processing an entire string of characters as a unit.
We've said this sort of thing before, and it's a general statement which is true of all arrays. Make sure you understand that in the lines
char *pmessage;
 pmessage = "now is the time";
 pmessage = "hello, world";
all we're doing is assigning two pointers, not copying two entire strings.
At the bottom of the page is a very important picture. We've said that pointers and arrays are different, and here's another illustration. Make sure you appreciate the significance of this picture: it's probably the most basic illustration of how arrays and pointers are implemented in C.
We also need to understand the two different ways that string literals like "now is the time" are used in C. In the definition
char amessage[] = "now is the time";
the string literal is used as the initializer for the array amessageamessage is here an array of 16 characters, which we may later overwrite with other characters if we wish. The string literal merely sets the initial contents of the array. In the definition
char *pmessage = "now is the time";
on the other hand, the string literal is used to create a little block of characters somewhere in memory which the pointer pmessage is initialized to point to. We may reassign pmessage to point somewhere else, but as long as it points to the string literal, we can't modify the characters it points to.
As an example of what we can and can't do, given the lines
char amessage[] = "now is the time";
 char *pmessage = "now is the time";
we could say
amessage[0] = 'N';
to make amessage say "Now is the time". But if we tried to do
pmessage[0] = 'N';
(which, as you may recall, is equivalent to *pmessage = 'N'), it would not necessarily work; we're not allowed to modify that string. (One reason is that the compiler might have placed the ``little block of characters'' in read-only memory. Another reason is that if we had written
char *pmessage = "now is the time";
 char *qmessage = "now is the time";
the compiler might have used the same little block of memory to initialize both pointers, and we wouldn't want a change to one to alter the other.)
Deep sentence:
The first function is strcpy(s,t), which copies the string t to the string s. It would be nice just to say s=t but this copies the pointer, not the characters.
This is a restatement of what we said above, and a reminder of why we'll need a function, strcpy, to copy whole strings.
page 105
Once again, these code fragments are being written in a rather compressed way. To make it easier to see what's going on, here are alternate versions of strcpy, which don't bury the assignment in the loop test. First we'll use array notation:
void strcpy(char s[], char t[])
 {
  int i;
  for(i = 0; t[i] != '\0'; i++)
   s[i] = t[i];
  s[i] = '\0';
 }
Note that we have to manually append the '\0' to s after the loop. Note that in doing so we depend upon i retaining its final value after the loop, but this is guaranteed in C, as we learned in Chapter 3.
Here is a similar function, using pointer notation:
void strcpy(char *s, char *t)
 {
  while(*t != '\0')
   *s++ = *t++;
  *s = '\0';
 }
Again, we have to manually append the '\0'. Yet another option might be to use a do/while loop.
All of these versions of strcpy are quite similar to the copy function we saw on page 29 in section 1.9.
page 106
The version of strcpy at the top of this page is my least favorite example in the whole book. Yes, many experienced C programmers would write strcpy this way, and yes, you'll eventually need to be able to read and decipher code like this, but my own recommendation against this kind of cryptic code is strong enough that I'd rather not show this example yet, if at all.
We need strcmp for about the same reason we need strcpy. Just as we cannot assign one string to another using =, we cannot compare two strings using ==. (If we try to use ==, all we'll compare is the two pointers. If the pointers are equal, they point to the same place, so they certainly point to the same string, but if we have two strings in two different parts of memory, pointers to them will always compare different even if the strings pointed to contain identical sequences of characters.)
Note that strcmp returns a positive number if s is greater than t, a negative number if s is less than t, and zero if s compares equal to t. ``Greater than'' and ``less than'' are interpreted based on the relative values of the characters in the machine's character set. This means that 'a' < 'b', but (in the ASCII character set, at least) it also means that 'B' < 'a'. (In other words, capital letters will sort before lower-case letters.) The positive or negative number which strcmp returns is, in this implementation at least, actually the difference between the values of the first two characters that differ.
Note that strcmp returns 0 when the strings are equal. Therefore, the condition
if(strcmp(a, b))
  do something...
doesn't do what you probably think it does. Remember that C considers zero to be ``false'' and nonzero to be ``true,'' so this code does something if the strings a and b are unequal. If you want to do something if two strings are equal, use code like
if(strcmp(a, b) == 0)
  do something...
(There's nothing fancy going on here: strcmp returns 0 when the two strings are equal, so that's what we explicitly test for.)

To continue our ongoing discussion of which pointer manipulations are safe and which are risky or must be done with care, let's consider character pointers. As we've mentioned, one thing to beware of is that a pointer derived from a string literal, as in
char *pmessage = "now is the time";
is usable but not writable (that is, the characters pointed to are not writable.) Another thing to be careful of is that any time you copy strings, using strcpy or some other method, you must be sure that the destination string is a writable array with enough space for the string you're writing. Remember, too, that the space you need is the number of characters in the string you're copying, plus one for the terminating '\0'.
For the above reasons, all three of these examples are incorrect:
char *p1 = "Hello, world!";
 char *p2;
 strcpy(p2, p1);  /* WRONG */


char *p = "Hello, world!";
 char a[13];
 strcpy(a, p);  /* WRONG */


char *p3 = "Hello, world!";
 char *p4 = "A string to overwrite";
 strcpy(p4, p3);  /* WRONG */
In the first example, p2 doesn't point anywhere. In the second example, a is a writable array, but it doesn't have room for the terminating '\0'. In the third example, p4 points to memory which we're not allowed to overwrite. A correct example would be
char *p = "Hello, world!";
 char a[14];
 strcpy(a, p);
(Another option would be to obtain some memory for the string copy, i.e. the destination for strcpy, using dynamic memory allocation, but we're not talking about that yet.)
page 106 continued (bottom)
Expressions like *p++ and *--p may seem cryptic at first sight, but they're actually analogous to array subscript expressions like a[i++] and a[--i], some of which we were using back on page 47 in section 2.8.


http://www.eskimo.com/~scs/cclass/krnotes/sx8e.html

Is a string literal in c++ created in static memory?

Where it's created is an implementation decision by the compiler writer, really. Most likely, string literals will be stored in read-only segments of memory since they never change.

In the old compiler days, you used to have static data like these literals and global but changeable data. These were stored in the TEXT (code) segment and BSS (initialized data) segment.

Even when you have code like char *x = "hello";, the hello string is stored in read-only memory while the variable x is on the stack (or writable memory at global scope). x just gets set to the address of the hello string. This allows all sorts of tricky things like string folding, so that "invalid option" (0x1000) and "valid option" (0x1002) can use the same memory block as follows:

0x1000 invalid option\0
Keep in mind I don't mean read-only memory in terms of ROM, just memory that's dedicated to storing unchangeable stuff (which may be marked really read-only by the OS).

They're also never destroyed until main() exits.

Source: http://stackoverflow.com/questions/349025/is-a-string-literal-in-c-created-in-static-memory

Tuesday, June 22, 2010

Shell Loop Interaction with SSH

A flawed method to run commands on multiple systems entails a shell while loop over hostnames, and a Secure Shell (SSH) connection to each system. However, the default standard input handling of ssh drains the remaining hosts from the while loop:
#!/bin/sh

# run hostname command on systems listed below; will only work for
# the first host
while read hostname; do
ssh $hostname hostname
done <
example.com
example.org
EOF
The hostname command will only be run on the first host connected to, as ssh will pass the remaining hostnames in the while loop to hostname as standard input. hostname ignores this input silently, and the while loop then exits, as no hosts remain to connect to.
Any command that reads from standard input will consume the rest of the items to loop over, as illustrated below using the cat command.
#!/bin/sh

while read line; do
echo "line: $line"
cat
done <
foo
bar
zot
EOF
The cat should print the remaining items of the loop to standard output, as by default it reads from standard input.
$ sh test
line: foo
bar
zot
To avoid this problem, alter where the problematic command reads standard input from. If no standard input need be passed to the command, read standard input from the special/dev/null device:
#!/bin/sh

while read hostname; do
ssh $hostname hostname < /dev/null
done <
example.com
example.org
EOF
Another option: use the -n option to ssh, which prevents ssh from reading from standard input:
ssh -n $hostname hostname
However, sometimes standard input must be passed to the remote system, for example when listing, editing, then updating crontab(5) data. The first ssh instance disables passing standard input, while the second does not, as the updated crontab(5) data is passed via standard input over ssh:
while read hostname; do
ssh -n $hostname crontab -l | \
grep -v rdate | \
ssh $hostname crontab -
done

Alternatives & Caveats

  • for loop - a common alternative, and perhaps useless use of cat, instead loops over the hostnames via for host in `cat hostlist`; …. Beware extraneous IFS related data in the file, though this should not be a concern for hostnames.
  • $ echo -n $IFS | od -bc 0000000 040 011 012 000 \t \n \0 0000004
  • while loops will not process the last line, if the file does not end with a newline. This is a risk if the hostname list origniates on a foreign system, or via any editor that does not enforce the traditional unix requirement that files end with a trailing newline.


Source: http://sial.org/howto/shell/while-ssh/

Thursday, June 17, 2010

Pointers to Pointers in C

Since we can have pointers to int, and pointers to char, and pointers to any structures we've defined, and in fact pointers to any type in C, it shouldn't come as too much of a surprise that we can have pointers to other pointers. If we're used to thinking about simple pointers, and to keeping clear in our minds the distinction between the pointer itself and what it points to, we should be able to think about pointers to pointers, too, although we'll now have to distinguish between the pointer, what it points to, and what the pointer that it points to points to. (And, of course, we might also end up with pointers to pointers to pointers, or pointers to pointers to pointers to pointers, although these rapidly become too esoteric to have any practical use.)
The declaration of a pointer-to-pointer looks like
int **ipp;
where the two asterisks indicate that two levels of pointers are involved.
Starting off with the familiar, uninspiring, kindergarten-style examples, we can demonstrate the use of ipp by declaring some pointers for it to point to and some ints for those pointers to point to:
int i = 5, j = 6; k = 7;
 int *ip1 = &i, *ip2 = &j;
Now we can set
ipp = &ip1;
and ipp points to ip1 which points to i*ipp is ip1, and **ipp is i, or 5. We can illustrate the situation, with our familiar box-and-arrow notation, like this:

If we say
*ipp = ip2;
we've changed the pointer pointed to by ipp (that is, ip1) to contain a copy of ip2, so that it (ip1) now points at j:

If we say
*ipp = &k;
we've changed the pointer pointed to by ipp (that is, ip1 again) to point to k:


What are pointers to pointers good for, in practice? One use is returning pointers from functions, via pointer arguments rather than as the formal return value. To explain this, let's first step back and consider the case of returning a simple type, such as int, from a function via a pointer argument. If we write the function
f(int *ip)
 {
  *ip = 5;
 }
and then call it like this:
int i;
 f(&i);
then f will ``return'' the value 5 by writing it to the location specified by the pointer passed by the caller; in this case, to the caller's variable i. A function might ``return'' values in this way if it had multiple things to return, since a function can only have one formal return value (that is, it can only return one value via the return statement.) The important thing to notice is that for the function to return a value of type int, it used a parameter of type pointer-to-int.
Now, suppose that a function wants to return a pointer in this way. The corresponding parameter will then have to be a pointer to a pointer. For example, here is a little function which tries to allocate memory for a string of length n, and which returns zero (``false'') if it fails and 1 (nonzero, or ``true'') if it succeeds, returning the actual pointer to the allocated memory via a pointer:
#include 

 int allocstr(int len, char **retptr)
 {
  char *p = malloc(len + 1); /* +1 for \0 */
  if(p == NULL)
   return 0;
  *retptr = p;
  return 1;
 }
The caller can then do something like
char *string = "Hello, world!";
 char *copystr;
 if(allocstr(strlen(string), &copystr))
  strcpy(copystr, string);
 else fprintf(stderr, "out of memory\n");
(This is a fairly crude example; the allocstr function is not terribly useful. It would have been just about as easy for the caller to call malloc directly. A different, and more useful, approach to writing a ``wrapper'' function aroundmalloc is exemplified by the chkmalloc function we've been using.)
One side point about pointers to pointers and memory allocation: although the void * type, as returned by malloc, is a ``generic pointer,'' suitable for assigning to or from pointers of any type, the hypothetical type void ** is not a ``generic pointer to pointer.'' Our allocstr example can only be used for allocating pointers to char. It would not be possible to use a function which returned generic pointers indirectly via a void ** pointer, because when you tried to use it, for example by declaring and calling
double *dptr;
 if(!hypotheticalwrapperfunc(100, sizeof(double), &dptr))
  fprintf(stderr, "out of memory\n");
you would not be passing a void **, but rather a double **.
Another good use for pointers to pointers is in dynamically allocated, simulated multidimensional arrays, which we'll discuss in the next chapter.
As a final example, let's look at how pointers to pointers can be used to eliminate a nuisance we've had when trying to insert and delete items in linked lists. For simplicity, we'll consider lists of integers, built using this structure:
struct list
  {
  int item;
  struct list *next;
  };
Suppose we're trying to write some code to delete a given integer from a list. The straightforward solution looks like this:
/* delete node containing i from list pointed to by lp */

 struct list *lp, *prevlp;
 for(lp = list; lp != NULL; lp = lp->next)
  {
  if(lp->item == i)
   {
   if(lp == list)
    list = lp->next;
   else prevlp->next = lp->next;
   break;
   }
  prevlp = lp;
  }
 }
This code works, but it has two blemishes. One is that it has to use an extra variable to keep track of the node one behind the one it's looking at, and the other is that it has to use an extra test to special-case the situation in which the node being deleted is at the head of the list. Both of these problems arise because the deletion of a node from the list involves modifying the previous pointer to point to the next node (that is, the node before the deleted node to point to the one following). But, depending on whether the node being deleted is the first node in the list or not, the pointer that needs modifying is either the pointer that points to the head of the list, or the next pointer in the previous node.
To illustrate this, suppose that we have the list (1, 2, 3) and we're trying to delete the element 1. After we've found the element 1, lp points to its node, which just happens to be the same node that the main list pointer points to, as illustrated in (a) below:

To remove element 1 from the list, then, we must adjust the main list pointer so that it points to 2's node, the new head of the list (as shown in (b)). If we were trying to delete node 2, on the other hand (as illustrated in (c) above), we'd have to adjust node 1's next pointer to point to 3. The prevlp pointer keeps track of the previous node we were looking at, since (at other than the first node in the list) that's the node whose next pointer will need adjusting. (Notice that if we were to delete node 3, we would copy its next pointer over to 2, but since 3's next pointer is the null pointer, copying it to node 2 would make node 2 the end of the list, as desired.)
We can write another version of the list-deletion code, which is (in some ways, at least) much cleaner, by using a pointer to a pointer to a struct list. This pointer will point at the pointer which points at the node we're looking at; it will either point at the head pointer or at the next pointer of the node we looked at last time. Since this pointer points at the pointer that points at the node we're looking at (got that?), it points at the pointer which we need to modify if the node we're looking at is the node we're deleting. Let's see how the code looks:
struct list **lpp;
 for(lpp = &list; *lpp != NULL; lpp = &(*lpp)->next)
  {
  if((*lpp)->item == i)
   {
   *lpp = (*lpp)->next;
   break;
   }
  }
 }
That single line
*lpp = (*lpp)->next;
updates the correct pointer, to splice the node it refers to out of the list, regardless of whether the pointer being updated is the head pointer or one of the next pointers. (Of course, the payoff is not absolute, because the use of a pointer to a pointer to a struct list leads to an algorithm which might not be nearly as obvious at first glance.)
To illustrate the use of the pointer-to-pointer lpp graphically, here are two more figures illustrating the situation just before deleting node 1 (on the left) or node 2 (on the right).

In both cases, lpp points at a struct node pointer which points at the node to be deleted. In both cases, the pointer pointed to by lpp (that is, the pointer *lpp) is the pointer that needs to be updated. In both cases, the new pointer (the pointer that *lpp is to be updated to) is the next pointer of the node being deleted, which is always (*lpp)->next.
One other aspect of the code deserves mention. The expression
(*lpp)->next
describes the next pointer of the struct node which is pointed to by *lpp, that is, which is pointed to by the pointer which is pointed to by lpp. The expression
lpp = &(*lpp)->next
sets lpp to point to the next field of the struct list pointed to by *lpp. In both cases, the parentheses around *lpp are needed because the precedence of * is lower than ->.
As a second, related example, here is a piece of code for inserting a new node into a list, in its proper order. This code uses a pointer-to-pointer-to-struct list for the same reason, namely, so that it doesn't have to worry about treating the beginning of the list specially.
/* insert node newlp into list */

 struct list **lpp;
 for(lpp = &list; *lpp != NULL; lpp = &(*lpp)->next)
  {
  struct list *lp = *lpp;
  if(newlp->item < lp->item)
   {
   newlp->next = lp;
   *lpp = newlp;
   break;
   }
  }
 }



Source http://www.eskimo.com/~scs/cclass/int/sx8.html

Wednesday, June 16, 2010

What is an lvalue and rvalue in C

Lvalue or location value is an address that is stored into while rvalue is the "read" value, ie., value of a constant or the value stored at a location. In the assignment

a = 31;

we have the lvalue of a used on the left hand side and the integer contant value 31 assigned to this location.

In the assignment

b = a;

we have the rvalue of a (31) used to assign to the lvalue of b . So depending on which side of an assignment, we use the variable a , we get two different behaviors.

Source: http://www.quickembeddedtips.com/what-lvalue-and-rvalue-c

Friday, June 11, 2010

Formatting a Date Using a Custom Format

http://www.exampledepot.com/egs/java.text/FormatDate.html






Formatting a Date Using a Custom Format

A pattern of special characters is used to specify the format of the date. This example demonstrates some of the characters. For a complete listing, see the javadoc documentation for the SimpleDateFormat class.
Note: This example formats dates using the default locale (which, in the author's case, is Locale.ENGLISH). If the example is run in a different locale, the text (e.g., month names) will not be the same.


Thursday, June 10, 2010

UNIX mail with Attachment

by Bruce Knox  bknox @t uaex.edu     Oracle Database Programmer/Analyst                                       Copyright 2009     last updated 05/26/10                
Creating email with a text message and an attachment from standard UNIX.  mirror at http://betwinx.com/email_with_attachment.htm
The following is for instructional purposes and provides a solution to UNIX's mail not directly providing for attachments.  While you can have attachments (by using uuencode piped to mail) or send a text message using mail, you must take some extra steps to include both in the same email. 
The example below has been tested on AIX (Korn Shell) and may be different on other flavors of UNIX.  The example sends a report file (unix_attachment.lst) as an attachment.  The text message file (message.txt) will become the body of the email.
# Create the email message text and the report file.
# Note that the final Line Feed (LF) and
 Carriage Return (CR) are critical.
# That is, the last line of text in both files must be ended.

# to check our test files:
# cat message.txt should give:

$ cat message.txt
Message Text Line1 This is the email message text
Message Text Line2
Message Text Line3

Hope this helps, Bruce
$

# the $ prompt above should be on its own line
# cat unix_attachment.lst should give:

$ cat unix_attachment.lst
Report Line1 This is the Attached Report
Report Line2
Report Line3
$

# the $ prompt above should be on its own line

# uuencode the attachment file

/usr/bin/uuencode unix_attachment.lst email_attachment.lst > attachment.txt

# note that the uuencode'd file will contain an internal file label of email_attachment.lst

# concatenate or combine the email message and the uuencode'd attachment

cat message.txt attachment.txt > combined.txt

# the combined text file looks a bit strange:

$ cat combined.txt
Message Text Line1 This is the email message text
Message Text Line2
Message Text Line3

Hope this helps, Bruce
begin 666 email_attachment.lst
M4F5P;W)T($QI;F4Q(%1H:7,@:7,@=&AE($%T=&%C:&5D(%)E<&]R=`I297!O
6
`
end
$


# note that the "begin 666 email_attachment.lst" starts at the begining of a line of text

# finally, mail the combined file

mail -s "Message with Attachment" bknox @t uaex.edu < combined.txt
(Just give it a real email address. Yes, I did get lots of test messages before I broke my example address;)

While instructive, this example leaves a wide trail of work files.  To help you remove them:
rm message.txt
rm unix_attachment.lst
# Note that rm email_attachment.lst is not a file on the sending server.
rm attachment.txt
rm combined.txt