Author Topic: beginner questions  (Read 50844 times)

Offline jackjps

  • Jr. Member
  • *
  • Posts: 60
Re: beginner questions
« Reply #45 on: February 26, 2016, 08:03:28 PM »
Code: [Select]
Hi Bryant,
Haven't read your last post yet but will.
I wanted you to see this stripped down version of your
program that just tries to put a blue screen on the monitor,
not the terminal. It puts a blue screen on the monitor filling
the same size as the terminal (1/4 of the screen)
I downloaded "xterm" and it did the same thing as the regular
terminal in Nasm. My problem is that I can't expect a user to
change to a console mode. I will try your suggestion and read
the 3 sites you gave me. Thanks.

;   2-26-2016 using NASM 64
;   Order of colors: BGR
;
; This is a stripped down version of your program.
; Trying to fill the screen of whatever monitor is
; in place in light blue.

; Dependencies:
;  libc-dev          - GNU C library.
;  libncurses-dev    - Developer's libraries for ncurses.

; Build Process:
;  nasm -f elf64 demo64.asm -o demo64.o
;  gcc -o demo64 demo64.o -lcurses

; Run Process:
;   ./demo64

   bits 64
   cpu IA64

   global main

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Functions from the Standard C Library
   extern signal
   extern atoi
   extern exit

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Functions from the NCurses Library
   extern initscr
   extern keypad
   extern nonl
   extern cbreak
   extern echo
   extern has_colors
   extern start_color
   extern init_pair
   extern newwin
   extern endwin
   extern refresh
   extern wrefresh
   extern wgetnstr
   extern wbkgd

   extern LINES
   extern COLS

   %define SIGINT 2  ; defined in signal.h
   %define TRUE   1  ; defined in curses.h
   %define FALSE  0  ; defined in curses.h

   %define COLOR_BLACK     0
   %define COLOR_RED       1
   %define COLOR_GREEN     2
   %define COLOR_YELLOW    3
   %define COLOR_BLUE      4
   %define COLOR_MAGENTA   5
   %define COLOR_CYAN      6
   %define COLOR_WHITE     7
   %define COLOR_PAIR(n) ((n) << (8))

   %define BLACK_ON_BLUE   1
   %define BLACK_ON_YELLOW 2

   %define BLACK_ON_BLUE   1
   %define BLACK_ON_YELLOW 2

   %define STACK_ALIGN sub rsp, 8
   %define STACK_RESTORE add rsp, 8

section .data

hWindow:       dq 0
hChildWindow:  dq 0
szUserInput:   db 0, 0, 0, 0, 0

; test code begin
  msg db      "got past clear_blue  "
; test code end

section .text
;;  do_init : nothing -> boolean .
;;  preform all of the applications initialization.
;;  when initialization was successful, hWindow will
;;  contain the curses screen handle and the return
;;  value will be TRUE. otherwise, it returns FALSE.

do_init:
   STACK_ALIGN

;;  setup an interrupt to terminate
   mov rsi,do_exit
   mov rdi,SIGINT
   call signal

;;  initialize the curses library
   call initscr

;;  was curses initialization successful?
   cmp rax,0
   jne .CursesInitSuccessful

;;  initialization failed, return FALSE
   mov rax,FALSE
   ret

.CursesInitSuccessful:
;;  save a copy of curses root window
   mov [hWindow],rax

;;  does this system support color terminals?
   call has_colors
   cmp rax,0
   jne .HasColorSupport

;;  No color support, return FALSE
   STACK_RESTORE
   mov rax,FALSE
   ret

.HasColorSupport:
   call start_color

;;  create our color pairs
;;  black foreground, blue background
   mov rdx,COLOR_BLUE
   mov rsi,COLOR_BLACK
   mov rdi,BLACK_ON_BLUE
   call init_pair

;;  if we reach this point, we have initialized successfully.
   STACK_RESTORE
   mov rax,TRUE
   ret

;;  do_exit : integer -> nothing .
;;  exit to the operating system.
do_exit:
   STACK_ALIGN

;;  refresh our screen
   call refresh

;;  shut down curses
   call endwin

;;  return to operating system
   push qword 0
   call exit
   add rsp,4

;;  we should never reach this point
   STACK_RESTORE
   ret

;;  clear_blue : nothing -> nothing .
;;  create a full screen of a light blue color.
clear_blue:
   STACK_ALIGN

;;  make our background blue
   mov rsi,COLOR_PAIR(BLACK_ON_BLUE)
   mov rdi,[hWindow]
   call wbkgd

   ;; refresh our screen
   mov rdi, [hWindow]
   call wrefresh
   STACK_RESTORE
   ret

;;   main : integer (string . string) -> integer .
;;   our program starts here.
main:
   STACK_ALIGN
   call do_init
   cmp rax,TRUE
   jne .done

;;  clear the screen to blue
   call clear_blue

; test code begin
    mov     rax,1   ; sys-write
    mov     rdi,1   ; standard output
    mov     rsi,msg
    mov     rdx,21  ; message length
    syscall         ; write message to screen
    mov     rax,60  ; sys_exit
    mov     rdi,0   ; error code
    syscall         ; exit
; test code end

.done:
   STACK_RESTORE
   xor rdi,rdi
   call do_exit
   ret
 
« Last Edit: February 26, 2016, 08:35:35 PM by jackjps »

Offline Bryant Keller

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 360
  • Country: us
    • About Bryant Keller
Re: beginner questions
« Reply #46 on: February 26, 2016, 08:29:12 PM »
Hi Bryant,
Haven't read your last post yet but will.
I wanted you to see this stripped down version of your
program that just tries to put a blue screen on the monitor,
not the terminal
It puts a blue screen on the monitor filling the same size as the
terminal (1/4 of the screen)
Code: [Select]
;   2-26-2016 using NASM 64
;   Order of colors: BGR
;
; This is a stripped down version of your program.
; Trying to fill the screen of whatever monitor is
; in place in light blue.

; Dependencies:
;  libc-dev          - GNU C library.
;  libncurses-dev    - Developer's libraries for ncurses.

