Menu

How to display arrows?

cdg
2019-09-29
2024-11-20
  • cdg

    cdg - 2019-09-29

    With Realia Cobol,

    display X"18" x"19" 
    

    displays the up and down arrows.

    With GNU Cobol, we get ^X and ^Y.

    How can I display the left, right, up and down arrow characters with GNU Cobol?

     
    • Eugenio Di Lorenzo

      You can simply use

      . . .
      01  ArLe         pic x value x'11'.
      01  ArRi         pic x value x'10'.
      01  ArUp         pic x value x'1E'.
      01  ArDo         pic x value x'1F'.
      . . .
      . . .
        *> enable display of ASCII symbols from x"00" to x"1F"
         CALL STATIC "raw_output" USING 1
         . . .
         . . .
            display ArLe at Line ...
            display ArRi at Line ...
            display ArUp at Line ...
            display ArDo at Line ...
            . . .
      

      there is no need of any C wrapper.

      I forgot to add that when compiling you need to have the pdcurses library available (raw_output is a pdcurses function)
      for example use: cobc program.COB -lpdcurses

      Please see also at
      https://sourceforge.net/p/gnucobol/discussion/help/thread/7f9830a113/?limit=50#bf77

       

      Last edit: Eugenio Di Lorenzo 2024-11-20
  • Edward Hart

    Edward Hart - 2019-09-29

    Does changing the command prompt code page work (e.g. chcp 437)?

     
  • cdg

    cdg - 2019-09-29

    The active code page is current 437

     
  • Edward Hart

    Edward Hart - 2019-09-29

    Some googling suggests two different possible solutions:

    1. Using the Qodem terminal emulator, which appears to convert CP437 output to the intended UTF8 equivalent.
    2. Replacing all instances of non-ASCII CP437 characters with their UTF8 equivalent. Maybe also changing the codepage to 65001. Maybe even replacing the DISPLAY's with manual calls to ncurses' add_wch.
     

    Last edit: Edward Hart 2019-10-03
  • cdg

    cdg - 2019-10-02
    1. Why would I want to use a modem emulator to accomplish a simple character display, and how would Qodem accomplish this?
      2. How would you display a UTF8 character with GNU Cobol, when it won't even display the ASCII-7 set? Changing the codepage, if GNU Cobol even noticed, would mess up everything else in 265 WORKING programs. Replacing displays with manual calls to undocumented routines that aren't available without rebuilding, and recompiling everything, is hardly a solution.
     

    Last edit: cdg 2019-10-06
  • David Wall

    David Wall - 2019-10-02

    I've just modded a simple program to display x"18" & x"19" and I get ^X & ^Y.
    But I edited a text file to 18 19 18 19 0D 0A and typed it at a dos command
    and got the up & down arrows as you'd expect - so what's going on.
    I tried compiling the test under 3.0rc1 & still wrong.
    This does sound rather stupid that it can't even display simple hex characters.

    I went back to Cob 2.2 & still wrong - yet dos does it fine. ???

     

    Last edit: David Wall 2019-10-02
  • Edward Hart

    Edward Hart - 2019-10-02

    I think I now have some understanding of what is happening. All curses libraries output control characters into caret notation. So, X"18" is translated to the two ASCII characters ^X. There is nothing that lets us easily undo this conversion. The only "correct" fix is to translate all input to/output from Unicode. GnuCOBOL should do this for you. However, it won't be able to for a long time. I didn't realise how extensively you used CP437 characters; that rules out any conversion of those to Unicode. That leaves one way to go: disabling the conversion to caret notation in the first place.

    In ncurses, a "control character" depends on the locale. So we can fix the output by running Cygwin and doing set LC_ALL=en_US.CP437 (and maybe calling setlocale in the COBOL program as well).

    In PDCurses, a "control character" is not locale-dependent - it always the ASCII control characters. Instead, we have to use the non-standard PDCurses function raw_output to disable the conversion to caret notation.

    To access raw_output, we need a C shim, two lines of new COBOL code and two changes to your cobc.exe commands. NB: I haven't tested the following, but based on the entries of the FAQ, this should work.

    Create raw_enable_output.c:

    #include <pdcurses.h>
    
    int enable_raw_output()
    {
        raw_output (1);
        // GnuCOBOL assumes int return type of C functions
        return 0;
    }
    

    Add to the start of your main COBOL program:

    *> Force initialisation of PDCurses
    DISPLAY LOW-VALUE AT 0101
    *> Prevent caret notation
    CALL "enable_raw_output"
    

    Then, compile like

    REM Compile the C shim with the headers/libraries needed by GnuCOBOL
    cobc.exe -c enable_raw_output.c
    REM Add the dll to your "cobc.exe -x" command:
    cobc.exe -x prog1.cob prog2.cob ... enable_raw_output.dll
    
     
    • Simon Sobisch

      Simon Sobisch - 2019-10-02

      Why not using an UTF8 enabled curses version and convert the box and arrow characters in the source file to utf8-encoding (it is a one click with notepad++)?
      Note: this should work on any system with both ncurses and pdcurses - as long as those are configured to use utf8.

       
      • Edward Hart

        Edward Hart - 2019-10-02

        I didn't think it would be that easy. I was expecting to have to convince curses to accept non-ASCII characters and then have to convince a terminal emulator or cmd.exe to display them properly.

         

        Last edit: Edward Hart 2019-10-03
        • Simon Sobisch

          Simon Sobisch - 2019-10-02

          If you have an utf8 build of pdcurses then it completely ignores any setting of cmd.exe which normally cannot display utf8 (that's even true for Windows 10) and does it well. Any non UTF8 display obviously gets broken on the way. If previously hex constants were used those would have to be converted manually (preferably by copy+paste the unicode variant to the COBOL source which is saved with utf8 encoding).

           
  • cdg

    cdg - 2019-10-02

    The only "correct" fix is to translate all input to/output from Unicode.

    Please explain how this is done

    GnuCOBOL should do this for you. However, it won't be able to for a long time.

    ???

    I didn't realise how extensively you used CP437 characters; that rules out any conversion of those to Unicode.

    I don't extensively use CP437 characters. I use them in a few places. Arnold's GC31 now correctly displays the line-drawing characters, so we are just concerned with the arrow characters. But (as I understand it) Unicode uses two bytes for each character. If I have to convert all my text to Unicode, THAT would be a huge endeavor, affected not only program code but file layouts and contents. But if there is some way of displaying Unicode in a single instance, please inform us.

     
    • Edward Hart

      Edward Hart - 2019-10-02

      The only "correct" fix is to translate all input to/output from Unicode.

      Please explain how this is done

      GnuCOBOL should do this for you. However, it won't be able to for a long time.

      The conversion is not something that would be done in COBOL sources - just in the GnuCOBOL runtime. It would require adding a codeset conversion library (e.g. iconv, libicu), detecting the active codeset (probably by some kind of compiler directive/configuration option), converting all characters sent to DISPLAY to Unicode and outputting them using curses wide-character functions (and vice-versa for ACCEPT). That would take some effort to design and implement (especially after considering portability), so it cannot be done soon.

      But if there is some way of displaying Unicode in a single instance, please inform us.

      I'll try to find one. The ncurses function add_wch looks promising, but I've not got anything working so far.

       
      • Edward Hart

        Edward Hart - 2019-10-02

        It turns out that, with ncurses and LANG set to en_GB.UTF-8, you can just copy-and-paste the Unicode characters into COBOL source and DISPLAY them normally:

        *> Unicode character and its hex
        DISPLAY "↑ " & X"e28691"
        

        Maybe this works on Windows and PDCurses, too?

         
        • Simon Sobisch

          Simon Sobisch - 2019-10-02

          Yes, as long as you use the UTF8 version.

           
  • cdg

    cdg - 2019-10-03

    The person asking the original question (how to display x"18" and x"19" with GNU Cobol) is not a C programmer, nor is he an expert in all the nuances of the GNU Cobol library. So your responses are not helpful.

    "It turns out that, with ncurses and LANG set to en_GB.UTF-8, you can just copy-and-paste the Unicode characters into COBOL source and DISPLAY them normally:

    *> Unicode character and its hex
    DISPLAY "↑ " & X"e28691"

    Maybe this works on Windows and PDCurses, too?"

    Where would I set LANG to "en_GB.UTF-8"? How would I copy and paste Unicode characters when Notepad (and other text editors) respond to the arrows as commands? What effect would the LANG setting have on the rest of the text in my program(s)?

    "Why not using an UTF8 enabled curses version and convert the box and arrow characters in the source file to utf8-encoding (it is a one click with notepad++)?
    Note: this should work on any system with both ncurses and pdcurses - as long as those are configured to use utf8."

    Because I don't have any control over which curses version I use, and I don't have Notepad++. And, if I did have "an UTF enabled curses version", What effect would it have on the rest of the text in my program(s)? I don't want to create a larger problem to solve a minor one.

    "I didn't think it would be that easy."

    So far, it's not easy for me.

    "If you have an utf8 build of pdcurses then it completely ignores any setting of cmd.exe which normally cannot display utf8 (that's even true for Windows 10) and does it well. Any non UTF8 display obviously gets broken on the way. If previously hex constants were used those would have to be converted manually (preferably by copy+paste the unicode variant to the COBOL source which is saved with utf8 encoding)."

    So, to display two hex characters that are part of the default code page, but ignored by curses, I should modify every hex character in every program? How exquisitely simple!

     

    Last edit: cdg 2019-10-06
  • cdg

    cdg - 2019-10-06

    As it turns out, there are two very simple solutions to the problem, one that doesn't work (although it should), and one that does:

    1) addrawch(24) and addrawch(25)should work, and it does work for some characters, but it displays the wrong character for the up and down arrows. (And, yes, my code page is 437).

    2) addch(ACS_UARROW) and addch(ACS_DARROW) display the up and down arrows properly.

    I couldn't get either to work directly from a Cobol program CALL, so I wrote a C "wrapper":

    #include "curses.h"
    int write_up_arrow()
    {
     addch(ACS_UARROW);
     return (0);
    }
    int write_down_arrow()
    {
     addch(ACS_DARROW);
     return (0);
    }
    

    and invoked them from the Cobol program as follows:

       display " " at line 1. *> needed to start pdcurses
       call static "write_up_arrow".
       call static "write_down_arrow".
    

    The Cobol program needs to be compiled with

    cobc -x {cobol-source-program} {c-wrapper-program} **-A /DPDC_DLL_BUILD -lpdcurses**
    
     
    • Simon Sobisch

      Simon Sobisch - 2019-11-07

      addch(ACS_UARROW) and addch(ACS_DARROW) display the up and down arrows properly.
      I couldn't get either to work directly from a Cobol program CALL ...

      That's because addch() may be a macro and ACS_UARROW/ACS_DARROW very likely is. Your c-wrapper is fine although you could change it to alternative formats, too:

      #include "curses.h"
      void write_up_arrow()   { addch(ACS_UARROW); }
      void write_down_arrow() { addch(ACS_DARROW); }
      

      with

         call static "write_up_arrow"   returning nothing.
         call static "write_down_arrow" returning nothing.
      

      or

      #include "curses.h"
      void display_arrow(char given_opt)
      {
       char opt = (char)toupper(given_opt);
       if (opt == 'U') addch(ACS_UARROW);
       else if (opt == 'D') addch(ACS_DARROW);
       else if (opt == 'L') addch(ACS_LARROW);
       else if (opt == 'R') addch(ACS_RARROW);
      }
      

      with

         call static "display_arrow" using by content "U" returning nothing.
         call static "display_arrow" using by content "D" returning nothing.
      

      You may even use something similar to print every special character. In this case you'd likely define a copybook that includes "internal magic characters" for the complete extended characters [see attachment] like

      78 upper-left-corner pic x value "1".
      78 lower-left-corner pic x value "2".
      

      and a portable C program to compile and use those

      #if defined (HAVE_NCURSES_H)
      #include "ncurses.h"
      #elif defined (HAVE_PDCURSES_H)
      #include "pdcurses.h"
      #else
      #include "curses.h"
      #endif
      void display_special(char opt)
      {
       // 
       if      (opt == '1') addch(ACS_ULCORNER);
       else if (opt == '2') addch(ACS_LLCORNER);
      // duplicate the magic characters from the copybook here
      }
      

      used by

         copy "DISPVALUES".
       ...
         call static "display_special" using by content upper-left-corner returning nothing.
      

      To not need to take care of the special "non-cobol linking" each time and to be more portable I'd create a minimal wrapper program "SPECIALDISP" that just takes a PIC X (by reference) and calls the C programm. This way you can compile a single module:

      cobc -b SPECIALDISP.COB wrap.c -DHAVE_PDCURSES_H -A "/DPDC_DLL_BUILD" -lpdcurses

      and then call this COBOL program from everywhere without any special linking:

         copy "DISPVALUES".
       ...
         call "SPECIALDISP" using upper-left-corner.
      

      Additional benefit: if you ever want to adjust the table of characters or change to a different curses library (version) or even to a different technology you only have to adjust/recompile/relink a single program.

       
      • Mário Matos

        Mário Matos - 2019-11-07

        And for the special case of 'Bill Gray's PDCurses", depending on how it was built, two more macros are in order:

        CHTYPE size (mandatory for 32-bit compatibility reasons):
        32-bit 'chtype's - /DCHTYPE_32
        64-bit 'chtype's - NONE (the default)

        WIDE version (which is needed to fully integrate PDCurses with Windows):
        /DPDC_WIDE (allows ACS and WACS; see 'curses.h' for details)

        cobc -b SPECIALDISP.COB wrap.c -DHAVE_PDCURSES_H -A "/DPDC_DLL_BUILD" -lpdcurses

        will become:

        cobc -b SPECIALDISP.COB wrap.c -DHAVE_PDCURSES_H -A /DPDC_DLL_BUILD -A /DCHTYPE_32 -A /DPDC_WIDE" -lpdcurses (assuming 'pdcurses' has been built with those macros as well, not to forget 'GnuCOBOL' as well for 'screenio.c'). If PDC_WIDE is not provided, some characters may not display properly, or none at all, depending on the font used by the console.

        Once more:

        Bill Gray's PDCurses does not need UTF8=Y at all (at least on Windows).

        From 'ncurses' perspective , the characters from your 'png' table work pretty well with 'ncursesw' in a Cygwin console (although very limited).

        Cheers,
        MM

         

        Last edit: Mário Matos 2019-11-07

Anonymous
Anonymous

Add attachments
Cancel





Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.