Mathjax

jsxgraph

Monday, July 22, 2013

X11 factorial code with Xft and GMP

/*
This is the factorial code using X11 with Xft and GMP.  Xft provides anti-aliased fonts and can be toggled on or off with an 'a' or 'x' keys.  The results from the Gnu Multi-Precision Library can have the precision reduced by bit masking the results to 8, 4, 2 or 1 Byte by pressing the 'p' key.  The results can also be presented in binary or hexadecimal by pressing the 'b' key.  The number digits are entered with number keys.  The 'delete' or 'backspace' keys remove the last digit.  The 'enter' or 'return' keys clear the number.

The code listing is color highlighted -
  gray - is comments, ignored by the compiler
  green - pre-processor directives
  blue - native primitive variable types
  black - normal code
  bold pink / bold light green - documentation key words
  bold light blue - documentation key word targets
  light brown - integer constants
  red - constant character arrays ( strings )
  purple - character constant
  
  The code should copy into an editor without color highlighting.

The code has been updated to include working doxygen comments. To generate doxygen documentation

doxygen -g

then edit Doxyfile and and change lines by appending as below:
INPUT = factX.c
PROJECT_NAME = "factX"
PROJECT_BRIEF = "Program to play with factorial computations"
INPUT = factX.c
OPTIMIZE_OUTPUT_FOR_C = YES

then type

doxygen

will produce documentation in html/index.html under files tab.
*/
  
/** @file 
 * This program computes and displays the factorial of a decimal number
 * @verbatim
  If USE_GMP is defined it will use the gmp library to compute the factorial
       to high precision
       Otherwise it will use a long long int as the result
  If USE_XFT is defined, antialiased font display can be toggled with an
       "a" or "x" key
  A number key (0-9) will add that digit to the number
  'backspace' or 'delete' will remove the last digit
  'b' will cycle through decimal, binary and hexadecimal
          display of the solution
  'p' will cycle through number of bytes in the solution - full,8,4,2,1
  'q' or 'escape' key will cleanly exit the program
  'return' or 'enter' key will reset the number to 0 @endverbatim
  To compile try:
 @verbatim
    gcc factX.c -g -o factX -I/usr/include/freetype2 -lXft -lX11 -lgmp

        -g is only neccessary for debuging
        -I indicates a directory (folder) to search for header files
                  These depend on how your system is setup
        -lXft is only neccessary if USE_XFT is defined
        -lgmp is only neccessary if USE_GMP is defined@endverbatim
 * Thanks to Brian Hammond 
 * http://math.msu.su/~vvb/2course/Borisenko/CppProjects/GWindow/hi.c
 * and Yoshi Rokuko
 * https://groups.google.com/forum/#!msg/comp.windows.x.intrinsics
 *       /bBZHFlePiR0/9Vc8pfDCg-IJ
 *      for posting good examples of X11 and Xft usage programs
 */

/** define USE_XFT for compiling with antialiased fonts with the Xft library */
#define USE_XFT

/** define USE_GMP for compiling to use arbitrary precision math */
#define USE_GMP

/* include some standard headers */
#include <stdio.h>   // sprintf, printf
#include <stdlib.h>  // exit, atoi, atol, malloc, free
#include <string.h>  // strlen, strdup

/* include the X library headers */
#include <X11/Xlib.h>
#include <X11/keysym.h> // XK_ symbols

// Gnu Multiple Precision Library
#ifdef USE_GMP
#include <gmp.h>
#endif

/** declare bit mask used to reduce number precision
 *  byteMask = eight bits i.e. 11111111 in binary, ff in hex, 255 in decimal
 */
unsigned long int byteMask; 
unsigned long int twoByte;   ///< sixteen bits or 0xffff
unsigned long int fourByte;    ///< 32 bits or 0xffffffff
unsigned long long int eightByte;  ///< 64 bits or 0xffffffffffffffff

/* declare X11 variables globally - outside of any function */

/** An X11 Display can have multiple screens(monitors)
 * and input devices (keyboard, mouse, touch screen) */
Display *dis; 

/** The screen on the display */    
int screen;

/** The Window may be controlled by a window manager so
 * this program only gives suggestions to the window manager */
Window win;

/** The graphics context (GC) preserves drawing information 
 * like color, line width, font etc. between draw actions */
GC gc;

/** The XFontStruct holds font and font information 
 * Three font sizes are used depending on window and solution size */   
XFontStruct *smallFont;
XFontStruct *mediumFont; ///< medium sized font data for X11 drawing
XFontStruct *bigFont;  ///< large sized font data for X11 drawing

/** XTextItem items can be an array to hold multiple lines
 * of text for drawing
 * Here it is used only for a single line to show its usage
 * in XDrawText () */
