TweetFollow Us on Twitter

Print Window
Volume Number:2
Issue Number:10
Column Tag:ABC's of C

A Print Window for Debugging

By Bob Gordon, Apropos Publications, Contributing Editor

In the first column we did the traditional first C program and wrote "hello, world" on the screen using the C function printf(). Since then we have examined some C programming concepts and gotten a window and menus to appear on the screen. Beginning with this column we are going to spend some time writing to a window. I am going to start by writing some text. My main reason for wanting to start with text is the complaint I had with the LightSpeed C compiler: there was no way to write to the screen and still see the menus and window you put there. Since one of the most useful debugging tools is the ability to print out the value of variables and to get some indication of where you are in a program, I thought a useful and instructive function to write would be a printf()-like routine that would not take over the entire screen. I called the function printw() (print to window), and it turned out to be fairly complex and include some rather obscure C. It is not that important if you don't follow the entire explanation. There is a lot of standard C presented in this month's column, and the function will prove to be quite useful. Type it in and get it working. By the way, it is not finished, and we will add to it in subsequent installments.

C Text Conventions

C compilers provide an escape mechanism in text to allow the placement of non-displayable characters inside a string. The escape character is the backslash (\). Certain characters preceded by the backslash result in a control character. Note that the control character is placed in the string replacing the backslash and the following character. These sequences are referred to in The C Programming Language as character constants.

Sequence ASCII Description

\n LF line feed

\t HT horizontal tab

\v VT vertical tab

\b BS backspace

\r CR carriage return

\f FF form feed

\" double quote

\' single quote

\\ backslash

To use these, just place the sequence where you wish to have the character:

 char   c;
 char   *s;

 c = '\b';
 s = "\nhello, world\n";

You may also follow the backslash with one to three octal (octal!) digits to generate any arbitrary character. You will most often see '\0' which is the null character.

Fig. 1 Our printw() window is out of the way

Loops

Except for the event loop, we have not had much reason to use loops so far. This month, however, there are two functions that scan through strings, and I have used two C looping constructs.

To have a loop that tests before the code is run, use the while loop.

 while (expression )
 statement

The expression may be any C expression. If the expression is true (non-zero), the statement is executed. If the expression is false (zero), the loop is terminated and the expression is not executed.

A second type of loop tests at the bottom. This means that the body of the loop is executed at least once.

 do
 statement
 while (expression  );

In both these loops the statement may consist of any number of C statements surrounded by braces ({}).

Pointers

It is often necessary to loop through strings. Remember that a C string is an array of bytes terminated by the null character ('\0'). A string (or an array) is usually accessed as a pointer. For example, given this declaration:

 char   s[20];   /* an array of twenty bytes */

Assume s is a string with a terminating null character. We could loop through s by:

 while (s[i])

or

 while (*s)

The first form uses an index to access each byte or character. The second uses the name of the array by itself as a pointer. The name of an array is the address of the element zero. The * uses the contents of the pointer and accesses that address to retrieve the value stored there. In our example, s[0] equals *s.

The other operator heavily involved with pointers is the address of operator, &. This returns the address of any object.

 short  x;/* declare x  as a short */
 short  *px;/* px  is a pointer to a short */

 px = &x; /* assign address of x to px */

We have used the address of operator when passing structures to toolbox functions.

Pointer Arithmetic

C knows the size of the object to which a pointer points, so it can handle the process of pointing at the next (or previous) object automatically. If px is a pointer, px += 1 increments px by the size (in bytes) of the object to which px points. If px points to a structure containing 72 bytes, px += 1 adds 72 to the current value of px.

At this point, I should introduce two additional and rather unusual C operators. Since incrementing and decrementing are done so often, C has special operators for these operations.

 ++px;  /* increment px */
 --px;  /* decrement px */

These are unary operators. What is unusual about them is that they may be placed before or after the variable, and the placement affects when the operation is carried out relative to the variables use in an expression. If placed before the variable, the increment (or decrement) operation is done before the variable is used. If placed after, the increment/decrement is done after the variable is used.

 short  x, y, z;

 x = 5;
 y = ++x;

 x = 5;
 z = x++;

In both cases above, x ends up equal to 6. In the first, y is also six, but in the second z is five as the variable, x, is used and then incremented. In many cases it does not matter which you use, but when it does matter, it is a likely source of problems. The notation is often used because it is compact and may result in very efficient code, depending on the compiler. The increment and decrement operators work correctly with pointers: they increment or decrement by the size of the object to which the pointer points.

Writing to a Window

