🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: comp.databases.xbase.fox
1 messages
1 total messages Started by Keith "Justified And Ancient" Co... Tue, 04 Oct 1994 14:52
FoxPro Databases FAQ #3: Things Your Mamma Never Told You.
#3
Author: Keith "Justified And Ancient" Co...
Date: Tue, 04 Oct 1994 14:52
541 lines
19923 bytes
Archive-name: databases/foxpro/misc
Posting-frequency: monthly

[This is FAQ version 1.0.0.5 - Last Updated 09/18/94.  New sections or
altered text are marked with ">" in the left hand column.]

This FAQ assumes that you have anything from a passing knowledge of xBase
languages in general to an intense knowledge of FoxPro event programming
in C.

Sections in this FAQ are seperated with "*****", but are not numbered,
because the FAQ itself is in alphabetical order based on title.  If
you have discovered a new trick in FoxPro, feel free to submit it to
me at kcochran@nyx.cs.du.edu.

EDITORIAL DISCLAIMER:  I have taken the liberty of editing the entries
in this FAQ slightly.  Mostly, I have reworded the occasional awkward
sentence, and done such cosmetic changes as putting all FoxPro commands
in ALL CAPS, reworded them into FoxPro format (i.e SELECT - SQL instead
of an SQL SELECT statement), and other such stuff.

POLICY DISCLAIMER:  Most of the information in this FAQ is unsupported
by Microsoft.  I make no guarantees of any sort about the information
contained in this FAQ.  If you use something you find here and wind up
clobbering all your data, it's your problem, not mine.

WHAT'S IN THIS FAQ:

Abnormal Program Termination in Extended FoxPro
   kruckenb@sal.cs.utah.edu (Joseph Kruckenberg)

Diagonal Lines In FoxPro/Windows
   blank@silver.ucs.indiana.edu (Doug Blank)

Generating Complex Indexes On Numeric Fields

Getting Rid Of The Microsoft FoxPro Screen And Title

Outer Joins In FoxPro
   davec@wsti.demon.co.uk (David Churcher)

Source Code Wanted - Only Singles Need Apply
   martin@convext.csd.uwm.edu (Martin A. Miller)

Unsupported Trick To Get Blank (Not Zero) Fields
   wsd@world.std.com (Rorschach)

Writable SQL Cursors!
   lotridge@charlie.ccd.bnl.gov (Charlie Lotridge)

*****
Abnormal Program Termination in Extended FoxPro
   kruckenb@sal.cs.utah.edu (Joseph Kruckenberg)

So, you're running along in the Extended Version of FoxPro when all
of a sudden you see:

abnormal program termination: page fault. cs:eip=000ch:0007791fh

