TweetFollow Us on Twitter

Text Display
Volume Number:2
Issue Number:11
Column Tag:ABC's of C

Text Display from Quickdraw

By Bob Gordon, Apropos Publications, MacTutor Contributing Editor

Text Display on the Mac

Like last month's, this month's column deals with using QuickDraw routines for writing text to a window. Last month we only needed a couple of routines to get printw() working; this time I tried to use as many of the QuickDraw text functions as I could. [Note that Quickdraw is the only way text can be drawn to the screen. Ultimately, all programs no matter how sophisticated must use Quickdraw to get text on the screen. -Ed]

Those who have been reading along since the ABC's of C started will realize we have almost covered all of C. This does not mean we are done, but does reflect the nature of C as a language. C is a relatively small language. If you count keywords, for example, it has fewer than many dialects of Basic. On the other hand, much of the language's capabilities are not in the language itself but are in one or another libraries. Many capabilities included in other languages (such as file access and I/O) are in libraries. In learning to use C on the Macintosh, the main part of the problem is to learn to use the various Toolbox functions. We have done menus and started windows. The plan is to now follow the chapters in Using the Macintosh Toolbox with C and focus on the Toolbox. This will result in a distorted view of C, in that we will not generally discuss the standard C functions if there is an analogous Macintosh function.

Short Personal Digression

You may have noticed the note in the September issue. I came down with an exotic, flu-like disease that lasted about two weeks and had me bedridden for one of them. It must have been reasonably serious because my doctor threatened to stick an IV in my arm and put me in the hospital. I convinced her that such measures were not necessary and seem to have survived.

But then over Labor Day weekend, my Mac died. I stepped out of the room to check on the state of the children, and when I returned the screen was dark and there was the unmistakeable smell of fried electrons. I quickly turned everything off, but it was clear that some component had expired. My diagnosis was that the analog board had failed. I called around to get estimates for replacing the analog board. These ranged from just over $100 to over $200. If you are unlucky enough to have your Mac fail, be sure to get estimates. I figure I saved $90.00 to $100.00 just by spending some time on the phone.

Fig. 1 Text from Quickdraw

Text on the Macintosh

Anyone who has ever seen a Mac realizes that unlike conventional computers, the Macintosh displays text in different sizes, styles, and fonts. While the Macintosh Toolbox contains a set of text-editing functions (TextEdit), they are limited to displaying only one font/size/style at a time. By directly calling the QuickDraw functions, we can display text almost any way we want. In order to do this, I first set up menus to allow user control over the font, style, and size, and then placed a routine in the event loop to capture keys and write them to a window. That is all this month's program does. It does not word wrap, scroll, backspace, or do any other useful editing operation.

Text Menus

Like the Desk Accessories, the font menu is acquired with AddResMenu(). AddResMenu() searches resource files for resources of the type specified and appends them to the menu. So only two lines are needed to create the font menu:

 menuFont = NewMenu(Mfont), CtoPstr("Font"));
 AddResMenu (menuFont, 'FONT');

This creates the menu, but a program cannot use the information directly. The program needs to be able to use the font number that identifies the font. When a user pulls down a menu and selects an item, the program receives a number indicating which menu and which item. Since the program has no idea of the available fonts or their position in the menus, we need a way to determine the font number from the item number. Two functions accomplish this. The first supplies the item text given the number, and the second supplies the font number given the font name. These functions are called in dofont():

 GetItem(menuFont,item,&itemS);
 GetFNum(&itemS,&cfont);

The parameter itemS is a Pascal string. There is no need to call CtoPstr() because both routines are from the Toolbox and both expect Pascal strings. cfont receives the font number which is passed to the editor routines with ed_cset(). (I am taking the liberty of calling them editor routines even though they do no editing. Perhaps someday they will.)

The operation of the size menu is simpler. The sizes displayed in the menu are 9, 10, 12, 14, 18, 24, 28, and 36 points. To get the correct size from the menu item, a global array called sizes is initialized to those values. In C, all arrays start at zero so the zero element is not used, at least not directly from the menu. You will note it is initialized to 8 points. One of the styles supported is “Small Caps,” and the 8 point size is used to make small caps for the 9 point size.

One of the features of size menus is that they let the user know which sizes are available and which must be scaled. This varies with the font and so is included in dofont(). A function from the font manager, RealFont() returns a true value if the font in a given size actually exists. The following little loop provides this feature.

 for (i = 1; i < Nsize; i++)
 if (RealFont(cfont, sizes[i]))
     SetItemStyle(menuSize,i,OutlineStye);
 else
 SetItemStyle(menuSize,i,0);