The other point of this month's column was to start using some QuickDraw functions to write to the screen. I only needed DrawChar() and DrawString() to get text on the screen. You will also note a call to ScrollRect(), but it is being used in a very simple way, and I think it would be best if we pretend it isn't really there this month.

What is important to note about writing to the screen is that all writing takes place in objects called GrafPorts. A GrafPort is a complex structure that contains all sorts of information about the environment that the QuickDraw routines will use. In general you need not worry about the individual members of the GrafPort structure as there are functions that provide access to them. Only one GrafPort is active at a time: the QuickDraw routines do not have a parameter that specifies which GrafPort to use; they use the one indicated by SetPort(). This is done near the beginning of printw(). printw() also obtains the current GrafPort and restores it when it is done.

The Macintosh Toolbox with C book has a couple of pages describing how to create and dispose of a GrafPort. What they do not make clear is that by creating a window you have created a GrafPort. If you examine the window structure, WindowRecord, you will see that the first member is a GrafPort and that a WindowPtr is a GrafPtr which is a pointer to a GrafPort. So if you have a window, you have a GrafPort, and you can draw to it.

This Month's Program

This month's program is last month's program [See August 1986, issue of MacTutor. -Ed] with the addition of two functions: printw() and ntoa(). I placed calls to printw() inside domouse() just so I could have printw() work under something I could control. At the moment it does not print out anything interesting, but you can use printw() to examine a variety of variables in the program. Since most of the program is exactly the same as last month's, I am going to discuss only the two new functions.

As we all know, one of the problems with using C on the Mac is the incompatibility between C strings and Pascal strings. These functions use C strings so you can use them in your program without any special worry. printw() does any necessary conversions to Pascal strings before it calls Toolbox routines.

ntoa()

ntoa() converts numbers to ASCII. It is a fairly general purpose routine that handles signed or unsigned numbers and shorts and longs. It begins by checking for signed values. If the variable is signed, it converts it to its absolute value and sets a flag. Then there is a while loop that mods and divides to convert the number to ASCII. It stops when the number goes to zero. At this point the number has been converted but it is in the string backwards. A do-while loop is used to copy the string into the correct order. Finally, the null character is put on the end of the string.

One thing to note is the variable i. It is initialized when it is declared. Automatic and register variables have garbage values until they are initialized either in code or when they are declared. The effect of initializing an automatic variable is the same as setting its value in the code, but sometimes it is clearer to use initialization. Also note the use of casts to convert the value to the correct size. There will be more on this in the discussion of printw().

printw()

This routine contains a certain amount of C esoterica. If you are not interested in how C handles parameters, feel free to skip this discussion. On the other hand, the routine should prove quite useful, and it does follow the tradition established in Kernighan and Ritchie of learning C by examining standard C functions.

printw() mimics the standard C library function printf(). printf() prints to the "standard output device" and can take a variable number of parameters. printw() prints to its own window and also can take a variable number of parameters.

One parameter is required in printf() (and printw()), the control string. This is a string that is printed and may contain a variety of conversion specifications. These have varying complexity and can specify justification, the type and size of a variable to be printed, the width of the field in which to print, and whether the variable is signed or unsigned. Each specification starts with a percent sign (%) and ends with a conversion character. printw() provides a limited subset of these:

d decimal

u unsigned decimal

c a single character*

s a string*

x unsigned hexadecimal*

*Not yet implemented.

You may place a lower case l ('l') before the u or d to indicate the variable is a long rather than a short.

As printw() prints to its own window, the first time it is called it creates the window. The window is set at the bottom of the screen. This is hard coded in the call to SetRect(); change the position or size as desired. In fact it might be useful to have a code in the control string that allows the rectangle to be defined on the fly. To know whether or not the window has been created, it checks the value of pw, the WindowPtr. This is a static variable (static variables retain their values between calls), and actually C guarantees that all statics will be initialized to zero. If pw is zero, the window does not exist so it is created. C also guarantees that no legal pointer will have a value of zero, so we know the value returned by NewWindow() will be non-zero.

I used GetFontInfo() to retrieve the line size. Since this does not change, the computation of line size could be moved inside the window opening code.

Parameter Passing

C generally passes parameters on the stack. LightSpeed C does this. Mac C passes parameters in registers if it can, however you can force it to pass parameters on the stack if you need to. Mac C also has a special, non-standard way of indicating that a function will receive a variable number of parameters. See note at the end.