(Note:  cs:eip may point to pretty much anywhere.  If you don't know
386 assembler, don't worry about what the numbers mean.)

Now what?  You can fire FoxPro back up and hope and pray that it doesn't
happen again, or you can add the following line to your AUTOEXEC.BAT
file:

SET FOXPROX=-saveregs

(Note:  No spaces between the equals and minus signs.)

This command tells FoxPro to preserve any registers in use and not to
overwrite them while running (given the limited explanation I recieved).

*****
Diagnoal Lines In FoxPro/Windows
   blank@silver.ucs.indiana.edu (Doug Blank)

Is there any way to draw lines that are neither horizontal or vertical in
FoxPro?  I am trying to make line graphs from data without using Microsoft
Graph. Any ideas?

Yes, it is sad but true: you cannot draw a diagonal line. I did try
dropping down to the windows API, and you can in fact draw any thing
that you want in the fox window --- but Fox doesn't "know" about it.
Therefore, if you close the window and reopen it your line is gone.
Any time that you cover your line, it won't be redrawn.

So, I finally ended up with the solution below. It does a pretty good
job on arbitrary lines. You may have to adjust x and y dotsize. These
parameters exist because of translation problems from real-valued
points to screen coordinates (welcome to the world of GUI's!)

To use, call with:

=drawline(1,5,11,30,.T.) && to produce a color line from @ 1,5 to 11,30 or
=drawline(1,5,11,30)     && to produce a black line 

Using this method, you can draw circles, splines, etc. Put the
function below in your program, or comment out the first line and
place in a file named DRAWLINE.PRG. It's not real fast nor smooth,
but it works. You probably can't make the line any thinner due to
related problems with real-valued vs. screen coordinates, so pensize
and penlength probaly can't be changed. You can change the RGB()
funtion to make any colors you want, or even add a CASE statement to
do them all, add shadows, etc.

FUNCTION drawline
PARAMETER x1,y1,x2,y2,color
PRIVATE x,y,B,slope
#DEFINE xdotsize (.2)
#DEFINE ydotsize (.5)
#DEFINE pensize (3)
#DEFINE penlen (.7)
IF m.y1 = m.y2 && vertical line
   IF x1 < x2
      IF color
         @m.x1,m.y1 to m.x2,m.y1 pen pensize color ;
            RGB(0,255,0,255,255,255) style "T"
      ELSE
         @m.x1,m.y1 to m.x2,m.y1 pen pensize color ;
            RGB(255,0,255,255,255,255) style "T"
      ENDIF
   ELSE
      IF color
         @m.x2,m.y1 to m.x1,m.y1 pen pensize color ;
            RGB(0,255,0,255,255,255) style "T"
      ELSE
         @m.x2,m.y1 to m.x1,m.y1 pen pensize color ;
            RGB(255,0,255,255,255,255) style "T"
      ENDIF
   ENDIF
ELSE
   m.slope = (m.x1 - m.x2)/(m.y1 - m.y2)
   m.B = m.x1 - (m.slope * m.y1)
   IF ABS((m.x1 - m.x2) / xdotsize) > ABS((m.y1 - m.y2) / ;
      ydotsize)
      FOR m.x = m.x1 TO m.x2 STEP xdotsize * ;
         IIF( m.x1 > m.x2, -1, 1)
            m.y = (m.x - m.B) / m.slope
            IF color
               @m.x,m.y to m.x,m.y+penlen pen ;
                  pensize color RGB(0,255,0,255,255,255) ;
                  style "T"
            ELSE
               @m.x,m.y to m.x,m.y+penlen pen ;
                  pensize color RGB(255,0,255,255,255,255) ;
                  style "T"
            ENDIF
      ENDFOR
   ELSE
      FOR m.y = m.y1 TO m.y2 STEP ydotsize * IIF( m.y1 > ;
         m.y2, -1, 1)
         m.x = (m.slope * m.y) + m.B
         IF color
            @m.x,m.y to m.x,m.y+penlen pen ;
               pensize color RGB(0,255,0,255,255,255);
               style "T"
         ELSE
            @m.x,m.y to m.x,m.y+penlen pen ;
               pensize color RGB(255,0,255,255,255,255) ;
               style "T"
         ENDIF
      ENDFOR
   ENDIF
ENDIF
RETURN

*****
Generating Complex Indexes On Numeric Fields

There's an interesting "feature" that the FoxPro manuals don't tell
you about in the information on indexes.  Let's say you have a database:
ACCOUNT N(6,0)
SSN N(9,0)

On first glance, if you wanted to sort the database by social security
number, and then account, you can just:

INDEX ON SSN+ACCOUNT TAG myorder
SET ORDER TO myorder

This, of course, doesn't work.  What happens is that FoxPro just adds
the values together, causing:

SSN = 076541111 ACCOUNT = 999999 (Key value = 77541110)

To appear AFTER

SSN = 076541122 ACCOUNT = 000333 (Key value = 76541455)

Note:  Microsoft assures me that this problem doesn't occur if you are
working with N(x,y > 1) fields, date fields, or logical fields.

What can you do to sort properly?  There are several schools of thought:

(1)You can add a digit after the decimal point.  Microsoft assures me
   that this will solve the problem.

(2)If you're working with fixed length fields, you can shift one set
   of digits over so that your math is correct.  In the above example,
   you would want to:
   INDEX ON ssn*1000000+account TAG myorder

(3)Convert the numerics into strings, and concatenate them:
   INDEX ON STR(ssn)+STR(account) TAG myorder

   or:

   INDEX ON TRANSFORM(ssn,"#########")+TRANSFORM(account,"######") TAG myorder

*****
Getting Rid Of The Microsoft FoxPro Screen And Title

The first thing to do if you're tired of seeing "Microsoft FoxPro"
every time you start your application is to use the -T command line
option to prevent it from showing up.  This looks like this:

FOX -T

If you're using FoxPro/Windows or FoxPro/MAC, and want to get rid of
the "Microsoft FoxPro" title in the bar of the main screen, you can
do several things.  After your application starts, you can

MODIFY WINDOW ... TITLE "My Title"

(Anybody know what the window's called?)

and the window name will change to whatever your title is.

You can also put the following line in your config.fpw/config.fpm
file:

Title=My Title

Note the lack of quotes.  This will cause the main window to be listed
as "My Title" as soon as FoxPro starts up.  For some reason, there are
differences in the way this works depending on whether you are running
your application from the development kit or the distribution kit.

*****
Outer Joins In FoxPro
   davec@wsti.demon.co.uk (David Churcher)

I give up, I RTFM (and I got FAQ'd) and did not find the syntax.

Using the foxpro Select command, I wish to join two or more tables 
inclusivley. By this I mean :

        To join Table A and B, if there is no join then include the
        records from table A and place blanks in the fields from table B.

In previous versions of foxpro I would have used "Set relation to" and 
it would have just happened.

Oh no, it's the dreaded Left Outer Join! This is an SQL construct which 
FoxPro doesn't currently support, so you have to simulate it using a 
UNION of two selects: one for all the records with matches in table B, 
and one for all the records without. Here's an example:

SELECT a.keyfield, ;
       a.datafield1, ;
       b.datafield2, ;
       b.datafield3 ;
   FROM a,b ;
   WHERE a.keyfield = b.keyfield ;
   UNION ;
      SELECT a.keyfield, ;
             a.datafield1, ;
             000.00, ;
             000.00 ;
         FROM a ;
         WHERE a.keyfield NOT IN ;
            (SELECT b.keyfield ;
                FROM b)

Couple of points:

1. The numeric and string constants in the second SELECT (000.00 in this
example) have to exactly match the length of the fields in the second
database, because FoxPro requires both sides of a UNION to exactly the
same structure.

2. SET RELATION TO and SET SKIP TO may be faster and easier if it's only
a simple query.

****
Source Code Wanted - Only Singles Need Apply
   martin@convext.csd.uwm.edu (Martin A. Miller)

There are two companies who provide software to generate source code
from compiled Fox* applications/programs.

1) Xitech Inc. 
   Toledo, Ohio (407) 292-8629; FAX: (407) 292-8652
   Product name: ReFox
   Restores FoxBASE, FoxBASE+, FoxPro 1.x, FoxPro 2.0,
   FoxPro 2.5 (including Windows).
   Cost: $299 + S&H

2) HILCO Software
   Sebastopol, CA (707) 829-5011; FAX: (707) 829-5710
   Product Names: dCRYPTR for dBASE III Run-Time
                  DECODE for dBASE II Run-Time
                  deFOX for FoxBase II (early dBASE II compatible)
                  OutFOX for Foxbase+
   Cost: $149.95 + $5.00 S&H

>In addition, Ron Talmadge made me aware of the following:
>   Frx2Prg Version 2.5
>   Have it your way with FoxPro Reports
>   Rory Data International
>   17 Thorburn Road
>   North Potomac, MD 20878
>   Phone: (301) 251-0497
>   BBS: 301-251-9206
>   FAX: 301-258-6862
>   CIS: 73765,121
>
>   Frx2Prg is a utility that translates a FoxPro 2.0 or 2.5 report
>   format (.FRX) file into a corresponding program (.PRG) file.

*****
Unsupported Trick To Get Blank (Not Zero) Fields
   wsd@world.std.com (Rorschach)

I been pulling my hair out for hours trying to figure this out.  Is is
possible to exclude records from an average that are blank?

DOCUMENT:Q97647  14-DEC-1993  [B_WFOXPRO]
TITLE   :INF: How Exclude Blanks, but Not Zeros, from an Average
PRODUCT :FoxPro For Windows
PROD/VER:2.50 2.50a | 2.00 2.50 2.50a
OPER/SYS:WINDOWS    | MS-DOS
KEYWORDS:

--------------------------------------------------------------------
The information in this article applies to:

 - Microsoft FoxPro for Windows, versions 2.5 and 2.5a
 - Microsoft FoxPro for MS-DOS, versions 2.0, 2.5, and 2.5a
--------------------------------------------------------------------

SUMMARY
=======

FoxPro's AVERAGE command sums numeric fields and divides the summed result
by the number of records summed. In some cases, you may want to determine
the AVERAGE only for fields that are not blank. Since there is no command
in the FoxPro language that can distinguish between a numeric field that is
blank and one that contains a zero, you must write a user-defined function
similar to the one below in order to accomplish this task.

MORE INFORMATION
================

The following function requires two parameters, the database name and field
name. An example of calling this function is as follows:

  ave = ave_nobl("test","num")

The above command shows "test" as the name of the database file and "num"
as the numeric field to be averaged.

Sample Code
-----------

   FUNCTION ave_nobl

   PARAMETERS dbfname,fld_name
   PRIVATE blank,skipbytes,i,numofblanks
   skipbytes=0
   numofblanks=0

   IF USED(dbfname)
      SELECT (dbfname)
   ELSE
      SELECT 0
      USE (dbfname)
   ENDIF

   headersize = HEADER(dbfname)
   no_records = RECCOUNT()
   rec_size   = RECSIZE()
   fld_width  = FSIZE(fld_name)

   * Place the database structure information in an array to
   * determine the field's position. The position is equal to
   * the row number of the field in the array, which is returned
   * by ASUBSCRIPT().

   =afields(afld_pos)
   fld_pos = ASUBSCRIPT(afld_pos,ASCAN(afld_pos,UPPER(fld_name)),1)

   FOR i=1 TO (fld_pos-1)
      skipbytes=skipbytes+FSIZE(FIELD(i))
   ENDFOR
   USE

   blank = REPLICATE(" ",fld_width)

   m.file = FOPEN(dbfname+".dbf")

   IF m.file<0
      RETURN "Error opening database "+dbfname+"."
   ELSE
      * The numeric field begins on the first byte following the
      * header and any preceding fields (headersize+skipbytes+1).

      m.move = FSEEK(m.file,headersize+skipbytes+1)

      * Read the value of the numeric field and compare it to
      * the variable blank.

      m.num  = FREAD(m.file,fld_width)

      DO WHILE .NOT. FEOF(m.file)
         IF m.num = blank
            numofblanks = numofblanks+1
         ENDIF

         * Move to the beginning of the numeric field in the next
         * record, read the next value, and compare it to the variable
         * blank.

         m.move = FSEEK(m.file,(rec_size-fld_width),1)
         m.num  =   FREAD(m.file,fld_width)
      ENDDO
      m.move = FCLOSE(m.file)

      USE (dbfname)
      SUM EVAL(fld_name) TO sub_result
      USE

      * Divide the sum by the number of records that are not blank.

      result = sub_result/(no_records-numofblanks)

      * Return the result to the program that called ave_nobl().

      RETURN result
   ENDIF

Additional reference words: 2.00 2.50 2.50a null blank

=============================================================================

THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS
PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.  MICROSOFT DISCLAIMS
ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  IN NO
EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR
ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL,
CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF
MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.  SOME STATES DO NOT ALLOW THE EXCLUSION
OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES
SO THE FOREGOING LIMITATION MAY NOT APPLY.

Copyright Microsoft Corporation 1993.
		
*****
   Writable SQL Cursors!
      By Charlie Lotridge (lotridge@charlie.ccd.bnl.gov)

   We've all had this problem:  You go to extract some temporary
   data from a few tables using a SELECT - SQL statement.  You
   set up the SELECT to output into a cursor so that you have
   the flexibility and efficiency of a table without having to
   be concerned about cleaning up after yourself.  THen you decide
   you'd like to add a record to this cursor or change a value in
   it and BOOM! - "Cannot Write To A Read-Only File".

   So what do you do?  In one of their FastTips, Microsot suggests
   that you first do your SELECT into an array, then create your
   cursor with the same structure, and finally use the APPEND FROM
   ARRAY command to move the data into the cursor.  For example:

   SELECT cust_name ;
      FROM customers ;
      INTO ARRAY temp
   CREATE CURSOR cust_curs ;
      (cust_name C(30))
   SELECT cust_curs
   APPEND FROM ARRAY temp
   RELEASE temp

   But this solution is less than ideal for at least two reasons
   that I can think of.  First, the cost in memory for the array
   can be quite large if the SELECT - SQL statement generates a
   lot of data.

   The second reason is more substantial - you must know the exact
   structure of the data being generated by the SELECT; both the
   order of the fields and their respective sizes.  This is at
   best an inconvenience, since if you change the structure of any
   of the source DBF's, you may also have to change the program
   code, and at worst impossible if you're trying to write some
   generalized routine which doesn't know much about the data
   it is operating on.

   [Question from the peanut gallery:  Can't you COPY STRUCTURE TO
    ARRAY, and then create your cursor from that array?]

   So what's the solution?  It's simple, really.  I came upon this
   idea when I was trying to change the alias of a cursor (don't
   ask why).

   At the temporary expense of an extra work area, you can rename
   the alias of your cursor (or any open table for that matter) and
   at the same time make it writable!!!  For example:

   PROCEDURE rename_table
   PARAMETERS m.fromalias, m.toalias
      * Open the table in another work area. *
      USE (dbf(m.fromalias)) IN 0 ALIAS (m.toalias) AGAIN

      * Close the old alias. *
      USE IN (m.fromalias)

      * And you're done! *
   RETURN

   And that's all there is to it.  The beauty of this solution is that
   your cursor's new alias has all the appearances of a regular DBF
   (it shows up in all caps in the View Window, and you can even use
   the SETUP button on it), yet it retains that most attractive quality
   of a cursor - it goes away when you close it!

   If the original alias or workarea of the cursor is important for some
   reason, with a little extra work rename_table can be make to preserve
   these characteristics with no loss of functionality.

   ***WARNING*** In some circumstances, the cursor you create is actually
   ***WARNING*** just a view of the table, not a seperate table in itself.
   ***WARNING*** In this case, appending, deleting, or altering records
   ***WARNING*** in your "cursor" will also alter data in the database.
-- 
=kcochran@nyx.cs.du.edu | B(0-4) c- d- e++ f- g++ k(+) m r(-) s++(+) t | TSAKC=
=My thoughts, my posts, my ideas, my responsibility, my beer, my pizza.  OK???=
=...the saddest thing:  The same people who are trying to get my .net access  =
=  removed are the same ones who insist on "educating" their own children...  =
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads