                           EDM/2
                     Volume 4, Issue 2
                       ASCII Edition

-----------------------------------------------------------------
Copyright Notice

EDM/2  is published by IQPac Inc.  IQPac Inc. can be reached
via U.S. Mail at the following address:

IQPac Inc.
7 East Broadway, Box 804
New York, NY 10038
U.S.A.

Editor-in-chief          Larry Salomon Jr.
                         (larry_salomon@iqpac.com)
Associate editor         Carsten Whimster
                         (carsten_whimster@iqpac.com)
Contributing editor      Gordon Zeglinski
                         (gordon_zeglinski@iqpac.com)

CEO/President            Larry Salomon Jr.
                         (larry_salomon@iqpac.com)

All material is copyrighted by its original author.  No part
of  this magazine may be reproduced without permission  from
the original author.

This  publication  may be freely distributed  in  electronic
form  provided that all parts are present in their  original
unmodified  form.  A reasonable fee may be charged  for  the
physical act of distribution; no fee may be charged for  the
publication itself.

Neither IQPac Inc.  nor this publication are affiliated with
International Business Machines Corporation.

OS/2  is  a  registered trademark of International  Business
Machines  Corporation.   Other trademarks  are  property  of
their  respective owners.  Any mention of a product in  this
publication   does   not  constitute   an   endorsement   or
affiliation unless specifically stated in the text.

[ OS/2 Accredited Logo ]

The  OS/2  Accredited Logo is a trademark  of  International
Business  Machines  Corporation and is used  by  IQPac  Inc.
under  license.   This On-line Publication is  independently
produced  by IQPac Inc.  and IBM is not responsible  in  any
way for its contents.

IQPac  Inc.  is an accredited member of the IBM  Independent
Vendor League.

-----------------------------------------------------------------
/dev/edm2/BookReview

Written by Carsten Whimster

Introduction

In   /dev/EDM2/BookReview,  I  focus  on  development  books  and
materials. I have written this column from the point of  view  of
an intermediate PM C programmer and intermediate REXX programmer.
Pick  up  whichever book strikes your fancy, and join the growing
group  of  people  following our PM programming columns.  I  have
already  reviewed a number of beginner's books, and will  try  to
concentrate  a  bit more on intermediate techniques  and  special
topics from now on.

Please send me your comments and thoughts so that I can make this
column what you want it to be. I read and respond to all mail.

Due  to the large number of books I have received in late '95,  I
am reviewing two books this month:

OS/2  Warp Workplace Shell API is the third and (currently)  last
book in the Wiley API series.

The OS/2 Warp Programmer's Sidekick, Functions and Structures  is
a new concise Warp reference book from Quarter Horse.

-----------------------------------------------------------------
Errata