As the LightSpeed C manual points out, the parameter passing conventions are a de facto standard so what follows may not apply to your compiler. When a function is called, the parameters are placed on the stack from right to left:

 afunc(a,b,c,d);   /* call of afunc() with four                
 parameters */

Picture of stack d

 c
 b
 a
 SP---> return address

As illustrated, d is pushed first, then c, and so on (remember, the stack grows down in memory). This means the first parameter (a) is the last one placed on the stack and is in a known position just above the return address. If the first parameter contains information about the number of parameters passed on a call, we can write a function that can handle a variable number of parameters. Unlike Pascal, the process of cleaning up the stack after the call is handled by the caller. Since the caller knows how many parameters were passed (or where the stack pointer was before the call), the stack can be correctly maintained. printf() and printw() use the percent signs in the control string to determine the number of parameters passed.

The problem now is to determine where the parameters are. The control string is passed as a pointer. That is, we have the address of the string. What we need is the address of the pointer (the parameter). This is obtained by using the address of operator in the line:

 ts = &s;

ts is now a pointer to a pointer to a string. This is converted to a ordinary pointer with a cast on the next line. Finally, we add the size of a pointer to the value to leave us pointing at the second parameter on the stack.

Back to printw()

The major portion of printw() is a case statement that examines every character in the control string. If the character is not a new line or a conversion character, it is drawn in the window (with DrawChar()). If it encounters a new line (\n), it determines if it should scroll the window or not and moves the drawing position to the beginning of the next line. This is where the line size, computed at the beginning of the function, is used. If it finds a percent sign, it begins to determine the kind of parameter.

I think most of the code is fairly straightforward. When the a u or d conversion character is detected, it must extract a number from the parameters. At this point we know if the number is a long or not (having previously detected an 'l' if it is to be a long). Since we have a pointer to a char instead of a parameter, a cast is used to obtain the correct size number.

 num = *(ulong*)ps;

ps is a pointer to a character. The cast (ulong*) converts it to a pointer to an unsigned long (ulong was added to abc.h), and the '*' to the left of the cast dereferences the pointer to obtain the value. Note that the variable num is an unsigned long which is what ntoa() expects.

Another less obvious construction is in the call to ntoa(). ntoa() receives four parameters one of which is a flag indicating whether the value is signed or not (it is True if signed). The call to ntoa() contains

'u' - *s

for the signed parameter. If the conversion character (*s) is a 'u,' this results in a value of zero or False, if it is a 'd,' it will be non-zero and True.

Also note that each time we extract a parameter we increment the parameter pointer, ps, by the size of the parameter. This is an excellent place for the code to get confused.

Note for Mac C

To create a function that deals with a variable number of parameters Mac C uses a special construct. The last parameter in the function must be " " as in:

  int printf(format, arg,  )

If the routine is external (not included in the file in which it is called), it must be declared:

 extern int printf( );

Another difference in Mac C relevant to printw() is the interpretation of the \n character. LightSpeed C (and standard C) interpret the \n as a line feed; Mac C translates it to a carriage return. This should pose no problem if you use the '\n' consistently.

Refer to Appendix A of the Mac C Programmer's Guide for details.

A Problem

In the domouse() routine that passes control to different routines depending on where the mouse is, there are a number of printw() calls. They are there simply to have something print out. Also in this routine is a change from last month's program caused by the addition of the printw(). If the mouse is in the window content area, it may be in the printw() window or some other window. We normally would be interested only in the other window. I added an if-statement here to ensure response only if in the correct window, but this is not a very good solution. Another solution would be to declare the pointer to the printw() window as a global and check that the mouse is not in that window. A third possibility would be a function that checks for the printw() window. Perhaps the best would be a replacement for FindWindow() that could check for the printw() window. This way when it came time to remove the printw(), you could simply link in the correct version of FindWindow().

Current Version of abc.h

/* abc.h 
 *
 * Local definitions to improve readability
 *
 */
 
#define True1
#define False    0
#define Nil 0
#define and &&
#define or||
#define not !
#define equals   ==
#define notequal !=


/* unsigned longs and shorts
 * (unsigned longs may not be 
 *  available with all compilers
 */
#define ushort   unsigned short
#define ulong    unsigned long


/* General purpose external routines 
 * String conversion routines 
 * return a pointer to a char 
 */