XTextItem *items;

/* Test if USE_XFT is defined for drawing anitaliased text */
#ifdef USE_XFT

  /* include declarations of Xft (X FreeType interface) functions */
  #include <X11/Xft/Xft.h>

  /* test if the version of Xft is less than 2 and don't use Xft 
  * if it is not at least version 2 */
  #if ( XFT_MAJOR < 2 ) 

    /* undefine USE_XFT, Sorry no antialiased fonts */
    #undef USE_XFT

  #else // else for "if (XFT_MAJOR < 2 )" test - good version of Xft */

    /** Three Xft font structures, holds font and font information */
    XftFont *smallXft;
    XftFont *mediumXft; ///< medium sized font data for Xft drawing
    XftFont *largeXft; ///< big sized font data for Xft drawing

    /** extents is used to find string sizes */
    XGlyphInfo extents;

    /** drawXft is what anitaliased fonts are drawn on */
    XftDraw *drawXft;

    /** A Colormap holds indexed colors for drawing */
    Colormap cmap;

    /** XRenderColor is a high precision (16bit) rgb color with transparency */
    XRenderColor colorXrender;

    /** Holds a color index (pixel) and an rgba color (XRenderColor)
    * rgba is a combination of red,green,blue and alpha
    * alpha is the opacity, 0=transparent */
    XftColor colorXft;

  #endif  // end of #if (XFT_MAJOR < 2 );   #else block,  
#endif  // end of USE_XFT code block,  #ifdef USE_XFT

/** If true ( not equal to 0 ) draw antialiased text */
int useXft;

/** Indicate the number base for the solution
 * @verbatim
   0 - display solution in decimal (base 10)
   1 - display solution in binary (base 2)
   2 - display solution in hexadecimal (base 16) @endverbatim */
int showBin;

/**  Indicate the precision of the solution
 * @verbatim
   0 - display full precision solutions
   1 - display 8 byte precision solutions 
   2 - display 4 byte precision solutions
   3 - display 2 byte precision solutions
   4 - display 1 byte precision solutions  @endverbatim*/
int precision;

/** character array to hold solution text
 * deallocate memory befor resetting
 * global to preserve for DrawString */
char *fact;

/** Initialize X and Xft resources */
void init_x();

/** Free X and Xft resources and exit */
void close_x();

/** recalculate the factorial and refresh the window display 
 * @param text the character representation of the number to compute */
void redraw(char * text);

/** Xft routines to draw the equation
 * @param numfeq char array with number, factorial, and equals sign
 * @param fact char array with the solution */
void xftDraw(char * numfeq,char * fact);

/** X routines to draw the equation
 * @param numfeq char array with number, factorial, and equals sign
 * @param fact char array with the solution */
void draw(char * numfeq,char * fact);

/** Function for getting the window width 
 * @returns the window width in pixels */
unsigned int winWidth();

/** Function for getting the window height 
 * @returns the window height in pixels */
unsigned int winHeight();

/** convert k to a binary string (long to binary ascii)
 * @param k the number to convert 
 * @returns a pointer to an allocated character array with the binary
 * representation of k */
char * ltoba( long long int k);

/** convert k to a hex string (long to hex ascii)
 * @param k the number to convert 
 * @returns a pointer to an allocated character array with the hex 
 * representation of k */
char * ltoha( long long int k);

/** get descriptive text for top of window
 * @return newly allocated pointer to char with either default instructions
 * or indication of precision and number representation
 * @note the string should be freed to prevent a memory leak */
char * nowShowing();

/** 
 * This program computes and displays the factorial of a decimal number.
  \verbatim
  If USE_GMP is defined it will use the gmp library to compute the factorial
      to high precision
      Otherwise it will use a long long int as the result
  If USE_XFT is defined, antialiased font display can be toggled with an
      "a" or "x" key
  A number key (0-9) will add that digit to the number
  'backspace' or 'delete' will remove the last digit
  'b' will cycle through decimal, binary and hexadecimal
          display of the solution
  'p' will cycle through number of bytes in the solution - full,8,4,2,1
  'q' or 'escape' key will cleanly exit the program
  'return' or 'enter' key will reset the number to 0
  \endverbatim
 */