Well, I have just moved, so not much is new here other than  mess
(but that's not new either).

I  have  recently received a letter from a reader  who  expressed
concern  regarding my giving OS/2 Certification  Handbook  an  A-
when  he felt a B was more appropriate due to the numerous errors
in  the  book.  I  feel that the errors that I came  across  were
easily caught, and that the value of the book is more in the fact
that it demonstrates what depth of knowledge and what breadth  of
subjects is covered on the actual tests, but I can also  see  his
point.  I intend to add an "Errors" page to the site, and  put  a
link  directly  in the column of issue 3-9, to let  people  catch
these errors and to let them judge for themselves. If anyone  has
found  any errors in this book, please pass them on, and  we  can
keep  track of them here. In fact, that goes for any of the books
I have reviewed. A central site to check for errors would be very
beneficial, I feel, so hopefully we can get this thing together.

Due  to the large number of books I received all at once in  late
'95  and  due  to the understandable anxiousness of some  of  the
authors,  I have decided to review two books this month.  Because
they are both reference books, and because they don't in any  way
compete  with each other, there should be no concern  as  to  the
fairness  of  these reviews, hopefully. They are each  useful  in
their own way, and have quite different philosophies, so actually
contrasting them with each other seems like a useful thing to do.
Be sure not to miss the second review.

By  the  way,  I believe that Mindy Pollack's name  has  recently
changed to Mindy Engelberg.

If  you look over the most recent few books that I have reviewed,
you  will  notice that I have been giving a lot of A's and  A+'s.
This is not coincidence, and it is not a sell-out. Unlike the me-
too market of Windows programming books, the OS/2 market seems to
have  fewer,  but  higher  quality  books  and  references,   and
naturally I gravitate towards the best ones. I will try  to  find
some  lousy  books to review, just so that you, the readers,  can
stay  convinced that I am doing my job, and not just  taking  the
easy way out. Please read on for another couple of A+'s <grin>...

-----------------------------------------------------------------
OS/2 Warp Workplace Shell API - review 1

This month's book is third and currently last in a new series  of
three  API  references  from John Wiley and  Sons,  covering  the
Control Program, Presentation Manager, and Workplace Shell  APIs.
Here are the chapters:

1.   Workplace Shell Overview
2.   Installing Workplace Classes
3.   Object Manipulation
4.   Instance and Class Data
5.   General Object Settings
6.   In-Use List
7.   Views
8.   Settings Notebooks
9.   Pop-up Menus
10.  Drag/Drop
11.  File System Objects
12.  Folder Objects
13.  Programs and Associations
14.  Disk Objects
15.  Shadow Objects
16.  Launch Pad Objects
17.  Palette Objects
18.  Help
19.  Printing
20.  Miscellaneous Methods
21.  System Object Model (SOM)
Appendix A.    Setup String Keynames
Appendix B.    DOS Settings Keynames
Appendix C.    Settings Page Methods
Appendix D.    Workplace Default Object IDs
Appendix E.    Predefined Views
Appendix F.    Device Object Settings

Unlike  the previous two month's books, publishing deadlines  did
not  get  in  the way of creating a decent number of examples  to
demonstrate  the  APIs in this book, and I  feel  that  this  has
strengthened  the presentation of the material greatly.  I  would
like  to see more sample code for the material later in the book,
but  this is a small detail. It does seem as if time may have run
out  for  examples for the last few chapters, though,  with  some
exceptions,  notably printing and finding objects. Hopefully  the
next  revisions of the other two books will allow a similar level
of detail to be added.

Similar  to both the other books, the major organization  of  the
book is as follows:

    each major topic is given its own chapter (see above)
    each chapter has a few introductory paragraphs, tutorial and
     explanatory in nature
    each function/method which comes under this chapter's
     heading is then given, as follows:
         name and type of API (ie. chapter heading repeated)
         brief description
    syntax
         parameters, each with a brief explanation, and tables of
          possible values, if appropriate
         returns, with value and description of error codes
         a "How to call" section which describes why and when to call
          this method
         a "How to override" section which explains the benefits of
          overriding the method
    other info, including include file, define, ordinal, and DLL
     API resides in
    see also, with related APIs, each with a page number
    notes, which usually lists any additional "gotchas" to be
     aware of
    restrictions/warnings
    sample code for many methods, but sometimes another method
     is referred to

The  two  "How  to" sections, the restrictions/warnings  and  the
notes  section  are particularly well implemented in  this  book,
with many great explanations of otherwise difficult material, and
counter-intuitive behaviour. I really feel that an  extra  effort
was  put  forth  in  this  area, and from  what  I  know  of  WPS
programming,  this  extra care and attention is  invaluable,  and
very  necessary. Sometimes the explanations seem  a  little  more
than  is  called  for,  but I far prefer  this  approach  to  the
opposite  one, in which the author assumes that you  know  things
which in fact you don't.

The first two chapters serve only as an introduction to WPS and a
quick  synopsis of the "normal" Win/Sys functions from  the  Warp
APIs  which  are  relevant  to  WPS  programming.  Chapter  three
introduces the first actual WPS methods. The differences  between
classes  and instances, and their methods, and when to use  which
is  carefully explained. It is not always obvious which is which,
but  read this material carefully, and I am sure that even people
almost as dense as me can understand it.

The  introductions to each chapter are extremely informative, and
very  well  written. They are concise, but invariably  manage  to
communicate a large quantity of cautions and explanations.  There
are  many  potential  pitfalls in WPS programming,  and  while  I
cannot  guarantee  that  they are all taken  care  of,  the  book
certainly conveys the impression of having done just that.

At  the end of each chapter, there is a small section which lists
all structures used by the methods of that chapter.

Finally, at the end of the book are several appendices which list
many useful constants, setup strings, and so on.

Here  is  an example of the care with which this book is crafted,
the wpViewObject instance method:

-----------------------------------------------------------------
     wpViewObject        WPObject instance method

Opens a view of an object

SYNTAX
HWND wpViewObject (HWND hwndCnr, ULONG ulView, ULONG param)

PARAMETERS
hwndCnr - input
The window handle for the container from which this object
is opened. This can be set to NULLHANDLE. The system usually
sets this parameter when the user opens an object.
ulView - input
The numerical value hta represents the view to open. See
Appendix E for a list of predefined Workplace views.
param - input
Application-defined parameter for the view. For predefined
Workplace views, this value should be NULLHANDLE.

RETURNS
(nonzero value) - The handle for the opened view.
NULLHANDLE - An error occurred.

HOW TO CALL
Call this method on any object to open a view. Calling this
method is preferred over calling wpOpen directly.

HOW TO OVERRIDE
Override this method to change its behaviour, but do not use
this override to process the opening of application-defined
views; wpOpen should be overridden for that purpose.

OTHER INFO
Include file:  wpobject.h

SEE ALSO
wpClose - 158, wpclsQueryDefaultView - 178, wpHide - 159,
wpOpen - 160, wpQueryDefaultView - 165, wpRegisterView -
167, wpRestore - 168, wpSetDefaultView - 171, wpSwitchTo -
173.

NOTES
The WPObject class processes this method first by checking
the concurrent view behaviour of the object with
wpQueryConcurrentView. If concurrent views are allowed,
wpOpen is called, passing the same parameters that were
passed to wpViewObject. If concurrent views are not allowed,
an existing view is searched for with wpSwitchTo. If
wpSwitchTo then returns FALSE, wpOpen is called. The net
effect is that a view of the requested type is brought to
the foreground.

SAMPLE CODE
The following sample demonstrates how to call wpViewObject
by opening the icon view of the System Setup Folder.

SOMAny *Folder;

/* get the object pointer for the system setup folder */
Folder = _wpclsQueryFolder (_WPObject, "<WP_CONFIG>", TRUE);
if (Folder)
{
     /* open the folder and unlock the object because we are
        through with it */
     _wpViewObject (Folder, NULLHANDLE, OPEN_CONTENTS, 0);
     _wpUnlockObject (Folder);
}
-----------------------------------------------------------------

I  think it is fairly obvious from this sample that this book was
not  whipped  together,  but it is probably  the  most  carefully
written  and put together book in my collection, and  as  a  book
reviewer,  that  is not inconsequential. Even more  so  than  the
first  two  books  in  this  series, both  excellent,  this  book
represents incredible quality at a good price, and I can say with
faith that this book is a very worthwhile addition to the library
of  any  OS/2 WPS programmer. When you realize that Mindy Pollack
was part of the WPS development team, you can begin to appreciate
the  depth of knowledge presented here. It almost sounds  like  I
have sold out or something, and when you look back over the books
I  have  reviewed, many have good marks, but this trio really  is
quite outstanding. Another A+ with no hesitation.

I  should make one caution here, however: as good as the book is,
it  does not teach WPS programming, but assumes that you know PM,
SOM, and at least the WPS basics. This is not anything to be held
against the book, but rather something to be aware of.

-----------------------------------------------------------------
Summary - review 1

This  is  one  solid book. Great explanations,  well  thought-out
section  for each method, good sample code, and useful appendices
go  a  long way towards making this one of the best books  in  my
library. A+. Another must-have for serious PM programmers. I have
nothing bad to say about this book.

This  is the third and last book in this series. I am very  happy
with these three books, but I would be even happier if Marc Stock
went on to have a book written on each of the GPI, Messages,  and
SOM.  I  hope that many more authors this good will come  forward
and  write  books for OS/2, and I hope that more publishers  will
allow  this  amount of care to be put into each of  their  books.
These  are  some of the best programming references I  have  ever
seen.

-----------------------------------------------------------------
The OS/2 Warp Programmer's Sidekick, Functions and Structures -
review 2

This  month's second book is also a reference manual, but with  a
different slant. The first and most noticeable difference is that
this  book  is  ring-bound rather than the more normal  paperback
cover. This helps it lie flat where you open it. Each chapter and
appendix also has a little gray blotch at the right edge  of  the
pages,  helping  you  to  quickly jump from  chapter  to  chapter
without  having to go to the index to look up page numbers.  Here
are the chapters:

General Notes
1.   Dynamic Data Formatting Functions
2.   Device Context Functions
3.   Control Program Functions
4.   Direct Manipulation Functions
5.   Graphics Programming Interface Functions
6.   Profile Manipulation Functions
7.   Presentation Manager Functions
8.   Macros
9.   Structures
10.  Error Codes
Appendices:
1.   Character Codes
2.   Virtual Key Codes
3.   Code Pages
4.   Default Country Codes
5.   Scan Codes
6.   Control Style Flags
7.   Graphics Primitve Attributes
8.   Raster Operation Codes
9.   Drawing Mode Contexts
10.  GPI Function Scopes

Overview

As  you  can see from this list of chapters, this book apparently
has  a  lot more information than the previous reference books  I
have  reviewed. That is both true and false. There is a lot  more
APIs covered in total, but the ones covered are covered in a less
detailed  fashion that the Wiley series. Through  this  different
emphasis, this book should appeal to more experienced programmers
who  have  already used many APIs a few times, and just  have  to
freshen their memory. There is a lot less information about usage
than  there  is  in the Wiley series, but all the most  important
stuff is there, of course, and more...

Chapters 1 through 7 cover the Ddf, Dev, Dos, Drg, Gpi, Prf,  and
Win  functions and macros. Each of these chapters starts out with
about one page of cautions and information about the functions in
that  chapter.  There is not a lot of detailed information  here,
but some good points are made. Each function is described more or
less in the following format:

- name.
- include.
- one-line description.
- syntax, including explanation  of values allowed for restricted
  parameters.
- returns, which explains all possible return values.
- errors,  which lists  all error messages, both  hex  value  and
  #define.
- notes, which lists a small amount of usage information and some
  cautions.

One  or  more of these sections may be missing, depending on  the
nature  of the function. For example, some functions are  missing
the   returns  section  if  the  return  value  is  obvious   and
unambiguous,  such as an HWND. This return value  would  then  be
mentioned in the description. One thing I would like to see added
is  a  note for each parameter which explains whether it is input
or  output. Sometimes this is obvious, and other times  it  seems
obvious, but is in fact misleading. Sometimes parameters  can  be
both  input  and  output, and this should be listed  too.  As  an
example,  some functions normally take a size, but  if  the  size
passed  is  NULL  or  0, then the appropriate size  is  returned.
Perhaps  this  omission is deliberate, and in  keeping  with  the
general "you used to know this but forgot" approach of the book.

Surprisingly,  I  have found myself using  this  book  much  more
frequently  than  one  would expect from a novice-to-intermediate
OS/2  programmer. It is just very handy, and it is easy  to  find
what  you  are  looking  for.  The  functions  are  all  in  pure
alphabetical order. Then when I stumble across what I was looking
for,  but  can't  figure out how to use it, I  defer  to  a  more
detailed reference or a programming book. Three quarters  of  the
time, though, I am able to find what I want in this book, and can
then move on to the next problem.

An  example of the level of detail provided can be seen  in  this
function:

-----------------------------------------------------------------
WinNextChar         INCL_WINCOUNTRY

Returns the address of the character after the current
character.

PSZ NoName WinNextChar (
     HAB       Anchor,        Anchor block
     ULONG     CodePage,      Code page, or 0 for process default
     ULONG     CountryCode,   Country code, or 0 for system default
     PSZ       Current )      Pointer to current string position

Errors
     0x100B    PMERR_INVALID_STRING_PARM

Notes
     - This function works for both double-byte and single
       byte character sets.
     - See page 522 for a list of code pages.

-----------------------------------------------------------------

While  not  as  detailed  as the Wiley series,  this  allows  the
authors to pack much more information in a similarly sized  book,
and  I  challenge anyone to find a book this size with this  much
information.  The main source for this book is the Warp  Toolkit,
but  apparently many of the errors in the toolkit have been found
and corrected, and some ambiguities corrected.

Starting  in chapter 8, macros, structures, and error  codes  are
given. The macros are useful, and you can learn quite a bit about
the  implementation of OS/2 by studying these and the structures.
The error codes I have yet to use, but they are there.

The appendices have all kinds of tidbits and goodies, and several
times already, I have found something in these appendices that  I
could not find conveniently anywhere else. As an example, I  have
used  the control style flags many times, and each of these comes
with  a quick explanation, unlike most of the other stuff in  the
appendices. In this section you can find slider styles, container
styles,  value  set styles, and so on. The list of  GPI  primitve
attributes is also quite handy. This is a section of lists of GPI
related  things, followed by a large table of all GPI  functions,
cross-listed  by  the drawing modes they are available  in.  This
table has also been put to use by me.

Finally, after the appendices, there is a large section which  is
modestly  called "Overview". This section has a list of  all  the
functions  in the whole book, along with a half-line  explanation
for each. This is a great way of browsing for a function that you
know should exist, but you can't find.

All in all, this book is leaner, but has much wider coverage than
the Wiley series, and so is aimed more at programmers who already
know  what  they  are doing with OS/2. It is  biased  towards  PM
programming,  but also has extensive control program  support.  I
can heartily recommend this book as the cure to your I-can-never-
find-what-I-am-looking-for ailment, as long as you can live  with
the leanness of the presentation. An undisputed A+.

-----------------------------------------------------------------
Summary - review 2

This  is now also my favorite PM reference book <grin>, alongside
the Wiley series. A great book, and without competition as a wide-
coverage, quick-reference PM reference book. If you want  detail,
and more help, the Wiley reference series is for you. If you want
extensive  coverage,  and don't need as  much  help,  the  quick-
reference Sidekick is for you. Yet another must-have for  serious
PM programmers.

-----------------------------------------------------------------
Books Reviewed

OS/2 Warp Workplace Shell API, Pollack
    John Wiley and Sons. ISBN 0-471-03872-5. US$29.99, CAN$40
    OS/2 C WPS Programmers
    A+

This  is  quite  simply  authoritative  and  outstanding.  Highly
recommended. If you program the WPS, get this. Full  of  gotchas,
and detailed implementation information.

The  OS/2  Warp Programmer's Sidekick, Functions and  Structures,
Murray and Diviney

    Quarter Horse Software and Publications. ISBN 0-9647472-8-6.
     US$39.95, CAN$53.95
    Intermediate and Advanced OS/2 C PM Programmers
    A+

This  is  an excellent reference. Light on implementation detail,
but  heavy on coverage. If the Sidekick doesn't have what you are
looking  for,  you  are  going  to  need  a  much  more  detailed
reference! Highly recommended.

NOTES

Please  note that books aimed at different audiences should  only
be  compared  with great care, if at all. I intend to concentrate
on  the strong points of the books I review, but I will point out
any weaknesses in a constructive manner.

LEGEND

BOOK: The name of the book, and the author(s)

PUBLISHING INFORMATION: Publishing company, ISBN, and approximate
price.

AUDIENCE: This is a description of the audience I think the  book
targets  best. This is not intended as gospel, just  a  guideline
for people not familiar with the book.

MARK:  My opinion of the success of the book's presentation,  and
how  well  it targets its audience. Technical content,  accuracy,
organization, readability, and quality of index all weigh heavily
here,  but  the single most important item is how well  the  book
covers what it says it covers. Many books try to cover too  much,
and get a lower mark as a result.

A+   Ground-breaking, all-around outstanding book
A    Excellent book. This is what I want to see happen a lot
A-   Excellent book with minor flaws
B+   Very good book with minor flaws or omissions
B    Good book with some flaws and omissions
B-   Good book, but in need of improvement
C+   Mediocre book with some potential, but in need of some updating
C    Mediocre book with some good sections, but badly in need of fixing
C-   Mediocre book, little good material, desperately in need of an overhaul
D    Don't buy this book unless you need it, and nothing else exists
F    Don't buy this book. Period

COMMENTS: This is a very brief summary of the review proper.

-----------------------------------------------------------------
Content Index

This  Content  Index is designed to let you find  the  book  that
covers  the  topics you need to learn about. It  will  eventually
have  a lot of categories, with each book being rated along  each
row. These tables will be quite large, and will continually grow,
so  please  give  me your feedback regarding what categories  you
would like to see, and which you don't. It may take me a while to
flesh them out, so have a little patience.

BOOK LEGEND:

Code Issue     Title

RWP  2-3  Real World Programming for OS/2 2.1
LPE  2-4  Learning to Program OS/2 2.0 Presentation Manager  by Example
ODD  2-5  Writing OS/2 2.1 Device Drivers in C
GPI  2-6  OS/2 Presentation Manager GPI
TAO  2-7  The Art of OS/2 2.1 C Programming
MOR  2-8  Mastering OS/2 REXX
RSH  2-9  REXX Reference Summary Handbook
ADO  2-10 Application Development Using OS/2 REXX
PMP  2-11 OS/2 Presentation Manager Programming
DOA  3-1  Designing OS/2 Applications
OSP  3-2  OS/2 Programming
TGO  3-4  The GUI-OOUI War
OWU  3-5  OS/2 Warp Unleashed, Deluxe Edition
QR1  3-6  WIN Functions, OS/2 Quick Reference Library Volume 1
PWG  3-7  Programming the OS/2 Warp Version 3 GPI
DHP  3-8  Designing High-Powered OS/2 Warp Applications
OCH  3-9  OS/2 Certification Handbook
CPA  3-10 OS/2 Warp Control Program API
PMA  4-1  OS/2 Warp Presentation Manager API
WSA  4-2  OS/2 Warp Workplace Shell API
OPS  4-2  The OS/2 Warp Programmer's Sidekick, Functions and Structures

NOTE:  Books  which cover the same material can look  similar  in
this  table, but be different in real life. The style of a  book,
for  example,  can not be seen from a quick table, so  make  sure
that  you follow up by reading the reviews of the books you  find
here. Finally, be sure that the books you are comparing are aimed
at the same audiences.

PM C/C++ BOOKS:

BOOK  MARK  Kernel    Device    VIO/ PM    GPI   Fonts      Print
WPS
          Basics    Drivers   AVIO

RWP  B+   2    0    0    4    4    4    3    0
PME  B-   1    0    0    2    2    2    0    0
ODD  A    0    5    0    0    1    0    1    0
GPI  C+   0    0    0    0    5    2    3    0
TAO  B+   3    2    1    4    1    2    0    0
PMP  A-   1    0    1    5    3    4    2    0
OSP  B+   2    0    0    3    2    1    0    0
PWG  A-   0    0    0    1    5    5    5    0

PM C/C++ REFERENCES:

QR1  A    0    0    0    5    0    0    0    0
CPA  A+   5    0    0    0    0    0    0    0
PMA  A    0    0    0    5    1    1    1    0
WSA  A+   0    0    0    1    0    1    3    5
OPS  A+   4    0    0    4    4    1    1    2

REXX BOOKS:

BOOK MARK REXX WPS  Reference
          Intro

MOR  B    4    0    2
RSH  A    1    2    5
ADO  A-   3    2    4

SYSTEM AND NON-PROGRAMMING BOOKS:

BOOK  MARK  Kernel     Device    VIO/ PM   Thread     GPI   Fonts
Print     WPS
          Basics    Drivers   AVIO

DOA  A    4    4    2    4    5    3    2    3    1
TGO  B    0    0    0    2    1    0    2    1    5
OWU  A+   1    4    4    5    2    5    5    5    5
DHP  A    4    4    2    4    5    3    2    3    1
OCH  A-   2    2    2    4    3    2    2    3    4

RATINGS LEGEND:

0    No coverage
1    Very light coverage
2    Introductory coverage
3    Good Coverage
4    In-depth coverage
5    Authoritative

-----------------------------------------------------------------
Coming Up

I  will  likely  review Programming in REXX or The REXX  Cookbook
next month.

Books I have:

Programming in REXX, Daney

The REXX Cookbook, Callaway

OS/2 Quick Reference Library - Message Functions, Scholin

Other books I would like to review:

The  Art of OS/2 Warp Programming, Panov, Salomon, Panov - I have
recently  noticed that this has been out for a few  weeks.  Hint,
hint, Q.

The  Design of OS/2, 2nd Edititon, Kogan and Deitel - I am having
trouble getting a copy of this, so if anyone can help, please do.
A 1st edition would do me fine too.

OS/2 C++ Class Library: Power GUI Programming with C Set ++, Law,
Leong, Love and Tsuji - This is on the way I am told.

OS/2 Presentation Manager GPI, 2nd edition, Winn - I really would
like  to review this soon, as I am coming across some stuff  that
the  old one doesn't handle in an up-to-date manner, and want  to
see what the new one is all about.

Visual Age: Concepts and Features, ? - This sounds interesting.

If  anyone has a book they want to see reviewed, I will be  happy
to oblige. Just mail me and tell me which. Publishers can send me
books  at  the  address on my personal page at  the  end  of  the
magazine,  and  I  will  review all OS/2 development-related  and
advanced user books I receive.

-----------------------------------------------------------------
Introduction to PM Programming

Written by Larry Salomon, Jr.

Introduction

The  purpose  of this column is to provide the  readers  out
there  who  are not familiar with PM application development
the   information  necessary  to  satisfy  their  curiosity,
educate  themselves,  and give them an  advantage  over  the
documentation  supplied by IBM.  Of  course,  much  of  this
stuff  could probably be found in one of the many books  out
there,  but the problem with books in general is  that  they
don't answer the questions you have after you read the  book
the first time through.

I will gladly entertain feedback from the readers about what
was   "glossed  over"  or  what  was  detailed  well,   what
tangential  topics need to be covered and  what  superfluous
crap  should have been removed.  This feedback is  essential
in guaranteeing that you get what you pay for.  <grin>

It  should be said that you must not depend solely  on  this
column to teach you how to develop PM applications; instead,
this  should  be  viewed  as  a  supplement  to  your  other
information  storehouses  (books, the  network  conferences,
etc.).   Because  this column must take a general  approach,
there  will  be  some  topics that you  would  like  to  see
discussed   that  really  do  not  belong  here.    Specific
questions can be directed to me via email and I will  do  my
best to answer them in a timely fashion.

-----------------------------------------------------------------
This Month

The  consensus  is  in!   You want  more  "meat"  with  your
potatoes.  Heck, I could have figured that out, since anyone
can  read  an Online Reference to find out what a particular
message  does.  Anyway, we will look at the slider  control,
how  it is used, and dissect a sample application which uses
three sliders to display a fillet.

-----------------------------------------------------------------
What Is a Slider, Anyway?

Back  in the days when OS/2 1.2 was around, a lot of  people
found  that  they  were  using the scroll  bars  to  display
various  types  of things.  However, when  these  uses  were
viewed  collectively, it was noticed that  the  things  that
were being done had similar characteristics:

     Most had feedback to display a number corresponding to
  the  scrollbar position - whether it was the  size  of  an
  object,  the  length of time to process a calculation,  or
  something  else,  the  user had to  know  what  they  were
  selecting.

    Most used the number from the scrollbar to control some
  aspect of the application - I keep thinking about the myriad
  of applications that allowed to you to define a color.  All
  would display three scroll bars which controlled the  red,
  green, and blue components of the color being defined  and
  this color was updated as you moved the scroll bars.

When  combined  with  other,  commonly-seen  user  interface
components,  e.g. progress indicators, it was  decided  that
these  applications would be better served by a window class
that was tailored somewhat for these types of things.  Thus,
the slider was born.  (The circular slider made its debut in
2.0 and the programming interface in 2.1.)

The slider (shown below) has many components:

[ Graphic ]

     Slider arm - this is the part that the user moves with
  the  mouse or keyboard.  It properly indicates that it has
  the input focus by displaying a dot in the center of itself.
  The  programmer may additionally specify "snap to  scale,"
  meaning that the slider arm is always on an integral part of
  the scale - no intermediate values are allowed.

    Slider buttons - these are alternate ways of moving the
  slider  arm one unit lower or higher.  (I hesitate to  use
  "up"  / "down" or "left" / "right" since the slider really
  doesn't care if it is oriented horizontally or vertically.)

     Ribbon strip - this is the "shaft" on which the slider
  arm travels.  This is frequently "ownerdrawn."

     Tick marks - these are indicators of the scale used in
  the  slider.   They may be sized (shown)  collectively  or
  individually.  You could, for example, only show every fifth
  item on the scale.

     Detent - these markers are inserted by the application
  to mark points of interest on the slider.

-----------------------------------------------------------------
Some Definitions

The  slider has some concepts associated with it, which  you
need to know before we may continue.

     Slider  type - we haven't mentioned it, but there  are
  two  types  of  sliders:  linear and  circular.   We  will
  initially deal exclusively with the linear slider, but  we
  will get to the circular one afterward.

     Home position - this is the position of the slider arm
  corresponding to point "0".  This may be up or down, left or
  right, depending on the style you use to create the slider.

     Scales - the linear slider provides two scales for you
  to  use  and  some messages will return to you information
  based on a particular scale.  The primary scale is the one
  you  will reference the most, but you may have use for the
  secondary scale.

-----------------------------------------------------------------
Slider Messages

I  won't  bore  you  with the parameters and  such  of  each
message.   Instead,  I  will  list  each  message,   briefly
describe  the  message's purpose, and annotate as  necessary
with any thoughts that come into my head.

SLM_ADDDETENT  - this message adds a detent to  the  slider.
Since  you  may  add  more  than  one,  you  must  save  the
identifier  returned so that you can send  it  back  to  the
slider when you send future messages related to this detent.

SLM_QUERYDETENTPOS - this message returns the position of  a
detent  relative to the home position of the slider  and  on
which  scale  the detent resides.  There are  two  problems,
however:  1) there is no way that I know of to add a  detent
to  the secondary scale, and 2) the position is returned  in
pels and not increments of the associated scale.  The second
item  isn't  such a bad thing because a detent will  usually
refer to points of reference that are not integral multiples
of  the  scale unit.  The first item seems to point  out  an
oversight, but maybe I'm just missing something.