extern  char*CtoPstr();
extern  char*PtoCstr(); 
Program with printw()
/* Sending text to window with
 *  function that accepts a variable
 * number of parameters
 *
 * Compiled with LightspeedC
 * Note LS puts 'Mgr' in h file names!
 * (load MacTraps into the project first.)

 * Important note for Mac C users:
 * Every place you see event->where,
 * replace it with &event->where
 */
 
 #include "abc.h"
 #include "Quickdraw.h"
 #include "EventMgr.h"
 #include "WindowMgr.h"
 #include "MenuMgr.h"
 
 /* defines for menu ID's */
 
 #defineMdesk    100
 #defineMfile    101
 #defineMedit    102
 #defineMwind    103
 #defineMtest    104
 
 /* Global variables */
 
 MenuHandle menuDesk;/* menu handles */
 MenuHandle menuFile;
 MenuHandle menuEdit;
 MenuHandle menuWind;
 MenuHandle menuTest;
 
 WindowPtrtheWindow;
 WindowRecord    windowRec;
 Rect   dragbound;
 Rect   limitRect;
 
main()
{
 initsys(); /* system initialization */
 initapp(); /* application initialization */
 eventloop();
}

/* system initialization 
 * note use of hard coded screen sizes
 * with LightspeedC.  This will work
 * with other compilers but is not
 * good practice
 */
initsys() 
{
 InitGraf(&thePort); /* these two lines done */
 InitFonts();    /* automatically by Mac C */
 InitWindows();
 InitCursor();
 InitMenus();
 theWindow = Nil;/*indicates no window */
 SetRect(&dragbound,0,0,512,250);
 SetRect(&limitRect,60,40,508,244);
}

/*
 * application initialization
 * Sets up menus.
 * Each menu is a separate group
 * of lines.  Note the last menu
 * is appended but not inserted.  This
 * makes it part of the menu list but 
 * not in the menu bar.
 */
initapp()
{
 menuDesk = NewMenu(Mdesk,CtoPstr("\24"));
 AddResMenu (menuDesk, 'DRVR');
 InsertMenu (menuDesk, 0);
 
 menuFile = NewMenu(Mfile, CtoPstr("File"));
 AppendMenu (menuFile, 
 CtoPstr("Open Window/M;Close Window/X;Quit/Q"));
 AppendMenu (menuFile, 
 CtoPstr("(-;Show Test;(Hide Test"));
 InsertMenu (menuFile, 0);
 
 menuEdit = NewMenu(Medit, CtoPstr("Edit"));
 AppendMenu (menuEdit, 
 CtoPstr("Undo;(-;Cut;Copy;Paste;Clear"));
 InsertMenu (menuEdit, 0);
 
 menuWind = NewMenu(Mwind, CtoPstr("Window"));
 AppendMenu (menuWind, 
 CtoPstr("Hide;Show;New Title"));
 InsertMenu (menuWind, 0);
 
 menuTest = NewMenu(Mtest, CtoPstr("Test"));
 AppendMenu (menuTest, 
 CtoPstr("Pick;One;Of;These"));
 
 DrawMenuBar();
}
 
/* Event Loop 
 * Loop forever until Quit
 */
eventloop()
{
 EventRecordtheEvent;
 char   c;
 short  windowcode;
 WindowPtrww;
 
 while(True)
 {
 if (theWindow)      /* this code is here to prevent */
 { /* closing an already closed */
 EnableItem(menuFile,2);  /* window! */
 DisableItem(menuFile,1);
 }
 else   
 { 
 EnableItem(menuFile,1);
 DisableItem(menuFile,2);
 }
 
 if (GetNextEvent(everyEvent,&theEvent))
 switch(theEvent.what)  
 { /* only check key and */
 case keyDown:   /* mouse down events */
 if (theEvent.modifiers & cmdKey)
 {
 c = theEvent.message &   charCodeMask;
 domenu(MenuKey(c));
 }
 break;
 case mouseDown:
 domouse(&theEvent);
 break;
 default:
 break;
 }
 }
}


/* domouse
 * handle mouse down events
 */
domouse(er)
 EventRecord*er;
{
 short  windowcode;
 WindowPtrwhichWindow;
 short  ingo;
 long   size;
 ushort t1 = 0xFFFF;
 short  t2 = 0xFFFF;
 
 windowcode = FindWindow(er->where, &whichWindow);
 switch (windowcode)
 {
 case inDesk:
 if (theWindow notequal 0)
 {
 HiliteWindow(theWindow, False);
 DrawGrowIcon(theWindow);
 }
 printw(" In Desk %d %ld %d ",10,123L,-456);
 break;
 case inMenuBar:
 printw("\nIn MenuBar %u %d ",t2,t1);
 domenu(MenuSelect(er->where));
 break;
 case inSysWindow:
 SysBeep(1);
 break;
 case inContent:
 printw("\nIn content %ld %d",700000,700000);
 if (whichWindow equals theWindow)
 {
 HiliteWindow(whichWindow,True);
 DrawGrowIcon(theWindow);
 }
 break;
 case inDrag:
 DragWindow(whichWindow, er->where, &dragbound);
 DrawGrowIcon(theWindow);
 break;
 case inGrow:
 /* not included this month */
 break;
 case inGoAway:
 ingo = TrackGoAway(whichWindow,er->where);
 if (ingo)
 {
 CloseWindow(whichWindow);
 theWindow = Nil;
 }
 break;
 }
}