main () 
{
  
  /* the XEvent declaration - This is a union of several structures */
  XEvent event;
  
  KeySym key;  /* handle KeyPress Events */
  char text[ 8 ]; /* a char buffer for the number */
  int itext;            /* index for the end of the text string */
  
  text[0] = '\0';       /* initialize the text string to an empty string */
  itext=0;              /* initialize the end of the text to the first position */
  useXft = 0;           /* start without anialiased text */
  showBin = 0;          /* start without binary solution display */
  fact = NULL;          /* mark fact as not allocated */
  
  init_x();             /* initialize X and Xft variables */
  
  /* Print formated values to standard output, usually the console,
   * An explicit line return ,'\n', is required, so multiple prints are on
   * the same line */
  printf(" This program computes and displays the factorial of a decimal");
  printf(" number\n");
  #ifdef USE_GMP
  printf(" The factorial is computed to arbitrary precision with the gmp");
  printf(" library\n");
  #else
  printf(" The factorial is computed with a long long int (usually 8 bytes)");
  printf(" as the result\n");
  #endif
  printf("  - Any number key adds the digit to the number\n");
  printf("  - Backspace or delete will remove the last digit\n");
  
  /* an alternate means for line continuation, a backslash followed by return*/
  printf("  - 'B' will cycle through decimal, binary and hex display of the\
 solution\n");
  printf("  - 'P' will cycle through solution # of bytes precision -");
  printf(" full,8,4,2,1 \n");
  printf("  - Return or Enter will reset the number to 0,");
  printf(" Note: convention 0! = 1\n");
  #ifdef USE_XFT
  printf("  - 'A' or 'X' will toggle display text antialiasing with the");
  printf(" Xft library\n");
  #endif
  printf("  - 'Q' or 'Escape' will cleanly exit the program\n");
  
  /*  a loop to look for events forever ... ( Well till close_x is called )*/
  while(1) {  
    /* get the next event and put it into our event variable.
     *  The program waits for an event before continuing
     * Note: only event types we set with XSelectInput() are detected!
     * 
     */
    XNextEvent(dis, &event);
    
    if (event.type == Expose && event.xexpose.count==0) {
      /* the window was exposed redraw it! */
      redraw(text);
    }
    if (event.type == KeyPress) {
      /* A key was pressed */
      key = XLookupKeysym(&(event.xkey),0); // Which key was pressed
      switch( key ) {        // go to a 'case' with the value of key
        case XK_Q:
        case XK_q:
        case XK_Escape:      // in c cases "fall through"
          close_x();         // this will exit the program, no 'break;' needed
        case XK_0:
        case XK_KP_0:        // Key Pad 0 was pressed
          text[itext] = '0';   // set text character at itext to '0'
          itext++;           // add 1 to itext to position at next character
          break;             // leave the switch code block
        case XK_1:
        case XK_KP_1:
          text[itext] = '1';
          itext++;
          break;
        case XK_2:
        case XK_KP_2:
          text[itext] = '2';
          itext++;
          break;
        case XK_3:
        case XK_KP_3:
          text[itext] = '3';
          itext++;
          break;
        case XK_4:
        case XK_KP_4:
          text[itext] = '4';
          itext++;
          break;
        case XK_5:        case XK_KP_5:
          text[itext] = '5';
          itext++;
          break;
        case XK_6:
        case XK_KP_6:
          text[itext] = '6';
          itext++;
          break;
        case XK_7:
        case XK_KP_7:
          text[itext] = '7';
          itext++;
          break;
        case XK_8:
        case XK_KP_8:
          text[itext] = '8';
          itext++;
          break;
        case XK_9:
        case XK_KP_9:
          text[itext] = '9';
          itext++;
          break;
        case XK_Return:
        case XK_Linefeed:
        case XK_KP_Enter: 
          itext=0;              // reset itext to the start of the string
          text[itext] = '\0';   // mark the end of the number text
          /* restart the while loop so the new 0! is not imediately drawn */
          continue;             // continue - go back to the start of the loop
        case XK_BackSpace:
        case XK_Delete:
          itext--;             // subtract 1 from itext to go back a character
          if(itext < 0 ) itext=0;  // don't go negative
          break;
        case XK_X:
        case XK_x:
        case XK_A:
        case XK_a: 
          /* change useXft to its opposite (logical not of useXFT) */
          useXft = !useXft; 
          break;
        case XK_B:
        case XK_b:
          showBin++;            // increment showBin - number format indicator
          switch(showBin) {
            default:            // no case found matching showBin 
              showBin=0;        // reset to default base 10 decimal output
              /* print the current number output format to standard out */
              case 0:    printf("Decimal output\n");     break;
              case 1:    printf("Binary output\n");      break;
              case 2:    printf("Hexadecimal output\n"); break;
          }
          break;
       case XK_P:
       case XK_p:
         precision++;          // increment precision by 1
         switch(precision) {
           default:            // no 'case' found for precision
             precision = 0;    // reset precision to default
             /* print the current precision to standard out */
             case 0: printf("Full Precision\n"); break;
             case 1: printf("Eight Byte solution\n"); break;
             case 2: printf("Four Byte solution\n"); break;
             case 3: printf("Two Byte solution\n"); break;
             case 4: printf("One Byte solution\n"); break;
         }
         break;
             default:                // no 'case' for key
               continue;             // go to start of while loop
      } // end of switch(key)
      if(itext == 7) {  // limit the number to 6 digits
        for(itext=0;itext<6;itext++) { 
          text[itext] = text[itext+1];   // shift digits left
        }
        itext=6;
      }
      text[itext]='\0';         // mark the end of the text string
      redraw(text);             // redraw the screen
} // end of if(KeyPress) } // end of while(1) loop } /* Initialize X and Xft resources */ void init_x() { unsigned long black,white; // default black and white colors /* These are for the new way to set window properties */ XTextProperty *winTitle; XTextProperty *iconTitle; char ** list; useXft = 0; // initialize to not use Xft dis = XOpenDisplay((char *)0); // Open the display for interaction /* Exit if no display was opened */ if(dis == NULL) { fprintf(stderr, "Cannot open display\n"); exit(1); } screen = DefaultScreen(dis); // Get the monitor to use black = BlackPixel(dis, screen); // Get the default black color white = WhitePixel(dis, screen); // Get the default white color /* create a top level window 400 by 247 pixels on the display dis * with no X11 border */ win = XCreateSimpleWindow(dis,DefaultRootWindow(dis),0,0, 400, 247, 0, black, white); /* Set the window title to "Factorial" and icon name to "Fact" */ /* The old way to set window title and icon title -- one line */ //XSetStandardProperties(dis,win,"Factorial","Fact",None,NULL,0,NULL); /* new way to set window properties -- a lot more complicate */ /* allocate memory for XTextProperty variables */ winTitle = (XTextProperty *)malloc(sizeof(XTextProperty)); iconTitle = (XTextProperty *)malloc(sizeof(XTextProperty)); /* allocate memory for a pointer to a pointer to char */ list = (char **)malloc(sizeof(char*)); list[0] = "Factorial"; // set the pointer to char XmbTextListToTextProperty(dis,list,1,XTextStyle,winTitle); // setup winTitle list[0] = "Fact"; // set the pointer to char /* setup iconTitle */ XmbTextListToTextProperty(dis,list,1,XTextStyle,iconTitle); XSetWMProperties(dis,win,winTitle,iconTitle,NULL,0,NULL,NULL,NULL); /* Tell the X server we will listen for expose and keypress events */ XSelectInput(dis, win, ExposureMask|KeyPressMask); /* Get the Graphic Context - used for all drawing */ gc=XCreateGC(dis, win, 0,0); /* set forground and background colors */ XSetBackground(dis,gc,white); XSetForeground(dis,gc,black); /* Empty the window contents */ XClearWindow(dis, win); /* make the window visible, i.e. show the window */ XMapRaised(dis, win); /* set up three monospaced fonts */ smallFont = NULL; mediumFont = NULL; bigFont = NULL; /* get small, medium and large monospaced fonts */ /* List of what each position is for ( '*' means anything ) * FOUNDRY: Type foundry - vendor or supplier of this font * FAMILY_NAME: Typeface family * WEIGHT_NAME: Weight of type * SLANT: Slant (upright, italic, oblique, reverse italic, reverse oblique, * or "other") * SETWIDTH_NAME: Proportionate width (e.g. normal, condensed, narrow, * expanded/double-wide) * ADD_STYLE_NAME: Additional style (e.g. (Sans) Serif, Informal, Decorated) * PIXEL_SIZE: Size of characters, in pixels; 0 (Zero) means a scalable font * POINT_SIZE: Size of characters, in tenths of points * RESOLUTION_X: Horizontal resolution in dots per inch (DPI), for which * the font was designed * RESOLUTION_Y: Vertical resolution, in DPI * SPACING: monospaced, proportional, or "character cell" * AVERAGE_WIDTH: Average width of characters of this font; * 0 means scalable font * CHARSET_REGISTRY: Registry defining this character set * CHARSET_ENCODING: Registry's character encoding scheme for this set */ /* a 9 pixel monospaced font */ smallFont = XLoadQueryFont(dis,"-*-*-*-*-*-*-9-*-*-*-m-*-*-*"); if(smallFont == NULL) { printf("Could not load smallFont\n"); close_x(); } /* a 18 pixel monospaced font */ mediumFont = XLoadQueryFont(dis,"-*-*-*-*-*-*-18-*-*-*-m-*-*-*"); if(mediumFont == NULL) { printf("Could not load mediumFont\n"); close_x(); } /* a 36 pixel monospaced font */ bigFont = XLoadQueryFont(dis,"-*-*-*-*-*-*-36-*-*-*-m-*-*-*"); if(bigFont == NULL) { printf("Could not load bigFont\n"); close_x(); } items = (XTextItem*)malloc(sizeof(XTextItem)); #ifdef USE_XFT /* get small, medium and large monospaced Xft fonts using the same XLFD * desciptors as above*/ smallXft = NULL; mediumXft = NULL; largeXft = NULL; smallXft = XftFontOpenXlfd(dis,screen,"-*-*-*-*-*-*-9-*-*-*-m-*-*-*"); if(smallXft == NULL) { printf("Could not load smallXft font\n"); close_x(); } mediumXft = XftFontOpenXlfd(dis,screen,"-*-*-*-*-*-*-18-*-*-*-m-*-*-*"); if(mediumXft == NULL) { printf("Could not load mediumXft font\n"); close_x(); } largeXft = XftFontOpenXlfd(dis,screen,"-*-*-*-*-*-*-36-*-*-*-m-*-*-*"); if(largeXft == NULL) { printf("Could not load largeXft font\n"); close_x(); } /* a color map contains indexed colors */ cmap = DefaultColormap(dis,screen); /* drawXft is where all Xft drawing is done */ drawXft = XftDrawCreate(dis, win, DefaultVisual(dis, screen), cmap); if(drawXft == NULL) { printf("Could not create Xft Drawable\n"); close_x(); } /* set the font color to black */ colorXrender.blue = 0; colorXrender.green = 0; colorXrender.red = 0; colorXrender.alpha = 0xffff; // note: Xrender uses 16 bit rgba values XftColorAllocValue(dis,DefaultVisual(dis,screen),cmap,&colorXrender,\ &colorXft); #endif byteMask = 0xff; twoByte = 0xffff; fourByte = 0xffffffff; eightByte = 0xffffffffffffffff; } /* Function to free resources used and exit */ void close_x() { #ifdef USE_XFT if(smallXft != NULL) XftFontClose(dis,smallXft); if(mediumXft != NULL) XftFontClose(dis,mediumXft); if(largeXft != NULL) XftFontClose(dis,largeXft); if(drawXft != NULL) XftDrawDestroy(drawXft); #endif if(smallFont != NULL) XFreeFont(dis,smallFont); if(mediumFont != NULL) XFreeFont(dis,mediumFont); if(bigFont != NULL) XFreeFont(dis,bigFont); XFreeGC(dis, gc); XDestroyWindow(dis,win); XCloseDisplay(dis); exit(1); }; /* recalculate the factorial and refresh the window display * \param text the character representation of the number to compute */ void redraw(char * text) { char numfeq[1024]; /// The string "n! = " #ifdef USE_GMP unsigned long int n; unsigned long int kp; /* gmp factorial calculation */ mpz_t k; // mpz_t is mutiprecision integer type from gmp mpz_t kt; mpz_t bmask; /* initalize gmp integer structures - setup memory */ mpz_inits( k, kt, bmask, NULL ); n = atol(text); // convert "text" to a long int /* print to the string numfeq the value of n with the * long decimal format (%ld) folowed by '! = ' */ snprintf(numfeq,1023,"%ld! = ",n); /* mpz_fac_ui is a gmp function to compute the factorial * of an unsigned int (n) and put it into an mpz_t (k) */ mpz_fac_ui( k, n ); /* reduce precision by logical and with byte mask * example: binary numbers 11101010 & 1111 = 1010 * mpz_set_ui sets k to the unsigned long integer value * mpz_and performs the logical bitwise & , kt = k & bmask * mpz_set copies the value of kt to k */ switch(precision) { // go to value of precision, case statement default: precision = 0; // set default precision if not in cases case 0: // case 0 use full precision break; case 1: /* use string initialization for bit mask just in case * native integer can not hold an 8 byte integer */ mpz_set_str(bmask,"ffffffffffffffff",16);// use string mpz_and(kt,k,bmask); mpz_set(k,kt); break;; case 2: mpz_set_ui(bmask,0xffffffff); mpz_and(kt,k,bmask); mpz_set(k,kt); break; case 3: mpz_set_ui(bmask,0xffff); mpz_and(kt,k,bmask); mpz_set(k,kt); break; case 4: mpz_set_ui(bmask,0xff); mpz_and(kt,k,bmask); mpz_set(k,kt); break; } /* if it has been set, free the memory for fact * before resetting it */ if( fact != NULL) { free(fact); fact = NULL; } /* mpz_get_str returns a new string (char *) pointer * representing k in the specified base */ switch(showBin) { default: showBin = 0; case 0: fact = mpz_get_str(NULL,10,k); break; case 1: fact = mpz_get_str(NULL,2,k); break; case 2: fact = mpz_get_str(NULL,16,k); break; } printf("%ld! = %s\n",n,fact); // print the solution to stdout mpz_clears ( k, kt, bmask, NULL); // reset k, kt and bmask - release internal memory #else /* regular factorial calculation with long long int */ char answer[1024]; // The solution is limited to 1023 characters int n,i; long long int k; /* size_t is an integer type that can hold the largest possible * result from sizeof function. Essetially the pointer size. */ size_t li; li = sizeof(long long int); n = atoi(text); // convert text to an integer /* snprintf - prints upto 1023 characters plus a null char '\0' * to the string numfeq * with the format of a decimal number of 'n' + "! = " */ snprintf(numfeq,1023,"%d! = ",n); k=1; for(i=1; i<=n; i++) { k *= i; } printf("%d! = %ld\n",n,k); /* reduce precision with logical .and. operation with byte mask * \note that k may be four or eight bytes and is signed * \note on 32 bit systems a long long int may only be 4 Bytes * so li=sizeof(long long int) is used to limit * precision mask to 4 Bytes */ switch(precision) { default: precision = 0; case 0: break; case 1: // cool logic here, using fall through if(li >= 8) { k = k & eightByte; break; }else{ precision = 2; } case 2: k = k & fourByte; break; case 3: k = k & twoByte; break; case 4: k = k & byteMask; break; } /* free memory for string fact if it has been allocated * this avoids a memory leak where memory for fact could be multiply * allocated*/ if( fact != NULL) { free(fact); fact = NULL; } /* set string fact to hold the solution in the number base ( 10, 2, 16) * desired * note: in base 16 ( hexadecimal or hex ), each 2 digits represent a Byte */ switch(showBin) { default: showBin = 0; case 0: snprintf(answer,1023,"%ld",k); fact = strdup(answer); break; case 1: fact = ltoba(k); // convert k to a binary string representation break; case 2: //fact = ltoha(k); // convert k to a hex string representation snprintf(answer,1023,"%lx",k); fact = strdup(answer); break; } #endif XClearWindow(dis, win); if(useXft) { xftDraw(numfeq,fact); }else{ draw(numfeq,fact); } } /* Function for getting the window width * \returns the window width in pixels */ unsigned int winWidth() { Window root_return; int x_return, y_return; unsigned int height_return,width_return; unsigned int border_width_return; unsigned int depth_return; XGetGeometry(dis, win, &root_return, &x_return, &y_return, &width_return, &height_return, &border_width_return, &depth_return); return width_return; } /* Function for getting the window height * \returns the window height in pixels */ unsigned int winHeight() { Window root_return; int x_return, y_return; unsigned int height_return,width_return; unsigned int border_width_return; unsigned int depth_return; XGetGeometry(dis, win, &root_return, &x_return, &y_return, &width_return, &height_return, &border_width_return, &depth_return); return height_return; } /* Xft routines to draw the equation * \param numfeq char array with number, factorial, and equals sign * \param fact char array with the solution */ void xftDraw(char * numfeq,char * fact) { #ifdef USE_XFT XftFont * font; // a pointer to a font - used to change font size /* the x position to start drawing the solution string */ unsigned int xstart; unsigned int awid; unsigned int width,height;// The window width and height in pixels /* pixel locations to start drawing * x=0 is the left edge increasing to the right * y=0 is the top edge increasing downward */ unsigned int x,y; /* the width and height of a string to draw */ unsigned short textWidth,textHeight; int nlines; // number of lines required to draw the solution string int nchar; // number of characters to draw per line int charwid; // character width; int totchar; // number of characters in the solution int start; // character of solution at start of line int maxlines; // number of lines that fit window with given font char * instr; // instructions or comment drawn above solution instr = nowShowing(); // get top line of text x = 5; /* y = 0 at top of window increasing downward * 5 + ( font height above baseline ) pixels */ y = 5 + smallXft->ascent; /* draw the instruction line in the small font */ XftDrawString8(drawXft,&colorXft,smallXft,x,y,instr,strlen(instr)); y += 5 + smallXft->descent; // move down 5 + lower part of font /* calculations to see if the number will fit with largeXft font */ width = winWidth(); height = winHeight(); nlines = 1; totchar = nchar = strlen(fact); font = largeXft; XftTextExtents8 (dis,font,(FcChar8 *)numfeq,strlen(numfeq),&extents); textWidth = extents.width; textHeight = extents.height; maxlines = (height-y)/(textHeight+5); /* xstart is the end of the "n! = " string */ xstart = x + textWidth + 5; /* calculate the number of characters per line and number of lines */ XftTextExtents8 (dis,font,(FcChar8 *)fact,totchar,&extents); charwid = extents.width/totchar + 1; awid = (width - xstart - 5); nchar = awid/charwid; nchar = ( nchar > 0 ) ? nchar : 1 ; // prevent divide by 0 nlines = totchar/nchar + 1; if(nlines > maxlines ) { // solution does not fit with largeXft font font = mediumXft; XftTextExtents8 (dis,font,(FcChar8 *)numfeq,strlen(numfeq),&extents); textWidth = extents.width; textHeight = extents.height; maxlines = (height-y)/(textHeight+5); xstart = x + textWidth + 5; XftTextExtents8 (dis,font,(FcChar8 *)fact,totchar,&extents); charwid = extents.width/totchar + 1; awid = (width - xstart - 5); nchar = awid / charwid; nchar = ( nchar > 0 ) ? nchar : 1 ; nlines = totchar/nchar + 1; if(nlines > maxlines ) { // solution does not fit with mediumXft font font = smallXft; XftTextExtents8 (dis,font,(FcChar8 *)numfeq,strlen(numfeq),&extents); textWidth = extents.width; textHeight = extents.height; maxlines = (height-y)/(textHeight+5); xstart = x + textWidth + 5; XftTextExtents8 (dis,font,(FcChar8 *)fact,totchar,&extents); charwid = extents.width/totchar + 1; awid = (width - xstart - 5); nchar = awid/charwid; nchar = ( nchar > 0 ) ? nchar : 1 ; nlines = totchar/nchar + 1; if(nlines > maxlines) { // solution does not fit with smallXft font font = mediumXft; XftTextExtents8 (dis,font,(FcChar8 *)numfeq,strlen(numfeq),&extents); textWidth = extents.width; xstart = x + textWidth + 5; nlines = 1; fact = strdup(" is to Big"); totchar = strlen(fact); } } } y += font->ascent; XftDrawString8(drawXft,&colorXft,font,x,y,numfeq,strlen(numfeq)); for(start = 0; start < totchar; start += nchar) { nchar = ((totchar-start) < nchar)? totchar-start : nchar; XftDrawString8(drawXft,&colorXft,font,xstart,y,fact+start,nchar); y+= textHeight+5; } free(instr); /*default to non-Xft draw routine if USE_XFT is not defined */ #else draw(numfeq,fact); #endif } /* X routines to draw the equation * \param numfeq char array with number, factorial symbol, and equals sign * \param fact char array with the solution */ void draw(char * numfeq,char * fact) { XFontStruct * font; // pointer the font to draw /* the x position to start drawing the solution string */ unsigned int xstart; unsigned int awid; unsigned int width,height; // The window width and height in pixels /* pixel locations to start drawing * x=0 is the left edge increasing to the right * y=0 is the top edge increasing downward */ unsigned int x,y; int nlines; // number of lines required to draw the solution string int nchar; // number of characters to draw per line int totchar; // number of characters in the solution int start; // character of solution at start of line int maxlines; // number of lines that fit window with given font char * instr; // instructions or comment drawn above solution instr = nowShowing(); // get top line of text x = 5; /* y = 0 at top of window increasing downward * 5 + ( font height above baseline ) pixels */ y = 5 + smallFont->ascent; /* draw the instruction line */ XSetFont(dis,gc,smallFont->fid); XDrawString(dis,win,gc,x,y, instr, strlen(instr) ); y += 5 + smallFont->descent; // move down 5 + lower part of font /* calculations to see if the number will fit with bigFont */ width = winWidth(); height = winHeight(); nlines = 1; totchar = nchar = strlen(fact); font = bigFont; maxlines = (height-y)/(font->ascent + font->descent+5); /* xstart is the end of the "n! = " string */ xstart = 5 + XTextWidth(font,numfeq,strlen(numfeq)); awid = (width - xstart - 5); awid = ( awid > 0 ) ? awid : font->max_bounds.width ; nchar = awid/font->max_bounds.width; nchar = ( nchar > 0 ) ? nchar : 1 ; nlines = totchar/nchar + 1; if(nlines > maxlines ) { // solution does not fit with bigFont font = mediumFont; maxlines = (height-y)/(font->ascent+font->descent+5); xstart = 5 + XTextWidth(font,numfeq,strlen(numfeq)); awid = (width - xstart - 5); awid = ( awid > 0 ) ? awid : font->max_bounds.width ; nchar = awid/font->max_bounds.width; nchar = ( nchar > 0 ) ? nchar : 1 ; nlines = totchar/nchar + 1; if(nlines > maxlines) { // solution does not fit with mediumFont font = smallFont; maxlines = (height-y)/(font->ascent+font->descent+5); xstart = 5 + XTextWidth(smallFont,numfeq,strlen(numfeq)); awid = (width - xstart - 5); awid = ( awid > 0 ) ? awid : font->max_bounds.width ; nchar = awid/font->max_bounds.width; nchar = ( nchar > 0 ) ? nchar : 1 ; nlines = totchar/nchar + 1; if(nlines > maxlines) { // solution does not fit with smallFont font = mediumFont; xstart = 5 + XTextWidth(font,numfeq,strlen(numfeq)); nlines = 1; fact = strdup(" is to Big"); totchar = nchar = strlen(fact); } } } XSetFont(dis,gc,font->fid); // set font in graphic context (GC) y += font->ascent; // initial y location XDrawString(dis,win,gc,5,y, numfeq, strlen(numfeq) ); /* draw the solution string after the equal sign, nchar per line */ for(start = 0; start < totchar; start += nchar) { nchar = ((totchar-start) < nchar)? totchar-start : nchar; XDrawString(dis,win,gc,xstart,y, fact+start, nchar); y += font->ascent + font->descent + 5; // move to y location of next line } free(instr); // release memory for instr string } /* convert k to a binary string (long to binary ascii) * \param k the number to convert * \returns a pointer to a newly allocated character array with the * binary representation of k */ char * ltoba(long long int k) { char * answer; long long int kt; int index; index = 0; kt = k; while( kt>0 ) { index++; kt = kt/2; } answer = (char *)malloc((index+2)*sizeof(char)); answer[index+1] = '\0'; if(index == 0) { answer[0]='0'; } kt = k; while( kt>0 ) { answer[index] = ( kt & 1 ) ? '1' : '0'; kt /= 2; // could also do right shift , kt = kt >> 1, or kt >>= 1 // but sign extension could cause an infinite loop index--; } return answer; } /* convert k to a hex string (long to hex ascii) * \param k the number to convert * \returns a pointer to a newly allocated character array with the * hex representation of k */ char * ltoha(long long int k) { char * answer; long long int kt; int index; int ichar; /* find out how many hex digits required for k */ index = 0; kt = k; while( kt>0 ) { index++; kt = kt/16; } answer = (char *)malloc((index+2)*sizeof(char)); /* mark the end of the string with a null character */ answer[index+1] = '\0'; /* take care of the case where k is 0 */ if(index == 0) { answer[0]='0'; return answer; } /* build the string backwards */ kt = k; while( kt>0 ) { /* the value to be represented by the current character * The percent operator is called mod which is the remainder after division * example: 35 mod 16 (35%16) is 3 */ ichar = kt%16; /* set the character representation of ichar */ switch(ichar) { case 0: answer[index] = '0'; break; case 1: answer[index] = '1'; break; case 2: answer[index] = '2'; break; case 3: answer[index] = '3'; break; case 4: answer[index] = '4'; break; case 5: answer[index] = '5'; break; case 6: answer[index] = '6'; break; case 7: answer[index] = '7'; break; case 8: answer[index] = '8'; break; case 9: answer[index] = '9'; break; case 10: answer[index] = 'a'; break; case 11: answer[index] = 'b'; break; case 12: answer[index] = 'c'; break; case 13: answer[index] = 'd'; break; case 14: answer[index] = 'e'; break; case 15: answer[index] = 'f'; break; } /* an alternative more efficient form for the switch could be: * answer[index] = ( ichar < 10 ) ? '0'+ichar : 'a'+ichar-10 ; * but this is not as portable */ /* go to the next number place by removing the low place * A right shift could also be used here, kt >>= 4; * but sign extension could cause an infinite loop * but could result in anomolies by sign extension */ kt /= 16; index--; // go to the next number place } return answer; } /* descriptive text for top of window * \return newly allocated pointer to char with either default instructions * or indication of precision and number representation * \note the string should be freed to prevent a memory leak */ char * nowShowing() { if( precision || showBin ) { char showing[1024]; char p[9]; char b[9]; switch(precision) { case 1: snprintf(p,8,"8 bytes"); break; case 2: snprintf(p,8,"4 bytes"); break; case 3: snprintf(p,8,"2 bytes"); break; case 4: snprintf(p,8,"1 byte"); break; default: snprintf(p,8,"full"); } switch(showBin) { case 1: snprintf(b,8,"binary"); break; case 2: snprintf(b,8,"hex"); break; default: snprintf(b,8,"decimal"); } snprintf(showing,1023,"%s precision in %s",p,b); return strdup(showing); }else{ return strdup( "Enter digits for a number, [Enter] to clear, or 'q' to quit"); } }

No comments:

Post a Comment