SLM_QUERYSCALETEXT   -  this  message   returns   the   text
associated with a specific tick mark on the primary scale.

SLM_QUERYSLIDERINFO - this message allows you to  query  any
of  four  pieces of information about the slider,  including
the  slider  arm position and the size of the ribbon  strip.
For  the  slider arm position, you may request it either  in
pels  or  units along the primary scale.  Again, I  find  it
difficult  to  understand  why  the  secondary  scale  isn't
allowed here.

SLM_QUERYTICKPOS - this message returns the  (x,y)  position
of a particular tick mark.

SLM_QUERYTICKSIZE - this message returns  the  length  of  a
particular tick mark.  Note that all ticks have a width of 1
pel.

SLM_REMOVEDETENT  - this message removes a  specific  detent
from the slider.  Besides the lack of a scale specifier, the
slider lacks a way to remove all detents as well.

SLM_SETSCALETEXT  -  this  messages  sets  the  text  for  a
specific tick mark.

SLM_SETSLIDERINFO - this message allows you to  specify  the
size  and position of the components of the slider.  I would
have  liked  to see a way to set the position of the  slider
buttons.

SLM_SETTICKSIZE - this message allows you to set the size of
a  specific tick mark or all tick marks.  Tick marks have an
initial size of 0, so you must send this message if you want
to see any ticks.

