About
Docs
Files
Support
Index

Essentials
AutoDocs
Library functions
Cooperate
Process mastering
Debug
Own debugging kit
FGE
Smart modeid pick
Loader
Shared lib. loader
Macros
Helper macros
Structs
All the structures
Logs
Library changelogs
Tools
Progs baked inside



M
A
N
U
A
L

SOURCE: qdev_manual.txt 1.06 (11/09/2014) English

1 Getting started
  1.1 Official ASCII logo
  1.2 Background/history
  1.3 About this manual
  1.4 Foreign languages
  1.5 How to participate
  1.6 People involved

2 Installation notes
  2.1 System requirements
  2.2 Library flavours
  2.3 Step by step install

3 Compatibility notes
  3.1 LibNIX and nativity
  3.2 QCLI extension tips
  3.3 QCRT0 startup code

4 Library usage
  4.1 Out of the box use
  4.2 Build control macros
  4.3 Library wide macros
  4.4 Own library loader
  4.5 Order of CLI things
  4.6 Getting help on API
  4.7 Coding shortcuts
  4.8 How to report a bug

5 Complex subsystems
  5.1 File Descriptor Relay
    5.1.1 Supported packets
    5.1.2 Private MsgPorts
    5.1.3 ACTION_LOCK_RECORD
    5.1.4 ACTION_WAIT_CHAR
    5.1.5 Pipe limitations
    5.1.6 Address checks
    5.1.7 Relay policy
    5.1.8 Rollover files
    5.1.9 Status explained
  5.2 Link Point
    5.2.1 Supported packets
    5.2.2 Packet route
    5.2.3 Context behaviour
    5.2.4 Limitations
  5.3 DOS device unmounter
    5.3.1 Clean method
    5.3.2 Shield method

6 Obviously mumbo-jumbo
  6.1 Internal bases
  6.2 Cached bases
  6.3 IEEE arithmetics
  6.4 Modular segments
  6.5 A4 register issue
    6.5.1 Callbacks/Hooks
  6.6 Undocumented routines
  6.7 Local Base Support

7 FAQ
  7.1 Questions and answers
    7.1.1 Package related
    7.1.2 Programming



1 Getting started

  1.1 Official ASCII logo
                     #                           http://qdev.sdf.org/
                     ##                       
                     ##                          oooooooooooooooooooo
      Powered by     ##                          8                888
                     ##                          8 oooooooooooood"888
                     ##                          8 88888888888P"  888
    88888888   ########  #######   #     #       8 888888888P"    888
    88     88 ##     ## ##     ## ##     ##      8 8888888P"      888
    88     88 ##     ## ######### ##     ##      8 88888P"        888
    88     88 ##     ## ##        ##     ##      8 888P"   by BCD 888
    88     88 ##     ## ##        ##     ##      8 8P"oooooooooooo888
    88     88 ##     ## ##        ##     ##       888888888888888888
     88888888 ########   ########  ########
           88                                     oooooooooooooooooo
           88                                    d       ..ooo888888b
           88  Quick Development Suite          d    ..odo88888888888b
           88                                  doooooooooooooooooooooob
           88       for the Amiga computer    
           8


If you feel that mentioning 'qdev' as per program that uses its features is
the right thing to do then feel free to copy this logo and paste it in your
readme  or manual. You can get rid of  the computer emblem  on the right if
you want to. Thanks in advance!


    
  1.2 Background/history
At the beginning there was just darkness... Heh. At the beginning there was
a loader. Not  a sophisticated  loader. Just  a tiny loader. The loader was
told  to  free the  'startup-sequence'  from  command  line  stuff, so that
things  could be done  low-level. The  loader was verbose  due to  its  own
screen which did not interfere with the Workbench screen. This way programs
were free to say whatever they wanted. That  meant that  whenever  an error
occurred  the  user  was  to  know  that something  failed badly(unlike  in
'startup-sequence'  where everything  is  redirected to dreaded 'NIL:'). It
all was great to a point where  loader Creator found out  that its creation
is a massive dirt ball and the code is so unreadable that further expansion
would  be literally a one small step for man,  everything but forward! Then
the idea did spring into mind. Why not to write a  specialized library that
helps in building loaders? Creator was  given an enlightment! "Holy fuck, i
must write that very special library and split all this mess across objects
and master the API  and debug it and write a solid documentation as soon as
possible before i forget everything!" - he said. Yes, he was certainly very
excited. The work began  in  June  2010 on a sunny day after drinking fresh
orange juice. But something was missing. Yap it was the Nectarine demoscene
radio, so he  tuned in and started a chat with  Socrates to  borrow on some
philosophy and stuff.

The concept was API as you understand it, but also the alternative meaning,
the acronym that expands to: Amiga Portable Independent, which  divided the
API into three parts, so that many generic functions could easily be ported
to  other  platforms. The  first  group of functions to be implemented were
the ones starting with the letter I like independent(platform independent).
Then after establishing the bare minimum there was a time for A like Amiga.
And at that time due to great  coincidence the Creator has met a person who
was also into home computers and did see that great potential in loader, so
he  joined  the project  as a  beta  cowboy  and  eventually  became  human
Debugger! The  Debugger  was nothing  like a computer debugger, he was  way
advanced, he could  load  the code  into  brain, process it  and find a bug
before  the  Creator  was  annoyed  by the  fact that he screwed  something
halfway  through. The  cooperation  was all  fine  and  dandy. The  library
started  to  grow  rapidly  and  by  the  opening  of 2011  it had about 70
functions(and a totally broken FDR which  Debugger was trying to heal). One
day when  breakpoints were all set and the  porn was being ripped into XVID
the  Debugger  noticed that his  depraved computer is  starting to give him
smoke signals that the movie is definetly  too hot  for this  CPU. It  then
yelled  through speech synthesis: "It is unfair that  i go to hell for your
porn you bastard!" and eventually died from hell's fire ;-) . But  that was
just an effect of trauma and a bad dream Debugger had after it happened.

A fitting tribute to poor machine that suffered due to human desire was the
dance of  Burnt  Chip  Dominators  at the grave of AMD's finest hardware...
The Debugger  was sad, so  he started to eat cookies and played  Soccer Kid
a lot to kill that awful pain. Meanwhile Creator was studying so many books
on Amiga  programming that eventually  all progress ceased for a few months
and so he  also started to  eat cookies. After long  pause the Creator  was
asked to  write a program  that would eliminate duplicate lines in the text
files really quick. This is when  'hashlab'  was created  and  unbelievable
thing happened the  Debugger also wanted to know  which hash routine is the
best, so  the  forces were joined once again. At that time it was mid 2011.
Now the team has realised that  the library is shifting into universal. The
toolbox  that had just  5 or 6 different  instruments started manifest that
clearly. The goal? Oh yes the loader, faded a bit and  the team  focused on
functionality. This  is the time when these  tiny utilities really impacted
the library. The  Debugger  was an optimist, the  Debugger was  wrong there 
were  still too many bugs  everywhere! It was  no other way  than to  start 
writing tiny  progs that would actually put their work to a test. Testsuite
was there  for a while, but it was a no-go. Although a good  checkpoint  in
general, the tools and dirty binaries won in the end. Problems were driving
function  splitting and  simplifying which caused  function  population  to
grow  and  when  it exceeded  100, the  existing program  flow  monitor was
found too inefficient due to bad  implementation. Creator had to go back to
books on assembly and to do freaky experiments with the compiler.

Debugger  was still fighting  bugs in hash evaluator, so  they did not know
what  hash will be the best  for text filtering  purposes. Creator tried to
hire 'pthreads'  to switch between  books and actually  woke up in  between
contexts screeming  that there is no documentation  what so ever! They  did
drop  current  schedule  and  attempted to  work  on  documentation. Again,
numerous  bugs  were  squashed...  "Why did i do that this way, any ideas?"
- Creator on it's own code. "What the fuck is this?" - Debugger overlooking
supposedly fixed code. In the end the team had  to study the code  all over
again  to  point  out  possible  exceptions. The  time  was  mercyless  and
started to boost. It was practically the  end of  2011 and the  project was
begging for  new extra powers as the  team was bored to death  and did  not
even  get back to what  was  interrupted. A  crisis! Oh  really? They  were
puking  all over the place  with  that  longish scroll  of  autodocs. Then,
surprise.  Somehow, the  news  about  the  library that is in the works got
spread(well,  they were not  hiding it but  also not talking  about  it out
loud) and  they received an e-mail from a company that basically  wanted to
know what is this  and if they can possibly put their hands on it. Debugger
was stunned, while Creator  thought it is a joke. It was  not a  joke as it
then did turn out, but  the company which heavily praises the Amiga is just
a bad sign... BCD  explained  briefly what the library is all about and how
much bugs it contains and how shitty this project is in hope that they will
just go away. And they did not.

The  polite way of taking care of  business was way  in the past.  Numerous
tricks  were played on BCD  just to gain access  to the source code. In the
end  Creator  decided that a hobby  project is to be a hobby project and no
hoax  companies  need  ever  to kill  it. The  case  was closed.  But  then
question was asked whether it is okay to make this code  GNU GPL  compliant
in whole? A  friend suggested that  this  would easily  demotivate them and
the  progress  would  eventually  stop in a blink of an eye. The  team took
that seriously and started to think on its own license that does not impose
restrictions  on users and programers, but  totally  forbids corporate use.
This  may sound  silly,  but  when one  realises that  there  are  parasite
companies  all around the world who play dirty and turn valuable ideas into
garbage, then certainly it  is no longer that funny. This is also the  time
when the part  P like portable was sorta neglected. Although some functions
were marked to be portable and at least  GNU/Linux hosted  OSes did compile
that  stuff just fine due to personal  reasons that did  not get  too  far.
Debugger definetly took a break in  the need to learn to the exams. Creator
was very thankful ("Thank you very much man!") for his time and the effort.
The 2012 was about to begin, the docs were nearly complete, the code shiny,
new batch of functions and tools on their way and the Nectarine radio still
on the air although  relays  tend to  shrink and go  AAC. Argh! But overall
Burnt Chip Dominators did what they planned. Well, sort of...

