home *** CD-ROM | disk | FTP | other *** search
/ World of Shareware - Software Farm 2 / wosw_2.zip / wosw_2 / CPROG / CMAGIC.ZIP / TUTOR.2 < prev    next >
Text File  |  1992-09-02  |  53KB  |  1,090 lines

  1.  
  2.                         CONTINUED FROM FILE: TUTOR.DOC
  3.  
  4.          Program  #20  is  going to be a big, but very special program
  5.          because it will be something you'll  use  everyday.   Run  it
  6.          and  see  what  it  does,  then  study  the  source  code  to
  7.          understand it.
  8.  
  9.               /* program #20 */
  10.               #include <magic.h>
  11.               #include <string.h>
  12.               #include <stdlib.h>
  13.               #include <stdio.h>
  14.               #include <conio.h>
  15.               #include <ctype.h>
  16.               void extkey(void);
  17.               void asciichart(void);
  18.               void main(){     /*** 1 ***/
  19.                  magic_setup();
  20.                  centerjustify = 1;
  21.                  xclear();
  22.                  mc = 1;
  23.                  do {
  24.                     boxback = RED;
  25.                     pile("Programmer's Tools");
  26.                     pile("Copyright 1992, Freeware by Another Company");
  27.                     pop(18,2);
  28.                     boxback = GREEN;
  29.                     strcpy(sent[1],"ASCII Chart");   /*** 2 ***/
  30.                     strcpy(sent[2],"Extended Keys");
  31.                     strcpy(sent[3],"Quit");
  32.                     menu(-1,-1);
  33.                     if (u == 13) switch (mc) {
  34.                        case 1 : asciichart(); break;  /*** 3 ***/
  35.                        case 2 : extkey();
  36.                     }
  37.                     restore();   /*** 4 ***/
  38.                  }
  39.                  while (!((u == 13) && (mc == 3)));
  40.                  cleanup();
  41.               }
  42.  
  43.               void extkey(void){
  44.                  char tempstr[3];
  45.                  xclear();
  46.                  pile("Press any key to see it's extended code");
  47.                  pile("Press [Esc] when done.");
  48.                  pop(18,3);
  49.                  strcpy(sent[1]," ");
  50.                  strcpy(sent[2],"");
  51.                  do {
  52.                     getanykey(-1,-1);
  53.                     if (keydetect == 2){        /*** 5 ***/
  54.                        strcpy(sent[1],"#0 + ");
  55.                     }
  56.                     sprintf(tempstr,"%c",u);
  57.                     if ((u == 13) || (u == 8) || (u == 10) || (u == 7))
  58.                        strcat(sent[1]," ");   /*** 6 ***/
  59.                     else strcat(sent[1],tempstr);
  60.                     itoa(u,tempstr,10);
  61.                     strcat(sent[1],"(#");
  62.                     strcat(sent[1],tempstr);
  63.                     strcat(sent[1],")");
  64.                  }
  65.                  while (u != 27);   /*** 7 ***/
  66.                  xclear();
  67.               } // end of function extkey()
  68.  
  69.               void asciichart(void){
  70.                  char x = 1,y = 1;  /*** 8 ***/
  71.                  int temp;
  72.                  char tempstr[3];
  73.                  textcolor(YELLOW); textbackground(BLUE);
  74.                  clrscr();
  75.                  for (temp = 0; temp < 256; temp++) {   /*** 9 ***/
  76.                     gotoxy(x,y);
  77.                     cprintf(" ");
  78.                     if (temp < 10) cprintf(" ");  /*** 10 ***/
  79.                     if (temp < 100) cprintf (" ");
  80.                     if ((temp != 7) && (temp != 8) && (temp != 10)
  81.                       &&(temp != 13) && (temp != 27))   /*** 11 ***/
  82.                      cprintf("%d=%c ",temp,temp);
  83.                     else cprintf("%d=",temp);
  84.                     y++;
  85.                     if (y > 25){
  86.                        y = 1;
  87.                        x += 7;   /*** 12 ***/
  88.                     } //end of if y > 25
  89.                  } // end of for loop;
  90.                  waitforuser(); /*** 13 ***/
  91.                  xclear();
  92.               }
  93.  
  94.          Note   #1:  When  most  programmers  start  looking  over  an
  95.          unfamiliar program, they head right for the main()  function,
  96.          and follow it line by line. When one of these lines is a call
  97.          to  another  function,  they  go to that function, observe it
  98.          line by line, then return to the main() function.
  99.  
  100.          Note #2: Unlike, menu(), getanykey() and  dialog(),  after  a
  101.          call  to  pop(),  the  sent[]s are not cleared, so if we used
  102.          pile() here, sent[4] and sent[5] would get these strings.
  103.  
  104.          Note #3: These are the functions below.  If the user  selects
  105.          menu  item  3,  the  program  falls through, otherwise one of
  106.          these is then executed.
  107.  
  108.          Note #4:  This wipes out the pop(), and frees memory that  it
  109.          was holding.
  110.  
  111.          Note  #5:  These  two  lines  are  interesting.  Getanykey(),
  112.          getyn() and  many  other  functions  use  an  internal  Magic
  113.          function  called  poll(), (more about it later) which returns
  114.          u, the character value of the key pressed, plus  keydetected,
  115.          a  little  more  information  about the keypress. If the user
  116.          operated the mouse,  keypress  =  0.   If  the  user  presses
  117.          something  on  the  keyboard the value of keypress is greater
  118.          than 0.  Specifically, if it  is  an  alphanumeric  key,  the
  119.          value  will be 1, and if it is an extended key, such as [F2],
  120.          [Insert], [Home], etc,  keydetected  will  be  2.   For  your
  121.          convenience,  extkey()  returns the value of the key pressed,
  122.          prefixed by "0 +" for extended keys.
  123.  
  124.          Note  #6:  These  keys  are excluded because their values are
  125.          unprintable.  Some "characters," when written to the  screen,
  126.          do  funny things. For instance ASCII #7 beeps, and #13 causes
  127.          a carriage return, which would mess up the chart.
  128.  
  129.          Note #7: This function falls through when  the  user  presses
  130.          [Esc], which is ASCII #27.
  131.  
  132.          Note #8: By declaring variables this way, you can force their
  133.          initial value.  Forgetting to make sure you have a handle  on
  134.          the initial value of variables is a frequent and hard-to-find
  135.          programmer's mistake.
  136.  
  137.              But what's going on here? Are we using char - character -
  138.          globals to hold numbers? The answer is YES.  You see, C makes
  139.          no  distinction  between  a  character and a byte.  Since any
  140.          alphanumeric character can be represented within 0 - 127,  we
  141.          can use a single byte, which can have a value of -128 to +127
  142.          to  hold a character.  So a byte-size variable has been named
  143.          "char" (somewhere in history) because it  is  often  used  to
  144.          hold  character  values.   So,  the variable char, can hold a
  145.          small integer value, or hold a character, represented by it's
  146.          integer value as listed in the ASCII chart.  In other  words,
  147.          if your char = 65, it also can equal "A", and 66 = "B" and so
  148.          on.
  149.               Just when you thought it all made sense,  remember  that
  150.          there  are 256 values on the entire ASCII chart.  So we often
  151.          don't use "char" variables to hold characters after all,  but
  152.          rather  "unsigned  char"  which  is  still a byte, but in the
  153.          range of 0 to 255 (no negative  numbers)  or  even  "unsigned
  154.          int",  in  the  range  of 0 to +65,535. Ints require more RAM
  155.          space, since it takes two bytes to hold a number as large  as
  156.          65,535.   Well,  don't worry about all this now. It will make
  157.          sense later on, as you get more practice.
  158.  
  159.          Note  #9:  The  "for  loop."   If you haven't seen a for loop
  160.          before, get used to it, because it is a very  frequent  thing
  161.          in  C  programming.   The  for  loop  is  very  flexible  and
  162.          powerful, but it is usually used this way:
  163.  
  164.             It has 3 parts in the parentheses using the same variable.
  165.          The first part initializes the variable to the first value at
  166.          which it will  be  used.   The  middle  statement  tests  the
  167.          variable every time the loop executes.  As long as the middle
  168.          statement  evaluates  truthfully,  the  loop  continues.   So
  169.          usually the > or < test are used.  Remember, if  you  want  a
  170.          specific  number  of  iterations,  it  must  test for <= your
  171.          number, or < your number + 1. The last part changes the value
  172.          each time the loop runs.  Usually the variable is incremented
  173.          by one, as in this example. Whatever follows the for loop  is
  174.          what  occurs on each execution of the loop.  Many times there
  175.          is a whole block surrounded by { and }.  It is  usually  good
  176.          programming  practice  not to change the loop variable within
  177.          the { and }, because you can easily become  confused  between
  178.          your  changes  here  and the loop's own incrementation of the
  179.          variable.
  180.  
  181.              In  this  particular  loop, the variable called "temp" is
  182.          incremented until it is equal to 255.  Since we  are  testing
  183.          up  to  256,  "temp"  must  be  an  "int", not a "char" or an
  184.          "unsigned char," because these  variables  are  incapable  of
  185.          holding an number as big as 256.
  186.  
  187.              There  are  nine  lines  within  the  for  loop's  block.
  188.          Although it may be hard to understand  at  first,  they  take
  189.          each  instance  of  "temp," - all the characters of the ASCII
  190.          chart - and lay them out neatly at x and y coordinates on the
  191.          screen.
  192.  
  193.          Note #10: We use "cprintf()" instead  of  "printf()"  because
  194.          the  former  will  work  with  the  chosen  color variable, a
  195.          capability printf() doesn't have. If you can't figure why  we
  196.          are  printing  spaces  when  "temp"  is  less  than  100, try
  197.          commenting out these lines and see how your chart looks.
  198.  
  199.          Note #11: These few characters are unprintable. See note #6.
  200.  
  201.          Note #12: We increment "y" until we hit  the  bottom  of  the
  202.          screen.  then  we  go to the top by resetting y to 1 and move
  203.          over to the next row by incrementing  x  by  7.   Notice  the
  204.          function gotoxy() a few  lines  above.   It  moves  the  next
  205.          location  at  which  text  will be printed to the coordinates
  206.          passed to it.
  207.  
  208.          Note #13: Waitforuser() is a  simple  Magic  function  which,
  209.          like it sounds, simply stalls until the user presses a key or
  210.          clicks a mouse button.
  211.  
  212.              This is an excellent  program  to  study  in  detail.   A
  213.          really   good   way   to  understand  it  is  to  modify  it.
  214.          Experiment.  Make changes,  and  see  if  when  you  run  the
  215.          program, your changes act as you had expected. See if you can
  216.          improve  on this program or add new features. Perhaps you can
  217.          add a metric to inch converter.  Hint: Extend the menu,  make
  218.          a  new  function called metric() or something similar.  (Make
  219.          sure to declare the new function at the top of the program.)
  220.              If  you  can understand all of this, you are well on your
  221.          way to being a GOOD programmer.
  222.  
  223.          Program   #21   is   derived  from  program  #20.   It  is  a
  224.          demonstration of writing to a disk file. The object  of  this
  225.          program  is  to  put  a column of ASCII equivalents in a text
  226.          file, so you can use it with your word processor,  etc.   Run
  227.          program  #21,  then go look at the file called ASCII.TXT with
  228.          the IDE or your favorite word processor.
  229.  
  230.               /* program #21 */
  231.               #include <magic.h>
  232.               #include <stdio.h>
  233.               #include <string.h>
  234.               void main(){
  235.                  magic_setup();
  236.                  int temp;
  237.                  nameoutfile("Ascii.txt");
  238.                  for (temp = 0; temp <= 255; temp++){
  239.                     if ((temp != 7) && (temp != 8) && (temp != 10)
  240.                       && (temp != 13) && (temp != 26) && (temp != 27))
  241.                     sprintf(sent[1],"%d = %c ",temp,temp);
  242.                     else sprintf(sent[1],"%d = ",temp);
  243.                     filewriteln(sent[1]);
  244.                 }
  245.               }
  246.  
  247.               There are two  special  items  in  Magic,  "infile"  and
  248.          "outfile."  Infile  is used to get text or binary information
  249.          in from the disk and use it within your program.  Outfile  is
  250.          used  to  put information out to the disk. Essentially, these
  251.          are pathways to disk files. You must  give  them  names  that
  252.          will  be  used  in  the  disk  directory.  As usual with disk
  253.          files,  these  names  must  be  DOS-legal,  with  up   to   8
  254.          characters,  optionally  followed  by  a  period  and up to a
  255.          three-character extension. Drive designator and sub-directory
  256.          designations can precede file names.
  257.  
  258.              The neat thing about the way Magic uses  these  files  is
  259.          that  you  don't  have to know all that confusing stuff about
  260.          file types, and file handling as presented  by  your  Borland
  261.          manuals.   Although,  later  on, you might like to study that
  262.          stuff, because pretty much anything you can do with a text or
  263.          a binary file, can be done with the two special Magic  files.
  264.  
  265.              Anyway,  we  would  use  outfile to convey information to
  266.          the  disk. The first operation in program #21 is to associate
  267.          a disk filename with outfile, using "nameoutfile()."
  268.  
  269.              If  you forget to attach a name to the magic output file,
  270.          it will automatically be named "OUTPUT."  If  you  forget  to
  271.          rename then input file it will be "INPUT" on disk.
  272.  
  273.             Then a for loop builds a string in the  variable  sent[1],
  274.          containing each ASCII number and the character represented by
  275.          that  number.  The  last  line  in this loop, "filewriteln()"
  276.          writes sent[1] to the disk.
  277.  
  278.             There  is  another  function  called  "filewrite()"  which
  279.          writes  strings  to  disk,  but  does  not  put each one on a
  280.          separate line.
  281.  
  282.             If you have named a file that does not yet exist on  disk,
  283.          it  will  be  created  automatically  with  the first call to
  284.          filewriteln() or filewrite(). If the file already exists, the
  285.          string passed to filewriteln or filewrite() will be  appended
  286.          to the end of the file.
  287.  
  288.              The compliment of filewriteln() is filereadln().  Program
  289.          #22  shows  it  in  operation,  using  the previously created
  290.          file, "ASCII.TXT".
  291.  
  292.               /* program #22 */
  293.               #include <magic.h>
  294.               #include <string.h>
  295.               #include <stdio.h>
  296.               #include <conio.h>
  297.               void main(){
  298.                  magic_setup();
  299.                  clrscr();
  300.                  nameinfile("ASCII.TXT");
  301.                  problem = 0;
  302.                  while (!problem) {
  303.                     filereadln();
  304.                     strcpy(sent[1],answer);
  305.                     printf("%s\n",sent[1]);
  306.                  }
  307.                  waitforuser();
  308.                  cleanup();
  309.               }
  310.  
  311.          Not very elegant, since  the  stuff  scrolls  right  off  the
  312.          screen,  but  you  get  the  general  idea. If you don't pass
  313.          "ASCII.TXT" to nameinfile(), the program will be looking  for
  314.          the standard infile called "INPUT."
  315.  
  316.              There is a char variable in Magic called "problem"  which
  317.          is  used in many of it's functions.  If a function works like
  318.          it should, problem is 0, but if the function  cannot  perform
  319.          properly,  it  changes  problem  to  a  number larger than 0,
  320.          typically 1.  You can use this for many checks  and  balances
  321.          in  your  program.   In  this  case, problem will become 1 if
  322.          filereadln() tries to read past the end of the file. This is,
  323.          of course, where the program should stop, so the  while  loop
  324.          is  constantly  checking  the condition of "problem".  You'll
  325.          notice  that  this  "while"  loop  is  an  inversion  of  the
  326.          "do-while"  loop  you are used to.  Sometimes it is easier to
  327.          write.  The difference is  that  this  variation  checks  the
  328.          condition  before the loop executes, the do-while loop always
  329.          runs at least once, then checks the condition at the  end  of
  330.          the  loop.  When using this type of while loop, you must know
  331.          or set the  condition  in  advance.   That's  why  the  line:
  332.          "problem = 0."
  333.  
  334.              And, printf() has a new feature.  Actually, it is one  of
  335.          the first things you see in a typical C tutorial, but we have
  336.          held  back for a while, because Magic often replaces printf()
  337.          with more elegant functions.  Printf() is nice because it can
  338.          handle a variety of inputs such as floats, ints, and strings.
  339.          But  it  usually requires a weird construction called "format
  340.          specifiers," which are notices of what kind of  variables  to
  341.          print,  followed  by  the  actual  variables.   You  can also
  342.          include some information about how to write the text  to  the
  343.          screen.   "\n"  is  one  of  the  most  common.  It appends a
  344.          carriage return/linefeed to the end of the  line.   See  your
  345.          Borland  Library  Reference  manual for a complete rundown of
  346.          the fascinating powers of printf().
  347.  
  348.          Program 23 explores graphics a bit. Compile it, run it, study it.
  349.  
  350.               /* program #23 */
  351.               #include <magic.h>
  352.               void main(){
  353.                  magic_setup();
  354.                  pile("This is text mode");
  355.                  getanykey(-1,-1);
  356.                  bestvideo();
  357.                  pile("This is a graphics mode");
  358.                  getanykey(-1,-1);
  359.                  cleanup();
  360.               }
  361.  
  362.              This simple program is like several that you have already
  363.          seen, except for the new function bestvideo().  This is truly
  364.          a magic function, since it sets up the computer to run in the
  365.          highest-resolution  graphics  mode it is capable of, and then
  366.          makes getanykey(), getyn(), dialog(), menu(), pop() and other
  367.          functions work in the graphics mode just as easily as if they
  368.          were running in text mode.
  369.  
  370.              Cleanup() at the end of this program returns the computer
  371.          to a text-based screen mode.
  372.  
  373.              Instead of bestvideo(), you could also  use  vgahivideo()
  374.          or  hercvideo(),  for  instance,  if  you  want  to force the
  375.          computer to  a  specific  mode.   Obviously,  you  can't  use
  376.          something  like  egavideo()  with a Hercules system, however.
  377.          You  can  always  uses  bestvideo().   These are the graphics
  378.          functions available, depending on your equipment:
  379.  
  380.          textvideo() - 80 x 25 color text
  381.          cgalovideo() - 320 x 200 4-color
  382.          cgahivideo() - 640 x 200 2-color
  383.          egalovideo() - 640 x 200 16-color
  384.          egahivideo() - 640 x 350 16-color
  385.          hercvideo() - 720 x 348 2-color
  386.          vgalovideo() - 320 x 200 256-color (will not work with older
  387.                                              versions of Turbo C)
  388.          vgahivideo() - 640 x 480 16-color
  389.          bestvideo()   -  something  from  the  above  chart,  highest
  390.                           resolution possible for your equipment
  391.  
  392.              You can switch from one video mode to another as often as
  393.          you like within a program. However, RAM becomes quite full if
  394.          you use  bestvideo()  or  several  different  graphics  modes
  395.          within one program.
  396.  
  397.              Those of you who have done some graphics programming will
  398.          find a surprise.  You don't have to include a *.BGI  file  on
  399.          disk with your finished program.  The graphics stuff is built
  400.          entirely  into  your  .EXE  file.  This  is true for graphics
  401.          fonts, too, which we'll cover in a few minutes.
  402.  
  403.              Pop(),  getyn(),  getanykey(),  dialog(),  and menu() all
  404.          work almost the same in any graphics mode as  in  text  mode.
  405.          The only difference, is that in text mode, you can have up to
  406.          10 layers of pop-ups, and each one can be restored, revealing
  407.          the  screen underneath.  In any graphics mode, only one layer
  408.          is saved to memory.
  409.  
  410.              (However, with the  purchase  of  source  code,  you  can
  411.          easily  wrap  up  the  graphics  stuff  into  object oriented
  412.          programming and then  create  as  many  instances  of  pop(),
  413.          menu(), etc as you require, within the limits of RAM.)
  414.  
  415.              Textvideo() is the way out of graphics.  For instance, if
  416.          you write a program that starts in graphics mode to display a
  417.          drawing, then you want to switch  back  to  text  for  faster
  418.          handling   of   strings,  you  simply  call  the  textvideo()
  419.          function, as in program #24 below:
  420.  
  421.               /* program #24 */
  422.               #include <magic.h>
  423.               #include <string.h>
  424.               void main(){
  425.                  magic_setup();
  426.                  strcpy(sent[1],"This is text mode");
  427.                  getanykey(-1,-1);
  428.                  cgahivideo();
  429.                  strcpy(sent[1],"This is a graphics mode");
  430.                  getanykey(-1,-1);
  431.                  textvideo();
  432.                  strcpy(sent[1],"This is text again");
  433.                  getanykey(-1,-1);
  434.                  cleanup();
  435.               }
  436.  
  437.  
  438.          Program  #24 switches to CGA graphics mode, then back to text
  439.          mode.   After  running  in   a   graphics   mode,   cleanup()
  440.          automatically  does  one  more  thing.   It  resets the video
  441.          system to text mode as the program ends.
  442.  
  443.          Program #25 shows some complexity in using bestvideo().
  444.  
  445.               /* program #25 */
  446.               #include <magic.h>
  447.               #include <string.h>
  448.               #include <graphics.h>
  449.               void main(){
  450.                  magic_setup();
  451.                  strcpy(sent[1],"This is text mode");
  452.                  getanykey(-1,-1);
  453.                  bestvideo();
  454.                  setcolor(YELLOW);
  455.                  circle(getmaxx() / 2,getmaxy() / 2, getmaxy() / 4);
  456.                  strcpy(sent[1],"This is a graphics mode");
  457.                  getanykey(-1,-1);
  458.                  textvideo();
  459.                  cleanup();
  460.               }
  461.  
  462.              This one switches to  a  graphics  mode  when  a  key  is
  463.          pressed.  If you have a VGA system, then you'll see a  yellow
  464.          circle   around   a   pop-up   box.   But,  then  change  the
  465.          "bestvideo()" line to "cgalovideo()" and you'll see that  the
  466.          pop-up  box  partially  covers  the  circle,  even though the
  467.          circle is supposedly the same  size.  It's  the  pop-up  that
  468.          changed it's size.
  469.  
  470.             Notice that you can change color by simply passing a color
  471.          to setcolor().  In the GRAPHICS.H file, the 16 colors used by
  472.          EGA  and  VGA (16-color mode) are defined the same as CONIO.H
  473.          (in newer  Borland  compilers)  uses  for  text  colors.   In
  474.          graphics  modes  (except  CGA, which is all weird, with three
  475.          possible palettes of 3 fixed colors  each  and  one  variable
  476.          background  color),  all elements of background or foreground
  477.          may be changed to any of the sixteen  colors.  The  function,
  478.          "circle()" is declared in the GRAPHICS.H file.
  479.  
  480.          Program  #26  shows a few of the many other things you can do
  481.          with the Borland graphics library (GRAPHICS.LIB).
  482.  
  483.               /* program #26 */
  484.               #include <magic.h>
  485.               #include <graphics.h>
  486.               void main(){
  487.                  magic_setup();
  488.                  bestvideo();
  489.                  setcolor(WHITE);
  490.                  circle(100,100,50);
  491.                  circle(100,100,40);
  492.                  setfillstyle(SOLID_FILL,WHITE);
  493.                  floodfill(51,100,WHITE);
  494.                  setcolor(LIGHTGREEN);
  495.                  setlinestyle(0,0,3);
  496.                  rectangle(70,70,130,130);
  497.                  setfillstyle(SOLID_FILL,LIGHTMAGENTA);
  498.                  bar(90,90,110,110);
  499.                  waitforuser();
  500.                  cleanup();
  501.               }
  502.  
  503.              Go ahead and mess with this  program  a  bit.   See  what
  504.          other  patterns  you  can  make.   To find out what tools are
  505.          available  to  you,  take a look at the GRAPHICS.H file.  Or,
  506.          even better, look through your Borland Library Reference book
  507.          for the various graphics functions available.
  508.  
  509.              Program #27 shows how to work with  text  in  a  graphics
  510.          mode.  Borland  C  supplies a default font, which is an 8 x 8
  511.          pixel  bitmapped  font.  Pop(), getanykey(), dialog(), menu()
  512.          and the other similar Magic functions always use this default
  513.          font.
  514.  
  515.               /* program #27 */
  516.               #include <magic.h>
  517.               #include <graphics.h>
  518.               void main(){
  519.                  magic_setup();
  520.                  bestvideo();
  521.                  setcolor(LIGHTMAGENTA);
  522.                  outtextxy(100,100,"This is the default font.");
  523.                  waitforuser();
  524.                  cleanup();
  525.               }
  526.  
  527.              In Program #27 we see that the way to display a string is
  528.          through  outtextxy(),  which  is similar to gotoxy() combined
  529.          with printf() in  text  mode.   Outtextxy()  requires  screen
  530.          coordinates,  then  a string.  Unlike printf(), which  allows
  531.          you  to  print numeric variables, strings, and what-have-you,
  532.          you must pass a string, and only one  string  at  a  time  to
  533.          outtextxy() after the coordinates.
  534.  
  535.              In older versions of Borland and Turbo C/C++, there  were
  536.          four  external  fonts  provided,  and in the newest versions,
  537.          there are 10. By external, I  mean  that  they  were  usually
  538.          supplied  on  disk  along  with  your  finished  program, not
  539.          actually linked into the .EXE program.   Of  course,  Borland
  540.          provides  a  way to link these into your program, and C Magic
  541.          takes it a step further and  does  it  automatically  with  a
  542.          single line of code as in the following example:
  543.  
  544.          Program #28 shows how to work with different fonts.
  545.  
  546.               /* program #28 */
  547.               #include <magic.h>
  548.               #include <graphics.h>
  549.               void main(){
  550.                  magic_setup();
  551.                  bestvideo();
  552.                  setcolor(YELLOW);
  553.                  triplex();
  554.                  outtextxy(100,100,"This is TRIPLEX font.");
  555.                  waitforuser();
  556.                  cleanup();
  557.               }
  558.  
  559.              We have simply called the Magic function, triplex(),  and
  560.          now   outtextxy()   will   use  the  Triplex  font  until  we
  561.          specifically  call  another  font  function.  For the older C
  562.          compilers, these font functions are available:
  563.  
  564.                triplex()   {1}
  565.                little()    {2}
  566.                sansserif() {3}
  567.                gothic()    {4}
  568.  
  569.              The newer compilers will also allow you to use these font
  570.          functions:
  571.  
  572.                script()    {5}
  573.                simple()    {6}
  574.                italic()    {7}
  575.                complex()   {8}
  576.                european()  {9}
  577.                bold()      {10}
  578.  
  579.              And, to return to the default Bitmap font:
  580.  
  581.                bitmap()
  582.  
  583.              By simply calling one of these  functions,  the  font  is
  584.          linked  into the .EXE program (thereby occupying space in RAM
  585.          when run) and outtextxy() will use the chosen font.  You  can
  586.          switch  from  one  font  to another as often as you like, but
  587.          everytime  you  choose  a  new  font,  the RAM and disk space
  588.          requirement will increase.  Only bitmap() does not  call  for
  589.          extra RAM.
  590.  
  591.              You don't want to automatically link all 10  fonts  every
  592.          time  you write a program, because the program would be about
  593.          207k in size, minimum!
  594.  
  595.          You can also use a font without linking it into the .EXE file
  596.          by  keeping it as an external .CHR file on disk and using the
  597.          Borland-provided  function  settextstyle().  You can also use
  598.          settexstyle() to change the  size  of  a  Magic-linked  font.
  599.          Settextstyle()  takes three variables.  The first is a number
  600.          representing  the  chosen  font  (see  chart  above  for  our
  601.          Magic-imposed  font  function  names, and their corresponding
  602.          font numbers).  The  second  number,  usually  0,  tells  the
  603.          compiler  whether  you want the font to lay across the screen
  604.          horizontally or vertically, and the last is the relative size
  605.          of the font, ranging from 1 to 10.  If  you  state  0  for  a
  606.          size,  then  the  font's  default  size will be used.  Here's
  607.          settextstyle() in action:
  608.  
  609.               /* program #29 */
  610.               #include <magic.h>
  611.               #include <graphics.h>
  612.               void main(){
  613.                  magic_setup();
  614.                  cgalovideo();
  615.                  setcolor(YELLOW);
  616.                  triplex();
  617.                  settextstyle(1,0,8);
  618.                  outtextxy(0,0,"TEST");
  619.                  waitforuser();
  620.                  cleanup();
  621.               }
  622.  
  623.              In program #29 we've done the  usual  stuff  to  enter  a
  624.          graphics mode (CGA - LO) then linked in the Triplex font with
  625.          a  call  to triplex(). Then comes a call to settextstyle() to
  626.          enlarge our Triplex font.  See your Borland  books  for  more
  627.          information   about   settextstyle(),   settextjustify()  and
  628.          setusercharsize().  Note: setusercharsize() is available with
  629.          the newer compilers.
  630.  
  631.          Program 30 shows off some basic  mouse  work,  and  the  main
  632.          principal  of  drawing to the screen.  This will work whether
  633.          or not you have a mouse.  Our mouse  support  includes  arrow
  634.          key  emulation.   In  addition  to  the arrow keys, [Insert],
  635.          [Page Up], [Delete] and [Page Down]  move  diagonally.   With
  636.          the [Num Lock] on, the number keys move the mouse up, down or
  637.          diagonally  large  amounts,  while  with  [Num Lock] off, the
  638.          movements are small.  Pressing [Enter] is like  clicking  the
  639.          left  mouse  button  and  [Esc]  is  like  clicking the right
  640.          button.
  641.  
  642.               /* program #30 */
  643.               #include <magic.h>
  644.               #include <graphics.h>
  645.               void main(){
  646.                  magic_setup();
  647.                  bestvideo();
  648.                  waste();
  649.                  moveto(getmaxx() / 2, getmaxy() / 2);
  650.                  while (!left){
  651.                     poll();
  652.                  lineto(px,py);
  653.                  }
  654.                  cleanup();
  655.               }
  656.  
  657.              In  program  we use the function moveto() to start out in
  658.          the middle of the screen. Getmaxx() and getmaxy() are  simple
  659.          functions   which   return   the  number  of  pixels  at  the
  660.          coordinates in the middle of the  screen.   We  start  there.
  661.          Then, with a while loop, we poll(), which is a Magic function
  662.          which  determines  whether  the mouse has been moved or if an
  663.          arrow key or number key has been pressed.   If  movement  has
  664.          been  requested  by  the  user through keyboard or mouse, the
  665.          global int px and py are updated, and the current position is
  666.          moved to the new px and py coordinates.  A line is drawn from
  667.          the previous position  to  the  new  one  with  the  function
  668.          lineto().   This  loop  continues  until the global variable,
  669.          left is 1, meaning the left mouse button has been clicked  or
  670.          the  [Enter]  key  was  pressed.   There  are   corresponding
  671.          variables,  right (for right mouse button and [Esc] key), and
  672.          center, for the center mouse button on three-button mice.
  673.  
  674.              Waste()  was  called  early in this program, to make sure
  675.          the variable "left" is reset to 0, otherwise the loop may not
  676.          execute.
  677.  
  678.              Px  and  py  are  global int variables declared in Magic,
  679.          which are generally used  for  graphics  screen  coordinates.
  680.          They are used by poll(), pointertoxy(), etc.
  681.  
  682.          Program 31 shows you one way to move a rectangle around. This
  683.          program  will  display the mouse pointer until the left mouse
  684.          button is clicked, then it  will  turn  it  off  and  show  a
  685.          movable  rectangle  until  the right mouse button is clicked.
  686.          Remember, the way to end this program is to click  the  right
  687.          mouse button (or press [Esc]).
  688.  
  689.               /* program #31 */
  690.               #include <magic.h>
  691.               #include <graphics.h>
  692.               void main(){
  693.                  magic_setup();
  694.                  bestvideo();
  695.                  waste();
  696.                  px = getmaxx() / 2;
  697.                  py = getmaxy() / 2;
  698.                  pointertoxy();
  699.                  pointeron();
  700.                  do poll(); while (!left);
  701.                  pointeroff();
  702.                  setfillstyle(SOLID_FILL,BLACK);
  703.                  rectangle(px,py, px + 40, py + 20);
  704.                  do{
  705.                     bar(px,py, px + 40, py + 20);
  706.                     poll();
  707.                     rectangle(px,py, px + 40, py + 20);
  708.                  }
  709.                  while (!right);
  710.                  cleanup();
  711.               }
  712.  
  713.              First we set px and py to  coordinates  representing  the
  714.          middle  of  the  screen,  move  the  mouse  pointer  to  that
  715.          location,   and   make   it   visible    with    pointeron().
  716.          Pointertoxy()  always  uses  the  global  ints,  px  and  py.
  717.          Pointertoxy() works even when the pointer is invisible.  Then
  718.          we  poll() over and over again until the user clicks the left
  719.          button.  When this happens, the pointer is turned off  and  a
  720.          rectangle  is drawn on the screen, with its upper left corner
  721.          at px,py.
  722.  
  723.             Then, a loop starts.  With each iteration of the loop, the
  724.          rectangle is erased by drawing a black bar over it, poll() is
  725.          called to see if the user has a new position for px  and  py,
  726.          and then a new rectangle is drawn.
  727.  
  728.             You'll also notice in  this  program,  a  function  called
  729.          setfillstyle().   This  dictates  what  kind of bar() will be
  730.          drawn.  Besides a solid black  bar  (best  for  our  purposes
  731.          here)  you  can  use  various  patterns  and colors.  See the
  732.          Borland Library Reference for more information.
  733.  
  734.             There are at least two other techniques commonly used  for
  735.          animations,  but  they are beyond the scope of this tutorial.
  736.          Basically, you can switch back and forth  between  two  video
  737.          pages,  one  with  the  original picture in it, and the other
  738.          with a rectangle on it. The other way is to save an image  of
  739.          the  area  where  the rectangle is to be placed in RAM first,
  740.          place the rectangle, then replace it with the original  image
  741.          again.  Look up getimage(), putimage(), and setwritemode() in
  742.          your  Borland  books for more information.  Setwritemode() is
  743.          available only with the newer compilers.
  744.  
  745.          Program #32 shows a couple of small improvements:
  746.  
  747.               /* program #32 */
  748.               #include <magic.h>
  749.               #include <graphics.h>
  750.               void main(){
  751.                  int oldx,oldy;
  752.                  magic_setup();
  753.                  bestvideo();
  754.                  waste();
  755.                  settextjustify(CENTER_TEXT,BOTTOM_TEXT);
  756.                  outtextxy(getmaxx() / 2,getmaxy() - 4,
  757.                    "Click right mouse button to end program");
  758.                  px = getmaxx() / 2;
  759.                  py = getmaxy() / 2;
  760.                  pointertoxy();
  761.                  setfillstyle(SOLID_FILL,BLACK);
  762.                  rectangle(px,py, px + 40, py + 20);
  763.                  do {
  764.                     oldx = px;
  765.                     oldy = py;
  766.                     while ((px == oldx) && (py == oldy) && (!right)) poll();
  767.                     bar(oldx,oldy, oldx + 40, oldy + 20);
  768.                     rectangle(px,py, px + 40, py + 20);
  769.                  }
  770.                  while (!right);
  771.                  cleanup();
  772.               }
  773.  
  774.              First, we took off the mouse pointer  stuff  to  simplify
  775.          the  program.   Then  we use one of the fancy features of the
  776.          GRAPHICS.LIB file to cause text to be centered from  left  to
  777.          right around the x coordinate and the bottom of the string at
  778.          the y coordinate. With outtextxy() a  notice  is  posted  for
  779.          the user.
  780.  
  781.              When writing software, always make it as user-friendly as
  782.          possible.  Ultimately, you will gain a reputation for writing
  783.          GOOD software, if it is easy to use.
  784.  
  785.              You'll notice that the rectangle no longer flickers as it
  786.          did  in  program  #31.   In  that  program, the rectangle was
  787.          redrawn every time the loop recycled, even  if  the  position
  788.          hadn't  changed.   Now,  we  remember  the old coordinates in
  789.          "oldx" and "oldy" and keep poll()ing  until  the  coordinates
  790.          change.  Only then do we redraw the rectangle.
  791.  
  792.              In  our  last  program I'll show you how to use the sound
  793.          effects in Magic, and we'll fool around with text in graphics
  794.          modes a bit more.
  795.  
  796.               /* program #33 */
  797.               #include <magic.h>
  798.               #include <string.h>
  799.               #include <dos.h>                   /*** 1 ***/
  800.               /* #include <conio.h> */           /*** 1a ***/
  801.               #include <graphics.h>
  802.               void main(){
  803.                  magic_setup();
  804.                  musicon = 1;                    /*** 2 ***/
  805.                  bugle();                        /*** 3 ***/
  806.                  mainback = BLUE;                /*** 4 ***/
  807.                  vgahivideo();                   /*** 5 ***/
  808.                  setcolor(LIGHTMAGENTA);
  809.                  gothic();                       /*** 6 ***/
  810.                  settextstyle(GOTHIC_FONT,HORIZ_DIR,6);
  811.                  settextjustify(CENTER_TEXT,TOP_TEXT);
  812.                  outtextxy(getmaxx()/2,0,"Type Anything");
  813.                  setcolor(YELLOW);
  814.                  settextstyle(DEFAULT_FONT,VERT_DIR,2); /*** 7 ***/
  815.                  settextjustify(LEFT_TEXT,CENTER_TEXT);
  816.                  outtextxy(20,(getmaxy() / 2) + 30,"Press [Enter]");
  817.                  outtextxy(40,(getmaxy() / 2) + 30,"when done.");
  818.                  settextstyle(0,0,2);
  819.                  settextjustify(LEFT_TEXT,TOP_TEXT);
  820.                  setfillstyle(SOLID_FILL,BLACK);
  821.                  setcolor(LIGHTCYAN);
  822.                  waste();
  823.                  pile("This sentence has no purpose!");
  824.                  savesettings();                    /*** 8 ***/
  825.                  pop(-1,400);
  826.                  restoresettings();                 /*** 9 ***/
  827.                  strcpy(answer,"");                 /*** 10 ***/
  828.                  do {
  829.                     u = getch();                    /*** 11 ***/
  830.                     pink();                         /*** 12 ***/
  831.                     if (u > 31) {                   /*** 13 ***/
  832.                        answer[strlen(answer) + 1] = 0;  /*** 14 ***/
  833.                        answer[strlen(answer)] = u;
  834.                     }
  835.                     if ((u == 8) && (strlen(answer) > 0)) /*** 15 ***/
  836.                     {
  837.                        bar(70,100,70 + textwidth(answer), /*** 16 ***/
  838.                          130 + textheight(answer));
  839.                        answer[strlen(answer) - 1] = 0;  /*** 17 ***/
  840.                     }
  841.                     outtextxy(70,100,answer); /*** 18 ***/
  842.                  }
  843.                  while (u != 13);    /*** 19 ***/
  844.                  restore();     /*** 20 ***/
  845.                  delay(500);    /*** 21 ***/
  846.                  sorry();       /*** 22 ***/
  847.                  delay(500);
  848.                  twinkle();     /*** 23 ***/
  849.                  cleanup();
  850.               }
  851.  
  852.  
  853.          Program #33 has notes within /*** and ***/:
  854.  
  855.          Note  #1: A function called delay(), used in this program, is
  856.          declared in the DOS.H file.
  857.  
  858.          Note  #1a:   The function getch() is prototyped in CONIO.H in
  859.          newer Borland  compiler  packages,  and  will  result  in  an
  860.          executable  program,  but  with  a  warning  if  this line is
  861.          commented out.  The older versions did  not  have  a  CONIO.H
  862.          file.
  863.  
  864.          Note #2: Before we can use the built-in sound effects in  the
  865.          Magic  library, we have to turn them on by setting the global
  866.          variable  "musicon" to 1.  Actually, the default is 1, or ON,
  867.          but good programming  practice  dictates  that  we  KNOW  the
  868.          status of all control variables.
  869.  
  870.          Note #3: Bugle() is  one  of  several  sound  effects  within
  871.          Magic.   The  others  are:  soundup(),  sounddown(),  pink(),
  872.          sorry() and twinkle(). Calling any of these when musicon =  0
  873.          will have no effect.
  874.  
  875.          Note  #4:  By changing the variable mainback to BLUE (BLUE is
  876.          color 1, as defined in  GRAPHICS.H),  the  screen  background
  877.          will  be  blue  when  cleared with xclear() or (in this case)
  878.          when a graphics mode is chosen.
  879.  
  880.          Note #5: For this example we use vgahivideo(),  but  if  your
  881.          computer  does not support it, change to a different graphics
  882.          mode and  change  the  coordinates  throughout  this  program
  883.          accordingly.
  884.  
  885.          Note  #6:  First,  we  load the Gothic font into the program,
  886.          then in the next line, we change it's size.
  887.  
  888.          Note #7: Do this for vertical text.
  889.  
  890.          Note #8: We're gonna  use  pop(),  which  draws  a  rectangle
  891.          border  in  a box, and uses the Bitmap font, in a small size.
  892.          When it is done, we want our old colors, linestyle, font type
  893.          and size, etc. back.   We  don't  want  to  reset  all  these
  894.          variables.     Therefore,    the   Magic   library   provides
  895.          savesettings() and  restoresettings().   Call  savesettings()
  896.          before  an  operation which may mess up your choices of font,
  897.          color, etc., and then restoresettings() when done.  This  can
  898.          be  use  with  pop()  as  well as almost anything you want to
  899.          create.  It  is  not  necessary  with  getanykey(),  getyn(),
  900.          dialog()  or  menu()  because  they  call  savesettings() and
  901.          restoresettings() automatically.
  902.  
  903.          Note  #9:   So,  right  after  pop(),  which  changed  color,
  904.          fillstyle,  font choice and size, etc., we restore all  these
  905.          variables    we    were    using    with   restoresettings().
  906.          Savesettings() and restoresettings() have no effect  in  text
  907.          mode - only in graphics modes.
  908.  
  909.          Note #10: We'll be  borrowing  a  string  variable  (character
  910.          array)  from  Magic  for  building a string which as the user
  911.          types, will be displayed on  screen.  This  first  "strcpy()"
  912.          makes sure the string, "answer" starts out empty.
  913.  
  914.          Note  #11:  We  have  established  a loop which will wait for
  915.          keystrokes from the user, turn them into  a  string  and  and
  916.          write it on the screen. At the top of the loop, the variable,
  917.          "u"  takes  on the value of the key the user pressed with the
  918.          function getch().
  919.  
  920.          Note #12: Pink() makes a click every time a key is pressed.
  921.  
  922.          Note #13:  The first 32 ASCII characters starting with #0 are
  923.          generally   unprintable,   containing  such  "characters"  as
  924.          carriage return or "beep." So,  we  won't  add  them  to  the
  925.          string.
  926.  
  927.          Note #14: These two goofy-looking lines illustrate one way to
  928.          build a string of text using a character array.  A  character
  929.          array  is  a  line  of locations in memory all containing one
  930.          byte, or character.  C handles strings by filling part or all
  931.          of an array with the text and then the next  byte  after  the
  932.          last  character is always set to 0.  This way, even the array
  933.          may allow room for more characters than the  string  actually
  934.          contains.   When  the compiler comes across a #0, it knows to
  935.          regard that spot as the end  of  the  string.  So  to  add  a
  936.          character,  we  effectively move the #0 over one position and
  937.          squeeze in the new character where the #0 was.
  938.  
  939.          Note  #15: ASCII #8 is the backspace key.  This is a compound
  940.          "if" statement because we better not try to backspace if  the
  941.          length of our string is already 0 characters! No telling what
  942.          might happen.
  943.  
  944.          Note  #16:   If we are backspacing, we need to erase at least
  945.          part of what is displayed on the screen.  The simplest way to
  946.          do it is erase the whole general area and redisplay the  new,
  947.          shorter  string.   Bar()  uses  the  currently  selected fill
  948.          pattern and color  as  set  by  setfillstyle()  a  few  lines
  949.          earlier.
  950.  
  951.          Note   #17:   This  is  the  actual  deletion,  using  direct
  952.          manipulation of the character string.  Remembering  that  the
  953.          compiler ignores everything past the #0, we simply put a zero
  954.          where the last character was when backspacing.
  955.  
  956.          Note  #18:  And, no matter what the user pressed, we might as
  957.          well rewrite the new string onto  screen.  It  takes  only  a
  958.          split second.
  959.  
  960.          Note #19:  This is the end of the loop. If the  user  presses
  961.          [Enter] (ASCII #13) the loop "falls through."
  962.  
  963.          Note  #20: Restore() is the compliment of pop().  It gets rid
  964.          of the pop up  box  and  replaces  what  was  on  the  screen
  965.          previously.
  966.  
  967.          Note  #21:  Delay()  is  a function prototyped in DOS.H which
  968.          will delay for the specified  number  of  milliseconds.  1000
  969.          milliseconds = one second, so our delay is 1/2 second.
  970.  
  971.          Note #22: sorry() is a fun sound effect.
  972.  
  973.          Note #23: Twinkle(): another fun sound effect.
  974.  
  975.  
  976.                                      - - -
  977.  
  978.             And  that almost wraps up this tutorial! Hope you have had
  979.          as much fun reading and experimenting as I did writing it.
  980.  
  981.             There  is far more available in C than this short tutorial
  982.          can tell you about.  To learn  as  much  as  you  can,  in  a
  983.          reasonable  amount of time, I recommend getting several books
  984.          on C and C++, and experimenting with every idea that  crosses
  985.          your  mind.  You'll find the overwhelmingly powerful and huge
  986.          Borland compilers and related programs easier  to  tackle  if
  987.          you  stay  with  C (and possibly C++) until you fairly master
  988.          them,  and  only then move onto TASM, Turbo Profiler, Windows
  989.          programming and all the other neat stuff.
  990.  
  991.             In fact, there's quite  a  bit  more  to  the  Magic  unit
  992.          itself.  You can read MAGIC.TXT to learn more of its included
  993.          functions  and  global  variables,  and  get  more  technical
  994.          information on the ones you already know.
  995.  
  996.             This is shareware.  Feel free to copy and  distribute  the
  997.          shareware  version  of  C  Magic  as long as all files remain
  998.          intact and unchanged.
  999.  
  1000.             If  you  have  paid a professional shareware distributor a
  1001.          few dollars for this disk, you have paid for the  service  of
  1002.          providing a copy.  The author (that's me!) has not  yet  been
  1003.          paid.
  1004.  
  1005.             If you use MAGIC.LIB in your  programs,  or  if  you  have
  1006.          found this tutorial helpful, you must pay for the creation of
  1007.          the product. Send $39.95 to:
  1008.  
  1009.                                 Another Company
  1010.                                  P.O. Box 298
  1011.                               Applegate, OR 97530
  1012.  
  1013.             Please  add $3 per order for USA postage, $5 for Canada or
  1014.          $7 - all other countries.
  1015.  
  1016.             If you need 3.5" disk size, please add $1.00.
  1017.  
  1018.             Complete source code is available for the MAGIC.LIB.  This
  1019.          is good for using as a framework for your own very customized
  1020.          applications,  for  learning  more  about  C programming, for
  1021.          stripping down to top efficiency, for using  MAGIC  functions
  1022.          in  object  oriented  programming,  and  for  improving.  For
  1023.          registration AND source code, send $79.90.
  1024.  
  1025.          Even  in  this version 1.5 you may find a bug or two.  I make
  1026.          no guarantees about  it's  suitability  to  your  programming
  1027.          needs.
  1028.  
  1029.          If we find any major bugs, they will probably be corrected by
  1030.          the time you get your registered  version!   Furthermore,  if
  1031.          this  evolves  the  same way our Pascal Magic did, registered
  1032.          users may get a version with even more features.
  1033.  
  1034.          If  you require technical assistance, you can try to phone me
  1035.          at 503-846-7884. Best bet is 9-5 weekdays, but I'm not always
  1036.          available.  Or, you can contact me via Compuserve: 71022,175.
  1037.  
  1038.              Since you are going to write some wonderful programs, you
  1039.          might as well start making money with them! You won't have to
  1040.          work in an office doing programming for  someone  else.   You
  1041.          can write exactly the kind of programs you want to write, and
  1042.          make money at home!
  1043.  
  1044.              The  'secret'  is shareware.  Does it work?  You bet! You
  1045.          can easily have a small success, making some  extra  spending
  1046.          money  each month, or with some practice, you may even have a
  1047.          larger success!
  1048.  
  1049.              ANOTHER COMPANY shows you everything.   Besides  our  own
  1050.          shareware products, including WRITER'S DREAM, BICYCLE TUNE-UP
  1051.          AND  REPAIR, MONEY, THE MULTIMEDIA WORKSHOP, BETTER EYESIGHT,
  1052.          WHAT'S IN THAT BOX?  and THE 21ST CENTURY  ALMANAC,  we  have
  1053.          researched  the  shareware  market, we have interviewed other
  1054.          shareware authors and have learned about  all  sides  of  the
  1055.          rapidly expanding shareware business.
  1056.  
  1057.               We  show  you  how  to  write  programs that capture the
  1058.          public's interest, how to make sure your  customers  want  to
  1059.          'register',  and how to get money by other means through your
  1060.          shareware.  We show you more. We show  you  frequency  charts
  1061.          indicating  which  types  of  programs  sell  best,  we offer
  1062.          suggestions for programs as yet unwritten, we talk about your
  1063.          on-disk instruction manuals, we even show you  how  to  write
  1064.          user-friendliness into your programs.
  1065.  
  1066.               Can  you  succeed without  SUCCESS WITH SHAREWARE?  Yes!
  1067.          But  why do  it  the  hard  way?  We  have  learned  all  the
  1068.          super-professional   approaches,   the   pitfalls   and   the
  1069.          shortcuts. We'll tell you all about it, and then  instead  of
  1070.          stumbling  around  for  the  first couple of years, you'll be
  1071.          a professional from the start!
  1072.  
  1073.              To get your copy of SUCCESS WITH SHAREWARE! (which is not
  1074.          shareware, itself - only  available  from  Another  Company),
  1075.          send $29.95. Please add $1.00 if you need 3.5" disk size.
  1076.  
  1077.                                                          Thanks,
  1078.                                                      - Jeff Napier -
  1079.                                                     September 1, 1992
  1080.  
  1081.             Please  include $3 per order for postage within USA, $5 to
  1082.          Canada, or $7 for all other countries.
  1083.  
  1084.          You can order products by writing your order on plain  paper,
  1085.          or  by  printing the included ASCII file called ORDER.FRM, or
  1086.          by phoning 1-503-846-7884, generally weekdays between  9  and
  1087.          5, west coast time.
  1088.  
  1089.  
  1090.