-----------------------------------------------------------------
About The Sample Application

Now  that we've taken an admittedly accelerated look at  the
linear   slider,  let  us  now  move  forward  to  a  sample
application.    The  application  doesn't  utilitize   every
feature  of the slider control, but it shows enough  of  the
feature set to be useful to us.

What  this program does is display a fillet.  A fillet is  a
mathematical construct composed of a curve drawn in relation
to  the lines connecting three points.  (I am not a guru  on
this  topic,  so  I  will  stop the discussion  here.)   The
vertical position of any of the three points may be  changed
via   a  slider  which  corresponds  to  a  specific  point.
Additionally,  after the position is changed,  a  detent  is
added  to  indicate the current position of the point  along
the  slider.   To  graphically demonstrate  the  effects  of
moving  the points, a call to GpiPolyFillet is made to  draw
the construct as well.

Before  we get into the code, a few other points of interest
need to be mentioned:

     Modeless  dialogs  - I'm not sure if  we've  discussed
  these  beasts in this column, and I'm too lazy  to  do  an
  exhaustive search, so I'll describe them anyway.  A dialog,
  as  we  know,  is a window temporarily created  to  obtain
  information  from  the user so that  the  application  may
  continue  its processing.  These are also referred  to  as
  modal dialogs.

  A  modeless  dialog, however, is not created  temporarily,
  but  is  instead utilized for a longer period of time  and
  is   used   concurrently  with  the  application   (versus
  stopping   the  application  until  a  modal   dialog   is
  completed).   Modeless  dialogs  are  commonly  used   for
  palettes  in  graphics  applications,  such  as  a   color
  palette or tool palette.

  Another  common  use of modeless dialogs is  to  create  a
  main  window with many child windows in them.   We  could,
  of  course,  repeatedly call WinCreateWindow() within  our
  WM_CREATE message to create the child windows, but why  go
  through  all  of the typing when there is an  easier  way?
  Additionally,  dialogs were never meant  to  be  minimized
  and  there are some nasty caveats when trying to  get  the
  icon  to  display  properly  if  you  minimize  a  dialog.
  Instead,  we'll  call  WinCreateStdWindow()  to  create  a
  "regular" window (without the minimize problems) and  then
  call  WinLoadDlg() to create a modeless dialog as a  child
  of  the  client window.  WinLoadDlg() will create  all  of
  the child windows and we can go on our merry way.

     Subclassing  within dialogs - if you need  to  provide
  some customized painting within a dialog, you can do things
  the hard way or the easy way.  The hard way is to register a
  window class in the initialization of your application and
  then  specify  this  window class  in  the  DIALOGTEMPLATE
  definition of your resource file.  However, support for user-
  defined classes within the Dialog Editor is dismal, so the
  easy way is usually used instead.

  The  simplest  of  all window classes  is  a  simple  text
  control,  aligned  left  and  top  to  take  advantage  of
  default  styles.  Wouldn't it be easier to create  one  of
  these  and subclass it instead?  This way, you can  easily
  see  what's going on within the Dialog Editor and you  can
  let  the WC_STATIC class handle the petty details of being
  a  window while you concentrate on the animated logo  that
  you  want to display in your "Product information" dialog.
  We use subclassing to display the fillet in our window.

Instead  of  going through the source code line-for-line,  I
commented it liberally and will leave it up to you  to  read
through  it for comprehension.  Believe me when I  say  that
the application is indeed a simple one.  Should you have any
questions, however, feel free to email me.

