No announcement yet.

Error handling errors in PB3.5?

  • Filter
  • Time
  • Show
Clear All
new posts

  • Error handling errors in PB3.5?

    Error trap handling is a large part of my program work. For debugging
    from users I write a simple append file on their disk. The executable
    name, log unit number, PowerBASIC ERR and ERL, date and time and sometimes
    free memory values and stack space can be gained from each append line.

    PowerBASIC's error trap capabilities are a HUGE benefit. Try hand writing
    code in C/C++ to equal it, even though it is keyed to numeric line lables.
    So NUMERIC line lables for PB error service are well placed in some critical
    points, yet most lines, with utmost care where no lables are needed, have
    no lables in my source code. That to remove another source of confusion.

    Long before PB 3.5, I chose to 'reserve' a block of the 64K available
    BASIC line numbers for common SUB's and FUNCTIONS for core lower and
    mid-level common functions. The concept has been stable for years. My
    entire core lowest level suite-wide video, string and file operations on
    standard PB code are all common library modules assigned to the 50,000
    to 59,999 line number range. They always retain the same code and line
    numbers. Now please consider the following corruption I can't figure out!

    Here are error log results for one client site on four different boxes
    with different hardware mix, ages, raw hardwired memory size. We can't
    really force people to keep hardware at the same level there, even though
    my code suite support files on that server have a total of only TWO (2)
    hours of failure down time in now EIGHT years of 24X7 service in my suite
    under the OS/2 superb operating system and network capability there!

    In the combined error log below, a program is followed by log unit, PB ERR
    number, PB ERL NUMERIC line number, date and time. Two programs also seek
    to return available free string memory, free high memory and free stack
    space. But note the FAILURE to report that also in some cases. That's a
    curious point as the line is generated in these executables by exactly the
    same compilation that DOES provide that memory data for some of the errors!
    Five separate programs show unreasonable errors just AFTER the same little
    SUB. And the failure to show any memory values in the space available
    print points indicate corruption issues to me. The SUB which produces the
    data values for the memory in NAMES.EXE is called at the start of each new
    or edit function for the program, for example.

    "ENTRY.EXE Log # ","1"," err# ",70," line",50421,"01-31-2005","18:26:53"
    "INVENT.EXE Log # ","1"," err# ",70," line",50421,"01-20-2005","16:08:59"
    "PRLIST.EXE Log # ","1"," err# ",70," line",50421,"03-14-2005","16:16:01",0,0,0
    "NAMES.EXE Log # ","1"," err# ",5," line",50421,"03-17-2005","11:53:38",8174,227600,3788
    "PRLIST.EXE Log # ","1"," err# ",70," line",50421,"04-05-2005","17:33:23",0,0,0
    "ENTRY.EXE Log # ","1"," err# ",70," line",50421,"04-08-2005","07:29:30"
    "NAMES.EXE Log # ","1"," err# ",5," line",50421,"04-14-2005","17:12:53",0,0,0
    "NAMES.EXE Log # ","1"," err# ",5," line",50421,"04-17-2005","18:36:05",0,0,0
    "NAMES.EXE Log # ","1"," err# ",5," line",50421,"04-17-2005","18:55:36",0,0,0
    "NAMES.EXE Log # ","1"," err# ",5," line",50421,"04-17-2005","18:58:49",0,0,0
    "NAMES.EXE Log # ","1"," err# ",5," line",50421,"04-17-2005","19:05:28",0,0,0
    "NAMES.EXE Log # ","1"," err# ",5," line",50421,"04-18-2005","07:28:22",8174,225552,3788
    "NAMES.EXE Log # ","1"," err# ",5," line",50421,"04-18-2005","07:30:31",0,0,0
    "NAMES.EXE Log # ","1"," err# ",5," line",50421,"04-18-2005","08:36:12",0,0,0

    What produces this PB 'error' 70 (Unable to write to a protected disk)
    and 5 (Illegal function)? Here is a declaration. Please, If this utmost
    core level SUB occurs hundreds of times in a suite and every program of
    over a hundred has to use the results of it; the smartest way to use a
    CORE level function is to use PUBLIC variables for it in suite-wide. I do,
    from a comman include file so there are no declaration errors. The SUB
    in question does nothing other than to recover the cursor line and postion.
    It put that in two PUBLIC short integers variables. That's all.

    DECLARE SUB PK50420() '                         REMCURS:
    Here is all this tiny SUB does!

    SUB PK50420() PUBLIC '                          REMCURS:
    ' Globals are CURL%, CURS%
    50420    CURL% = CSRLIN
             CURS% = POS(0)
    50421    END SUB
    And in the five programs above, over 60 different uses similar to the
    below are used from whence the logged errors above arose:

          CALL PK50420() '                          REMCURS:
          GXD% = CURL%'                             Recall line
          GYD% = CURS%'                             Recall column
    7590 ' PB err spacer with hard line number for trace support.

    That NUMERIC line number 7590 in the example above is there for a VERY
    good reason. When you hit an error trap, like the NUMERIC line number
    50421 trap above, go on below it with no further NUMERIC line lable,
    you still show the 50421 error line from the SUB, even though the error may
    be at a line WAY below the reported 50421. Not here. In no case here is
    there ever anything other than a simple integer equate for more than a
    few lines below, followed by yet another hard NUMERIC line number which
    should trip the PB error mechanism pointer to it, not the one shown.
    If the error trap routine is operating correctly, the trap above has to
    be following the SUB and before the next hard NUMERIC line lable.

    And in every case of the reported errors for the problem above there is FIRM
    ability to know from all the source, that the error 70 or 5 is restricted
    only to code just after that SUB - for simple integer equates. In every
    case, unless there is a compiler error that blows this up, the cursor has
    to be somewhere legitimate on the screen for the request made to even
    return error free from the SUB! And if that were the case, we would get
    the error 50420 line, not the 50421 line.

    So how in whatever can you have any simple integer equate produce this?
    How do we get any totally irregular incidence for an ERROR 5 illegal
    function call out of this game, let alone an ERROR 70 for failure to be
    able to write to a protected disk for just the above integer equates?
    That unless this is memory corruption issues?

    An associate of mine who is a lot more informed than I suggests the
    following. To help prove memory corruption, right at the first of the
    programs, declare a unique new PUBLIC integer variable. Very early on
    in the program set it to a specific value. Never look at it again in
    the program, except to print it out in my error log error line report!
    If the value printed on the error line is different than the initialized
    value, we have 'proof' memory is corrupt. Then we also have a beginning
    point that might help find exactly where the application is failing.


    Mike Luther
    [email protected]
    Mike Luther
    [email protected]

  • #2
    Disclaimer: I haven't really worked with PB/DOS for about four years, so I am going from memory on this.

    I'm not sure what the question is, Mike.

    I experienced 'inconsistent errors and error handling' like this; they have been caused by:

    1. Untrapped errors at some prior point in the program, and usually involved using LOCAL error handling and not turning 'ON ERROR GOTO' on and off correctly.
    2. Insufficient stack space. This can be a real dog to track down, because once the stack is corrupt, everything goes straight to hell, because any error-handler code is perforce itself 'lost in space.'
    3. Programs which, when compiled, have one or more segments "close to" the 64K segment limit. The compiler generates a compile-time error if you go 'over', but if you are 'close' it has resulted in flaky code (e.g., even a simple assignment statement failed without triggering an error).

    The fact that you sometimes get an error, and sometimes don't leads me to think the errors are data-dependent.. that is, there is likely an untrapped numeric overflow and/or illegal function call caused by a missed edit (e.g., using some string functions on null strings can cause this) somewhere.

    This untrapped error theory is further bolstered by the "impossible" return of error code #70.. unless of course, this error was set elsewhere in your program and was left untested at that time.. and what you get now is simply the vestigial effects of not handling the error at that time.

    Michael Mattias
    Tal Systems (retired)
    Port Washington WI USA
    [email protected]


    • #3
      Thanks Michael for your very thoughtful right on the mark comments. I've
      added the following concept to my code for study to as best as possible
      rule out memory corruption in seemingly meaningless and highly irregular
      PB ERR 5 traps. Just after all the other DIM and initialization I've added:

        PUBLIC CCK% '       Create global memchk variable
        CCK% = 443 '        Set memory check to 443

      I also added as a last print item in the disk recording of any unresolved
      error handling data that CCK%. CCK% is never touched again except to first
      file print it and thence on screen. If 443 is displayed at least some
      proof of global memory integrity is there.

        WRITE #FL%(8), "INVENT.EXE Log # ", K$(56), " err# ", ERR, " line", ERL, DATE$, TIME$, CCK%

      Well, I got to see a perfect 443 print for another irregular PB ERR 5
      totally puzzling program collapse yesterday at a client site. I have
      no explanation for the following PB ERR 5 which has happened perhaps 20
      times over the last 50,000 sales invoices from this program at this site.

      A single precision and integer array are defined and dimensioned at program
      start and there is no redimension for:

        DIM QL#(2, 40)
        DIM LP%(40)

      I don't prefer GOTO statements with line numbers over block IF/THEN code.
      But over years of trying to trace these strange PB ERR 5 rare collapses
      with hard target numeric line lables, it is possible to narrow a part of
      code involved in these error traps which are difficult without GOTO and
      numeric line lable code construction. Here's another example of these
      queer PB ERR 5 code failure points narrowed down from a far broader block
      of non-GOTO constructs covering years of use to the following code.

      In the current code sample, the variable array QTX#(NJ%) is accessed and
      filled from code used with absolutely no errors ever seen in years of use.
      Yet we take a strange irregular PB 3.5 ERR = 5 at ERL 13995 hits for the
      following uses of it in this one executable. As you think about this, note
      that in no case in this site's use is QTX#(NJ%) ever anything but a value
      of ZERO. In the entire portfolio of recorded errors for years here in this
      executable over the years at this site, their entire result of QTXP# will
      always evaluated to ZERO value. Thus QTXP# will always also be ZERO. At
      the time of this job at this site at the end of a sale, QL#() array items
      have not been used since setting them to ZERO at the start of an invoice:

       13995 QTXP# = 0 '               Spcl tax total
               FOR NJ% = 4 TO 16 '     Examine all special tax types
                 QL#(2, LP%(NJ%)) = QL#(2, LP%(NJ%)) + QTX#(NJ% - 3)
                 QTXP# = QTXP# + QTX#(NJ% - 3)
               NEXT NJ%
               IF QTXP# = 0 THEN '     No special taxes exist
                 GOTO 14045
               END IF
             QL#(2, LP%(18)) = QL#(2, LP%(18)) - QTXP# ' Spcl tax not current earninins
             QPL# = QPL# - QTXP# '     Nor is it in profit and loss ledger
       14045   IF QIN# = 0 THEN '      We bought nor sold nothing
                 GOTO 14065
               END IF
             QL#(1, AP%(9)) = QL#(1, AP%(9)) + (QIN#) '  Sell FGI out of inventory
       14065   IF O8% = 3 THEN
                 GOTO 14090
               END IF
             QPL# = QTL# - STX# + QIN# + QHP# ' Profit includes no sales tax or FGI
             GOTO 14095 '                       Continue
       14090 QPL# = QTL# + QIN# - QHP# '        Profit reduced by inventory bought
       14095   IF O8% = 3 THEN  ......

      Over the the last couple years, by changing the code to GOTO and numeric
      line lable construction I've narrowed the line 13995 failure down to the
      code above line number 14045 by changing the code from block form to the
      GOTO style above. As I see this, if any QTX#() element was in trouble
      prior to the above code, the PB ERR 5 trap would be then, not here. As
      far as I can tell, I've thus 'forced' this 'error' to above line 14045.
      And from the PB error handling references as I read it, there is NOTHING
      in the above code at execution time which can result in PB ERR 5.

      The above program is 25071 source lines long, a 480957 byte executeable
      that cannot be run elsewhere, as virtually all of them cannot be, in this
      site-wide 114 program suite of now over 1,300,000 lines of PB 3.5 source.
      There is no feasible way to submit sample code beyond the above in any way
      that I can see to further debug this. What is submitted should be at
      least evidence something beyond the 'normal' ERR 5 issues are at work here.

      What more can I do? This, the second example of what I see here that
      I cannot trace, is just another of similar unexplained traps that haunt
      me. Now that the CCK% 443 value shows, that at least might help defend
      memory integrity. I'll add free memory and free stack trace attempts
      here also. But can you get accurate FRE() data once an error like this
      has hit?


      Mike Luther
      [email protected]
      Mike Luther
      [email protected]


      • #4
        Thing one I'd do:

        Recompile all modules, recording segment sizes. If anthing in like the 55K+ range, add segment break.

        Thing two I'd do:

        Put 'complete rewrite' on the development calendar. I know you have been working with this application for eight or ten years, and if you have had anything resembling 'normal' maintenance over that period of time, this code is likely rife with syntax and control flags and shared veriables you'd never use were you writing it new.

        I am a commmitted believer that software source code has a finite useful life, and there does come a time when you simply must start over.


        Michael Mattias
        Tal Systems (retired)
        Port Washington WI USA
        [email protected]


        • #5
          Thanks again Michael for your time and thoughts..

          Thing one I'd do:

          Recompile all modules, recording segment sizes. If anthing in like
          the 55K+ range, add segment break.
          Already done in a planned sort of way. The modules, libraries ..
          are kept in a hierarchy such that if a change has to be made in the
          lowest level, that trips my work to recompile EVERYTHING which
          depends on that module. Thus, the segment size will be the same
          for any given library, in the final compiled product for any
          executable and I know the size of all the lower level code units
          as firm until it changes.

          With that in mind, as the whole suite presently works out, the
          largest single segment in it happens to be, of all things, the
          very lowest level core PBU, which is and has been for at least
          two years now .. 58K.

          Duhh .. wince ..

          You know, with all you and I both have gone through with this
          issue of 'errors' in big whatever's, it didn't hit me until you
          posted this. I'm going through and breaking up all the MAIN code
          I'm working with at top level when it gets up in the 50K range.
          But here I am with a core level PBU at 58K and this hasn't even
          tripped my attention. It's worked for so long and so many years
          and .. hmmmmmmmm..

          Brings a question. I actually have this .PBU already set up
          as a $SEGMENT in a library component which is already declared:

           ' ---
           $CODE SEG "PACKFILE"
           $STRING 8
          It clocks in at 58K. I don't see how I can add another $SEGMENT
          in the middle of it to break it up into smaller than 58K. Of
          course, years ago when I first thought all this out, and the docs
          for PB 3.5 tell us that 64K is segment max size, with no other
          experience upon which to draw upon, I never thought about your
          advised upper max size boundary.

          Which brings us to:

          Put 'complete rewrite' on the development calendar. I know you
          have been working with this application for eight or ten years,
          and if you have had anything resembling 'normal' maintenance
          over that period of time, this code is likely rife with syntax
          and control flags and shared veriables you'd never use were you
          writing it new.
          Actually, it's gone through a fairly large number of 'complete
          rewrites' over the years. Curiously, the syntax, control flags,
          and shared variables that are in there haven't been condensed much
          at all over these re-writes. That's either the result of my
          inability to see better at how to do things over the years, or ..
          my ability to see what was needed 20 years ago and hasn't changed
          since BASIC as a tool hasn't changed into a more condensed way of
          doing things for these years either.

          What has happened as the 'complete rewrites' have gone forward is
          actually where new techniques and ways of handling data have sprung
          forward have ADDED new modules to the old ones. A good example of
          that in my suite was caused, for example, when PB's mouse routines
          were added to my suite which was non-mouse enabled as first coded
          back in 1974. A second total rewrite went forward when network use
          of Btrieve file support was added to the original M/S PD7, thence
          PB shared file support.

          But that was all, as the other, is coded in modules which are write
          once use many times oriented, totally, throughout the suite.

          And to which a single master file of common named and declared
          variables has always been included in all work, just to keep the
          programs focused only on exactly same-use-definition such things.
          As to syntax changes; sure! A complete re-write followed the
          decision to *NEVER* again use a single line IF/THEN construction
          as opposed to a multiple line IF/THEN - inside do this - END IF
          way of sourcing things.

          But the core goal for what to do with the project has never changed
          over all the two decades of wishing. As I see it, all professional
          site management is exactly the same!

          For example, it doesn't make a bit of difference if the party at
          the front desk takes cash from a family that is severely handicapped
          and can pay only $20 a month on a $500 account bill. Instead of
          handing the non-English speaking payor an English printed receipt
          for the $20 bill, a $10 receipt is given, $10 is paid on the account
          due and $10 is pocketed by the window clerk! The debtor goes on
          for weeks and so on .. homeless .. no place to store the receipts
          and a year later they still seemingly 'owe' hundreds on their medical
          bill which really has been paid. But it has vanished into wherever
          and no record of who took it is there?

          No .. he paid with a $10 bill!

          Or the $20 actually was recorded into the account payments, but $10
          was written off and that same $10 amount was pocketed elsewhere? Or
          a charge for $200 for whatever was made for supplies, and paid by
          the client, client's representative, though the inventory of supplies
          was never decremented and is over what should be there, but where?
          Or used where else?

          What difference does it make if this is medicine, a divorce issue
          at law with a lawyer's client (fat chance?), or even massage parlor
          big time house?

          Or the brief, that in theory, was put on the mute and partially
          paralyzed resident in a nursing home, but wasn't, was stuffed in
          the aide's clothes and used away from the home - in another 'home'?
          While the sponsor was paying for the service and thinking all the
          time their loved one was cleaned up?

          Makes no difference if the profession is medicine, law, police work,
          engineering; whatever. The process of applying resources to solving
          a problem is really the same. It is only the definition of the
          resources and bookeeping and control of the application of these
          things which change from one profession to another. I'm driven to
          working toward an easily defined and near real-time management template
          to bring this toward affordable reality.

          And in that respect, while 'mice' may appear and infest the operation
          of the template so one can point at something and control this or
          that; the core issues of management and control really don't change
          much as I see it. Haven't for thousands of years. Won't for thousands
          of years more if mankind is a little lucky.

          We just need a little BASIC help from the right stars in our horizon
          like PB and Bob Zale .. on the right platforms where our ships land ]
          and take off .. to give humanity a chance Michael.

          Plus people like you who are willing to help like you are doing here.

          Thanks friend for your suggestions.

          And for what is is worth, simply adding two more numeric line numbers
          in this program which we are discussing, has stopped the 'error',
          and even .. grin .. stopped the failure to apply the change due printed
          as such in some invoices .. from also being subtracted from the cash
          ledger and print run from a few strange out-of-balance invoice runs!

          Plus so far stopped the unexplained ERR 5 traps?

          Mike Luther
          [email protected]
          Mike Luther
          [email protected]


          • #6
            I use to have my share of grief with PB/DOS when some little
            piece of code would work in the IDE, but would generate an error
            during the execution of the compile process. I never could nail
            it down, so I never reported it. I did learn three things in my
            efforts to track it down and attempt to correct it that seemed
            to help a lot.

            (1) Avoid imbedding multiple IF ... END IF statements inside of
            each other. After you put about three levels of IF statements
            inside, in a large complicated structure, yos might find that
            the IF/END IF branching goes screwy down somewhere deep in the
            sequence. If I replaced some of the IF ... ELSEIF ... END IF
            structures with SELECT CASE statements, the problem disappeared.

            (2) If a particular sequence of instructions keep erroring
            out, but compile and work right in the IDE, put a few
            inconsequential statements at the point where the problem
            occurs so that the offending code is moved down a few lines.
            It does not help to insert blank or REM statements, these have
            to be executable statements. I'm always using a variable called
            "a" in my code, so all I do is a three or four lines of a = a,
            and the problem will magically go away.

            (3) Don't push the limits on the 64K boundary. Limit your
            program segments to 30k to 40k by adding more $SEGMENT statements.

            (4) The big change was to abandon the effort to create one
            error handler routine that tries to handle any error. I just
            do a global called BadErr%, and if I am about to do something
            likely to result in an error, I execute this code:

            Baderr = 0
            ON ERROR GOTO bad
            [execute the I/O or other statement that might cause an error]
            ON ERROR GOTO 0
            IF BadErr THEN    'here I caught an error, which I know must
                              'relate specifically to the previous
                              'suspect statement, narrowing the possible
                              'range of errors likely reported
            END IF
            The counterpart code for Bad is this:
            BadErr = Err
            IF BadErr = 0 THEN BadErr = -1
            RESUME NEXT
            That's it. I now can process the error as a local event,
            even inside a SUB or FUNCTION, and even though Bad: is located in
            the main program area. The only time that Err is likely to
            return a zero is if you are single-stepping through the code,
            so I force BadErr to -1 to signal that the original error code
            was lost, but an error trap did occur. You can also get the
            error line number, but what for? Since it is related to the
            offending statement, and is being handled as a local event,
            you can already determine what the likely cause was and you
            know where it happened. Sometimes I don't even bother to check
            the BadErr value, particularly with I/O, because if I can read
            a file, the probable reason is that it doesn't exist, or is
            already being used by another process.

            Old Navy Chief, Systems Engineer, Systems Analyst, now semi-retired


            • #7
              After you put about three levels of IF statements inside, in a large complicated structure...the IF/END IF branching goes screwy down somewhere deep in the sequence. If I replaced some of the IF ... ELSEIF ... END IF structures with SELECT CASE statements, the problem disappeared.
              I had forgotten that, Donald, but now that you mention it, I had some weird things happen in this area... not so much with 'total' loop nesting depth, but specifically with ELSEIF when it's down a couple of levels, e.g., DO... SELECT CASE... IF... IF ... ELSEIF..

              That's definitely worth a look, Mike.
              Michael Mattias
              Tal Systems (retired)
              Port Washington WI USA
              [email protected]


              • #8
                Thanks *VERY* much for your post Don.. and also Michael for the
                confirmation of seeing what Don notes.

                The comments on nested IF .. ELSEIF techniques actually focused
                what I've also noted. But I never related it to the nesting as
                to the focal point. Donald, this is the first time I've heard
                about plowing around the error by:

                If I replaced some of the IF ... ELSEIF ... END IF
                structures with SELECT CASE statements, the problem disappeared.
                Yes, I've seen this over and over again for many years here. What
                I'll see is that the compiled code seems to hop over a line which
                ought to be the target for the next point of execution following
                the END IF, or in rare cases, more than one line. What is in that
                'hopped over' line simply doesn't execute as I see this effect.

                My most vivid memory of this behavior actually extends far prior
                to Bob Zale and PB 3.5. It was also present in the M/S PD7 BASIC
                compiler too, folks. I had been called and flown from Texas to
                Woodward, Oklahoma to trace an error that just couldn't be in this
                exact same behavior in PD7! And when I discovered the hop-over
                fluke .. at that same moment, I was paged and put on notice my Dad
                was going through death. Had to fly back to Texas with another line
                number added just as you see here, in 1989, that 'solved' the prohlem
                there too. No code is perfect. Neither is life. And this is NOT
                a complaint of PB, Bob Zale at all. I would have far less to ever
                contemplate in life had I not made the decision to rely on PB.

                Now I've never tried the use of SELECT CASE to plow around this.
                In every case where I've finally been able to pin this down, what
                I've done is to simply add a numeric line lable at the first line
                below the END IF where this seems to arise. It has solved the issue
                here for me. However, I'll look to see if I can implement the SELECT
                CASE style of coding that you've pointed toward, Don.

                I've just checked this INVENT.EXE source at least to the MAIN module.
                The worst nesting for IF THEN type constructs in it is to the
                third level in one place in one pretty long block of such a primary
                IF THEN which focuses a major program complex action based on what
                letter the user punched in for a menu exit option choice. I convert
                the letter punched to an integer value, then use IF THEN block coding
                to totally contain the response work for that choice.

                So said, I notice that, for whatever reason, there are a number of
                otherwise not needed already existing numeric line lables in this
                block! Without checking the development log, which I do keep for
                each item, my bet is that this has already 'fixed' issues here. Let's
                add a concept question short list here for thoughts about code
                style, OK? It might be relevant to minimizing the effects of
                this behavior as seen by others.

                1.) I could change the exit selection choice, en grande, to
                a SELECT CASE style coding.

                2.) My code style, however, uses a global 'technique', that
                in many cases, if execution of what is inside the IF THEN
                block produces a non-valid data response, or the user
                seeks HELP from a point in it, that the operation which
                is being done is properly started over 'above' the
                point internal to the IF THEN block.

                Here is sample code that illustrates this:

                5565          INSH% = 1 '                       Set internal search flag
                              CALL PK50510() '                  C25HLD:
                              CALL PK50661() '                  BRTWHTBLK:
                              HBEG$ = "\invecplx\"
                              PRINT "     Use complex search pattern routine? <Esc> <Y or N>:
                              GOSUB 24745'                      Input a byte
                              IF Z6% = 27 THEN '                Escape
                                 GOSUB 6070 '                   Reverse slush stuff
                                 GOTO 6040 '                    Close everything try again
                              END IF
                              IF Z7% = 59 THEN '                Help needed
                                 CURL% = GXD% '                 Restore this line
                                 CURS% = GYD '                  Restore this column
                                 CALL PK50430() '               RETCURS:
                                 GOTO 5565'                     Try again
                              END IF
                Notice that GOSUB to input a byte? Why would anyone want to use
                such a thing just to input a byte? Well, the only way to stop PB
                from totally running away with the CPU in multi-tasking environments
                that I have found is to bury the INKEY$ routine in time sharing
                release code. Hence, as earlier noted, one of the lowest level
                core .PBU routines in the 50000 series reserved line number routines
                in the whole code suite here, that GOSUB 24745 is actually:

                24745 ' Input a byte
                      BRT% = 1 '                                Set to bright input
                      CALL PK50300() '                          INPBYTE:
                      CALL PK50661() '                          BRTWHTBLK:
                I simply can't afford three lines of code for every time a single byte
                is required in input, chuckle. Not when that PK50300 sub is actually
                FIVE HUNDRED THREE lines of code in the suite which actually really
                NEEDS the following THIRTY-TWO global variables just to function properly
                in our world:

                SUB PK50300() PUBLIC '                          INPBYTE:
                   ' Globals are BRT%, KZ%(), CURL%, CURS%, Z1%, ZZ0%,
                   ' Z7%, GFX%, LNPT$, PRPT%, Z0$, Z2%, Z6%, VBOF&
                   ' Row%, Column%, Button%, Status%, UseMouse%, Rows%, Cols%
                   ' MouseButton%, MouseX%, MouseY%, sKey, Clix%
                   ' OldRow%, OldColumn%, pbvScrnMode, SMSE!, MMSE%, YMSE%
                   MsCursorOn '                           Turn on mouse cursor
                   ZZ0% = 0'                              Null output choice flag
                   Z6% = 0 '                              Null escape flag
                   Z7% = 0'                               Null output function key choic
                   VCNT& = 0'                             Null timer second counter
                   DMYP$ = RIGHT$(TIME$, 2)'              Remember seconds of time
                   CALL PK50420() '                       REMCUR:
                Yes, every single just one byte input has to really involve all
                that and now you can see why when Bob's wonderful mouse code was
                put into the suite, the whole suite really had to be re-written as
                you folks do properly advocate.

                Plus which with all the lower level LOCAL error trapping code, plus
                what LANCE finally taught me in the use of EXIT FAR really does work
                to help trace these errors.

                Now, Don .. Michael .. whomever. If I go to the SELECT CASE way
                of doing these things, where do I place the LINE NUMBER LABLE to
                which we should return UP PROGRAM, from errors, or help choices?

                More important. You still have to go back and start all over at
                a much earlier lable in the programs for major reversal choices.
                What happens when IF THEN and END IF type construction is replaced
                with SELECT CASE here? Does it stop this fluke there too?

                And thanks for the confirmation, Donald, that you've also had to
                resort to this one:

                (2) If a particular sequence of instructions keep erroring
                out, but compile and work right in the IDE, put a few
                inconsequential statements at the point where the problem
                occurs so that the offending code is moved down a few lines.
                It does not help to insert blank or REM statements, these have
                to be executable statements. I'm always using a variable called
                "a" in my code, so all I do is a three or four lines of a = a,
                and the problem will magically go away.
                I have had to do this all the time for years now all through my
                code work. I use the line 'GGG% = 1' for this same use. However
                in this particular executable only ONE such use has been needed:

                17830 ' Inv hdr      Only if disk file open
                      BJH% = 1 '     Set to print the date on print
                      CALL PK50121(NHDR%, HDR$(), XP$, LG%, C$(), TM$, DR$(), EX$, PVT$, PU$,
                17844 GGG% = 1
                17845 RETURN
                Another tip you may want to add to your notes at least from what
                has been needed here for years too in this issue is to never use
                the CALL operation tied adjacent to a hard numeric line lable in
                these very complex, very large and memory hungry programs. Pad
                the source with a remark at the lable and simply place the needed
                CALL operation just under it:

                3595  ' PB error kludge
                      CALL IN36771(MEDL%, MEPR%) '              TRAPMED:
                Just trying to contribute back to those who are so thoughtfully
                trying to help me here.

                And lastly, Donald, I already also use a similar technique to your

                (4) The big change was to abandon the effort to create one
                error handler routine that tries to handle any error. I just
                do a global called BadErr%, and if I am about to do something
                likely to result in an error, I execute this code:
                Evem more specific, to bracket where an error actually is happening,
                I seed the source with integer step trace settings! To trace
                these curious hop over line execution issues, what I do is to
                set an integer value to the line lable number as in:

                13845  BTRV% = 13845
                Virtually all of my code is far to large to ever run in the IDE,
                which also still has major line display disparity between where
                it shows you the code is running and where it actually is running.
                Yes, I can bust this by adding those seemingly not needed numeric
                line lables in the IF THEN sections of the code and so on. But
                there are places even with LOCAL and EXIT FAR that defy analysis
                for me. By initializing the above sort of trace integer and looking
                at that with cheese debugging techniques even when I can't do this
                in the PBD game for size and so on, I HAVE been able to plow around
                some more of these issues.

                Thank you all for your time and thoughts.

                Mike Luther
                [email protected]
                Mike Luther
                [email protected]


                • #9
                  Not when that PK50300 sub is actually FIVE HUNDRED THREE lines of code in the suite which actually really NEEDS the following THIRTY-TWO global variables just to function properly in our world:
                  Thirty-Two (32) GLOBAL (SHARED) variables? For only 500 lines of source code?

                  Then I think you should move this proc to UNIT (PBU) or CHAIN module (*.PBC) all by itself. If this is the "all mouse access" unit, it should not need to share any variables with "main" at all.

                  The use of more separately-compiled modules might simplify this error tracking dramatically.

                  [This message has been edited by Michael Mattias (edited May 16, 2005).]
                  Michael Mattias
                  Tal Systems (retired)
                  Port Washington WI USA
                  [email protected]


                  • #10
                    Well Michael ..

                    Yes, the mouse, and timing and what it returns really does get
                    shared by LOTS of other things in this suite, especially in
                    relation to what it and that low level I/O can be allowed to do
                    in relation to real-time totally integrated telecommunications
                    operations that also are embedded everywhere as needed as well!

                    When you really start working in near-real time with other hardware
                    operations and port I/O in the middle of everything else all this
                    does, indeed need global consideration. PB only allows us how many
                    SEGMENTS per program and how many variables we can pass to a given
                    SUB or function?

                    I suspect that most folks have no idea how global resources must be
                    when you contemplate a full near-real-time facility-wide control
                    template. It's taken me over 40,000 hours to even get this far at
                    packaging the concept. And it works!

                    The usual concept of a major programming effort is to break things
                    down and modularize things so that a particular more or less single
                    process is done as only one step. Hours, days, weeks, or more than
                    a month later someone else comes along and integrates just the
                    I/O from that and other processes into another 'module'. And on
                    and on. But by the time that string of modular processes is over,
                    the horse is already out of the barn. You can go broke and never
                    know it!

                    When an entire facility, such as a medical clinic, really winds up
                    with no back office and the whole thing; from the case files, the
                    complete inventory of things, the entire time operations for each
                    and every person who does anything, and the whole accounting and
                    operations communications I/O gets done with each and every minute
                    in near-real time, the concept of modularity is *SURE* still there.

                    But the issue of global items that really do have to share suite-wide
                    awareness is totally beyond what a conventional code architect has
                    normally ever seen or considered.

                    And yes. I sure could have reduced the PUBLIC variable, if .. I
                    had, say 64 variables that could have been passed to SUB's and so
                    on. But when I noted that early on in the decision to move to PB,
                    that was met with a view of, "Why would anyone need that many
                    variables passed to a SUB?" The House is too valuble in the middle
                    of the North 40. So we plow around it, right?


                    And you are darned sure right. This complex kitty *IS* reduced to
                    a whole cadre of separately compiled .PBU's, libraries of them, and
                    what is already some 13 segments for this executable alone from the
                    common suite-wide needs. And you are sure right to postulate that
                    tracking errors in this thing is a REAL excercise in detection work.

                    Do you know of any other professional facility management template
                    which lets you pull a complete income statement, balance sheet,
                    inventory control and count, all the case data, acting agent data,
                    latitude/longitude and position coordination of each event, time and
                    actions logging of the case, transaction posting and document
                    production, fully synchronized across the entire facility LAN,
                    phone line real-time inbound and outbound merged data into the
                    case and actions registries, every digit, every call progress
                    action in real-time sync and logged, with each and every professional
                    action? No, not client-server; server-server if you will.

                    When the hour rolls; it roles. When the day rolls; it rolls.
                    When the month rolls; it rolls. When the year rolls; it rolles.
                    All according to the rules and sure you can correct errors. But
                    you get to explain them all and when; in real-time as well!

                    Even what your mouse returned, as needed, wherever it happened
                    to be in public, with no place to hide under the chair and frighten
                    the Queen - without being known. Ah yes, TIMER and all that stuff
                    concurrently as well as needed? Including time slicing for mice
                    and all that stuff too. Remember, we may be running four or five
                    different PB 3.5 executables in the suite at any given time on the
                    same OS/2 box at any given work station. And it all works so well
                    it is staggering, to most folks. Takes both modularity as well
                    as globularity, chuckle. And you are, as well, exactly on target
                    with what you posted!

                    Yeah, if I had say 64 SEGMENTS maybe I could further break it down.
                    But like 64 variables per SUB, that's not too likely I suspect.
                    And this PB product is so beautiful, such a masterpiece we have,
                    that even a Go Devil is worth it behind a pair of mules. Just to
                    get to see the beauty of the rows ..

                    Mike Luther
                    [email protected]
                    Mike Luther
                    [email protected]