; Build Process:
;  nasm -f elf64 demo64.asm -o demo64.o
;  gcc -o demo64 demo64.o -lcurses

; Run Process:
;   ./demo64

   bits 64
   cpu IA64

   global main

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Functions from the Standard C Library
   extern signal
   extern atoi
   extern exit

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Functions from the NCurses Library
   extern initscr
   extern keypad
   extern nonl
   extern cbreak
   extern echo
   extern has_colors
   extern start_color
   extern init_pair
   extern newwin
   extern endwin
   extern refresh
   extern wrefresh
   extern wgetnstr
   extern wbkgd

   extern LINES
   extern COLS

   %define SIGINT 2  ; defined in signal.h
   %define TRUE   1  ; defined in curses.h
   %define FALSE  0  ; defined in curses.h

   %define COLOR_BLACK     0
   %define COLOR_RED       1
   %define COLOR_GREEN     2
   %define COLOR_YELLOW    3
   %define COLOR_BLUE      4
   %define COLOR_MAGENTA   5
   %define COLOR_CYAN      6
   %define COLOR_WHITE     7
   %define COLOR_PAIR(n) ((n) << (8))

   %define BLACK_ON_BLUE   1
   %define BLACK_ON_YELLOW 2

   %define BLACK_ON_BLUE   1
   %define BLACK_ON_YELLOW 2

   %define STACK_ALIGN sub rsp, 8
   %define STACK_RESTORE add rsp, 8

section .data

hWindow:       dq 0
hChildWindow:  dq 0
szUserInput:   db 0, 0, 0, 0, 0

; test code begin
  msg db      "got past clear_blue  "
; test code end

section .text
;;  do_init : nothing -> boolean .
;;  preform all of the applications initialization.
;;  when initialization was successful, hWindow will
;;  contain the curses screen handle and the return
;;  value will be TRUE. otherwise, it returns FALSE.

do_init:
   STACK_ALIGN

;;  setup an interrupt to terminate
   mov rsi,do_exit
   mov rdi,SIGINT
   call signal

;;  initialize the curses library
   call initscr

;;  was curses initialization successful?
   cmp rax,0
   jne .CursesInitSuccessful

;;  initialization failed, return FALSE
   mov rax,FALSE
   ret

.CursesInitSuccessful:
;;  save a copy of curses root window
   mov [hWindow],rax

;;  does this system support color terminals?
   call has_colors
   cmp rax,0
   jne .HasColorSupport

;;  No color support, return FALSE
   STACK_RESTORE
   mov rax,FALSE
   ret

.HasColorSupport:
   call start_color

;;  create our color pairs
;;  black foreground, blue background
   mov rdx,COLOR_BLUE
   mov rsi,COLOR_BLACK
   mov rdi,BLACK_ON_BLUE
   call init_pair

;;  if we reach this point, we have initialized successfully.
   STACK_RESTORE
   mov rax,TRUE
   ret

;;  do_exit : integer -> nothing .
;;  exit to the operating system.
do_exit:
   STACK_ALIGN

;;  refresh our screen
   call refresh

;;  shut down curses
   call endwin

;;  return to operating system
   push qword 0
   call exit
   add rsp,4

;;  we should never reach this point
   STACK_RESTORE
   ret

;;  clear_blue : nothing -> nothing .
;;  create a full screen of a light blue color.
clear_blue:
   STACK_ALIGN

;;  make our background blue
   mov rsi,COLOR_PAIR(BLACK_ON_BLUE)
   mov rdi,[hWindow]
   call wbkgd

   ;; refresh our screen
   mov rdi, [hWindow]
   call wrefresh
   STACK_RESTORE
   ret

;;   main : integer (string . string) -> integer .
;;   our program starts here.
main:
   STACK_ALIGN
   call do_init
   cmp rax,TRUE
   jne .done

;;  clear the screen to blue
   call clear_blue

; test code begin
    mov     rax,1   ; sys-write
    mov     rdi,1   ; standard output
    mov     rsi,msg
    mov     rdx,21  ; message length
    syscall         ; write message to screen
    mov     rax,60  ; sys_exit
    mov     rdi,0   ; error code
    syscall         ; exit
; test code end

.done:
   STACK_RESTORE
   xor rdi,rdi
   call do_exit
   ret
 

Let's break down some key points.

Code: [Select]
; test code begin
    mov     rax,1   ; sys-write
    mov     rdi,1   ; standard output
    mov     rsi,msg
    mov     rdx,21  ; message length
    syscall         ; write message to screen

Because we are working within ncurses, this will have unexpected results. You shouldn't be writing on standard output, instead you should be writing to root window provided by curses. This window is buffered and all the decorations (background color, etc.) occur when the root window is refreshed. If you want to write msg to the screen, you first should modify:

Code: [Select]
; test code begin
  msg db      "got past clear_blue  "
; test code end

To be defined like this:


Code: [Select]
; test code begin
  msg db      "got past clear_blue  ", 0
; test code end

Next, you'll want to use waddstr instead of the system call:

Code: [Select]
; test code begin
    mov rsi, msg
    mov rdi, [hWindow]
    call waddstr

Also, you'll need to add extern waddstr to the list of "Functions from the NCurses Library".

Code: [Select]
    mov     rax,60  ; sys_exit
    mov     rdi,0   ; error code
    syscall         ; exit
; test code end

Remember Frank talking about having to reset his screen, if you do this, that's what will happen. You need to let ncurses do some last minute things before closing out your program (like resetting your default terminal options). I handle this in the "do_exit" procedure. If you want to use the syscall version of exit, you should move that to the do_exit procedure and replace these lines with your syscall verison:

Code: [Select]
;;  return to operating system
   push qword 0
   call exit
   add rsp,4

That's a good idea since that's actually wrong anyway, the 64-bit calling convention uses EDI for the first parameter. The code from demo64.asm uses:

Code: [Select]
   ;; return to operating system
   mov rdi, 0
   call exit

Use either this one or your syscall version, but the current one is wrong.

About Bryant Keller
bkeller@about.me