/* domenu
 * handles menu activity
 * simply a dispatcher for each
 * menu.
 */
domenu(mc)
 long   mc; /* menu result */
{
 short  menuId;
 short  menuitem;
 
 menuId = HiWord(mc);
 menuitem = LoWord(mc);
 
 switch (menuId)
 {
 case Mdesk  : 
 break; /* not handling DA's */
 case Mfile  : 
 dofile(menuitem);
 break;
 case Medit  : 
 break;
 case Mwind : 
 dowind(menuitem);
  break;
 case Mtest : 
 dotest(menuitem);
 break;
 }
 HiliteMenu(0);
}

/* dofile
 * handles file menu
 */
dofile(item)
 short  item;
{
 char   *title1; /* first title for window */
 Rect   boundsRect;
 
 switch (item)
 {
 case 1 : /* open the window */
 title1 = "ABC Window";
 SetRect(&boundsRect,50,50,300,150);
 theWindow = NewWindow(&windowRec, &boundsRect,
 CtoPstr(title1),True,documentProc,
 (WindowPtr) -1, True, 0);
 DrawGrowIcon(theWindow);
 PtoCstr(title1);
 DisableItem(menuFile,1);
 EnableItem(menuFile,2);
 break;
 
 case 2 : /* close the window */
 CloseWindow(theWindow);
 theWindow = Nil;
 DisableItem(menuFile,2);
 EnableItem(menuFile,1);
 break;
 
 case 3 : /* Quit */
 ExitToShell();
 break;
 
 case 5 : /* Install additional menu */
 InsertMenu(menuTest,0);
 EnableItem(menuFile,6);
 DisableItem(menuFile,5);
 DrawMenuBar();
 break;
 
 case 6 : /* remove additional menu */
 DeleteMenu(Mtest);
 EnableItem(menuFile,5);
 DisableItem(menuFile,6);
 DrawMenuBar();
 break;
 }
}

/*
 * dowind
 * handles window menu 
 * Note that each case contains an
 * if testing the existance of the
 * window.  This could be written
 * with one if before the switch.
 */
dowind(item)
 short  item;
{
 char   *title2; /* second title for window */
 
 switch (item)
 {
 case 1 : /* Hide */
 if (theWindow)
 HideWindow(theWindow);
 break;
 case 2 : /* Show */
 if (theWindow)
 ShowWindow(theWindow);
 break;
 case 3 : /* Change title */
 if (theWindow)
 {
 title2 = "A Different Title";
 SetWTitle(theWindow, CtoPstr(title2));
 PtoCstr(title2);
 }
 break;
 }
}

/* dotest
 * Handles new menu.
 * All this does is mark menu
 * items if they are not marked and
 * unmark them if they are.
 */
dotest(item)
 short  item;
{
 short  mark;
 
 GetItemMark(menuTest,item,&mark);
 if (mark)
 CheckItem(menuTest,item,False);
 else
 CheckItem(menuTest,item,True);
}

/* Displays strings and numbers in a 
 * special window
 * This function is designed to receive
 * a variable number of parameters. The 
 * number is computed by the number of
 * percent signs in the control string.
 * If the number of parameters following the 
 * control string does not match the 
 * number of percent signs, expect 
 * the unexpected.
 */
