Thursday, October 22, 2009

 

Simple shell implementation

Just done a simple exercise in C programming and wrote a trivial implementation of Unix-style "shell" utility in C.

The source is here: http://code.google.com/p/inet-lab/source/browse/trunk/utils/Misc/myshell.c

All it does is basically accepts a user's command, parses it into "utility" and "arguments", does a basic sanity check, finds utility in $PATH, forks a child process and executes an utility with arguments via execv().

It also optionally supports GNU readline library and could be compiled e.g. with gcc like that :

gcc  -g --pedantic –Wall [-DRL] -o myshell myshell.c [-lreadline]

Double quotes can be used as part of command line to pass a single argument with spaces. Other than that, no other shell substitution or expansion is done; in particular, there is no way to escape a double quote to pass it as part of an argument.

Why would anyone need this primitive shell?

Well, other that a simple training in a few basic C-programming concepts (also serving as a basic GNU readline example), it allows one to create a "back door" bypassing system security. Indeed, if such a "shell" is owned by root and is granted setuid privilege, it allows a regular user to execute any administrative/privileged command, a goal which cannot be accomplished with either regular system shells (which all have built-in protection against setuid flag) or any tools written in a scripting language; it must be a native system executable.

Labels: , ,


Saturday, May 09, 2009

 

Magic of C preprocessor

Curtis Krauskopf discusses a neat trick which forces C preprocessor to merge __FILE__ and __LINE__ as one string, which isn't straightforward since __FILE__ is a string but __LINE__ is an integer.

It turns out you can solve the problem with two additional macros:

#include <stdio.h>
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define AT __FILE__ ":" TOSTRING(__LINE__)
void error(const char *location, const char *msg)
{
  printf("Error at %s: %s\n", location, msg);
}
int main(int , char**)
{
  error(AT, "fake error");
  return 0;
}

Now, if only someone could find a way to merge __func__ and __LINE__ ....

Labels:


Thursday, December 21, 2006

 

Portable thread library

Given how important multithreading programming has become, it is surprisingly difficult to find simple and usable portable C/C++ thead library.

In fact, this page claims there are only two such C++ libraries in existence: zthread and Boost.Threads.

zthread offers a clean, well-thought C++ design (claimed to be modeled after Java threads). Despite the fact that Cygwin was not mentioned as one of the supported platforms, it does compile and run under Cygwin with no visible (Cygwin-specific) problems. However,

Speaking of Boost.Threads, this is apparently just one piece of a huge collection of libraries - the latest release takes around 11M of source files - there is no documented way to build a single library separate from others.

So, is there a better alternative?

It appears that there is: it is POSIX Threads for Win32 project. They provide ready-to use libraries that can be (dynamically) linked with any Win32 application for (almost) complete POSIX thread support. See FAQ for long and interesting discussion on various ways to handle exceptions that arise from inside the library (in my experiments, I used pthreadVC1.lib)

Finally, a good pthread tutorial and documentation is available here.

Appendix. Sample C++ application implemented with zthread:

#include <string>
#include <iostream>
#include <zthread/Thread.h>
#include <zthread/Mutex.h>
  
ZThread::Mutex * output = new ZThread::Mutex ();

class ThreadExample : public ZThread::Runnable
{
 public:
   ThreadExample(std::string thread_name, size_t iterations)
      :   name_(thread_name), num_times_to_loop_(iterations)
   {}
  
   void run()
   {
      for (size_t i = 0; i < num_times_to_loop_; i++) 
      {
         output->acquire();
         std::cerr << i << " " << name_ << "\n";
         output->release();
      }
      output->acquire();
      std::cerr << name_ << " finished! " << std::endl;
      output->release();
   }
  
 private:
   std::string name_;
   size_t num_times_to_loop_;
};

int main()
{
   using namespace std;
   using namespace ZThread;
  
   try
   {
      Thread t1(new ThreadExample("Thread-1", 50));
      Thread t2(new ThreadExample("Thread-2", 50));
   }
   catch (const Synchronization_Exception& e)
   {
      cerr << e.what() << "\n";
   }
}

and pthread:

#include <string>
#include <iostream>
#include <pthread.h>

pthread_mutex_t output = PTHREAD_MUTEX_INITIALIZER;

class ThreadExample
{
 public:
   ThreadExample(std::string thread_name, size_t iterations)
      :   name_(thread_name), num_times_to_loop_(iterations)
   {}
  
   void run()
   {
      for (size_t i = 0; i < num_times_to_loop_; i++) 
      {
         pthread_mutex_lock (&output);
         std::cerr << i << " " << name_ << std::endl;
         pthread_mutex_unlock (&output);
      }
      pthread_mutex_lock (&output);
      std::cerr << name_ << " finished! " << std::endl;
      pthread_mutex_unlock (&output);
   }

   static void * prun(void * self) 
   {
      ((ThreadExample *)self)->run();
      return NULL;
   }
  
 private:
   std::string name_;
   size_t num_times_to_loop_;
};

int main()
{
   pthread_t  p1, p2;

   pthread_create(&p1, NULL, ThreadExample::prun, new ThreadExample("Thread-1", 50));
   pthread_create(&p2, NULL, ThreadExample::prun, new ThreadExample("Thread-2", 50));

   pthread_exit(NULL);
   return 0;
}

Labels: , , , ,


Sunday, December 10, 2006

 

double to float conversion

When we must convert float number to integer in C, we have two convenient functions at our disposal: floor and ceil. For some reason however, there are no natural counterparts to these functions when we deal with double -> float conversion.

I wrote a simple implementation of these utilities using existing C library functions frexp and ldexp:

float fdround ( double x, int isfloor )
{
  const int    Nf = 23; /* IEEE 754: http://en.wikipedia.org/wiki/IEEE_754 */
  double    m;
  int        exp, sx;
  if (0 == (sx = ((x < 0.0) ? (-1) : ((x > 0.0) ? 1 : 0)))) return 0.0;
  m = frexp ( x * sx, &exp );
  return (float)(ldexp ( (double)sx * ((isfloor ^ (sx == -1))? floor : ceil)
           (m * (1 << (Nf + 1))), exp - Nf - 1));  
}  
#define fceil(x) (fdround ( (x), 0 ))  
#define ffloor(x) (fdround ( (x), 1 ))  

This implementation of course depends on the correct knowledge of the number of bits for mantissa as per IEEE standard, which is 23 for 32-bit floating-point numbers.

Here is a simple utility to test whether the above function generates correct numbers:

void test(double x)
{
  float f = ffloor(x), c = fceil(x);
  float a = 0.4 * f + 0.6 * c, b = 0.6 * f + 0.4 * c, y = (f + c)/2;
  assert ( f <= x && c >= x );
  assert ( a == c && b == f );
  assert ( y == f || y == c );
}

Enjoy!

Labels:


Thursday, June 22, 2006

 

printf() and 64-bit integers

In the last post we talked about scanf(), so perhaps it would be proper now to discuss printf().

Good and reasonably brief manual page could be found here; then make sure to check Microsoft-specific formats here.

Some interesting features are there, e.g. you can use <'> format (single quote) to enable locale-specific number output (has no effect in C locale); you can also refer to specific argument by number, specify format width as a separate argument, and so on.

Let's consider one specific task to print some (large) 64-bit value. The basic problem is that you must know (1) what (integer) type to use to represent (at least) 64-bit integers, and (2) what printf() format does this type correspond to, if any.

On UNIX platforms long usually correspond to "machine word" (that is to say, has same size as pointer) so on 64-bit UNIX long is 64-bit and the following code:

printf ( "2^63 = %lu\n", 1L << 63 );

will print 2^63 = 9223372036854775808.

On 32-bit UNIX systems long is 32-bit but long long is 64-bit, and then the following code will work as expected:

printf ( "2^63 = %llu\n", (long long)1 << 63 )

(Gnu gcc understands 1LL, but I am not sure if other compilers do).

On Windows, however (with Microsoft compiler) approach is different and size of basic types does not change with CPU and so long is always 32-bit (same as int). Thus, in older Visual C++ systems you have to write:

printf ( "2^63 = %I64u\n", (__int64)1 << 63 );

... while in Visual .NET the above example with "long long" will work.

Labels: , ,


Tuesday, June 06, 2006

 

scanf

For the first time since I learned C 18 years ago I noticed that the standard library function scanf (and friends) has been enhanced with many new formats and features.

E.g., the following code

scanf ("%s %[^\n]\n", name, args);

reads a "word" from the input (and assigns it to name) and then reads the rest of the line till end-of-line, irrespective of spaces and other symbols, and assigns it to args.

Very detailed description of scanf formats is available at Solaris 10 Reference Manual Collection pages.

There is also a brief introduction to the standard C library here. Wikipedia, as usual, has a worthy collection of links as well.

Labels:


This page is powered by Blogger. Isn't yours?