Offline jackjps

  • Jr. Member
  • *
  • Posts: 60
Re: beginner questions
« Reply #47 on: February 27, 2016, 02:07:46 PM »
Hi Bryant,
I made the changes you last posted.
I have no idea if this library is on my computer.
;  libncurses-dev    - Developer's libraries for ncurses.
Maybe hwindow is not getting loaded

  your code:
;;  was curses initialization successful?
   cmp rax,0
   jne .CursesInitSuccessful
;;  initialization failed, return FALSE
   mov rax,FALSE
   ret
.CursesInitSuccessful:
;;  save a copy of curses root window
   mov [hWindow],rax
my comment: at this point I would think that rax has a "1" in it.
Is that correct???

I have this message after hwindow is loaded.
; test code begin.
;  msg2 db      "hwindow is loaded   ",0
    mov     rdi,[hWindow]
    mov     rsi,msg2
    call waddstr    ; write message to screen
; test code end

I can not test after initscr because I don't know how to
change the test code from hwindow to a  test of rax. It is
not loaded at the initscr call yet.

Please a little clarification:
I see so much on the internet of programmers using 80h, syscall and no ncurses.
Is ncurses something new or just better than the old way?
« Last Edit: February 27, 2016, 03:31:33 PM by jackjps »

Offline Bryant Keller

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 360
  • Country: us
    • About Bryant Keller
Re: beginner questions
« Reply #48 on: February 27, 2016, 11:34:49 PM »
Hi Bryant,
I made the changes you last posted.
I have no idea if this library is on my computer.
;  libncurses-dev    - Developer's libraries for ncurses.

If GCC compiles the code without errors, then you have it.

Maybe hwindow is not getting loaded

  your code:
Code: [Select]
;;  was curses initialization successful?
   cmp rax,0
   jne .CursesInitSuccessful
;;  initialization failed, return FALSE
   mov rax,FALSE
   ret
.CursesInitSuccessful:
;;  save a copy of curses root window
   mov [hWindow],rax
my comment: at this point I would think that rax has a "1" in it.
Is that correct???

No, RAX contains a pointer to the stdscr structure, we save that in hWindow so we can access it later. All calls to ncurses functions that start with the letter 'w' (eg. waddstr, waddchr, wmove) require you to pass that pointer as the first argument.

I have this message after hwindow is loaded.
Code: [Select]
; test code begin.
;  msg2 db      "hwindow is loaded   ",0
    mov     rdi,[hWindow]
    mov     rsi,msg2
    call waddstr    ; write message to screen
; test code end
I can not test after initscr because I don't know how to
change the test code from hwindow to a  test of rax. It is
not loaded at the initscr call yet.

I'm confused; that is exactly what the code above does. Where the comment starts "was curses initialization successful?" the value of RAX should be the return value of the call to initscr. We check to see if that value is zero because initscr returns zero when it fails to initialize ncurses.  If you want to place an waddstr message, then you should do that after the last instruction of that code. HOWEVER, writing to a curses window is not like writing to your screen normally, it is back-buffered. Your changes won't show up until you call wrefresh on the handle in hWindow.

Code: [Select]
; Use Case:
;  - create a full screen of a light blue color.
;  - put a small rectangle on the screen in yellow.
;  - let the user enter 4 digits in black in that rectangle.
;  - read the 4 digits from the rectangle.

; Dependencies:
;  libc-dev          - GNU C library.
;  libncurses-dev    - Developer's libraries for ncurses.

; Build Process:
;  nasm -f elf64 demo64.asm -o demo64.o
;  gcc -o demo64 demo64.o -lcurses
;
; Run Process:
;   ./demo64


   bits 64

   global main

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Functions from the Standard C Library
   extern signal
   extern fputs ;; we'll need this for an error message without curses.
   extern exit

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Functions from the NCurses Library
   extern initscr
   extern nodelay
   extern noecho
   extern nonl
   extern cbreak
   extern keypad
   extern has_colors
   extern start_color
   extern init_pair
   extern endwin
   extern refresh
   extern wrefresh
   extern wattron
   extern waddstr
   extern wgetch

   %define STDIN  0
   %define STDOUT 1
   %define STDERR 2

   %define SIGINT 2  ; defined in signal.h
   %define TRUE   1  ; defined in curses.h
   %define FALSE  0  ; defined in curses.h
   %define ERR  (-1) ; defined in curses.h

   %define COLOR_BLACK     0
   %define COLOR_YELLOW    3
   %define COLOR_PAIR(n) ((n) << (8))

   %define BLACK_ON_YELLOW 1

   %define STACK_ALIGN sub rsp, 8
   %define STACK_RESTORE add rsp, 8

section .rodata

szNCursesHelloWorld: db "Hello, ncurses world!", 0
szNCursesInitFailed: db "ncurses initialization; failed.", 0

section .data

hWindow:       dq 0

section .text

;; do_init : nothing -> boolean .
;; preform all of the applications initialization.
;; when initialization was successful, hWindow will
;; contain the curses screen handle and the return
;; value will be TRUE. otherwise, it returns FALSE.
do_init:
   STACK_ALIGN

   ;; setup an interrupt to terminate
   mov rsi, do_exit
   mov rdi, SIGINT
   call signal

   ;; initialize the curses library
   call initscr

   ;; was curses initialization successful?
   cmp rax, 0
   jne .CursesInitSuccessful

      ;; initialization failed, return FALSE
      STACK_RESTORE
      mov rax, FALSE
      ret

.CursesInitSuccessful:
   ;; save a copy of curses root window
   mov [hWindow], rax

   ;; enable keyboard mapping
   mov rsi, TRUE
   mov rdi, [hWindow]
   call keypad

   ;; tell curses not to translate LF into CRLF on output
   call nonl

   ;; take input chars one at a time, no waiting for newline
   call cbreak

   ;; Don't wait on input from wgetch, we'll just poll on user input instead.
   call nodelay

   ;; disable character echoing
   call noecho

   ;; does this system support color terminals?
   call has_colors
   cmp rax, 0
   jne .HasColorSupport

      ;; No color support, return FALSE
      STACK_RESTORE
      mov rax, FALSE
      ret