-----------------------------------------------------------------
OOPS Avenue

Written by Gordon Zeglinski

Introduction

As  Caesar  was  warned "Beware the ides of March,"  so  too
should   programmers  be  warned  "Beware  the   quirks   of
compilers." Compared to C-Set++ and Borland, Watcom has some
strangeness.  Watcom uses "POSIX" file handles in  order  to
open  more than the default number of files, _grow_handles()
must  be  called,  which is classified as a Watcom  specific
function.   Interestingly enough, there is no  reference  to
this  function in any other file I/O related function.  Most
annoying to say the least.

C++  iostreams  provide a simple highly flexible  method  of
performing   formatted  and  unformatted  I/O.   The   basic
implementation  provides classes to perform  I/O  on  files,
memory  buffers,  and  the standard streams  (error,  input,
output).  Any  good  C++ book will tell you  how  to  format
output, or write raw data to a stream. Few books will detail
how to extend the hierarchy.

In this column, we will examine adding socket support to the
iostreams hierarchy. There's no point reinventing the wheel,
so  we'll start by looking at socket++, a Unix-based  socket
extension to iostream.

-----------------------------------------------------------------
SOCKET++

The  original  Unix  version has  classes  to  support  inet
sockets  and pipes. In addition, the FTP and SMTP  protocols
are  encapsulated in classes. Remember that BSD sockets  can
support  sockets that aren't Internet based  but  OS/2  only
supports Internet (Inet) sockets.  We will only look at this
library's generic socket and Inet socket support.

All  reading and writing to the medium is performed  by  the
streambuf  hierarchy.  The  generic  socket  buffer  object,
sockbuf,  is  the  heart of library. We'll  look  closer  at
stream buffers later. That being said, the programmer almost
never  works  directly with the stream buffer. Instead,  the
stream  hierarchy  is used to read/write  data.  The  stream
hierarchy  provides  operators  and  functions  to   perform
formatted and unformatted I/O on a buffer. Three classes are
derived  to provide input only, output only and input/output
streams.  These  classes are isockstream,  osockstream,  and
iosockstream.   These  last 3 classes are  very  simple.  As
shown  below,  isockstream defines only a few simple  member
functions. All of the work functions are inherited from  ios
and istream.

   class isockstream: public istream {
   protected:
       isockstream (): ios (0) {}
   public:
      isockstream(sockbuf& sb)
         : ios (new sockbuf(sb)) {}
       ~isockstream ();


       sockbuf*      rdbuf () { return
(sockbuf*)ios::rdbuf(); }
       sockbuf*      operator -> () { return rdbuf(); }

       void          error (const char* errmsg) const;
   };

Definitions  of  the  other  2  classes  are  similar   (see
sockstream.h).

Internet  sockets  use  the buffer class  sockinetbuf.  This
class  is derived from sockbuf, and provides tcp/ip specific
functions.  The classes isockinet, osockinet and  iosockinet
are derived from their generic socket counter-parts.

The  sockbuf class performs all socket operations,  binding,
connecting,  listening,  etc.  A stream  buffer  (streambuf)
class  provides  buffers  for buffering  input  and  output.
Utilizing  the  unbuffered I/O capabilities doesn't  require
any  additional programming effort, so we will look  at  the
more complex case of buffered I/O.

When a stream needs to write data, it calls member functions
in  the  streambuf class to write the data into the  buffer.
When  the  buffer  becomes full, the streambuf::overflow  is
called.  The overflow function must move the data  from  the
output  buffer  (also  called the put area)  to  the  output
medium (in this case the socket).

When  a  stream  reads from streambuf,  it  calls  streambuf
member  functions  to remove data from the  buffer,  if  the
buffer   is   empty   or   doesn't  contain   enough   data,
streambuf::underflow is called. The underflow function reads
data from the input medium and places it in the input buffer
(also called the get area).

The  get and put areas are sections of the reserve area. The
reserve  area  is  the block of memory  which  is  used  for
buffering  I/O.   Both  underflow and overflow  are  virtual
member  functions of streambuf. At the very least, a  custom
buffer   class   must  declare  members  for  overflow   and
underflow.  Note:  some  implementations  of  the   iostream
classes,  have  overflow  and  underflow  as  pure   virtual
classes. The following is a modified version of sockbuf.

   class sockbuf: public streambuf {
   public:
      enum type {
         sock_stream     = SOCK_STREAM,
         sock_dgram = SOCK_DGRAM,
           sock_raw = SOCK_RAW,
           sock_rdm = SOCK_RDM,
         sock_seqpacket  = SOCK_SEQPACKET
      };
      enum option {
         so_debug   = SO_DEBUG,
         so_acceptconn   = SO_ACCEPTCONN,
         so_reuseaddr    = SO_REUSEADDR,
         so_keepalive    = SO_KEEPALIVE,
         so_dontroute    = SO_DONTROUTE,
         so_broadcast    = SO_BROADCAST,
         so_useloopback  = SO_USELOOPBACK,
         so_linger  = SO_LINGER,
         so_oobinline    = SO_OOBINLINE,
         so_sndbuf  = SO_SNDBUF,
         so_rcvbuf  = SO_RCVBUF,
         so_sndlowat     = SO_SNDLOWAT,
         so_rcvlowat     = SO_RCVLOWAT,
         so_sndtimeo     = SO_SNDTIMEO,
         so_rcvtimeo     = SO_RCVTIMEO,
         so_error   = SO_ERROR,
         so_type         = SO_TYPE
      };
      enum level { sol_socket = SOL_SOCKET };
      enum msgflag {
         msg_oob         = MSG_OOB,
         msg_peek   = MSG_PEEK,
         msg_dontroute   = MSG_DONTROUTE,
         msg_maxiovlen   = MSG_MAXIOVLEN
      };
      enum shuthow {
         shut_read,
         shut_write,
         shut_readwrite
      };
      enum { somaxconn   = SOMAXCONN };
      struct socklinger {
         int   l_onoff;  // option on/off
         int   l_linger; // linger time

         socklinger (int a, int b): l_onoff (a), l_linger (b) {}
      };

   protected:
      struct sockcnt {
         int   sock;
         int   cnt;

         sockcnt(int s, int c): sock(s), cnt(c) {}
      };

      sockcnt* rep;  // counts the # refs to sock
      int      stmo; // -1==block, 0==poll, >0 == waiting time in secs
      int      rtmo; // -1==block, 0==poll, >0 == waiting time in secs

      virtual int    underflow ();
      virtual int    overflow (int c = EOF);
      virtual int    doallocate ();
      int            flush_output ();

   #ifdef _S_NOLIBGXX
      int      x_flags; // port to USL iostream
      int      xflags () const { return x_flags; }
      int      xsetflags (int f) { return x_flags |= f; }
      int      xflags (int f){ int ret = x_flags; x_flags = f; return ret; }
      void     xput_char (char c) { *pptr() = c; pbump (1); }
      int      linebuffered () const { return x_flags & _S_LINE_BUF; }
   #endif // _S_NOLIBGXX

      void     Destroy();  //added by gwz

   public:
      sockbuf (int soc = -1);
      sockbuf (int, type, int proto=0);
      sockbuf (const sockbuf&);
      virtual ~sockbuf ();

      sockbuf&      operator = (const sockbuf&);

      operator    int () const { return rep->sock; }

      virtual sockbuf*     open(type, int proto=0);
      virtual sockbuf*     close();
      virtual int          sync();
      virtual _G_ssize_t   sys_read (char* buf, _G_ssize_t len);
      virtual _G_ssize_t   sys_write (const void* buf, long len);
      virtual int          xsputn (const char* s, int n);
      int                  is_open () const { return rep- >sock >= 0; }
      int                  is_eof  ()       { return xflags() & _S_EOF_SEEN; }


      virtual int          bind(sockAddr&);
      virtual int          connect(sockAddr&);

      void                 listen(int num=somaxconn);
      virtual sockbuf      accept();
      virtual sockbuf      accept(sockAddr& sa);

      int                  read(void* buf, int len);
      int                  recv(void* buf, int len, int msgf=0);
      int                  recvfrom(sockAddr& sa,void* buf, int len, int msgf=0);

#ifndef __linux__
      int                    recvmsg (msghdr* msg, int msgf=0);
      int                    sendmsg    (msghdr* msg, int msgf=0);
#endif

      int                  write(const void* buf, int len);
      int                  send(const void* buf, int len, int msgf=0);
      int                  sendto(sockAddr& sa,const void* buf, int len, int msgf=0);

      int                  sendtimeout (int wp=-1);
      int                  recvtimeout (int wp=-1);
      int                  is_readready (int wp_sec, int wp_usec=0) const;
      int                  is_writeready (int wp_sec, int wp_usec=0) const;
      int                  is_exceptionpending (int wp_sec, int wp_usec=0) const;

      void                 shutdown (shuthow sh);

      int                  getopt(option op, void* buf,int len,
                              level l=sol_socket) const;
      void                 setopt(option op, void* buf,int len,
                              level l=sol_socket) const;

      type                 gettype () const;
      int                  clearerror () const;
      int                  debug     (int opt= -1) const;
      int                  reuseaddr (int opt= -1) const;
      int                  keepalive (int opt= -1) const;
      int                  dontroute (int opt= -1) const;
      int                  broadcast (int opt= -1) const;
      int                  oobinline (int opt= -1) const;
      int                  linger    (int tim= -1) const;
      int                  sendbufsz (int sz=-1)   const;
      int                  recvbufsz (int sz=-1)   const;

      void          error (const char* errmsg) const;
   };