This also shows a for loop. The statement consists of five components:

 for ( initialize ; test ; increment ) 
 statement;
  

This directly translates into the following while loop:

 initialize;
 while ( test )
 {
 statement;
 increment;
 }

This translation shows how the loop is constructed. The initialization takes place once before the loop begins. The test occurs at the top of the loop, and the increment at the bottom. The primary advantage of using a for over a while is that all the loop components are available on one line. You may omit any of the components on the for line but the semicolons must be there as place holders.

It is also possible to have several statements in the for:

 for (i = 0, j = 0; i < 10; i++, j++)
 statement;

Commas separate statements within each line section.

The final text menu handles the style. I have included all the styles I have seen, which include:

Plain

Bold

Italic

Underline

Outline

Shadow

Condensed

Extended

Small Caps

Superscript

Subscript

The first eight are standard Macintosh styles; the others are in MacWrite or Word. As anyone familiar with the Mac is aware, the styles generally may be combined. I assumed that it makes no sense to combine Condensed and Extended or Superscript and Subscript. This complicates the menu arrangement a bit, as selection of an item does not mean just setting or removing a check mark. The total style is collected in a short, in which each bit represents one style. Since only ten bits are in use so far (Plain is all bits off) suggestions for additional styles are open (would it, for example, be nice to set a block of text to all upper case or lower case as in MacDraw?). Where possible, the style menu illustrates the style through the use of the menu meta-characters.

Getting the Text

The eventloop() detects keyDown events. If the command key is not down, it calls ed_key() to send the character to the window. The event loop does not call ed_key() unless the window has been opened to prevent writing to an unopened window. At the moment it does not detect auto-key events. This would be something to add.

The Edit Functions

There are several Edit functions, but only two of them are of real importance. Two, ed_init() and ed_new() do some simple initialization. For this program they probably could have been combined. The most important thing that ed_new() does is to call each of the text-setting functions, dofont(), dosize(), and dostyle(), to establish initial conditions and set the menus accordingly. Each of those functions contains special code to handle the situation where the item equals zero. Since the item cannot equal zero when it is the result of mouse input, I used it for initialization.

Any time there is a change in font, size, or style, the relevant function calls ed_cset() where the change is noted and stored. ed_cset does not effect the change; it just keeps it around. This allows users to change their minds by making repeated changes through the menu without affecting anything. The change is put into effect when ed_key() is called from the event loop.

The function ed_key() does most of the work. It calls the various QuickDraw routines for changing font, size, and style, uses DrawChar() to write the character. For each kind of change it checks the flag in edbuf.cesc, and if the flag is set, it gets the value and does the change.

The styles not built into QuickDraw require special handling. To deal with the super and subscripts, ed_key() retrieves the pen position and adjusts it vertically. It does this for every character written. It probably could be done only when the the styles involved changed, but this logic is simpler.

Prior to writing each character, ed_key() checks if small caps is on. If it is, and the character is a lower case letter, it sets the size to the next smaller size (in the menu), converts the character to upper case, draws it and sets the size back to the original size. The actual character itself is not affected. Two library functions, islower() and toupper(), provide the test of lower case and change to upper case. These are part of a set of character functions that most C compilers include. I have not used the library, but included the functions right in the program. This is not due to any aversion to using libraries, but because the functions in the Lightspeed library use a C construct we have not used before:

 toupper(c)
 char c;
 {
 return( c>='a')&&(c<='z') ? (c-32) : c);
 }

This construction may be read:

 test ? do if true : do if false

As can be seen in toupper(), this form can be rather cryptic at first. toupper() simply asks if the character, c, is greater or equal to 'a' and less than or equal to 'z.' If it is, subtract 32 (converts to upper case in ASCII) and return that value; if not, return c unchanged.

Organization of the Program

The edit functions are in a separate file, and there is a separate header file, ed.h, that is included in the main program and in ed.c.

You will notice several lines in ed_key() that serve no apparent purpose. The structure edbuf contains a buffer in all characters and font/size/style changes are written (though the line that writes to the buffer is commented out). This is to allow eventual updating of the window.

printw()

There have been two changes to printw(). First, I fixed a bug. Previously it determined the line size on each call from the Grafport that was open when it was called. This resulted in rather odd interaction between the window being written by ed_key(), the printw() window and the menus. At one time I had menus with text in one or two point type. I moved the determination of line size inside the if-statement that is done the first time printw() is called.

The other change is the addition of code to print strings. This prints only C strings. We probably should add the ability to print Pascal strings and points and rectangles. Some of these changes may happen for next month.

Next Month

I hope to get my Mac upgraded with the 128K ROMs and the 800K drive. I also hope to stay healthy. We will continue to explore QuickDraw. I intend to draw various shapes on the screen.


/* QD1.C
 *    Sending text to window with
 *    function that accepts a variable
 * number of parameters
 *
 * Compiled with LightspeedC
 *
 * 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"
 #include "FontMgr.h"
 #include "ed.h" 
 
 /* defines for menu ID's */
 
 #defineMdesk    100
 #defineMfile    101
 #defineMedit    102
 #defineMfont    103
 #defineMstyl    104
 #defineMsize    105
 
 /* Window items */
 /* File */
 #defineiNew1
 #defineiClose 2
 #defineiQuit  3
 
 /* Edit */
 #defineiUndo  1
 #defineiCut3
 #defineiCopy  4
 #defineiPaste 5
 
 /* Style */
 #defineiPlain 1
 #defineiBold  2
 #defineiItalic  3
 #defineiUline 4
 #defineiOline 5
 #defineiShado 6
 #defineiCon7
 #defineiExt8
 #defineiScaps 9
 #defineiSuper 10
 #defineiSub11
 
 #definePlainStyle 0
 #defineBoldStyle1
 #defineItalicStyle2
 #defineUnderStyle 4
 #defineOutlineStyle 8
 #defineShadowStyle16
 #defineCondStyle32
 #defineExtStyle 64
 
 
 
 /* Global variables */
 
 MenuHandle menuDesk;/* menu handles */
 MenuHandle menuFile;
 MenuHandle menuEdit;
 MenuHandle menuFont;
 MenuHandle menuStyl;
 MenuHandle menuSize;
 
 
 WindowPtrtheWindow;
 WindowRecord    windowRec;
 Rect   dragbound;
 Rect   limitRect;
 
 #defineNsize  9
 
 uchar  sizes[Nsize] = {8,9,10,12,14,18,24,28,36};
 
 
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.
 * Initialize ed
 */
initapp()
{
 setupmenu();
 ed_init();
}

/*
 * set up application's menus
 * Each menu is a separate group
 * of lines.  
 */