.HasColorSupport:
   call start_color

   ;; create our color pairs
   ;; black foreground, yellow background
   mov rdx, COLOR_YELLOW
   mov rsi, COLOR_BLACK
   mov rdi, BLACK_ON_YELLOW
   call init_pair

   ;; if we reach this point, we have initialized successfully.
   STACK_RESTORE
   mov rax, TRUE
   ret

;; do_exit : integer -> nothing .
;; exit to the operating system.
do_exit:
   STACK_ALIGN

   ;; refresh our screen
   call refresh

   ;; shut down curses
   call endwin

   ;; return to operating system
   mov rdi, 0
   call exit

   ;; we should never reach this point
   STACK_RESTORE
   ret


;; main : integer (string . string) -> integer .
;; our program starts here.
main:
   STACK_ALIGN

   call do_init
   cmp rax, FALSE
   jne .initSuccess

      ;; do_init failed so let's display a message to the console
      ;; instead of the ncurses window (since it doesn't exist).
      mov esi, szNCursesInitFailed
      mov edi, STDERR
      call fputs

   jmp .done

.initSuccess:

   ;; At this point, ncurses's has successfully initialized and
   ;; hWindow contains a pointer to the stdscr structure.

   ;; Display our message in black text on a yellow background.
   mov esi, COLOR_PAIR(BLACK_ON_YELLOW)
   mov edi, [hWindow]
   call wattron

   mov esi, szNCursesHelloWorld
   mov edi, [hWindow]
   call waddstr

   ;; The last two commands wrote a string on the window buffer,
   ;; now we need to display that buffer on the screen.
   mov edi, [hWindow]
   call wrefresh

   ;; Now that we've displayed something on the screen, we should
   ;; wait for the user to hit any key. We set the user input to
   ;; nonblocking mode with (nodelay) earlier, so wgetch returns
   ;; a translated keycode from the user input, if the user hasn't
   ;; hit a key, it will immediately return ERR. We loop on this
   ;; until we get input from the user.
.getChar:
   mov edi, [hWindow]
   call wgetch

   cmp eax, ERR
   jne .getChar

   ;; once the user has it a key, we can now exit the application.
   ;; we only waited on user input so the message we displayed can
   ;; be read by the user.
.done:
   STACK_RESTORE
   xor rdi, rdi
   call do_exit
   ret

Please a little clarification:
I see so much on the internet of programmers using 80h, syscall and no ncurses.

You asked about doing colors on the screen, that's what ncurses is for. If you just want to display test, you don't need ncurses, you can just write to the screen using the 'write' system call. The int 80h stuff is related to 32-bit system calls, this was replaced by the opcode syscall on 64-bit systems.


Is ncurses something new or just better than the old way?

ncurses actually stands for "New Curses". Basically it's one of several implementations of the curses api, and the most common one in my experience. CURSES itself predates Linux and Windows systems, it goes back to the old AT&T UNIX platforms. So technically curses this is the old way.

About Bryant Keller
bkeller@about.me

Offline jackjps

  • Jr. Member
  • *
  • Posts: 60
Re: beginner questions
« Reply #49 on: February 28, 2016, 10:42:35 AM »
Thank you Bryant for your patience.
About "initscr".
If I understand correctly: initscr puts a zero in rax
if initscr fails and puts a pointer in rax if initscr is good.

I tried to run your new program and I got a segmentation fault.
section .rodata - is just a typo or does it make any difference?
Will continue looking to see if I can find what's causing it.

I am having no luck with "alt+ctrl+f1-f8". Where would I execute it?
Running Linux mint 17.3 rosa xfce
« Last Edit: February 28, 2016, 02:47:27 PM by jackjps »

Offline Bryant Keller

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 360
  • Country: us
    • About Bryant Keller
Re: beginner questions
« Reply #50 on: February 28, 2016, 05:45:04 PM »
Thank you Bryant for your patience.
About "initscr".
If I understand correctly: initscr puts a zero in rax
if initscr fails and puts a pointer in rax if initscr is good.

I tried to run your new program and I got a segmentation fault.
section .rodata - is just a typo or does it make any difference?
Will continue looking to see if I can find what's causing it.

The .rodata section is a read-only data section. It's where you store your constant variables so there is no chance that the get changed. I mostly use it to store strings.

Disregard that last bit of code, I made some mistakes in it. That's the problem with me helping people with 64-bit stuff.. I don't have a 64-bit machine to test the code. I think I fixed the errors in the following code.

Code: [Select]
; Dependencies:
;  libc-dev          - GNU C library.
;  libncurses-dev    - Developer's libraries for ncurses.

; Build Process:
;  nasm -f elf64 hello64.asm -o hello64.o
;  gcc -o hello64 hello64.o -lcurses
;
; Run Process:
;   ./hello64


   bits 64

   global main

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Functions from the Standard C Library
   extern signal
   extern fputs ;; we'll need this for an error message without curses.
   extern exit

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Functions from the NCurses Library
   extern initscr
   extern noecho
   extern nonl
   extern cbreak
   extern keypad
   extern has_colors
   extern start_color
   extern init_pair
   extern endwin
   extern refresh
   extern wrefresh
   extern wattron
   extern waddstr
   extern wgetch

   %define STDIN  0
   %define STDOUT 1
   %define STDERR 2

   %define SIGINT 2  ; defined in signal.h
   %define TRUE   1  ; defined in curses.h
   %define FALSE  0  ; defined in curses.h

   %define COLOR_BLACK     0
   %define COLOR_YELLOW    3
   %define COLOR_PAIR(n) ((n) << (8))

   %define BLACK_ON_YELLOW 1

   %define STACK_ALIGN sub rsp, 8
   %define STACK_RESTORE add rsp, 8

section .rodata

szNCursesHelloWorld: db "Hello, ncurses world!", 0
szNCursesInitFailed: db "ncurses initialization; failed.", 0

section .data

hWindow:       dq 0

section .text

;; do_init : nothing -> boolean .
;; preform all of the applications initialization.
;; when initialization was successful, hWindow will
;; contain the curses screen handle and the return
;; value will be TRUE. otherwise, it returns FALSE.
do_init:
   STACK_ALIGN

   ;; setup an interrupt to terminate
   mov rsi, do_exit
   mov rdi SIGINT
   call signal

   ;; initialize the curses library
   call initscr

   ;; was curses initialization successful?
   cmp rax, 0
   jne .CursesInitSuccessful

      ;; initialization failed, return FALSE
      STACK_RESTORE
      mov rax, FALSE
      ret

.CursesInitSuccessful:
   ;; save a copy of curses root window
   mov [hWindow], rax

   ;; enable keyboard mapping
   mov rsi, TRUE
   mov rdi, [hWindow]
   call keypad

   ;; tell curses not to translate LF into CRLF on output
   call nonl

   ;; take input chars one at a time, no waiting for newline
   call cbreak

   ;; disable character echoing
   call noecho

   ;; does this system support color terminals?
   call has_colors
   cmp rax, 0
   jne .HasColorSupport

      ;; No color support, return FALSE
      STACK_RESTORE
      mov rax, FALSE
      ret

.HasColorSupport:
   call start_color

   ;; create our color pairs
   ;; black foreground, yellow background
   mov rdx, COLOR_YELLOW
   mov rsi, COLOR_BLACK
   mov rdi, BLACK_ON_YELLOW
   call init_pair

   ;; if we reach this point, we have initialized successfully.
   STACK_RESTORE
   mov rax, TRUE
   ret

;; do_exit : integer -> nothing .
;; exit to the operating system.
do_exit:
   STACK_ALIGN

   ;; refresh our screen
   call refresh

   ;; shut down curses
   call endwin

   ;; return to operating system
   mov rdi, 0
   call exit

   ;; we should never reach this point
   STACK_RESTORE
   ret


;; main : integer (string . string) -> integer .
;; our program starts here.
main:
   STACK_ALIGN

   call do_init
   cmp rax, FALSE
   jne .initSuccess

      ;; do_init failed so let's display a message to the console
      ;; instead of the ncurses window (since it doesn't exist).
      mov rsi, szNCursesInitFailed
      mov rdi, STDERR
      call fputs

   jmp .done

.initSuccess:

   ;; At this point, ncurses's has successfully initialized and
   ;; hWindow contains a pointer to the stdscr structure.

   ;; Display our message in black text on a yellow background.
   mov rsi, COLOR_PAIR(BLACK_ON_YELLOW)
   mov rdi, [hWindow]
   call wattron

   mov rsi, szNCursesHelloWorld
   mov rdi, [hWindow]
   call waddstr

   ;; The last two commands wrote a string on the window buffer,
   ;; now we need to display that buffer on the screen.
   mov rdi, [hWindow]
   call wrefresh

   ;; Now that we've displayed something on the screen, we should
   ;; wait for the user to hit any key.

   mov rdi, [hWindow]
   call wgetch

   ;; once the user has it a key, we can now exit the application.
   ;; we only waited on user input so the message we displayed can
   ;; be read by the user.
.done:
   STACK_RESTORE
   mov rdi, 0
   call do_exit
   ret

I am having no luck with "alt+ctrl+f1-f8". Where would I execute it?
Running Linux mint 17.3 rosa xfce

At the bottom left side of your keyboard should be keys labeled CTRL and ALT. At the top of you keyboard should be keys labeled F1, F2, F3, ... F12. Most Linux and BSD systems I use map the key sequence CTRL+ALT+F1 to the first console, CTRL+ALT+F2 to the second, and so on until around CTRL+ALT+F7 or CTRL+ALT+F8 which will usually be running your GUI (in your case XFCE).

The + means that you push each of the keys at the same time. Make a "V" with the fingers on your left hand and hold down both CTRL and ALT. While keeping them pressed, take your right hand and touch the F1 key. This is what's meant by CTRL+ALT+F1.
« Last Edit: February 28, 2016, 05:50:32 PM by Bryant Keller »

About Bryant Keller
bkeller@about.me

Offline jackjps

  • Jr. Member
  • *
  • Posts: 60
Re: beginner questions
« Reply #51 on: February 28, 2016, 06:41:24 PM »
Thanks Bryant,
That worked. Got a black screen, with a yellow rectangle,
the message and a terminal sized screen.
Left out a comma. Fixed it and everything ran fine.

In Windows I frequently used Ctrl+Alt+Delete.
I go into /home/jack/nasmfld. Then I click on demo64.exe.
Go to a clear space and RC and click on open in terminal.
Then I do alt+ctrl+f8. I get a screen with the cursor setting
at Jack@jack-myheadache. I would think at this point I
need to change back into /home/jack/nasmfld to execute
demo64. I don't know how to do that.

 
« Last Edit: February 28, 2016, 06:51:20 PM by jackjps »

Offline Bryant Keller

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 360
  • Country: us
    • About Bryant Keller
Re: beginner questions
« Reply #52 on: February 28, 2016, 08:31:18 PM »
Thanks Bryant,
That worked. Got a black screen, with a yellow rectangle,
the message and a terminal sized screen.
Left out a comma. Fixed it and everything ran fine.

Great, glad it works. :)

In Windows I frequently used Ctrl+Alt+Delete.

Yeah, it's the same kind of key combinations. :)

I go into /home/jack/nasmfld. Then I click on demo64.exe.
Go to a clear space and RC and click on open in terminal.

The "Open in Terminal" option is going to open the current directory in a virtual terminal emulator (VTE). If you're just wanting to make your VTE window to run in full screen mode, you just use F11(this is assuming your using xfce's VTE) once the VTE is running and it'll expand to fill the screen.