As  mentioned before, the sockbuf class defines  the  member
functions underflow, and overflow.  In addition, it  defines
the   member  function  doallocate.  The  virtual   function
doallocate()  allows an ancestor of streambuf  to  customize
the allocation of the internal buffers.

   int sockbuf::doallocate (){
      // return 1 on allocation and 0 if there is no need

      if (!base ()) {
         char* buf = new char[2*BUFSIZ];  //allocate a buffer
         setb (buf, buf+BUFSIZ, 0);       //set the reserve area
         setg (buf, buf, buf);            //set the get area

         buf += BUFSIZ;
         setp (buf, buf+BUFSIZ);          //set the put area
         return 1;
      }
      return 0;
   }

The  '0'  parameter  in  the call to setb()  indicates  that
streambuf is not to free reserve area.

In the sockbuf definition, I added a destroy function. Below
is the function bodies for the destructor and the assignment
operator.  Note  that  in  the  original  version   of   the
assignment  operator, the destructor was explicitly  called.
This  resulted in hidden destructor code being  called  that
erased the calling instance's virtual function tables.   The
Destroy() function contains all the programmer written clean
up  code. It can be called by either the destructor  or  the
assignment operator without strange side effects.

   sockbuf& sockbuf::operator = (const sockbuf& sb){
      if (this != &sb && rep != sb.rep && rep->sock != sb.rep->sock) {
         //this is bad.. seems to nuke the virtual tables!
         //    this->sockbuf::~sockbuf(); << original code...

         Destroy();
         rep  = sb.rep; stmo = sb.stmo; rtmo = sb.rtmo;
         rep->cnt++;
         #ifdef _S_NOLIBGXX
            xflags (sb.xflags ());
         #else
               // xflags () is a non-const member function in libg++.
            xflags (((sockbuf&)sb).xflags ());
         #endif
      }
     return *this;
   }

   sockbuf::~sockbuf (){
      Destroy();
   }

   void sockbuf::Destroy(){
      overflow (EOF);         //flush the put area
      if (rep->cnt == 1 && !(xflags () & _S_DELETE_DONT_CLOSE)) close ();
      delete [] base ();
      if (--rep->cnt == 0) delete rep;
   }

Porting   the  unix  socket  code  to  OS/2  wasn't   overly
difficult.  It's  simply  a  matter  of  removing  Unix-like
headers and using the appropriate ANSI ones. To save  a  bit
of work, the BSD version of select() was used instead of the
OS/2 version.

-----------------------------------------------------------------
Wrapping Things Up

Extending the iostream class is simply a matter of  creating
the appropriate buffer class.  In the simplest case, the new
buffer  class  must  overload  the  underflow  and  overflow
streambuf functions. Once the buffer class has been defined,
a  new stream class is created.  The stream class is derived
from  either istream, ostream of iostream. That's  all  that
needs to be done.

-----------------------------------------------------------------
Rexx Inside and Out

Written by Joe Wyatt

Introduction

One of the more powerful weapons in your arsenal of functions  in
the  standard  Rexx  library  is  translate.   This  function  is
commonly  used  to  replace characters in one string  that  match
those  in  a second string with corresponding characters  from  a
third  string.  You follow all of that?  Well, by  the  time  you
finish  reading this month's column you will not only be able  to
use this function for simple character translations, but you will
have  the ability to format data strings such as currency,  time,
and dates with translate.  But wait; that's not all!

Since  this is an international "publication", I could  not  talk
about  formatting  currency and such without  either  being  very
favorable to one country's implementation or giving you a way  to
get  the current country dependent formatting options.  With that
in  mind  it is time to introduce the first edition of the  EDM/2
Rexx Utility Library.

For  supporting  ideas  and efforts in this  column  I  have  put
together a (currently) small DLL which houses three external Rexx
functions.  This library will be expanded as requested by readers
or  as  deemed necessary by me.  Please consider this library  as
"freeware".  &deity. knows that you don't have anything left over
to  support "shareware" after shelling out the money to  pay  for
this  free  magazine so it is included in the price [grin].   The
library  can be freely distributed; all I ask is that it  not  be
modified in any way.

This  month's column will provide initial documentation  for  the
new  Rexx  utility library as well as information on  effectively
using the translate function.

-----------------------------------------------------------------
EDM/2 Rexx Utility Library (EDMRexx)

The new library contains three functions that should prove
useful.

EdmRexxVer

Purpose

I figured there might be copies of this library scattered about
in the future and it might be helpful to check the validity of
each copy.  You might also use EdmRexxVer to test for a new
function's existence.  Let's say that I add EdmFutureFunction to
the library next month; when this function is needed the version
could be tested to see if it is at least "4.3".

Syntax

version = EdmRexxVer();  /* there are no arguments */

Returns

Version of the magazine for which this library was modified.
That means that even though this is the first edition of the
library, the initial return value will be 4.2.

EdmLoadFuncs

Purpose

Function will register all public functions to Rexx so that you
don't have to.

Syntax

call EdmLoadFuncs   /* there are no arguments */

Returns

0 if successful.  40 if called incorrectly.


Example

/* register all functions contained in EdmRexx.Dll to Rexx  */
/* external functions residing in a dll must be registered to
*/
/* be accessed by the Rexx program.                    */

call RxFuncAdd "EdmLoadFuncs", "EdmRexx", "EdmLoadFuncs"
call EdmLoadFuncs

EdmCountryInfo

Purpose

Provide read access to current country dependent information.

Syntax

rc = EdmCountryInfo( "ctry." );

Returns

0 if information returned ok.  40 if there was a problem.

Parameter

Name of a stem.  This stem is updated with the following
information:

ctry.Country             Country code.
ctry.CodePage            Code page.
ctry.DateFormat          Possible values
                         0 -> mm/dd/yy
                         1 -> dd/mm/yy
                         2 -> yy/mm/dd
ctry.Currency            Currency indicator
ctry.ThousandsSeparator  Character to use in numerics to separate
                         thousands.
ctry.Decimal             Character to use as the decimal indicator
ctry.DateSeparator       Character to use to separate elements in
                         date format
ctry.TimeSeparator       Character to use to separate elements in
                         time format
ctry.CurrencyFormat      Possible values
                         0 -> currency indicator precedes money
                         1 -> currency indicator follows amount
                         2 -> currency indicator replaces decimal
ctry.DecimalPlace        Number of digits after the decimal in
                         monetary strings
ctry.TimeFormat          Possible values
                         0 -> 12 hour format
                         1 -> 24 hour format
ctry.DataSeparator       Data list separator

Look for a separate INF file for this library soon.  (whenever I
get the time)

-----------------------------------------------------------------
Translate

Last issue's column mentioned that Rexx was a great language  for
processing strings and full words at a time.  That is still  true
and  we  will be using translate to change an entire number  with
one  call,  but  we  must introduce translate  for  what  it  is.
Translate  deals with one character at a time.  The  online  Rexx
reference manual defines the syntax of the translate function  as
follows:

     str = translate(string, <tableout>, <tablein>, <pad>);

Let's  see  what  happens  when  translate  is  called  with  all
parameters present.  The first action is to check the  length  of
tableout and tablein.  If tableout's length is less than that  of
tablein  the  pad  character is appended to  tableout  until  the
lengths  match.   The  default pad  character  is  a  space.   If
tableout's length is greater nothing is done, but it is easier to
imagine  tableout being truncated to match the length of tablein.
Once  the tables are satisfactory a copy is made of the value  in
the variable string, and the real processing begins.

String is searched for all occurrences of the first character  of
tablein.   If any are found then the corresponding characters  in
the  copy  are changed to the first character of tableout.   This
process  continues  until  string  has  been  searched  for   all
characters  in tablein.  The result value is the copy  of  string
that  was changed with the characters in tableout.  Now  for  the
variations.

When  there  is  only one parameter passed the variable  tableout
defaults  to  the  upper case alphabet, tablein defaults  to  the
lower case alphabet, and pad is a space.  This has the effect  of
translating all lower case characters in the passed parameter  to
upper case.

When  string is specified along with either tablein or  tableout,
but not both, the return string is the pad character repeated for
the  length of the original string.  This is also the  case  when
only  string and pad are specified.  I haven't found any use  for
these  permutations but, gosh, isn't it good to  know  that  they
exist.