At present  'qdev' hides so much of low-level stuff in its stomach that the
library tends  to look complex  but fortunately though  usage is considered
relatively  easy and at the same time tries to address  different  needs by
the  variety  of departments. Currently  things  like:  text  manipulation,
text/data  parsers,  I/O  tweaks,  context  enhancing, device  interfacing,
virtual files, simple graphics ops, memory  clustering, integer conversion,
feature  rich  debug  subsystem,  stream  handlers,  friendly  little  code
agents, inexclusive task exceptions, resident  module  creation,  file  and 
directory  ops, simplified  user dialog creation, and many other things are
either possible with very little input or available out of  the box. So how
to describe the   'qdev'   today with  its  quite  wide  routine  spectrum?
This does not sound like a difficult question really, but lets conclude. It
is  simply universal and that is most probably what  Amiga enthusiasts will
appreciate(BCD is hoping) when coding. Can  it  truly  serve as  a seed for
growing fancy, OS friendly loaders? Certainly, it will all resolve  in  the
year  2013  when the team  will enter full-blown post-incarnated  Workbench
distro project(yet another hope). And we will let you know about it as soon
as it will become usable. Cheers!


    
  1.3 About this manual
Although this manual was written to document the library usage, it does not
cover every single aspect of it! The reason this file exists is that humans
are not computers and they happen to forget things. BCD is no different, we
have no idea what  the future will bring, so we would like to protect basic
library guidelines from being  lost in case this piece of software is to be
found  after the years of possible abandonment by a fresh person, or by the
people who have simply lost.

As you may have guessed by the TOC,  an absolute minimum of information was
served. It  may seem insufficient, but  really there are AutoDocs and other
papers who try to address issues not mentioned here. Aside detailed library
usage section there are supplementory sections. In 'Complex subsystems' you
will  find lots of information  on the most fuzzy  library code. The  other
section namely  'Obviously mumbo-jumbo'  reveals some tricky internals that
may be important when interfacing this code with auxiliary code.

We just hope that the  time spent on familarizing  will be recovered by the
new  great  ideas and  programs of course  that the  Amiga  community  will
possibly  be given to run on  their amazing  home computers  for another 30
years.


    
  1.4 Foreign languages
We  do not intend to translate any papers to our native languages nor other
languages. It is our belief that  English language is the most universal of
all World languages, so that with a bit of effort anyone can understand the
contents. We sure accept translations though! If you would like to nativise
the docs  prior to your  first language then please contact us. We  will be
able then to help you formulate  what you do not really understand. It does
not matter you are green on coding,  the key is you can translate stuff and
that certainly counts!

Please note that we cannot pay you for your work(we are hobbysts afterall),
but we can give a full credit  for your contribution. Important! The use of
automatic  translation  engines  as  available  on   the  web  is  strongly
discouraged! It makes no sense at all to put such docs in the distribution.


    
  1.5 How to participate
Feel free to  contribute some  useful code of your's. The  material  can be
in Public Domain, copyrighted, licensed under your terms or better GNU GPL.
We  will need your consent that you  allow us to host your material without
major  limitations. We give a choice whether  the code falls under the  API
and so can  be altered by  us, or if it must  not be altered  but a wrapper
should  be created instead. In the  latter case it will  end up in  'supp/'
directory. Before  sending us  anything please contact  us first, so we can
discuss   "this  and  that"   including  the   usefulness  factor,  typical
application, bottlenecks and the like.

Also, the  ideas concerning some  extra functionality are welcome. You need
not  to be a coder to come  up with something  that will  possibly rule the
universe ;-) . Additionally you can donate some money through PayPal if you
like what we do. Your name will be listed in the CONTRIB file. E-mail us if
you do not want to be mentioned! The cash will be largely used to cover the
development expenses. It is not  meant to pay the electricity  bill, but to
help  in case  something breaks badly and requires costly repair(Amigas are
rather old).


    
  1.6 People involved
Currently the cult members (the Burnt Chip Dominators) are following folks:


Anatoliy Kashpirovsky   (megacz  )

  Nicknames  are all over the Internet. I like them more than real names as
  the computer world appears  to be something very  artifficial even though
  real in the end. My name is another nickname by the way (-: . If you  did
  read the  intro then  you  know  who brought this project to life. I seem
  to  be the main coder, a person  whose crime  is to  spend  hours writing 
  things  and  possibly hand  them down to  Tony  who tries  to fix  bugs i
  introduced.


Tony     Krutchenko     (kowalsky)

  Hello. This  is  Tony  speaking. From  time  to  time  I  do support home 
  computer  fans in various ways. The  Amiga is actually a new thing to me,
  not  because I never  used it or something  but  because I  prefer  8 bit
  machines. I have joined this project because I see great potential in it.
  It is not only due  to planned rebirth  of  `fancy'  OS loader but simply
  because this library allows basically anyone to be a coder and I like the
  idea. When  I  have  got the  time I try to  debug code  thus  megacz can
  introduce new bugs ;-> .



    
2 Installation notes

  2.1 System requirements
Currently the library comes as a static archive, and is available for Amiga
computers  only. All  objects were compiled in   68020-68060  compatibility
mode. The FPU is not being used directly thus it is not necessary. In order
to compile anything and link against the library following minimum hardware
requirements must be met:

  - Any Amiga with ROM 37.300 and up
  - At least 8 MiB of free memory
  - CPU of MC68020 or better


Please  note  that library code  often  relies on  ROM 39.xxx  features, so
certain  things may  not work  under  earlier  OS  releases!  A comfortable
development setup is more or less this:

  - Amiga 1200 with ROM 39.106 and up
  - At least 24 MiB of free memory
  - CPU of MC68040 or better


As to developer environment Geek Gadgets are necessary. Depenedencies along
with links are listed in the 'README'  file. All software is either GNU GPL
or  freeware. As  you may have guessed you will need  GCC  compiler and its
GNU friends. If you are really puzzled about GG as to how to configure this
beast  or just too lazy to do that you can use 'GG-Lite'(a compact DE) that
was created with 'qdev' in mind.


    
  2.2 Library flavours
This  archive comes with  three library  branches that  were compiled  with
different compiler flags. They all share the same name, but sit in separate
directories. The major  difference lies in  code and/or data handling. With
so called  STANDARD  library no addressing  problems will occurr,  but such
binaries cannot be made resident. On the other hand with RESIDENT libraries
(including the  32 bit branch) programs can be pure, so that memory  can be
used more efficiently, but  addressation issues may appear thus coder  must
really be careful about what he/she is doing. More details below:


lib/libqdev.a                  (STANDARD  )

  This is the standard library. It should  work flawlessly with any startup
  code  around. Problemless  operation under any circumstances  can just be
  expected. If the debug support is required then only this branch will do!


lib/libb/libqdev.a             (RESIDENT  )

  This  is the resident/pure branch. Programs can be at max  64k big, since
  the  addressing mode is  only  16 bit wide! Programs  that  utilise  this 
  flavour may work a bit faster and  really have small footprint on memory.
  When coding using this and the  32 bit braches remember about A4 register
  copy/restore! Yes, you must do it manually!


lib/libb32/libm020/libqdev.a   (RESIDENT32)

  In  theory this build allows 32 bit  binaries to be resident. Afaik  this
  works in 'ixlibrary' model, so it should work for your binaries too. Note
  however that  such binaries will work on  68020  onwards. This branch was
  not evaluated at all. Use at your own risk!


    
  2.3 Step by step install
Installing the library and headers is not really a pain. All you have to do
is to  copy them to your  GG  developer environment and that is it. You can
use  your favourite file  manager to do that or  you can type these  at the
shell prompt:

  cd libqdev-?.?-bin-m68k/
  makedir gg:include/qdev
  copy include/qdev/ gg:include/qdev
  copy lib/libqdev.a gg:lib/
  copy lib/libb/libqdev.a gg:lib/libb/
  copy lib/libb32/libm020/libqdev.a gg:lib/libb32/libm020/


One  more important  thing is the  header search  path. You  have  got  two
choices. You can either create the CPPFLAGS global environment variable and
place there the path:

  setenv CPPFLAGS "-I/gg/include/qdev"


Or you can request headers with  'qdev/' prefix in your code. Both ways are
OK and can be mixed. Alternatively you can do something like this:

  cd gg:
  makedir qdev-include qdev-include/include
  copy include/qdev/ qdev-include/include/
  delete all include/qdev 
  assign add gg: qdev-include


Compiler  will find each  header thanks to  Amiga  multiassign facility. At
this  point you can  compile and link  against the library  with no special
macros being  defined. The default startup  code will be used.

But  the best part  is that you do  not really  need to  install  anything!
Surprised? Package  was designed  in such a way  that your  projects can be
hosted  in it. This way  OS  API  can be  used without  U**X  setup and its
primitives. Also,  no  knowledge  about  all  special  lowlevel  macros  is
necessary since everything is already prepared. In order to create your own
utility go  'user/template-x.x/'  directory. Now copy  it under the name of
your choice, modify  Makefile  and start working on your program. Then just
'make' it.



    
3 Compatibility notes

  3.1 LibNIX and nativity
Due to the fact that GCC alone cannot produce immediate executables, a glue
startup  code is necessary. One such startup code is 'crt0.o' which depends
on  'ixemul'. Obviously  this is a bloatware in case nothing references its
features  because each time such prog  is to be started heavy BSD artillery
has to  be involved. Fortunately though there is an  alternative('ncrt0.o')
which utilises static link library called 'libnix'.

Thanks to  LibNIX  quick ports of wide  variety of software  are essentialy
possible and  sometimes they even work. But that  is not the point. What is
really  useful about  this library is its startup code that allows pure  OS
coding! By principle  'qdev'  is one such thing that is meant to be used in
that way thus most of its tools use the glue code at absolute minimum which
guides the  program through lowlevel wizardy  and leaves at the point where
things are straighten up.

This  particulary means that no standard libraries  are ever  opened. It is
up to  programmer to take care of that. This  also means that  STABS and/or
assembly  inline affected  code will most likely  malfunction  leading to a
crash just at startup! Therefore  one must avoid linkage against 'libnix.a'
when coding natively or to make sure no objects are  STABS/ASM affected nor
they reference features currently disabled in the startup code.

To summarize, when coding using OS API only you generally want your prog to
just takeoff so that you can do the rest your way. In such case use  'qdev'
own library loader  feature called ___QDEV_LIBINIT_NOEXTRAS . You will also
need to construct custom command line and pass the arguments and objects in
the right order! I encourage  you to go to  'user/template-x.x/'  directory
and build the template yourself so you can see where stuff goes.


    
  3.2 QCLI extension tips
QCLI  is an extension that  allows console only  programs to  be  Workbench
launchable. It does  that by testing CLI  pointer in the Process structure.
If this pointer is NULL then the environment is considered improper and the
program is being relaunched in true CLI mode. This extension is implemented
as a macro in the 'qdev' library loader so that practically anything can be
Workbench  compliant. To  activate this  feature  one  should supply  macro
___QDEV_LIBINIT_CLIONLY with stream name.

While there is no serious problems with the extension itself there are some
restrictions  as to when it is possible to use  QCLI. If  you did  overlook
'ixemul'  startup code and its magic helper blocks  then you surely noticed
that it does deal  with the  Workbench  startup message internally and does
not export anything like 'WBenchMsg'. And that is the main bottleneck, thus
QCLI  and 'mem_getwbstartup()' function will only work with  LibNIX startup
code.


    
  3.3 QCRT0 startup code
As of version  1.2 of the package there exists special light-weight startup
code  that allows to create  standard and resident  binaries that (aside of
OS 1.3 compatibility)  do not require  separate  initial  objects.  Startup
autosenses  if certain user objects  were compiled resident  and if so lets
one know  (through a special structure) that  he/she  should take an action
and relocate this and that.

Due  to  modularistic  nature of  QCRT  it is programmer  who  decides what
features will be utilised. This is because  it is practically impossible to
guess which  feature may be useful and  which may become major hindrence in
the process of custom  creation (ROM/resetproof objects seem a good example
here). Modules  are special  functions (usually  wrapped  in  handy macros)
starting with the crt_#? prefix that are to be put in 'main()'.



    
4 Library usage

  4.1 Out of the box use
One  of the coolest things about  'qdev'  is the  ability  to  utilise  the
library  out of the box. No need to copy  any components to your GG/system.
You can start developing programs as hosted in the  'user/'  directory. And
believe it or not it was not our goal it just happened when 'tools/' needed
to  be integrated. As a consequence,  people who do not really  want to get
into technical compiler details are handed preconfigured setup.

As stated earlier  'user/template-x.x/'  is a starting point. Of course you
should  also visit 'examples/',  but with template you can just make a copy
of  it and start your own project  which will be totally  native. One thing
to consider is the use of  'pdksh'. As the makefiles really define paths in
an U**X way and also make use of  GNU software, the OS shell may not always
be the right choice.

At this point it is assumed that the GG is fully reliable and all necessary
installation  was  performed  just right(taking  notes  into  account). The
actual out of the box use is very simple. You will need to remeber only few
preparation steps each time  you go into compiler and no surprise will ever
Guru in. The template can be built like this:

  changetaskpri -10
  stack 131072
  sh
  cd libqdev-x.x-bin-m68k/user/template-x.x/
  make


And after the  'make' is complete you will be left in the  'Korn' shell. It
is advised  to wrap first three  lines in a script  that will  transfer you
to 'Korn' shell and thus let you safely fiddle with the compiler.


    
  4.2 Build control macros
When  we mention  build  related  macros  we  really  mean the  contents of
makefiles  who are used to construct compiler command line input. All these
things sit in the following files:


tools/Makefile.i

  Despite the location  all important variables  and declarations are here.
  With  BINARYMODE  variable you can determine how binaries are supposed to
  be built(S, R, R32) package wide! As to  NOSTARTFILES  variable  it  does
  include normal compiler option plus  the define under the same name. This
  is to allow 'qdev' library loader to be used where 'exec' and 'dos' bases
  are already initialized. CPU  and platform related flags  can also be set
  in this file.


lib/Makefile.i

  Library includor defines everything that is needed to just build the lib.
  Note however that  the debug variables are also defined in here! With the
  DEBUGIO attached  somewhere in  CFLAGS you  can activate detailed program
  flow and also  activate your debug output. Consult  'qdev_debug.txt'  for
  more details.


    
  4.3 Library wide macros
Library wide macros are those who  trigger some actions  in the main header
file. Most of them are explained in the 'lib/Makefile'. Certain macros have
effect on the library code while doing the compile, while other can be used
to change/implement something during own binary compilation. It is strongly
recommended to review the  'qdev.h'  file and to actually get familiar with
these macros/triggers before making any use of them by judging on the name!


    
  4.4 Own library loader
As the aim of the project  is to nativise the programs  as much as possible
we wanted  to have macroized library loader that would hide all the library
initialization  from programmer. This  way one can  define  dependencies as
macros,  store them in a separate file  possibly and make  just two  simple
calls that will init and cleanup stuff. While this is essential when coding
with  minimalistic startup in mind  it also pays off  when custom libraries
need to be opened where the full blown startup does not normally do that.

We know that 'libnix'  has that magic library opener, that 'ixemul' can use
autoinits, that you can write your  custom init part, but still this is not
as universal as we would like it to be, because it lacks easy exensibility.
Compile time library  table creation as opposed to static  library table is
superrior. No need to rebuild, no need to prepare special autoinit objects,
no need to edit the code at the  C  level. And  if these are  not arguments
then how about reduced binary size, preprocessor based table expandability,
lack  of library related statements  per base or the gain of extra features
inlined in the loader.

To  find out more on this topic  see the 'qdev_libloader.txt'  quick manual 
and also take a look at  'a-pre_xxxlibs.h', the loader itself. Satisfaction
guaranteed or your old way of dealing with things back! Heh.


    
  4.5 Order of CLI things
Creating and compiling native Amiga programs with  GNU C is not really that
difficult. Having  LibNIX  startup code and  'qdev' library loader  you can
even create combos! To put it simply you can still use the library like any
other library and be forced to link-in  heavy startup code and even heavier
'ixemul' kernel or you can  create lightweight proggies with a bit of extra
CLI input who are as native as possible. Consider this listing:

   1 /*
   2  * template.c (program that does print a text)
   3 */
   4
   5 #define ___QDEV_LIBINIT_NOEXTRAS
   6 #define ___QDEV_LIBINIT_SYS       37
   7 #define ___QDEV_LIBINIT_DOS       37
   8
   9 #include <qdev/a-pre_xxxlibs.h>
  10
  11 int main(void)
  12 {
  13   if (pre_openlibs())
  14   {
  15     FPrintf(Output(), "Hi there!\n");
  16   }
  17
  18   pre_closelibs();
  19
  20   return 0;
  21 }


As you can see the code(line 15) is surrounded by the  'qdev'  lib. loader.
Such setup has one great advantage over classic library access, as you  can
compile it in two ways(using two distinct startups). To produce plain Amiga
executable you would need to type this:

  gcc -O -s -nostdlib -nostartfiles -Dnostartfiles /lib/libnix/ncrt0.o    \
      ^^ ^^ ^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
       1  2         3             4              5                   6
  template.c -o template -L/lib -lqdev
  ^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^
           7           8             9


The binary will be something like 800 bytes and free from BSD API layer. Of
course you can compile it the standard way too,

  gcc -O -s template.c -o template -lqdev


so that  the binary will grow to something like  4 kilos and runtime memory
usage will increase even higher. Notice that  our code is by all means 100%
native. It is the Amiga 'FPrintf()' and not the C library 'fprintf()'. With
that being said the first approach seems best suited. Lets now discuss  CLI
input as numbered(especially beginners should read this):

  1 - This is  the code optimization option. Level of  'O'  was selected to
      build the binary as fast as possible and maintain all code checks.

  2 - This  option  tells the  linker to strip all symbols and/or the debug
      information.

  3 - Quite an important switch! What it does  is to discard  all automatic
      library  linkage. It should  especially be  passed when  doing custom
      compiles.

  4 - This switch  implies that no startup code nor its helper options must
      be passed to the compiler.

  5 - Very  special define that plays a  role in the 'qdev' library loader.
      This must generally be passed whenever doing native compiles!

  6 - Custom  startup code. In this case  this the LibNIX startup code, the
      non-resident  version. Important!  Startup code  must  always  be the
      first object!

  7 - Code  to be compiled(or precompiled objects). At this point  order of
      these objects depends on what you are doing.

  8 - Binary output. You  can specify paths to  static link libraries along
      with libraries afterwards, so that all references will be resolved.

  9 - The  library itself and/or  other libraries preceeded  by the  search
      path.  Note that in  case of resident compile  this  should point  at
      '/lib/libb' - 16bit or '/lib/libb32/libm020' - 32bit.
      

Once you know how to do it, you  will be able to write programs that do not
take  that much memory and their  robustness will never  be limited by some
supervisor code. Consult  'qdev'  autodocs on  how to  implement  different
subsystems  in  case  you  need  'ixemul'  functionalities  such  as signal
handlers in your native code.


    
  4.6 Getting help on API
API  and MACRO autodocs resemble  good, old  manual  page layout very much.
They really lack true MAN markers, thus they are considered clear text with
the addition  of platform type separators and  FF(Form Feed) per page. Each
such document contains quick  TOC,  so it is very easy to locate particular
function.  All you need  is just a text  viewer with search  feature. While
this method is  quite common since the  beginning of visual computing there
are better ways.

Due to the fact that we prefer  plain text as a base and that doubling same
information  multiple times(once per file format) is a waste of storage, we
decided  to  include a  proggy('auto2guide')  that can generate  AmigaGuide
powered autodocs.  Yes,  the resulting documents look similar to those  NDK
comes with.  It is then easy to convert such material to  HTML  or anything
else(check Aminet for such software).

  cd libqdev-?.?-bin-m68k/tools/auto2guide-?.?/
  auto2guide //docs/qdev_macros.txt >//docs/qdev_macros.guide
  auto2guide //docs/qdev_autodocs.txt >//docs/qdev_autodocs.guide


Warning! AmigaGuide documents may  be rendered  with the lack of  backslash
prefixes. For example,  NULL byte that can also be expressed with backslash
and zero ('\0') will only yeld for ('0') in the end... This is in regard to
EXAMPLE section.

Typical  function  description  consists of  the following  sections: NAME,
SYNOPSIS,  FUNCTION, INPUTS, RETURNS,  BASES, NOTES, SEE ALSO, EXAMPLE  and
BUGS. This type of layout is so intuitive that hopefully  no explanation is
necessary(remark, at all times pay attention to NOTES). What may  be new to
experienced  programmers is section called  BASES. It basically gives you a
hint what bases this very function  expects to  be initialized. Internal or
optional  bases  are  square bracketed - [Base], while  indirect  bases are
braced by parentesis - (Base).


    
  4.7 Coding shortcuts
At some point we realised that the documentation alone may not be enough in
order to understand how to apply particular function properly. We then came
up with  the idea of creating  examples(one per  function). And despite the
eggheads  who mostly think that  reading a book equals great understanding,
we  think  that  this is  not  true  for majority  of  information  sources
(including autodocs). Hence a bag of  'examples/'  is to be given.  Luckily
we did fill it with typical  application demos  giving  you the  ability to
quickcode  whatever you need just by  overlooking the right usage. Examples
that begin with '666' prefix are not directly related to functions.


    
  4.8 How to report a bug
If you think you have found a bug that manifests its existance clearly from
within  the library then your  feedback is greatly appreciated. But for the
sake of completness please double check your code before reporting and read
all possible docs! As long as you can prove that the faulty  element is one
of the sybsystems or  single function or  that the problem  lies clearly in
the library  but you are unable to  track it down then  we just expect code
snippet that triggers the problem and we will try to locate it. It would be
nice though if you could include a dump from your favourite memory watchdog
(Enforcer,  CyberGuard,  MuForce +  MuGuardianAngel, etc)  or  on  the  fly
code disassembly of possible problem with offsets.

Of course we accept outputs from other debugging software as long as we can
put our  hands on it,  but memory related hits are essential. On  the other
hand we are totally open for your hints on  what it could be that your code
forces library code to malfunction. And remember, all wierd findings can do
only  good! As  to  bugreport  itself  it is  advised  to  pack  everything
in  a  single  text file,  but if  that seems  impossible  a  file  archive
with its  own  directory  will  do. The  file/directory  should  be  called
'qbug_<nick>_<tv>[.txt|.lha]' where '<nick>' is your nickname and '<tv>' is
the time in seconds since 1st Jan 1978 as a hexadecimal.

Typical bugreport can look like the one presented below. Of course contents
of  that report is artifficial  as the problem  described is  not an  issue
because  documentation states  that parser related  members are  not to  be
copied! You can use the 'Ed' in current shell to write the report the quick
way(make sure that your RTC is set to the right time first):

  ed qbug_hacker_`rx "say d2x(86400*date(i)+time(s))"`.txt window console:


  S: Member 'sd_errors' not copied after doing 'mem_copysmlcb()'!

  Hi There!

  I think i found a bug in 'mem_copysmlcb()' it does not make a copy of the
  errors  pointed  to by source structure. Check the following code out and
  see the output:

  ---BEGIN code.c---
  #include "../gid.h"

  int GID_main(void)
  {
    struct nfo_sml_cb sc;
    struct nfo_sml_cb *nsc;


    txt_memfill(&sc, 0, sizeof(struct nfo_sml_cb));

    sc.sc_sd.sd_dosdevice = "MYDEV0";

    sc.sc_sd.sd_handler = "myfilesystem";

    sc.sc_sd.sd_hantype = QDEV_NFO_SCANML_HANFS;

    sc.sc_sd.sd_device = "mydrive.device";

    sc.sc_sd.sd_unit = "\x00\x00\x00\x00\x00";

    sc.sc_sd.sd_flags = "\x00\x00\x00\x00\x00";

    sc.sc_sd.sd_control = "";

    sc.sc_sd.sd_startup = "";

    sc.sc_sd.sd_stacksize = 4096;

    sc.sc_sd.sd_priority = 0;

    sc.sc_sd.sd_globvec = -1;

    sc.sc_sd.sd_activate = 1;

    sc.sc_sd.sd_errors = "Keyword\n";

    QDEV_NFO_SCANML_PREPDE(&sc.sc_de);

    if ((nsc = mem_copysmlcb(&sc)))
    {
      FPrintf(Output(),
                      "( sc) sd_errors = 0x%08lx\n"
                     "(nsc) sd_errors = 0x%08lx\n",
                          (LONG)sc.sc_sd.sd_errors,
                       (LONG)nsc->sc_sd.sd_errors);

      mem_freesmlcb(nsc);
    }

    return 0;
  }
  ---ENDOF code.c---

  ---BEGIN output---
  (sc)  sd_errors = 0x01F5A688
  (nsc) sd_errors = 0x01F5A688
  ---ENDOF output---

  The addresses are same! One may think that this will cause illegal memory
  reads sooner or later... What do you think?

  Cya,
  Gregory Hacker

  <ESC>sa<RETURN>
  <ESC>q<RETURN>


Then just  e-mail  resulting file as an attachment to us and possibly await
the answer  if you expect it. Please note that we may be unable to reply at
once but we will certainly do that  at some point. And  yet a small  remark
concerning privacy. Be  aware that the reports will  form a library and may
be  available  to the  public,  so  it  is not  a good  place  for  private
corespondence really!



    
5 Complex subsystems

  5.1 File Descriptor Relay
File Descriptor Relay initially written as Stream Wrapper in the early days
of SWLoader  acted as a global redirector. The key was to eliminate  'NIL:'
redirection, so  that programs could actually output  messages and the user
could  see what is going on during bootup on a separate screen. Aside that,
this magic handler was and still is, able to memorise  boot history  thanks
to virtual  rollover files. While  Stream Wrapper was just this and nothing
more  File Descriptor Relay  is way  advanced. For now  FDR  comes with the
following features:

  - Multitarget channels (channel  can relay  data to  virtually  unlimited
    number of destinations/files).

  - Each channel can relay data to built-in, scalable, rollover pseudofile.

  - One of the  existing channels can be marked default so that  'CONSOLE:'
    or '*' call will address it immediately.

  - Primitive  channel finder  which allows to  locate channel  by client's
    address.

  - Symbolic  channel access control(password)  for better  reliability  in
    case of I/O sensitive application.

  - Automated  client signalling  and descriptor closing  on  channel/relay
    termination.

  - Simple pipe implementation that affects WaitForChar() from under single
    process. Pipe channels and relay channels can coexist!

  - Built-in smart  ANSI  escape sequence stripper that in conjunction with
    virtual  files can preserve all  ANSI  while regular streams may or may
    not contain it.

  - Built-in VCR redirector that can remember and blast delays between I/Os
    so that playback with exact timings is possible.

  - Built-in  control CSI  forwarder which acts  as a proxy between channel
    and the console handler FileHandle.

  - Plaintext  line formatter(prefixer) with variety  of options  which can
    make each line to begin with some valuable  information such as current
    time and/or caller address.

  - Plaintext  device statistics always at hand with simple  FGets()  until
    EOF ('type <DEV>:' from CLI).


As you can see  FDR  has evolved into quite a machinery giving a programmer
lots of neat possibilites. At present the only program in this package that
makes use of large portion of features is  'amiscreen'  which tries to copy
on what 'screen' is doing. For your convinience 'amiserver' is available in
'amiscreen/' directory which is a pure FDR you can start by feeding it with
the device name. This way you can experiment with FDR from shell. Note that
'amiserver' is not needed in order to run 'amiscreen'.


    
    5.1.1 Supported packets
ACTION_FINDINPUT         Standard I/O handling. Initializes  client  space.
ACTION_FINDOUTPUT        Standard I/O handling. Initializes  client  space.
ACTION_FINDUPDATE        Standard I/O handling. Initializes  client  space.
ACTION_END               Standard I/O handling. Destroys     client  space.
ACTION_LOCK_RECORD       Raw interface access. See    'dos_getfmfdrelay()'.
ACTION_FREE_RECORD       Raw interface access. See   'dos_freefmfdrelay()'.
ACTION_READ              Status, pipe  and  virtual file related  'Read()'.
ACTION_WRITE             Relay, pipe  and virtual  file related  'Write()'.
ACTION_WAIT_CHAR         Single   tasking  'WaitForChar()'  implementation.
ACTION_TIMER_PACKET      Special  helper packet  used in  ACTION_WAIT_CHAR.
ACTION_SCREEN_MODE       Raw/cooked  mode  switcher and/or  CSI  forwarder.
ACTION_CHANGE_SIGNAL     Stub. Always returns not  OK  state for clearance.
ACTION_SEEK              Stub. Always returns an  OK  state  for clearance.
ACTION_IS_FILESYSTEM     Stub. Always  tells  that  handler  is not  an FS.
ACTION_DISK_INFO         Wrapper. Always  redirects this  packet to target.
ACTION_DIE               Device selftermination. Effective when no clients.


    
    5.1.2 Private MsgPorts
FDR  uses so called  "private message ports"  that can cause soft-interrupt
each  time new packet arrives on that very port. Each  private message port
is tied to the particular FileHandle as returned by 'Open()' function. This
way  it is possible  to inject  client  related  pointer(fh_Arg1 typically)
somewhere in the  DosPacket  and thus be able to access it no matter packet
type. This is absolutely  necessary since different packets  make different
DosPacket  assignments where some of these packets  simply lack client data
pointer due to design decision that  Commodore engineers did take.  Packets
who do not  come with client data pointer set are thought  to be dispatched
in a separate process. But  FDR is meant to be a single tasking handler for
maximum efficiency so...

At this point it may seem it is all  straighten up and the handler does not
need to spawn children processes to do the strict console packets cus there
is that magic guard that keeps  an eye on each packet and glues client data
pointer and  forwards such packets to  the real  handler message  port. Yep
that  works great and the overhead is very little, but there are quirks too
unfortunately. One particular flaw of this solution is that you cannot just
take the message port from FDR FileHandle and try to perform direct handler
conversation nor clone such descriptor! Please do not do that or your Miggy
will crash. Instead try the following code,

   1 void clone_fdr_fh(LONG fd)
   2 {
   3   struct ctl_csh_data ct = {0, 0, 0};
   4   struct Process *pr = (void *)FindTask(NULL);
   5   LONG newfd;
   6
   7   /*
   8    * Make the supplied 'fd' default for this process.
   9   */
  10   ctl_doconswitch(&ct, fd);
  11
  12   /*
  13    * Now you can access -real- handler message port if
  14    * you need to.
  15    * {
  16    *  struct MsgPort *mp = (void *)pr->pr_ConsoleTask;
  17    *
  18    *  ...
  19    * }
  20   */
  21
  22   /*
  23    * This is a copy of the 'fd', you want to buffer it
  24    * and set origin to NULL.
  25   */
  26   newfd = ct.ct_newcon;
  27
  28   ct.ct_newcon = NULL;
  29
  30   /*
  31    * Undo Process structure changes having cloned 'fd'
  32    * as 'newfd' or NULL in the worst case.
  33   */
  34   ctl_undoconswitch(&ct);
  35
  36   return newfd;
  37 }


which  utilises  'ctl_doconswitch()'  which  knows  how to  deal  with  FDR
FileHandles  and can of course be used with other FileHandles too. For your
information, FDR interrupt code lives in a totally separate code segment!


    
    5.1.3 ACTION_LOCK_RECORD
This packet acts as a main  FDR  structure resolver through special routine
called  'dos_getfmfdrelay()'. This  packet also  accepts  masked  signal in
dp_Arg1 so that FDR can be put on hold. It will wait for that signal and if
it did arrive will start processing upcoming packets again. Please use this
feature with extreme care as it is very easy to lockup the OS when handlers
get queried and FDR cannot reply!


    
    5.1.4 ACTION_WAIT_CHAR
FDR  implements  non-buffered,  single context  pipes  who can  utilise the
WaitForChar()  'dos.library'  function. This really allows 'console.device'
alike  keystroke detection so  that programs can  be written in  such a way
that I/O blockage is greatly reduced. Other than that all existing programs
should  be able  to direct  their requests to  FDR  instead of  'CON:'  for 
instance if proxification is necessary.


    
    5.1.5 Pipe limitations
Currently  aside lack of buffering  the only true limitation  is that there
can  be unlimited number of clients on the channel, each of which can write
something, but  only the very first reader  will get the data. The  rest of
readers  will simply receive EOF. I  was questioning myself whether to  add
something  like  "tee read"  and eventually found  that this feature is not
that important right now.


    
    5.1.6 Address checks
Generally  speaking, when a  FDR  channel is in  relay mode  you can attach
files  expressed literally like  'CON:////myconsole',  but that is not all.
You  can also pass  the  addresses  of already opened  FileHandles  without
major limits! This of course does  rise a question of system stability when
such an address does not point at valid FileHandle. What  can  happen then,
will  a disasterous  memory trashing  occurr? The  answer is: No. FDR  does
check for a valid FileHandle by comparing fh_Func1 against the ROM pointer.
If these  do not match then the FileHandle is considered invalid.  You will
probably  notice single illegal read when 'Enforcer' is turned on, but that
is all.

On the other hand such protection mechanism forbids  Output() and all other
custom  FileHandles from being used! As to first case this is only good cus
you must not use your  Output()  from other contexts but there is a problem
with the second case, the custom FileHandles. Fortunately  though  you  can
turn off these address checks by accessing  FDR main structure with special
function called  'dos_getfmfdrelay()'  and stuffing  fm_fdcheck  with NULL.
After that you should call 'dos_freefmfdrelay()' to eliminate the lock.


    
    5.1.7 Relay policy
FDR  never overwrites files as added to the channel thus you must make sure
that  the target already exists  before attaching and that  it is empty. In
other  words all files  are always  accessed using  MODE_OLDFILE  mode  and
a call to 'Seek()' with OFFSET_END is being performed!


    
    5.1.8 Rollover files
FDR  supports so called  virtual rollover  files. There  can be exactly one
such  file per channel and  15 of them per process. These virtual files are
totally  user  definable in the  terms of  size and are  intended  to store
information circularily. Primary goal of this was to provide quick rollback
of  information that is  all relevant in a  small scale of  time so that no
huge  logs are to be unnecessarily  produced. This  feature is  still being
used in the  SWLoader  to memorise bootlog and will probably be utilised in
the further incarnations.

Please note that  FDR virtual rollover files  can always  be read  from the
beginning to  EOF only. There  is no way to  set the cursor  to  particular
position!  Fyi rollover files are  not a special  FDR  feature. You can add
them to your code using 'han_rollifh()'  + 'mem_openifh()'/'mem_closeifh()'
calls. Such circularity is also being used in the  'qfill'  program to form
a binary pseudo-infinite buffer.


    
    5.1.9 Status explained
FDR  tries to be firendly to the user  and comes with  built-in status that
can be requested with simple 'type' CLI command. Suppose that  'FDR0:'  was
started and channel  'mychan' was created. Plus that channel can relay data
to some  'CON:'  handler. What you would see by executing  'type FDR0:'  is
this:

  > run amiserver FDR0:
  > echo >"FDR0:mychan df CON:////myconsole"
  > type FDR0:

  D 001       000       001       256 254 000           "FDR0:" 
  ^ ^^^       ^^^       ^^^       ^^^^^^^^^^^           ^^^^^^^
  1   2         3         4                 5                 6

  C 001       000                 000:00:00:09 -D -P -T "mychan" "" 
  ^ ^^^       ^^^                 ^^^^^^^^^^^^ ^^ ^^ ^^ ^^^^^^^^ ^^
  7   8         9                           10 11 12 13       14 15

  F $0067077F $01B8A898 $00000000 0000000000   +A +B +C "CON:////myconsole"
  ^ ^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^^   ^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^
  16       17        18        19         20   21 22 23                  24


Each status dump of  File Descriptor Relay  comes with the 'D' entry at the
beginning that describes the device  basic status. Then  all  the  channels
marked with 'C' follow. Each channel holds a list of files marked with 'F'.
Follow the numbers below indicators to get their meaning:

   1 - Device entry marker.

   2 - Total number of files attached. A sum  of  entries  taken  from  all
       possible channels.

   3 - Total number of clients connected. Currently there is a limit of 256
       clients. Client  space is preallocated! This  means that even in low
       memory situations clients will still be accepted.

   4 - Total number of channels formed. Channel  space is not preallocated!

   5 - First integer  means how many loops to flush(this can be set to 0 if
       no  abandoned  channel removal  is needed). Second  counts down each
       access. Third shows how many abandoned channels were flushed.

   6 - DOS device name.

   7 - Channel entry marker.

   8 - Number of files this channel has to deliver data to. Currently there
       are no limits.

   9 - Number  of clients/callers on this  channel right now(at the time of
       status creation).

  10 - DateStamp  indicating how  long this channel  exists in ddd:hh:mm:ss
       format.

  11 - Default route indicator so that  'CONSOLE:'  or  '*'  request can be
       directed  to this channel. By  default  implicit  NULL  channel will
       accept all such packets.

  12 - Is channel password  protected indicator. If the channel is set as a
       default  and is password  protected then other channel cannot be set
       the default without unmarking current channel first.

  13 - Should channel selfterminate and close all files or signal caller on
       flush indicator.

  14 - Channel name.

  15 - Channel prefixation. This  is only useful when data to be relayed is
       plain text. You can place there selfexpanding options. See autodocs.

  16 - File entry marker.

  17 - Address of FileHandle to relay to. This should be used when removing
       file from the list.

  18 - Address of  the client who did attach  the file. This address is not
       being validated at any time so be careful when using signalling!

  19 - Signal to send to  the client who did attach  the file if channel or
       FDR goes down. Please note that if this is non-zero then closing the
       file  has  no  effect! File  closing  and  signalling  are  mutually
       exclusive.

  20 - Number  of transport failures per  this file. Write  errors in other
       words.

  21 - Should ANSI pass through indicator. This indicator can be in form of
       '-A' - no ANSI, '*A' - forward control CSI here and '*V' - VCR file.
       Last two cases imply pass the ANSI through.

  22 - Should buffered  calls be used when  relaying. Please note that this
       setting  can  only  be effectively  changed when no writes were made
       yet for this file. Eventually this indicator will change to the '-F'
       or '+F' letter in case you requested  data flushes. This change does
       not impact buffering mode!

  23 - Should  this  file  be automatically  closed down when channel is to
       be removed or FDR goes down indicator.

  24 - Short literal file identification. This filename can also be used to
       remove it from channel.


Refer to autodocs on how to control FDR from  C with 'dos_ctrlfdrelay()' or
simply check the 'dos_addfdrelay()' description for literal options.


    
  5.2 Link Point
Link Point  is a simplified filesystem  mapper that allows to reflect files
and/or  stream handlers as regular  files thus making  it possible  to feed
restrictive  software  with  data from  different sources. At  the time  LP
concept did appear  TCP/IP  was the main objective as the goal was to allow
Internet  radio to be streamed by WiFi capable devices that cannot directly
reach  global  network by the means of  anti-features  of the  firmware. At
present LP does not offer built-in network support(this was removed) but is
able to do that through external DOS handlers such as  'TCP:' for instance.
LP went through a long mastering stage and for now it is capable of:

  - Simulating root filesystem(without  directories) with references stored
    in the comment fields.

  - Maintaining  address consistency of  the file slots/chain, so that root
    container can be refreshed at any point of operation.

  - Controlling stream size, taking  care of access control, cooperate with
    auxiliary programs and correlate client activity with resource usage.

  - Utilising user friendly  LPX  interface, so  that all  arguments can be
    entered along mapping.

  - Emulating locks  at the bare minimum to make sure that all software can
    benefit.

  - Emulating 'RHTTP:' and 'HTTP:' devices thanks to 'TCP:'. It is possible
    to make these devices OS wide too.

  - Protecting  from accessing circular objects to avoid deadlocks and race
    conditions.

  - Locating objects very fast thanks to 32 bit  FNV1a hash routine used to
    establish file tree.

  - Multitasking,  so  each  mapping does the  I/O  from  its  own process.


Aside of exporting LP contents over various network programs LP can also be
exported itself through  Timo Rossi's  AmigaNetFS  and hence be used across
other Amigas. You should definetly  visit the  'linkpoint/' directory for a
standalone  program that comes with a nice set of tips and tricks.


    
    5.2.1 Supported packets
ACTION_LOCATE_OBJECT     Allocates client  space and grants an object lock.
ACTION_COPY_DIR          Makes a copy of client  slot/lock currently given.
ACTION_PARENT            Stub. Will always return 0 meaning root directory.
ACTION_SAME_LOCK         Checks if two client slots/locks reference device.
ACTION_EXAMINE_OBJECT    Requests  FIB feed  of  currently  locked  object.
ACTION_EXAMINE_NEXT      Requests  next object taking current  FIB pointer.
ACTION_FREE_LOCK         Discards  the lock  and deallocates  client space.

ACTION_FINDINPUT         Sets up  client and accesses  mapping for reading.
ACTION_FINDOUTPUT        Sets up  client and accesses  mapping for writing.
ACTION_FINDUPDATE        Sets up client and accesses mapping non-exclusive.
ACTION_FH_FROM_LOCK      Associates previously located object with mapping.
ACTION_COPY_DIR_FH       Copies   client  slot/lock   from  legitimate  FH.
ACTION_EXAMINE_FH        Requests  FIB feed  of  currently opened file(FH).
ACTION_PARENT_FH         Grants access to the  root using fake volume node.
ACTION_SET_PROTECT       Stub  that does nothing. An  OK  will be returned.
ACTION_SET_COMMENT       Stub  that does nothing. An  OK  will be returned.
ACTION_SET_DATE          Stub  that does nothing. An  OK  will be returned.
ACTION_READ              Forwards  this packet to mapping's proc. 'Read()'.
ACTION_WRITE             Forwards this packet to mapping's proc. 'Write()'.
ACTION_SEEK              Forwards  this packet to mapping's proc. 'Seek()'.
ACTION_END               Terminates  mapping association  and frees client.

ACTION_IS_FILESYSTEM     Depending on global  LP setting returns OK or not.
ACTION_INFO              Fills  InfoData, id_NumSoftErrors == ommited objs.
ACTION_DISK_INFO         Fills  InfoData, id_NumSoftErrors == ommited objs.
ACTION_CURRENT_VOLUME    Returns pointer to  fake volume for compatibility.
ACTION_INHIBIT           Flushes  and/or rebuilds  root directory contents.
ACTION_WRITE_PROTECT     Write  protects  all  mappings,  these in use too.
ACTION_DIE               Tells the  handler to go down if clients are gone.


    
    5.2.2 Packet route
As the  LP  handles mappings in separate contexts to avoid  I/O stalls that
may  be caused  by different  handlers, certain  client  packets  such  as:
ACTION_FIND#?, ACTION_FH_FROM_LOCK,  ACTION_READ, ACTION_WRITE, ACTION_SEEK
and ACTION_END  must be forwarded to the corresponding subprocess. There is
no direct client-mapping communication since it would be impossible then to
implement  effective parent-child  synchronisation. Note  however that only
the queries are being  forwarded, replies are  point-to-point though. Below
is a  quick diagram that explains  how callers communicate  with the LP and
how LP deals with requests.
           
    +--------+             +--------+             +--------+
    |        |  ACTION_#?  |        |  ACTION_#?  |        |  REPLY
    | CLIENT | ----------> |   LP   | - - - - - > | MAP PR | - - - - - ,
    |        |    all      |       2|    fwd      |       3|            
    |        |             +--------+             +--------+           |
    |        |                 |                                        
    |        |   DIRECT REPLY  |                                       |
    |        | <---------------'                                        
    |       1| < - - - - - - - - - - - - - - - - - - - - - - - - - - - '
    +--------+


As long as packets are  not to be forwarded or an error was detected by the
LP  a direct reply will be attempted otherwise  mapping's process will have
to reply.


    
    5.2.3 Context behaviour
In  LP  all lock related packets are isolated from mappings in the way that
obtaining  lock  does  not imply  target access  on a file  level. This  is
considered  healthy, because  no  subprocess need to be created in order to
examine  the  object. On the other hand  LP  does peek the target on a lock
level directly,  which may not always be the right thing to do. Fortunately
though most lock interfaces are well behaved and do not block. As to stream
handlers  they mostly  lack  lock interface  completly,  but  the  risk  of
blockage  is still there  since they may  be waiting  for an event and thus
be unable to process new packets at that time... One simple solution to the
latter problem is to use  'wrapmount'  program that is able to disable lock
related packets migration entirely.

When  talking about  mapping subprocesses  they can only  be created by the
supply of ACTION_FIND#?  and  ACTION_FH_FROM_LOCK packets and terminated on
ACTION_END arrival. The  only other  thing that is  able to  terminate  the
subprocess is  'timer.device'. The use of timer was introduced so that dead
mappings can  be flushed off the system in a  piecewise way thus protecting
from  resource exhaustion. It  all works by renewing  timer requests  every
packet  received. If the delay is too  big then private  termination signal
hits the subprocess and brings it down along with resource deallocation. LP
gets  then  notified  about that  through  client  packet,  so that it will
not  forward  any new  packets  from that  client  but will  reply with  an
ERROR_OBJECT_WRONG_TYPE.

Auxiliary  CLI  process creation and synchronisation is a bit trickier. All
CLI processes get started in the main LP process, but at that time they are
told to wait until mapping subprocess is up and running. This in turn makes
it dead simple to handle error cases since the legitimate  CLI entry is not
yet executing. The execution starts when mapping subprocess gains access to
the  target  file. It then sends  synchronisation signal which gives former
CLI command a spin. The tricky part is that even though the CLI command was
initiated  by the LP it now depends on mapping subprocess as  it alters the
client slot! What  that means is CLI process must die first so that mapping
process  can effectively die too. But note that when  mapping subprocess is
complete and the CLI process is still executing the first one is considered
a dead body only. Fortunately all gets sorted out on CLI completion.

In  conclusion, such  a  design allows  CLI command to be  "shared"  across
mappings so that stream splitting is essentially possible. In major, LP was
designed with that  in mind and believe  it or not  it works. All  you need
is  just a multiclient  pipe handler such as 'fifo-handler'  and some  sort
of stream agent like 'qfill' for instance.


    
    5.2.4 Limitations
Currently  there is no support for strict console packets and its uncertain
if  they will ever be implemented. Although  comfortable handler aliasation
would be  available this way  its use is  rather questionable. Also  direct
filesystem  manipulation is not  possible at this  time. You really need to
alter the source filesystem/buffer and refresh the contents of the  LP. You
can  of  course  implement some sort of notification  so the  refreshing is
automatic. The  most disturbing  limitation is the  length of  comments who
currently  store filenames  of the targets. We consider  a switch to larger
buffer  but that will have  to wait as there  are more  important things to
work on right now.


    
  5.3 DOS device unmounter
Sometimes  there is a deep need to unmount or remount the volume or handler
in order to change some mount entry parameters. AmigaOS handlers  are known
to  implement  special packet called  ACTION_DIE  which in conjunction with
'assign' command allows to  dismount the volume or handler quite safely and
aside memory leaks that cannot be  avoided this seems to work. On the other
hand it proves completly  useless when handler or  filesystem are in use or
code  does  not allow  ACTION_DIE. So what does a typical  Amiga fan do? Of
course, he/she tries to  ACTION_INHIBIT the volume maybe and to kick device
node from the list.

Chances  are that your filesystem  does support  volume changes and that it
did detach  from medium,  but the process is still running. The worst thing
that can be done is to strip device node only. This is  because even though
you  cannot  access this volume anymore, the process is fully in touch with
the  partition. The real  danger here is that  after mounting  such  volume
again there will  be now two processes  that are unaware of  each other and
who are tied to single partition. Caboom, you loose!

For that reason 'ctl_devunmount()' was created. This single function allows
to get rid of the volume/device or handler in a way that the process behind
it terminates in peace no matter if it supports ACTION_DIE or not. All this
is fully synchronised and can only happen when handler does not process any
packets thus data integrity is to be cared about. For  user utility see the
'fsmount' tool.


    
    5.3.1 Clean method
This subsystem can be used in a way described at the very beginning of this
section. The  difference is  that you do not  need to use separate tools to
send the  ACTION_DIE  packet and then to strip the volume and device nodes.
All  this is fully automatic. Generally this method is considered to be the
OS  friendly way of  dismounting devices,  read: clean, but devices may not
always be able to go down.


    
    5.3.2 Shield method
In  case when a filesystem or handler refuse to go down  'ctl_devunmount()'
can attempt so called forcible unmounting. The  simpliest way of doing this
would be to just freeze the process and strip device node, but clearly that
is too  dirty and would eventually  cause lockups. Such  that all processes
tied to the  handler would simply  hang. There  exists also a risk  of data
integrity loss from partition  point of view because you never know what is
filesystem  doing at the time  when you take away  CPU from it. Fortunately
there is a better way. Instead  of keeping  a zombie in  memory we can tell
the process to just exit as if it ended the execution.

This  of course does  not solve  synchronisation problem, but look how nice
instead  of murder, euthanasia ;-) . So  having that as a replacement it is
time to  detect when handler's activity  ceases. It is not easy though, but
hopefully  'ctl_devunmount()' does that and when it detects that handler is
'Wait()'ing  then it attempts to make sure its message port is empty and if
so then  it converts it a little bit  so that  packets instead of migrating
to  the handler go to stub handler  where they get replied with an error so
that programs cannot hang.

Next step it does is to locate all the children of the main process and put
them all to sleep. Then it injects short assembly  inline into their bodies
which is responsible for transferring them to exit and  wakes them up. They
do disappear instantly and the OS deallocates their explicit resources such
as memory  list  entries,  segments,  TCB  an its members. Next  step is to
strip  volume and device  nodes and try to  deallocate them. At  this point
handler does not exist anymore and the possible  partition is  shielded and
ready to be mounted again without the risk of data disintegration.



    
6 Obviously mumbo-jumbo

  6.1 Internal bases
Yes, [un]fortunately  some of the  'qdev' library  objects  define internal
library bases,  so  that  they  are  optional  thus do not require explicit
declaration  anywhere  in  the code. This  also  makes  it  possible to use
resident  library branches without problems. The following table shows what
functions initiate internal library instance:

---------------------------------------------------------------------------
| Function               | Shared library        | Library base           |
---------------------------------------------------------------------------
| crt_createargv()       | exec.library          | SysBase                |
| crt_destroyargv()      | exec.library          | SysBase                |
| crt_exitmethod()       | exec.library          | SysBase                |
| crt_freeinstance()     | exec.library          | SysBase                |
| crt_initmethod()       | exec.library          | SysBase                |
| crt_newinstance()      | exec.library          | SysBase                |
| ctl_addidcmphandler    | exec.library          | SysBase                |
| ctl_openconscreen()    | diskfont.library      | DiskfontBase           |
| ctl_rearrangecon()     | intuition.library     | IntuitionBase        C |
|                        | mathffp.library       | MathBase             C |
|                        | exec.library          | SysBase                |
| ctl_remidcmphandler    | exec.library          | SysBase                |
| ctl_zoomifycon()       | intuition.library     | IntuitionBase        C |
|                        | mathffp.library       | MathBase             C |
|                        | exec.library          | SysBase                |
| dos_dopacket()         | exec.library          | SysBase                |
| han_binaryifh          | exec.library          | SysBase                |
| han_rollifh()          | exec.library          | SysBase                |
| han_rwifh()            | exec.library          | SysBase                |
| han_termifh            | exec.library          | SysBase                |
| mem_cooperate          | exec.library          | SysBase                |
| mem_grabqarea          | exec.library          | SysBase                |
| mem_loadpicture()      | guigfx.library        | GuiGFXBase             |
| mem_obtainhotvec()     | exec.library          | SysBase                |
| mem_resolvehotvec()    | exec.library          | SysBase                |
| mem_signalsafe()       | exec.library          | SysBase                |
| nfo_getsystime()       | timer.device          | TimerBase              |
|                        | exec.library          | SysBase                |
| nfo_typeofgfxmem()     | cybergraphics.library | CyberGfxBase           |
| ___ctl_animsubtask()   | exec.library          | SysBase                |
| ___ctl_devhandler()    | exec.library          | SysBase                |
| ___ctl_drawingsubtask()| exec.library          | SysBase                |
| ___ctl_idcmphandler()  | exec.library          | SysBase                |
| ___ctl_layerbackfill() | graphics.library      | GfxBase              C |
| ___ctl_osdsubtask()    | intuition.library     | IntuitionBase        C |
|                        | layers.library        | LayersBase           C |
| ___ctl_realforbid()    | exec.library          | SysBase                |
| ___ctl_realpermit()    | exec.library          | SysBase                |
| ___ctl_redrawperform() | graphics.library      | GfxBase              C |
|                        | exec.library          | SysBase                |
| ___ctl_refreshimage()  | exec.library          | SysBase                |
| ___ctl_putosdtext()    | graphics.library      | GfxBase              C |
| ___ctl_trigcode()      | exec.library          | SysBase                |
| ___ctl_trigperform()   | graphics.library      | GfxBase              C |
|                        | intuition.library     | IntuitionBase        C |
|                        | exec.library          | SysBase                |
| ___ctl_startanim()     | exec.library          | SysBase                |
| ___ctl_stopanim()      | exec.library          | SysBase                |
| ___ctl_trigsubtask()   | exec.library          | SysBase                |
| ___ctl_xxxviewctrl()   | exec.library          | SysBase                |
| ___ctl_zoomsubtask()   | exec.library          | SysBase                |
| ___dos_clihandler()    | exec.library          | SysBase                |
| ___dos_packetglue()    | exec.library          | SysBase                |
| ___dos_prochandler()   | exec.library          | SysBase                |
| ___dos_vcrdelay()      | timer.device          | TimerBase              |
| ___mem_createpicbmap() | guigfx.library        | GuiGFXBase           C |
| ___mem_newswitch       | exec.library          | SysBase                |
| ___mem_packethandler() | exec.library          | SysBase                |
| ___mem_readfd()        | exec.library          | SysBase                |
| ___qdev_prv_initfunc() | exec.library          | SysBase                |
| ___qdev_prv_putfunc()  | exec.library          | SysBase                |
---------------------------------------------------------------------------


    
  6.2 Cached bases
Aside internal bases, cached global bases are to be found amongst "control"
related  functions that may  transfer the control  outside current context.
Caching  is a much better  approach than manipulating the  A4 register! See
the structures on where the cached pointers are used.

---------------------------------------------------------------------------
| Function               | Shared library        | Library base           |
---------------------------------------------------------------------------
| ctl_addconlogo()       | graphics.library      | GfxBase                |
| ctl_addviewctrl()      | graphics.library      | GfxBase                |
|                        | intuition.library     | IntuitionBase          |
|                        | layers.library        | LayersBase             |
| ctl_openconscreen()    | intuition.library     | IntuitionBase          |
|                        | graphics.library      | GfxBase                |
|                        | mathffp.library       | MathBase               |
---------------------------------------------------------------------------

Warning! As of release  1.2 cached bases no longer directly point at global
bases! They are tied to  process local bases! To  access global base out of
local one use QBASERESOLVE() macro.


    
  6.3 IEEE arithmetics
As the library  progressed and started to  shift into the native direction,
we  did notice that 'gcc'  IEEE wrappers are not very pure and the resident
code  crashes heavily under some  circumstances. We had to  workaround this
problem  by replacing  normal arithmetics  by direct  calls to  Amiga  math
libraries. At present  only bare minimum(basic) of ops are supported. These
are: MFADD() - Addition,  MFSUB() - Subtraction,  MFMUL() - Multiplication,
MFDIV() - Division, MFFIX() - Float  conversion, MFFLT() - Int. conversion,
MFCMP() - Comparison, MFCLE() - Less/equal  helper, MFCGE() - Greater/equal
helper.

By default all arithmetics is being done on  'float's and so initialization
of 'mathieeesingbas.library', which is a part of the ROM is necessary. This
can easily be changed by defining macro called  ___QDEV_DOUBLEPREC  so that
the  very same macros will work on  'double's. But this time  you will need
to initialize  'mathieeedoubbas.library'  which is a disk based library! At
all  times it is desired to  use the   MFARITH  datatype  declarator  which
defines 'float' or 'double' depending on state of control macro.

Warning! If you must use non-IEEE arithmetics which is possible by defining
___QDEV_NOIEEEMATH then there may be a problem in a matter of float layout!
Compiler('gcc')  assumes  IEEE(EM) but  FFP(ME)  format  is  different thus
immediate  variable initialisation will call  for wrong results! Value that
is  known at compilation time  must be passed to/assigned  using  MFVALUE()
macro! This  unfortunately  makes it unable  to define  such a value beyond
function body...

Note! By  default all library subsystems who  do some arithmetic ops depend
on  'mathffp.library'! This is because 'mathieeesingbas.library' in ROM V40
is broken(division specifically)!


    
  6.4 Modular segments
Modular  segments are  essentially possible with  'a-pre_xxxseg.h'(see this
header on how to use) macroset. These can act like private libraries  or be
the extra code  segments that can  be scatterloaded inside running code, so
that they  may stay in the memory  when base  code was  unloaded. Currently
modular segments  are  being used as  #?.lo[c|g]o  containers and interrupt
handler loaders in  FDR  and device  unmounter core. But  you  can  do much
more with it. You can for instance port  'glib' modules with it very easily
as symbol binding is also supported.

Unlike Amiga shared libraries, modular segments do not require complex init
code in order to use them. This is just ideal solution for those who do not
want to learn how a shared library works nor to maintain assembly interface
along  with  offsets  and  stuff. Symbol  binding allows the  API/ABI to be
altered in such a way that function pointers can change their place without
any side  effects! Unfortunately  there are limitations too. One of them is
the code model, which can only be non-resident.

Modular  segments should really be treated like a task private code, but as
long as you write your code in a reentrant way their API can be made public
so  that your module qualifies  as a shared object. There  is just one rule
you  must stick to. Do not  reference anything from the outside of function
body  and all should be just fine. This way  modular software interrupts or
public exceptions can easily be implemented.


    
  6.5 A4 register issue
Old  Amiga sharks know, but inexpirienced  newcomers may not  that resident
binary  model is somewhat restricted  by the lack of automatic A4  register
setup upon new context spawn. This is especially the case when coding using
LibNIX  as its resident  startup  code lacks  'geta4()'  subroutine! Please
consult  'qdev_macros.txt'  on how  to manually  deal with  A4  register in
your code that is ought to be pure. See the '__LOADA4()'  and  '__SAVEA4()'
macros. Just to remind you, the A4 register always carries the base address
responsible for global variables.


    
    6.5.1 Callbacks/Hooks
Recently we did discover  that it is unsafe to  reference indirect ROM code
(the  one that gets  called  through user  segment) and  global data inside
callbacks attempted in ROM space while the binary is  resident. The problem
lies in wrong A4 register contents as you may have guessed but things are a
bit more fuzzy that just saving and restoring that single CPU  register. It
turns out to be  also a matter of current  set of registers that have to be
preserved before the call is to take place. And that may or may not include
just the A4!

One such problematic case is 'InternalLoadSeg()' which takes function table
that provides memory management and file I/O function pointers. All is just
fine if these are direct  AllocMem()/FreeMem()/Read()  resolved through LVO
against bases. Unfortunately  things change if these  functions are wrapped
in your code  and/or they reference  bases defined as global. But it is not
only a  case of globals, this is also how  GCC  produces code per function.
And it may not generate a code to save the registers at all...

It may  happen that your callback  ditches the registers  that the original
callback  would  not which in turn  makes the  ROM  code bleed  really bad.
Happily, there is a cure for that. You  can create  a driver  function with
QDEV_HLP_DFUNC()  macro that will take care of register contents. But there
left just one tiny, and nasty at the  same time problem. How to pass backed
up  A4 register if function does  not  take some  sort of data pointer? You
cannot just buffer it in a global variable!

To solve  this problem, as of release  1.1  of the library  so called  "hot
vector arrays"  have  been  implemented. These  are address arrays that get
created at runtime and are stored in tc_MemEntry list of a task or process.
This way you can obtain such array at any stage in your program safely thus
be  able to pass and restore the  A4  register in the callback. See the API
reference and code in 'example/' directory for more details.


    
  6.6 Undocumented routines
Most of  the time you will like to look into  API documentation but you may
be unable  to find all the routines there. This is because some of them are
almost identical to  their prototypes so  there is no point  to double  the
information, although  you will find the note  that such a function exists.
Below is a table of such routines:

---------------------------------------------------------------------------
| Prototype              | Cousin                | Description            |
---------------------------------------------------------------------------
| cnv_ALtoULONG()        | cnv_ALtoLONG()        | Singed converter       |
|                        | cnv_ALtoQUAD()        | Singed 64bit conv.     |
|                        | cnv_ALtoUQUAD()       | Unsigned 64bit c.      |
| cnv_AtoULONG()         | cnv_AtoLONG()         | Singed converter       |
|                        | cnv_AtoQUAD()         | Singed 64bit conv.     |
|                        | cnv_AtoUQUAD()        | Unsigned 64bit c.      |
| cnv_ULONGtoA()         | cnv_LONGtoA()         | Singed converter       |
|                        | cnv_QUADtoA()         | Singed 64bit conv.     |
|                        | cnv_UQUADtoA()        | Unsigned 64bit c.      |
| cnv_ULONGtoBITS()      | cnv_UQUADtoBITS()     | 64bit input ver.       |
| mem_scanlbl()          | mem_scanlblncc()      | Skips C comments       |
| txt_bstrncat()         | txt_bstrncatlc()      | Lower case output      |
|                        | txt_bstrncatuc()      | Upper case output      |
| txt_bstrnpcat()        | txt_bstrnpcatlc()     | Lower case output      |
|                        | txt_bstrnpcatuc()     | Upper case output      |
| txt_datdat()           | txt_datidat()         | Case insensitive       |
| txt_fnv128hash()       | txt_fnv128ihash()     | Case insensitive       |
| txt_fnv64hash()        | txt_fnv64ihash()      | Case insensitive       |
| txt_memcmp()           | txt_memicmp()         | Case insensitive       |
| txt_pjw64hash()        | txt_pjw64ihash()      | Case insensitive       |
| txt_quickhash()        | txt_quickihash()      | Case insensitive       |
| txt_strboth()          | txt_striboth()        | Case insensitive       |
| txt_strchr()           | txt_strichr()         | Case insensitive       |
| txt_strncat()          | txt_strncatlc()       | Lower case output      |
|                        | txt_strncatuc()       | Upper case output      |
| txt_strnpcat()         | txt_strnpcatlc()      | Lower case output      |
|                        | txt_strnpcatuc()      | Upper case output      |
| txt_strpat()           | txt_stripat()         | Case insensitive       |
| txt_strstr()           | txt_stristr()         | Case insensitive       |
---------------------------------------------------------------------------


    
  6.7 Local Base Support
Release  1.2  adds  Local Base Support (LBS)  which is active for Amiga and
Portable objects. LBS  is an extension that allows to modify shared library
jump table  per context (locally). In contrast, using 'SetFunction()' it is
possible  to  alter jump  table  globally  only. LBS  inserts just one more
MOVEA.L (An),A6 instruction during compiling before actual JSR  which makes
it practically unnoticable (in terms of overhead) starting from  68030  and
up. On 68000 this needs extra  12 clock cycles. This way function calls can
be made using alternate jump table which affects only current process.

LBS consists of two parts: ___QLBS_NT_LOCALBASE  and  ___QLBS_NT_LOCALVECT.
Local base is nothing more than a Node (an alias)  that addresses real base
twice (changable pointer and reference) initially. Local  vector/jump table
contains  special call entry  addresses instead  of the function addresses.
This way table can easily  be fixed or manipulated without the need to save
each address first. But also thanks to such  a design relative and absolute
addressing are  possible with custom A6 register setup! By default no local
jump  table is ever allocated  so function calls  are direct (as if LBS was
not there). Local base gets linked from separate object  (when needed) that
can be found in the library.

Under  normal circumstances (using bases declared globally) coding with LBS
is  totally transparent. The  programmer does  not have to write extra code
nor add extra statements. Note however that when 'qlbs.h' has been included
(always before protos and inlines) and  bases are declared function-private
there is a need to use  QBASEDECL2()  macro! This is because function calls
are always attempted against local base which starts with the  'L_' prefix.
So having 'SysBase' there will be also 'L_SysBase'. It is important to tell
the compiler that it should reference function-private  'L_SysBase'  rather
than the global 'L_SysBase' and that is what QBASEDECL2() does.

Let us tell something about key uses. LBS allows one to monitor shared lib.
calls and thus program flow without hacking on the OS! LBS makes it easy to
implement missing shared library functions (this is the case when  software
was  compiled using  newer inlines  and  launched  under earlier OS/library
releases) without the need to touch actual program code. One just allocates
new jump table, imports the contents of a main library jump table, attaches
missing functions, activates it and voila. See the 'mem_xxxjumptable()' and
'mem_xxxjtslot()'  functions in autodocs for more details or go straight to
examples.



    
7 FAQ

  7.1 Questions and answers
Of  course no nowadays  manual can stay without Frequently Asked Questions,
so here they are. We  will try to bank all your doubts in  here  along with
answers, so if you do not understand something feel free to ask. Important!
We  reserve the right to make  a selection on questions we receive,  but as
long  as they are project related or do not go off-topic too much they will
appear under this chapter.


    
    7.1.1 Package related
   1 Can I wrap selected 'qdev' code in a true Amiga shared library so that
     my programs will use memory more efficiently?

      Sure you can. Remeber though that this is only possible with resident
      branches!


   2 How to use  'qdev'  own debug facility, there is nothing about this in
     the manual?

      Debug  support was described  in a separate article that is  availabe
      under 'qdev_debug.txt'. Do not forget to visit the 'examples/' too.


   3 I see that the 'include/' directory contains some private headers, can
     a programmer use them?

      Of course,  that is their purpose to help one access private structs.
      if there is no other, better way.


   4 Why is the autodocs and macro layout so weirdly unalphabetical and why
     it often lacks functions that do the similar job?

      The  reason for that is to  keep object family in one place, but also
      due to  API  principle that sorts functions in  A, P, I  order. It is
      true that many  text related functions such as 'txt_strcmp()' are not
      doubly  described due to their  non-case insensitive twin brother. So
      you will not find an entry for 'txt_stricmp()' for example but a note
      that such function exists.


   5 Why does the  'mss'  do animated  logo files  faster than  'viewlogo'?

      This is because 'mss' activates frame optimization in the logo loader
      and  'viewlogo'  does not. Main  reason for that is to have reference
      when something is wrong with the optimizer.


   6 What do  2 letter acronyms under the 'Stat' entry per remark in change
     logs mean?

      Currently there are four shorts and they mean:  BD - Bug Detected(but
      not fixed), BF - Bug Fixed, FA - Feature Added, NO - Notice.


   7 I found that this  LZW  compressor that  comes with the library cannot
     really crunch binaries why?

      It  is very simple implementation that does not do any sorting before
      compression, thus  it is best for compressing  bitmaps who often come
      in large portions of 0's.


   8 Why static link  library and not a shared  Amiga  library, any reason?

      First of all this is  all-purpose library so converting it into Amiga
      library would not be very smart because  each, even smallest  program
      would require  to load quite a monster into memory! Secondly,  static
      link library allows you to bypass functions that other functions need
      so the gain is obvious - wrappers can be made really easy.


   9 Main  library header is huge! Would  not it be better to scatter stuff
     across N smaller ones?

      Yes, that is true. We consider  chapter-based-split  but nobody knows
      when this will happen and how it will be ordered.


  10 Bases: SysBase and DOSBase seem to disappear from object when compiled
     standalone while using 'a-pre_xxxlibs.h'! What the hell is going on?

      Stuff $(NOSTARTFILES) in $(CFLAGS). Sorry about that, but there is no
      other, better way to make the loader compatible with fat startups.


  11 Why is the date written as (dd/mm/yyyy) instead of standard (d.m.yy) ?

      Original date format Commodore programmers introduced allows to store
      year as a two digit value only. This sucks and the  'version' command
      will show it wrong if its written using four digits. Hence the format
      was changed to mitigate this problem.


  12 Should one be concerned about the  tools this package  comes with from
     release to release even though their version information is same?

      Yes. Each  tool is being  rebuilt when new  package is to be released
      which  may have impact on bugs  found in the  previous builds. Please
      note  that since version  1.1  of the package  every tool contains an
      extended  version information  telling library  details. As a general
      rule  you should update  all tools you  have copied to system drawers
      upon new package release.


    
    7.1.2 Programming
   1 Virtual files are cool,  but they seem not to work after my process is
     gone and the other process wants to I/O, what is going on?

      Virtual files  use private task exception  mechanism to do the I/O so
      the process that did create them must be up.


   2 Is it  possible to display graphics on non-console related screen with 
     'ctl_addconlogof()' function?

      Yes, see the 'examples/mem_xxxpicture/' on how to prepare such screen
      or window properly.


   3 How  do I convert each  animation frame as cropped from the whole into
     Intuition Image format with Personal Paint 7.x?

      This  is  easy, go to  'misc/'  directory and install the script that
      allows to export  Anim brush to other formats, including  C  headers.
      Then when exporting apply zero  aligner to first frame, such as this:
      '<filename>000.h'.


   4 How can i create my own logo easily after i have saved all frames as C
     headers that contain Intuition Images?

      The  easiest way is to  copy one of the  existing logos,  say 'boing'
      directory under new name, remove all existing frames,  place your own
      frames, fix the name and delays in the 'Makefile' and just 'make' it.


   5 Are  #?.lo[c|g]o  files being kept in memory after they were processed
     by 'mem_loadpicture()' function?

      No, logo segment is being freed, so that the only thing that lives in
      memory are remapped bitmaps.


   6 Is  'mem_remapbitmap2()' slower than  'mem_remapbitmap()' function and
     why?

      Yes, 'mem_remapbitmap2()' is slower because it was written totally in
      C, plus is is able to convert only 8 pixels at a time. But beneficial
      can be the fact that it does not allocate chunky buffer at all!


   7 What  is that memory clustering  and how can this speed up my code and
     yet reduce memory fragmentation?

      Memory clustering is possible thanks to  'mem_xxxcluster()'  function
      family. What it does is to allocate a block of memory, divide it into
      smaller and equal pieces that can then be requested locally.


   8 Can i  compress  #?.logo  files with some  executable cruncher such as
     PowerPacker, Imploder, CrunchMania, etc and will they still load?

      In theory yes, but you will have to apply special  'LoadSeg()'  patch
      first most probably.


   9 I'm  not sure how to resolve  symbol address  in my program as stuffed
     with '___QDEV_SEGINIT_BINDS' in my modular segment, what do i do?

      This is simple really, look at the example usage in  'a-pre_xxxseg.h'
      and  right after  '___QDEV_SEGINIT_FINDPTR()'  pass its  result along
      with symbol name to '___QDEV_SEGINIT_FINDSYM()'.


  10 Can I attach exception  handler to remote task and if so,  how do I do
     that?

      This  indeed is  possible and  may be the  only way to hack on remote
      task. The trick is to pretend for a brief moment that the remote task
      is you. Simply,  enter  forbidden  state,  backup  SysBase->ThisTask,
      assign it remote task address, install exception handler then restore
      your address and permit task switches. Remember though, that the code
      and/or data live in your segment!

      As of release  1.2 of the library there is a special subsystem called
      'mem_xxxsniffer()'  that allows to sniff on message ports of any task
      that is running. You can use this code for that purpose regardless of
      exception handler being installed already on -this- signal as sniffer
      in an extension to the exception.


  11 Can I intermix  standard and  resident  code without any side effects?

      This is  really not recommended  unless you know  what you are doing.
      The simple answer would be: No, you cannot.


  12 Help! My code crashes/hits when compiled with  '-resident'  switch but
     all is just fine without it. What the hell is going on?

      * Make sure that all objects were compiled with  '-resident' and that
      you link against  'nrcrt0.o'  or other RESIDENT  capable startup code
      and that all link libraries are resident compliant too!

      * Make sure that  before accessing  global variables or library bases
      outside main context  A4  register was restored. You  will have to do
      that  in: subtasks/subprocesses, interrupts, private task exceptions,
      callbacks or hooks called in ROM or disk loaded library space.

      * Try to create a driver function per callback with  QDEV_HLP_DFUNC()
      macro and see if it helps. Exclude  all registers your callback  uses
      plus A5 and A7. If  return type is  'void'  and  D0 is not used as an
      input register include D0.


  13 I really miss  Amiga-like function names. What can be done about that?

      As of  1.1  there is a file called  'qalias.h' which tries to address
      this issue. Just include it in your project and voila :-) .


  14 What can I do with QCRT startup that  I cannot do with other startups?

      QCRT was created so that your hands are free from lauchsite detection
      and standard or resident  code  init/kill ops. Plus you can precisely
      tell when certain operation will take place in 'main()'. QCRT is also
      capable of  being  utilised in  ROMTag  affected binaries so the same
      binary  can be regular  executable and  ROM  module  at the same time
      because it lacks  global/BSS symbols.  OS V34 is supported :-) . QCRT
      uses special structure that defines cached CPU registers that contain
      all you need to do lots of tricks with your binary.
    


No more fear cus pure HTML is here!
Copyright (C) 2013-2014 by Burnt Chip Dominators