Then I do alt+ctrl+f8. I get a screen with the cursor setting
at Jack@jack-myheadache. I would think at this point I
need to change back into /home/jack/nasmfld to execute
demo64. I don't know how to do that.

The use of CTRL+ALT+F1 switches you to an actual console (not a terminal). At the console, you'll login and be put into your home directory. At this point, you'll need to move around in text mode. If you're familiar with DOS, you might find the Linux/Unix for DOS Users web-page helpful. If not, then maybe you should stick to the VTE until you become better acquainted with working within the shell.

The big confusion here is that many uses think that "console" and "virtual terminal" are just two words that mean the same thing. That's not true, these are very different. The console is an application that lets you execute commands on a local Linux/UNIX system and "virtual terminals" are programs that simulate the operation of a real terminal. Your "virtual terminal" connects to the console and gives you access to it from within your GUI (or possibly from another network). A better way to think of this is, from a Windows user perspective, DOS is a console and HyperTerminal or PuTTY are virtual terminals.

Before you continue with your programming studies, get to know Linux itself. The following links are listed in increasing level of difficulty, I suggest working your way down the list.


About Bryant Keller
bkeller@about.me

Offline jackjps

  • Jr. Member
  • *
  • Posts: 60
Re: beginner questions
« Reply #53 on: February 28, 2016, 09:25:59 PM »
Thanks again Bryant.
Cut my baby teeth on DOS. It's an old friend.
However, need to do that reading on Linux.