You  are  now  armed  with  everything you  need  to  know  about
translate to understand the next discussion.

-----------------------------------------------------------------
Formatting

Someone  somewhere sometime before I got into  this  business  15
years  ago  figured  out a way to use the  translate  function  a
little  differently.  (It should be noted here that translate  is
not unique to Rexx and even exists as an assembler instruction on
some  machines.)  It seems natural to have your tables be  static
and  the value of string be the real variable.  What would happen
if we let string and tablein be the somewhat static pieces of the
equation and our main variable be tableout?

String  now  becomes a template for what the output  should  look
like  and  tablein  maps the current positions of  characters  in
tableout, our variable.  Let's pick apart an example to  see  how
this might work.

     str = translate("$abc,def.gh", 27446295, "abcdefgh")

Here,  string is searched for the first character in tablein,  an
"a".   This  "a"  is found in string and the first  character  of
tableout,  a  "2", replaces the "a" in the copy of string.   This
makes the value of copy become "$2bc,def.gh".  When this is  done
for the second character of tablein the copy becomes $27c,def.gh.
When  all  characters  of tablein have been processed  the  final
result is "$274,462.95".  Nice bit of formatting, no?  Let's look
at one more example.

     str = translate("ma/db/yc", "96/02/01", "yc/ma/db")

Table out is a date in yy/mm/dd format, but the desired format is
mm/dd/yy.  This invocation of translate will place 02/01/96  into
the return variable, str.  Now we are ready for the big finale.

Country Independent Currency Formats

I'm  certain that with the above information you can put  EdmRexx
and  translate  together to produce beautiful  results,  but  I'm
going  to  bore you with my solution anyway.  We'll pretend  that
I'm paid by the word and call it an example.

What  follows  is  a detailed discussion of accompanying  example
command file, money.cmd.  This program receives an amount as  the
argument  and  formats  it as currency for  the  current  country
dependencies recorded in OS/2.

The first statement in the program sets the number of digits Rexx
can  deal with to handle the maximum number that the routine  can
handle.   RxFuncAdd is called next to tell Rexx that the external
routine,  EdmLoadFuncs,  resides in  a  dll  called  EDMREXX.DLL.
EdmLoadFuncs is then called to register all other functions  that
are included in the dll to Rexx.

     /* money.cmd -- a country independent currency formatter */

     numeric digits 27  /* as if I'd ever see this much cash! */

     call RxFuncAdd "EdmLoadFuncs", "EdmRexx", "EdmLoadFuncs"
     call EdmLoadFuncs

To  Rexx,  the value of every variable is a string.  Datatype,  a
builtin  Rexx  function to check the type of the  contents  of  a
variable,  is used to ensure that the argument that we are  about
to format does indeed contain only numeric data.

     numb = arg( 1 )
     do while ( datatype(numb, "Number") <> 1)
         say "Please enter a valid number to be formatted as currency:"
         pull numb
     end /* do */

EdmRexx is used to gather the specific country information needed
complete  the  format.  The name of a stem, X., is passed  to  be
used to build all variables.

     call EdmCountryInfo "X."

Our  first  call to translate simply replaces the spaces  in  the
variable  string  to  the  character that  is  used  to  separate
thousand   groupings   in   the   current   country.    If    the
ThousandsSeparator is a comma, as it is in the US then the  value
of      string     after     the     translate      would      be
"abc,def,ghi,jkl,mno,pqr,stu,vwx".

     tablein     = "abcdefghijklmnopqrstuvwx"
     string      = "abc def ghi jkl mno pqr stu vwx"
     string      = translate(string, x.ThousandsSeparator, " ");