setupmenu()
{
 menuDesk = NewMenu(Mdesk,CtoPstr("\24"));
 AddResMenu (menuDesk, 'DRVR');
 InsertMenu (menuDesk, 0);
 
 menuFile = NewMenu(Mfile, CtoPstr("File"));
 AppendMenu (menuFile, CtoPstr("New;Close;Quit/Q"));
 InsertMenu (menuFile, 0);
 
 menuEdit = NewMenu(Medit, CtoPstr("Edit"));
 AppendMenu (menuEdit, CtoPstr( "(Undo/Z;(-;(Cut/X;(Copy/C;(Paste/V;(Clear"));
 InsertMenu (menuEdit, 0);
 
 menuFont = NewMenu(Mfont, CtoPstr("Font"));
 AddResMenu (menuFont, 'FONT');
 InsertMenu (menuFont, 0);
 
 menuStyl = NewMenu(Mstyl, CtoPstr("Style"));
 AppendMenu (menuStyl, 
 CtoPstr("Plain/P;<BBold/B;<IItalic/I;<UUnderline/U;"));
 AppendMenu (menuStyl,CtoPstr( "<OOutline/O;<SShadow/S;Condensed;Extended"));
 AppendMenu (menuStyl,CtoPstr( "SmallCaps;Superscript/H;Subscript/L"));
 InsertMenu (menuStyl, 0);
 
 menuSize = NewMenu(Msize, CtoPstr("Size"));
 AppendMenu (menuSize,CtoPstr( "09 Point;10 Point;12 Point;14 Point"));
 AppendMenu (menuSize,CtoPstr( "18 Point;24 Point;28 Point;36 Point"));
 InsertMenu (menuSize, 0);
 
 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 */
 EnableItem(menuFile,2);  /* closed 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 */
 c = theEvent.message & charCodeMask;
 if (theEvent.modifiers & cmdKey)
 domenu(MenuKey(c));
 else if (theWindow)
 ed_key(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;
 long   newsize;
 
 
 windowcode = FindWindow(er->where, 
 &whichWindow);
 switch (windowcode)
 {
 case inDesk:
 if (theWindow notequal 0)
 {
 HiliteWindow(theWindow, False);
 DrawGrowIcon(theWindow);
 }
 break;
 case inMenuBar:
 domenu(MenuSelect(er->where));
 break;
 case inSysWindow:
 SysBeep(1);
 break;
 case inContent:
 if (whichWindow equals theWindow)
 {
 HiliteWindow(whichWindow,True);
 DrawGrowIcon(theWindow);
 }
 break;
 case inDrag:
 DragWindow(whichWindow, 
   er->where, &dragbound);
 DrawGrowIcon(theWindow);
 break;
 case inGrow:
 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; 
 /*apple menu not handling DA's */
 case Mfile : dofile(menuitem);
  break;
 case Medit : /* all disabled */
  break;
 case Mfont : dofont(menuitem);
  break;
 case Mstyl : dostyle(menuitem);
  break;
 case Msize : dosize(menuitem);
  break;
 }
 HiliteMenu(0);
}

/* dofont
 * marks selected font and obtains
 * font number.  modifies size 
 * menu to reflect available sizes
 * If item is zero, sets item to 3
 * (geneva, the application default)
 */
 
 dofont(item)
 short  item;
 {
 Str255 itemS;
 short  cfont; /* actual font number */
 short  i;
 static short  lastitem = 0;
 
 if (item equals 0)
 do
   {
   item++;
   GetItem(menuFont,item,&itemS);
   GetFNum(&itemS,&cfont);
   }
 while (cfont notequal 3);
 CheckItem (menuFont,lastitem,False);
 CheckItem (menuFont,item,True);
 lastitem = item;
 GetItem(menuFont,item,&itemS);
 GetFNum(&itemS,&cfont);
 for (i = 1; i < Nsize; i++)
 {
 if (RealFont(cfont,sizes[i]))
 SetItemStyle(menuSize,i,OutlineStyle);
 else
 SetItemStyle(menuSize,i,0);
 }
 ed_cset(edFont,cfont);
 }
 
 
 /*
  * sets size menu, if item
  * is 0, sets item to 3 (12pt)
  */
 dosize (item)
 short  item;
 {
 static short  lastitem = 0;
 
 if (item equals 0)
   item = 3;
 CheckItem (menuSize,lastitem,False);
 CheckItem (menuSize,item,True);
 lastitem = item;
 ed_cset(edSize,item);
 }
 
 dostyle(item)
 short  item;
 {
 static short  thestyle = 0;
 short  mitems;
 short  i;
 short  style;
 short  styleflag;
 short  offflag;
 
 if (item equals 0)
 item = 1;
 style = item - 1; /* move item to style range */
 if (style) /* if not plain */
 {
 styleflag = 1;
 styleflag = styleflag << (style - 1);
 CheckItem (menuStyl,1,False); /* unmark plain */
 if (thestyle & styleflag) /* if style is marked */
 { /* un mark it */
 CheckItem (menuStyl,item,False);
 thestyle = thestyle & ~styleflag;
 }
 else
 {
 offflag = 0;
 switch (item)
 {
 case iCon :
 CheckItem(menuStyl,iExt,False);
 offflag = 64;
 break;
 case iExt :
 CheckItem(menuStyl,iCon,False);
 offflag = 32;
 break;
 case iSuper :
 CheckItem(menuStyl,iSub,False);
 offflag = 512;
 break;
 case iSub :
 CheckItem(menuStyl,iSuper,False);
 offflag = 256;
 break;
 } 
 CheckItem (menuStyl,item,True);
 thestyle &= ~offflag;
 thestyle ^= styleflag;
 }
 }
 else
 {
 thestyle = 0;
 mitems = CountMItems(menuStyl);
 for (i = 2; i <= mitems; i++)
 CheckItem (menuStyl,i,False);
 CheckItem (menuStyl,1,True);
 }
 ed_cset(edStyle,thestyle);
 }
  

/* dofile
 * handles file menu
 */
dofile(item)
 short  item;
{
 char   *title1; /* first title for window */
 Rect   boundsRect;
 
 switch (item)
 {
 case iNew :/* open the window */
 title1 = "ABC Window";
 SetRect(&boundsRect,50,50,400,200);
 theWindow = NewWindow(&windowRec, &boundsRect,
 CtoPstr( title1),True,documentProc,
 (WindowPtr) -1, True, 0);
 DrawGrowIcon(theWindow);
 PtoCstr(title1);
 DisableItem(menuFile,1);
 EnableItem(menuFile,2);
 ed_new(theWindow);
 break;
 
 case iClose :   /* close the window */
 CloseWindow(theWindow);
 theWindow = Nil;
 DisableItem(menuFile,2);
 EnableItem(menuFile,1);
 break;
 
 case iQuit :    /* Quit */
 ExitToShell();
 break; 
 }
}


/* printw()
 *
 * 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(cs)
 char   *cs;/* the control string */
{
#define Bufsz  14/* size of buffer to hold */
 /* converted numbers */  

 static RectboundsRect; /* variables for */
 static RectwindowRect; /* defining printw */
 static WindowRecord wrc; /* window, pw is */
 static WindowPtrpw = 0;  /* initialized to 0 */
 static short    linesz;  /* size of line */
 
 WindowPtroldport; /* save grafport here */
 FontInfo info;  
 short  nl;
 Point  pt;
 RgnHandleupdrgn;/* 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 */
 char   c;/* char parameter */
 char   *s; /* string pointer parameter */
 long   tcs;
 char   *tps;
 
/* Window rectancgle coordinates */

#define wl0
#define wr512
#define wt250
#define wb342
 
 
 GetPort(&oldport);/* save current graph port */
 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);
 GetFontInfo(&info); /* compute line height */
 linesz = info.ascent + info.descent;
 nl = linesz;    /* move down one line as */
 } /*  writing will be above */
 else   /*  boundary.  No need to  */
 nl = 0;/*  move line if already open */
 SetPort(pw);    /* Set graf port to this window */
 Move(0,nl);/* Move (relative) */
 
 ts = &cs;/* get address of control string ptr */
 ps = (char *)ts;/* convert to pointer to params */
 ps += sizeof(long); /* skip over control string ptr */
 tcs = (long)cs;
 tps = ps;
 while (*cs)/* loop until end of control string */
 {
 switch (*cs)    /* check each character */
 {
 case '%' : /* percent sign: check conversion */
 cs++;  /* point to next char */
 convchar = False; /* init for conv loop */
 islong = False;
 do {   /* loop til reach conversion char */
 switch (*cs)
 {
 case 'l' : /* indicates a long */
 islong = True;
 cs++;
 break;
 case 'u' : /* unsigned decimal */
 case 'd' : /* signed decimal */
 if (islong)   /* extract numb */
 {
 num = *(ulong*)ps;
 nsz = sizeof(long);
 }
 else
 {
 num = *(ushort*)ps;
 nsz = sizeof(short);
 }
 ps += nsz; /* point to next */
 ntoa(num,nsz,'u' - *cs,numAsStr); /* convert & write number */
 DrawString(CtoPstr(numAsStr));
 convchar = True;
 break;
 case 's' :
 num = *(ulong*)ps;
 DrawString(CtoPstr(num));
 PtoCstr(num);
 ps += sizeof(char*);
 convchar = True;
 break; 
 case 'c' :
 c = *(ushort*)ps;
 DrawChar(c);
 nsz = sizeof(short);
 convchar = True;
 ps += nsz;
 break;
 default: /* all other char */
 DrawChar(*cs); /* write char */
 convchar = True;
 } 
 } while (not convchar);
 break;
 case '\n' :/* newline ('\n') control string */
 GetPen(&pt);  /* find current pen position */
 if (pt.v+linesz > wb-wt)
 /* if it goes off window, */
 { /* 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 beg of next line */
 break;
 default :/* any other character just gets */
 DrawChar(*cs);  /*  written on the window */
 }
 cs++;  /* move pointer to next char */
 } /*  in control string and continue */
 
 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.  This */
 n /= 10; /*  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 */



/*
 *
 *  ed.c source
 * 
 */
#include"abc.h"
#include"ed.h"

extern  charsizes[];

edrec edbuf;

/*
 * Initialize some parts of the
 * edbuf structure.  This coulb
 * easily be combined with ed_new()
 */
ed_init()
{
 edbuf.cesc = 0;
 edbuf.cndx = 0;
 edbuf.supsub = 0;
 edbuf.chars[0] = 0;
 edbuf.linenum = 0;
}

/*
 * save grafport, moves to
 * top of port, initializes
 * font, style, and size.
 * Initialize edbuf values so
 * the calls to dofont will
 * find different values than
 * are being set.
 */
ed_new(aport)
 GrafPtraport;
{
 GrafPtrgp;
 
 edbuf.edport = aport;
 GetPort(&gp);
 SetPort(aport);
 MoveTo(0,0);
 edbuf.face[edFont] = -1;
 edbuf.face[edStyle] = -1;
 edbuf.face[edSize] = -1;
 dofont(0);
 dostyle(0);
 dosize(0);
 SetPort(gp);
}


/*
 * Allows setting or getting
 * a value (size,font,style).
 * Is not used.
 */
ed_set(what,value)
 short  what;
 short  value;
{
 if (value >= 0)
 edbuf.face[what] = value;
 return(edbuf.face[what]);
}

/*
 * Called by any routine wishing
 * to change the size, style or font.
 * The change is indicated in the
 * cesc element of the edbuf structure, 
 * and the value stored in the cface 
 * element.  The change is not applied
 * until a new character is written.
 */
ed_cset(what,value)
 short  what;
 short  value;
{
 char wbit = 1;
 
 wbit <<= what;
 if (edbuf.face[what] equals value)
 edbuf.cesc &= ~wbit;
 else
 {
 edbuf.cesc |= wbit;
 edbuf.cface[what] = value;
 }
}


/*
 * Writes the character c to the
 * window.  Before writing any 
 * character, it checks to see if 
 * size/font/style have changed and
 * effects the necessary changes.
 *
 * Since sub and super scripts and 
 * small caps styles are not supported
 * by quick draw, they are handled
 * here.
 *
 * Small Caps is implemented by using
 * the font size one smaller on the 
 * menu for the lower case letters.
 *
 * Sub and superscripts are generated
 * by shifting the position up or down
 * one third of a line of the the current
 * size.
 */
ed_key(c)
 char c;
{
 short  *sp;
 FontInfo info;
 static short  linesz;
 GrafPtrgp;
 Point  pt;
 short  lineinc;
 short  linedec;
 
 GetPort(&gp);
 SetPort(edbuf.edport);
 lineinc = linedec = 0;
 if (edbuf.cesc)
 {
 if (edbuf.face[edStyle] & Supbit + Subbit)
 linedec = -edbuf.supsub;
 edbuf.chars[edbuf.cndx++] = edbuf.cesc;
 sp = (short *)&edbuf.chars[edbuf.cndx];
 if (edbuf.cesc & 1) /* Font */
 {
 *sp = edbuf.cface[edFont];
 edbuf.face[edFont] = *sp;
 TextFont(*sp);
 sp++;
 edbuf.cndx +=2;
 }
 if (edbuf.cesc & 2) /* Size */
 {
 *sp = edbuf.cface[edSize];
 edbuf.face[edSize] = *sp;
 TextSize(sizes[*sp]);
 sp++;
 edbuf.cndx +=2;
 }
 if (edbuf.cesc & 4) /* Style */
 {
 *sp = edbuf.cface[edStyle];
 edbuf.face[edStyle] = *sp;
 TextFace((Style)*sp & 0x7F);
 sp++;
 edbuf.cndx += 2;
 }
 edbuf.chars[edbuf.cndx++] = edbuf.cesc;
 edbuf.cesc = 0;
 GetFontInfo(&info);
 linesz = info.ascent + info.descent;
 if (edbuf.face[edStyle] & Subbit)
 edbuf.supsub = linesz / 3;
 else if (edbuf.face[edStyle] & Supbit)
   edbuf.supsub = -linesz/3;
 else
 edbuf.supsub = 0;
 lineinc = edbuf.supsub;
 } 
 /*edbuf.chars[edbuf.cndx++] = c;*/
  if (c equals '\r')
   {
   GetPen(&pt);
   Move(-pt.h,linesz + lineinc + linedec);
   edbuf.linenum++;
   }
  else
   {
   GetPen(&pt);
   Move (0,linedec + lineinc);
   if (edbuf.face[edStyle] & Capbit and islower(c))
   {
   TextSize(sizes[edbuf.face[edSize] - 1]);
   DrawChar(toupper(c));
   TextSize(sizes[edbuf.face[edSize]]);
   }
   else
   DrawChar(c);
   }
 SetPort(gp);
}
 
inttoupper(c)
 char c;
{
 return( (c>='a')&&(c<='z') ? (c-32) : c );
}
 
intislower(c)
 char c;
{
 return( (c >= 'a') and (c <= 'z') ? True : False);
}
 
 
/* 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
#define uchar    unsigned char

/* General purpose external routines 
 * String conversion routines 
 * return a pointer to a char 
 */
extern  char*CtoPstr();
extern  char*PtoCstr(); 

/*
 * ed.h
 * definitions for edit functions
 */
 
#include"quickdraw.h"
 
#define edFont 0
#define edSize 1
#define edStyle  2

#define Capbit 128
#define Supbit 256
#define Subbit 512

struct edstruct
 {
 GrafPtredport;
 Rect   edrect;
 short  face[3];
 short  cface[3];
 short  supsub;
 short  linenum;
 char   cesc;
 char   chars[1000];
 short  cndx;
 };
 
typedef struct edstruct edrec;
typedef edrec *edpointer;
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

A Better Finder Rename 10.00b1 - File, p...
A Better Finder Rename is the most complete renaming solution available on the market today. That's why, since 1996, tens of thousands of hobbyists, professionals and businesses depend on A Better... Read more
CrossOver 14.1.6 - Run Windows apps on y...
CrossOver can get your Windows productivity applications and PC games up and running on your Mac quickly and easily. CrossOver runs the Windows software that you need on Mac at home, in the office,... Read more
Printopia 2.1.14 - Share Mac printers wi...
Run Printopia on your Mac to share its printers to any capable iPhone, iPad or iPod Touch. Printopia will also add virtual printers, allowing you to save print-outs to your Mac and send to apps.... Read more
Google Drive 1.24 - File backup and shar...
Google Drive is a place where you can create, share, collaborate, and keep all of your stuff. Whether you're working with a friend on a joint research project, planning a wedding with your fiancé, or... Read more
Chromium 45.0.2454.85 - Fast and stable...
Chromium is an open-source browser project that aims to build a safer, faster, and more stable way for all Internet users to experience the web. Version 45.0.2454.85: Note: Does not contain the "... Read more
OmniFocus 2.2.5 - GTD task manager with...
OmniFocus helps you manage your tasks the way that you want, freeing you to focus your attention on the things that matter to you most. Capturing tasks and ideas is always a keyboard shortcut away in... Read more
iFFmpeg 5.7.1 - Convert multimedia files...
iFFmpeg is a graphical front-end for FFmpeg, a command-line tool used to convert multimedia files between formats. The command line instructions can be very hard to master/understand, so iFFmpeg does... Read more
VOX 2.6 - Music player that supports man...
VOX is a beautiful music player that supports many filetypes. The beauty is in its simplicity, yet behind the minimal exterior lies a powerful music player with a ton of features and support for all... Read more
Box Sync 4.0.6567 - Online synchronizati...
Box Sync gives you a hard-drive in the Cloud for online storage. Note: You must first sign up to use Box. What if the files you need are on your laptop -- but you're on the road with your iPhone? No... Read more
Carbon Copy Cloner 4.1.4 - Easy-to-use b...
Carbon Copy Cloner backups are better than ordinary backups. Suppose the unthinkable happens while you're under deadline to finish a project: your Mac is unresponsive and all you hear is an ominous,... Read more

You Can Play Madfinger Games' Unkil...
Madfinger Games - probably best known for the Dead Trigger series - has officially launched their newest zombie shooter (that isn't called Dead Trigger), named Unkilled. [Read more] | Read more »
KORG iELECTRIBE for iPhone (Music)
KORG iELECTRIBE for iPhone 1.0.1 Device: iOS iPhone Category: Music Price: $9.99, Version: 1.0.1 (iTunes) Description: ** 50% OFF Special Launch Sale - For a Limited Time **The ELECTRIBE reborn in an even smaller form A full-fledged... | Read more »
I am Bread (Games)
I am Bread 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: ‘I am Bread’ is the latest quirky adventure from the creators of 'Surgeon Simulator', Bossa Studios. This isn't the best thing... | Read more »
Rock(s) Rider - HD Edition (Games)
Rock(s) Rider - HD Edition 1.0.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.0 (iTunes) Description: *** PLEASE NOTE: Compatible with iPhone 4s, iPad 2, iPad mini, iPod touch (5th generation) or newer *** Do you... | Read more »
Rebuild 3: Gangs of Deadsville (Games)
Rebuild 3: Gangs of Deadsville 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: It's been a few years since the zombpocalypse turned the world's cities into graveyards and sent the few... | Read more »
Power Ping Pong (Games)
Power Ping Pong 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: Do you wield your bat with zen-like focus or do your balls of fury give you a killer spin? Table tennis goes mobile with a... | Read more »
Z.O.N.A Project X (Games)
Z.O.N.A Project X 1.00 Device: iOS Universal Category: Games Price: $1.99, Version: 1.00 (iTunes) Description: Z.O.N.A Project X - shooter in the post-apocalyptic world. | Read more »
Trick Shot (Games)
Trick Shot 1.0.6 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0.6 (iTunes) Description: A game where all you have to do is throw a ball into a box, simple? Trick Shot is a minimalist physics puzzler with 90 levels... | Read more »
VoxelCity (Games)
VoxelCity 1.0.2 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0.2 (iTunes) Description: Looking for a new city builder? Tired of social media anti-games with no strategy? Look no further! NO IAP EVER! VoxelCity is a... | Read more »
Goat Simulator MMO Simulator (Games)
Goat Simulator MMO Simulator 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: ** IMPORTANT - SUPPORTED DEVICESiPhone 4S, iPad 2, iPod Touch 5 or better.** Coffee Stain Studios brings next-gen... | Read more »

Price Scanner via MacPrices.net

Near-Office Input Functionality Virtually Any...
Today Logitech introduced the Logitech K380 Multi-Device Bluetooth Keyboard and the Logitech M535 Bluetooth Mouse, giving users the freedom to work on any device, most anywhere. According to... Read more
College Student Deals: Additional $100 off Ma...
Take an additional $100 off all MacBooks and iMacs at Best Buy Online with their College Students Deals Savings, valid through September 4, 2015. Anyone with a valid .EDU email address can take... Read more
Will You Buy An iPad Pro? – The ‘Book Mystiqu...
It looks like we may not have to wait much longer to see what finally materializes as a new, larger-panel iPad (Pro/Plus?) Usually reliable Apple product prognosticator KGI Securities analyst Ming-... Read more
eFileCabinet Announces SMB Document Managemen...
Electronic document management (EDM) eFileCabinet, Inc., a hosted solutions provider for small to medium businesses, has announced that its SecureDrawer and eFileCabinet Online services will be... Read more
WaterField Designs Unveils American-Made, All...
San Francisco’s WaterField Designs today unveiled their all-leather Cozmo 2.0 — an elegant attach laptop bag with carefully-designed features to suit any business environment. The Cozmo 2.0 is... Read more
Apple’s 2015 Back to School promotion: Free B...
Purchase a new Mac or iPad at The Apple Store for Education and take up to $300 off MSRP. All teachers, students, and staff of any educational institution qualify for the discount. Shipping is free,... Read more
128GB MacBook Airs on sale for $100 off MSRP,...
B&H Photo has 11″ & 13″ MacBook Airs with 128GB SSDs on sale for $100 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 11″ 1.6GHz/128GB MacBook Air: $799.99, $100 off MSRP... Read more
13-inch 2.5GHz MacBook Pro (refurbished) avai...
The Apple Store has Apple Certified Refurbished 13″ 2.5GHz MacBook Pros available for $829, or $270 off the cost of new models. Apple’s one-year warranty is standard, and shipping is free: - 13″ 2.... Read more
27-inch 3.2GHz iMac on sale for $1679, save $...
B&H Photo has the 27″ 3.2GHz iMac on sale for $1679.99 including free shipping plus NY sales tax only. Their price is $120 off MSRP. Read more
Apple and Cisco Partner to Deliver Fast-Lane...
Apple and Cisco have announced a partnership to create a “fast lane” for iOS business users by optimizing Cisco networks for iOS devices and apps. The alliance integrates iPhone with Cisco enterprise... Read more

Jobs Board

*Apple* Desktop Analyst - KDS Staffing (Unit...
…field and consistent professional recruiting achievement. Job Description: Title: Apple Desktop AnalystPosition Type: Full-time PermanentLocation: White Plains, NYHot Read more
Simply Mac *Apple* Specialist- Repair Techn...
Simply Mac is the greatest premier retailer of Apple products expertise in North America. We're looking for dedicated individuals to provide personalized service and Read more
Simply Mac *Apple* Specialist- Service Repa...
Simply Mac is the greatest premier retailer of Apple products expertise in North America. We're looking for dedicated individuals to provide personalized service and Read more
*Apple* Desktop Analyst - KDS Staffing (Unit...
…field and consistent professional recruiting achievement. Job Description: Title: Apple Desktop AnalystPosition Type: Full-time PermanentLocation: White Plains, NYHot Read more
Simply Mac- *Apple* Specialist- Store Manag...
Simply Mac is the largest premier retailer for Apple products and solutions. We're looking for dedicated individuals with a passion to simplify and enhance the Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.