To get the wide screen I clicked on the xfce terminal icon.
Did cd /home/jack/nasmfld. Hit enter.
Keyed in ./demo64 and voila, got a full screen. :)

Only question I have about all this is, it will not work
for a user. They want to run an ex: "demo64.exe" and be
in the full screen without doing anything else....

« Last Edit: February 28, 2016, 10:55:49 PM by jackjps »

Offline Bryant Keller

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 360
  • Country: us
    • About Bryant Keller
Re: beginner questions
« Reply #54 on: February 29, 2016, 12:20:11 AM »
Thanks again Bryant.
Cut my baby teeth on DOS. It's an old friend.
However, need to do that reading on Linux.

To get the wide screen I clicked on the xfce terminal icon.
Did cd /home/jack/nasmfld. Hit enter.
Keyed in ./demo64 and voila, got a full screen. :)

Awesome :)

Only question I have about all this is, it will not work
for a user. They want to run an ex: "demo64.exe" and be
in the full screen without doing anything else....

Pretty much all Linux users will expect text mode applications to be ran either in the console or a terminal. Very few applications take over fullscreen on Linux and those are usually based around graphics frameworks like SDL or OpenGL. If you want the user to just double-click and get a terminal you need to develop a bash script to go along with your application that loads your program in a new terminal window. Create a file called "demo64.sh" and put the following in it:

Code: [Select]
#!/bin/sh
x-terminal-emulator -e ./demo64

Make that file executable with the command chmod +x demo64.sh and then from your GUI, double click that file. It should create a new xterm instance that the command runs it. Since you're using xfce, you could also opt to create a demo.desktop file that contains:

Code: [Select]
[Desktop Entry]
Type=Application
Terminal=true
Name=Demo64
Comment=A simple 64-bit NASM demo.
Icon=
Exec=./demo64
Path=

When you view this file from xfce (and a few others) GUI, it shows up as Demo64 with a tooltip of "A simple 64-bit NASM demo.", When you double click the file it runs in a terminal and you can even customize an icon for the file. You should note however, that "Exec=" needs to reference your executable exactly, so if you move the demo64.desktop file out of the same directory, it'll probably stop working, unless you use a full path name.

About Bryant Keller
bkeller@about.me

Offline jackjps

  • Jr. Member
  • *
  • Posts: 60
Re: beginner questions
« Reply #55 on: February 29, 2016, 12:52:17 PM »
Code: [Select]
HI Bryant,
1. The following pretty much lost me.
EX: I read the "man chmod" and didn't understand it.
So I am not able to fill this out "chmod +x demo64.sh".

2. The next example. Am I supposed  to fill out those fields or just
use it as is???
Which one should I use?

3.
I need to make sure that the user only enters
digits in demo64. I read the man pages on these two calls
and again I didn't understand the explanation. How do you
know what to put where? Have no idea how to enter the x/y
coordinates for placing a message.
;------------------------------------------------
;   3-1-2016 using NASM 64
;   Order of colors: BGR
;
; Bryants goodies
; Use Case:
;  - create a full screen of a light blue color.
;  - put a small rectangle on the screen in yellow.
;  - let the user enter 4 digits in black in that rectangle.
;  - read the 4 digits from the rectangle.

; Dependencies:
;  libc-dev          - GNU C library.
;  libncurses-dev    - Developer's libraries for ncurses.

; Build Process:
;  nasm -f elf64 demo64.asm -o demo64.o
;  gcc -o demo64 demo64.o -lcurses

; Run Process:
;   ./demo64

   bits 64
   cpu IA64

   global main

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Functions from the Standard C Library
   extern signal
   extern atoi
   extern exit

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Functions from the NCurses Library
   extern initscr
   extern keypad
   extern nonl
   extern cbreak
   extern echo
   extern has_colors
   extern start_color
   extern init_pair
   extern newwin
   extern endwin
   extern refresh
   extern waddstr
   extern wattron
   extern wrefresh
   extern wgetch
   extern wgetnstr
   extern wbkgd

   extern LINES
   extern COLS

   %define SIGINT 2  ; defined in signal.h
   %define TRUE   1  ; defined in curses.h
   %define FALSE  0  ; defined in curses.h
   %define STDERR 2

   %define COLOR_BLACK     0
   %define COLOR_RED       1
   %define COLOR_GREEN     2
   %define COLOR_YELLOW    3
   %define COLOR_BLUE      4
   %define COLOR_MAGENTA   5
   %define COLOR_CYAN      6
   %define COLOR_WHITE     7
   %define COLOR_PAIR(n) ((n) << (8))

   %define BLACK_ON_BLUE   1
   %define BLACK_ON_YELLOW 2

   %define BLACK_ON_BLUE   1
   %define BLACK_ON_YELLOW 2

   %define STACK_ALIGN sub rsp, 8
   %define STACK_RESTORE add rsp, 8

section .data

hWindow:       dq 0
hChildWindow:  dq 0
szUserInput:   db 0, 0, 0, 0, 0
uinputerr      db "only digits may be entered - enter again",0