The number is divided into whole number and fraction parts in the
next  section.   The  length  of the whole  number  section  plus
thousands  separators  is  placed into  the  variable  len.   Its
calculation is a bit queer and worth reviewing.  It is  basically
the  sum  of the length of the whole number portion, length(int),
plus  the number of thousands groups, lennumb % 3.  If it is left
here  then there will be an extra comma preceding the number when
there   are  even  groups  of  three.   The  odd  looking  amount
subtracted from the sum, (lennumb // 3 = 0), is an equality  test
that resolves to 1 if there are even groupings of three and 0  if
there are not.  This use of the comparison statement is extremely
common, but proves quite useful in this case.

For  the  sake  of  a  complete example  let's  set  a  value  of
"123456.78"  for  numb.   After the  following  section  of  code
executes  "int"  is  equal to "123456", "lennumb"  contains  "6",
"len"  is "7" (length of 6 plus 2 groups of three minus 1 because
they are even groups), and "fract" has a value of "78".

     int    = trunc(numb)
     lennumb  = length(int)
     len    = lennumb + lennumb % 3 - (lennumb // 3 = 0)
     fract       = numb - int

The  next  section contains the meat of this column.  Tablein  is
truncated on the left to the length to contain the same number of
letters  as our integer has digits.  String is truncated  on  the
left  to the length of the integer plus the number of commas that
need  to  be inserted.  String now serves as a template for  what
the  number should look like.  "whole" is then created  with  the
result of the formatting translate.

Using  the same numbers from our previous example "tablein"  will
be  "stuvwx",  the  template, "string", will  be  "stu,vwx",  and
"whole" will contain "123,456" after the next three statements.

     tablein     = right(tablein, lennumb)
     string      = right(string, len)
     whole       = translate(string, int, tablein)

The  final section of code puts all of the pieces together  based
on the value of the CurrencyFormat value of the compound variable
created by EdmCountryInfo.  The only real point of interest below
is  the  invocation  of substr.  Substr is  used  to  ensure  the
fraction value of the monetary amount contains the proper  number
of   digits   according  to  the  country  dependent   value   of
DecimalPlace.  The function left() could also have been used  for
this purpose.

Completing  our  running example and assuming US  code  page  the
returned string would be "$123,456.78".

     select
       when (x.CurrencyFormat = 0) then
             /* currency indicator goes is at beginning */
           final = x.Currency || whole || x.Decimal || ,
                   substr(fract, 3, x.DecimalPlace, '0');

       when (x.CurrencyFormat = 1) then
             /* currency indicator goes is at ending */
           final = whole || x.Decimal || substr(fract, 3, ,
                   x.DecimalPlace, '0') || x.Currency;

       when (x.CurrencyFormat = 2) then
             /* currency indicator replaces decimal */
           final = whole || x.Currency || substr(fract, 3, ,
                   x.DecimalPlace, '0');
     end

     return final

-----------------------------------------------------------------
All Said and Done

Even if you knew everything there was to know about the translate
function  before you started reading this column,  you  at  least
have gained a new toy.  EdmRexx will grow in the future.  All you
have to do is ask.  Let's face it, if you are going to wait on me
to have all of the original thoughts for this column we are going
to  go  downhill fast.  Let me know of any problems or  successes
you have.  I have only tested this code in one country.  If you'd
like  to send me tickets to Bermuda I'd be happy to test it there
as well.  [wink]

-----------------------------------------------------------------
Under The Scope

Written by Brad Scharf

Introduction

Welcome  to the Utility Review column. This is a new  column
that   will  review  freeware,  shareware  and  commercially
available  applications  intended  to  aid  the  development
process  and  initially will be targeted  towards  beginning
OS/2 programmers.

The  column will feature one or two utilities each month.  I
will try and let the reader know in advance which tools will
be  featured.  Also, there will be an index at  the  end  of
every   column   that   will  include  program   names   and
descriptions,  which  issue of EDM/2  featured  the  program
review  and  in future issues I will try and let the  reader
know where the utilities can be found and at what cost.

If  you  have  any  comments or suggestions  regarding  this
column  please let me know. If the column is to be a success
it will be through the feedback of its readers. Likewise, if
you  know  of  a utility that would be beneficial  to  other
programmers  please mention it and I'll do  what  I  can  to
ensure that readers are made aware of it.

This Issue

After  a few false starts I managed to find a tool that  (as
far  as  I know) doesn't have a new version due by the  time
you read this!.

I  feel like confessing something so here I go ... I'm lazy.
Yup, really lazy. I don't like to do more than I need to and
when  I  do do something I believe it should be as  easy  as
possible. This applies to learning programming and  actually
building a project as much as anything else. This being  the
case,  you can only imagine my excitement when I came across
an  application development tool called Guidelines. In fact,
I was so excited I've decided to do this review over several
issues which will be broken down as follows:

Part 1 - a general overview.
Part  2  - a closer look at the development environment  and
review of the same.
Part 3 - an introduction to and review of the language.
Part  4  -  build  a simple project (probably  the  standard
"Hello World" with one or two extras but this remains to  be
decided)  and  a more-in-depth summary than will  appear  in
this issue.

While all this is taking place I will also review some other
utilities  (that is after all, the purpose of this  column).
Depending on what we look at will determine if the  4  parts
to  the Guidelines review will appear consecutively or  not.
If  not,  there won't be more than a one-issue pause between
sections  and it's quite likely that some of the four  parts
will  be  published in conjunction with another  review.  As
well, each section will receive a rating independent of  the
others, with an overall rating at the end.

By  the  way, if you have any comments or suggestions  about
this  multi-part format please let me know, as this is  only
the  first  of many reviews that I would like to present  in
this manner.

Guidelines 3.1j Base Pack

[ Graphic ]

-----------------------------------------------------------------
Part 1: A General Overview

Guidelines is an application development package with cross-
platform  capabilities and supports  a  variety  of  popular
compilers for OS/2 and MS-Windows 3.1.

Right  from  the start it's apparent that this  program  has
something  special to offer. A straight-forward installation
program  lets  you select installation directories,  creates
the  desktop  folders  and objects and  optionally  modifies
CONFIG.SYS paths.

The Guidelines 3.1 interface is easy to use and it's easy to
look at. The user is not overwhelmed with tool palettes  and
menus, the menus themselves are well organized and intuitive
and options are not so deep as to make options difficult  to
find.

Much  of the work to build a project has been taken care  of
for  you with Guidelines. Frame windows, dialog windows  and
menu items are created by menu selection. Controls are added
by  selecting from either the menu or tool palette. Likewise
for  presentation  parameters and window behavior,  etc.  In
fact,  almost  everything is accomplished  by  pointing  and
clicking. Double clicking the left mouse button on a  window
or   control  brings  up  the  'details'  dialog  for   that
particular item. Single clicking with the right button takes
you  to the 'action module' for that item and once there you
can  add modify the code for that same item. Even a fair bit
of  code  can  be  added in via mouse  selection  by  right-
clicking  where  you  want the code to be  placed  and  then
selecting  the code template you require from  a  series  of
list  boxes  that  become more specific as  you  go  deeper.
Simply modifying the templates to your specific needs is all
that's required.

As  mentioned  in  the introduction, Guidelines  supports  a
number  of compilers for OS/2. These include IBM C++ v.2.01,
Borland C++ v1.00 and Watcom C++ v9.5 and 10.0. In addition,
several  compilers  are supported for the  creation  of  MS-
Windows 3.1 applications if you are bent that way.

Compiler switches are pre-configured by Guidelines for  each
compiler,  depending on whether or not you wish  to  include
debug  information in your files. Compiler, linker and other
program  switches (make, rc, implib etc.) may also be  added
or  removed, depending on your preferences. Paths  are  also
pre-configured and can be modified on a case-by-case  basis,
or   you  may  choose  to  use  environment  settings   from
CONFIG.SYS. It is also possible to add compilers to the list
but it is not known if support for additional compilers must
be  built  into  the Guidelines libraries  for  code  to  be
properly generated for other compilers.

Guidelines  is not only easy to use, but allows creation  of
programs  that  make full use of the OS/2 environment.  Your
can  write  multi-threaded programs, use CUA  '91  controls,
create  client/server and database apps, support  DDE,  SOM,
create  EXEs or DLLs and quite a bit more. Not all  of  this
functionality  is  included with the Base  Pack  that  we're
looking at here and must be purchased separately as modules.
For  example, if you wish to create containers or  notebooks
from  within Guidelines you'll need the PDK. If you wish  to
use  Guidelines to create WPS programs you'll need  the  SOM
extensions,  client/server  apps require  the  Client/Server
extensions  etc. However, the Base Pack itself  will  permit
the  creation of simple yet functional programs and  if  you
need  to  do something that the Base Pack doesn't allow  you
can  always write the code in C++ and add it to the  project
as  either an internal module or as an external file.  After
all,  when  you  build your project with  Guidelines  you'll
actually be using your own compiler anyhow so any code  that
your compiler will accept as input should be valid.

If you are already an accomplished PM programmer you may not
actually  benefit from a tool such as this. In fact,  if  if
you  are you'll notice decreased productivity until you gain
an   understanding  of  the  language.  Guidelines  uses   a
proprietary language called JOT. The language itself is  not
too  complicated  but  there will still  be  the  inevitable
learning  curve.  The  most  benefit  from  this  tool  will
probably  be derived from people like myself whose knowledge
of   C++  is  not  great  and  whose  understanding  of   PM
programming  isn't  much better. We have  here  a  situation
where,  in order to become proficient, a lot of new concepts
must  be learned and now we have a tool that eases that task
of gaining that proficiency.

-----------------------------------------------------------------
Summary

Guidelines is obviously not the only tool available to  ease
the  task  of creating PM programs, and certainly isn't  the
cheapest  when you consider that the PDK alone costs  almost
$600  (US), requires an OS/2 compiler and still won't  allow
you  to  add  the functionality (using JOT alone)  that  you
could  with a compiler and C or C++ unless you purchase  the
extension packages.

On  the  up-side, once you know the language  you  have  the
ability to create an application for multiple platforms from
one  environment. You can change compilers without  worrying
about  the peculiarities of the brand. There are no run-time
libraries  to  distributed, thus no run-time royalties.  The
development process is fast and simple and for inexperienced
C  or  C++  programmers the JOT language  should  allow  the
creation  of  PM  programs much faster  than  writing  a  PM
program in C/C++.

Overall,  this is an outstanding package (from  a  beginners
point  of view). It is easy to use, the language is easy  to
learn,  it isolates beginning programmers from much  of  the
complexity  of  PM  programming  and  allows  even  new   PM
programmers to create functional programs in a short  period
of time.

-----------------------------------------------------------------
Larry Salomon Jr.

Larry  Salomon  Jr.   has been developing OS/2  applications
since   version  1.1  in  1989.   He  has  written  numerous
applications,  including  the  Scramble  applet   that   was
included in OS/2 versions 2.0-2.11, and the I-Brow, Magnify,
and  Screen  Capture  trio  that  has  been  distributed  on
numerous CD-ROMs.

Larry  is also the coauthor of the successful book, The  Art
of  OS/2 2.1 C Programming (Wiley-QED). Finally, he  is  the
CEO/President  of IQPac Inc.  which is responsible  for  the
publication  of  EDM/2, and he is a frequent contributor  to
the publication.

Larry  can  be  reached electronically via the  Internet  at
larry_salomon@iqpac.com.

-----------------------------------------------------------------
Brad Scharf

Brad discovered computers while enroled in a chemistry B.Sc.
program  and soon switched to computer science. He has  been
using   OS/2 since the release of version 2.0, and has  used
OS/2   exclusively  since version 2.1  and  is  now  in  the
process of  teaching himself PM programming.

Brad can be reached via the internet at schab@sasknet.sk.ca

-----------------------------------------------------------------
Carsten Whimster

Carsten is an undergraduate Computer Science student at  the
University of Waterloo. He is currently in fourth year,  and
enjoying it immensely. He uses Visual Age C++, Watcom  C/C++
10.0a  and  Watcom VX-REXX 2.0c.  Carsten is the  author  of
some  commandline utilities, and POV-Panel/2.  He is also  a
TEAM-OS/2 member.

You may reach Carsten...

...via email (Internet):

bcrwhims@undergrad.math.uwaterloo.ca

...via the World Wide Web:

http://www.undergrad.math.uwaterloo.ca/~bcrwhims/

Please note the changed address and phone number

...via snail mail:

Carsten Whimster
43 Wilhelm Street, apt. 2
Kitchener, Ontario
Canada
N2H 5R9

...via voice:

(519)749-2391

-----------------------------------------------------------------
Joe Wyatt

Joe has been working in OS/2 since 1.3 and has programmed in
Rexx  on  four  different  platforms.   Rexx  projects  have
included  elegant,  complex systems in  both  VM  and  OS/2,
operating  system automation in MVS, and your  basic  "quick
and  dirty" tools in DOS.  He has recently mustered  up  the
courage  to  jump  into  the world of consulting  and  self-
employment.   (God  help him.)  He makes  his  home  in  San
Antonio, Texas with a wife and four children (along  with  2
dogs,  1  cat,  1  turtle, varying numbers of  fish,  and  a
rabbit).

He can be reached via internet address jwyatt@txdirect.net
for comments and criticisms.

-----------------------------------------------------------------
Gordon Zeglinski

Gordon  Zeglinski  is a freelance programmer/consultant  who
received  his Master&apos.s degree in Mechanical Engineering
with  a  thesis on C++ sparse matrix objects.  He  has  been
programming  in  C++  for 6 years  and  also  has  a  strong
background   in   FORTRAN.   He  started   developing   OS/2
applications with version 2.0 .

His  current projects include a client/server communications
program  that utilitizes OS/2's features which  has  entered
beta   testing.   Additionally,  he  is  involved   in   the
development of a "real-time" automated vehicle based on OS/2
and using C++ in which he does device driver development and
designs the applications that comprise the control logic and
user interface.

He can be reached via the Internet at
gordon_zeglinski@iqpac.com .