printw(s)
 char   *s; /* the control string */
{
#define Bufsz  14/* size of buffer to hold */
 /* converted numbers */  

static Rect boundsRect; /* variables for */
static Rect windowRect; /* defining printw */
static WindowRecordwrc;   /* window, pw is */
static WindowPtr pw = 0;  /* initialized to 0 */
WindowPtr oldport; /* save grafport here */
short   linesz;  /* size of line */
FontInfoinfo;    
short   nl;
Point   pt;
RgnHandle updrgn;/* needed for scrolling */
char    numAsStr[Bufsz];  /* number conversion */
short   nsz;/* size of numbers (2 or 4) */
char    **ts;    /* ptr to ptr to ctrl string */
char    *ps;/* ptr to parameters */
ulong   num;/* for number conversion */
short   convchar;/* found conversion char */
short   islong;  /* number is a long */
 
/* Window rectancgle coordinates */

#define wl0
#define wr512
#define wt250
#define wb342
 
 
GetPort(&oldport); /* save current graph port */
GetFontInfo(&info);/* compute line height */
linesz = info.ascent + info.descent;
if (pw equals 0) /* if window does not exist*/
 { /*  open it */
 SetRect(&boundsRect,wl,wt,wr,wb);
 pw = NewWindow(&wrc, &boundsRect,
 CtoPstr(""),True,plainDBox,
 (WindowPtr) -1, True, 0);
 nl = linesz;    /* move down one line as */
 } /*  writing will be above */
 else   /*  boundary.  No need to  */
 nl = 0;/*  move line if  open */
 SetPort(pw);    /* Set port to this window */
 Move(0,nl);/* Move (relative) */
 
 ts = &s; /* get address of control string ptr */
 ps = (char *)ts;/* convert to pointer to params */
 ps += sizeof(long); /* skip over control string pointer*/
 while (*s) /* loop until end of control string */
 {
 switch (*s)/* check each character */
 {
 case '%' : /* percent sign: check conversion */
 s++;   /* point to next char */
 convchar = False; /* initialize conv  loop */
 islong = False;
 do {   /*  until reach conv char */
 switch (*s)
 {
 case 'l' : /* indicates a long */
 islong = True;
 s++;
 break;
 case 'u' : /* unsigned decimal */
 case 'd' : /* signed decimal */
 if (islong)/* extract number  */
 {
 num = *(ulong*)ps;
 nsz = sizeof(long);
 }
 else
 {
 num = *(ushort*)ps;
 nsz = sizeof(short);
 }
 ps += nsz; /* point to next param */
 /* convert number and write it to 
  *   window
  */
 ntoa(num,nsz,'u' - *s,numAsStr);
 DrawString(CtoPstr(numAsStr));
 convchar = True;
 break;
 /* strings, individual chars and hex numbers handled yet */
 case 's'   :
 break; 
 case 'c' :
 break;
 /* if it is not any expected char,
  * write it out and go on
  */
 default:   
 DrawChar(*s);
 convchar = True;
 } 
 } while (not convchar);
 break;
 case '\n' :/* newline ('\n') in control string */
 GetPen(&pt);  /* find current pen position */
 if (pt.v+linesz > wb-wt)   /* if it goes off , */
 { /* scroll the window */
 updrgn = NewRgn();
 ScrollRect(&(pw->portRect),0,-linesz,updrgn);
 DisposeRgn(updrgn);  /* no update */
 Move(0,-linesz);/* move onto window */
 }
 Move(-pt.h,linesz);/* move to next line */  break;
 default :/* any other character gets */
 DrawChar(*s); /*  written on the window */
 }
 s++;   /* move pointer to next char */
 } /*  in control string and cont*/
 SetPort(oldport); /* restore orignal graf port */
}

/* Convert numbers to ascii strings
 * Handles signed and unsigned
 * short and long values
 * Note:Length of string returned 
 * must be large enough to 
 * hold -2G (12 bytes)
 */
ntoa(n,len,issigned,s)
 ulong  n;/* number to convert */
 short  len;/* size of n (2 or 4)*/
 short  issigned;/* signed flag */
 char   *s; /* string to return */
{
 char   ts[12];  /* temporary string */
 int    i = 0;   /* counter, initialized */
 ulong  m;/* working copy of */
 long   sm; /* to convert signed values */
 
 if (n equals 0) /* if n is zero, place '0' */
 ts[i++] = '0';  /*  in temporary string */
 else
 {
 if (issigned)   /* if sign flag is set, */
 { /*  convert to signed value */
 if (len equals sizeof(long))
 sm = (long)n;
 else
 sm = (short)n;
 if (issigned = sm < 0) /* Check if value is */
 n = -sm; /*  negative. If so, */
 } /*  keep the flag and */
 /*  get the absolute value */
 while (n)/* Convert number into ascii */
 { /*  by repeatedly taking mod */
 ts[i++] = n % 10 + '0';  /*  and dividing.  */
 n /= 10; /*  This gives a string in */
 } /*  reverse order */
 if (issigned)   /* If number was negative, */
 ts[i++] = '-';  /*  stick a minus sign in */
 } /*  the string.*/
 
 do{    /* Reverse the string */
 *s++ = ts[--i]; /*  to the correct direction*/
 } 
 while (i);

 *s = '\0'; /* Place null terminator on */
}/*  string */
 
AAPL
$97.23
Apple Inc.
-0.92
MSFT
$43.45
Microsoft Corpora
-0.13
GOOG
$583.21
Google Inc.
-4.21

MacTech Search:
Community Search:

Software Updates via MacUpdate

OmniPlan 2.3.6 - Robust project manageme...
With OmniPlan, you can create logical, manageable project plans with Gantt charts, schedules, summaries, milestones, and critical paths. Break down the tasks needed to make your project a success,... Read more
Command-C 1.1.1 - Clipboard sharing tool...
Command-C is a revolutionary app which makes easy to share your clipboard between iOS and OS X using your local WiFi network, even if the app is not currently opened. Copy anything (text, pictures,... Read more
Knock 1.1.7 - Unlock your Mac by knockin...
Knock is a faster, safer way to sign in. You keep your iPhone with you all the time. Now you can use it as a password. You never have to open the app -- just knock on your phone twice, even when it's... Read more
Mellel 3.3.6 - Powerful word processor w...
Mellel is the leading word processor for OS X and has been widely considered the industry standard since its inception. Mellel focuses on writers and scholars for technical writing and multilingual... Read more
LibreOffice 4.3.0.4 - Free Open Source o...
LibreOffice is an office suite (word processor, spreadsheet, presentations, drawing tool) compatible with other major office suites. The Document Foundation is coordinating development and... Read more
Freeway Pro 7.0 - Drag-and-drop Web desi...
Freeway Pro lets you build websites with speed and precision... without writing a line of code! With it's user-oriented drag-and-drop interface, Freeway Pro helps you piece together the website of... Read more
Drive Genius 3.2.4 - Powerful system uti...
Drive Genius is an OS X utility designed to provide unsurpassed storage management. Featuring an easy-to-use interface, Drive Genius is packed with powerful tools such as a drive optimizer, a... Read more
Vitamin-R 2.15 - Personal productivity t...
Vitamin-R creates the optimal conditions for your brain to work at its best by structuring your work into short bursts of distraction-free, highly focused activity alternating with opportunities for... Read more
Toast Titanium 12.0 - The ultimate media...
Toast Titanium goes way beyond the very basic burning in the Mac OS and iLife software, and sets the standard for burning CDs, DVDs, and now Blu-ray discs on the Mac. Create superior sounding audio... Read more
OS X Yosemite Wallpaper 1.0 - Desktop im...
OS X Yosemite Wallpaper is the gorgeous new background image for Apple's upcoming OS X 10.10 Yosemite. This wallpaper is available for all screen resolutions with a source file that measures 5,418... Read more

Latest Forum Discussions

See All

Plants vs. Zombies 2 Enters the Second H...
Plants vs. Zombies 2 Enters the Second Half of the Dark Ages Posted by Ellis Spice on July 31st, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Why Does It Spin? (Games)
Why Does It Spin? 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: THERE'S ONLY ONE RULE: DON'T TOUCH THE WALLS! Do you think you're able to follow this simple rule even if you would have to... | Read more »
Ice Wings Plus (Games)
Ice Wings Plus 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: THE GREAT ENDLESS RUNNER OF COMBAT JETS IS BACK !! With more than 680.000 downloads in the App Store, Ice Wings: Skies of Steel... | Read more »
Murl the Squirrel (Games)
Murl the Squirrel 1.0 Device: iOS Universal Category: Games Price: $.99, Version: 1.0 (iTunes) Description: Meet Murl. He is teased by a group of flying squirrels because he can't fly. Determined to show them he's can fly, he meets... | Read more »
Celleste (Games)
Celleste 0.1 Device: iOS Universal Category: Games Price: $2.99, Version: 0.1 (iTunes) Description: Lots of cute action with amazing 3D graphics and a new type of gameplay! Take control over the forces of the universe to help a group... | Read more »
Super Heavy Sword (Games)
Super Heavy Sword 0.0.1 Device: iOS Universal Category: Games Price: $.99, Version: 0.0.1 (iTunes) Description: Get Ready to Get HEAVY! Monster Robot Studios presents SUPER Heavy Sword! The sequel to the smash hit HEAVY sword which... | Read more »
Angels In The Sky (Games)
Angels In The Sky 1.00 Device: iOS Universal Category: Games Price: $6.99, Version: 1.00 (iTunes) Description: - A.I.S will only run smoothly on iPhone 5s. It's NOT compatible with iPad, iPhone 5 or earlier devices.- In order to... | Read more »
80 Days (Games)
80 Days 1.0.2 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.2 (iTunes) Description: 1872, with a steampunk twist. Phileas Fogg has wagered he can circumnavigate the world in just eighty days. Choose your own route... | Read more »
Micromon (Games)
Micromon 1.0 Device: iOS Universal Category: Games Price: $.99, Version: 1.0 (iTunes) Description: 130+ Animated Monsters to Catch & Battle! No waiting, play at your own pace! Embark on an epic monster capture RPG like none... | Read more »
Empire Manager (Games)
Empire Manager 1.0 Device: iOS iPhone Category: Games Price: $3.99, Version: 1.0 (iTunes) Description: Become ruler of an empire. Manage your economy, develop technology, hire an army and conquer the world in this addictive turn-... | Read more »

Price Scanner via MacPrices.net

iPad Cannibalization Threat “Overblown”
Seeking Alpha’s Kevin Greenhalgh observes that while many commentators think Apple’s forthcoming 5.5-inch panel iPhone 6 will cannibalize iPad sales, in his estimation, these concerns are being... Read more
Primate Labs Releases July 2014 MacBook Pro P...
Primate Labs’ John Poole has posted Geekbench 3 results for most of the new MacBook Pro models that Apple released on Tuesday. Poole observes that overall performance improvements for the new MacBook... Read more
Apple Re-Releases Bugfixed MacBook Air EFI Fi...
Apple has posted a bugfixed version EFI Firmware Update 2.9 a for MacBook Air (Mid 2011) models. The update addresses an issue where systems may take longer to wake from sleep than expected, and... Read more
Save $50 on the 2.5GHz Mac mini, plus free sh...
B&H Photo has the 2.5GHz Mac mini on sale for $549.99 including free shipping. That’s $50 off MSRP, and B&H will also include a free copy of Parallels Desktop software. NY sales tax only. Read more
Save up to $140 on an iPad Air with Apple ref...
Apple is offering Certified Refurbished iPad Airs for up to $140 off MSRP. Apple’s one-year warranty is included with each model, and shipping is free. Stock tends to come and go with some of these... Read more
$250 price drop on leftover 15-inch Retina Ma...
B&H Photo has dropped prices on 2013 15″ Retina MacBook Pros by $250 off original MSRP. Shipping is free, and B&H charges NY sales tax only: - 15″ 2.3GHz Retina MacBook Pro: $2249, $250 off... Read more
More iPad Upgrade Musings – The ‘Book Mystiqu...
Much discussed recently, what with Apple reporting iPad sales shrinkage over two consecutive quarters, is that it had apparently been widely assumed that tablet users would follow a two-year hardware... Read more
13-inch 2.5GHz MacBook Pro on sale for $999,...
Best Buy has the 13″ 2.5GHz MacBook Pro available for $999.99 on their online store. Choose free shipping or free instant local store pickup (if available). Their price is $100 off MSRP. Price is... Read more
Save up to $300 on an iMac with Apple refurbi...
The Apple Store has Apple Certified Refurbished iMacs available for up to $300 off the cost of new models. Apple’s one-year warranty is standard, and shipping is free. These are the best prices on... Read more
WaterField Unveils 15″ Outback Solo & 13″...
Hard on the heels of Apple’s refreshed MacBook Pro Retina laptops announcement, WaterField Designs has unveiled a 15-inch version of the waxed-canvas and leather Outback Solo and a 13-inch version of... Read more

Jobs Board

Sr. Product Leader, *Apple* Store Apps - Ap...
**Job Summary** Imagine what you could do here. At Apple , great ideas have a way of becoming great products, services, and customer experiences very quickly. Bring Read more
Sr Software Lead Engineer, *Apple* Online S...
Sr Software Lead Engineer, Apple Online Store Publishing Systems Keywords: Company: Apple Job Code: E3PCAK8MgYYkw Location (City or ZIP): Santa Clara Status: Full Read more
Sr Software Lead Engineer, *Apple* Online S...
Sr Software Lead Engineer, Apple Online Store Publishing Systems Keywords: Company: Apple Job Code: E3PCAK8MgYYkw Location (City or ZIP): Santa Clara Status: Full Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
Sr. Product Leader, *Apple* Store Apps - Ap...
**Job Summary** Imagine what you could do here. At Apple , great ideas have a way of becoming great products, services, and customer experiences very quickly. Bring Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.