section .text
;    global _start    ;??  bryant said these are included in the "c" lib
;_start:              ;??

;;  do_init : nothing -> boolean .
;;  preform all of the applications initialization.
;;  when initialization was successful, hWindow will
;;  contain the curses screen handle and the return
;;  value will be TRUE. otherwise, it returns FALSE.

do_init:
   STACK_ALIGN

;;  setup an interrupt to terminate
   mov rsi,do_exit
   mov rdi,SIGINT
   call signal

;;  initialize the curses library
   call initscr

;;  was curses initialization successful?
   cmp rax,0
   jne .CursesInitSuccessful

;;  initialization failed, return FALSE
   mov rax,FALSE
   ret

.CursesInitSuccessful:
;;  save a copy of curses root window
   mov [hWindow],rax

;;  enable keyboard mapping
   mov rsi,TRUE
   mov rdi,[hWindow]
   call keypad

;;  tell curses not to translate LF into CRLF on output
   call nonl

;;  take input chars one at a time, no waiting for newline
   call cbreak

;;  enable echoing of input
   call echo

;;  does this system support color terminals?
   call has_colors
   cmp rax,0
   jne .HasColorSupport

;;  No color support, return FALSE
   STACK_RESTORE
   mov rax,FALSE
   ret

.HasColorSupport:
   call start_color

;;  create our color pairs
;;  black foreground, blue background
   mov rdx,COLOR_BLUE
   mov rsi,COLOR_BLACK
   mov rdi,BLACK_ON_BLUE
   call init_pair

;;  black foreground, yellow background
   mov rdx,COLOR_YELLOW
   mov rsi,COLOR_BLACK
   mov rdi,BLACK_ON_YELLOW
   call init_pair

;;  lets create a child window
   mov rcx,50    ; x value
   mov rdx,10    ; y value
   mov rsi,5     ; 5 columns for 4 digits
   mov rdi,1     ; 1 line for 1 row of digits
   call newwin
   mov [hChildWindow],rax

;;  if we reach this point, we have initialized successfully.
   STACK_RESTORE
   mov rax,TRUE
   ret

;;  do_exit : integer -> nothing .
;;  exit to the operating system.
do_exit:
   STACK_ALIGN

;;  refresh our screen
   call refresh

;;  shut down curses
   call endwin

;;  return to operating system
   mov rdi,0
   call exit

;;  we should never reach this point
   STACK_RESTORE
   ret

;;  clear_blue : nothing -> nothing .
;;  create a full screen of a light blue color.
clear_blue:
   STACK_ALIGN

;;  make our background blue
   mov rsi,COLOR_PAIR(BLACK_ON_BLUE)
   mov rdi,[hWindow]
   call wbkgd

;; refresh our screen
   mov rdi, [hWindow]
   call wrefresh
   STACK_RESTORE
   ret

;;  draw_child_window : nothing -> nothing .
;;  put a small rectangle on the screen in yellow.
draw_child_window:
   STACK_ALIGN

;;  make our background yellow
   mov rsi,COLOR_PAIR(BLACK_ON_YELLOW)
   mov rdi,[hChildWindow]
   call wbkgd

;;  refresh our child window
   mov rdi,[hChildWindow]
   call wrefresh
   STACK_RESTORE
   ret

;;   get_user_input : nothing -> integer.
;;   let the user enter 4 digits in black in the rectangle.
get_user_input:
   STACK_ALIGN

;;   get user input
;;   here I am trying to test the input from the user for valid
;;   digits. The error message should go on the same line as the
;;   yellow rectangle. This bad code gives the error message at
;;   x-0,y-0. The yellow rectangle is not cleared for new input. 
.n1:
   mov rdx,4
   mov rsi,szUserInput
   mov rdi,[hChildWindow]
   call wgetnstr      ; reads all 4 characters good or bad
   mov rsi,szUserInput    ; check user input for digits
   mov ah,3
.n2:
   cmp ah,3     ; process 4 digits
    jg .out1    ; good input
   mov al,[rsi]
   cmp al,0
    jl .err1
   cmp al,9   
    jg .err1
   inc ah
   inc rsi
    jmp .n2

.err1:
   ;; Display error message in black text on a yellow background.
   mov rsi,COLOR_PAIR(BLACK_ON_YELLOW)
   mov rcx,5     ;???? x value
   mov rdx,10    ;????? y value
   mov rdi, [hWindow]
   call wattron

;uinputerr      db "only digits may be entered - start over",0
   mov rsi,uinputerr
   mov rdi, [hWindow]
   call waddstr

   ;; The last two commands wrote a string on the window buffer,
   ;; now we need to display that buffer on the screen.
   mov rdi, [hWindow]
   call wrefresh

   call draw_child_window
    jmp .n1

.out1:
;;   convert string to integer
;;   rdi, rsi, rdx, rcx, r8, r9
   mov rdi,szUserInput
   call atoi
   STACK_RESTORE
   ret

;;   main : integer (string . string) -> integer .
;;   our program starts here.
main:
   STACK_ALIGN
   call do_init
   cmp rax,TRUE
   jne .done

;;  clear the screen to blue
   call clear_blue

;;  draw yellow window
   call draw_child_window

;;  get user input
   call get_user_input

   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   ;; At this point in our code, the number we ;;
   ;; entered into our child window is in the  ;;
   ;; RAX register. We can now use it for any- ;;
   ;; thing we want.                           ;;
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

.done:
   STACK_RESTORE
   xor rdi,rdi
   call do_exit
   ret








 
« Last Edit: March 01, 2016, 09:32:44 PM by jackjps »

Offline Bryant Keller

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 360
  • Country: us
    • About Bryant Keller
Re: beginner questions
« Reply #56 on: March 02, 2016, 09:47:29 PM »
HI Bryant,
1. The following pretty much lost me.
EX: I read the "man chmod" and didn't understand it.
So I am not able to fill this out "chmod +x demo64.sh".

Unlike Windows, Linux doesn't care what a filename's extension is. Linux determines if a program is executable or not based on a series of attributes that are attached to the file. These attributes are modified using chmod. If you want to make a file eXecutable, you give it the x attribute. To add an attribute to a file you use the + (plus) sign, and to remove it, you use the - (minus) sign. So chmod +x demo64.sh adds the executable attribute to the demo64.sh file. Once marked as executable, it can be ran like a program.

2. The next example. Am I supposed  to fill out those fields or just
use it as is???
Which one should I use?

I have no clue what your talking about here. The examples I've been giving you have just been to give you an idea about code you've been talking about. The first example was almost exactly what you said you were working on. The others were just to expand on questions you've asked. The most recent example was a basic hello world application which displayed an error using fputs when ncurses failed to initialize to show how you should handle that message instead of trying to write to the ncurses screen that didn't initialize. ;)

3.
I need to make sure that the user only enters
digits in demo64. I read the man pages on these two calls
and again I didn't understand the explanation.

Well, there are two ways to go about this, you can create your own wgetnstr routine using wgetch which limits user input to only digits. Or, when wgetnstr returns a string, you can then check the contents of the string to make sure it's a valid number and report an error to the screen. How you handle this is totally up to you.

How do you
know what to put where?

I referenced the documents I've linked you too. Most of them contains simple examples and will give you a basic understanding of how to work with curses. Until this thread, I had never used curses from assembly. Turns out, it's not that difficult.  ;D

Have no idea how to enter the x/y
coordinates for placing a message.

You move your cursor using the wmove command. The wmove procedure moves the cursor to a line number 'y' and a column 'x' relative to the windows origin. That last part makes it a bit confusing because if you are using wmove in a child window that's on line 4 column 3, then using wmove on that window with y=2 and x=1, the cursor would actually be on the screen at line 6 column 4. But working with the root window, the coordinates would be relative to the screen and should be easy enough to use, like so:

Code: [Select]
mov rdx, [x_val]
mov rsi, [y_val]
mov rdi, [hWindow]
call wmove

About Bryant Keller
bkeller@about.me

Offline jackjps

  • Jr. Member
  • *
  • Posts: 60
Re: beginner questions
« Reply #57 on: March 04, 2016, 05:03:50 PM »
Hi Bryant,
I'm still having problems with your last post. I will put that aside
for now and continue trying to complete my 1st program.
I have read the man page about "getmaxyx" and don't understand
the format of the instruction.

 void getmaxyx(WINDOW *win, int y, int x)

For instance what does void do?
what are the () for?
what goes where "window" is.
I assume the *win is stdscr

What I need is to get the number of columns on a monitor.

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2616
  • Country: us
Re: beginner questions
« Reply #58 on: March 04, 2016, 09:10:34 PM »
Hi jackjps,

"void" just advises the compiler not to use the returned eax/rax for anything. You shouldn't either, of course. The '()"s are just 'cause C programmers like 'em. The "*win" is presumably the "handle" of the window you're enquiring about - either the root window or the child window.

I'm quite puzzled by how a function that returns "void" can "get" anything. I could see it if you were passing the address of x and y, but that's not what it says. RTFM solves the puzzle:

http://invisible-island.net/ncurses/man/curs_getyx.3x.html

see down where it says NOTES? This puppy is a macro, and the "address of" indicator(s) are hidden - you do want to pass the address of x and y to be filled in. Gotta love this high-level shtuff! :)

Hope that helps until Bryant can get to you.

Best,
Frank


Offline Bryant Keller

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 360
  • Country: us
    • About Bryant Keller
Re: beginner questions
« Reply #59 on: March 04, 2016, 11:23:05 PM »
I'm still having problems with your last post. I will put that aside
for now and continue trying to complete my 1st program.
I have read the man page about "getmaxyx" and don't understand
the format of the instruction.

 void getmaxyx(WINDOW *win, int y, int x)

This is where things get complicated for working with C libraries under assembly. Unfortunately, C macros look just like C functions so sometimes it's hard to differentiate them unless you read the headers yourself. What makes it worse is, the macros usually make use of high level constructs which means they should actually be multi-line macros in assembly where (you might think you could just use a %define).


What I need is to get the number of columns on a monitor.

That hWindow we've been passing around is actually a data structure that holds information about the window's coordinates and other stuff i might need later on. NCURSES provides us with a convenience in the form of LINES and COLS. These are variables which old the maximum number of LINES and COLS of the current window. You'll notice that on earlier examples I was including these with:

Code: [Select]
   extern LINES
   extern COLS

The problem with these variables is that if you resize the window, these variables won't reflect the change. They are only defined once the program starts. This lead to the NCURSES header including the macro you've looked up there. Since implementing an exact clone of that macro would introduce a lot of code (specifically detecting our parameter types and ensuring we properly write to either memory or register correctly, etc) I decided to implement two new macros that just access the contents of the structure for you.

Code: (get_max_coord) [Select]
;; get_max_coord : window_handle -> { x y }
;; Obtains the max X and Y coordinates from a window handle
;; and returns the maximum X coordinate in rax and the maximum
;; Y coordinate in rbx.
%macro get_max_coord 1
push rsi
mov rsi, %1
xor rax, rax
xor rbx, rbx
mov ax, [rsi + 6]
mov bx, [rsi + 4]
pop rsi
%endmacro

Code: (get_cur_coord) [Select]
;; get_cur_coord : window_handle -> { x y }
;; Obtains the current X and Y coordinates from a window handle
;; and returns the current X coordinate in rax and the current
;; Y coordinate in rbx.
%macro get_cur_coord 1
push rsi
mov rsi, %1
xor rax, rax
xor rbx, rbx
mov ax, [rsi + 2]
mov bx, [rsi]
pop rsi
%endmacro

The actual data structure uses "short" integers for the coordinate variables so they are 16-bits (even on 64-bit machines). These macros return the coordinates in the RAX and RBX registers so if you you are using those variables in your code, be sure to save them before calling these macros.
« Last Edit: March 26, 2016, 11:34:26 PM by Bryant Keller »

About Bryant Keller
bkeller@about.me