summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert de Bath <rdebath@poboxes.com>1997-02-25 20:42:19 +0100
committerLubomir Rintel <lkundrak@v3.sk>2013-10-23 23:38:07 +0200
commit4c36e9a0c125ccfff37aa440dab2cf58c4152fff (patch)
treea5d9c84ba2661029ddb2223dacd50529a361c3d5
parentf8de35da65c5d93bb733073cf40da154bc1c0748 (diff)
parent9696d7b0e1f3a1b0f5fd4a0428eb75afe8ad4ed6 (diff)
downloaddev86-4c36e9a0c125ccfff37aa440dab2cf58c4152fff.tar.gz
Import Dev86src-0.0.11.tar.gzv0.0.11
-rw-r--r--COPYING339
-rw-r--r--Changes88
-rw-r--r--Contributors30
-rw-r--r--Libc_version2
-rw-r--r--MAGIC (renamed from libc/MAGIC)0
-rw-r--r--Make.defs26
-rw-r--r--Makefile187
-rw-r--r--README64
-rw-r--r--as/Makefile20
-rw-r--r--as/as.c22
-rw-r--r--as/as86_encap.sh (renamed from as/as86_encap)5
-rw-r--r--as/express.c8
-rw-r--r--as/flag.h2
-rw-r--r--as/genbin.c18
-rw-r--r--as/genlist.c2
-rw-r--r--as/macro.c2
-rw-r--r--as/pops.c2
-rw-r--r--as/proto.h6
-rw-r--r--as/readsrc.c19
-rw-r--r--as/syshead.h22
-rw-r--r--as/typeconv.c1
-rw-r--r--bcc/Makefile20
-rw-r--r--bcc/bcc.c235
-rw-r--r--bcc/bcc.exebin13949 -> 0 bytes
-rw-r--r--bcc/const.h6
-rw-r--r--bcc/input.c23
-rw-r--r--bcc/preproc.c2
-rw-r--r--bcc/proto.h1
-rw-r--r--bootblocks/Makefile42
-rw-r--r--bootblocks/README80
-rw-r--r--bootblocks/bzimage.c555
-rw-r--r--bootblocks/dosboot.c72
-rw-r--r--bootblocks/dosfs.c419
-rw-r--r--bootblocks/help.c93
-rw-r--r--bootblocks/i86_funcs.c28
-rw-r--r--bootblocks/makeboot.c634
-rw-r--r--bootblocks/mbr.s4
-rw-r--r--bootblocks/monitor.c161
-rw-r--r--bootblocks/msdos.s214
-rw-r--r--bootblocks/nofs.c55
-rw-r--r--bootblocks/relocate.c9
-rw-r--r--bootblocks/skip.s1
-rw-r--r--bootblocks/sysboot.s64
-rw-r--r--compile.bat508
-rw-r--r--copt/Makefile6
-rw-r--r--copt/README25
-rw-r--r--copt/copt.c826
-rw-r--r--copt/rules.386427
-rw-r--r--copt/rules.86427
-rw-r--r--copt/rules.end18
-rw-r--r--copt/rules.inl8
-rw-r--r--copt/rules.net42
-rw-r--r--copt/rules.start19
-rw-r--r--dis88/Makefile4
-rw-r--r--doselks/Makefile3
-rw-r--r--elksemu/Makefile6
-rw-r--r--elksemu/elks.c5
-rw-r--r--elksemu/minix.c72
-rw-r--r--ifdef.c357
-rw-r--r--ld/Makefile19
-rw-r--r--ld/bugs3
-rw-r--r--ld/globvar.h1
-rw-r--r--ld/io.c39
-rw-r--r--ld/ld.c19
-rw-r--r--ld/syshead.h18
-rw-r--r--ld/writebin.c7
-rw-r--r--ld/writex86.c12
-rw-r--r--ld/x86_aout.h2
-rw-r--r--libbsd/Makefile10
-rw-r--r--libc/Contributors8
-rw-r--r--libc/Make.defs100
-rw-r--r--libc/Makefile132
-rwxr-xr-xlibc/New_subdir11
-rw-r--r--libc/README27
-rw-r--r--libc/bcc/Makefile49
-rw-r--r--libc/bcc/heap.c4
-rw-r--r--libc/bios/Makefile35
-rw-r--r--libc/bios/bios.c12
-rw-r--r--libc/bios/bios_vid.c24
-rw-r--r--libc/crt0.c2
-rw-r--r--libc/error/Makefile15
-rw-r--r--libc/getent/Config1
-rw-r--r--libc/getent/Makefile (renamed from libc/pwd/Makefile)44
-rw-r--r--libc/getent/__getgrent.c (renamed from libc/grp/__getgrent.c)0
-rw-r--r--libc/getent/__getpwent.c (renamed from libc/pwd/__getpwent.c)0
-rw-r--r--libc/getent/config-grp.h (renamed from libc/grp/config-grp.h)0
-rw-r--r--libc/getent/config.h (renamed from libc/grp/config.h)0
-rw-r--r--libc/getent/fgetgrent.c (renamed from libc/grp/fgetgrent.c)0
-rw-r--r--libc/getent/fgetpwent.c (renamed from libc/pwd/fgetpwent.c)0
-rw-r--r--libc/getent/getgrgid.c (renamed from libc/grp/getgrgid.c)0
-rw-r--r--libc/getent/getgrnam.c (renamed from libc/grp/getgrnam.c)0
-rw-r--r--libc/getent/getpw.c (renamed from libc/pwd/getpw.c)0
-rw-r--r--libc/getent/getpwnam.c (renamed from libc/pwd/getpwnam.c)0
-rw-r--r--libc/getent/getpwuid.c (renamed from libc/pwd/getpwuid.c)0
-rw-r--r--libc/getent/grent.c (renamed from libc/grp/grent.c)0
-rw-r--r--libc/getent/initgroups.c (renamed from libc/grp/initgroups.c)0
-rw-r--r--libc/getent/putpwent.c (renamed from libc/pwd/putpwent.c)0
-rw-r--r--libc/getent/pwent.c (renamed from libc/pwd/pwent.c)0
-rw-r--r--libc/getent/test_grp.c (renamed from libc/grp/test_grp.c)0
-rw-r--r--libc/getent/test_pwd.c (renamed from libc/pwd/test_pwd.c)0
-rw-r--r--libc/getent/utent.c (renamed from libc/utmp/utent.c)0
-rw-r--r--libc/grp/Config1
-rw-r--r--libc/grp/Makefile42
-rw-r--r--libc/gtermcap/Makefile18
-rw-r--r--libc/i386fp/Makefile38
-rw-r--r--libc/i386sys/Config1
-rw-r--r--libc/i386sys/Makefile52
-rw-r--r--libc/i386sys/dirent.c106
-rw-r--r--libc/i386sys/exec.c292
-rw-r--r--libc/i386sys/mksyscall (renamed from libc/syscall/mksys386)29
-rw-r--r--libc/i386sys/signal.c99
-rw-r--r--libc/i386sys/syscall.dat (renamed from libc/syscall/sys386.dat)0
-rw-r--r--libc/i386sys/syslibc.c255
-rw-r--r--libc/include/setjmp.h8
-rw-r--r--libc/include/stdarg.h4
-rw-r--r--libc/include/sys/stat.h4
-rw-r--r--libc/kinclude/Makefile10
-rw-r--r--libc/malloc1/Makefile21
-rw-r--r--libc/malloc2/Makefile20
-rw-r--r--libc/misc/Makefile51
-rw-r--r--libc/misc/strtod.c4
-rw-r--r--libc/msdos/Makefile35
-rw-r--r--libc/pwd/Config1
-rw-r--r--libc/regexp/Makefile27
-rw-r--r--libc/stdio2/Makefile41
-rw-r--r--libc/stdio2/printf.c21
-rw-r--r--libc/stdio2/scanf.c24
-rw-r--r--libc/stdio2/stdio.c4
-rw-r--r--libc/string/Makefile23
-rw-r--r--libc/syscall/Makefile70
-rw-r--r--libc/syscall/TODO2
-rw-r--r--libc/syscall/getinfo.c32
-rw-r--r--libc/syscall/mksyscall25
-rw-r--r--libc/syscall/setjmp.c6
-rw-r--r--libc/syscall/syscall.dat.chad55
-rw-r--r--libc/syscall/syscall.dat.code70
-rw-r--r--libc/syscall/syscall.dat.rdb142
-rw-r--r--libc/syscall/syslib0.c20
-rw-r--r--libc/syscall/syslib3.c109
-rw-r--r--libc/syscall/syslibc.c13
-rw-r--r--libc/termios/Makefile28
-rw-r--r--libc/tests/Config2
-rw-r--r--libc/tests/Makefile20
-rw-r--r--libc/tests/Real_make19
-rw-r--r--libc/tests/ls.c1049
-rw-r--r--libc/tests/size.c51
-rw-r--r--libc/time/Makefile12
-rw-r--r--libc/utmp/Makefile26
-rw-r--r--makefile.in226
-rw-r--r--man/Makefile6
-rw-r--r--man/as86.134
-rw-r--r--man/bcc.126
-rw-r--r--man/elksemu.12
-rw-r--r--man/ld86.16
-rw-r--r--mkcompile2
-rw-r--r--mkcompile2103
-rw-r--r--tests/Makefile33
-rw-r--r--tests/README (renamed from libc/tests/README)10
-rw-r--r--tests/compr.c (renamed from libc/tests/compr.c)0
-rw-r--r--tests/env.c (renamed from libc/tests/env.c)0
-rw-r--r--tests/ft.c (renamed from libc/tests/ft.c)0
-rw-r--r--tests/grab.c (renamed from libc/tests/grab.c)0
-rw-r--r--tests/hd.c (renamed from libc/tests/hd.c)0
-rw-r--r--tests/line2.c (renamed from libc/tests/line2.c)0
-rw-r--r--tests/lines.c (renamed from libc/tests/lines.c)0
-rw-r--r--tests/ouch.c (renamed from libc/tests/ouch.c)0
-rw-r--r--tests/rand.c (renamed from libc/tests/rand.c)0
-rw-r--r--tests/size.c83
-rw-r--r--tests/sync.c (renamed from libc/tests/sync.c)0
-rw-r--r--tests/ucomp.c (renamed from libc/tests/ucomp.c)0
-rw-r--r--tests/wc.c (renamed from libc/tests/wc.c)0
-rw-r--r--unproto/Makefile109
-rw-r--r--unproto/Makefile.old123
-rw-r--r--unproto/README184
-rw-r--r--unproto/Shar.Headers50
-rw-r--r--unproto/Sharheader6
-rw-r--r--unproto/acc.sh35
-rw-r--r--unproto/cpp.sh36
-rw-r--r--unproto/error.c57
-rw-r--r--unproto/error.h4
-rw-r--r--unproto/example.c96
-rw-r--r--unproto/example.out182
-rw-r--r--unproto/hash.c54
-rw-r--r--unproto/stdarg.h93
-rw-r--r--unproto/stddef.h23
-rw-r--r--unproto/stdlib.h53
-rw-r--r--unproto/strsave.c71
-rw-r--r--unproto/symbol.c39
-rw-r--r--unproto/tok_class.c334
-rw-r--r--unproto/tok_io.c604
-rw-r--r--unproto/tok_pool.c13
-rw-r--r--unproto/token.h38
-rw-r--r--unproto/unproto.1137
-rw-r--r--unproto/unproto.c466
-rw-r--r--unproto/unproto.c.old999
-rw-r--r--unproto/vstring.c39
-rw-r--r--unproto/vstring.h3
197 files changed, 10457 insertions, 3834 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..a43ea21
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Changes b/Changes
index 7c3d1dd..ddcb414 100644
--- a/Changes
+++ b/Changes
@@ -1,3 +1,89 @@
+For version 0.0.11.
+
+> New, most recent, version of unproto inserted.
+
+> AAARG! First_arg_in_ax breaks stdarg.h! As a consequence printf wasn't
+ working, now why didn't _you_ notice! OK. printf now uses varargs, that
+ is more likely to work and does for printf & scanf.
+
+> Added -Mc for 'caller saves' _without_ first_arg_in_ax. As this uses the
+ normal libc there are likely to be problems with library -> user callbacks.
+
+> Added -Ml for 386 'Large linux' compile.
+
+> Added -Mn for 'normal' elks compiles so the default for dos can be -Md
+
+> Brand new, an optimiser has been added, it's in its early stages yet
+ the 8086 (plain -O) version seems ok. The 386 generator (-O3) is definitly
+ missing some requirements. It's probably not a good idea to use -Ml and -O.
+ (Later: The 8086 can generate bad code it seems, oh well)
+
+> Some changes to the makefile, minix make will now _try_ to compile bcc,
+ it doesn't seem to succeed yet though. Also because of this I've gone
+ back over the headers, should be better on non-ansi or non-posix systems
+ now. BTW: minix make has no chance with compiling libc so I've added
+ another zip archive containing just the compiled libcs.
+
+> Add the -a-, -j-, -g-, -u- and -w- flags to as86; specifically for -w-
+ to allow easy enabling of assembler warnings while using bcc.
+
+> Bugfix for assembler 'ifc' pseudo op.
+
+> Bugfix for preprocessor and unterminated last line of included file.
+
+> Add minix syscall detector to elksemu, I may make it into an emulator ...
+
+> I've split of the 8086 ELKS and i386 Linux libc stuff into seperate
+ directories. I expect Chad will want to take over the 8086 one for a while.
+ Plus some other files moved around to help new users.
+
+For version 0.0.10.
+
+> Some serious changes to the makefiles, practically a rewrite of them.
+ 'make', 'make all', 'make install', 'make clean' and 'make realclean'
+ do the expected things. 'make distribution' should let you create the
+ partial and binary dirtributions from the full source.
+
+> The makefiles now allow multiple libc binaries to co-exist.
+
+> The makefiles now allow a _full_ compile without installing anything.
+
+> In part because of the makefile changes a lot of files in the library
+ have been moved, this is a large portion of the patch size.
+
+> ifdef.c added as part of makefile changes, I'm not quite sure if I like
+ this way of doing things but it's ok for the mo.
+
+> MSDOS, in the output of *.bin files from as86 skipped areas have zeros
+ written not semi-random bytes.
+
+> MSDOS (+ other machines where sizeof(char*) != sizeof(int)) problem with
+ macros resolved, they appear to work correctly now.
+
+> NCC added, this is a different version of bcc with libs and include dirs
+ in the same format as the MSDOS driver.
+ This is used for 'uninstalled' compiling and also if you do:
+ $ ln -s `pwd`/bcc/ncc $HOME/bin/bcc
+ The bcc will use the 'uninstalled' include and library files for when you
+ don't have root access.
+
+> -H option added to ld86, this controls the size of the heap or 'chmem'
+ field in the executable.
+
+> BOOT-Blocks, makeboot can be compiled as a DOS COM, bootblock for msdos
+ filesystem completed, this will allow lilo, monitor.out or any Linux-86
+ standalone executable to be executed from an msdos floppy. Makeboot
+ can also install several other types of bootblock.
+
+> Monitor.out not includes 'bzimage' command, which will boot a Linux-i386
+ bzImage with command line and initrd.
+
+> 'skip.s' bootblock fixed.
+
+> A few more functions now work in 'standalone' mode, malloc() especially.
+
+-Rob
+
For version 0.0.9.
> The debian stuff has been removed again, Christoph want's to keep contol
@@ -107,7 +193,7 @@ For version 0.0.8.
> Added for bcc-cc1, code between #asm and #endasm _is_ scanned for #defined
words and functions, it didn't effect the libc at all. Of course we now
need some way to put multiple instructions in one #define, I've nominated
- '^' as the statment terminator, I didn't have many choices :-(
+ '^' as the statement terminator, I didn't have many choices :-(
> Added '-t' for bcc-cc1 when bcc gets -S
diff --git a/Contributors b/Contributors
new file mode 100644
index 0000000..976e69e
--- /dev/null
+++ b/Contributors
@@ -0,0 +1,30 @@
+Top of the list, without whom this wouldn't be here...
+
+Bruce Evans <bde@FreeBSD.org>
+
+Then there's me, I'm controlling the releases of Dev86 and have
+the master files.
+
+Robert de Bath <robert@mayday.cix.co.uk>
+
+The files are available at linux.mit.edu with pointers and yesterday's
+patch file available via http://www.cix.co.uk/~mayday
+
+We're all available through the Linux-8086 mailing list at:
+ linux-8086@vger.rutgers.edu
+
+send a blank message to <majordomo@vger.rutgers.edu> for help on joining
+the list.
+
+Rob.
+
+Finally the list itself, if you're missing send me a patch :-)
+
+Alan Cox <alan@cymru.net>
+Nat Friedman <ndf@aleph1.mit.edu>
+Steven Huang <sthuang@hns.com>
+Gero Kuhlmann <gero@gkminix.han.de>
+Chad Page <page0588@sundance.sjsu.edu>
+Dick Porter <dick@cymru.net>
+Dale Schumacher <dal@syntel.UUCP>
+Joel Weber II <nemo@koa.iolani.honolulu.hi.us>
diff --git a/Libc_version b/Libc_version
index c5d54ec..2cfabea 100644
--- a/Libc_version
+++ b/Libc_version
@@ -1 +1 @@
-0.0.9
+0.0.11
diff --git a/libc/MAGIC b/MAGIC
index 319751e..319751e 100644
--- a/libc/MAGIC
+++ b/MAGIC
diff --git a/Make.defs b/Make.defs
deleted file mode 100644
index 644029c..0000000
--- a/Make.defs
+++ /dev/null
@@ -1,26 +0,0 @@
-
-WALLP =-Wtraditional -Wshadow -Wid-clash-14 -Wpointer-arith \
- -Wcast-qual -Wcast-align -Wconversion -Waggregate-return \
- -Wstrict-prototypes -Wmissing-prototypes -Wredundant-decls \
- -Wnested-externs -Winline
-
-# unproto is yukky, I've included '-w' in the local makefile.
-WALL =-Wstrict-prototypes
-
-ifeq ($(CC),cc)
-CC =gcc
-CCFLAGS =-Wall $(WALL) -O2 -fno-strength-reduce
-else
-CCFLAGS =-O
-endif
-
-CFLAGS =$(CCFLAGS)
-LDFLAGS =-s
-
-export DIST
-export BINDIR =$(DIST)/usr/bin
-export MANDIR =$(DIST)/usr/man
-export BCCROOT =/usr/bcc
-export BCCHOME =$(DIST)$(BCCROOT)
-export LIBDIR =$(BCCHOME)/lib/bcc
-export ELKSSRC =/usr/src/linuxmt
diff --git a/Makefile b/Makefile
index 375fa72..8866f91 100644
--- a/Makefile
+++ b/Makefile
@@ -1,134 +1,67 @@
+# Copyright (C) 1997 Robert de Bath <robert@mayday.cix.co.uk>
+# This file is part of the Linux-8086 Development environment and is
+# distributed under the GNU General Public License.
-export TOPDIR := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi)
+TARGETS=all bcc unproto copt as86 ld86 \
+ install install-all install-lib install-lib2 install-other \
+ clean tests alt-libs library config other
-include Make.defs
+$(TARGETS): make.fil
+ PATH="`pwd`/bin:$$PATH" $(MAKE) -f make.fil TOPDIR=`pwd` $@
-PARTS= ld as unproto bcc
-LIBS2= libbsd
-LIBS= libc $(LIBS2)
-EXTRAS= man dis88 doselks
-TESTDIRS= tests
-DISTFILES=Makefile Make.defs README Changes Libc_version Uninstall
-DISTDIRS= $(LIBS2) elksemu $(TESTDIRS) $(EXTRAS)
-DOSBITS= mkcompile compile.bat later.c
-
-default: dummy
- @echo "You have to do 'make install' as root"
- @echo Or:
- @echo
- @echo '$ make bcc'
- @echo '$ su -c "make install-bcc"'
- @echo '$ make library'
- @echo '$ su -c "make install-lib"'
- @echo '$ make elksemu'
- @echo '$ su -c "make install-emu"'
- @echo '$ su -c "make install-man"'
- @echo
- @echo 'Other libraries are built with:'
- @echo '$ su -c "make install-lib2"'
- @echo
- @echo "Or do 'make install-all' for _everything_"
-
-dummy:
- @if [ -f .runme ] ; then sh .runme ; rm .runme ; fi
-
-install: install-bcc install-lib install-emu install-man
-
-# Do _everything_!
-install-all:
- make realclean
- make config
- make install-bcc
- make install-man
- make install-lib-fast
- make install-lib-dos
- make install-lib-bios
- make install-lib-386
- make install-lib
- make install-emu
- make -C dis88 install
- make realclean
-
-config:
- make -C libc config
-
-all: bcc library elksemu tests extras
-
-bcc: dummy
- @for i in $(PARTS) ; do make -C $$i || exit 1; done
+$(TARGETS): phony
+phony:
realclean:
- @for i in $(PARTS) libc $(DISTDIRS) ; do \
- if grep -q '^realclean' $$i/Makefile ; then \
- make -C $$i realclean ; else \
- make -C $$i clean ; fi ; done
-
-clean:
- @for i in $(PARTS) libc $(DISTDIRS) ; do \
- make -C $$i clean || exit 1; done
-
-tests: dummy
- @test -f $(BINDIR)/bcc || \
- ( echo 'Must do "make install-bcc" first' && exit 1 )
- @test -f $(LIBDIR)/i86/crt0.o || \
- ( echo 'Must do "make install-lib" first' && exit 1 )
- @for i in $(TESTDIRS) ; do make -C $$i || exit 1; done
-
-library: dummy
- @test -f $(BINDIR)/bcc || \
- ( echo 'Must do "make install-bcc" first' && exit 1 )
- make -C libc PLATFORM=i86-ELKS
-
-elksemu: dummy
- @test -f libc/syscall/call_tab.v || \
- ( echo 'Must do "make library" first' && exit 1 )
- make -C elksemu
-
-extras: dummy
- @for i in $(EXTRAS) ; do make -C $$i || exit 1; done
-
-install-bcc: dummy
- @for i in $(PARTS) ; do make -C $$i install || exit 1; done
-
-install-lib: dummy
- @test -f $(BINDIR)/bcc || \
- ( echo 'Must do "make install-bcc" first' && exit 1 )
- @for i in $(LIBS) ; do \
- make -C $$i PLATFORM=i86-ELKS install || exit 1 ; \
- done
-
-install-lib2: install-lib-bios install-lib-dos install-lib-fast install-lib-386
-
-install-lib-bios: dummy
- @test -f $(BINDIR)/bcc || \
- ( echo 'Must do "make install-bcc" first' && exit 1 )
- make -C libc PLATFORM=i86-BIOS install
-
-install-lib-dos: dummy
- @test -f $(BINDIR)/bcc || \
- ( echo 'Must do "make install-bcc" first' && exit 1 )
- make -C libc PLATFORM=i86-DOS install
-
-install-lib-fast: dummy
- @test -f $(BINDIR)/bcc || \
- ( echo 'Must do "make install-bcc" first' && exit 1 )
- make -C libc PLATFORM=i86-FAST install
-
-install-lib-386: dummy
- @test -f $(BINDIR)/bcc || \
- ( echo 'Must do "make install-bcc" first' && exit 1 )
- make -C libc PLATFORM=i386-BCC install
-
-install-emu: dummy
- @test -f libc/syscall/call_tab.v || \
- ( echo 'Must do "make library" first' && exit 1 )
- make -C elksemu install
-
-install-man: dummy
- make -C man install
+ [ ! -f make.fil ] || $(MAKE) -f make.fil TOPDIR=`pwd` $@
+ rm -f make.fil ifdef
+
+make.fil: ifdef makefile.in
+ ./ifdef -MU makefile.in >tmp.mak
+ mv -f tmp.mak make.fil
+
+ifdef: ifdef.o
+ $(CC) -o ifdef ifdef.o
+
+Uninstall: phony
+ @echo 'Are you really sure... have you checked this... ^C to interrupt'
+ @read line
+ rm -rf /usr/bcc
+ rm -f /usr/bin/bcc /usr/bin/as86_encap /usr/bin/dis88
+ rm -f /lib/elksemu
+ rm -f /usr/lib/liberror.txt
+ rm -f /usr/man/man1/elks.1* /usr/man/man1/elksemu.1*
+ rm -f /usr/man/man1/dis88.1* /usr/man/man1/bcc.1*
+ rm -f /usr/man/man1/as86.1* /usr/man/man1/ld86.1*
+ rm -f /usr/man/man1/dis88.1*
-install-extras: dummy
- @for i in $(EXTRAS) ; do make -C $$i install || exit 1; done
-
distribution:
- sh Build_dist
+ @rm -f /tmp/linux-86 || true
+ @[ ! -f Copy_dist ] || sh Copy_dist
+ mkdir -p /tmp/Dist
+ [ -d /tmp/linux-86 ] || ln -s `pwd` /tmp/linux-86
+ cd /tmp ;\
+ $(MAKE) -C linux-86 realclean || exit 1 ;\
+ $(MAKE) -C linux-86/libc Libc_version ;\
+ VER=`cat linux-86/Libc_version` ;\
+ tar cf Dist/Dev86src-$$VER.tar linux-86/* ;\
+ ln -s linux-86/as as86 ;\
+ cp -p linux-86/man/as86.1 as86/as86.1 ;\
+ tar cf Dist/as86-$$VER.tar `find as86/* -prune -type f` ;\
+ rm as86/as86.1 as86 ;\
+ ln -s linux-86/libc libc-$$VER ;\
+ tar cf Dist/libc-8086-$$VER.tar libc-$$VER/* ;\
+ rm libc-$$VER ;\
+ $(MAKE) -C /tmp/linux-86 install \
+ ARFLAGS=q DIST=/tmp/linux-86-dist || exit 1 ;\
+ tar cf /tmp/Dist/Dev86bin-$$VER.tar -C /tmp/linux-86-dist . ;\
+ rm -f /tmp/Dist/Dev86clb-$$VER.zip Bcc ;\
+ ln -s /tmp/linux-86 Bcc ;\
+ zip -9rpk /tmp/Dist/Dev86clb-$$VER.zip \
+ Bcc/lib/crt0.o Bcc/lib/libc.a Bcc/lib/libbsd.a \
+ Bcc/lib/libdos.a Bcc/lib/libc_f.a Bcc/lib/libc_s.a \
+ Bcc/lib/i386/crt0.o Bcc/lib/i386/libc.a ;\
+ rm Bcc
+
+ gzip -v9f /tmp/Dist/*.tar
+ @rm /tmp/linux-86 || true
diff --git a/README b/README
index 12145cd..d7a17cf 100644
--- a/README
+++ b/README
@@ -1,41 +1,41 @@
-This is a development environment for ELKS-86
+This is a development environment for ELKS-86 and standalone 8086 code.
-To install the basic environment you have to do 'make install' as root
-Or:
+The only hand configuration is to choose one of libc/syscall/syscall.dat.*
+to be used as libc/syscall/syscall.dat The '*.chad' one matches the *.50
+elks kernel but you're best to pickup the one in the kernel you're compiling
+for.
-$ make bcc
-$ su -c "make install-bcc"
-$ make library
-$ su -c "make install-lib"
-$ make elksemu
-$ su -c "make install-emu"
+All you then need to do then is 'make' from the top directory and the main
+parts of the package will be made. These can be tested by use the 'ncc'
+program from the newly created bin subdirectory.
-All from the top directory.
-Once this is done new files will be /lib/elksemu, /usr/bcc/*, /usr/bin/bcc
-and /usr/bin/as86_encap.
+Use 'make install' to install them.
+Use 'make Uninstall' to remove everything (Beware with this though!)
+
+Some other bits can be built by 'make other' and installed with
+'make install-other'.
The manual pages in the man subdirectory are a start as some pages matched
to these programs, there are also some hints for using as86 well.
The tests and bootblocks directories give some example code.
The bcc command defaults to using /usr/bcc/include and /usr/bcc/lib the
-libraries _and_ include files are compied to these locations by install.
+libraries _and_ include files are copied to these locations by install.
-After this you may want to install the other libraries, 'fast', 'MSDOS',
+All the versions of the library are built by make; 'normal', 'fast', 'MSDOS',
'standalone' and Linux-i386.
-$ su -c "make install-lib2"
-Use these libraries like this:
+You use the other libraries like this:
'FAST' $ bcc -Mf prog.c -o prog
+ Caller saves $ bcc -Mc prog.c -o prog
MSDOS $ bcc -Md prog.c -o prog.com
Standalone $ bcc -Ms prog.c -o prog.sys
- Minix 386 $ bcc -3 prog.c -o prog
- Linux-i386 $ bcc -3 -N prog.c -o prog
+ Linux-i386 $ bcc -Ml prog.c -o prog
The Linux-i386 version generates static Linux a.out programs, they need
neither elksemu nor a.out shared libries to run. If you want you can
convert them to an odd ELF executable with:
- $ bcc -N -3 prog.c -o prog
+ $ bcc -Ml prog.c -o prog
$ objcopy -O elf32-i386 prog
If you want to install everything in one go just login as root an do:
@@ -46,12 +46,28 @@ linux-i386 kernel but can replace them, the kernel-i386 ones _will_ _not_
work correctly here!
Unfortunatly, the DOSEMU folks have been using the '-r' option of ld86
-This version does accept '-r' but it generates _LINUX_ a.out object files.
-I think they should really be using 'as86_encap'. Neverthless this ld86
-will call a program called /usr/bin/ld86r if it's given -r without -N.
+This version does accept '-r' (with -N) but it generates _LINUX_ a.out
+object files. I think they should really be using 'as86_encap' but in
+the short term DOSEMU is being changed to be able to use the new ld86.
+
+Neverthless this ld86 will call a program called /usr/bin/ld86r if it's
+given -r without -N, this can be the old ld86 renamed. For simplicity
+Dev86 doesn't yet overwrite /usr/bin/ld86 but stores the linker in
+/usr/bcc/lib.
I _strongly_ suggest you install the kernel patch or load the module in
the elksemu directory in your Linux-i386 kernel, it makes things _much_
-easier.
+easier. (They both need the elksemu executable installed correctly)
+
+Copyrights
+----------
+This software is for the most part under GPL style copyright, the libc and
+libbsd are covered by the 'weaker' library versions of this document.
+(See the COPYING files in this and the libc directories for details)
+
+The copyrights of other parts are documented in the relevent files. Some
+parts are explicitly PD others like the unproto code have copyrights that
+allow free distribution but are otherwise more vague.
--Rob.
+--
+Rob. (Robert de Bath <robert@mayday.cix.co.uk>)
diff --git a/as/Makefile b/as/Makefile
index 3fb2551..4319371 100644
--- a/as/Makefile
+++ b/as/Makefile
@@ -1,35 +1,33 @@
-ifneq ($(TOPDIR),)
-include $(TOPDIR)/Make.defs
-else
CFLAGS=-O
+LDFLAGS=-s
LIBDIR=/usr/bin
BINDIR=/usr/bin
-endif
-
-# Temp needed for libc-5.4.7
-CFLAGS+= -Dwarn=as_warn
OBJS =as.o assemble.o error.o express.o \
genbin.o genlist.o genobj.o gensym.o \
keywords.o macro.o mops.o pops.o readsrc.o \
scan.o table.o typeconv.o
-all: as86
+all: as86 as86_encap
as86: $(OBJS)
$(CC) $(LDFLAGS) $(OBJS) -o as86
+as86_encap: as86_encap.sh
+ sed "s:%%LIBDIR%%:$(LIBDIR):" < as86_encap.sh > tmp
+ @mv -f tmp as86_encap
+ chmod +x as86_encap
+
install: all
install -d $(LIBDIR)
install -m 755 as86 $(LIBDIR)
- sed "s:%%LIBDIR%%:$(LIBDIR):" < as86_encap > tmp
install -d $(BINDIR)
install -m 755 tmp $(BINDIR)/as86_encap
-@rm -f tmp
-clean:
- rm -f *.o as86
+clean realclean:
+ rm -f *.o as86 as86_encap
as.o: const.h type.h byteord.h macro.h file.h flag.h globvar.h
assemble.o: const.h type.h address.h globvar.h opcode.h scan.h
diff --git a/as/as.c b/as/as.c
index ce72c13..234fe18 100644
--- a/as/as.c
+++ b/as/as.c
@@ -63,7 +63,7 @@ char **argv;
initobj();
initsource(); /* only nec to init for unsupported mem file */
typeconv_init(BIG_ENDIAN, LONG_BIG_ENDIAN);
- warn.global = TRUE; /* constant */
+ as_warn.global = TRUE; /* constant */
last_pass=1;
process_args(argc, argv);
initscan();
@@ -158,6 +158,7 @@ char **argv;
bool_t isnextarg;
char *nextarg = 0;
int opened_file = 0;
+ int flag_state;
#ifdef I80386
setcpu(0xF);
@@ -170,6 +171,10 @@ char **argv;
arg = *++argv;
if (arg[0] == '-' && arg[1] != '\0')
{
+ flag_state = 1;
+ if (arg[2] == '-' && arg[3] == 0 )
+ flag_state = 0;
+ else
if (arg[2] != 0)
usage(); /* no multiple options */
isnextarg = FALSE;
@@ -191,7 +196,7 @@ char **argv;
setcpu(0xF);
break;
case 'a':
- asld_compatible = TRUE;
+ asld_compatible = flag_state;
break;
#endif
case 'b':
@@ -203,12 +208,13 @@ char **argv;
++argv;
break;
case 'g':
- globals_only_in_obj = TRUE;
+ globals_only_in_obj = flag_state;
break;
#ifdef I80386
case 'j':
- jumps_long = TRUE;
- ++last_pass;
+ jumps_long = flag_state;
+ if( jumps_long ) ++last_pass;
+ else last_pass = 1;
break;
#endif
case 'l':
@@ -250,10 +256,12 @@ char **argv;
++argv;
break;
case 'u':
- inidata = IMPBIT | SEGM;
+ if( flag_state ) inidata = IMPBIT | SEGM;
+ else inidata = 0;
break;
case 'w':
- warn.semaphore = -1;
+ if( flag_state ) as_warn.semaphore = -1;
+ else as_warn.semaphore = 0;
break;
default:
usage(); /* bad option */
diff --git a/as/as86_encap b/as/as86_encap.sh
index 4d50e23..0ba4e71 100644
--- a/as/as86_encap
+++ b/as/as86_encap.sh
@@ -19,7 +19,10 @@
trap "rm -f _$$.* ; exit 99" 1 2 3 15
LIBDIR='%%LIBDIR%%' # Set by make install
-[ -d "$LIBDIR" ] || LIBDIR=/usr/bin
+
+# If the one set by install fails then try a couple of others.
+[ -x "$LIBDIR/as86" ] || LIBDIR="`dirname $0`/../lib"
+[ -x "$LIBDIR/as86" ] || LIBDIR=/usr/bin
IFILE="$1"
OFILE="$2"
diff --git a/as/express.c b/as/express.c
index 3e93061..0bcd8b4 100644
--- a/as/express.c
+++ b/as/express.c
@@ -358,26 +358,32 @@ PUBLIC void scompare()
register char *string1;
register char *string2;
- for (string2 = string1 = lineptr; *string2 != ')'; ++string2)
+ for (string2 = string1 = lineptr; *string2 != ','; ++string2)
if (*string2 == 0 || *string2 == ')')
{
symname = string2;
experror(COMEXP);
return;
}
+ string2++;
while (*string1++ == *string2++)
;
if (string2[-1] == ')')
{
if (string1[-1] == ',')
lastexp.offset = TRUE; /* else leave FALSE */
+ lineptr = string2;
}
else /* FALSE, keep reading to verify syntax */
+ {
for (; *string2 != ')'; ++string2)
if (*string2 == 0 || *string2 == ',')
{
symname = string2;
experror(RPEXP);
}
+ lineptr = ++string2;
+ }
+ getsym();
}
}
diff --git a/as/flag.h b/as/flag.h
index 791dcc1..d9124e0 100644
--- a/as/flag.h
+++ b/as/flag.h
@@ -2,4 +2,4 @@
EXTERN struct flags_s list; /* listing on/off */
EXTERN struct flags_s maclist; /* list macros on/off */
-EXTERN struct flags_s warn; /* warnings on/off */
+EXTERN struct flags_s as_warn; /* warnings on/off */
diff --git a/as/genbin.c b/as/genbin.c
index 377c6bf..887c921 100644
--- a/as/genbin.c
+++ b/as/genbin.c
@@ -213,18 +213,22 @@ opcode_pt ch;
else
#endif
{
+#ifdef MSDOS
+static PT zapptr = 0;
+#endif
outfd = binfil;
- if( binfbuf != (PT)binmbuf)
- if( lseek(binfil, (long)((PT)binmbuf-binfbuf), 1) < 0 )
- error(BWRAP);
- binfbuf = binmbuf;
-#if 0
- while (binfbuf < (PT)binmbuf)
+#ifdef MSDOS
+ while (binfbuf < (PT)binmbuf && binfbuf >= zapptr+binmin)
{
- writec(0x0);/* pad with nulls if file buffer behind */
+ writec(0);
++binfbuf;
+ ++zapptr;
}
#endif
+ if( binfbuf != (PT)binmbuf)
+ if( lseek(binfil, (long)((PT)binmbuf-binfbuf), 1) < 0 )
+ error(BWRAP);
+ binfbuf = binmbuf;
writec(ch);
binmbuf = ++binfbuf;
}
diff --git a/as/genlist.c b/as/genlist.c
index e1c43ea..f7c2572 100644
--- a/as/genlist.c
+++ b/as/genlist.c
@@ -138,7 +138,7 @@ error_pt errnum;
register struct error_s *errptrlow;
unsigned char position;
- if ((unsigned) errnum < MINWARN || warn.current)
+ if ((unsigned) errnum < MINWARN || as_warn.current)
{
if (errcount >= MAXERR)
erroverflow = TRUE;
diff --git a/as/macro.c b/as/macro.c
index e6c1173..566c086 100644
--- a/as/macro.c
+++ b/as/macro.c
@@ -114,7 +114,7 @@ PUBLIC void pmacro()
else
symptr->type |= MACBIT;
symptr->data = UNDBIT; /* undefined till end */
- symptr->value_reg_or_op.value = (unsigned) heapptr;
+ symptr->value_reg_or_op.value = (offset_t) heapptr;
/* beginning of store for macro */
/* value s.b. (char *) */
getsym_nolookup(); /* test for "C" */
diff --git a/as/pops.c b/as/pops.c
index 2de56fe..a2670c8 100644
--- a/as/pops.c
+++ b/as/pops.c
@@ -990,7 +990,7 @@ PUBLIC void ptext()
PUBLIC void pwarn()
{
- bumpsem(&warn, -1);
+ bumpsem(&as_warn, -1);
}
#ifdef I80386
diff --git a/as/proto.h b/as/proto.h
index e6dd062..b4fb82b 100644
--- a/as/proto.h
+++ b/as/proto.h
@@ -1,11 +1,5 @@
/* extern functions */
-#if __STDC__
-#define P(x) x
-#else
-#define P(x) ()
-#endif
-
/* as.c */
int main P((int argc, char **argv));
void as_abort P((char *message));
diff --git a/as/readsrc.c b/as/readsrc.c
index 82be10f..557ca5d 100644
--- a/as/readsrc.c
+++ b/as/readsrc.c
@@ -29,6 +29,10 @@
#endif
#endif
+#ifdef MSDOS
+#define off_t long /* Not a typedef! */
+#endif
+
#ifndef MINIBUF
#define MINIBUF 1 /* Add in a reasonable buffer */
#endif
@@ -94,8 +98,13 @@ char *name;
fd = 0;
else
#endif
+#ifdef O_BINARY
if ((unsigned) (fd = open(name, O_RDONLY|O_BINARY)) > 255)
as_abort("error opening input file");
+#else
+ if ((unsigned) (fd = open(name, O_RDONLY)) > 255)
+ as_abort("error opening input file");
+#endif
#if BIGBUFFER == 1
if( mem_start == 0 )
@@ -254,9 +263,9 @@ PUBLIC void pproceof()
{
list.current = list.global;
maclist.current = maclist.global;
- warn.current = TRUE;
- if (warn.semaphore < 0)
- warn.current = FALSE;
+ as_warn.current = TRUE;
+ if (as_warn.semaphore < 0)
+ as_warn.current = FALSE;
}
if (infiln != 0)
@@ -348,6 +357,10 @@ PUBLIC void readline()
}
}
macstak->text = bufptr;
+#if 0
+ *reglineptr = 0;
+ printf("MLINE:%s.\n", lineptr);
+#endif
*reglineptr = EOLCHAR;
return;
}
diff --git a/as/syshead.h b/as/syshead.h
index d2a1655..926be5d 100644
--- a/as/syshead.h
+++ b/as/syshead.h
@@ -6,9 +6,9 @@
#endif
#ifndef POSIX_HEADERS_MISSING
-#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <unistd.h>
#include <fcntl.h>
#endif
@@ -20,6 +20,12 @@
#undef POSIX_HEADERS_MISSING
#endif
+#if __STDC__ && !defined(__minix)
+#define P(x) x
+#else
+#define P(x) ()
+#endif
+
#ifdef STDC_HEADERS_MISSING
char *strcpy P((char *s1, const char *s2));
char *strrchr P((const char *s, int c));
@@ -38,13 +44,17 @@ int creat P((const char *path, int mode));
int open P((const char *path, int oflag, ...));
int read P((int fd, void *buf, unsigned nbytes));
int write P((int fd, const void *buf, unsigned nbytes));
-off_t lseek P((int fd, off_t offset, int whence));
typedef long off_t;
-#define O_RDONLY 0
-
+off_t lseek P((int fd, off_t offset, int whence));
#define BIGBUFFER 0 /* Can't use a big buffer ... sorry */
#endif
-#ifndef O_BINARY
-#define O_BINARY 0
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#endif
+#ifndef O_WRONLY
+#define O_WRONLY 1
+#endif
+#ifndef O_RDWR
+#define O_RDWR 2
#endif
diff --git a/as/typeconv.c b/as/typeconv.c
index 82dafdd..c51b991 100644
--- a/as/typeconv.c
+++ b/as/typeconv.c
@@ -34,6 +34,7 @@
preprocessor is too dumb to tell us at compile time.
*/
+#include "syshead.h"
#include "const.h"
#include "type.h"
#include "globvar.h"
diff --git a/bcc/Makefile b/bcc/Makefile
index a95c5bc..512c013 100644
--- a/bcc/Makefile
+++ b/bcc/Makefile
@@ -3,20 +3,13 @@
# $Id$
#
-ifneq ($(TOPDIR),)
-include $(TOPDIR)/Make.defs
-BCCDEFS =-DLOCALPREFIX="\"$(BCCROOT)\"" -DDEFARCH=0
-else
+PREFIX=/usr
+
CFLAGS =-O
LDFLAGS =-s
BINDIR =/usr/bin
LIBDIR =/usr/lib/bcc
-BCCDEFS =-DLOCALPREFIX="\"/usr\"" -DDEFARCH=0
-endif
-
-ifeq ($(CC),bcc)
-CFLAGS=-Mf
-endif
+BCCDEFS =-DLOCALPREFIX=$(PREFIX) -DDEFARCH=0
OBJS = bcc-cc1.o codefrag.o debug.o declare.o express.o exptree.o floatop.o \
function.o gencode.o genloads.o glogcode.o hardop.o input.o label.o \
@@ -34,6 +27,9 @@ install: all
bcc: bcc.c
$(CC) -ansi $(CFLAGS) $(BCCDEFS) $(LDFLAGS) bcc.c -o $@
+ncc: bcc.c
+ $(CC) -ansi $(CFLAGS) -DL_TREE -DDEFARCH=0 $(LDFLAGS) bcc.c -o $@
+
bcc09: bcc.c
$(CC) -ansi $(CFLAGS) -DMC6809 $(BCCDEFS) $(LDFLAGS) bcc.c -o $@
@@ -43,8 +39,8 @@ ccc: bcc.c
bcc-cc1: $(OBJS)
$(CC) $(LDFLAGS) $(OBJS) -o bcc-cc1
-clean:
- rm -f bcc bcc-cc1 bcc09 ccc bcc.o $(OBJS)
+clean realclean:
+ rm -f bcc bcc-cc1 ncc bcc09 ccc bcc.o $(OBJS)
$(OBJS): align.h byteord.h condcode.h const.h gencode.h input.h label.h os.h \
diff --git a/bcc/bcc.c b/bcc/bcc.c
index 6b8d3a0..9f7474d 100644
--- a/bcc/bcc.c
+++ b/bcc/bcc.c
@@ -24,21 +24,31 @@
#ifdef __STDC__
#define P(x) x
+#define HASHIT(x) #x
+#define QUOT(x) HASHIT(x)
#else
#define P(x) ()
+/* Well you find something that works! */
+#define QUOT(x) "x"
#endif
#ifdef MSDOS
-#define LOCALPREFIX "/linux86"
+#define LOCALPREFIX /linux86
#define EXESUF ".exe"
#define R_OK 4 /* Test for read permission. */
#define W_OK 2 /* Test for write permission. */
#define X_OK 1 /* Test for execute permission. */
#define F_OK 0 /* Test for existence. */
+#define L_TREE 1 /* Use different tree style */
+#define DEFARCH 0 /* Default to 8086 code */
#else
#define EXESUF
#endif
+#ifdef __minix
+#define realpath(x,y) 0
+#endif
+
#define BAS86
#define BCC86
@@ -51,8 +61,9 @@
#define GCC "gcc"
#define LD "ld86" EXESUF
#define UNPROTO "unproto" EXESUF
+#define OPTIM "copt" EXESUF
-#ifdef MSDOS
+#ifdef L_TREE
#define STANDARD_CRT0_0_PREFIX "~/lib/"
#define STANDARD_CRT0_3_PREFIX "~/lib/i386/"
#define STANDARD_EXEC_PREFIX "~/lib/"
@@ -60,6 +71,7 @@
#define DEFAULT_INCLUDE "-I~/include"
#define DEFAULT_LIBDIR0 "-L~/lib/"
#define DEFAULT_LIBDIR3 "-L~/lib/i386/"
+#define OPTIM_RULES "-d~/lib"
#else
#define STANDARD_CRT0_0_PREFIX "~/lib/bcc/i86/"
#define STANDARD_CRT0_3_PREFIX "~/lib/bcc/i386/"
@@ -68,6 +80,7 @@
#define DEFAULT_INCLUDE "-I~/include"
#define DEFAULT_LIBDIR0 "-L~/lib/bcc/i86/"
#define DEFAULT_LIBDIR3 "-L~/lib/bcc/i386/"
+#define OPTIM_RULES "-d~/lib/bcc/i86"
#endif
#ifdef CCC
@@ -117,6 +130,7 @@ PRIVATE struct arg_s asargs = { AS, };
PRIVATE struct arg_s ccargs = { CC1, CC1_MINUS_O_BROKEN, };
PRIVATE struct arg_s cppargs = { CPP, };
PRIVATE struct arg_s unprotoargs = { UNPROTO, TRUE };
+PRIVATE struct arg_s optargs = { OPTIM };
#ifdef STANDARD_CRT0_PREFIX
PRIVATE struct prefix_s crt0_prefix = { STANDARD_CRT0_PREFIX, };
#endif
@@ -137,7 +151,7 @@ PRIVATE struct arg_s tmpargs; /* = empty */
PRIVATE char *tmpdir;
PRIVATE unsigned verbosity; /* = 0 */
-PRIVATE char * localprefix = LOCALPREFIX;
+PRIVATE char * localprefix = QUOT(LOCALPREFIX);
#ifdef REDECLARE_STDC_FUNCTIONS
void exit P((int status));
@@ -173,7 +187,7 @@ FORWARD char *my_mktemp P((void));
FORWARD void my_unlink P((char *name));
FORWARD void outofmemory P((char *where));
FORWARD int run P((char *in_name, char *out_name, struct arg_s *argp));
-#ifdef MSDOS
+#ifdef L_TREE
FORWARD void reset_localprefix P((void));
#endif
FORWARD void set_trap P((void));
@@ -218,6 +232,11 @@ char **argv;
char *crt0;
#endif
char *libc = "-lc";
+#ifdef MSDOS
+ char major_mode = 'd';
+#else
+ char major_mode = 0;
+#endif
bool_T debug = FALSE;
bool_T echo = FALSE;
unsigned errcount = 0;
@@ -234,13 +253,14 @@ char **argv;
unsigned nifiles = 0;
unsigned npass_specs;
bool_T optimize = FALSE;
+ char *optflags = 0;
char *out_name;
bool_T profile = FALSE;
bool_T prep_only = FALSE;
bool_T prep_line_numbers = FALSE;
int status;
char *temp;
- bool_T patch_exe = FALSE;
+ bool_T patch_exe = FALSE; /* Hackish patch to convert minix i386->OMAGIC */
progname = argv[0];
addarg(&cppargs, CPPFLAGS);
@@ -252,9 +272,11 @@ char **argv;
addarg(&ldrargs, "-r");
addarg(&ldrargs, "-N"); /* GCC uses native objects */
/* GCC also uses 386 how to add -3 too ? */
+ addarg(&optargs, "-c!");
+ optflags = stralloc("start");
#endif
-#ifdef MSDOS
+#ifdef L_TREE
reset_localprefix();
#endif
/* Pass 1 over argv to gather compile options. */
@@ -287,7 +309,10 @@ char **argv;
prep_line_numbers = FALSE;
break;
case 'O':
- optimize = TRUE; /* unsupported( arg, "optimize" ); */
+ optimize = TRUE;
+ temp = optflags;
+ optflags=stralloc2(optflags,",86");
+ free(temp);
break;
case 'S':
cc_only = TRUE;
@@ -390,31 +415,19 @@ char **argv;
addarg(&ldargs, arg);
break;
case 'M':
- switch(arg[2])
+ major_mode=arg[2];
+ break;
+
+ case 'O':
+ optimize = TRUE;
+ temp=optflags; optflags=stralloc2(optflags,","); free(temp);
+ temp=optflags; optflags=stralloc2(optflags,arg+2); free(temp);
+ if( arg[3] == 0 && ( arg[2] >= '1' && arg[2] <= '3' ))
{
- case 'd': /* DOS compile */
-#ifndef CCC
- addarg(&ccargs, "-D__MSDOS__");
-#endif
- addarg(&cppargs, "-D__MSDOS__");
- addarg(&ldargs, "-d");
- addarg(&ldargs, "-s");
- addarg(&ldargs, "-T100");
- libc= "-ldos";
- break;
- case 'f': /* Caller saves+ax is first arg */
- libc= "-lc_f";
- addarg(&ccargs, "-f");
- addarg(&ccargs, "-c");
- break;
- case 's': /* Standalone executable */
-#ifndef CCC
- addarg(&ccargs, "-D__STANDALONE__");
-#endif
- addarg(&cppargs, "-D__STANDALONE__");
- addarg(&ldargs, "-s");
- libc= "-lc_s";
- break;
+ temp=optflags;
+ optflags=stralloc2(optflags,"86,86");
+ free(temp);
+ addarg(&optargs, "-huse16 386");
}
break;
case 'P':
@@ -467,7 +480,61 @@ char **argv;
if (errcount != 0)
exit(1);
- if( !aswarn )
+#ifdef BCC86
+ switch(major_mode)
+ {
+ case 'd': /* DOS compile */
+ bits32 = FALSE;
+ libc= "-ldos";
+#ifndef CCC
+ addarg(&ccargs, "-D__MSDOS__");
+#endif
+ addarg(&cppargs, "-D__MSDOS__");
+ addarg(&ldargs, "-d");
+ addarg(&ldargs, "-s");
+ addarg(&ldargs, "-T100");
+ break;
+
+ case 'n': /* Normal Linux-86 */
+ bits32 = FALSE;
+ libc= "-lc";
+ break;
+
+ case 'f': /* Caller saves+ax is first arg */
+ bits32 = FALSE;
+ libc= "-lc_f";
+ addarg(&ccargs, "-f");
+ addarg(&ccargs, "-c");
+ break;
+
+ case 'c': /* Just caller saves, normal C-lib is ok */
+ bits32 = FALSE;
+ libc= "-lc";
+ addarg(&ccargs, "-c");
+ break;
+
+ case 's': /* Standalone executable */
+ bits32 = FALSE;
+ libc= "-lc_s";
+#ifndef CCC
+ addarg(&ccargs, "-D__STANDALONE__");
+#endif
+ addarg(&cppargs, "-D__STANDALONE__");
+ break;
+
+ case 'l': /* Large Linux compile */
+ bits32 = TRUE;
+ libc= "-lc";
+#ifndef CCC
+ addarg(&ccargs, "-D__linux__");
+#endif
+ addarg(&cppargs, "-D__linux__");
+ addarg(&ldargs, "-N"); /* Make OMAGIC */
+ break;
+ }
+#endif
+
+if( !aswarn )
addarg(&asargs, "-w");
if( patch_exe )
addarg(&ldargs, "-s");
@@ -500,6 +567,14 @@ char **argv;
#endif
addarg(&ldargs, DEFAULT_LIBDIR0);
}
+
+ addarg(&optargs, OPTIM_RULES);
+ temp=optflags; optflags=stralloc2(optflags,",end"); free(temp);
+ for(temp=strtok(optflags,","); temp; temp=strtok((char*)0,","))
+ {
+ temp = stralloc2("rules.", temp);
+ addarg(&optargs, temp);
+ }
addprefix(&exec_prefix, STANDARD_EXEC_PREFIX);
addprefix(&exec_prefix, STANDARD_EXEC_PREFIX_2);
cppargs.prog = fixpath(cppargs.prog, &exec_prefix, X_OK);
@@ -510,6 +585,7 @@ char **argv;
ldrargs.prog = fixpath(ldrargs.prog, &exec_prefix, X_OK);
#endif
unprotoargs.prog=fixpath(unprotoargs.prog, &exec_prefix, X_OK);
+ optargs.prog = fixpath(optargs.prog, &exec_prefix, X_OK);
if (tmpdir == NUL_PTR && (tmpdir = getenv("TMPDIR")) == NUL_PTR)
#ifdef MSDOS
tmpdir = ".";
@@ -603,7 +679,7 @@ char **argv;
{
if (prep_only)
continue;
- if (cc_only)
+ if (cc_only && !optimize)
{
if (f_out != NUL_PTR)
out_name = f_out;
@@ -618,6 +694,25 @@ char **argv;
if (run(in_name, out_name, &ccargs) != 0)
continue;
in_name = out_name;
+ if( optimize )
+ {
+ if (cc_only)
+ {
+ if (f_out != NUL_PTR)
+ out_name = f_out;
+ else
+ {
+ out_name = stralloc(basename);
+ out_name[strlen(out_name) - 1] = 's';
+ }
+ }
+ else
+ out_name = my_mktemp();
+
+ if (run(in_name, out_name, &optargs) != 0)
+ continue;
+ in_name = out_name;
+ }
ext = 's';
}
if (ext == 'S')
@@ -826,6 +921,7 @@ static struct aout_exec {
close(fd);
}
+#ifdef L_TREE
#ifdef MSDOS
PRIVATE void reset_localprefix()
{
@@ -846,6 +942,68 @@ PRIVATE void reset_localprefix()
else
free(temp);
}
+#else
+
+PRIVATE void reset_localprefix()
+{
+ char *ptr, *temp;
+
+ if( *progname == '/' )
+ temp = stralloc(progname);
+ else
+ {
+ char * s, * d;
+ ptr = getenv("PATH");
+ if( ptr==0 || *ptr == 0 ) return;
+ ptr = stralloc(ptr);
+ temp = stralloc("");
+
+ for(d=s=ptr; d && *s; s=d)
+ {
+#ifdef MAXPATHLEN
+ char buf[MAXPATHLEN];
+#else
+ char buf[1024];
+#endif
+
+ free(temp);
+ d=strchr(s, ':');
+ if( d ) *d='\0';
+ temp = my_malloc(strlen(progname)+strlen(s)+2, "prefixing");
+ strcpy(temp, s);
+ strcat(temp, "/");
+ strcat(temp, progname);
+ if( realpath(temp, buf) != 0 )
+ {
+ free(temp);
+ temp = stralloc(buf);
+ }
+ if( access(temp, X_OK) == 0 ) break;
+ d++;
+ }
+ if( s == 0 )
+ {
+ free(temp);
+ temp = stralloc(progname);
+ }
+ free(ptr);
+ }
+
+ if( (ptr = strrchr(temp, '/')) != 0
+ && temp<ptr-4 && strncmp(ptr-4, "/bin", 4) == 0 )
+ {
+ ptr[-4] = 0;
+ localprefix = temp;
+ if (verbosity > 2)
+ {
+ show_who("localprefix is now ");
+ writesn(localprefix);
+ }
+ }
+ else
+ free(temp);
+}
+#endif
#endif
PRIVATE char * expand_tilde(str, canfree)
@@ -966,13 +1124,14 @@ PRIVATE char *my_mktemp()
static unsigned tmpnum;
#ifdef MSDOS
- p = template = stralloc2(tmpdir, "/$$YYYXXX");
+ digits = 42;
+ p = template = stralloc2(tmpdir, "/$$YYYYXX");
#else
+ digits = getpid();
p = template = stralloc2(tmpdir, "/bccYYYYXXXX");
#endif
p += strlen(p);
- digits = getpid();
while (*--p == 'X')
{
if ((digit = digits % 16) > 9)
@@ -1060,6 +1219,12 @@ struct arg_s *argp;
if (verbosity > 4 ) return 0;
#ifdef MSDOS
status = spawnv(0, argp->prog, argp->argv+arg0);
+ if( status<0 )
+ {
+ show_who("spawn of ");
+ writes(argp->prog);
+ writesn(" failed");
+ }
#else
switch (fork())
{
diff --git a/bcc/bcc.exe b/bcc/bcc.exe
deleted file mode 100644
index db47d08..0000000
--- a/bcc/bcc.exe
+++ /dev/null
Binary files differ
diff --git a/bcc/const.h b/bcc/const.h
index 20608c2..f8fd692 100644
--- a/bcc/const.h
+++ b/bcc/const.h
@@ -2,6 +2,12 @@
/* Copyright (C) 1992 Bruce Evans */
+#ifdef __STDC__
+#include <stdlib.h>
+#else
+#include <malloc.h>
+#endif
+
/* switches for code generation */
#if !defined(I8088) && !defined(MC6809)
diff --git a/bcc/input.c b/bcc/input.c
index f32fd9e..f905416 100644
--- a/bcc/input.c
+++ b/bcc/input.c
@@ -433,7 +433,10 @@ ts_s_pathname_tot -= strlen(inputbuf->fname) + 1;
ts_s_inputbuf_tot -= sizeof *inputbuf;
#endif
ourfree((char *) inputbuf);
- close(input.fd);
+#ifndef NO_EOFHACK
+ if(input.fd>=0)
+#endif
+ close(input.fd);
#ifdef FAKE_INBUFSIZE_1
fclose(input.fp);
#endif
@@ -675,7 +678,23 @@ case0:
#endif
*lineptr = ich;
#else
- nread = read(input.fd, lineptr = inputbuf->fbuf, INBUFSIZE);
+#ifndef NO_EOFHACK
+ if(input.fd<0)
+ nread=0;
+ else
+ {
+#endif
+ nread = read(input.fd, lineptr = inputbuf->fbuf, INBUFSIZE);
+#ifndef NO_EOFHACK
+ if( nread == 0 && inclevel > 0 )
+ {
+ close(input.fd);
+ input.fd = -1;
+ memcpy(inputbuf->fbuf, "\n", 1);
+ nread = 1;
+ }
+ }
+#endif
#endif
if (nread < 0)
fatalerror("input error");
diff --git a/bcc/preproc.c b/bcc/preproc.c
index 030214b..b9aed0e 100644
--- a/bcc/preproc.c
+++ b/bcc/preproc.c
@@ -64,7 +64,9 @@ FORWARD void undef P((void));
PRIVATE void asmcontrol()
{
+#ifdef ASM_BARE
char treasure; /* to save at least one leading blank */
+#endif
asmmode = TRUE;
if (orig_cppmode)
diff --git a/bcc/proto.h b/bcc/proto.h
index cd26e0c..e45cf0e 100644
--- a/bcc/proto.h
+++ b/bcc/proto.h
@@ -7,7 +7,6 @@
#else
#define P(x) ()
#endif
-#include <malloc.h>
/* assign.c */
void assign P((struct symstruct *source, struct symstruct *target));
diff --git a/bootblocks/Makefile b/bootblocks/Makefile
index 9a4ccd9..85393a7 100644
--- a/bootblocks/Makefile
+++ b/bootblocks/Makefile
@@ -1,17 +1,16 @@
HOSTCC=cc
HOSTCCFLAGS=-O
+BCC=bcc
-CC=bcc
-CFLAGS=-ansi -O -Ms
-AS=as86
+CC=$(BCC)
+CFLAGS=-ansi -Ms -H0x10000 -s
ASFLAGS=-0
# LST=-l $*.lst
-nothing:
- @more README
+default: makeboot makeboot.com monitor.out
-all: makeboot monitor.out bin
+all: default tgz bin
CSRC=minix.c
SSRC=tarboot.s skip.s com_bcc.s tich.s sysboot.s bootlist.s mbr.s msdos.s
@@ -19,8 +18,8 @@ SSRC=tarboot.s skip.s com_bcc.s tich.s sysboot.s bootlist.s mbr.s msdos.s
encap: $(SSRC:s=v) $(CSRC:c=v)
bin: $(SSRC:s=bin) $(CSRC:c=bin)
-MOBJ=monitor.o i86_funcs.o relocate.o
-MSRC=monitor.c i86_funcs.c relocate.c
+MOBJ=monitor.o i86_funcs.o relocate.o help.o bzimage.o dosfs.o nofs.o
+MSRC=monitor.c i86_funcs.c relocate.c help.c bzimage.c dosfs.c nofs.c
install:
@@ -29,40 +28,41 @@ monitor.out: $(MOBJ)
monitor: $(MSRC)
@rm -f $(MOBJ)
- make 'CFLAGS=-ansi -O' monitor.out
+ make 'CFLAGS=-ansi' monitor.out
mv monitor.out monitor
@rm -f $(MOBJ)
minix.s: minix.c
- bcc -Mf -O -S minix.c
+ $(BCC) -Mc -S minix.c
-makeboot: tarboot.v sysboot.v makeboot.c
+makeboot: makeboot.c sysboot.v skip.v msdos.v tarboot.v
$(HOSTCC) $(HOSTCCFLAGS) -o makeboot makeboot.c
-dosboot: dosboot.c sysboot.v skip.v msdos.v
- $(HOSTCC) $(HOSTCCFLAGS) -o dosboot dosboot.c
+makeboot.com: makeboot.c sysboot.v skip.v msdos.v tarboot.v
+ $(BCC) -Md -o makeboot.com makeboot.c
-clean:
- rm -f monitor makeboot dosboot minix.s *.o *.bin *.out *.lst *.sym *.v
+clean realclean:
+ rm -f monitor makeboot bootblocks.tar.gz
+ rm -f minix.s *.com *.o *.bin *.out *.lst *.sym *.v
-tgz: minix.bin monitor.out makeboot
+tgz: minix.bin monitor.out makeboot.com makeboot
tar cfV bootblocks.tar ENIAC monitor.out \
README Makefile \
- $(MSRC) dosboot.c makeboot.c \
+ $(MSRC) makeboot.c \
$(CSRC) $(SSRC) \
- makeboot minix.bin
- makeboot bootblocks.tar
+ makeboot.com minix.bin
+ makeboot tar bootblocks.tar
gzip -f9 bootblocks.tar
distribution:
tar czf /tmp/bootblocks.tar.gz README Makefile \
- $(MSRC) dosboot.c makeboot.c \
+ $(MSRC) makeboot.c \
$(CSRC) $(SSRC)
.SUFFIXES: .bin .v
.s.bin:
- $(AS) $(ASFLAGS) -b $*.bin -s $*.sym -l $*.lst $*.s
+ $(BCC) -c $*.s -A-b -A$*.bin -A-s -A$*.sym -A-l -A$*.lst
.s.v:
as86_encap $*.s $*.v $*_ $(ASFLAGS) $(LST)
diff --git a/bootblocks/README b/bootblocks/README
index c57f3aa..5d2344b 100644
--- a/bootblocks/README
+++ b/bootblocks/README
@@ -12,18 +12,43 @@ $ tar cvfV /dev/fd0 ENIAC monitor.out item2 item3
Make it bootable
-$ makeboot /dev/fd0
+$ makeboot tar /dev/fd0
Note, the distribution tar file is made using this procedure and can be booted
if uncompressed and copied onto a raw floppy.
+To install the dosfs boot sector
+--------------------------------
+
+$ make makeboot
+$ makeboot dosfs /dev/fd0
+
+or
+$ make makeboot.com
+C:\> makeboot dos a:
+
+ Place a Linux-8086 executable in the root directory of the floppy.
+
+$ make monitor.out
+$ mount -t msdos /dev/fd0 /mnt
+$ cp monitor.out /mnt/bootfile.sys
+$ umount /dev/fd0
+
+or
+C:\> copy monitor.out a:\bootfile.sys
+
+ This works on my 3 1/5 floppy and my 5 1/4, and it _should_ work on
+ any double sided drive. (It does work on a 3.5/720k floppy too)
+ For single sided floppies you need to alter msdos.s (the heads var)
+ and remove the check in makeboot.c
+
To install the minixfs boot sector
----------------------------------
Make a minix filesystem on the floppy:
$ mkfs -t minix /dev/fd0 1440
-
+or
$ mkfs -t minix /dev/fd0 1200
Make the bootblock program.
@@ -41,22 +66,51 @@ $ mount -t minix /dev/fd0 /mnt
$ cp monitor.out /mnt/linux
$ umount /dev/fd0
- Or in a tar file:
+ This works on my 3 1/4 floppy, and it _should_ work on any double sided
+ drive. Be sure to make the filesystem the full size of the floppy.
-$ make monitor.out
-$ mount -t minix /dev/fd0 /mnt
-$ tar cvf /mnt/linux monitor.out long list of other files
+
+Booting a Linux-386 bzImage
+---------------------------
+
+NOTE: This only works with bzImage files NOT zImage files.
+
+Take 1 msdos floppy.
+
+$ makeboot dos /dev/fd0
+$ mount -t msdos /dev/fd0 /mnt
+$ cp monitor.out /mnt/bootfile.sys
+$ umount /dev/fd0
+$ cp /usr/src/linux/arch/i386/boot/bzImage /mnt/fd0/vmlinuz
+$ echo 'root=/dev/ram ramdisk_file=ramdisk.gz mem=80M' > /mnt/fd0/vmlinuz.cmd
+$ cp /archive/ramdisk.gz /mnt/fd0/ramdisk.gz
$ umount /dev/fd0
- This works on my 3 1/4 floppy, and it _should_ work on any double sided
- drive. Be sure to make the filesystem the full size of the floppy.
+The stuff about ramdisk is only if you want an init ramdisk. You can also use:
+
+vmlinuz.app: Arguments prepended to the Linux command line.
+vmlinuz.cmd: Arguments appended to the Linux command line.
+vmlinux.dfl: Arguments appended to the Linux command line.
+
+If there's a *.cmd file you won't be asked anything. If there's a *.dfl or
+neither you'll be asked:
+
+vmlinuz:
-To boot the floppy in DOSEMU
-----------------------------
+where you can type a command line to override the *.dfl file. If there's
+a *.cmd file the *.dfl file is ignored, the *.app file is placed at the
+start of the line whichever you do.
-$ dos -A
+If the file isn't called 'vmlinuz' you can still boot it by typing "=linux"
+at the prompt '>' where 'linux' is the name of the bzImage file.
- Press ^C to exit DOSEMU from inside monitor.c
+Escape or ^C will interrupt the boot and drop you to the '>' prompt.
+Esacpe or ^C at the '>' prompt will reboot
+ (This may be a little sensitive :-)
-Rob.
+A file called 'help.txt' will be displayed upto the first line that starts
+with a '%', chunks after that (seperated by '%'s) will be displayed when
+the user presses a function key, home, page up or page down. (Note it's
+best if you try to ensure 'help.txt' is completely contained on one track
+so the file is entirely in the track buffer)
diff --git a/bootblocks/bzimage.c b/bootblocks/bzimage.c
new file mode 100644
index 0000000..8d38753
--- /dev/null
+++ b/bootblocks/bzimage.c
@@ -0,0 +1,555 @@
+/*
+ * Load and execute a bzImage file from the device the 'open_file' and
+ * friends use.
+ */
+
+#include <stdio.h>
+#include "i86_funcs.h"
+#include "readfs.h"
+
+int auto_flag = 1;
+char * append_line = 0; /* A preset append line value */
+
+static char * initrd_name = 0; /* Name of init_ramdisk to load */
+static int vga_mode = -1; /* SVGA_MODE = normal */
+
+static char * read_cmdfile();
+static char * input_cmd();
+
+cmd_bzimage(ptr)
+char * ptr;
+{
+ char * image;
+ int ch;
+
+ if( (auto_flag=(ptr==0)) ) ptr="";
+
+ while(*ptr == ' ') ptr++;
+ image = ptr;
+ while(*ptr != ' ' && *ptr) ptr++;
+ ch = *ptr;
+ *ptr = '\0';
+ if( ch ) ptr++;
+ while(*ptr == '\n' || *ptr == ' ') ptr++;
+
+ if( *ptr == '\0' ) ptr = 0;
+ if( *image )
+ bzimage(image, ptr);
+ else
+ bzimage("vmlinuz", ptr);
+}
+
+bzimage(fname, command_line)
+char * fname;
+char * command_line;
+{
+ char buffer[1024];
+ long len;
+ char * ptr;
+ int low_sects;
+ unsigned int address;
+
+ if( open_file(fname) < 0 )
+ {
+ if( auto_flag == 0 )
+ printf("Cannot find file %s\n", fname);
+ return -1;
+ }
+
+ printf("Loading %s\n", fname);
+
+ if( read_block(buffer) < 0 || check_magics(buffer) < 0 )
+ {
+ printf("File %s isn't a bzImage.\n", fname);
+ return -1;
+ }
+
+ if( boot_mem_top < 0x9500 )
+ {
+ printf("There must be 640k of boot memory to load Linux\n");
+ return -1;
+ }
+
+ /* Guestimate how much the uncompressed kernel will use.
+ * I expect we could lookup the size in the gzip header but
+ * this is probably close enough (3*the size of the bzimage)
+ */
+ len = file_length() * 3 / 1024;
+ if( main_mem_top < len )
+ {
+ printf("This kernel needs at least %ld.%ldM of main memory\n",
+ len/1024, len*10/1024%10);
+ return -1;
+ }
+ if( main_mem_top < 3072 )
+ printf("RTFM warning: Linux really needs at least 4MB of memory.\n");
+
+ low_sects = buffer[497] + 1; /* setup sects + boot sector */
+ address = 0x900;
+
+ /* load the blocks */
+ rewind_file();
+ for(len = file_length(); len>0; len-=1024)
+ {
+ int v;
+
+ printf("%ldk to go \r", len/1024); fflush(stdout);
+
+ v = (bios_khit()&0x7F);
+ if( v == 3 || v == 27 )
+ {
+ printf("User interrupt!\n");
+ bios_getc();
+ return -1;
+ }
+
+ if( read_block(buffer) < 0 )
+ {
+ printf("Error loading %s\n", fname);
+ return -1;
+ }
+
+ for(v=0; v<1024; v+=512)
+ {
+ if( putsect(buffer+v, address) < 0 )
+ return -1;
+
+ address += 2;
+
+ if( low_sects )
+ {
+ low_sects--;
+ if( low_sects == 0 ) address = 0x1000;
+ }
+ }
+ }
+
+ /* Yesss, loaded! */
+ printf("Loaded, "); fflush(stdout);
+
+ /* Ok, deal with the command line */
+ if( build_linuxarg(auto_flag, fname, append_line, command_line) < 0 )
+ return -1;
+
+ if( initrd_name )
+ if( load_initrd(address) < 0 )
+ return -1;
+
+ printf("Starting ...\n");
+
+ if( x86 < 3 )
+ {
+ printf("RTFM error: Linux-i386 needs a CPU >= 80386\n");
+ if( !keep_going() ) return -1;
+ }
+
+ if( a20_closed() ) open_a20();
+ if( a20_closed() )
+ {
+ printf("Normal routine for opening A20 Gate failed, Trying PS/2 Bios\n");
+ bios_open_a20();
+ }
+ if( a20_closed() )
+ {
+ printf("All routines for opening A20 Gate failed, if I can't open it\n");
+ printf("then Linux probably can't either!\n");
+ if( !keep_going() ) return -1;
+ }
+
+ /* Patch setup to deactivate safety switch */
+ __set_es(0x9000);
+ __poke_es(0x210, 0xFF);
+
+ /* Set SVGA_MODE if not 'normal' */
+ if( vga_mode != -1 ) __doke_es(506, vga_mode);
+
+ /* Default boot drive is auto-detected floppy */
+ if( __peek_es(508) == 0 ) __poke_es(508, 0x200);
+
+ /* Finally do the deed */
+ {
+#asm
+ ! Kill the floppy motor, needed in case the kernel has no floppy driver.
+ mov dx,#0x3f2
+ xor al, al
+ outb
+
+ ! Setup required registers and go ...
+ mov ax,$9000
+ mov bx,$4000-12 ! Fix this to use boot_mem_top
+ mov es,ax
+ mov ds,ax
+ mov ss,ax
+ mov sp,bx
+ jmpi 0,$9020 ! Note SETUPSEG NOT INITSEG
+#endasm
+ }
+}
+
+check_magics(buffer)
+char * buffer;
+{
+ /* Boot sector magic number */
+ if( *(unsigned short*)(buffer+510) != 0xAA55 ) return -1;
+
+ /* Setup start */
+ if( memcmp(buffer+0x202, "HdrS", 4) != 0 ) return -1;
+
+ /* Setup version */
+ if( *(unsigned short*)(buffer+0x206) < 0x200 ) return -1;
+
+ /* Check load flags for bzImage */
+ if( (buffer[0x211] & 1) == 0 ) return -1;
+
+ /* Code 32 start address */
+ if( *(unsigned long*)(buffer+0x214) != 0x100000 ) return -1;
+
+ return 0;
+}
+
+putsect(buffer, address)
+char * buffer;
+unsigned int address;
+{
+ int rv, tc=3;
+retry:
+ tc--;
+#if 1
+ if( x86_emu )
+ {
+static unsigned int last_address = 0;
+ if( address <= last_address )
+ printf("Problem %d<=%d\n", address, last_address);
+ if( address < 0xA00 )
+ {
+ int i;
+ __set_es(address*16);
+ for(i=0; i<512; i++)
+ __poke_es(i, buffer[i]);
+ }
+ return 0;
+ }
+#endif
+ if( (rv=ext_put(buffer, address, 512)) != 0 )
+ {
+ switch(rv)
+ {
+ case 1:
+ printf("Parity error while copying to extended memory\n");
+ break;
+ case 2:
+ printf("Interrupt error while copying to extended memory\n");
+ if ( tc>0 ) goto retry;
+ break;
+ case 3:
+ printf("BIOS cannot open A20 Gate\n");
+ break;
+ case 0x80: case 0x86:
+ printf("BIOS has no extended memory support\n");
+ break;
+ default:
+ printf("Error %d while copying to extended memory\n", rv);
+ break;
+ }
+ if( x86 < 3 )
+ printf("RTFM error: Linux-i386 needs a CPU >= 80386\n");
+ else if( x86_emu )
+ printf("RTFM error: Linux-i386 cannot be run in an emulator.\n");
+ return -1;
+ }
+ return 0;
+}
+
+static char *
+read_cmdfile(iname, extno)
+char * iname;
+int extno;
+{
+ char buffer[1024];
+ char buf[16];
+ long len;
+ char * ptr = strchr(iname, '.');
+
+ buf[8] = '\0';
+ strncpy(buf, iname, 8);
+ switch(extno)
+ {
+ case 1: strcat(buf, ".cmd"); break;
+ case 2: strcat(buf, ".app"); break;
+ case 3: strcat(buf, ".dfl"); break;
+ default: return 0;
+ }
+
+ if( ptr == 0 && open_file(buf) >= 0 )
+ {
+ /* Ah, a command line ... */
+ if( extno == 1 ) printf("Loading %s\n", buf);
+ len = file_length();
+ if( len > 1023 )
+ {
+ printf("Command line file %s truncated to 1023 characters\n", buf);
+ len = 1023;
+ }
+ if( read_block(buffer) >= 0 )
+ {
+ int i;
+ for(i=0; i<len; i++)
+ if( buffer[i] < ' ' ) buffer[i] = ' ';
+ buffer[len] = '\0';
+
+ return strdup(buffer);
+ }
+ }
+ return 0;
+}
+
+char *
+input_cmd(iname)
+char * iname;
+{
+ char buffer[1024];
+ char lbuf[20];
+ int cc;
+
+ for(;;)
+ {
+ printf("%s: ", iname); fflush(stdout);
+
+ cc = read(0, buffer, sizeof(buffer)-1);
+ if( cc <= 0 ) return 0;
+ buffer[cc] = 0;
+ if( cc == 1 && *buffer != '\n' )
+ {
+ putchar('\n');
+ cc = (buffer[0] & 0xFF);
+
+ if( cc == 0xAD ) /* ALT-X */
+ return 0;
+
+ sprintf(lbuf, "$%02x", cc);
+ cmd_help(lbuf);
+ continue;
+ }
+ if( buffer[cc-1] == '\n' ) buffer[cc-1] = '\0';
+
+ break;
+ }
+
+ return strdup(buffer);
+}
+
+build_linuxarg(auto_flg, image, append, cmd)
+int auto_flg;
+char *image, *append, *cmd;
+{
+static char * auto_str = "auto";
+static char * image_str = "BOOT_IMAGE=";
+ int len = 0;
+ char * ptr, *s, *d;
+
+ char * free_cmd = 0;
+ char * free_app = 0;
+ char * free_dfl = 0;
+
+ if( append == 0 )
+ append = free_app = read_cmdfile(image, 2);
+
+ if( cmd == 0 )
+ cmd = free_cmd = read_cmdfile(image, 1);
+
+ if( cmd == 0 )
+ free_dfl = read_cmdfile(image, 3);
+
+ close_file(); /* Free up loads a room */
+
+ if( cmd == 0 )
+ {
+ cmd = free_cmd = input_cmd(image);
+ auto_flg = 0;
+ }
+
+ if( cmd == 0 )
+ {
+ printf("Aborted execution\n");
+ return -1;
+ }
+ else if( *cmd == 0 )
+ cmd = free_dfl;
+
+ if( auto_flg ) len += strlen(auto_str) + 1;
+ if( image ) len += strlen(image_str) + strlen(image) + 1;
+ if( append ) len += strlen(append) + 1;
+ if( cmd ) len += strlen(cmd) + 1;
+
+ if( len == 0 ) return 0;
+
+ ptr = malloc(len+1);
+ if( ptr == 0 )
+ {
+ printf("Unable to create linux command line\n");
+ if( free_cmd ) free(free_cmd);
+ if( free_app ) free(free_app);
+ if( free_dfl ) free(free_dfl);
+ return -1;
+ }
+
+ *ptr = 0; ptr[1] = 0;
+ if( auto_flg ) { strcat(ptr, " "); strcat(ptr, auto_str); }
+ if( image ) { strcat(ptr, " "); strcat(ptr, image_str); strcat(ptr, image); }
+ if( append ) { strcat(ptr, " "); strcat(ptr, append); }
+ if( cmd ) { strcat(ptr, " "); strcat(ptr, cmd); }
+
+ if( free_cmd ) free(free_cmd);
+ if( free_app ) free(free_app);
+ if( free_dfl ) free(free_dfl);
+
+ if( (d = malloc(len+1)) == 0 )
+ {
+ printf("Unable to compact linux command line\n");
+ free(ptr);
+ return -1;
+ }
+ *d = '\0';
+ for(s=strtok(ptr, " "); s; s=strtok((char*)0, " "))
+ {
+ if( strncmp(s, "vga=",4) == 0 )
+ {
+ if( strncmp(s+4, "ask", 3) == 0 )
+ vga_mode = -3;
+ else
+ {
+ s+=4; getnum(&s, &vga_mode);
+ }
+ }
+ else if( strncmp(s, "ramdisk_file=", 13) == 0 )
+ {
+ if( initrd_name ) free(initrd_name);
+ if( s[13] )
+ initrd_name = strdup(s+13);
+ else
+ initrd_name = 0;
+ }
+ else
+ {
+ strcat(d, " ");
+ strcat(d, s);
+ }
+ }
+ free(ptr); ptr = d;
+ len = strlen(ptr);
+
+ if( len > 2048 )
+ {
+ printf("Linux command line truncated to 2047 characters\n");
+ ptr[2048] = 0;
+ len = 2048;
+ }
+
+ __set_es(0x9000);
+ __doke_es(0x0020, 0xA33F);
+ __doke_es(0x0022, 0x4000);
+
+ __movedata(__get_ds(), (unsigned)ptr+1, 0x9000, 0x4000, len);
+
+ free(ptr);
+
+ return 0;
+}
+
+keep_going()
+{
+static int burning = 0;
+ char buf[1];
+ int cc;
+
+ printf("Keep going ? "); fflush(stdout);
+
+ cc = read(0, buf, 1);
+ if( cc == 1 && (*buf == 'Y' || *buf == 'y') )
+ {
+ printf("Yes, Ok%s\n", burning?"":", burn baby burn!");
+ return burning=1;
+ }
+ printf("No, Ok returning to monitor prompt\n");
+ return 0;
+}
+
+load_initrd(k_top)
+unsigned int k_top;
+{
+ unsigned int address, rd_start, rd_len;
+ long file_len;
+ char * fname = initrd_name;
+
+ char buffer[1024];
+
+ /* Top of accessable memory */
+ if( main_mem_top >= 15360 ) address = 0xFFFF;
+ else address = 0x1000 + main_mem_top*4;
+
+ if( *initrd_name == '+' )
+ {
+ char buf[2];
+ fname++;
+ close_file();
+ printf("Insert root floppy and press return:"); fflush(stdout);
+ read(0, buf, 2);
+ }
+
+ if( open_file(fname) < 0 )
+ {
+ printf("Cannot open %s\n", fname);
+ return -1;
+ }
+ file_len = file_length();
+ rd_len = (file_len+1023)/1024;
+
+ if( file_len > 15000000L || k_top + rd_len*4 > address )
+ {
+ printf("Ramdisk file %s is too large to load\n", fname);
+ return -1;
+ }
+
+ rd_start = address - rd_len*4;
+ rd_start &= -16; /* Page boundry */
+ address = rd_start;
+
+ printf("Loading %s at 0x%x00\n", fname, rd_start);
+
+ for( ; rd_len>0 ; rd_len--)
+ {
+ int v = (bios_khit()&0x7F);
+ if( v == 3 || v == 27 )
+ {
+ printf("User interrupt!\n");
+ bios_getc();
+ return -1;
+ }
+
+ printf("%dk to go \r", rd_len); fflush(stdout);
+ if( read_block(buffer) < 0 )
+ {
+ printf("Read error loading ramdisk\n");
+ return -1;
+ }
+ if( putsect(buffer, address) < 0 ) return -1;
+ address+=2;
+ if( putsect(buffer+512, address) < 0 ) return -1;
+ address+=2;
+ }
+ printf("Loaded, ");
+
+ /* Tell the kernel where it is */
+ {
+ long tmp = ((long)rd_start << 8);
+
+ __set_es(0x9000);
+ __doke_es(0x218, (unsigned) tmp);
+ __doke_es(0x21A, (unsigned)(tmp>>16));
+
+ __doke_es(0x21C, (unsigned) file_len);
+ __doke_es(0x21E, (unsigned)(file_len>>16));
+ }
+
+ return 0;
+}
diff --git a/bootblocks/dosboot.c b/bootblocks/dosboot.c
deleted file mode 100644
index 72b8d25..0000000
--- a/bootblocks/dosboot.c
+++ /dev/null
@@ -1,72 +0,0 @@
-
-#include <stdio.h>
-
-#include "sysboot.v"
-#include "msdos.v"
-#include "skip.v"
-
-char buffer[512];
-
-struct bblist {
- char * name;
- char * data;
- char * desc;
-} bblocks[] = {
- { "bare", sysboot_data, "Bare bootblock, lockup if booted" },
- { "dosfs", msdos_data, "Boots file BOOTFILE.SYS from dosfs" },
- { "skip", skip_data, "Bypasses floppy boot with message" },
- 0
-};
-
-char * progname = "";
-
-main(argc, argv)
-int argc;
-char ** argv;
-{
- FILE * fd;
- struct bblist *ptr = bblocks;
- int i;
-
- progname = argv[0];
-
- if( argc != 3 ) Usage();
-
- for(;ptr->name; ptr++) if( strcmp(argv[1], ptr->name) == 0 ) break;
- if( ptr->name == 0 ) Usage();
-
- fd = fopen(argv[2], "r+");
- if( fd == 0 )
- {
- fprintf(stderr, "Cannot open %s\n", argv[2]);
- exit(1);
- }
- if( fread(buffer, 512, 1, fd) != 1 )
- {
- fprintf(stderr, "Cannot read boot block\n");
- exit(1);
- }
- for(i=0; i<sysboot_dosfs_stat; i++)
- buffer[i] = ptr->data[i];
- for(i=sysboot_codestart; i<512; i++)
- buffer[i] = ptr->data[i];
-
- rewind(fd);
- if( fwrite(buffer, 512, 1, fd) != 1 )
- {
- fprintf(stderr, "Cannot write boot block\n");
- exit(1);
- }
- fclose(fd);
-}
-
-Usage()
-{
- struct bblist *ptr = bblocks;
-
- fprintf(stderr, "Usage: %s bootname /dev/fd0\n", progname);
- fprintf(stderr, "Blocks\n");
- for(;ptr->name; ptr++)
- fprintf(stderr, "\t%s\t%s\n", ptr->name, ptr->desc);
- exit(1);
-}
diff --git a/bootblocks/dosfs.c b/bootblocks/dosfs.c
new file mode 100644
index 0000000..a545b28
--- /dev/null
+++ b/bootblocks/dosfs.c
@@ -0,0 +1,419 @@
+
+#ifdef __STANDALONE__
+
+#include <ctype.h>
+#include <malloc.h>
+#include "readfs.h"
+
+#define DOS_SECT(P) get_uint(P,0x0B)
+#define DOS_CLUST(P) get_byte(P,0x0D)
+#define DOS_RESV(P) get_uint(P,0x0E)
+#define DOS_NFAT(P) get_byte(P,0x10)
+#define DOS_NROOT(P) get_uint(P,0x11)
+#define DOS_MAXSECT(P) get_uint(P,0x13)
+#define DOS_MEDIA(P) get_byte(P,0x15)
+#define DOS_FATLEN(P) get_uint(P,0x16)
+#define DOS_SPT(P) get_uint(P,0x18)
+#define DOS_HEADS(P) get_uint(P,0x1A)
+#define DOS_HIDDEN(P) get_long(P,0x1C)
+#define DOS4_MAXSECT(P) get_long(P,0x20)
+#define DOS4_PHY_DRIVE(P) get_byte(P,0x24)
+#define DOS4_SERIAL(P) get_long(P,0x27)
+
+/* These assume alignment is not a problem */
+#define get_byte(P,Off) *((unsigned char*)((char*)(P)+(Off)))
+#define get_uint(P,Off) *((unsigned short*)((char*)(P)+(Off)))
+#define get_long(P,Off) *((long*)((char*)(P)+(Off)))
+
+static int alloc_trackbuf();
+static char * read_sector();
+static int read_bootblock();
+
+int disk_drive = 0;
+
+static int track_number = -1;
+static char * track_buffer = 0;
+static int track_len = 0;
+static int disk_spt = -1;
+static int disk_heads = 2;
+
+static int dir_nentry, dir_sect;
+static int dos_clust0, dos_spc;
+
+static char * fat_buf = 0;
+
+struct filestatus {
+ char fname[12];
+ unsigned short first_cluster;
+ unsigned short cur_cluster;
+ unsigned short sector_no;
+ long file_length;
+}
+ cur_file = { "", 0, 0, 0 };
+
+open_file(fname)
+char * fname;
+{
+ char conv_name[12];
+ char *s, *d;
+ int i;
+ int dodir = 0;
+
+ if(strcmp(fname, ".") == 0) dodir = 1;
+ else
+ {
+ /* Convert the name to MSDOS directory format */
+ strcpy(conv_name, " ");
+ for(s=fname, d=conv_name; *s && *d && *s != '.' && *s != ' '; s++)
+ {
+ if( islower(*s) ) *d++ = toupper(*s);
+ else *d++ = *s;
+ }
+ while( *s && *s != '.' ) s++;
+ strcpy(d=(conv_name+8), " ");
+ if( *s == '.' )
+ {
+ for(s++; *s && *d; s++)
+ {
+ if( islower(*s) ) *d++ = toupper(*s);
+ else *d++ = *s;
+ }
+ }
+
+ /* Already opened ? Then just rewind it */
+ if( cur_file.first_cluster && strcmp(cur_file.fname, conv_name) == 0 )
+ return rewind_file();
+ }
+
+ memset(&cur_file, '\0', sizeof(cur_file));
+
+ /* Get the superblock */
+ s = read_sector(0);
+ if( s == 0 ) return -1;
+
+ /* Collect important data */
+ dir_sect = DOS_RESV(s) + DOS_NFAT(s)*DOS_FATLEN(s);
+ dir_nentry = DOS_NROOT(s);
+
+ dos_spc = DOS_CLUST(s);
+ if( dos_spc < 1 ) dos_spc = 1;
+ dos_clust0 = dir_sect + (dir_nentry+15)/16 - 2*dos_spc;
+
+ if( !dodir )
+ {
+ /* Read in and buffer the FAT */
+ if( fat_buf ) free(fat_buf);
+ fat_buf = malloc(DOS_FATLEN(s) * 512);
+ if( fat_buf == 0 ) return -1;
+ else
+ {
+ int fatsec = DOS_RESV(s);
+ int nsec = DOS_FATLEN(s);
+
+ for(i=0; i<nsec; i++)
+ {
+ s = read_sector(fatsec+i);
+ if(s == 0) return -1;
+ memcpy(fat_buf+i*512, s, 512);
+ }
+ }
+ }
+
+ /* Scan the root directory for the file */
+ for(i=0; i<dir_nentry; i++)
+ {
+ s = read_sector(dir_sect+i/16);
+ if( s == 0 ) return -1;
+ d = s + (i%16)*32;
+ if( dodir )
+ {
+ char dtime[20];
+ sprintf(dtime, " %02d/%02d/%04d %02d:%02d",
+ (get_uint(d,24)&0x1F),
+ ((get_uint(d,24)>>5)&0xF),
+ ((get_uint(d,24)>>9)&0x7F)+1980,
+ ((get_uint(d,22)>>11)&0x1F),
+ ((get_uint(d,22)>>5)&0x3F)
+ );
+ if( *d > ' ' && *d <= '~' ) switch(d[11]&0x18)
+ {
+ case 0:
+ printf("%-8.8s %-3.3s %10ld%s\n", d, d+8, get_long(d,28), dtime);
+ break;
+ case 0x10:
+ printf("%-8.8s %-3.3s <DIR> %s\n", d, d+8, dtime);
+ break;
+ case 8:
+ if( (d[11] & 7) == 0 )
+ printf("%-11.11s <LBL> %s\n", d, dtime);
+ break;
+ }
+ }
+ else if( memcmp(d, conv_name, 11) == 0 && (d[11]&0x18) == 0 )
+ { /* Name matches and is normal file */
+
+ strcpy(cur_file.fname, conv_name);
+ cur_file.first_cluster = get_uint(d,26);
+ cur_file.file_length = get_long(d,28);
+
+ cur_file.cur_cluster = cur_file.first_cluster;
+ cur_file.sector_no = 0;
+
+ return 0;
+ }
+ }
+ return -1;
+}
+
+rewind_file()
+{
+ /* Is there an opened file ? */
+ if( cur_file.fname[0] == 0 ) return -1;
+
+ cur_file.sector_no = 0;
+ cur_file.cur_cluster = cur_file.first_cluster;
+ return 0;
+}
+
+close_file()
+{
+ if( fat_buf ) free(fat_buf);
+ if( track_buffer ) free(track_buffer);
+ memset(&cur_file, '\0', sizeof(cur_file));
+ fat_buf = 0;
+ track_buffer = 0;
+ track_len = 0;
+ track_number = -1;
+ disk_spt = -1;
+ disk_heads = 2;
+ return 0;
+}
+
+long
+file_length()
+{
+ /* Is there an opened file ? */
+ if( cur_file.fname[0] == 0 ) return -1;
+
+ return cur_file.file_length;
+}
+
+read_block(buffer)
+char * buffer;
+{
+ int s;
+ char * ptr;
+
+ /* Is there an opened file ? */
+ if( cur_file.fname[0] == 0 ) return -1;
+
+ /* Are we before the EOF ? NB: FAT12 ONLY! */
+ if( cur_file.cur_cluster >= 0xFF0 || cur_file.cur_cluster < 2 ) return -1;
+
+ for(s=0; s<2; s++)
+ {
+ unsigned int sectno;
+
+ if( cur_file.cur_cluster >= 0xFF0 || cur_file.cur_cluster < 2 )
+ {
+ memset(buffer, '\0', 512);
+ buffer += 512;
+ continue;
+ }
+
+ sectno = dos_clust0
+ + cur_file.cur_cluster * dos_spc
+ + cur_file.sector_no % dos_spc;
+
+ ptr = read_sector(sectno);
+ if( ptr == 0 ) return -1;
+ memcpy(buffer, ptr, 512);
+
+ cur_file.sector_no++;
+ if( cur_file.sector_no % dos_spc == 0 )
+ {
+ int odd = (cur_file.cur_cluster&1);
+ unsigned int val;
+
+ val = cur_file.cur_cluster + (cur_file.cur_cluster>>1);
+ val = get_uint(fat_buf, val);
+
+ if( odd ) val>>=4;
+
+ val &= 0xFFF;
+
+ cur_file.cur_cluster = val;
+ }
+
+ buffer += 512;
+ }
+
+ return 0;
+}
+
+static char * read_sector(sectno)
+int sectno;
+{
+ int track_no, track_off, track_start, linsect;
+ if( disk_spt == -1 && read_bootblock() < 0 ) return 0;
+
+ track_no = sectno / track_len;
+ track_off= sectno % track_len;
+
+ if( track_no != track_number )
+ {
+ track_number = -1;
+ track_start = track_no * track_len;
+
+ for(linsect=0; linsect<track_len; linsect++)
+ {
+ if( raw_read(disk_drive, track_start+linsect,
+ track_buffer+linsect*512) <0 )
+ return 0;
+ }
+ if( raw_read(disk_drive, 0, 0) <0 )
+ return 0;
+
+ track_number = track_no;
+ }
+ return track_buffer + 512*track_off;
+}
+
+static int raw_read(drive, linsect, buffer)
+int drive, linsect;
+char * buffer;
+{
+static char * pend_buf = 0, *buf_start = 0;
+static int pend_s, pend_h, pend_c, pend_len = 0;
+
+ int phy_s = linsect%disk_spt;
+ int phy_h = linsect/disk_spt%disk_heads;
+ int phy_c = linsect/disk_spt/disk_heads;
+ int tries = 5;
+ int rv = 0;
+
+ if( buffer != pend_buf ||
+ pend_s+pend_len != phy_s ||
+ pend_h != phy_h ||
+ pend_c != phy_c )
+ {
+/*
+printf("phy_read(%d,%d,%d,%d,%d,%d);\n",
+ drive, pend_c, pend_h, pend_s+1, pend_len, buf_start);
+*/
+ if( buf_start ) do
+ {
+ rv = phy_read(drive, pend_c, pend_h, pend_s+1, pend_len, buf_start);
+ tries--;
+ }
+ while(rv && tries > 0);
+
+ pend_c = phy_c;
+ pend_h = phy_h;
+ pend_s = phy_s;
+ pend_len = 0;
+ pend_buf = buf_start = buffer;
+ }
+
+ pend_len++;
+ pend_buf += 512;
+
+ return rv;
+}
+
+static int read_bootblock()
+{
+ char * sptr;
+ int rv, media_byte = 0;
+ if( alloc_trackbuf(2) ) return -1;
+
+ disk_spt = 2;
+ sptr = read_sector(1);
+ disk_spt = -1;
+ if( sptr == 0 ) return -1;
+ media_byte = *(unsigned char*)sptr;
+
+ /* Valid media byte ? */
+ if( (media_byte & 0xF0) != 0xF0 ) return -1;
+ disk_spt = 2;
+ sptr = read_sector(0);
+ disk_spt = -1;
+ if( sptr == 0 ) return -1;
+
+ if( DOS_MEDIA(sptr) != media_byte ) return -1;
+ if( DOS_SPT(sptr) > 63 ) return -1;
+ if( DOS_SECT(sptr) != 512 ) return -1;
+
+ disk_spt = DOS_SPT(sptr);
+ disk_heads = DOS_HEADS(sptr);
+
+ rv = alloc_trackbuf(disk_spt*disk_heads); /* Cylinder buffer */
+ if( rv < 0 ) rv = alloc_trackbuf(disk_spt); /* Track buffer */
+ if( rv < 0 ) rv = alloc_trackbuf(disk_spt/2); /* 1/2 Track buffer */
+ if( rv < 0 ) rv = alloc_trackbuf(2); /* Block buffer */
+ if( rv < 0 ) disk_spt = -1;
+ return rv;
+}
+
+static int alloc_trackbuf(sectors)
+int sectors;
+{
+ char * new_track;
+ int seg_start, seg_end;
+ if( sectors <= track_len ) return 0;
+
+ if( track_buffer ) free(track_buffer);
+ track_buffer = 0;
+ track_len = 0;
+ track_number = -1;
+
+ if( sectors < 1 || sectors > 63 ) /* WTF! */ return -1;
+
+ new_track = malloc(sectors*512);
+ if( new_track == 0 ) return -1;
+
+ seg_start = __get_ds() + (unsigned int)new_track / 16;
+ seg_end = __get_ds() + (unsigned int)(new_track+sectors*512-1) / 16;
+
+ if( (seg_start&0xF000) != (seg_end&0xF000) ) /* Bugger */
+ {
+ int rv = alloc_trackbuf(sectors);
+ free(new_track);
+ return rv;
+ }
+
+ track_len = sectors;
+ track_buffer = new_track;
+ return 0;
+}
+
+#endif
+
+#if defined(__MSDOS__) || defined(__STANDALONE__)
+phy_read(drive, cyl, head, sect, length, buffer)
+{
+#asm
+ push bp
+ mov bp,sp
+
+ push ds
+ pop es
+
+ mov dl,[bp+2+_phy_read.drive]
+ mov ch,[bp+2+_phy_read.cyl]
+ mov dh,[bp+2+_phy_read.head]
+ mov cl,[bp+2+_phy_read.sect]
+ mov al,[bp+2+_phy_read.length]
+ mov bx,[bp+2+_phy_read.buffer]
+
+ mov ah,#$02
+ int $13
+ jc read_err
+ mov ax,#0
+read_err:
+
+ pop bp
+#endasm
+}
+#endif
+
diff --git a/bootblocks/help.c b/bootblocks/help.c
new file mode 100644
index 0000000..5083fdc
--- /dev/null
+++ b/bootblocks/help.c
@@ -0,0 +1,93 @@
+
+/*
+ * Display a page from help.txt, the argument is the scan code of a function
+ * key. F1..F10 display pages 1..10, HOME is page zero, PGUP and PGDN are
+ * previous and next page.
+ */
+
+#include <stdio.h>
+#include "readfs.h"
+
+struct keys {
+ int key;
+ int rel;
+ int abs;
+} keys[] = {
+ {0xC7, 0, 0}, /* HOME page 0*/
+ {0xBB, 0, 1}, /* F1 page 1 */
+ {0xBC, 0, 2}, /* F2 page 2 */
+ {0xBD, 0, 3}, /* F3 page 3 */
+ {0xBE, 0, 4}, /* F4 page 4 */
+ {0xBF, 0, 5}, /* F5 page 5 */
+ {0xC0, 0, 6}, /* F6 page 6 */
+ {0xC1, 0, 7}, /* F7 page 7 */
+ {0xC2, 0, 8}, /* F8 page 8 */
+ {0xC3, 0, 9}, /* F9 page 9 */
+ {0xC4, 0, 10}, /* F10 page 10 */
+
+ {0xC9, -1,0}, /* PGUP page-- */
+ {0xD1, 1,0}, /* PGDN page++ */
+
+ {0,0,1}
+};
+
+cmd_help(ptr)
+char * ptr;
+{
+static int lastpage = 0;
+ int helpkey = 1;
+ int i;
+
+ getnum(&ptr, &helpkey);
+
+ for(i=0; keys[i].key; i++)
+ if( keys[i].key == helpkey || i == helpkey )
+ break;
+
+ if( keys[i].key == 0 )
+ {
+ printf("Unbound key, press F1 for general help\n");
+ return -1;
+ }
+
+ if( keys[i].rel ) lastpage += keys[i].rel;
+ else lastpage = keys[i].abs;
+
+ if( lastpage < 0 ) { lastpage=0; return 0; }
+
+ return display_help(lastpage);
+}
+
+display_help(page)
+int page;
+{
+ char buffer[1024];
+ long length= -1;
+ int left = 0;
+ int ch,lastch = '\n';
+ int flg = 0;
+
+ if( open_file("help.txt") < 0 )
+ {
+ if( page == 1 )
+ printf("Help file 'help.txt' is not available, sorry.\n");
+ return -1;
+ }
+
+ for(length = file_length(); length>0; length--)
+ {
+ if( left==0 )
+ {
+ if( read_block(buffer) < 0 ) break;
+ left = 1024;
+ }
+ ch = buffer[1024-left]; left--;
+ if( ch == '%' && lastch == '\n' ) { flg = 1; page--; }
+ if( page < 0 ) break;
+ if( page == 0 && flg == 0 ) putchar(ch);
+ if( ch == '\n' ) flg = 0;
+ lastch = ch;
+ }
+ return 0;
+}
+
diff --git a/bootblocks/i86_funcs.c b/bootblocks/i86_funcs.c
index a17e7a4..c17a158 100644
--- a/bootblocks/i86_funcs.c
+++ b/bootblocks/i86_funcs.c
@@ -10,7 +10,7 @@ int x86_a20_closed = 1; /* Is the A20 gate closed ? */
int x86_test = 0; /* In test mode */
int x86_fpu = 0;
-unsigned boot_mem_top = 0x4000; /* Default 64k, the minimum */
+unsigned boot_mem_top = 0x2000; /* Default 128k, the minimum */
long main_mem_top = 0; /* K of extended memory */
int a20_closed()
@@ -52,6 +52,22 @@ empty_8042:
#endasm
}
+/* This calls the BIOS to open the A20 gate, officially this is only supported
+ on PS/2s but if the normal routine fails we may as well try this.
+ */
+void bios_open_a20()
+{
+#asm
+ mov ax,#$2401
+ int $15
+ jc bios_failed_a20
+ xor ax,ax
+bios_failed_a20:
+ mov al,ah
+ xor ah,ah
+#endasm
+}
+
void cpu_check()
{
static char *name_808x[] =
@@ -130,10 +146,10 @@ static struct {
char gdt1[8];
unsigned short src_len;
long src_seg;
- unsigned int spad;
+ unsigned short spad;
unsigned short dst_len;
long dst_seg;
- unsigned int dpad;
+ unsigned short dpad;
char gdt5[8];
} GDT = {
"","",
@@ -174,7 +190,7 @@ static asm_copy(length)
push es
push si
mov cx,ax
- mov ah,$87
+ mov ah,#$87
push ds
pop es
mov si,#_GDT
@@ -184,7 +200,7 @@ static asm_copy(length)
err:
mov al,ah
xor ah,ah
- push si
- push es
+ pop si
+ pop es
#endasm
}
diff --git a/bootblocks/makeboot.c b/bootblocks/makeboot.c
index 5a6348d..28d7ded 100644
--- a/bootblocks/makeboot.c
+++ b/bootblocks/makeboot.c
@@ -1,103 +1,328 @@
#include <stdio.h>
+#include <ctype.h>
+#include <time.h>
-#include "tarboot.v"
#include "sysboot.v"
+#include "msdos.v"
+#include "skip.v"
+#include "tarboot.v"
-char tarblock[512];
+char buffer[1024];
+
+#define FS_NONE 0
+#define FS_ADOS 1
+#define FS_DOS 2
+#define FS_TAR 3
+#define FS_STAT 4
+
+struct bblist {
+ char * name;
+ char * data;
+ int fstype;
+ char * desc;
+} bblocks[] = {
+ { "tar", tarboot_data, FS_TAR, "Bootable GNU tar volume lable" },
+ { "dosfs", msdos_data, FS_ADOS, "Boots file BOOTFILE.SYS from dosfs" },
+ { "bare", sysboot_data, FS_DOS, "Bare bootblock, lockup if booted" },
+ { "skip", skip_data, FS_DOS, "Bypasses floppy boot with message" },
+ { "stat", 0, FS_STAT, "Display dosfs superblock" },
+ { "copy", 0, FS_STAT, "Copy boot block to makeboot.sav" },
+ { "Zap", 0, FS_NONE, "Clear boot block to NULs" },
+ 0
+};
+
+char * progname = "";
+
+int disktype = 0;
+FILE * diskfd;
+
+int disk_sect = 63; /* These are initilised to the maximums */
+int disk_head = 256; /* Set to the correct values when an MSDOS disk is */
+int disk_trck = 256; /* successfully identified */
-char *bootblock = tarboot_data;
+main(argc, argv)
+int argc;
+char ** argv;
+{
+ FILE * fd;
+ struct bblist *ptr;
+ int i;
-struct tar_head {
- char name[100];
- char mode[8];
- char uid[8];
- char gid[8];
- char size[12];
- char mtime[12];
- char chksum[8];
- char linkflag;
- char linkname[100];
- char magic[8];
- char uname[32];
- char gname[32];
- char devmajor[8];
- char devminor[8];
- char padding[167];
-} ;
+ progname = argv[0];
-#define head (*(struct tar_head*) tarblock)
-#define boothead (*(struct tar_head*) bootblock)
+ if( argc != 3 ) Usage();
-int force = 0;
-int relocatable = 0;
-int tableload = 0;
-long loadaddress = 0x8000;
-long execaddress = 0x8000;
+ if( (i=strlen(argv[1])) < 2 ) Usage();
+ for(ptr = bblocks; ptr->name; ptr++)
+ if( strncmp(argv[1], ptr->name, i) == 0 ) break;
+ if( ptr->name == 0 ) Usage();
-main(argc, argv)
-int argc;
-char ** argv;
+ open_disk(argv[2]);
+ if( read_sector(0, buffer) != 0 )
+ exit(1);
+ read_sector(1, buffer+512);
+
+ switch(ptr->fstype)
+ {
+ case FS_NONE: /* override */
+ break;
+ case FS_ADOS:
+ check_simpledos();
+ break;
+ case FS_DOS:
+ case FS_STAT:
+ check_msdos();
+ break;
+ case FS_TAR:
+ check_tar();
+ break;
+
+ default:
+ fprintf(stderr, "Program error, unknown filesystem requirement\n");
+ exit(2);
+ }
+
+ switch(ptr->fstype)
+ {
+ case FS_STAT:
+ print_super(buffer);
+ if( strcmp(ptr->name, "copy") == 0 )
+ save_super(buffer);
+ close_disk();
+ exit(0);
+ case FS_ADOS:
+ case FS_DOS:
+ for(i=0; i<sysboot_dosfs_stat; i++)
+ buffer[i] = ptr->data[i];
+ for(i=sysboot_codestart; i<512; i++)
+ buffer[i] = ptr->data[i];
+ break;
+
+ case FS_TAR:
+ copy_tarblock();
+ break;
+
+ case FS_NONE:
+ if( ptr->data )
+ memcpy(buffer, ptr->data, 512);
+ else
+ memset(buffer, '\0', 512);
+ break;
+ }
+
+ write_sector(0, buffer);
+ close_disk();
+ exit(0);
+}
+
+Usage()
{
- int ar;
- int done=0;
+ struct bblist *ptr = bblocks;
+
+ if( progname == 0 || *progname == 0 || progname[1] == 0 )
+ progname = "makeboot";
+
+#ifdef __MSDOS__
+ fprintf(stderr, "Usage: %s bootname a:\n", progname);
+#else
+ fprintf(stderr, "Usage: %s bootname /dev/fd0\n", progname);
+#endif
+ fprintf(stderr, "Blocks\n");
+ for(;ptr->name; ptr++)
+ fprintf(stderr, "\t%s\t%s\n", ptr->name, ptr->desc);
+ exit(1);
+}
- if( sizeof(head) != sizeof(tarblock) )
- { fprintf(stderr, "Program structure error\n"); exit(1); }
+/**************************************************************************/
- for(ar=1; ar<argc; ar++) if(argv[ar][0]=='-') switch(argv[ar][1])
+int
+open_disk(diskname)
+char * diskname;
+{
+#ifdef __MSDOS__
+ if( strcmp("a:", diskname) == 0 ) { disktype = 1; return 0; }
+ if( strcmp("b:", diskname) == 0 ) { disktype = 2; return 0; }
+ if( strcmp("A:", diskname) == 0 ) { disktype = 1; return 0; }
+ if( strcmp("B:", diskname) == 0 ) { disktype = 2; return 0; }
+#endif
+ disktype = 0;
+ diskfd = fopen(diskname, "r+");
+ if( diskfd == 0 )
{
- case 'f': force++; break;
- case 'r': relocatable++; break;
- case 't': tableload++; break;
- case 'l': sscanf(argv[ar]+2, "%li", &loadaddress); break;
- case 'x': sscanf(argv[ar]+2, "%li", &execaddress); break;
+ fprintf(stderr, "Cannot open %s\n", diskname);
+ exit(1);
+ }
+ return 0;
+}
- case '?': Usage(1); break;
- default: Usage(0); break;
+close_disk()
+{
+ if( diskfd && disktype == 0 ) fclose(diskfd);
+ diskfd = 0;
+ disktype = 0;
+}
+
+int
+write_sector(sectno, loadaddr)
+int sectno;
+char * loadaddr;
+{
+#ifdef __MSDOS__
+ if( disktype == 1 || disktype == 2 )
+ {
+ int tries, rv;
+ int s,h,c;
+ s = sectno%disk_sect + 1;
+ h = sectno/disk_sect%disk_head;
+ c = sectno/disk_sect/disk_head;
+
+ for(tries=0; tries<6; tries++)
+ if( (rv = dos_sect_write(disktype-1, c, h, s, loadaddr)) == 0 )
+ break;
+ if( rv )
+ {
+ fprintf(stderr, "Error writing sector %d, (%d)\n", sectno, rv/256);
+ return -1;
+ }
+ return 0;
}
- else
+#endif
+ if( disktype )
{
- mktarboot(argv[ar]);
- done++;
+ fprintf(stderr, "Cannot write sector %d\n", sectno);
+ return -1;
}
+ fseek(diskfd, (long)sectno*512, 0);
+ if( fwrite(loadaddr, 512, 1, diskfd) != 1 )
+ {
+ fprintf(stderr, "Cannot write sector %d\n", sectno);
+ return -1;
+ }
+ return 0;
}
-Usage(flg)
-int flg;
+int
+read_sector(sectno, loadaddr)
+int sectno;
+char * loadaddr;
{
- fprintf(stderr, "Usage: makeboot [-f] device\n");
- exit(9);
+ int cc;
+#ifdef __MSDOS__
+ if( disktype == 1 || disktype == 2 )
+ {
+ int tries, rv;
+ int s,h,c;
+ s = sectno%disk_sect + 1;
+ h = sectno/disk_sect%disk_head;
+ c = sectno/disk_sect/disk_head;
+
+ for(tries=0; tries<6; tries++)
+ if( (rv = dos_sect_read(disktype-1, c, h, s, loadaddr)) == 0 )
+ break;
+ if( rv )
+ {
+ fprintf(stderr, "Error reading sector %d, (%d)\n", sectno, rv/256);
+ memset(loadaddr, '\0', 512);
+ return -1;
+ }
+ return 0;
+ }
+#endif
+ if( disktype )
+ {
+ fprintf(stderr, "Cannot read sector %d\n", sectno);
+ return -1;
+ }
+ fseek(diskfd, (long)sectno*512, 0);
+ if( (cc=fread(loadaddr, 1, 512, diskfd)) != 512 )
+ {
+ fprintf(stderr, "Cannot read sector %d, clearing\n", sectno);
+ if(cc<0) cc=0;
+ memset(loadaddr+cc, '\0', 512-cc);
+ }
+ return 0;
}
+/**************************************************************************/
-mktarboot(fname)
-char * fname;
+#ifdef __MSDOS__
+dos_sect_read(drv, track, head, sector, loadaddr)
{
- FILE * fd;
+#asm
+ push bp
+ mov bp,sp
- fd = fopen(fname, "r+");
- if( !fd ) { perror(fname); exit(1); }
+ push ds
+ pop es
- if( fread(tarblock, sizeof(tarblock), 1, fd) != 1 )
- { fprintf(stderr, "Cannot read boot block\n"); exit(1); }
+ mov dh,[bp+2+_dos_sect_read.head]
+ mov dl,[bp+2+_dos_sect_read.drv]
+ mov cl,[bp+2+_dos_sect_read.sector]
+ mov ch,[bp+2+_dos_sect_read.track]
- check_tar(1);
- mangle_tarvol();
+ mov bx,[bp+2+_dos_sect_read.loadaddr]
- rewind(fd);
- if( fwrite(tarblock, sizeof(tarblock), 1, fd) != 1 )
- { fprintf(stderr, "Cannot write boot block\n"); exit(1); }
+ mov ax,#$0201
+ int $13
+ jc read_err
+ mov ax,#0
+read_err:
- rewind(fd);
- if( fread(tarblock, sizeof(tarblock), 1, fd) != 1 )
- { fprintf(stderr, "Cannot re-read boot block\n"); exit(1); }
+ pop bp
+#endasm
+}
+#endif
- if( fread(tarblock, sizeof(tarblock), 1, fd) == 1 && head.linkflag == '0' )
- printf("Boot block installed to boot file %s\n", head.name);
+#ifdef __MSDOS__
+dos_sect_write(drv, track, head, sector, loadaddr)
+{
+#asm
+ push bp
+ mov bp,sp
- fclose(fd);
- exit(0);
+ push ds
+ pop es
+
+ mov dh,[bp+2+_dos_sect_write.head]
+ mov dl,[bp+2+_dos_sect_write.drv]
+ mov cl,[bp+2+_dos_sect_write.sector]
+ mov ch,[bp+2+_dos_sect_write.track]
+
+ mov bx,[bp+2+_dos_sect_write.loadaddr]
+
+ mov ax,#$0301
+ int $13
+ jc write_err
+ mov ax,#0
+write_err:
+
+ pop bp
+#endasm
}
+#endif
+
+/**************************************************************************/
+
+struct tar_head {
+ char name[100];
+ char mode[8];
+ char uid[8];
+ char gid[8];
+ char size[12];
+ char mtime[12];
+ char chksum[8];
+ char linkflag;
+ char linkname[100];
+ char magic[8];
+ char uname[32];
+ char gname[32];
+ char devmajor[8];
+ char devminor[8];
+ char padding[167];
+} ;
+
+#define buff_tar (*(struct tar_head*) buffer)
+#define boot_tar (*(struct tar_head*) tarboot_data)
unsigned int oct(s)
char *s;
@@ -109,46 +334,46 @@ char *s;
return val;
}
-check_tar(fatal)
-int fatal;
+check_tar()
{
char vbuf[100], *p;
unsigned int csum = 0;
long osum = -1;
- osum = oct(head.chksum);
- memset(head.chksum, ' ', sizeof(head.chksum));
+ for(p=buffer; p<buffer+512; p++)
+ if( *p ) goto not_zapped;
+ /* Block zapped, ok */
+ return 0;
+not_zapped:
+
+ osum = oct(buff_tar.chksum);
+ memset(buff_tar.chksum, ' ', sizeof(buff_tar.chksum));
- for(p=tarblock; p<tarblock+sizeof(tarblock); p++)
+ for(p=buffer; p<buffer+512; p++)
csum += (*p & 0xFF);
if( csum != osum )
{
fprintf(stderr, "TAR file checksum failed, this isn't a tar file.\n");
- if(fatal) exit(9);
- return -1;
+ exit(9);
}
- if( head.linkflag != 'V' )
+ if( buff_tar.linkflag != 'V' )
{
fprintf(stderr, "Tar file doesn't start with a volume label\n");
- if(fatal) exit(8);
- return -1;
+ exit(8);
}
- strcpy(vbuf, boothead.name); strcat(vbuf, " Volume 1");
- if( !force && strcmp(boothead.name, head.name) != 0
- && strcmp(vbuf, head.name) != 0 )
+ strcpy(vbuf, boot_tar.name); strcat(vbuf, " Volume 1");
+ if( strcmp(boot_tar.name, buff_tar.name) != 0
+ && strcmp(vbuf, buff_tar.name) != 0 )
{
- fprintf(stderr, "Volume is labeled as '%s' not '%s'\n",
- head.name, boothead.name);
- fprintf(stderr, "Use -f flag to force write\n");
- if(fatal) exit(1);
- return -1;
+ fprintf(stderr, "WARNING: Volume is labeled as '%s' not '%s'\n",
+ buff_tar.name, boot_tar.name);
}
return 0;
}
-mangle_tarvol()
+copy_tarblock()
{
char lbuf[20];
char * p;
@@ -157,31 +382,232 @@ mangle_tarvol()
struct tar_head temp;
- temp = boothead;
+ temp = boot_tar;
/* Copy preserved fields
*/
- memcpy(temp.mtime, head.mtime, sizeof(temp.mtime));
-
- memset(temp.name, 0x90, 16);
- for(i=0; head.name[i] && head.name[i] != ' ' && i<14; i++)
+ if( buff_tar.name[0] )
{
- int ch = head.name[i];
- if( islower(ch) ) ch = toupper(ch);
- if( strchr("/?@ABCDEFGHIJKLMNO", ch) == 0 )
- ch = '?';
- temp.name[i] = ch;
+ memcpy(temp.mtime, buff_tar.mtime, sizeof(temp.mtime));
+
+ memset(temp.name, 0x90, 16);
+ for(i=0; buff_tar.name[i] && buff_tar.name[i] != ' ' && i<14; i++)
+ {
+ int ch = buff_tar.name[i];
+ if( islower(ch) ) ch = toupper(ch);
+ if( strchr("/?@ABCDEFGHIJKLMNO", ch) == 0 )
+ ch = '?';
+ temp.name[i] = ch;
+ }
+ temp.name[i++] = 0;
+ temp.name[i] = 0xC0;
}
- temp.name[i++] = 0;
- temp.name[i] = 0xC0;
+ else
+ sprintf(temp.mtime, "%11lo", time((void*)0));
+
+ buff_tar = temp;
- head = temp;
- /* Calculate the checksum */
- memset(head.chksum, ' ', sizeof(head.chksum));
+ /* Re-calculate the checksum */
+ memset(buff_tar.chksum, ' ', sizeof(buff_tar.chksum));
- for(p=tarblock; p<tarblock+sizeof(tarblock); p++)
+ for(p=buffer; p<buffer+512; p++)
csum += (*p & 0xFF);
- sprintf(head.chksum, "%7o", csum);
+ sprintf(buff_tar.chksum, "%7o", csum);
+
+ printf("Boot block installed");
+ if( ((struct tar_head*)buffer)[1].name[0] )
+ printf(" to boot file '%s'\n",
+ ((struct tar_head*)buffer)[1].name);
+ else
+ printf(", use 'tar -r' to add executable\n");
+}
+
+/**************************************************************************/
+
+#define DOS_SYSID 0
+#define DOS_SECT 1
+#define DOS_CLUST 2
+#define DOS_RESV 3
+#define DOS_NFAT 4
+#define DOS_NROOT 5
+#define DOS_MAXSECT 6
+#define DOS_MEDIA 7
+#define DOS_FATLEN 8
+#define DOS_SPT 9
+#define DOS_HEADS 10
+#define DOS_HIDDEN 11
+#define DOS4_MAXSECT 12
+#define DOS4_PHY_DRIVE 13
+#define DOS4_SERIAL 14
+#define DOS4_LABEL 15
+#define DOS4_FATTYPE 16
+
+struct bootfields {
+ int offset;
+ int length;
+ int value;
+}
+ dosflds[] =
+{
+ { 0x03, 8, 0},
+ { 0x0B, 2, 0},
+ { 0x0D, 1, 0},
+ { 0x0E, 2, 0},
+ { 0x10, 1, 0},
+ { 0x11, 2, 0},
+ { 0x13, 2, 0},
+ { 0x15, 1, 0},
+ { 0x16, 2, 0},
+ { 0x18, 2, 0},
+ { 0x1A, 2, 0},
+ { 0x1C, 4, 0},
+ { 0x20, 4, 0},
+ { 0x24, 1, 0},
+ { 0x27, 4, 0},
+ { 0x2B, 11, 0},
+ { 0x36, 8, 0},
+ { -1,0,0}
+};
+
+print_super(bootsect)
+char * bootsect;
+{
+static char * fieldnames[] = {
+ "System ID",
+ "Sector size",
+ "Cluster size",
+ "Reserved sectors",
+ "FAT count",
+ "Root dir entries",
+ "Sector count (=0 if large FS)",
+ "Media code",
+ "FAT length",
+ "Sect/Track",
+ "Heads",
+ "Hidden sectors (Partition offset)",
+ "Large FS sector count",
+ "Phys drive",
+ "Serial number",
+ "Disk Label (DOS 4+)",
+ "FAT type",
+ 0
+};
+ int i;
+
+ for(i=0; dosflds[i].offset >= 0; i++)
+ {
+ printf("%-35s", fieldnames[i]);
+ if( dosflds[i].length <= 4 )
+ {
+ long v = 0; int j;
+ for(j=dosflds[i].length-1; j>=0; j--)
+ {
+ v = v*256 + (0xFF&( bootsect[dosflds[i].offset+j] ));
+ }
+ printf("%ld\n", v);
+ }
+ else
+ {
+ int ch, j;
+ for(j=0; j<dosflds[i].length; j++)
+ {
+ ch = bootsect[dosflds[i].offset+j];
+ if( ch <= ' ' || ch > '~' ) putchar('.');
+ else putchar(ch);
+ }
+ putchar('\n');
+ }
+ }
+}
+
+decode_super(bootsect)
+char * bootsect;
+{
+ int i;
+
+ for(i=0; dosflds[i].offset >= 0; i++)
+ {
+ if( dosflds[i].length <= 4 )
+ {
+ long v = 0; int j;
+ for(j=dosflds[i].length-1; j>=0; j--)
+ {
+ v = v*256 + (0xFF&( bootsect[dosflds[i].offset+j] ));
+ }
+ dosflds[i].value = v;
+ }
+ else
+ dosflds[i].value = 0;
+ }
+}
+
+save_super(bootsect)
+char * bootsect;
+{
+ FILE * fd;
+ fd = fopen("makeboot.sav", "wb");
+ fwrite(bootsect, 1024, 1, fd);
+ fclose(fd);
+}
+
+/**************************************************************************/
+
+check_msdos()
+{
+ decode_super(buffer);
+ if( dosflds[DOS_CLUST].value == 0 ) /* MSDOS v1.0 */
+ dosflds[DOS_CLUST].value = 1;
+
+ if( dosflds[DOS_MEDIA].value < 0xF0 )
+ fprintf(stderr, "Dos media descriptor is invalid\n");
+ else if( dosflds[DOS_MEDIA].value != (0xFF&buffer[512])
+ && dosflds[DOS_RESV].value == 1 )
+ fprintf(stderr, "Dos media descriptor check failed\n");
+ else
+ {
+ disk_sect = dosflds[DOS_SPT].value;
+ disk_head = dosflds[DOS_HEADS].value;
+ disk_trck = dosflds[DOS_MAXSECT].value/disk_head/disk_sect;
+ return;
+ }
+ exit(2);
+}
+
+check_simpledos()
+{
+ int numclust;
+ char * err = 0;
+ check_msdos();
+
+ /* Work out how many real clusters there are */
+ numclust = ( dosflds[DOS_MAXSECT].value
+ - dosflds[DOS_RESV].value
+ - dosflds[DOS_NFAT].value * dosflds[DOS_FATLEN].value
+ - ((dosflds[DOS_NROOT].value+15)/16)
+ ) / dosflds[DOS_MAXSECT].value + 2;
+
+ if( dosflds[DOS_NFAT].value > 2 )
+ err = "Too many fat copies on disk";
+ else if( dosflds[DOS_HIDDEN].value != 0 )
+ err = "Dubious MSDOS floppy, it's got hidden sectors.";
+ else if( dosflds[DOS_NROOT].value < 15 )
+ err = "Root directory has unreasonable size.";
+ else if( dosflds[DOS_SECT].value != 512 )
+ err = "Drive sector size isn't 512 bytes sorry no-go.";
+ else if( dosflds[DOS_HEADS].value != 2 )
+ err = "Drive doesn't have two heads, this is required.";
+ else if( numclust > 0xFF0 )
+ err = "Filesystem has a 16 bit fat, only 12bits allowed.";
+ else if( dosflds[DOS_RESV].value + dosflds[DOS_FATLEN].value >
+ dosflds[DOS_SPT].value )
+ err = "The bootblock needs all of fat1 on the first track.";
+ else
+ return;
+
+ fprintf(stderr, "ERROR: %s\n\n", err);
+ print_super(buffer);
+ exit(2);
}
+/**************************************************************************/
diff --git a/bootblocks/mbr.s b/bootblocks/mbr.s
index e190be2..dd4cb27 100644
--- a/bootblocks/mbr.s
+++ b/bootblocks/mbr.s
@@ -14,8 +14,8 @@ preboot=1 ! Include the pre-boot loader ?
org ORGADDR
include sysboot.s
-org ORGADDR+$7
-.ascii "ELKS MBR Copyright 1996, Robert de Bath"
+org ORGADDR+$3
+.ascii "ELKS MBR Copyright 1996, Robert de Bath"
! Start after dos fsstat data, not strictly required.
org codestart
diff --git a/bootblocks/monitor.c b/bootblocks/monitor.c
index 6c1d9eb..b9cc751 100644
--- a/bootblocks/monitor.c
+++ b/bootblocks/monitor.c
@@ -1,13 +1,17 @@
-#define VERSION "0.0.0-ALPHA"
-#define NOT_ANSICOLOUR
-#define VT52COLOUR
+#define VERSION "0.1.1-ALPHA"
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
-#include <i86_funcs.h>
#include <dos.h>
+#include "i86_funcs.h"
+#include "readfs.h"
+
+#ifdef __STANDALONE__
+#define VT52COLOUR
+#define NOT_ANSICOLOUR
+#endif
char command_buf[256];
@@ -37,41 +41,29 @@ static char minibuf[2] = " ";
char *cmd, *args, *ptr;
struct t_cmd_list * cptr;
+#ifdef __STANDALONE__
printf("\n\n");
-#ifdef ANSICOLOUR
- printf("\033[H\033[0;44;37m\033[2J");
-#endif
-#ifdef VT52COLOUR
- printf("\033E\033Rg\033Sa\033J");
-#endif
- printf("Linux x86 boot monitor Version %s\n", VERSION);
-
-#ifndef __STANDALONE__
+#else
if( argc > 1 && strcmp(argv[1], "-t") == 0 ) x86_test=0; else x86_test=1;
#endif
init_prog();
+
+#if 0
#ifdef __STANDALONE__
- {
- extern union REGS __argr;
- printf("REGS: AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x\n",
- __argr.x.ax, __argr.x.bx, __argr.x.cx, __argr.x.dx,
- __argr.x.si, __argr.x.di);
- }
+ reg_line();
#endif
#ifdef VT52COLOUR
- printf("Colours: ");
- printf("\033S \033R_UNL ");
- printf("\033S \033R*BLK ");
- printf("\033S \033R+BLD ");
- printf("\033S \033R!REV");
- printf("\033Sa\033Rg ");
- printf("\033R@@\033Raa\033Rbb\033Rcc\033Rdd\033Ree\033Rff\033Rgg");
- printf("\033Rhh\033Rii\033Rjj\033Rkk\033Rll\033Rmm\033Rnn\033Roo");
- printf("\033Sa\033Rg\n");
+ colour_line();
+#endif
#endif
- printf("Type ^C to exit\n");
+ display_help(0);
+
+ if(1) /* ( x86 > 2 && !x86_emu ) /* Check some basics */
+ cmd_bzimage((void*)0);
+ else
+ printf("System appears incompatible use '=' <return> to try anyway\n");
for (;;)
{
@@ -88,7 +80,7 @@ static char minibuf[2] = " ";
command_buf[ch] = '\0';
if( ch == 1 && command_buf[0] != '\n' )
{
- sprintf(command_buf, "func 0x%02x\n", command_buf[0]&0xFF);
+ sprintf(command_buf, "?$%02x\n", command_buf[0]&0xFF);
printf("%s", command_buf);
}
if( command_buf[ch-1] == '\n' ) command_buf[ch-1] = 0;
@@ -127,6 +119,7 @@ static char minibuf[2] = " ";
#ifdef VT52COLOUR
printf("\033S \033Sa\033Rg");
#endif
+ fflush(stdout);
if( cptr->command )
(void) (*cptr->func)(args);
else
@@ -138,6 +131,14 @@ static char minibuf[2] = " ";
void init_prog()
{
+#ifdef ANSICOLOUR
+ printf("\033[H\033[0;44;37m\033[2J");
+#endif
+#ifdef VT52COLOUR
+ printf("\033E\033Rg\033Sa\033J");
+#endif
+ printf("Linux x86 boot monitor Version %s\n", VERSION);
+
cpu_check();
mem_check();
@@ -162,16 +163,41 @@ void init_prog()
printf("There is %dk of boot memory", boot_mem_top/64);
if( main_mem_top )
{
- printf(" %ld.%ldM of main memory",
+ printf(" %ld.%ldM %sof main memory",
main_mem_top/1024,
- (10*main_mem_top)/1024%10
+ (10*main_mem_top)/1024%10,
+ main_mem_top >= 0xFC00L ?"(perhaps more) ":""
);
}
printf("\n");
+}
- if( main_mem_top >= 0xFC00L )
- printf("There may be more main memory available but the BIOS don't say\n");
+#ifdef __STANDALONE__
+reg_line()
+{
+ extern union REGS __argr;
+ printf("REGS: AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x\n",
+ __argr.x.ax, __argr.x.bx, __argr.x.cx, __argr.x.dx,
+ __argr.x.si, __argr.x.di);
}
+#endif
+
+#ifdef VT52COLOUR
+colour_line()
+{
+ printf("Colours: \033S ");
+ printf("\033R_UNL\033S ");
+ printf("\033R*BLK\033S ");
+ printf("\033R+BLD\033S ");
+ printf("\033R!REV\033S ");
+ printf("\033Sa\033Rg ");
+ printf("\033R@@\033Raa\033Rbb\033Rcc\033Rdd\033Ree\033Rff\033Rgg");
+ printf("\033Rhh\033Rii\033Rjj\033Rkk\033Rll\033Rmm\033Rnn\033Roo");
+ printf("\033Sa\033Rg\n");
+
+ printf("\033S \033Sa\033Rg");
+}
+#endif
/****************************************************************************/
@@ -320,29 +346,84 @@ char * ptr;
printf("to 0x%04x\n", __get_cs());
}
+int cmd_dir(ptr)
+char * ptr;
+{
+ open_file(".");
+ return 0;
+}
+
+int cmd_type(ptr)
+char * ptr;
+{
+ char * fname;
+ char buffer[1024];
+ long len;
+
+ while(*ptr == ' ') ptr++;
+ if( (fname=ptr) == 0 ) return 0;
+ while(*ptr & *ptr != ' ') ptr++;
+
+ if( open_file(fname) >= 0 ) for(len=file_length(); len>0; len-=1024)
+ {
+ if( read_block(buffer) < 0 ) break;
+ if( len > 1024 )
+ write(1, buffer, 1024);
+ else
+ write(1, buffer, len);
+ }
+ else
+ printf("Cannout open file '%s'\n", fname);
+ close_file();
+ return 0;
+}
+
+/****************************************************************************/
+
+/* Others */
+extern int cmd_bzimage();
+extern int cmd_help();
+
/****************************************************************************/
struct t_cmd_list cmd_list[] =
{
{"exit", cmd_quit}, {"quit", cmd_quit}, {"q", cmd_quit},
- {"memdump",cmd_memdump}, {"m", cmd_memdump},
+ {"#", cmd_nop},
+ {"help", cmd_help}, /* Display from help.txt */
+ {"?", cmd_help}, /* Display from help.txt */
+ {"bzimage",cmd_bzimage}, /* Load and run 386 bzimage file */
+ {"=", cmd_bzimage}, /* Load and run 386 bzimage file */
+ {"dir", cmd_dir}, /* Display directory */
+ {"type", cmd_type}, /* Cat/Type a file to the screen */
+ {"cat", cmd_type}, /* Cat/Type a file to the screen */
+
+ /* Debugger/monitor commands */
+ {"memdump",cmd_memdump}, {"mem",cmd_memdump}, {"m", cmd_memdump},
/* Display bytes */
{"seg", cmd_seg}, /* Set default segment */
{"rel", cmd_rel}, /* Relocate self */
{"base", cmd_set_base},
{"n", cmd_set_base},
- {"#", cmd_nop},
+
+#ifdef VT52COLOUR
+ {"colour", colour_line},
+#endif
+ {"init", init_prog},
+#ifdef __STANDALONE__
+ {"reg", reg_line},
+ {"r", reg_line},
+#endif
+
/*
{"edit", cmd_edit}, Alter memory
{"move", cmd_move}, Move memory contents
- {"dir", cmd_dir}, Display dir of inode
{"load", cmd_load}, Load file of inode
{"stat", cmd_stat}, Stat info of inode
- {"zimage", cmd_zimage}, Load and run 386 zimage from inode or tar file
- {"bimage", cmd_bimage}, Load and run 386 bzimage from inode or tar file
- {"image", cmd_image}, Load and run 8086 image from inode or tar file
+ {"zimage", cmd_zimage}, Load and run 386 zimage file
+ {"image", cmd_image}, Load and run 8086 image file
{"read", cmd_read}, Read sector
{"write", cmd_write}, Write sector
diff --git a/bootblocks/msdos.s b/bootblocks/msdos.s
index 1e71f31..fdded78 100644
--- a/bootblocks/msdos.s
+++ b/bootblocks/msdos.s
@@ -2,21 +2,31 @@
! This is a bootblock to load an execute a standalone program from an
! MSDOS filesystem on a floppy disk.
!
-! The program is divided into two parts, the first 512 bytes contains a
-! loader to fetch one block from a file called 'BOOTFILE.SYS' from the
-! root directory of the disk. The second 512, which is stored in this file,
-! loads the executable using functions supplied by the first.
+! The file loaded is called 'BOOTFILE.SYS' it can be changed at install time
+! by following the label boot_name.
!
-! The 2nd part is loaded as if it's a floppy boot block and can be used to
-! store, for instance, a LILO boot block to let LILO boot from an MSDOS
-! floppy.
+! The file is loaded at address $7C00, this means it can be the image of a
+! boot block (eg LILO). It's also checked for the magic number associated
+! with a Linux-8086 standalone executable and this is used if found.
!
-! The second part is NOT yet complete!
+! There are a number of assumptions made by the code concerning the layout
+! of the msdos files system:
+!
+! 1) All of the first FAT must be on the first track.
+! 2) The FAT must be 12 bit
+! 3) The value of the hidden sectors field must be zero
+! 4) There must be two heads on the disk.
+!
+! All these are true for mtools created floppies on normal PC drives.
!
ORGADDR=$0500
use16
+! Some configuration values
+LOADSEG= $7C0
+
+!-------------------------------------------------------------------------
! Absolute position macro, fails if code before it is too big.
macro locn
if *-start>?1
@@ -25,6 +35,8 @@ macro locn
.blkb ?1 + start-*
mend
+heads=2 ! This can be 1 or 2 ONLY. (1 is untested)
+
org ORGADDR
start:
include sysboot.s
@@ -74,13 +86,13 @@ cont:
mov [bp],di
mov 2[bp],ax
- mov al,[dos_spt]
+ mov al,[dos_spt] ! Finally, correct spt.
mov 4[di],al
! For each sector in root dir
! For each dir entry
! If entry name is == boot_name
-! then load and call sector
+! then load and run
! First dir = dos_fatlen*dos_nfat+dos_resv
mov ax,[dos_fatlen]
@@ -88,6 +100,7 @@ cont:
xor dh,dh
mul dx
add ax,[dos_resv]
+ ! Assume: dos_hidden == 0
mov di,ax
! DI is sector number of first root dir sector.
@@ -109,6 +122,8 @@ nextsect:
mov si,bx
nextentry:
+ ! Test attributes for !dir !label here ?
+
! test entry name
push si
push di
@@ -118,61 +133,53 @@ nextentry:
cmpsb
pop di
pop si
- je got_entry
+ jne bad_entry
- add si,#32
+ mov ax,[si+26] ! Cluster number of start of file
+ test ax,ax ! Make sure we have a block.
+ jnz load_system
+
+bad_entry:
+ add si,#32 ! skip to next entry
cmp si,#512
jnz nextentry
- inc di
+ inc di ! Load next sector
sub [root_count],#16
jp nextsect
jmp no_system
-got_entry:
- mov ax,[si+26] ! Cluster number of start of file
- test ax,ax
- jz no_system ! Make sure we have a block.
-
- mov di,ax ! Save the cluster number we are loading.
- call linclust
-
- mov ax,#$0201
- int $13
- jc floppy_error
-
- mov bx,#7
- mov ax,#$0E3E
- int $10
-
- jmpi $7C00,0 ! No magics, just go.
-
-! Convert a cluster number into a CHS in CX:DX
+! Convert a cluster number in AX into a CHS in CX:DX
linclust:
sub ax,#2
mov dl,[dos_clust]
xor dh,dh
mul dx
- add ax,bp
- mov di,ax
- ! JMP linsect ...
+ add ax,bp ! Add sector number of first data sector.
+ jmp linsect2
!
! This function converts a linear sector number in DI
! into a CHS representation in CX:DX
!
linsect:
- xor dx,dx
mov ax,di
+linsect2:
+ xor dx,dx
div [dos_spt]
inc dx
mov cl,dl ! Sector num
xor dx,dx ! Drive 0
+ if heads =2
shr ax,#1 ! Assume dos_heads == 2
adc dh,#0 ! Head num
+ endif
mov ch,al ! Cylinder
ret
+error_msg:
+ .asciz "\r\nError during initial boot\r\nPress a key:"
+
no_system:
floppy_error:
@@ -191,31 +198,15 @@ EOS:
int $19 ! This should be OK as we haven't touched anything.
jmpi $0,$FFFF ! Wam! Try or die!
-error_msg:
- .asciz "\r\nError during initial boot\r\nPress a key:"
-
-export boot_name
-boot_name:
- .ascii "BOOTFILESYS"
-name_end:
-! NNNNNNNNEEE
!
-!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+! This loads the boot program 1 sector at a time, funny thing is it actually
+! loads at exactly the same speed as loading a track at a time, at least on
+! my slow old 286/8Mhz. Oh well, we need the space so if you're worried just
+! tell superformat to give you an interleave of 2 (-i 2).
!
-! Part 2, loaded like a boot block by part 1
-! ... Here we will allow some assumptions (cause we've set them)
-fat_table = ORGADDR+$400 ! Where to load the fat
-locn(512)
-part2_addr:
- push di
- mov cx,#$100 ! Move 256 words
- mov si,#$7C00 ! From default BB
- mov di,#part2_addr ! To the correct address.
- rep
- movsw
- jmpi cont2,#0 ! Set CS:IP correct.
-cont2:
+load_system:
+ push ax ! Save cluster we're loading
! 1) Load FAT
! This assumes all of FAT1 is on the first track, this is normal
@@ -226,28 +217,109 @@ cont2:
inc cx
xor dx,dx ! Head zero
int $13
- !jc floppy_error
+ jc floppy_error
- mov bx,#$7C00
+ mov ax,#LOADSEG
+ mov es,ax
pop di ! Cluster to start load.
! load whole cluster
next_cluster:
+ mov si,[dos_clust] ! How big is a cluster
+ and si,#255
+
+ mov ax,di ! Find it's physical address
+ call linclust
+
+next:
+ mov ax,#$0201
+ xor bx,bx
+ int $13 ! Load 1 sector at a time
+ jc floppy_error
+
+ mov ax,es
+ add ax,#512/16
+ mov es,ax
+
+ cmp cl,[dos_spt] ! Does cluster straddle tracks ?
+ jnz sectok
+ mov cl,#0
+ if heads=2
+ inc dh
+ cmp dh,#2 ! Does cluster straddle cylinders ?
+ jnz sectok
+ xor dh,dh
+ endif
+ inc ch
+sectok:
+ inc cl
+ dec si
+ jnz next
call next_fat
- cmp di,#0
- jnz next_cluster
- br maincode
+ jc next_cluster
+ jmp maincode
next_fat:
- !mov ax,di
- !mov bx,ax
- !shr ax,#1
- !add bx,ax
-
+ mov ax,di
+ shr ax,#1
+ pushf ! Save if odd number
+ add di,ax
+ mov di,fat_table[di]
+ popf
+ jnc noshift ! Odd in high nibbles.
+ mov cl,#4
+ shr di,cl
+noshift:
+ and di,#$FFF
+ cmp di,#$FF0 ! FFF is EOF, clear carry flag.
+ ! FF0+ are badblocks etc.
+ ret
-! The end ... place a marker.
-locn(1023)
- .byte $FF
maincode:
+ mov bx,#7
+ mov ax,#$0E3E
+ int $10 ! Marker printed to say bootblock succeeded.
+
+ xor dx,dx ! DX=0 => floppy drive
+ push dx ! CX=0 => partition offset = 0
+
+ mov bx,#LOADSEG
+ mov ds,bx ! DS = loadaddress
+ inc bx
+ inc bx ! bx = initial CS
+ xor di,di ! Zero
+ mov ax,[di]
+ cmp ax,#0x0301 ! Right magic ?
+ jnz bad_magic ! Yuk ...
+ mov ax,[di+2]
+ and ax,#$20 ! Is it split I/D ?
+ jz impure ! No ...
+ mov cl,#4
+ mov ax,[di+8]
+ shr ax,cl
+impure:
+ pop cx ! Partition offset.
+ add ax,bx
+ mov ss,ax
+ mov sp,[di+24] ! Chmem value
+ mov ds,ax
+
+ push bx ! jmpi 0,#LOADSEG+2
+ push di
+
+ ! AX=ds, BX=cs, CX=X, DX=X, SI=X, DI=0, BP=X, ES=X, DS=*, SS=*, CS=*
+ retf
+bad_magic:
+ jmpi $7C00,0 ! No magics, just go.
+
+export boot_name
+boot_name:
+ .ascii "BOOTFILESYS"
+name_end:
+! NNNNNNNNEEE
+
+locn(512)
+fat_table: ! This is the location that the fat table is loaded.
+ ! Note: The fat must be entirely on track zero.
diff --git a/bootblocks/nofs.c b/bootblocks/nofs.c
new file mode 100644
index 0000000..e671a69
--- /dev/null
+++ b/bootblocks/nofs.c
@@ -0,0 +1,55 @@
+
+#ifndef __STANDALONE__
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "readfs.h"
+
+static int fd = -1;
+
+open_file(fname)
+char * fname;
+{
+ if( fd >= 0 ) close(fd);
+ fd = open(fname, 0);
+ if( fd >= 0 ) return 0;
+ return -1;
+}
+
+rewind_file()
+{
+ if( fd == -1 ) return -1;
+ lseek(fd, 0L, 0);
+ return 0;
+}
+
+close_file()
+{
+ if( fd >= 0 ) close(fd);
+ fd = -1;
+}
+
+long
+file_length()
+{
+ struct stat st;
+ if( fd == -1 ) return -1;
+ if( fstat(fd, &st) < 0 ) return -1;
+
+ return st.st_size;
+}
+
+read_block(buffer)
+char * buffer;
+{
+ int rv;
+ if( fd == -1 ) return -1;
+
+ rv = read(fd, buffer, 1024);
+ if( rv <= 0 ) return -1;
+ if( rv < 1024 )
+ memset(buffer+rv, '\0', 1024-rv);
+ return 0;
+}
+
+#endif
diff --git a/bootblocks/relocate.c b/bootblocks/relocate.c
index 37396a1..6101296 100644
--- a/bootblocks/relocate.c
+++ b/bootblocks/relocate.c
@@ -50,11 +50,10 @@ unsigned newseg;
moved += lump;
}
- /* re-link int 0x80
- __set_es(0);
- __doke_es(0x80*4+2, newseg);
- __set_es(es);
- */
+ /* re-link int 0x80, this one is only an example (used by 'standalone.c') */
+ /*
+ __set_es(0); __doke_es(0x80*4+2, newseg); __set_es(es);
+ */
/* The actual jump ... */
memseg = newseg;
diff --git a/bootblocks/skip.s b/bootblocks/skip.s
index 8de5ada..3e55cd9 100644
--- a/bootblocks/skip.s
+++ b/bootblocks/skip.s
@@ -33,6 +33,7 @@ cont:
mov di,#5
hcode:
+ mov bx,#$7C00 ! Pointer to start of BB.
mov ax,#$0201 ! Read 1 sector
mov cx,#$0001 ! From sector 1
mov dx,#BOOTDISK ! Of the hard drive head zero
diff --git a/bootblocks/sysboot.s b/bootblocks/sysboot.s
index 622488f..54b0fb2 100644
--- a/bootblocks/sysboot.s
+++ b/bootblocks/sysboot.s
@@ -15,31 +15,33 @@
sysboot_start:
j codestart
+nop ! DOS appears to _require_ this to identify an MSDOS disk!!
.blkb sysboot_start+3-*
public dosfs_stat
+dos_sysid: .ascii "LINUX" ! System ID
+ .byte 0,0,0
dosfs_stat:
-dos_sysid: .blkb 8 ! System ID
-dos_sect: .word 0 ! Sector size
-dos_clust: .byte 0 ! Cluster size
-dos_resv: .word 0 ! Res-sector
-dos_nfat: .byte 0 ! FAT count
-dos_nroot: .word 0 ! Root dir entries
-dos_maxsect: .word 0 ! Sector count (=0 if large FS)
-dos_media: .byte 0 ! Media code
-dos_fatlen: .word 0 ! FAT length
-dos_spt: .word 0 ! Sect/Track
-dos_heads: .word 0 ! Heads
-dos_hidden: .long 0 ! Hidden sectors
+dos_sect: .blkw 1 ! Sector size
+dos_clust: .blkb 1 ! Cluster size
+dos_resv: .blkw 1 ! Res-sector
+dos_nfat: .blkb 1 ! FAT count
+dos_nroot: .blkw 1 ! Root dir entries
+dos_maxsect: .blkw 1 ! Sector count (=0 if large FS)
+dos_media: .blkb 1 ! Media code
+dos_fatlen: .blkw 1 ! FAT length
+dos_spt: .blkw 1 ! Sect/Track
+dos_heads: .blkw 1 ! Heads
+dos_hidden: .blkw 2 ! Hidden sectors
! Here down is DOS 4+ and probably not needed for floppy boots.
floppy_temp:
-dos4_maxsect: .long 0 ! Large FS sector count
-dos4_phy_drive: .byte 0 ! Phys drive
-.byte 0 ! Reserved
-.byte 0 ! DOS 4
-dos4_serial: .long 0 ! Serial number
+dos4_maxsect: .blkw 2 ! Large FS sector count
+dos4_phy_drive: .blkb 1 ! Phys drive
+.blkb 1 ! Reserved
+.blkb 1 ! DOS 4
+dos4_serial: .blkw 2 ! Serial number
dos4_label: .blkb 11 ! Disk Label (DOS 4+)
dos4_fattype: .blkb 8 ! FAT type
@@ -57,24 +59,28 @@ public bootblock_magic
.blkb sysboot_start+0x1BE-*
partition_1:
-.byte 0,0,0,0,0,0,0,0 ! IN,SH,SS,ST,OS,EH,ES,ET
-.long 0 ! Linear position (0 based)
-.long 0 ! Linear length
+.byte 0 ! IN
+.blkb 7 ! SH,SS,ST,OS,EH,ES,ET
+.blkw 2 ! Linear position (0 based)
+.blkw 2 ! Linear length
.blkb sysboot_start+0x1CE-*
partition_2:
-.byte 0,0,0,0,0,0,0,0 ! IN,SH,SS,ST,OS,EH,ES,ET
-.long 0 ! Linear position (0 based)
-.long 0 ! Linear length
+.byte 0 ! IN
+.blkb 7 ! SH,SS,ST,OS,EH,ES,ET
+.blkw 2 ! Linear position (0 based)
+.blkw 2 ! Linear length
.blkb sysboot_start+0x1DE-*
partition_3:
-.byte 0,0,0,0,0,0,0,0 ! IN,SH,SS,ST,OS,EH,ES,ET
-.long 0 ! Linear position (0 based)
-.long 0 ! Linear length
+.byte 0 ! IN
+.blkb 7 ! SH,SS,ST,OS,EH,ES,ET
+.blkw 2 ! Linear position (0 based)
+.blkw 2 ! Linear length
.blkb sysboot_start+0x1EE-*
partition_4:
-.byte 0,0,0,0,0,0,0,0 ! IN,SH,SS,ST,OS,EH,ES,ET
-.long 0 ! Linear position (0 based)
-.long 0 ! Linear length
+.byte 0 ! IN
+.blkb 7 ! SH,SS,ST,OS,EH,ES,ET
+.blkw 2 ! Linear position (0 based)
+.blkw 2 ! Linear length
bootblock_magic:
.blkb sysboot_start+0x1FE-*
diff --git a/compile.bat b/compile.bat
deleted file mode 100644
index 814548e..0000000
--- a/compile.bat
+++ /dev/null
@@ -1,508 +0,0 @@
-@echo off
-if not exist later.exe cl -nologo -O later.c %LIB%\setargv.obj -link /NOE
-
-later bcc/bcc.obj bcc/bcc.c
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -c -Fobcc\bcc.obj bcc\bcc.c
-if errorlevel 1 goto exit_now
-later bin/bcc.exe bcc/bcc.obj
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -o bin\bcc.exe bcc\bcc.obj %LIB%\setargv.obj -link /NOE
-if errorlevel 1 goto exit_now
-
-later bcc/bcc-cc1.obj bcc/bcc-cc1.c bcc/align.h bcc/byteord.h bcc/condcode.h bcc/const.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/bcc-cc1.obj bcc/gencode.h bcc/input.h bcc/label.h bcc/os.h bcc/output.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/bcc-cc1.obj bcc/parse.h bcc/proto.h bcc/reg.h bcc/sc.h bcc/scan.h bcc/sizes.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/bcc-cc1.obj bcc/table.h bcc/type.h bcc/types.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fobcc\bcc-cc1.obj bcc\bcc-cc1.c
-if errorlevel 1 goto exit_now
-later bcc/assign.obj bcc/assign.c bcc/align.h bcc/byteord.h bcc/condcode.h bcc/const.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/assign.obj bcc/gencode.h bcc/input.h bcc/label.h bcc/os.h bcc/output.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/assign.obj bcc/parse.h bcc/proto.h bcc/reg.h bcc/sc.h bcc/scan.h bcc/sizes.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/assign.obj bcc/table.h bcc/type.h bcc/types.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fobcc\assign.obj bcc\assign.c
-if errorlevel 1 goto exit_now
-later bcc/codefrag.obj bcc/codefrag.c bcc/align.h bcc/byteord.h bcc/condcode.h bcc/const.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/codefrag.obj bcc/gencode.h bcc/input.h bcc/label.h bcc/os.h bcc/output.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/codefrag.obj bcc/parse.h bcc/proto.h bcc/reg.h bcc/sc.h bcc/scan.h bcc/sizes.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/codefrag.obj bcc/table.h bcc/type.h bcc/types.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fobcc\codefrag.obj bcc\codefrag.c
-if errorlevel 1 goto exit_now
-later bcc/debug.obj bcc/debug.c bcc/align.h bcc/byteord.h bcc/condcode.h bcc/const.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/debug.obj bcc/gencode.h bcc/input.h bcc/label.h bcc/os.h bcc/output.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/debug.obj bcc/parse.h bcc/proto.h bcc/reg.h bcc/sc.h bcc/scan.h bcc/sizes.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/debug.obj bcc/table.h bcc/type.h bcc/types.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fobcc\debug.obj bcc\debug.c
-if errorlevel 1 goto exit_now
-later bcc/declare.obj bcc/declare.c bcc/align.h bcc/byteord.h bcc/condcode.h bcc/const.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/declare.obj bcc/gencode.h bcc/input.h bcc/label.h bcc/os.h bcc/output.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/declare.obj bcc/parse.h bcc/proto.h bcc/reg.h bcc/sc.h bcc/scan.h bcc/sizes.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/declare.obj bcc/table.h bcc/type.h bcc/types.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fobcc\declare.obj bcc\declare.c
-if errorlevel 1 goto exit_now
-later bcc/express.obj bcc/express.c bcc/align.h bcc/byteord.h bcc/condcode.h bcc/const.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/express.obj bcc/gencode.h bcc/input.h bcc/label.h bcc/os.h bcc/output.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/express.obj bcc/parse.h bcc/proto.h bcc/reg.h bcc/sc.h bcc/scan.h bcc/sizes.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/express.obj bcc/table.h bcc/type.h bcc/types.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fobcc\express.obj bcc\express.c
-if errorlevel 1 goto exit_now
-later bcc/exptree.obj bcc/exptree.c bcc/align.h bcc/byteord.h bcc/condcode.h bcc/const.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/exptree.obj bcc/gencode.h bcc/input.h bcc/label.h bcc/os.h bcc/output.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/exptree.obj bcc/parse.h bcc/proto.h bcc/reg.h bcc/sc.h bcc/scan.h bcc/sizes.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/exptree.obj bcc/table.h bcc/type.h bcc/types.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fobcc\exptree.obj bcc\exptree.c
-if errorlevel 1 goto exit_now
-later bcc/floatop.obj bcc/floatop.c bcc/align.h bcc/byteord.h bcc/condcode.h bcc/const.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/floatop.obj bcc/gencode.h bcc/input.h bcc/label.h bcc/os.h bcc/output.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/floatop.obj bcc/parse.h bcc/proto.h bcc/reg.h bcc/sc.h bcc/scan.h bcc/sizes.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/floatop.obj bcc/table.h bcc/type.h bcc/types.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fobcc\floatop.obj bcc\floatop.c
-if errorlevel 1 goto exit_now
-later bcc/function.obj bcc/function.c bcc/align.h bcc/byteord.h bcc/condcode.h bcc/const.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/function.obj bcc/gencode.h bcc/input.h bcc/label.h bcc/os.h bcc/output.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/function.obj bcc/parse.h bcc/proto.h bcc/reg.h bcc/sc.h bcc/scan.h bcc/sizes.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/function.obj bcc/table.h bcc/type.h bcc/types.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fobcc\function.obj bcc\function.c
-if errorlevel 1 goto exit_now
-later bcc/gencode.obj bcc/gencode.c bcc/align.h bcc/byteord.h bcc/condcode.h bcc/const.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/gencode.obj bcc/gencode.h bcc/input.h bcc/label.h bcc/os.h bcc/output.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/gencode.obj bcc/parse.h bcc/proto.h bcc/reg.h bcc/sc.h bcc/scan.h bcc/sizes.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/gencode.obj bcc/table.h bcc/type.h bcc/types.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fobcc\gencode.obj bcc\gencode.c
-if errorlevel 1 goto exit_now
-later bcc/genloads.obj bcc/genloads.c bcc/align.h bcc/byteord.h bcc/condcode.h bcc/const.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/genloads.obj bcc/gencode.h bcc/input.h bcc/label.h bcc/os.h bcc/output.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/genloads.obj bcc/parse.h bcc/proto.h bcc/reg.h bcc/sc.h bcc/scan.h bcc/sizes.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/genloads.obj bcc/table.h bcc/type.h bcc/types.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fobcc\genloads.obj bcc\genloads.c
-if errorlevel 1 goto exit_now
-later bcc/glogcode.obj bcc/glogcode.c bcc/align.h bcc/byteord.h bcc/condcode.h bcc/const.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/glogcode.obj bcc/gencode.h bcc/input.h bcc/label.h bcc/os.h bcc/output.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/glogcode.obj bcc/parse.h bcc/proto.h bcc/reg.h bcc/sc.h bcc/scan.h bcc/sizes.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/glogcode.obj bcc/table.h bcc/type.h bcc/types.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fobcc\glogcode.obj bcc\glogcode.c
-if errorlevel 1 goto exit_now
-later bcc/hardop.obj bcc/hardop.c bcc/align.h bcc/byteord.h bcc/condcode.h bcc/const.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/hardop.obj bcc/gencode.h bcc/input.h bcc/label.h bcc/os.h bcc/output.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/hardop.obj bcc/parse.h bcc/proto.h bcc/reg.h bcc/sc.h bcc/scan.h bcc/sizes.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/hardop.obj bcc/table.h bcc/type.h bcc/types.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fobcc\hardop.obj bcc\hardop.c
-if errorlevel 1 goto exit_now
-later bcc/input.obj bcc/input.c bcc/align.h bcc/byteord.h bcc/condcode.h bcc/const.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/input.obj bcc/gencode.h bcc/input.h bcc/label.h bcc/os.h bcc/output.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/input.obj bcc/parse.h bcc/proto.h bcc/reg.h bcc/sc.h bcc/scan.h bcc/sizes.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/input.obj bcc/table.h bcc/type.h bcc/types.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fobcc\input.obj bcc\input.c
-if errorlevel 1 goto exit_now
-later bcc/label.obj bcc/label.c bcc/align.h bcc/byteord.h bcc/condcode.h bcc/const.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/label.obj bcc/gencode.h bcc/input.h bcc/label.h bcc/os.h bcc/output.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/label.obj bcc/parse.h bcc/proto.h bcc/reg.h bcc/sc.h bcc/scan.h bcc/sizes.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/label.obj bcc/table.h bcc/type.h bcc/types.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fobcc\label.obj bcc\label.c
-if errorlevel 1 goto exit_now
-later bcc/loadexp.obj bcc/loadexp.c bcc/align.h bcc/byteord.h bcc/condcode.h bcc/const.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/loadexp.obj bcc/gencode.h bcc/input.h bcc/label.h bcc/os.h bcc/output.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/loadexp.obj bcc/parse.h bcc/proto.h bcc/reg.h bcc/sc.h bcc/scan.h bcc/sizes.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/loadexp.obj bcc/table.h bcc/type.h bcc/types.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fobcc\loadexp.obj bcc\loadexp.c
-if errorlevel 1 goto exit_now
-later bcc/longop.obj bcc/longop.c bcc/align.h bcc/byteord.h bcc/condcode.h bcc/const.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/longop.obj bcc/gencode.h bcc/input.h bcc/label.h bcc/os.h bcc/output.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/longop.obj bcc/parse.h bcc/proto.h bcc/reg.h bcc/sc.h bcc/scan.h bcc/sizes.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/longop.obj bcc/table.h bcc/type.h bcc/types.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fobcc\longop.obj bcc\longop.c
-if errorlevel 1 goto exit_now
-later bcc/output.obj bcc/output.c bcc/align.h bcc/byteord.h bcc/condcode.h bcc/const.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/output.obj bcc/gencode.h bcc/input.h bcc/label.h bcc/os.h bcc/output.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/output.obj bcc/parse.h bcc/proto.h bcc/reg.h bcc/sc.h bcc/scan.h bcc/sizes.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/output.obj bcc/table.h bcc/type.h bcc/types.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fobcc\output.obj bcc\output.c
-if errorlevel 1 goto exit_now
-later bcc/preproc.obj bcc/preproc.c bcc/align.h bcc/byteord.h bcc/condcode.h bcc/const.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/preproc.obj bcc/gencode.h bcc/input.h bcc/label.h bcc/os.h bcc/output.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/preproc.obj bcc/parse.h bcc/proto.h bcc/reg.h bcc/sc.h bcc/scan.h bcc/sizes.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/preproc.obj bcc/table.h bcc/type.h bcc/types.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fobcc\preproc.obj bcc\preproc.c
-if errorlevel 1 goto exit_now
-later bcc/preserve.obj bcc/preserve.c bcc/align.h bcc/byteord.h bcc/condcode.h bcc/const.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/preserve.obj bcc/gencode.h bcc/input.h bcc/label.h bcc/os.h bcc/output.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/preserve.obj bcc/parse.h bcc/proto.h bcc/reg.h bcc/sc.h bcc/scan.h bcc/sizes.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/preserve.obj bcc/table.h bcc/type.h bcc/types.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fobcc\preserve.obj bcc\preserve.c
-if errorlevel 1 goto exit_now
-later bcc/scan.obj bcc/scan.c bcc/align.h bcc/byteord.h bcc/condcode.h bcc/const.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/scan.obj bcc/gencode.h bcc/input.h bcc/label.h bcc/os.h bcc/output.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/scan.obj bcc/parse.h bcc/proto.h bcc/reg.h bcc/sc.h bcc/scan.h bcc/sizes.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/scan.obj bcc/table.h bcc/type.h bcc/types.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fobcc\scan.obj bcc\scan.c
-if errorlevel 1 goto exit_now
-later bcc/softop.obj bcc/softop.c bcc/align.h bcc/byteord.h bcc/condcode.h bcc/const.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/softop.obj bcc/gencode.h bcc/input.h bcc/label.h bcc/os.h bcc/output.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/softop.obj bcc/parse.h bcc/proto.h bcc/reg.h bcc/sc.h bcc/scan.h bcc/sizes.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/softop.obj bcc/table.h bcc/type.h bcc/types.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fobcc\softop.obj bcc\softop.c
-if errorlevel 1 goto exit_now
-later bcc/state.obj bcc/state.c bcc/align.h bcc/byteord.h bcc/condcode.h bcc/const.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/state.obj bcc/gencode.h bcc/input.h bcc/label.h bcc/os.h bcc/output.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/state.obj bcc/parse.h bcc/proto.h bcc/reg.h bcc/sc.h bcc/scan.h bcc/sizes.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/state.obj bcc/table.h bcc/type.h bcc/types.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fobcc\state.obj bcc\state.c
-if errorlevel 1 goto exit_now
-later bcc/table.obj bcc/table.c bcc/align.h bcc/byteord.h bcc/condcode.h bcc/const.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/table.obj bcc/gencode.h bcc/input.h bcc/label.h bcc/os.h bcc/output.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/table.obj bcc/parse.h bcc/proto.h bcc/reg.h bcc/sc.h bcc/scan.h bcc/sizes.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/table.obj bcc/table.h bcc/type.h bcc/types.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fobcc\table.obj bcc\table.c
-if errorlevel 1 goto exit_now
-later bcc/type.obj bcc/type.c bcc/align.h bcc/byteord.h bcc/condcode.h bcc/const.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/type.obj bcc/gencode.h bcc/input.h bcc/label.h bcc/os.h bcc/output.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/type.obj bcc/parse.h bcc/proto.h bcc/reg.h bcc/sc.h bcc/scan.h bcc/sizes.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bcc/type.obj bcc/table.h bcc/type.h bcc/types.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fobcc\type.obj bcc\type.c
-if errorlevel 1 goto exit_now
-later lib/bcc-cc1.exe bcc/bcc-cc1.obj bcc/assign.obj bcc/codefrag.obj bcc/debug.obj
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later lib/bcc-cc1.exe bcc/declare.obj bcc/express.obj bcc/exptree.obj bcc/floatop.obj
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later lib/bcc-cc1.exe bcc/function.obj bcc/gencode.obj bcc/genloads.obj bcc/glogcode.obj
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later lib/bcc-cc1.exe bcc/hardop.obj bcc/input.obj bcc/label.obj bcc/loadexp.obj
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later lib/bcc-cc1.exe bcc/longop.obj bcc/output.obj bcc/preproc.obj bcc/preserve.obj
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later lib/bcc-cc1.exe bcc/scan.obj bcc/softop.obj bcc/state.obj bcc/table.obj bcc/type.obj
-if errorlevel 3 goto exit_now
-if not errorlevel 1 goto done_bcc-cc1
-if exist doslib.lib del doslib.lib
-lib doslib.lib +bcc\assign.obj +bcc\codefrag.obj +bcc\debug.obj; >NUL
-lib doslib.lib +bcc\declare.obj +bcc\express.obj +bcc\exptree.obj; >NUL
-lib doslib.lib +bcc\floatop.obj +bcc\function.obj +bcc\gencode.obj; >NUL
-lib doslib.lib +bcc\genloads.obj +bcc\glogcode.obj +bcc\hardop.obj; >NUL
-lib doslib.lib +bcc\input.obj +bcc\label.obj +bcc\loadexp.obj +bcc\longop.obj; >NUL
-lib doslib.lib +bcc\output.obj +bcc\preproc.obj +bcc\preserve.obj; >NUL
-lib doslib.lib +bcc\scan.obj +bcc\softop.obj +bcc\state.obj +bcc\table.obj; >NUL
-lib doslib.lib +bcc\type.obj; >NUL
-cl -Ml -o lib\bcc-cc1.exe bcc\bcc-cc1.obj doslib.lib
-if errorlevel 1 goto exit_now
-if exist doslib.lib del doslib.lib
-if exist doslib.bak del doslib.bak
-:done_bcc-cc1
-
-later as/as.obj as/as.c as/address.h as/byteord.h as/const.h as/file.h as/flag.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/as.obj as/globvar.h as/macro.h as/opcode.h as/proto.h as/scan.h as/source.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/as.obj as/syshead.h as/type.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Foas\as.obj as\as.c
-if errorlevel 1 goto exit_now
-later as/assemble.obj as/assemble.c as/address.h as/byteord.h as/const.h as/file.h as/flag.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/assemble.obj as/globvar.h as/macro.h as/opcode.h as/proto.h as/scan.h as/source.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/assemble.obj as/syshead.h as/type.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Foas\assemble.obj as\assemble.c
-if errorlevel 1 goto exit_now
-later as/error.obj as/error.c as/address.h as/byteord.h as/const.h as/file.h as/flag.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/error.obj as/globvar.h as/macro.h as/opcode.h as/proto.h as/scan.h as/source.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/error.obj as/syshead.h as/type.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Foas\error.obj as\error.c
-if errorlevel 1 goto exit_now
-later as/express.obj as/express.c as/address.h as/byteord.h as/const.h as/file.h as/flag.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/express.obj as/globvar.h as/macro.h as/opcode.h as/proto.h as/scan.h as/source.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/express.obj as/syshead.h as/type.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Foas\express.obj as\express.c
-if errorlevel 1 goto exit_now
-later as/genbin.obj as/genbin.c as/address.h as/byteord.h as/const.h as/file.h as/flag.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/genbin.obj as/globvar.h as/macro.h as/opcode.h as/proto.h as/scan.h as/source.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/genbin.obj as/syshead.h as/type.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Foas\genbin.obj as\genbin.c
-if errorlevel 1 goto exit_now
-later as/genlist.obj as/genlist.c as/address.h as/byteord.h as/const.h as/file.h as/flag.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/genlist.obj as/globvar.h as/macro.h as/opcode.h as/proto.h as/scan.h as/source.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/genlist.obj as/syshead.h as/type.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Foas\genlist.obj as\genlist.c
-if errorlevel 1 goto exit_now
-later as/genobj.obj as/genobj.c as/address.h as/byteord.h as/const.h as/file.h as/flag.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/genobj.obj as/globvar.h as/macro.h as/opcode.h as/proto.h as/scan.h as/source.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/genobj.obj as/syshead.h as/type.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Foas\genobj.obj as\genobj.c
-if errorlevel 1 goto exit_now
-later as/gensym.obj as/gensym.c as/address.h as/byteord.h as/const.h as/file.h as/flag.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/gensym.obj as/globvar.h as/macro.h as/opcode.h as/proto.h as/scan.h as/source.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/gensym.obj as/syshead.h as/type.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Foas\gensym.obj as\gensym.c
-if errorlevel 1 goto exit_now
-later as/keywords.obj as/keywords.c as/address.h as/byteord.h as/const.h as/file.h as/flag.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/keywords.obj as/globvar.h as/macro.h as/opcode.h as/proto.h as/scan.h as/source.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/keywords.obj as/syshead.h as/type.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Foas\keywords.obj as\keywords.c
-if errorlevel 1 goto exit_now
-later as/macro.obj as/macro.c as/address.h as/byteord.h as/const.h as/file.h as/flag.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/macro.obj as/globvar.h as/macro.h as/opcode.h as/proto.h as/scan.h as/source.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/macro.obj as/syshead.h as/type.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Foas\macro.obj as\macro.c
-if errorlevel 1 goto exit_now
-later as/mops.obj as/mops.c as/address.h as/byteord.h as/const.h as/file.h as/flag.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/mops.obj as/globvar.h as/macro.h as/opcode.h as/proto.h as/scan.h as/source.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/mops.obj as/syshead.h as/type.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Foas\mops.obj as\mops.c
-if errorlevel 1 goto exit_now
-later as/pops.obj as/pops.c as/address.h as/byteord.h as/const.h as/file.h as/flag.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/pops.obj as/globvar.h as/macro.h as/opcode.h as/proto.h as/scan.h as/source.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/pops.obj as/syshead.h as/type.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Foas\pops.obj as\pops.c
-if errorlevel 1 goto exit_now
-later as/readsrc.obj as/readsrc.c as/address.h as/byteord.h as/const.h as/file.h as/flag.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/readsrc.obj as/globvar.h as/macro.h as/opcode.h as/proto.h as/scan.h as/source.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/readsrc.obj as/syshead.h as/type.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Foas\readsrc.obj as\readsrc.c
-if errorlevel 1 goto exit_now
-later as/scan.obj as/scan.c as/address.h as/byteord.h as/const.h as/file.h as/flag.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/scan.obj as/globvar.h as/macro.h as/opcode.h as/proto.h as/scan.h as/source.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/scan.obj as/syshead.h as/type.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Foas\scan.obj as\scan.c
-if errorlevel 1 goto exit_now
-later as/table.obj as/table.c as/address.h as/byteord.h as/const.h as/file.h as/flag.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/table.obj as/globvar.h as/macro.h as/opcode.h as/proto.h as/scan.h as/source.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/table.obj as/syshead.h as/type.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Foas\table.obj as\table.c
-if errorlevel 1 goto exit_now
-later as/typeconv.obj as/typeconv.c as/address.h as/byteord.h as/const.h as/file.h as/flag.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/typeconv.obj as/globvar.h as/macro.h as/opcode.h as/proto.h as/scan.h as/source.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later as/typeconv.obj as/syshead.h as/type.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Foas\typeconv.obj as\typeconv.c
-if errorlevel 1 goto exit_now
-later bin/as.exe as/as.obj as/assemble.obj as/error.obj as/express.obj as/genbin.obj
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bin/as.exe as/genlist.obj as/genobj.obj as/gensym.obj as/keywords.obj
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bin/as.exe as/macro.obj as/mops.obj as/pops.obj as/readsrc.obj as/scan.obj
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later bin/as.exe as/table.obj as/typeconv.obj
-if errorlevel 3 goto exit_now
-if not errorlevel 1 goto done_as
-if exist doslib.lib del doslib.lib
-lib doslib.lib +as\assemble.obj +as\error.obj +as\express.obj +as\genbin.obj; >NUL
-lib doslib.lib +as\genlist.obj +as\genobj.obj +as\gensym.obj +as\keywords.obj; >NUL
-lib doslib.lib +as\macro.obj +as\mops.obj +as\pops.obj +as\readsrc.obj; >NUL
-lib doslib.lib +as\scan.obj +as\table.obj +as\typeconv.obj; >NUL
-cl -Ml -o bin\as.exe as\as.obj doslib.lib
-if errorlevel 1 goto exit_now
-if exist doslib.lib del doslib.lib
-if exist doslib.bak del doslib.bak
-:done_as
-
-later ld/ld.obj ld/ld.c ld/align.h ld/ar.h ld/bindef.h ld/byteord.h ld/config.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later ld/ld.obj ld/const.h ld/globvar.h ld/obj.h ld/syshead.h ld/type.h ld/x86_aout.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fold\ld.obj ld\ld.c
-if errorlevel 1 goto exit_now
-later ld/dumps.obj ld/dumps.c ld/align.h ld/ar.h ld/bindef.h ld/byteord.h ld/config.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later ld/dumps.obj ld/const.h ld/globvar.h ld/obj.h ld/syshead.h ld/type.h ld/x86_aout.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fold\dumps.obj ld\dumps.c
-if errorlevel 1 goto exit_now
-later ld/io.obj ld/io.c ld/align.h ld/ar.h ld/bindef.h ld/byteord.h ld/config.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later ld/io.obj ld/const.h ld/globvar.h ld/obj.h ld/syshead.h ld/type.h ld/x86_aout.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fold\io.obj ld\io.c
-if errorlevel 1 goto exit_now
-later ld/linksyms.obj ld/linksyms.c ld/align.h ld/ar.h ld/bindef.h ld/byteord.h ld/config.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later ld/linksyms.obj ld/const.h ld/globvar.h ld/obj.h ld/syshead.h ld/type.h ld/x86_aout.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fold\linksyms.obj ld\linksyms.c
-if errorlevel 1 goto exit_now
-later ld/readobj.obj ld/readobj.c ld/align.h ld/ar.h ld/bindef.h ld/byteord.h ld/config.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later ld/readobj.obj ld/const.h ld/globvar.h ld/obj.h ld/syshead.h ld/type.h ld/x86_aout.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fold\readobj.obj ld\readobj.c
-if errorlevel 1 goto exit_now
-later ld/table.obj ld/table.c ld/align.h ld/ar.h ld/bindef.h ld/byteord.h ld/config.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later ld/table.obj ld/const.h ld/globvar.h ld/obj.h ld/syshead.h ld/type.h ld/x86_aout.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fold\table.obj ld\table.c
-if errorlevel 1 goto exit_now
-later ld/typeconv.obj ld/typeconv.c ld/align.h ld/ar.h ld/bindef.h ld/byteord.h ld/config.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later ld/typeconv.obj ld/const.h ld/globvar.h ld/obj.h ld/syshead.h ld/type.h ld/x86_aout.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fold\typeconv.obj ld\typeconv.c
-if errorlevel 1 goto exit_now
-later ld/writebin.obj ld/writebin.c ld/align.h ld/ar.h ld/bindef.h ld/byteord.h ld/config.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later ld/writebin.obj ld/const.h ld/globvar.h ld/obj.h ld/syshead.h ld/type.h ld/x86_aout.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fold\writebin.obj ld\writebin.c
-if errorlevel 1 goto exit_now
-later ld/writex86.obj ld/writex86.c ld/align.h ld/ar.h ld/bindef.h ld/byteord.h ld/config.h
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later ld/writex86.obj ld/const.h ld/globvar.h ld/obj.h ld/syshead.h ld/type.h ld/x86_aout.h
-if errorlevel 3 goto exit_now
-if errorlevel 1 cl -Ml -nologo -O -DPOSIX_HEADERS_MISSING -c -Fold\writex86.obj ld\writex86.c
-if errorlevel 1 goto exit_now
-later lib/ld.exe ld/ld.obj ld/dumps.obj ld/io.obj ld/linksyms.obj ld/readobj.obj
-if errorlevel 3 goto exit_now
-if not errorlevel 1 later lib/ld.exe ld/table.obj ld/typeconv.obj ld/writebin.obj ld/writex86.obj
-if errorlevel 3 goto exit_now
-if not errorlevel 1 goto done_ld
-if exist doslib.lib del doslib.lib
-lib doslib.lib +ld\dumps.obj +ld\io.obj +ld\linksyms.obj +ld\readobj.obj; >NUL
-lib doslib.lib +ld\table.obj +ld\typeconv.obj +ld\writebin.obj; >NUL
-lib doslib.lib +ld\writex86.obj; >NUL
-cl -Ml -o lib\ld.exe ld\ld.obj doslib.lib
-if errorlevel 1 goto exit_now
-if exist doslib.lib del doslib.lib
-if exist doslib.bak del doslib.bak
-:done_ld
-
-:exit_now
diff --git a/copt/Makefile b/copt/Makefile
new file mode 100644
index 0000000..9f273a3
--- /dev/null
+++ b/copt/Makefile
@@ -0,0 +1,6 @@
+
+copt: copt.c
+ $(CC) $(CFLAGS) -o copt copt.c
+
+realclean clean:
+ rm -f *.o copt
diff --git a/copt/README b/copt/README
new file mode 100644
index 0000000..2ac4453
--- /dev/null
+++ b/copt/README
@@ -0,0 +1,25 @@
+
+From gero@gkminix.han.de Thu Jan 30 19:54:34 1997
+Date: Wed, 29 Jan 1997 23:46:50 +0100 (MET)
+From: Gero Kuhlmann <gero@gkminix.han.de>
+Subject: Re: 8086 Development environment
+
+Hello again,
+
+And one hint for using the optimizer I sent you in an earlier mail: the
+order of the rules files matters! You should try:
+
+copt -c! -h"use16 386" rules.start rules.386 rules.86 rules.end
+
+If you don't want to optimize for 386 long integer operations, you
+can leave out the -h option and the rules.386 file. The rules.net file
+is only necessary for my bootrom code, and does some optimizations I
+can't do with preprocessor commands.
+
+gero.
+
+>--
+Life sucks, but it's better than the alternative.
+ - Peter da Silva
+--
+Gero Kuhlmann, Hannover 0511/6497525 (Voice) gero@gkminix.han.de
diff --git a/copt/copt.c b/copt/copt.c
new file mode 100644
index 0000000..83ee18f
--- /dev/null
+++ b/copt/copt.c
@@ -0,0 +1,826 @@
+/*
+ **************************************************************************
+ *
+ * Utility program to optimize the output of the BCC compiler
+ *
+ * Module: copt.c
+ * Purpose: Optimize BCC assembler output
+ * Entries: main
+ *
+ * This program is based on an idea from Christopher W. Fraser.
+ *
+ **************************************************************************
+ *
+ * Copyright (C) 1995,1996,1997 Gero Kuhlmann <gero@gkminix.han.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+#include "utility.h"
+#include "../../headers/general.h"
+#include "../../headers/version.h"
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <string.h>
+#include <ctype.h>
+
+#define MAXLINE 1024
+#define HASHSIZE 107
+#define NOCHAR '\177'
+#define VARNUM 10
+
+
+
+/* Struct containing each string of an input file */
+struct line_s {
+ char *text;
+ struct line_s *prev;
+ struct line_s *next;
+};
+
+
+/* Struct containing one rule */
+struct rule_s {
+ struct line_s *old;
+ struct line_s *new;
+ struct rule_s *next;
+};
+
+
+/* Hash table to store strings in a space saving way */
+struct hash_s {
+ char *text;
+ struct hash_s *next;
+};
+
+
+
+/*
+ * Global variables
+ */
+static struct rule_s *first = NULL; /* first rule */
+static struct rule_s *last = NULL; /* last rule */
+static struct line_s *infile = NULL; /* list of strings in input file */
+static struct hash_s *htab[HASHSIZE]; /* string hash table */
+static int hash_init = 0; /* flag if hash table initialized */
+static char *vars[VARNUM]; /* variable table */
+static char *progname; /* program name */
+
+
+
+/*
+ * Allocate memory and print error if none available
+ */
+static void *mymalloc(int size)
+{
+ void *p;
+
+ if ((p = malloc(size)) == NULL) {
+ fprintf(stderr, "%s: no memory\n", progname);
+ exit(1);
+ }
+ return(p);
+}
+
+
+
+/*
+ * Insert a string into the hash table. If the string is already in there
+ * just return the pointer to that string.
+ */
+static char *install(char *str, int slen)
+{
+ struct hash_s *hp;
+ char *chkstr;
+ char *cp;
+ int hashval;
+
+ /* Clear the hashing table if not already done */
+ if (!hash_init) {
+ for (hashval = 0; hashval < HASHSIZE; hashval++)
+ htab[hashval] = NULL;
+ hash_init++;
+ }
+
+ /* Get check string */
+ if (slen < 0)
+ slen = strlen(str);
+ chkstr = mymalloc(slen + 1);
+ strncpy(chkstr, str, slen);
+ chkstr[slen] = '\0';
+
+ /* Determine hashing value of string */
+ hashval = 0;
+ for (cp = chkstr; *cp; cp++)
+ hashval += *cp;
+ hashval %= HASHSIZE;
+
+ /* Check if the string is already in the hashing table */
+ for (hp = htab[hashval]; hp != NULL; hp = hp->next)
+ if (!strcmp(chkstr, hp->text)) {
+ free(chkstr);
+ return(hp->text);
+ }
+
+ /* String is not in hash table, so create a new entry */
+ hp = (struct hash_s *)mymalloc(sizeof(struct hash_s));
+ hp->text = chkstr;
+ hp->next = htab[hashval];
+ htab[hashval] = hp;
+ return(hp->text);
+}
+
+
+
+/*
+ * Read one line from input file and skip all blanks at the beginning
+ */
+static char *readline(FILE *fp)
+{
+ static char buf[MAXLINE];
+ char *cp;
+
+ /* Read line from input file */
+ if (fgets(buf, MAXLINE-1, fp) == NULL)
+ return(NULL);
+ buf[MAXLINE-1] = '\0';
+
+ /* Delete trailing newline */
+ if ((cp = strchr(buf, '\n')) != NULL)
+ *cp = '\0';
+
+ /* Delete leading white spaces */
+ for (cp = buf; *cp && isspace(*cp); cp++) ;
+ if (cp != buf && *cp)
+ strcpy(buf, cp);
+
+ return(buf);
+}
+
+
+
+/*
+ * Read a list of input lines. Terminate reading when the 'quit' character
+ * has been found in the first column of the input line. All lines with the
+ * 'comment' character in the first position will be skipped.
+ */
+static struct line_s *readlist(FILE *fp, char quit, char comment)
+{
+ struct line_s *lp;
+ struct line_s *first_line = NULL;
+ struct line_s *last_line = NULL;
+ char *cp;
+
+ while ((cp = readline(fp)) != NULL) {
+ if (quit != NOCHAR && quit == *cp)
+ break;
+ if (comment != NOCHAR && comment == *cp)
+ continue;
+ if (*cp == '\0')
+ continue;
+ lp = mymalloc(sizeof(struct line_s));
+ lp->text = install(cp, -1);
+ lp->prev = last_line;
+ lp->next = NULL;
+ if (first_line == NULL)
+ first_line = lp;
+ if (last_line != NULL)
+ last_line->next = lp;
+ last_line = lp;
+ }
+ return(first_line);
+}
+
+
+
+/*
+ * Read pattern file
+ */
+static void readpattern(char *rulesdir, char *filename)
+{
+ static char path[MAXLINE];
+ struct rule_s *rp;
+ FILE *fp;
+
+ /* Open pattern file */
+ if (rulesdir != NULL)
+ sprintf(path, "%s/%s", rulesdir, filename);
+ else
+ sprintf(path, "%s", filename);
+ if ((fp = fopen(path, "r")) == NULL) {
+ fprintf(stderr, "%s: can't open pattern file %s\n", progname, path);
+ exit(1);
+ }
+
+ /* Read every line of the pattern file */
+ while (!feof(fp)) {
+ rp = (struct rule_s *)mymalloc(sizeof(struct rule_s));
+ rp->old = readlist(fp, '=', '#');
+ rp->new = readlist(fp, '\0', '#');
+ rp->next = first;
+ if (rp->old == NULL || rp->new == NULL) {
+ free(rp);
+ break;
+ }
+ first = rp;
+ if (last == NULL)
+ last = rp;
+ }
+
+ /* Close pattern file */
+ (void)fclose(fp);
+}
+
+
+
+/*
+ * Clear pattern list to allow for another run
+ */
+static void clearpattern(void)
+{
+ struct rule_s *rp1, *rp2;
+ struct line_s *lp1, *lp2;
+
+ rp1 = first;
+ while (rp1 != NULL) {
+ /* Clear old rule text list */
+ lp1 = rp1->old;
+ while (lp1 != NULL) {
+ lp2 = lp1;
+ lp1 = lp1->next;
+ free(lp2);
+ }
+ /* Clear new rule text list */
+ lp1 = rp1->new;
+ while (lp1 != NULL) {
+ lp2 = lp1;
+ lp1 = lp1->next;
+ free(lp2);
+ }
+ /* Clear rule itself */
+ rp2 = rp1;
+ rp1 = rp1->next;
+ free(rp2);
+ }
+
+ first = NULL;
+ last = NULL;
+}
+
+
+
+/*
+ * Read input file
+ */
+static void readinfile(char *filename, char comment)
+{
+ FILE *fp;
+
+ fp = stdin;
+ if (filename != NULL && (fp = fopen(filename, "r")) == NULL) {
+ fprintf(stderr, "%s: can't open input file %s\n", progname, filename);
+ exit(1);
+ }
+ infile = readlist(fp, NOCHAR, comment);
+ if (fp != stdin)
+ (void)fclose(fp);
+}
+
+
+
+/*
+ * Eval an expression into an integer number
+ */
+static long eval(char *str, int len)
+{
+#define NO_OP 0
+#define ADD_OP 1
+#define SUB_OP 2
+#define MUL_OP 3
+#define DIV_OP 4
+#define SHL_OP 5
+#define SHR_OP 6
+
+ char *oldcp, *cp, c;
+ long retval = 0;
+ long num = 0;
+ int sign = 1;
+ int base = 10;
+ int state = 0;
+ int op = NO_OP;
+ int i, varnum;
+
+ /* Apply operation to current numeric value */
+ static void doretval(void)
+ {
+ switch (op) {
+ case NO_OP: retval = num * sign;
+ break;
+ case ADD_OP: retval += num * sign;
+ break;
+ case SUB_OP: retval -= num * sign;
+ break;
+ case MUL_OP: retval *= num * sign;
+ break;
+ case DIV_OP: retval /= num * sign;
+ break;
+ case SHL_OP: retval <<= num;
+ break;
+ case SHR_OP: retval >>= num;
+ break;
+ }
+ op = NO_OP;
+ num = 0;
+ sign = 1;
+ base = 10;
+ }
+
+ /* Scan through whole string and decode it */
+ for (cp = str, i = 0; *cp && i < len; cp++, i++) {
+ c = toupper(*cp);
+ if (c == '-' && (state == 0 || state == 5)) {
+ state = 1;
+ sign = -1;
+ } else if (c == '+' && (state == 0 || state == 5)) {
+ state = 1;
+ sign = 1;
+ } else if (c == '%' && isdigit(*(cp + 1)) && (state < 2 || state == 5)) {
+ state = 4;
+ varnum = *(cp + 1) - '0';
+ if (vars[varnum] == NULL || i >= len)
+ return(0);
+ num = eval(vars[varnum], strlen(vars[varnum]));
+ doretval();
+ cp++; i++;
+ } else if (c == '$' && (state < 2 || state == 5)) {
+ state = 2;
+ base = 16;
+ } else if (base == 10 && (c >= '0' && c <= '9') &&
+ (state <= 3 || state == 5)) {
+ state = 3;
+ num = num * 10 + (c - '0');
+ } else if (base == 16 &&
+ ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) &&
+ (state <= 3 || state == 5)) {
+ state = 3;
+ num = num * 16 + (c >= 'A' ? c - '0' - 7 : c - '0');
+ } else if (c == ' ' && (state == 3 || state == 4 || state == 5)) {
+ if (state == 3) {
+ doretval();
+ state = 4;
+ }
+ } else if (strchr("+-*/<>", c) != NULL && (state == 3 || state == 4)) {
+ if (state == 3)
+ doretval();
+ state = 5;
+ switch (c) {
+ case '+': op = ADD_OP;
+ break;
+ case '-': op = SUB_OP;
+ break;
+ case '*': op = MUL_OP;
+ break;
+ case '/': op = DIV_OP;
+ break;
+ case '<': op = SHL_OP;
+ break;
+ case '>': op = SHR_OP;
+ break;
+ }
+ } else
+ return(0);
+ }
+
+ /* Check if the string has been terminated correctly */
+ if (state != 3 && state != 4)
+ return(0);
+ if (state == 3)
+ doretval();
+ return(retval);
+}
+
+
+
+/*
+ * Compare an infile string with a pattern string. If there is any variable
+ * defined, it will be inserted into the variable list from the pattern
+ * string.
+ */
+static int match(char *ins, char *pat)
+{
+ char *cp, *oldpat;
+ long val;
+ int varnum;
+ int len;
+
+ while (*ins && *pat)
+ if (pat[0] == '%' && pat[1] == '%') {
+ /* '%%' actually means '%' */
+ if (*ins != '%')
+ return(0);
+ pat += 2;
+ } else if (pat[0] == '%' && (pat[1] == '*' || isdigit(pat[1]))) {
+ /* Copy variable text into vars array */
+ pat += 2;
+ for (cp = ins; *ins && !match(ins, pat); ins++) ;
+ if (pat[-1] == '*')
+ continue;
+ len = ins - cp;
+ varnum = pat[-1] - '0';
+ if (vars[varnum] == NULL)
+ vars[varnum] = install(cp, len);
+ else if (strlen(vars[varnum]) != len ||
+ strncmp(vars[varnum], cp, len))
+ return(0);
+ } else if (pat[0] == '%' && pat[1] == '[') {
+ /* Copy only specific variable text into vars array */
+ if ((cp = strchr(pat + 2, ']')) == NULL ||
+ (*(cp + 1) != '*' && !isdigit(*(cp + 1)))) {
+ if (*ins != '[')
+ return(0);
+ pat += 2;
+ continue;
+ }
+ oldpat = pat + 1;
+ pat = cp + 2;
+ /* Seperate allowable patterns and compare them with ins */
+ while (*oldpat && *oldpat != ']') {
+ oldpat++;
+ len = strcspn(oldpat, "|]");
+ if (!strncmp(ins, oldpat, len))
+ break;
+ oldpat += len;
+ }
+ if (!*oldpat || *oldpat == ']')
+ return(0);
+ ins += len;
+ if (!match(ins, pat))
+ return(0);
+ /* Install new string into variable table */
+ if (*(cp + 1) == '*')
+ continue;
+ varnum = *(cp + 1) - '0';
+ if (vars[varnum] == NULL)
+ vars[varnum] = install(oldpat, len);
+ else if (strlen(vars[varnum]) != len ||
+ strncmp(vars[varnum], oldpat, len))
+ return(0);
+ } else if (pat[0] == '%' && pat[1] == '!') {
+ /* Match only if the pattern string is not found */
+ if (pat[2] != '[' || (cp = strchr(pat + 3, ']')) == NULL) {
+ if (*ins != '!')
+ return(0);
+ pat += 3;
+ continue;
+ }
+ oldpat = pat + 2;
+ pat = cp + 1;
+ /* Seperate allowable patterns and compare them with ins */
+ while (*oldpat && *oldpat != ']') {
+ oldpat++;
+ len = strcspn(oldpat, "|]");
+ if (!strncmp(ins, oldpat, len))
+ return(0);
+ oldpat += len;
+ }
+ } else if (pat[0] == '%' && pat[1] == '(') {
+ /* Match ins with expression */
+ if ((cp = strchr(pat + 2, ')')) == NULL) {
+ if (*ins != '(')
+ return(0);
+ pat += 2;
+ continue;
+ }
+ oldpat = pat + 2;
+ pat = cp + 1;
+ len = cp - oldpat;
+ val = eval(oldpat, len);
+ for (cp = ins; *ins && !match(ins, pat); ins++) ;
+ len = ins - cp;
+ if (val != eval(cp, len))
+ return(0);
+ } else if (*pat++ != *ins++)
+ return(0);
+
+ return(*ins == *pat);
+}
+
+
+
+/*
+ * Substitute variables in a string
+ */
+static char *subst(char *pat)
+{
+ char buf[MAXLINE];
+ char *cp, *cp1, *cp2, *varptr;
+ long num;
+ int i = 0;
+ int j, pos;
+
+ while (*pat)
+ if (pat[0] == '%' && isdigit(pat[1])) {
+ /* Substitute with value of variable */
+ cp = vars[pat[1] - '0'];
+ while (cp != NULL && *cp) {
+ buf[i++] = *cp++;
+ if (i >= MAXLINE - 1) {
+ fprintf(stderr, "%s: line too long\n", progname);
+ exit(1);
+ }
+ }
+ pat += 2;
+ } else if (pat[0] == '%' && pat[1] == '(') {
+ /* Substitute with expression */
+ cp = pat + 2;
+ if ((pat = strchr(cp, ')')) == NULL || pat - cp <= 0)
+ num = 0;
+ else
+ num = eval(cp, pat - cp);
+ if (i >= MAXLINE - 20) {
+ fprintf(stderr, "%s: line too long\n", progname);
+ exit(1);
+ }
+ i += sprintf(&buf[i], "%s$%lx", num < 0 ? "-" : "", labs(num));
+ pat++;
+ } else if (pat[0] == '%' && pat[1] == '=') {
+ /* Substitute with converted variable */
+ /* First seperate all parts of the pattern string */
+ cp = pat + 2;
+ cp1 = cp2 = varptr = NULL;
+ if (*cp == '[') {
+ cp1 = ++cp;
+ while (*cp && *cp != ']')
+ cp++;
+ if (cp[0] == ']' && cp[1] == '[') {
+ cp += 2;
+ cp2 = cp;
+ while (*cp && *cp != ']')
+ cp++;
+ if (cp[0] == ']' && isdigit(cp[1]))
+ varptr = vars[cp[1] - '0'];
+ }
+ }
+ if (cp1 == NULL || cp2 == NULL || varptr == NULL) {
+ buf[i++] = *pat++;
+ if (i >= MAXLINE - 1) {
+ fprintf(stderr, "%s: line too long\n", progname);
+ exit(1);
+ }
+ continue;
+ }
+ pat = cp + 2;
+ /* Now scan through the first string to find variable value */
+ cp1--;
+ pos = 0;
+ while (*cp1 != ']') {
+ cp1++;
+ j = strcspn(cp1, "|]");
+ if (strlen(varptr) == j && !strncmp(cp1, varptr, j))
+ break;
+ pos++;
+ cp1 += j;
+ }
+ if (*cp1 == ']')
+ continue;
+ /* Scan through the second string to find the conversion */
+ cp2--;
+ while (*cp2 != ']' && pos > 0) {
+ cp2++;
+ j = strcspn(cp2, "|]");
+ pos--;
+ cp2 += j;
+ }
+ if (*cp2 == ']' || pos != 0)
+ continue;
+ /* Insert conversion string into destination */
+ cp2++;
+ while (*cp2 != '|' && *cp2 != ']') {
+ buf[i++] = *cp2++;
+ if (i >= MAXLINE - 1) {
+ fprintf(stderr, "%s: line too long\n", progname);
+ exit(1);
+ }
+ }
+ } else {
+ buf[i++] = *pat++;
+ if (i >= MAXLINE - 1) {
+ fprintf(stderr, "%s: line too long\n", progname);
+ exit(1);
+ }
+ }
+
+ buf[i] = '\0';
+ return(install(buf, i));
+}
+
+
+
+/*
+ * Optimize one line of the input file
+ */
+static struct line_s *optline(struct line_s *cur)
+{
+ struct rule_s *rp;
+ struct line_s *ins, *pat;
+ struct line_s *lp1, *lp2;
+ int i;
+
+ for (rp = first; rp != NULL; rp = rp->next) {
+ /* Clear variable array */
+ for (i = 0; i < VARNUM; i++)
+ vars[i] = NULL;
+
+ /* Scan through pattern texts and match them against the input file */
+ ins = cur;
+ pat = rp->old;
+ while (ins != NULL && pat != NULL && match(ins->text, pat->text)) {
+ ins = ins->next;
+ pat = pat->next;
+ }
+
+ /* Current pattern matched input line, so replace input with new */
+ if (pat == NULL) {
+ /* Clear all lines in the source file for this pattern */
+ lp1 = cur;
+ cur = cur->prev;
+ while (lp1 != ins) {
+ lp2 = lp1;
+ lp1 = lp1->next;
+ free(lp2);
+ }
+ /* Insert new lines into list */
+ pat = rp->new;
+ lp1 = cur;
+ lp2 = NULL;
+ while (pat != NULL) {
+ lp2 = mymalloc(sizeof(struct line_s));
+ lp2->text = subst(pat->text);
+ lp2->next = NULL;
+ lp2->prev = lp1;
+ if (lp1 != NULL)
+ lp1->next = lp2;
+ else
+ infile = lp2;
+ lp1 = lp2;
+ pat = pat->next;
+ }
+ if (ins != NULL)
+ ins->prev = lp2;
+ if (lp2 != NULL)
+ lp2->next = ins;
+ else if (lp1 != NULL)
+ lp1->next = NULL;
+ else
+ infile = NULL;
+ return(cur);
+ }
+ }
+ return(cur->next);
+}
+
+
+
+/*
+ * Actually optimize all strings in the input file
+ */
+static void optimize(int backup)
+{
+ struct line_s *cur, *lp;
+ int i;
+
+ /* Scan through all lines in the input file */
+ cur = infile;
+ while (cur != NULL) {
+ if ((lp = optline(cur)) != NULL && lp != cur->next) {
+ for (i = 0; i < backup && lp != NULL; i++)
+ lp = lp->prev;
+ if (lp == NULL)
+ lp = infile;
+ }
+ cur = lp;
+ }
+}
+
+
+
+/*
+ * Write out into destination file
+ */
+static void writeoutf(char *filename, char *headstr)
+{
+ FILE *fp;
+ struct line_s *lp;
+
+ fp = stdout;
+ if (filename != NULL && (fp = fopen(filename, "w")) == NULL) {
+ fprintf(stderr, "%s: can't open output file %s\n", progname, filename);
+ exit(1);
+ }
+ if (headstr != NULL) {
+ fprintf(fp, headstr);
+ fprintf(fp, "\n");
+ }
+ for (lp = infile; lp != NULL; lp = lp->next)
+ fprintf(fp, "%s\n", lp->text);
+ if (fp != stdout)
+ (void)fclose(fp);
+}
+
+
+
+/*
+ * Print usage
+ */
+static void usage(void)
+{
+ fprintf(stderr, "usage: %s [-c<comment-char>] [-f<src-file>] [-o<out-file>]\n"
+ "\t\t[-b<backup-num>] [-h<head-str>] [-d<ruls-dir>] "
+ "<rules-file> ...\n", progname);
+ exit(1);
+}
+
+
+
+/*
+ * Main program
+ */
+void main(int argc, char **argv)
+{
+ char comment = NOCHAR;
+ char *srcfile = NULL;
+ char *outfile = NULL;
+ char *headstr = NULL;
+ char *rulesdir = NULL;
+ int backup = 0;
+ int i;
+
+ /* Get program name */
+ if ((progname = strrchr(argv[0], '/')) == NULL)
+ progname = argv[0];
+ else
+ progname++;
+
+ /* Make life easy for bcc */
+ if ( argc > 4 && strcmp(argv[2], "-o") == 0 && argv[1][0] != '-' )
+ {
+ srcfile = argv[1];
+ argv++,argc--;
+ }
+
+ /* Get options from command line */
+ for (i = 1; i < argc; i++)
+ if (!strncmp(argv[i], "-c", 2))
+ comment = argv[i][2];
+ else if (!strncmp(argv[i], "-b", 2))
+ backup = atoi(&(argv[i][3]));
+ else if (!strncmp(argv[i], "-f", 2))
+ srcfile = &(argv[i][2]);
+ else if (!strncmp(argv[i], "-o", 2))
+ {
+ if(argv[i][2])
+ outfile = &(argv[i][2]);
+ else if(++i<argc)
+ outfile = argv[i];
+ else
+ usage();
+ }
+ else if (!strncmp(argv[i], "-h", 2))
+ headstr = &(argv[i][2]);
+ else if (!strncmp(argv[i], "-d", 2))
+ rulesdir = &(argv[i][2]);
+ else if (argv[i][0] == '-')
+ usage();
+ else
+ break;
+
+ /* Have to have enough parameters for rule file names */
+ if ((argc - i) < 1)
+ usage();
+
+ /* Read source file and optimze it with every rules file */
+ readinfile(srcfile, comment);
+ for ( ; i < argc; i++) {
+ readpattern(rulesdir, argv[i]);
+ optimize(backup);
+ clearpattern();
+ }
+ writeoutf(outfile, headstr);
+}
+
diff --git a/copt/rules.386 b/copt/rules.386
new file mode 100644
index 0000000..c2d07d7
--- /dev/null
+++ b/copt/rules.386
@@ -0,0 +1,427 @@
+# Rules to optimize BCC assembler output for 386
+
+# Rules for loading a long constant
+
+xor ax,ax
+xor %[bx|si|di]1,%[bx|si|di]1
+=
+xor eax,eax
+
+xor eax,eax
+mov %[ebx|ecx|edx]1,eax
+=
+xor %1,%1
+
+xor ax,ax
+mov %[bx|si|di]*,%[*|#]0%1
+=
+mov eax,%0%1<<16
+
+mov ax,%[*|#]0%1
+xor %[bx|si|di]2,%[bx|si|di]2
+=
+mov eax,%0%1 & $0000FFFF
+
+mov ax,%0[%1]
+xor %[bx|si|di]2,%[bx|si|di]2
+=
+movzx eax,word ptr %0[%1]
+
+mov ax,%[si|di]1
+xor bx,bx
+=
+movzx eax,%1
+
+%[movzx|movsx]5 eax,%1
+mov %[ebx|ecx|edx]2,eax
+=
+%5 %2,%1
+
+%[movzx|movsx]5 %[ebx|ecx|edx]1,%2
+mov eax,%[#|*]0%3
+%[add|and|xor|or]4 eax,%[ebx|ecx|edx]1
+=
+%5 eax,%2
+%4 eax,%0%3
+
+mov ax,%0[%1]
+cwde
+=
+movsx eax,word ptr %0[%1]
+
+mov ax,%[si|di]1
+cwde
+=
+movsx eax,%1
+
+mov ax,%[#|*]3%1
+mov %[bx|si|di]*,%[#|*]4%2
+=
+mov eax,%4%2<<16 + %1
+
+
+# Rules for pushing variables and constants onto the stack
+
+push %![dword ptr]%1[%[bx|si|di|bp]3]
+push %![dword ptr]%(%1-2)[%[bx|si|di|bp]3]
+=
+push dword ptr %(%1-2)[%3]
+
+push [%1+2]
+push [%1]
+=
+push dword ptr [%1]
+
+push %[bx|si|di]*
+push ax
+=
+push eax
+
+mov eax,%[#|*]0%1
+push eax
+=
+push dword %0%1
+
+mov %1,%[eax|ebx|ecx|edx]2
+push dword ptr %1
+=
+mov %1,%2
+push %2
+
+
+# Rules for loading long variables
+
+mov ax,[%1]
+mov %[bx|si|di]*,[%1+2]
+=
+mov eax,[%1]
+
+mov ax,%1[%[bx|si|di|bp]3]
+mov %[bx|si|di]*,%(%1+2)[%[bx|si|di|bp]3]
+=
+mov eax,%1[%3]
+
+mov ax,#%1[bx]
+mov %[bx|si|di]*,#%1+2[bx]
+=
+mov eax,#%1[bx]
+
+mov [%1],ax
+mov [%1+2],%[bx|si|di]*
+=
+mov [%1],eax
+
+mov [%1+%3],ax
+mov [%1+%(%3+2)],%[bx|si|di]*
+=
+mov [%1+%3],eax
+
+mov %1[%[si|di|bp]3],ax
+mov %(%1+2)[%[si|di|bp]3],%[bx|si|di]*
+=
+mov %1[%3],eax
+
+mov #%1[bx],ax
+mov #%1+2[bx],%[bx|si|di]*
+=
+mov #%1[bx],eax
+
+mov eax,%[#|*]0%1
+mov %![dword ptr]%3[%2],eax
+=
+mov dword ptr %3[%2],%0%1
+
+xor ax,ax
+xor %[bx|si|di]3,%[bx|si|di]3
+mov %1[%[bx|bp]4],ax
+mov %(%1+2)[%[bx|bp]4],%[bx|si|di]3
+=
+mov dword ptr %1[%4],#0
+
+mov ax,%1
+mov %[bx|si|di]5,%2
+mov %3[%[bx|bp]6],ax
+mov %(%3+2)[%[bx|bp]6],%[bx|si|di]5
+=
+mov eax,dword ptr %1
+mov dword ptr %3[%6],eax
+
+
+# Long return values are in EAX, so we can skip dx
+
+mov dx,bx
+add sp,*%1
+=
+add sp,*%1
+
+
+# Rules for manipulating long values
+
+call %1
+mov bx,dx
+=
+call %1
+
+call l%[tstu|tst]*l
+=
+test eax,eax
+
+call l%[comu|com]*l
+=
+not eax
+
+mov eax,eax
+%1
+=
+%1
+
+mov %2,%[eax|ebx|ecx|edx]1
+mov %[eax|ebx|ecx|edx]1,%2
+=
+mov %2,%1
+
+cwd
+mov bx,dx
+=
+cwde
+
+mov %[ebx|ecx|edx]0,%1
+mov eax,%2
+%3 eax,%[ebc|ecx|edx]0
+=
+mov eax,%2
+%3 eax,%1
+
+%[movzx|movsx|mov]0 %[eax|ebx|ecx|edx]2,%4
+%[add|and|xor|sub|or]1 %[eax|ebx|ecx|edx]2,%6
+mov %6,%[eax|ebx|ecx|edx]2
+=
+%0 %2,%4
+%1 %6,%2
+
+mov eax,%[#|*]0%1
+cmp eax,%2
+%[jbe |jae |jne |jge |jle ]3 %4
+=
+cmp dword ptr %2,%0%1
+%=[jbe |jae |jne |jge |jle ][jae |jbe |jne |jle |jge ]3 %4
+
+mov eax,%[#|*]0%1
+cmp eax,%2
+%[jb |ja |je |jg |jl ]3 %4
+=
+cmp dword ptr %2,%0%1
+%=[jb |ja |je |jg |jl ][ja |jb |je |jl |jg ]3 %4
+
+mov eax,%1[%3]
+cmp eax,dword %[#|*]0%2
+=
+cmp dword ptr %1[%3],%0%2
+
+
+# Rules for calling the bcc library routines.
+
+push %1
+push %2
+mov eax,%3[bp]
+%4 eax,%(%3-4)[bp]
+add sp,*8
+=
+mov edx,%2
+mov eax,%1
+%4 eax,edx
+
+push %1
+mov eax,%2
+push eax
+mov eax,%3[bp]
+%4 eax,%(%3-4)[bp]
+add sp,*8
+=
+mov edx,%2
+mov eax,%1
+%4 eax,edx
+
+push %1
+xor eax,eax
+push eax
+mov eax,%2[bp]
+%3 eax,%(%2-4)[bp]
+add sp,*8
+=
+mov eax,%1
+%3 eax,#0
+
+push %1
+mov eax,%2
+%3 eax,%4[bp]
+add sp,*4
+=
+mov edx,%1
+mov eax,%2
+%3 eax,edx
+
+push %1
+mov eax,%2
+%3 eax,%4[bp]
+mov %2,eax
+add sp,*4
+=
+mov edx,%1
+%3 %2,edx
+
+
+push %1
+push %2
+mov eax,%3[bp]
+%4 eax,%(%3-4)[bp]
+lea sp,%(%3+4)[bp]
+=
+mov edx,%2
+mov eax,%1
+%4 eax,edx
+
+push %1
+mov eax,%2
+push eax
+mov eax,%3[bp]
+%4 eax,%(%3-4)[bp]
+lea sp,%(%3+4)[bp]
+=
+mov edx,%2
+mov eax,%1
+%4 eax,edx
+
+push %1
+xor eax,eax
+push eax
+mov eax,%2[bp]
+%3 eax,%(%2-4)[bp]
+lea sp,%(%2+4)[bp]
+=
+mov eax,%1
+%3 eax,#0
+
+push %1
+mov eax,%2
+%3 eax,%4[bp]
+lea sp,%(%4+4)[bp]
+=
+mov edx,%1
+mov eax,%2
+%3 eax,edx
+
+
+# Rules for calling the basic bcc library routines.
+
+mov di,#%2
+call l%3%[ul|l]*
+=
+%3 eax,[%2]
+
+lea di,%2
+call l%3%[ul|l]*
+=
+%3 eax,%2
+
+mov di,%[si|di]1
+call l%3%[ul|l]*
+=
+%3 eax,[%1]
+
+mov di,%[ax|bx|cx|dx]1
+call l%3%[ul|l]*
+=
+mov di,%[ax|bx|cx|dx]1
+%3 eax,[di]
+
+
+# Rules for pushing short values
+
+mov %[ax|bx|cx|dx|si|di]2,%0[%1]
+push %[ax|bx|cx|dx|si|di]2
+=
+push word ptr %0[%1]
+
+mov %[ax|bx|cx|dx|si|di]2,%[#|*]0%1
+push %[ax|bx|cx|dx|si|di]2
+=
+push word %0%1
+
+
+# Shifting rules
+
+%[shl|shr]2 %1,*1
+%[shl|shr]2 %1,*1
+=
+%2 %1,*2
+
+mov cl,*%1
+%[shl|shr]2 %3,cl
+=
+%2 %3,*%1
+
+mov dx,ax
+shl ax,*%1
+add ax,dx
+shl ax,*%2
+=
+mov dx,ax
+imul ax,*%(1<%1+1<%2)
+
+mov dx,ax
+imul ax,*%1
+add ax,dx
+=
+mov dx,ax
+imul ax,*%(%1+1)
+
+mov dx,ax
+imul ax,*%1
+shl ax,*%2
+=
+mov dx,ax
+imul ax,*%(%1<%2)
+
+mov ax,%![#|*]%4
+mov dx,ax
+imul ax,*%1
+%[add|and|xor|sub|or]2 ax,%![dx]%3
+=
+imul ax,%4,*%1
+%2 ax,%3
+
+mov ax,%![#|*]%4
+mov dx,ax
+imul ax,*%1
+push ax
+=
+imul ax,%4,*%1
+push ax
+
+imul ax,%2,%[#|*]0%1
+add ax,%3
+mov bx,ax
+=
+imul bx,%2,%0%1
+add bx,%3
+
+
+# Different rules
+
+%1 dword ptr %[eax|ebx|ecx|edx]3,*%2
+=
+%1 %3,*%2
+
+%1 dword ptr %[eax|ebx|ecx|edx]3,#%2
+=
+%1 %3,#%2
+
+eor %1,%2
+=
+xor %1,%2
+
+com %1
+=
+not %1
+
diff --git a/copt/rules.86 b/copt/rules.86
new file mode 100644
index 0000000..d4fe131
--- /dev/null
+++ b/copt/rules.86
@@ -0,0 +1,427 @@
+# Rules for optimizing BCC assembler output
+
+# Rules for loading short variables
+
+# Chad says this one (I think) is broken
+# mov %0$0[%2],%3
+# =
+# mov %0[%2],%3
+
+mov %2,%[ax|bx|cx|dx]1
+mov %[ax|bx|cx|dx]1,%2
+=
+mov %2,%1
+
+mov %[ax|bx|cx|dx]3,%[#|*]0%1
+mov %2[%4],%[ax|bx|cx|dx]3
+=
+mov word ptr %2[%4],%0%1
+
+mov %[ax|bx|cx|dx]3,%[#|*]0%1
+mov %[ax|bx|cx|dx]2,%[ax|bx|cx|dx]3
+=
+mov %2,%0%1
+
+mov al,%[#|*]0%1
+mov %2,al
+=
+mov byte ptr %2,%0%1
+
+xor ax,ax
+mov bx,%[#|*]0%1
+mov [%2],ax
+mov [%2+2],bx
+=
+mov word ptr [%2],#0
+mov word ptr [%2+2],%0%1
+
+mov ax,%[#|*]0%1
+xor bx,bx
+mov [%2],ax
+mov [%2+2],bx
+=
+mov word ptr [%2],%0%1
+mov word ptr [%2+2],#0
+
+mov ax,%[#|*]4%1
+mov bx,%[#|*]5%3
+mov [%2],ax
+mov [%2+2],bx
+=
+mov word ptr [%2],%4%1
+mov word ptr [%2+2],%5%3
+
+
+# Rules for incrementing short variables
+
+mov %[ax|bx]2,%1
+%[inc|dec]3 %[ax|bx]2
+mov %1,%[ax|bx]2
+=
+%3 word ptr %1
+mov %2,%1
+
+
+# Rules for manipulating characters
+
+inc %[si|di]*
+inc %[si|di]*
+mov al,-1[si]
+mov -1[di],al
+=
+cld
+lodsb
+stosb
+
+inc %[si|di]*
+inc %[si|di]*
+mov al,-1[di]
+mov -1[si],al
+=
+cld
+xchg si,di
+lodsb
+stosb
+xchg si,di
+
+inc si
+mov al,-1[si]
+=
+cld
+lodsb
+
+inc di
+mov -1[di],al
+=
+cld
+stosb
+
+dec %[si|di]*
+dec %[si|di]*
+mov al,1[si]
+mov 1[di],al
+=
+std
+lodsb
+stosb
+
+dec %[si|di]*
+dec %[si|di]*
+mov al,1[di]
+mov 1[si],al
+=
+std
+xchg si,di
+lodsb
+stosb
+xchg si,di
+
+dec si
+mov al,1[si]
+=
+std
+lodsb
+
+dec di
+mov 1[di],al
+=
+std
+stosb
+
+
+# Rules for manipulating short values
+
+mov %[ax|bx]2,%1
+%[add|and|xor|sub|or]4 %[ax|bx]2,%3
+mov %1,%[ax|bx]2
+=
+mov %2,%3
+%4 %1,%2
+
+mov %[ax|bx]2,%1
+%[add|and|xor|or]4 %[ax|bx]2,%3
+mov %3,%[ax|bx]2
+=
+mov %2,%1
+%4 %3,%2
+
+mov %[ax|bx]4,%1
+%[add|and|xor|sub|or]2 %[si|di]3,%[ax|bx]4
+=
+%2 %3,%1
+
+mov al,%1
+xor ah,ah
+%[add|and|xor|sub|or]2 ax,%[#|*]0%3
+mov %1,al
+=
+%2 byte ptr %1,%0%3
+
+
+# Rules for comparing short values
+
+mov %[ax|bx]3,%1[%4]
+cmp %[ax|bx]3,%[#|*]0%2
+=
+cmp word ptr %1[%4],%0%2
+
+mov al,%1[%4]
+cmp al,%[#|*]0%2
+=
+cmp byte ptr %1[%4],%0%2
+
+mov %[ax|bx]3,%[ax|bx|cx|dx|si|di]2
+cmp %[ax|bx]3,%1
+=
+cmp %2,%1
+
+
+# General comparison rules
+
+xor %1,%1
+mov %2,%3
+cmp %2,%1
+=
+mov %2,%3
+cmp %2,#0
+
+mov %1,%[#|*]0%2
+mov %3,%4
+cmp %3,%1
+=
+mov %3,%4
+cmp %3,%0%2
+
+mov %1,%2
+cmp %1,%[#|*]00
+%[jne |je ]4 %3
+=
+mov %1,%2
+test %1,%1
+%4 %3
+
+%[and|xor|or]1 %2,%3
+test %2,%2
+=
+%1 %2,%3
+
+
+# General incrementation and decrementation rules
+
+inc %3 ptr %1
+mov %2,%1
+dec %2
+=
+mov %2,%1
+inc %3 ptr %1
+
+dec %3 ptr %1
+mov %2,%1
+inc %2
+=
+mov %2,%1
+dec %3 ptr %1
+
+mov %1,%2
+inc %3 ptr %2
+push %1
+=
+push %3 ptr %2
+inc %3 ptr %2
+
+mov %1,%2
+dec %3 ptr %2
+push %1
+=
+push %3 ptr %2
+dec %3 ptr %2
+
+
+# Misc. rules
+
+push word %[#|*]0%1
+inc %[si|di]2
+inc %[si|di]2
+mov %[ax|bx|cx|dx]3,%*[bp]
+mov %4[%[si|di]2],%[ax|bx|cx|dx]3
+inc sp
+inc sp
+=
+mov word ptr %(%4+2)[%2],%0%1
+inc %2
+inc %2
+
+push %1
+mov %[ax|bx|cx|dx]3,%2
+%[add|sub|and|xor|or]4 %[ax|bx|cx|dx]3,%*[bp]
+inc sp
+inc sp
+=
+mov %3,%2
+%4 %3,%1
+
+push %1
+mov %[ax|bx|cx|dx]3,%2
+%[add|sub|and|xor|or]5 %[ax|bx|cx|dx]3,%6
+%[add|sub|and|xor|or]4 %[ax|dx|cx|dx]3,%*[bp]
+inc sp
+inc sp
+=
+mov %3,%2
+%5 %3,%6
+%4 %3,%1
+
+push %1
+mov %[ax|bx|cx|dx]3,%*[bp]
+%[add|sub|and|xor|or]4 %2,%[ax|bx|cx|dx]3
+inc sp
+inc sp
+=
+mov %3,%1
+%4 %2,%3
+
+mov %1,%[ax|bx|cx|dx]2
+push %1
+=
+mov %1,%2
+push %2
+
+
+# Rules to remove superflous mov instructions
+
+mov %1,%2
+mov %1,%2
+=
+mov %1,%2
+
+mov %1,%2
+.%3:
+mov %1,%2
+=
+.%3:
+mov %1,%2
+
+mov %1,%2
+mov %2,%1
+=
+mov %1,%2
+
+mov %1,%[ax|bx|cx|dx|eax|ebx|ecx|edx]2
+mov %[ax|bx|cx|dx|eax|ebx|ecx|edx]3,%1
+=
+mov %1,%2
+mov %3,%2
+
+mov %1,%1
+=
+!mov %1,%1
+
+# Sometimes the compiler puts a jump right after a ret or another jump
+# (in if-else-if constructions). Eliminate the second unnecessary jump.
+# Also it puts a jump to the next instruction in extensive if-else
+# constructions. That jump can also be removed.
+
+jmp .%1
+jmp .%2
+=
+jmp %1
+
+ret
+jmp %2
+=
+ret
+
+jmp .%1
+.%1:
+=
+.%1
+
+jmp .%1
+.%2:
+.%1:
+=
+.%2:
+.%1:
+
+jmp .%1
+.%3:
+.%2:
+.%1:
+=
+.%3:
+.%2:
+.%1:
+
+
+# When using register variables the compiler initializes them when
+# they are found in the source code, and sets up the stack frame for
+# other local variables lateron. Move initialization of register variables
+# behind the add-sp instruction to make further optimization easier.
+
+proc_start
+mov %[si|di]3,%1
+add sp,*%2
+=
+proc_start
+add sp,*%2
+mov %3,%1
+
+proc_start
+mov %[si|di]3,%1
+dec sp
+dec sp
+=
+proc_start
+dec sp
+dec sp
+mov %3,%1
+
+add sp,*%1
+add sp,*%2
+=
+add sp,*%1+%2
+
+dec sp
+dec sp
+add sp,*%1
+=
+add sp,*%1-2
+
+add sp,*%1
+dec sp
+dec sp
+=
+add sp,*%1-2
+
+inc sp
+inc sp
+%1 %2
+inc sp
+inc sp
+=
+%1 %2
+add sp,*4
+
+inc sp
+inc sp
+%1 %2
+add sp,*%3
+=
+%1 %2
+add sp,*%3+2
+
+add sp,*%3
+%1 %2
+inc sp
+inc sp
+=
+%1 %2
+add sp,*%3+2
+
+add sp,*%3
+%1 %2
+add sp,*%4
+=
+%1 %2
+add sp,*%3+%4
+
diff --git a/copt/rules.end b/copt/rules.end
new file mode 100644
index 0000000..cd93d4e
--- /dev/null
+++ b/copt/rules.end
@@ -0,0 +1,18 @@
+# Rules to optimize BCC assembler output
+
+# Redo the changes done in rules.start
+
+proc_start
+=
+push bp
+mov bp,sp
+push di
+push si
+
+proc_end
+=
+pop si
+pop di
+pop bp
+ret
+
diff --git a/copt/rules.inl b/copt/rules.inl
new file mode 100644
index 0000000..8a3e218
--- /dev/null
+++ b/copt/rules.inl
@@ -0,0 +1,8 @@
+
+mov ax,%1
+mov bx,%2
+call isr
+=
+mov ax,%1
+mov cx,%2
+sar ax,cl
diff --git a/copt/rules.net b/copt/rules.net
new file mode 100644
index 0000000..356f90d
--- /dev/null
+++ b/copt/rules.net
@@ -0,0 +1,42 @@
+# Rules for optimizing BCC assembler output
+
+# Rules for converting short number from host to network order
+
+push word %[#|*]0%1
+call __htons
+inc sp
+inc sp
+=
+mov ax,#((%1 & $00FF) << 8) + ((%1 & $FF00) >> 8)
+
+mov ax,%[#|*]0%1
+push ax
+call __htons
+inc sp
+inc sp
+=
+mov ax,#((%1 & $00FF) << 8) + ((%1 & $FF00) >> 8)
+
+push %0[%1]
+call __htons
+inc sp
+inc sp
+=
+mov ax,%0[%1]
+xchg al,ah
+
+push ax
+call __htons
+inc sp
+inc sp
+=
+xchg al,ah
+
+push %[bx|cx|dx]1
+call __htons
+inc sp
+inc sp
+=
+mov ax,%1
+xchg al,ah
+
diff --git a/copt/rules.start b/copt/rules.start
new file mode 100644
index 0000000..f494305
--- /dev/null
+++ b/copt/rules.start
@@ -0,0 +1,19 @@
+# Rules to optimize BCC assembler output
+
+# The following rules protect the procedure prolog and epilogue from
+# getting optimized away in later steps
+
+push bp
+mov bp,sp
+push di
+push si
+=
+proc_start
+
+pop si
+pop di
+pop bp
+ret
+=
+proc_end
+
diff --git a/dis88/Makefile b/dis88/Makefile
index 56f9390..9e82095 100644
--- a/dis88/Makefile
+++ b/dis88/Makefile
@@ -37,12 +37,12 @@ dis88: $(OBJ)
install: dis88
install -m 755 -s dis88 $(DIST)/usr/bin/dis88
- install -m 644 -s dis88.1 $(DIST)/usr/man/man1/dis88.1
+ install -m 644 dis88.1 $(DIST)/usr/man/man1/dis88.1
$(OBJ): dis.h a.out.h
a.out.h:
ln -s ../libc/include/a.out.h .
-clean:
+clean realclean:
rm -f *.bak *.lst *.o core dis88 a.out.h
diff --git a/doselks/Makefile b/doselks/Makefile
index de3dd55..75144e8 100644
--- a/doselks/Makefile
+++ b/doselks/Makefile
@@ -1,5 +1,6 @@
-CC=bcc
+CC=$(BCC)
+BCC=bcc
CFLAGS=-Md
LDFLAGS=-Md -s
diff --git a/elksemu/Makefile b/elksemu/Makefile
index b2b34e8..5964353 100644
--- a/elksemu/Makefile
+++ b/elksemu/Makefile
@@ -4,7 +4,7 @@
ifeq ($(CC),bcc)
# Use BCC to make a tiny static a.out version.
-CFLAGS=-O -3 -N -ansi
+CFLAGS=-O -3 -N -ansi -s
else
# For gcc with the default compiler
CFLAGS=-O2 -fno-strength-reduce -Wall -idirafter . $(DEFS)
@@ -13,7 +13,7 @@ endif
# For gcc making a.out with a basically ELF compiler
# CFLAGS=-O2 -fno-strength-reduce -b i486-linuxaout -N -s -static
-OBJ=elks.o elks_sys.o elks_signal.o
+OBJ=elks.o elks_sys.o elks_signal.o minix.o
elksemu: $(OBJ)
$(CC) $(CFLAGS) -o elksemu $(OBJ)
@@ -32,7 +32,7 @@ install: elksemu
install -d $(DIST)/lib
install -s -o root -g root -m 4555 elksemu $(DIST)/lib/elksemu
-clean:
+clean realclean:
rm -f $(OBJ) elksemu call_tab.v defn_tab.v
module: binfmt_elks.o
diff --git a/elksemu/elks.c b/elksemu/elks.c
index 8cdcb14..2c58f8e 100644
--- a/elksemu/elks.c
+++ b/elksemu/elks.c
@@ -40,6 +40,9 @@ static void elks_init()
static void elks_take_interrupt(int arg)
{
+#if 1
+ if(arg==0x20) { minix_syscall(); return; }
+#endif
if(arg!=0x80)
{
dbprintf(("Took an int %d\n", arg));
@@ -48,7 +51,7 @@ static void elks_take_interrupt(int arg)
return;
}
- dbprintf(("syscall AX=%X BX=%X CX=%X DX=%x\n",
+ dbprintf(("syscall AX=%x BX=%x CX=%x DX=%x\n",
(unsigned short)elks_cpu.regs.eax,
(unsigned short)elks_cpu.regs.ebx,
(unsigned short)elks_cpu.regs.ecx,
diff --git a/elksemu/minix.c b/elksemu/minix.c
new file mode 100644
index 0000000..0c0ad67
--- /dev/null
+++ b/elksemu/minix.c
@@ -0,0 +1,72 @@
+
+/*
+ * System calls are mostly pretty easy as the emulator is tightly bound to
+ * the minix task.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/vm86.h>
+#include <sys/times.h>
+#include <utime.h>
+#include <termios.h>
+#include <time.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+#include <dirent.h>
+#include "elks.h"
+
+#ifdef DEBUG
+#define dbprintf(x) db_printf x
+#else
+#define dbprintf(x)
+#endif
+
+static char * minix_names[] = {
+ "0", "EXIT", "FORK", "READ", "WRITE", "OPEN", "CLOSE", "WAIT",
+ "CREAT", "LINK", "UNLINK", "WAITPID", "CHDIR", "TIME", "MKNOD",
+ "CHMOD", "CHOWN", "BRK", "STAT", "LSEEK", "GETPID", "MOUNT",
+ "UMOUNT", "SETUID", "GETUID", "STIME", "PTRACE", "ALARM", "FSTAT",
+ "PAUSE", "UTIME", "31", "32", "ACCESS", "34", "35", "SYNC", "KILL",
+ "RENAME", "MKDIR", "RMDIR", "DUP", "PIPE", "TIMES", "44", "45",
+ "SETGID", "GETGID", "SIGNAL", "49", "50", "51", "52", "53", "IOCTL",
+ "FCNTL", "56", "57", "58", "EXEC", "UMASK", "CHROOT", "SETSID",
+ "GETPGRP", "KSIG", "UNPAUSE", "66", "REVIVE", "TASK_REPLY", "69",
+ "70", "SIGACTION", "SIGSUSPEND", "SIGPENDING", "SIGPROCMASK",
+ "SIGRETURN", "REBOOT", "77"
+
+ };
+
+void
+minix_syscall()
+{
+ static char *nm[4] = {"?", "send", "receive", "sendrec"};
+ char tsks[10], syss[10];
+
+ int sr = (unsigned short) elks_cpu.regs.ecx;
+ int tsk = (unsigned short) elks_cpu.regs.eax;
+ int sys = ELKS_PEEK(short, (unsigned short) elks_cpu.regs.ebx + 2);
+
+ if (sr < 0 || sr > 3) sr = 0;
+ switch(tsk)
+ {
+ case 0: strcpy(tsks, "MM"); break;
+ case 1: strcpy(tsks, "FS"); break;
+ default: sprintf(tsks, "task(%d)", tsk);
+ }
+ if( sys > 0 && sys < 77 )
+ strcpy(syss, minix_names[sys]);
+ else
+ sprintf(syss, "%d", sys);
+
+ fprintf(stderr, "Minix syscall %s(%s,&{%d,%s,...})\n", nm[sr], tsks, getpid(), syss);
+ exit(99);
+}
diff --git a/ifdef.c b/ifdef.c
new file mode 100644
index 0000000..f856157
--- /dev/null
+++ b/ifdef.c
@@ -0,0 +1,357 @@
+/* (C) 1992,1996 R de Bath */
+
+#include <stdio.h>
+#include <ctype.h>
+
+struct varrec
+{
+ struct varrec * next;
+ int state;
+ char name[1];
+}
+ *varlist = 0;
+
+int cuttype = 0; /* 0 = use blank lines */
+ /* 1 = use #lines */
+ /* 2 = use '# 'oldtext */
+ /* 3 = delete unused lines */
+
+char linebuf[2048];
+
+char * filename;
+int lineno;
+int prline;
+FILE * fd;
+
+int iflevel = 0;
+int keeptext = 1;
+int unknown_stat = 0;
+
+char * commentstr = "#";
+
+char names[16][32];
+char state[16];
+
+main(argc, argv)
+int argc;
+char ** argv;
+{
+ int ar;
+ char * ptr;
+
+ if( argc <= 1 ) Usage(argv[0]);
+
+ for(ar=1; ar<argc; ar++) if( argv[ar][0] == '-' )
+ {
+ if( argv[ar][1] == 'D' || argv[ar][1] == 'U' )
+ {
+ if( argv[ar][2] )
+ save_name(argv[ar]+2, argv[ar][1]);
+ else
+ unknown_stat = argv[ar][1];
+ }
+ else if( argv[ar][1] == 'C' )
+ {
+ cuttype = 2;
+ if( argv[ar][2] ) commentstr = argv[ar]+2;
+ }
+ else for(ptr=argv[ar]+1; *ptr; ptr++) switch(*ptr)
+ {
+ case 'b': cuttype = 0; break;
+ case 'l': cuttype = 1; break;
+ case 'C':
+ case 'c': cuttype = 2; break;
+ case 'r': cuttype = 3; break;
+
+ case 'M': manifest_constant(); break;
+ case 'D': unknown_stat = 'D'; break;
+ case 'U': unknown_stat = 'U'; break;
+
+ default: Usage(argv[0]);
+ }
+ }
+ else
+ {
+ do_file(argv[ar]);
+ }
+ exit(0);
+}
+
+Usage(prog)
+char * prog;
+{
+ fprintf(stderr, "Usage: %s [-DFLAG] [-UFLAG] [-blcrMDU] [-C##] files\n",
+ prog);
+ exit(1);
+}
+
+save_name(varname, state)
+char * varname;
+int state;
+{
+ struct varrec * curr;
+ struct varrec * prev = 0;
+
+ for(curr=varlist;
+ curr && strcmp(curr->name, varname) != 0;
+ prev=curr, curr=curr->next)
+ ;
+
+ if( curr == 0 )
+ {
+ curr = (struct varrec*) malloc(sizeof(struct varrec)+strlen(varname));
+ if( curr == 0 )
+ fatal("Out of memory error");
+ if( prev ) prev->next = curr;
+ else varlist = curr;
+ curr->next = 0;
+ strcpy(curr->name, varname);
+ }
+ curr->state = state;
+}
+
+
+do_file(fname)
+char * fname;
+{
+ filename = fname;
+ prline = lineno = 0;
+ fd = fopen(fname, "r");
+ if( fd == 0 )
+ fatal("Cannot open file");
+
+ if( cuttype == 1 )
+ printf("#line 1 \"%s\"\n", filename);
+
+ while( fgets(linebuf, sizeof(linebuf), fd) != 0 )
+ {
+ int f = 1;
+ lineno++;
+ if( linebuf[0] == '#' )
+ f = do_hashcom();
+ if(f)
+ {
+ if( keeptext )
+ {
+ if( cuttype == 1 ) set_line(lineno);
+ printf("%s", linebuf);
+ }
+ else
+ {
+ if( cuttype == 0 ) printf("\n");
+ if( cuttype == 2 ) printf("%s %s", commentstr, linebuf);
+ }
+ }
+ }
+ fclose(fd);
+}
+
+set_line(lineno)
+int lineno;
+{
+ if( prline+2 == lineno )
+ printf("\n");
+ else if( prline+1 != lineno )
+ printf("#line %d \"%s\"\n", lineno, filename);
+ prline = lineno;
+}
+
+do_hashcom()
+{
+ char * p = linebuf+1;
+ int flg = -1;
+ while( *p == ' ' || *p == '\t' ) p++;
+
+ if(strncmp(p, "ifdef", 5) == 0)
+ {
+ do_ifdef(p+5, 'D');
+ }
+ else
+ if(strncmp(p, "ifndef", 6) == 0)
+ {
+ do_ifdef(p+6, 'U');
+ }
+ else
+ if(strncmp(p, "if", 2) == 0 && (p[2]==' ' || p[2]=='\t') )
+ {
+ state[iflevel++] = keeptext;
+ keeptext |= 2;
+ }
+ else
+ if(strncmp(p, "else", 4) == 0)
+ {
+ if( iflevel == 0 ) fatal("#else at top level");
+ if( iflevel && state[iflevel-1]) keeptext ^= 1;
+ }
+ else
+ if(strncmp(p, "endif", 5) == 0)
+ {
+ flg = (keeptext&2);
+ if( iflevel == 0 ) fatal("Too many endif's");
+ iflevel--;
+ keeptext = state[iflevel];
+ }
+ else if( cuttype != 0 ) return 1;
+
+ if( flg < 0 ) flg = (keeptext&2);
+
+ if( flg ) return 1;
+
+ if( cuttype == 0 ) printf("\n");
+ if( cuttype == 2 ) printf("%s %s", commentstr, linebuf);
+ return 0;
+}
+
+do_ifdef(p, which)
+char * p;
+int which;
+{
+ char * nm;
+ char * s;
+ struct varrec * curr;
+
+ while( *p == ' ' || *p == '\t') p++;
+ nm = p;
+
+ for(curr=varlist; curr ; curr = curr->next)
+ {
+ s = curr->name;
+ p = nm;
+ while( *p == *s ) { p++; s++; }
+ if( *s == '\0' && *p <= ' ' )
+ break;
+ }
+ state[iflevel] = keeptext;
+ iflevel++;
+
+ p=nm;
+ s=names[iflevel];
+ while(*p > ' ') *s++ = *p++;
+ *s = '\0';
+
+ if( curr == 0 )
+ {
+ if( unknown_stat == 0 )
+ {
+ if( keeptext ) keeptext |= 2;
+ return 0;
+ }
+ if( keeptext )
+ keeptext = (unknown_stat == which);
+ return 1;
+ }
+ if( keeptext )
+ keeptext = (curr->state == which);
+ return 1;
+}
+
+check_name(nm)
+char * nm;
+{
+ char * p;
+ char * s;
+ while(*nm == ' ' || *nm == '\t' ) nm++;
+ s = nm;
+ if( *s == '\n' || *s == '\r' || *s == '\0' ) return;
+ p = names[iflevel];
+ while(*p)
+ {
+ if( *p++ != *s++ )
+ goto x_error;
+ }
+ if( *s <= ' ' ) return;
+x_error:
+ fprintf(stderr, "Ifdef mis-nesting Line %d Expect '%s' Got '",
+ lineno,
+ names[iflevel]);
+ while(*nm > ' ' )
+ fputc(*nm++, stderr);
+ fputc('\'', stderr);
+ fputc('\n', stderr);
+}
+
+fatal(msg)
+char * msg;
+{
+ fprintf(stderr, "Fatal error:%s\n", msg);
+ exit(1);
+}
+
+/* This places manifest constants defined by the C compiler into ifdef
+ *
+ * Unfortunatly I can find no way of discovering the variables automatically
+ */
+manifest_constant()
+{
+/* General */
+#ifdef __STDC__
+ save_name("__STDC__", 'D');
+#endif
+#ifdef __GNUC__
+ save_name("__GNUC__", 'D');
+#endif
+
+/* MSDOS */
+#ifdef MSDOS
+ save_name("MSDOS", 'D');
+#endif
+#ifdef __MSDOS__
+ save_name("__MSDOS__", 'D');
+#endif
+
+/* Linux/unix */
+#ifdef __linux__
+ save_name("__linux__", 'D');
+#endif
+#ifdef __unix__
+ save_name("__unix__", 'D');
+#endif
+#ifdef __GNUC__
+ save_name("__GNUC__", 'D');
+#endif
+#ifdef __ELF__
+ save_name("__ELF__", 'D');
+#endif
+#ifdef __i386__
+ save_name("__i386__", 'D');
+#endif
+#ifdef __i486__
+ save_name("__i486__", 'D');
+#endif
+#ifdef i386
+ save_name("i386", 'D');
+#endif
+#ifdef linux
+ save_name("linux", 'D');
+#endif
+#ifdef unix
+ save_name("unix", 'D');
+#endif
+
+/* BCC */
+#ifdef __BCC__
+ save_name("__BCC__", 'D');
+#endif
+#ifdef __AS386_16__
+ save_name("__AS386_16__", 'D');
+#endif
+#ifdef __AS386_32__
+ save_name("__AS386_32__", 'D');
+#endif
+
+/* AIX, RS6000 */
+#ifdef _IBMR2
+ save_name("_IBMR2", 'D');
+#endif
+#ifdef _AIX
+ save_name("_AIX", 'D');
+#endif
+#ifdef _AIX32
+ save_name("_AIX32", 'D');
+#endif
+
+/* Ugh! Minix is actually _very_ nasty */
+#ifdef __minix
+ save_name("__minix", 'D');
+#endif
+}
diff --git a/ld/Makefile b/ld/Makefile
index 6351f10..da7b268 100644
--- a/ld/Makefile
+++ b/ld/Makefile
@@ -1,15 +1,11 @@
-ifneq ($(TOPDIR),)
-include $(TOPDIR)/Make.defs
-CFLAGS =$(CCFLAGS) -DREL_OUTPUT
-else
-LDFLAGS =-s
LIBDIR =/usr/bin
-CFLAGS =-O -DREL_OUTPUT
-endif
+CFLAGS =-O
+LDFLAGS =-s
# May need some of these if the auto-sense fails.
# -DV7_A_OUT -DBSD_A_OUT -DSTANDARD_GNU_A_OUT
+DEFS =-DREL_OUTPUT
OBJS= dumps.o io.o ld.o readobj.o table.o typeconv.o linksyms.o \
writex86.o writebin.o
@@ -23,8 +19,15 @@ install: ld86
install -d $(LIBDIR)
install -m 755 ld86 $(LIBDIR)
-clean:
+clean realclean:
rm -f $(OBJS) ld86
$(OBJS): align.h ar.h bindef.h byteord.h config.h const.h globvar.h obj.h \
syshead.h type.h x86_aout.h
+
+ar.h:
+ ln -s ../libc/include/ar.h . || \
+ ln ../libc/include/ar.h .
+
+.c.o:
+ $(CC) $(CFLAGS) $(DEFS) -c $< -o $@
diff --git a/ld/bugs b/ld/bugs
index b671f30..9444281 100644
--- a/ld/bugs
+++ b/ld/bugs
@@ -12,6 +12,3 @@ TODO:
TODO:
do malloc stuff better, as in compiler
-
-2. Error message about "foo.a is not an object file" is confusing - should
- name archive member.
diff --git a/ld/globvar.h b/ld/globvar.h
index d257d5c..4a66e89 100644
--- a/ld/globvar.h
+++ b/ld/globvar.h
@@ -16,3 +16,4 @@ extern int headerless; /* Don't output header on exe */
extern bin_off_t text_base_value; /* Base address of text seg */
extern bin_off_t data_base_value; /* Base or alignment of data seg */
+extern bin_off_t heap_top_value; /* Minimum 'total' value in x86 header */
diff --git a/ld/io.c b/ld/io.c
index 7b88222..39fc6a0 100644
--- a/ld/io.c
+++ b/ld/io.c
@@ -42,6 +42,10 @@ PRIVATE int trelfd; /* text relocation output file descriptor */
#endif
PRIVATE unsigned warncount; /* count of warnings */
+#ifdef MSDOS
+#define off_t long /* NOT a typedef */
+#endif
+
FORWARD void errexit P((char *message));
FORWARD void flushout P((void));
#ifdef REL_OUTPUT
@@ -117,14 +121,8 @@ int level;
PUBLIC void executable()
{
- mode_t oldmask;
-
if (errcount == 0)
- {
- oldmask = umask(0);
- umask(oldmask);
- chmod(outputname, outputperms | (EXEC_PERMS & ~oldmask));
- }
+ chmod(outputname, outputperms);
}
PUBLIC void flusherr()
@@ -164,7 +162,11 @@ char *filename;
{
closein();
inputname = filename; /* this relies on filename being static */
+#ifdef O_BINARY
if ((infd = open(filename, O_BINARY|O_RDONLY)) < 0)
+#else
+ if ((infd = open(filename, O_RDONLY)) < 0)
+#endif
inputerror("cannot open");
inbufptr = inbufend = inbuf;
}
@@ -173,21 +175,30 @@ char *filename;
PUBLIC void openout(filename)
char *filename;
{
- struct stat statbuf;
+ mode_t oldmask;
outputname = filename;
+#ifdef O_BINARY
if ((outfd = open(filename, O_BINARY|O_RDWR|O_CREAT|O_TRUNC, CREAT_PERMS)) == ERR)
+#else
+ if ((outfd = creat(filename, CREAT_PERMS)) == ERR)
+#endif
outputerror("cannot open");
- if (fstat(outfd, &statbuf) != 0)
- outputerror("cannot stat");
- outputperms = statbuf.st_mode;
+
+ oldmask = umask(0); umask(oldmask);
+ outputperms = ((CREAT_PERMS | EXEC_PERMS) & ~oldmask);
chmod(filename, outputperms & ~EXEC_PERMS);
+
#ifdef REL_OUTPUT
drelbufptr = drelbuf;
#endif
outbufptr = outbuf;
#ifdef REL_OUTPUT
- if ((trelfd = open(filename, O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, CREAT_PERMS)) == ERR)
+#ifdef O_BINARY
+ if ((trelfd = open(filename, O_BINARY|O_WRONLY, CREAT_PERMS)) == ERR)
+#else
+ if ((trelfd = open(filename, O_WRONLY, CREAT_PERMS)) == ERR)
+#endif
outputerror("cannot reopen");
trelbufptr = trelbuf;
#endif
@@ -556,11 +567,11 @@ PUBLIC void usage()
#ifdef REL_OUTPUT
errexit("\
[-03NMdimrstz[-]] [-llib_extension] [-o outfile] [-Ccrtfile]\n\
- [-Llibdir] [-Olibfile] [-T textaddr] [-D dataaddr] infile...");
+ [-Llibdir] [-Olibfile] [-T textaddr] [-D dataaddr] [-H heapsize] infile...");
#else
errexit("\
[-03NMdimstz[-]] [-llib_extension] [-o outfile] [-Ccrtfile]\n\
- [-Llibdir] [-Olibfile] [-T textaddr] [-D dataaddr] infile...");
+ [-Llibdir] [-Olibfile] [-T textaddr] [-D dataaddr] [-H heapsize] infile...");
#endif
}
diff --git a/ld/ld.c b/ld/ld.c
index a98618e..1de55ce 100644
--- a/ld/ld.c
+++ b/ld/ld.c
@@ -17,6 +17,7 @@
PUBLIC bin_off_t text_base_value = 0; /* XXX */
PUBLIC bin_off_t data_base_value = 0; /* XXX */
+PUBLIC bin_off_t heap_top_value = 0; /* XXX */
PUBLIC int headerless = 0;
PUBLIC char hexdigit[] = "0123456789abcdef";
@@ -77,6 +78,7 @@ char **argv;
static char libsuffix[] = ".a";
char *outfilename;
char *tfn;
+ int icount=0;
ioinit(argv[0]);
objinit();
@@ -90,7 +92,10 @@ char **argv;
{
arg = argv[argn];
if (*arg != '-')
+ {
readsyms(arg, flag['t']);
+ icount++;
+ }
else
switch (arg[1])
{
@@ -132,6 +137,7 @@ char **argv;
infilename = tfn;
/*fatalerror(tfn); * XXX - need to describe failure */
readsyms(infilename, flag['t']);
+ icount++;
break;
case 'L': /* library path */
if (lastlib < MAX_LIBS)
@@ -167,12 +173,24 @@ char **argv;
if (errno != 0)
use_error("invalid data address");
break;
+ case 'H': /* heap top address */
+ if (arg[2] == 0 && ++argn >= argc)
+ usage();
+ errno = 0;
+ if (arg[2] == 0 )
+ heap_top_value = strtoul(argv[argn], (char **)0, 16);
+ else
+ heap_top_value = strtoul(arg+2, (char **)0, 16);
+ if (errno != 0)
+ use_error("invalid heap top");
+ break;
case 'l': /* library name */
tfn = buildname(libprefix, arg + 2, libsuffix);
if ((infilename = expandlib(tfn)) == NUL_PTR)
infilename = tfn;
/* fatalerror(tfn); * XXX */
readsyms(infilename, flag['t']);
+ icount++;
break;
case 'o': /* output file name */
if (arg[2] != 0 || ++argn >= argc || outfilename != NUL_PTR)
@@ -183,6 +201,7 @@ char **argv;
usage();
}
}
+ if(icount==0) fatalerror("no input files");
#ifdef REL_OUTPUT
#ifndef MSDOS
diff --git a/ld/syshead.h b/ld/syshead.h
index f5f32ea..7e110ab 100644
--- a/ld/syshead.h
+++ b/ld/syshead.h
@@ -6,15 +6,14 @@
#endif
#ifndef POSIX_HEADERS_MISSING
-#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <unistd.h>
#include <fcntl.h>
#endif
#ifdef MSDOS
#undef POSIX_HEADERS_MISSING
-
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@@ -27,10 +26,6 @@
#define STDOUT_FILENO 0
#endif
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
-
/******************************************************************************/
/* EEEEyuk!! */
@@ -54,8 +49,6 @@ void *memset P((void *s, int c, unsigned n));
#endif
#ifdef POSIX_HEADERS_MISSING
-#include <sys/types.h>
-#include <sys/stat.h>
#define R_OK 0
int access P((const char *path, int amode));
@@ -76,3 +69,12 @@ mode_t umask P((int oldmask));
int write P((int fd, const void *buf, unsigned nbytes));
#endif
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#endif
+#ifndef O_WRONLY
+#define O_WRONLY 1
+#endif
+#ifndef O_RDWR
+#define O_RDWR 2
+#endif
diff --git a/ld/writebin.c b/ld/writebin.c
index 60440f7..a001b5d 100644
--- a/ld/writebin.c
+++ b/ld/writebin.c
@@ -341,9 +341,9 @@ bool_pt arguzp;
if( headerless ) setsym("__segoff", (bin_off_t)(segadj[1]-segadj[0])/0x10);
if( !bits32 )
{
- if( etextoffset > 65535L )
+ if( etextoffset > 65536L )
fatalerror("text segment too large for 16bit");
- if( endoffset > 65535L )
+ if( endoffset > 65536L )
fatalerror("data segment too large for 16bit");
}
@@ -915,8 +915,7 @@ PRIVATE void writeheader()
if (!reloc_output)
#endif
{
- if (uzp)
- offtocn((char *) &header.a_entry, page_size(),
+ offtocn((char *) &header.a_entry, btextoffset,
sizeof header.a_entry);
#ifndef STANDARD_GNU_A_OUT
offtocn((char *) &header.a_total, (bin_off_t)
diff --git a/ld/writex86.c b/ld/writex86.c
index 2b0f00a..5dd3e8d 100644
--- a/ld/writex86.c
+++ b/ld/writex86.c
@@ -263,9 +263,9 @@ bool_pt arguzp;
if( headerless ) setsym("__segoff", (bin_off_t)(segadj[1]-segadj[0])/0x10);
if( !bits32 )
{
- if( etextoffset > 65535L )
+ if( etextoffset > 65536L )
fatalerror("text segment too large for 16bit");
- if( endoffset > 65535L )
+ if( endoffset > 65536L )
fatalerror("data segment too large for 16bit");
}
@@ -528,9 +528,11 @@ PRIVATE void writeheader()
if (uzp)
offtocn((char *) &header.a_entry, page_size(),
sizeof header.a_entry);
- offtocn((char *) &header.a_total, (bin_off_t)
- (endoffset < 0x00008000L ? endoffset+0x8000L :
- (endoffset < 0x00010000L ? 0x00010000L : endoffset + 0x0008000L)),
+ if( heap_top_value < 0x100 || endoffset > heap_top_value-0x100)
+ heap_top_value = endoffset + 0x8000;
+ if( heap_top_value > 0x10000 && !bits32 ) heap_top_value = 0x10000;
+
+ offtocn((char *) &header.a_total, (bin_off_t) heap_top_value,
sizeof header.a_total);
if( FILEHEADERLENGTH )
writeout((char *) &header, FILEHEADERLENGTH);
diff --git a/ld/x86_aout.h b/ld/x86_aout.h
index f6a7b94..bd58346 100644
--- a/ld/x86_aout.h
+++ b/ld/x86_aout.h
@@ -90,7 +90,7 @@ struct reloc {
#define S_BSS ((unsigned short)-4)
struct nlist { /* symbol table entry */
- char n_name[24]; /* symbol name */
+ char n_name[8]; /* symbol name */
long n_value; /* value */
unsigned char n_sclass; /* storage class */
unsigned char n_numaux; /* number of auxiliary entries (not used) */
diff --git a/libbsd/Makefile b/libbsd/Makefile
index a33fbde..618c668 100644
--- a/libbsd/Makefile
+++ b/libbsd/Makefile
@@ -5,14 +5,11 @@
# Author: Rick Sladkey, <jrs@world.std.com>
# Ported to linux-86 (by removing select.c): Dick Porter <dick@cymru.net>
#
-
-# Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
# This file is part of the Linux-8086 C library and is distributed
# under the GNU Library General Public License.
-TOP=..
-include $(TOP)/Make.defs
-include ./Make.defs
+TOP=$(TOPDIR)
+include Make.defs
LIBBSD=libbsd.a
TARGETS=$(LIBBSD)
@@ -38,9 +35,8 @@ $(LIBBSD): $(OBJS)
$(AR) rcs $(LIBBSD) $(OBJS)
realclean: clean
- rm -f $(LIBBSD)
-
clean: dummy
rm -f *.o
+ rm -f $(LIBBSD)
dummy:
diff --git a/libc/Contributors b/libc/Contributors
deleted file mode 100644
index 27a3145..0000000
--- a/libc/Contributors
+++ /dev/null
@@ -1,8 +0,0 @@
-Alan Cox <alan@cymru.net>
-Bruce Evans <bde@FreeBSD.org>
-Chad Page <page0588@sundance.sjsu.edu>
-Dale Schumacher <dal@syntel.UUCP>
-Joel N. Weber II <nemo@koa.iolani.honolulu.hi.us>
-Nat Friedman <ndf@aleph1.mit.edu>
-Robert de Bath <robert@mayday.compulink.co.uk>
-Steven Huang <sthuang@hns.com>
diff --git a/libc/Make.defs b/libc/Make.defs
index b4f0c28..2b1eca6 100644
--- a/libc/Make.defs
+++ b/libc/Make.defs
@@ -1,108 +1,80 @@
-# Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
-# This file is part of the Linux-8086 C library and is distributed
-# under the GNU Library General Public License.
-
-# Set PLATFORM to i386-Linux to build for Linux/386 and to i86-ELKS to
-# build for ELKS. This doesn't quite work yet, though, because of some of
-# the platform and/or compiler-specific code flying around here.
-# Eventually, compiler-specificity won't be an issue, and we can put
-# platform-specific code in i86/ and i386/. -Nat
-
-# Define enviroment var for others.
-ifeq ($(PLATFORM),)
-# PLATFORM=i86-ELKS
-# PLATFORM=i86-FAST PLATFORM=i86-DOS PLATFORM=i386-BCC PLATFORM=i386-Linux
-
-PLATFORM=$(shell if [ -f $(TOP)/.config.otype ] ; \
- then cat $(TOP)/.config.otype ; \
- else echo i86-ELKS ; fi)
-export PLATFORM
-endif
-
-VERMAJOR=0
-VERMINOR=0
-VERPATCH=9
-VER=$(VERMAJOR).$(VERMINOR).$(VERPATCH)
-
-LIBDEFS='-D__LIBC__="$(VER)"'
-LIBC=libc.a
-
-##############################################################################
-
+############################################################################
# Normal standard 8086 code
+
ifeq ($(PLATFORM),i86-ELKS)
-ARCH=
+OBJ=crt0.o
+LIBC=$(TOP)/libc.a
+ARCH=-Mn
LIB_CPU=i86
LIB_OS=ELKS
endif
+##############################################################################
# 8086 elks code With "Caller saves" and "First arg in AX"
+
ifeq ($(PLATFORM),i86-FAST)
+OBJ=crt0.o
+LIBC=$(TOP)/libc_f.a
ARCH=-Mf
-LIBC=libc_f.a
LIB_CPU=i86
LIB_OS=ELKS
endif
+##############################################################################
# Standalone executable
+
ifeq ($(PLATFORM),i86-BIOS)
+OBJ=crt0.o
+LIBC=$(TOP)/libc_s.a
ARCH=-Ms
-LIBC=libc_s.a
LIB_CPU=i86
LIB_OS=BIOS
endif
+##############################################################################
# MSDOS COM file (msdos libs don't support "First arg in AX")
+
ifeq ($(PLATFORM),i86-DOS)
+OBJ=crt0.o
+LIBC=$(TOP)/libdos.a
ARCH=-Md
-LIBC=libdos.a
LIB_CPU=i86
LIB_OS=DOS
endif
##############################################################################
-
# BCC 386.
+
ifeq ($(PLATFORM),i386-BCC)
-ARCH=-3 -N
+OBJ=crt3.o
+LIBC=$(TOP)/libc3.a
+ARCH=-Ml
LIB_CPU=i386
LIB_OS=ELKS
-
-CC=bcc $(ARCH)
-CCFLAGS=-I -I$(TOP)/include
-LKFLAGS=-L -L$(TOP)/
endif
-ifeq ($(PLATFORM),i386-Linux)
-LIB_CPU=g386
-LIB_OS=ELKS
+##############################################################################
+# Anonymous
-CC=gcc $(ARCH)
-# ARCH=-b i486-linuxaout
-LKFLAGS=-static -N
-CCFLAGS=-O6 -fomit-frame-pointer -I- -I$(TOP)/include -I. -fno-builtin
-WALL= -ansi -pedantic -Wwrite-strings -Wpointer-arith -Wcast-qual \
- -Wcast-align -Wtraditional -Wstrict-prototypes -Wmissing-prototypes \
- -Wnested-externs -Winline -Wshadow
+ifeq ($(PLATFORM),ANON)
+OBJ=crt0.o
+LIBC=$(TOP)/libc.a
+ARCH=
+LIB_CPU=Bigbad
+LIB_OS=Nice
+CC=cc
+CCFLAGS=-I$(TOP)/include
endif
-############################################################################
-
-ifeq ($(LIB_CPU),i86)
-CC=bcc $(ARCH)
-CCFLAGS=-I -I$(TOP)/include # -O
-LKFLAGS=-L -L$(TOP)/ -s
-endif
+##############################################################################
+# Unknown
ifeq ($(LIB_CPU),)
+OBJ=crtX.o
+LIBC=$(TOP)/libc_X.a
+ARCH=
LIB_CPU=Unknown
LIB_OS=Unknown
-LIBC=libc_X.a
-CCFLAGS=-I$(TOP)/include
-LKFLAGS=
endif
-CFLAGS=$(CCFLAGS) $(LIBDEFS)
-LDFLAGS=$(LKFLAGS)
-
.PRECIOUS: $(LIBC)
diff --git a/libc/Makefile b/libc/Makefile
index 0359619..83aded9 100644
--- a/libc/Makefile
+++ b/libc/Makefile
@@ -1,103 +1,101 @@
-# Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+# Copyright (C) 1996,1997 Robert de Bath <robert@mayday.cix.co.uk>
# This file is part of the Linux-8086 C library and is distributed
# under the GNU Library General Public License.
-TOP=.
-include $(TOP)/Make.defs
+ifeq ($(TOPDIR),)
+# This should work, but ..
+TOP=..
+else
+TOP=$(TOPDIR)/libc
+endif
-SRC=crt0.c
-OBJ=crt0.o
+VERMAJOR=0
+VERMINOR=0
+VERPATCH=11
+VER=$(VERMAJOR).$(VERMINOR).$(VERPATCH)
-TARGETS=$(OBJ) $(LIBC)
-TXT=Makefile Make.defs README KERNEL COPYING Contributors MAGIC \
- New_subdir Pre_main Config_sh
+CC=bcc
+CCFLAGS=-I -I$(TOP)/include
+DEFS=-D__LIBC__
-all: .config.dir .config.otype $(TARGETS)
+include Make.defs
-install: all install_incl
- install -d $(BCCHOME)
- install -d $(LIBDIR)/$(LIB_CPU)
- install -m 644 crt0.o $(LIBDIR)/$(LIB_CPU)
- install -m 644 $(LIBC) $(LIBDIR)/$(LIB_CPU)
- -install -d $(DIST)/usr/lib
- -install -m 644 error/liberror.txt $(DIST)/usr/lib/liberror.txt
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
-# I've changed this so it'll be easier to make a binary dist.
-old_install_incl:
- rm -rf $(BCCHOME)/include
- ln -s $(TOPDIR)/libc/include $(BCCHOME)/include
+############################################################################
-install_incl:
- rm -rf $(BCCHOME)/include
- cp -pr include $(BCCHOME)/include
- if [ -f kinclude/Used ] ; \
- then cp -pr kinclude/arch $(BCCHOME)/include/arch ; \
- else rm -rf $(BCCHOME)/include/linuxmt ; \
- ln -s $(ELKSSRC)/include/linuxmt $(BCCHOME)/include ; \
- fi
- -chown -R root:root $(BCCHOME)/include 2>/dev/null
- -chmod -R u=rwX,og=rX $(BCCHOME)/include
+MAKEPASS= \
+ LIBC='$(LIBC)' CC='$(CC)' ARCH='$(ARCH)' CCFLAGS='$(CCFLAGS)' \
+ DEFS='$(DEFS)' LIB_CPU='$(LIB_CPU)' LIB_OS='$(LIB_OS)' \
-tests: dummy
- $(MAKE) -C tests
-dummy:
+all: $(OBJ) $(LIBC)
+ @:
$(LIBC): transfer .config.dir
@for i in `cat .config.dir` ; do \
- echo $(MAKE) -C $$i libc.a ; $(MAKE) -C $$i libc.a || exit 1 ; \
+ $(MAKE) $(MAKEPASS) -C $$i all || exit 1 ; \
done
+crt3.o: crt0.c Makefile
+ $(CC) -c $(CFLAGS) -D__LIBC_VER__='"$(VER)"' -o $@ crt0.c
+
+crt0.o: crt0.c Makefile
+ $(CC) -c $(CFLAGS) -D__LIBC_VER__='"$(VER)"' -o $@ crt0.c
+
+crtX.o:
+ @echo "You need to define the 'PLATFORM=...' variable"
+ @exit 1
+
+############################################################################
+
transfer: .config.dir
- @echo Checking for transfers
@for i in `cat .config.dir`; do \
- grep -q '^transfer' $$i/Makefile && $(MAKE) -s -C $$i $@ ; \
+ grep -s '^transfer' $$i/Makefile && $(MAKE) -s -C $$i $@ ; \
done ; echo -n
@[ -f kinclude/Used ] || \
{ rm -f include/linuxmt ; \
ln -s $(ELKSSRC)/include/linuxmt include ; }
-realclean: noconfig clean dellib
+############################################################################
+
+realclean: clean noconfig
clean:
- rm -f $(OBJ) $(LIBC)
+ rm -f *.o *.a
@for i in */Makefile ; do \
$(MAKE) -C `dirname $$i` $@ || exit 1 ; \
done
-dellib:
- rm -f *.a
+############################################################################
-##############################################################################
+install_incl:
+ rm -rf $(BCCHOME)/include
+ cp -pr include $(BCCHOME)/include
+ if [ -f kinclude/Used ] ; \
+ then cp -pr kinclude/arch $(BCCHOME)/include/arch ; \
+ else rm -rf $(BCCHOME)/include/linuxmt ; \
+ ln -s $(ELKSSRC)/include/linuxmt $(BCCHOME)/include ; \
+ fi
+ -chown -R root:root $(BCCHOME)/include 2>/dev/null
+ -chmod -R u=rwX,og=rX $(BCCHOME)/include
-.config.lst: Makefile Make.defs Config_sh
- sh Config_sh
-
-config:
+############################################################################
+
+config:
sh Config_sh
+.config.dir: .config.lst
+ @grep '^[^:]*:+:' < .config.lst | sed 's/:.*//' > .config.tmp
+ @mv -f .config.tmp .config.dir
+
+.config.lst: Config_sh
+ sh Config_sh
+
noconfig:
- rm -f .config.dir .config.lst .config.otype
+ rm -f .config.dir .config.lst .config.tmp
-.config.dir: .config.lst
- @grep '^[^:]*:+:' < .config.lst | sed 's/:.*//' > .config.dir
-
-.config.otype: dummy
- @[ -f .config.otype ] || echo $(PLATFORM) > .config.otype
- @[ "$(PLATFORM)" = "`cat .config.otype `" ] || $(MAKE) -$(MAKEFLAGS) clean
- @rm -f .config.otype
- @echo $(PLATFORM) > .config.otype
-
-dist: clean
- -rm -f include/linuxmt
- tar cf temp.tar \
- $(TXT) $(SRC) include \
- `for i in */Makefile */Config; do dirname $$i; done | sort -u`
- rm -rf libc-$(VER)
- mkdir libc-$(VER) ; cd libc-$(VER) ; tar xf ../temp.tar
- tar czf libc-8086-$(VER).tar.gz libc-$(VER)
- rm -rf libc-$(VER) temp.tar
-
-dist_ver: dist
- mv libc-8086-$(VER).tar.gz ..
+############################################################################
+
+Libc_version:
echo $(VER) > ../Libc_version
diff --git a/libc/New_subdir b/libc/New_subdir
index a28a5ec..e3803c7 100755
--- a/libc/New_subdir
+++ b/libc/New_subdir
@@ -28,17 +28,12 @@ cat <<! > $1/Makefile
# This file is part of the Linux-8086 C library and is distributed
# under the GNU Library General Public License.
-TOP=..
-include \$(TOP)/Make.defs
-
OBJ=$1.o
-all: \$(OBJ)
-
-libc.a: \$(OBJ)
- ar r ../\$(LIBC) \$(OBJ)
- @touch libc.a
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
+all: $(LIBC)($(OBJ))
+ @:
clean:
rm -f *.o libc.a
!
diff --git a/libc/README b/libc/README
index 0b65f99..6f45f26 100644
--- a/libc/README
+++ b/libc/README
@@ -1,14 +1,3 @@
-The lib can be compiled six different ways for Linux-8086 standard,
-Linux-8086 with 'First arg in AX', Linx-8086 standalone, MS-DOS, BCC-386
-or for GNU-386. At the moment the 386 GNU version will NOT work, the
-BCC-386 is just barely working.
-
-This can be done by running one of.
- make PLATFORM=i86-FAST clean all
- make PLATFORM=i86-DOS clean all
- make PLATFORM=i86-BIOS clean all
- make PLATFORM=i386-BCC clean all
-
SYSTEM CALLS
The system call table (syscalls/syscall.dat) is constantly changing, using
skewed versions is _very_ likely to give you segfaults and strange behaviour.
@@ -21,8 +10,8 @@ THE COMPILER
You should use the versions of bcc, unproto, as86, ld86 and elksemu that
are in this version of the combined development environment. Some other
versions will work but often they'll just appear to work or not work at
-all. The standard bcc-cc1 won't pickup the right header files, the
-standard ld86 won't generate COM files or 386-Linux files and looks in
+all. The original bcc-cc1 won't pickup the right header files, the
+original ld86 won't generate COM files or 386-Linux files and looks in
the wrong place for crt0.o and libc.a.
Main Subdirectories.
@@ -30,23 +19,21 @@ Main Subdirectories.
bcc Lots of BCC helper functions
bios Minimal 'system' calls for standalone executables.
error The C error functions.
-grp Routines for /etc/group, from Nat
+getent Routines for /etc/group, /etc/passwd and /etc/utmp
+gtermcap GNU termcap
i386fp BCC's floating point routines for 386 code.
include Some include files, some new others Glib or Glib hacked.
kinclude Kernel include files, here for now.
-malloc1 My malloc routines
+malloc1 Robert's malloc routines
malloc2 Joel's malloc routines
misc Various larger functions
-msdos This is the equlivent of the syscall directory for msdos.
-pwd Routines for /etc/passwd, from Nat
+msdos This is the syscall directory for msdos.
regexp Standard regular expression parser
-stdio2 My standard I/O
+stdio2 Robert's standard I/O
string The functions for string.h
syscall All the system call functions, and some tied lib ones.
termios Termimal mode control.
-utmp /etc/utmp updating
time Unix time related functions.
-tests Various C programs used to test the lib.
Directory structure:
diff --git a/libc/bcc/Makefile b/libc/bcc/Makefile
index 991b50e..f4cce3d 100644
--- a/libc/bcc/Makefile
+++ b/libc/bcc/Makefile
@@ -2,10 +2,6 @@
# This file is part of the Linux-8086 C library and is distributed
# under the GNU Library General Public License.
-TOP=..
-include $(TOP)/Make.defs
-CFLAGS=$(CCFLAGS)
-
# Support for integer arithmetic
ifeq ($(LIB_CPU),i86)
IOBJ=__idiv.o __idivu.o __imod.o __imodu.o __imul.o __isl.o __isr.o __isru.o
@@ -49,26 +45,43 @@ endif
OLDOBJ=$(ROBJ) $(POBJ)
-all: $(OBJ)
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
+
+ifneq ($(OBJ),)
-$(IOBJ): $(ISRC)
- $(CC) $(CFLAGS) -c -DL_$* -o $@ $(ISRC)
+all: $(LIBC)
+ @:
-$(LOBJ): $(LSRC)
- $(CC) $(CFLAGS) -c -DL_$* -o $@ $(LSRC)
+$(LIBC): $(LIBC)($(OBJ))
-$(AOBJ): $(ASRC)
- $(CC) $(CFLAGS) -c -DL_$* -o $@ $(ASRC)
+$(LIBC)($(IOBJ)): $(ISRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
-$(ROBJ): $(RSRC)
- $(CC) $(CFLAGS) -c -DL_$* -o $@ $(RSRC)
+$(LIBC)($(LOBJ)): $(LSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
-$(POBJ): $(PSRC)
- $(CC) $(CFLAGS) -c -DL_$* -o $@ $(PSRC)
+$(LIBC)($(AOBJ)): $(ASRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
-libc.a: $(OBJ)
- ar r ../$(LIBC) $(OBJ)
- @touch libc.a
+$(LIBC)($(ROBJ)): $(RSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+$(LIBC)($(POBJ)): $(PSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+else
+all:
+ @:
+endif
clean:
rm -f *.o libc.a
diff --git a/libc/bcc/heap.c b/libc/bcc/heap.c
index 2cab16e..c5b2457 100644
--- a/libc/bcc/heap.c
+++ b/libc/bcc/heap.c
@@ -49,7 +49,7 @@ has_change:
jb Enomem
sbrk_ok:
-#ifndef __MSDOS__
+#if !defined(__MSDOS__) && !defined(__STANDALONE__)
push ax ! MSDOS `kernel` doesn`t care
call ___brk ! Tell the kernel
test ax,ax
@@ -96,7 +96,7 @@ Enomem:
mov ax,#-1
ret
brk_ok:
-#ifndef __MSDOS__
+#if !defined(__MSDOS__) && !defined(__STANDALONE__)
push ax
call ___brk ! Tell the kernel
test ax,ax
diff --git a/libc/bios/Makefile b/libc/bios/Makefile
index 934ec07..5fcc964 100644
--- a/libc/bios/Makefile
+++ b/libc/bios/Makefile
@@ -2,29 +2,34 @@
# This file is part of the Linux-8086 C library and is distributed
# under the GNU Library General Public License.
-TOP=..
-include $(TOP)/Make.defs
-
ifeq ($(LIB_OS),BIOS)
ASRC=bios.c
AOBJ=bios_start.o bios_isatty.o \
bios_open.o bios_read.o bios_write.o bios_lseek.o bios_close.o
BSRC=bios_vid.c
-BOBJ=bios_putc.o bios_getc.o bios_rdline.o
-endif
+BOBJ=bios_putc.o bios_getc.o bios_khit.o bios_rdline.o
-all: $(AOBJ) $(BOBJ)
+OBJ=$(AOBJ) $(BOBJ)
-libc.a: $(AOBJ) $(BOBJ)
- ar r ../$(LIBC) $(AOBJ) $(BOBJ)
- @touch libc.a
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
-clean:
- rm -f *.o libc.a
+all: $(LIBC)($(OBJ))
+ @:
-$(AOBJ): $(ASRC)
- $(CC) $(CFLAGS) -c -DL_$* -o $@ $(ASRC)
+$(LIBC)($(AOBJ)): $(ASRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
-$(BOBJ): $(BSRC)
- $(CC) $(CFLAGS) -c -DL_$* -o $@ $(BSRC)
+$(LIBC)($(BOBJ)): $(BSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+else
+all:
+ @:
+endif
+
+clean:
+ rm -f *.o libc.a
diff --git a/libc/bios/bios.c b/libc/bios/bios.c
index 3059fd9..a8d2079 100644
--- a/libc/bios/bios.c
+++ b/libc/bios/bios.c
@@ -26,6 +26,8 @@ defarg:
.word boot_str, 0
boot_str:
.asciz "boot"
+loop_save:
+ .word 0
.text
export ___cstartup ! Crt0 startup
@@ -54,15 +56,17 @@ zap_bss: ! Clear the BSS
mov ax,#1
push ax
- mov si,#auto_start ! Pointer to first autostart function
+ mov bx,#auto_start ! Pointer to first autostart function
auto_run:
- mov bx,[si]
+ mov [loop_save],bx
+ mov bx,[bx]
test bx,bx
jz no_entry
call bx ! Call the function
no_entry:
- inc si ! SI at next
- inc si
+ mov bx,[loop_save]
+ inc bx ! next
+ inc bx
jmp auto_run ! And round for the next.
call_exit: ! Last item called by above.
diff --git a/libc/bios/bios_vid.c b/libc/bios/bios_vid.c
index 0d891a0..db2e91d 100644
--- a/libc/bios/bios_vid.c
+++ b/libc/bios/bios_vid.c
@@ -84,6 +84,9 @@ static int ctrl = 0;
default:
asm_putc(c);
break;
+ case CTRL('I'):
+ asm_putc(' '); /* Only some BIOS's have this, so play safe */
+ break;
case CTRL('L'):
asm_cpos(0,0);
asm_cls();
@@ -424,6 +427,7 @@ int len;
return 1;
}
ch &= 0x7F;
+ if( ch == '\033' ) ch=3; /* ESC= Interrupt too */
}
if( ch == '\r' )
{
@@ -460,6 +464,26 @@ bios_getc()
/****************************************************************************/
+#ifdef L_bios_khit
+bios_khit()
+{
+#asm
+ mov ah,#1
+ int $16
+ jz nokey
+ cmp ax,#0
+ jnz dort
+ mov ax,#3
+dort:
+ ret
+nokey:
+ xor ax,ax
+#endasm
+}
+#endif
+
+/****************************************************************************/
+
#endif
#endif
#endif
diff --git a/libc/crt0.c b/libc/crt0.c
index b21b525..bdf1585 100644
--- a/libc/crt0.c
+++ b/libc/crt0.c
@@ -23,7 +23,7 @@ export no_op
no_op: ! Generic no operation call
ret
- .ascii __LIBC__ ! Version id.
+ .ascii __LIBC_VER__ ! Version id.
loc 1 ! Segment 1 is where the pointers to the autostart
! functions are stored.
diff --git a/libc/error/Makefile b/libc/error/Makefile
index dc9b98e..ae3d1c0 100644
--- a/libc/error/Makefile
+++ b/libc/error/Makefile
@@ -2,18 +2,17 @@
# This file is part of the Linux-8086 C library and is distributed
# under the GNU Library General Public License.
-TOP=..
-include $(TOP)/Make.defs
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
ifeq ($(LIB_OS),ELKS)
OBJ=error.o sys_errlist.o perror.o sys_siglist.o __assert.o
-endif
-
-all: $(OBJ)
-libc.a: $(OBJ)
- ar r ../$(LIBC) $(OBJ)
- @touch libc.a
+all: $(LIBC)($(OBJ))
+ @:
+else
+all:
+ @:
+endif
clean:
rm -f *.o libc.a
diff --git a/libc/getent/Config b/libc/getent/Config
new file mode 100644
index 0000000..0349aba
--- /dev/null
+++ b/libc/getent/Config
@@ -0,0 +1 @@
+getent: Managment for /etc/passwd /etc/group /etc/utmp
diff --git a/libc/pwd/Makefile b/libc/getent/Makefile
index eb4b844..9321ced 100644
--- a/libc/pwd/Makefile
+++ b/libc/getent/Makefile
@@ -2,43 +2,35 @@
# This file is part of the Linux-8086 C library and is distributed
# under the GNU Library General Public License.
-TOP=..
-include $(TOP)/Make.defs
-
ifeq ($(PLATFORM),i386-ELKS)
-CFLAGS+=$(WALL)
+CFLAGS=$(ARCH) $(WALL) $(CCFLAGS) $(DEFS)
else
-CFLAGS=$(CCFLAGS) $(LIBDEFS) -ansi
+CFLAGS=$(ARCH) -ansi $(CCFLAGS) $(DEFS)
endif
PSRC=__getpwent.c pwent.c getpwnam.c getpwuid.c putpwent.c getpw.c fgetpwent.c
-ifeq ($(LIB_OS),ELKS)
-POBJ=__getpwent.o pwent.o getpwnam.o getpwuid.o putpwent.o getpw.o fgetpwent.o
-else
-POBJ=
-endif
+GSRC=__getgrent.c grent.c getgrnam.c getgrgid.c fgetgrent.c initgroups.c \
+ config-grp.h
+USRC=utent.c
-all: $(POBJ)
+POBJ=__getpwent.o pwent.o getpwnam.o getpwuid.o putpwent.o getpw.o fgetpwent.o
+GOBJ=__getgrent.o grent.o getgrnam.o getgrgid.o fgetgrent.o initgroups.o
+UOBJ=utent.o
-%.o: %.c
- $(CC) $(CFLAGS) -o $@ $< -c
+ifeq ($(LIB_OS),ELKS)
-libc.a: $(POBJ)
- ar r ../$(LIBC) $(POBJ)
- @touch libc.a
+OBJ=$(POBJ) $(GOBJ) $(UOBJ)
-test: test_pwd.c libpwd.a
- $(CC) $(CFLAGS) test_pwd.c -o test_pwd -L. -lpwd
+all: $(LIBC)($(OBJ))
+ @:
-libpwd.a: $(POBJ)
- ar r libpwd.a $(POBJ)
- ranlib libpwd.a
+$(LIBC)($(GOBJ)): config-grp.h
-libpwd: libpwd.a
+else
+all:
+ @:
+endif
clean:
- rm -f *.o libc.a libpwd.a
-
-
-
+ rm -f *.o libc.a
diff --git a/libc/grp/__getgrent.c b/libc/getent/__getgrent.c
index 612f112..612f112 100644
--- a/libc/grp/__getgrent.c
+++ b/libc/getent/__getgrent.c
diff --git a/libc/pwd/__getpwent.c b/libc/getent/__getpwent.c
index 9836ca7..9836ca7 100644
--- a/libc/pwd/__getpwent.c
+++ b/libc/getent/__getpwent.c
diff --git a/libc/grp/config-grp.h b/libc/getent/config-grp.h
index 337d54b..337d54b 100644
--- a/libc/grp/config-grp.h
+++ b/libc/getent/config-grp.h
diff --git a/libc/grp/config.h b/libc/getent/config.h
index 337d54b..337d54b 100644
--- a/libc/grp/config.h
+++ b/libc/getent/config.h
diff --git a/libc/grp/fgetgrent.c b/libc/getent/fgetgrent.c
index 800236f..800236f 100644
--- a/libc/grp/fgetgrent.c
+++ b/libc/getent/fgetgrent.c
diff --git a/libc/pwd/fgetpwent.c b/libc/getent/fgetpwent.c
index e12b890..e12b890 100644
--- a/libc/pwd/fgetpwent.c
+++ b/libc/getent/fgetpwent.c
diff --git a/libc/grp/getgrgid.c b/libc/getent/getgrgid.c
index c1dd20e..c1dd20e 100644
--- a/libc/grp/getgrgid.c
+++ b/libc/getent/getgrgid.c
diff --git a/libc/grp/getgrnam.c b/libc/getent/getgrnam.c
index e6c27fc..e6c27fc 100644
--- a/libc/grp/getgrnam.c
+++ b/libc/getent/getgrnam.c
diff --git a/libc/pwd/getpw.c b/libc/getent/getpw.c
index 4f4e390..4f4e390 100644
--- a/libc/pwd/getpw.c
+++ b/libc/getent/getpw.c
diff --git a/libc/pwd/getpwnam.c b/libc/getent/getpwnam.c
index 85dbc8e..85dbc8e 100644
--- a/libc/pwd/getpwnam.c
+++ b/libc/getent/getpwnam.c
diff --git a/libc/pwd/getpwuid.c b/libc/getent/getpwuid.c
index ffd58c1..ffd58c1 100644
--- a/libc/pwd/getpwuid.c
+++ b/libc/getent/getpwuid.c
diff --git a/libc/grp/grent.c b/libc/getent/grent.c
index 19d618b..19d618b 100644
--- a/libc/grp/grent.c
+++ b/libc/getent/grent.c
diff --git a/libc/grp/initgroups.c b/libc/getent/initgroups.c
index 35e1d03..35e1d03 100644
--- a/libc/grp/initgroups.c
+++ b/libc/getent/initgroups.c
diff --git a/libc/pwd/putpwent.c b/libc/getent/putpwent.c
index a0035ea..a0035ea 100644
--- a/libc/pwd/putpwent.c
+++ b/libc/getent/putpwent.c
diff --git a/libc/pwd/pwent.c b/libc/getent/pwent.c
index fd65db2..fd65db2 100644
--- a/libc/pwd/pwent.c
+++ b/libc/getent/pwent.c
diff --git a/libc/grp/test_grp.c b/libc/getent/test_grp.c
index b5ecd36..b5ecd36 100644
--- a/libc/grp/test_grp.c
+++ b/libc/getent/test_grp.c
diff --git a/libc/pwd/test_pwd.c b/libc/getent/test_pwd.c
index 74f7657..74f7657 100644
--- a/libc/pwd/test_pwd.c
+++ b/libc/getent/test_pwd.c
diff --git a/libc/utmp/utent.c b/libc/getent/utent.c
index 7f9e19a..7f9e19a 100644
--- a/libc/utmp/utent.c
+++ b/libc/getent/utent.c
diff --git a/libc/grp/Config b/libc/grp/Config
deleted file mode 100644
index 9f49d93..0000000
--- a/libc/grp/Config
+++ /dev/null
@@ -1 +0,0 @@
-grp: /etc/group managment
diff --git a/libc/grp/Makefile b/libc/grp/Makefile
deleted file mode 100644
index f5d42a0..0000000
--- a/libc/grp/Makefile
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright (C) 1996 Nat Friedman <ndf@aleph1.mit.edu>
-# This file is part of the Linux-8086 C library and is distributed
-# under the GNU Library General Public License.
-
-TOP=..
-include $(TOP)/Make.defs
-
-ifeq ($(LIB_CPU),g386)
-CFLAGS+=$(WALL)
-else
-CFLAGS=$(CCFLAGS) $(LIBDEFS) -ansi
-endif
-
-GSRC=__getgrent.c grent.c getgrnam.c getgrgid.c fgetgrent.c initgroups.c \
- config-grp.h
-
-ifeq ($(LIB_OS),ELKS)
-GOBJ=__getgrent.o grent.o getgrnam.o getgrgid.o fgetgrent.o initgroups.o
-else
-GOBJ=
-endif
-
-all: $(GOBJ)
-
-%.o: %.c config-grp.h
- $(CC) $(CFLAGS) -o $@ $< -c
-
-libc.a: $(GOBJ)
- ar r ../$(LIBC) $(GOBJ)
- @touch libc.a
-
-test: test_grp.c libgrp.a
- $(CC) $(CFLAGS) test_grp.c -o test_grp -L -lgrp # -static
-
-libgrp: libgrp.a
-
-libgrp.a: $(GOBJ)
- ar r libgrp.a $(GOBJ)
- ranlib libgrp.a
-
-clean:
- rm -f *.o libc.a libgrp.a
diff --git a/libc/gtermcap/Makefile b/libc/gtermcap/Makefile
index 62a966d..44e21da 100644
--- a/libc/gtermcap/Makefile
+++ b/libc/gtermcap/Makefile
@@ -2,22 +2,18 @@
# This file is part of the Linux-8086 C library and is distributed
# under the GNU Library General Public License.
-TOP=..
-include $(TOP)/Make.defs
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
ifeq ($(LIB_OS),ELKS)
OBJ=termcap.o tparam.o
-endif
-
-all: $(OBJ)
-libc.a: $(OBJ)
- ar r ../$(LIBC) $(OBJ)
- @touch libc.a
+all: $(LIBC)($(OBJ))
+ @:
+else
+all:
+ @:
+endif
clean:
rm -f *.o libc.a
-$(SOBJ): $(SSRC)
- $(CC) $(CFLAGS) -c -DL_$* -o $@ $(SSRC)
-
diff --git a/libc/i386fp/Makefile b/libc/i386fp/Makefile
index 88158f7..55d06da 100644
--- a/libc/i386fp/Makefile
+++ b/libc/i386fp/Makefile
@@ -1,19 +1,10 @@
# Makefile for bcc 386 software floating point library
-TOP=..
-include $(TOP)/Make.defs
-
.SUFFIXES: .x # .x files are .s files that need C-preprocessing
.x.o:
cp $< tmp.c
- $(CC) $(CFLAGS) -P tmp.c | $(AS) - -n $* -o $@
-
-# $(ASCPP) $(ASCPPFLAGS) $< >tmp
-# $(AS) tmp -n $* -l tmp.lst -o $@
-
-AS =as86 -3
-ASCPP =/lib/cpp
-ASCPPFLAGS =-P -traditional
+ $(CC) $(CFLAGS) -E tmp.c >tmp.s
+ $(CC) $(CFLAGS) -c tmp.s -A-n -A$* -o $@
FPDIST =Makefile $(FPSRC) test.c bccfp.tex
FPSRC =fadd.x fcomp.x fdiv.x fmul.x fbsr.x \
@@ -26,33 +17,22 @@ FPOBJ =fadd.o fcomp.o fdiv.o fmul.o fpbsr.o \
fperr.o fperror.o fptoi.o fpushd.o fpulld.o \
fpushi.o fpushf.o fpullf.o frexp.o ftst.o \
fabs.o ldexp.o modf.o
-JUNK =tmp tmp.c tmp.lst
+JUNK =tmp tmp.c tmp.s tmp.lst
LIB =.
-test: test.c $(LIB)/libfp.a
- $(CC) -o $@ test.c $(LIB)/libfp.a -lm
-
-$(FPOBJ): fplib.h
-fperr.c fperror.x: fperr.h
-
-$(LIB)/libfp.a: $(FPOBJ)
- ar rc $(LIB)/libfp.a $(FPOBJ)
- rm -f $(JUNK)
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
ifeq ($(LIB_CPU),i386)
-libc.a: $(FPOBJ)
+all: $(LIBC)($(FPOBJ))
rm -f $(JUNK)
- ar rc ../libc.a $(FPOBJ)
else
-libc.a:
+all:
+ @:
endif
-dist: $(FPDIST)
- /bin/tar cvf - $(FPDIST) | /bin/compress -b 13 >bccfp.tar.Z
- uue bccfp.tar.Z
+$(LIBC)($(FPOBJ)): fplib.h
+$(LIBC)(fperr.o fperror.o): fperr.h
clean:
rm -f $(FPOBJ) $(JUNK) test
rm -f $(LIB)/libfp.a bccfp.tar.Z bccfp.uue
-
-realclean: clean
diff --git a/libc/i386sys/Config b/libc/i386sys/Config
new file mode 100644
index 0000000..1bf0110
--- /dev/null
+++ b/libc/i386sys/Config
@@ -0,0 +1 @@
+sys386: Linux-i386 system call routines
diff --git a/libc/i386sys/Makefile b/libc/i386sys/Makefile
new file mode 100644
index 0000000..ef01ac9
--- /dev/null
+++ b/libc/i386sys/Makefile
@@ -0,0 +1,52 @@
+# Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+# This file is part of the Linux-8086 C library and is distributed
+# under the GNU Library General Public License.
+
+LSRC=syslibc.c
+LOBJ=__cstart3.o time.o abort.o wait.o waitpid.o wait3.o killpg.o setpgrp.o \
+ sleep.o usleep.o
+
+ESRC=exec.c
+EOBJ=execl.o execv.o execle.o execlp.o execvp.o
+
+DSRC=dirent.c
+DOBJ=opendir.o closedir.o readdir.o
+
+ifeq ($(LIB_CPU)-$(LIB_OS),i386-ELKS)
+OBJ=$(LOBJ3) $(LOBJ) $(EOBJ) $(DOBJ)
+SYSCALLS=syscalls
+
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
+
+all: $(SYSCALLS) $(LIBC)($(OBJ))
+ @:
+
+syscalls: syscall.mak
+ $(MAKE) -f syscall.mak LIBC="$(LIBC)" CFLAGS="$(CFLAGS)"
+
+syscall.mak: mksyscall syscall.dat
+ sh mksyscall
+
+$(LIBC)($(LOBJ)): $(LSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+$(LIBC)($(DOBJ)): $(DSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+$(LIBC)($(EOBJ)): $(ESRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+else
+all:
+ @:
+endif
+
+clean:
+ rm -f *.o libc.a
+ rm -f syscall.c syscall.mak
+
diff --git a/libc/i386sys/dirent.c b/libc/i386sys/dirent.c
new file mode 100644
index 0000000..8f7574c
--- /dev/null
+++ b/libc/i386sys/dirent.c
@@ -0,0 +1,106 @@
+
+#include <errno.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <malloc.h>
+
+#ifdef L_opendir
+DIR *
+opendir(dname)
+const char *dname;
+{
+ struct stat st;
+ int fd;
+ DIR *p;
+
+ if (stat(dname, &st) < 0)
+ return 0;
+
+ if (!S_ISDIR(st.st_mode))
+ {
+ errno = ENOTDIR;
+ return 0;
+ }
+ if ((fd = open(dname, O_RDONLY)) < 0)
+ return 0;
+
+ p = malloc(sizeof(DIR));
+ if (p == 0)
+ {
+ close(fd);
+ return 0;
+ }
+
+ p->dd_buf = malloc(sizeof(struct dirent));
+ if (p->dd_buf == 0)
+ {
+ free(p);
+ close(fd);
+ return 0;
+ }
+ p->dd_fd = fd;
+ p->dd_loc = p->dd_size = 0;
+
+ return p;
+}
+#endif
+
+#ifdef L_closedir
+int
+closedir(dirp)
+DIR *dirp;
+{
+ int fd;
+ fd = dirp->dd_fd;
+ free(dirp->dd_buf);
+ free(dirp);
+ return close(fd);
+}
+#endif
+
+#ifdef __AS386_16__
+#ifdef L_readdir
+/*
+ * This currently assumes we see a v. simple diectory structure, it's
+ * probably faked!
+ */
+struct dirent *
+readdir(dirp)
+DIR *dirp;
+{
+ int cc;
+ cc = read(dirp->dd_fd, dirp->dd_buf, sizeof(struct dirent));
+
+ if (cc <= 0)
+ return 0;
+ if (cc != sizeof(struct dirent))
+ {
+ errno = EBADF;
+ return 0;
+ }
+ return dirp->dd_buf;
+}
+#endif
+#else
+
+/* This is for 386 linux */
+
+#ifdef L_readdir
+struct dirent *
+readdir(dirp)
+DIR *dirp;
+{
+ int cc;
+
+ cc = __readdir(dirp->dd_fd, dirp->dd_buf, 1);
+ if (cc <= 0)
+ return 0;
+ if (cc>1) dirp->dd_buf->d_name[cc] = 0;
+
+ return dirp->dd_buf;
+}
+#endif
+
+#endif
diff --git a/libc/i386sys/exec.c b/libc/i386sys/exec.c
new file mode 100644
index 0000000..411b744
--- /dev/null
+++ b/libc/i386sys/exec.c
@@ -0,0 +1,292 @@
+
+#include <errno.h>
+#include <sys/stat.h>
+
+extern char ** environ;
+
+#ifdef L_execl
+int
+execl(fname, arg0)
+char * fname, *arg0;
+{
+ return execve(fname, &arg0, environ);
+}
+#endif
+
+#ifdef L_execv
+int
+execv(fname, argv)
+char * fname, **argv;
+{
+ return execve(fname, argv, environ);
+}
+#endif
+
+#ifdef L_execle
+int
+execle(fname, arg0)
+char *fname, *arg0;
+{
+ char ** envp = &arg0;
+ while(*envp) envp++;
+ return execve(fname, &arg0, envp+1);
+}
+#endif
+
+#ifdef L_execve
+int
+execve(fname, argv, envp)
+char * fname;
+char ** argv;
+char ** envp;
+{
+ char **p;
+ int argv_len=0, argv_count=0;
+ int envp_len=0, envp_count=0;
+ int stack_bytes;
+ unsigned short * pip;
+ char * pcp, * stk_ptr, *baseoff;
+ int rv;
+
+ /* How much space for argv */
+ for(p=argv; p && *p && argv_len >= 0; p++)
+ {
+ argv_count++; argv_len += strlen(*p)+1;
+ }
+
+ /* How much space for envp */
+ for(p=envp; p && *p && envp_len >= 0; p++)
+ {
+ envp_count++; envp_len += strlen(*p)+1;
+ }
+
+ /* tot it all up */
+ stack_bytes = 2 /* argc */
+ + argv_count * 2 + 2 /* argv */
+ + argv_len
+ + envp_count * 2 + 2 /* envp */
+ + envp_len;
+
+ /* Allocate it */
+ if( argv_len < 0 || envp_len < 0 || stack_bytes <= 0
+ || (int)(stk_ptr = (char*)sbrk(stack_bytes)) == -1)
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+
+/* Sanity check
+ printf("Argv = (%d,%d), Envp=(%d,%d), stack=%d\n",
+ argv_count, argv_len, envp_count, envp_len, stack_bytes);
+*/
+
+ /* Now copy in the strings */
+ pip=(unsigned short *) stk_ptr;
+ pcp=stk_ptr+2*(1+argv_count+1+envp_count+1);
+
+ /* baseoff = stk_ptr + stack_bytes; */
+ baseoff = stk_ptr;
+ *pip++ = argv_count;
+ for(p=argv; p && *p; p++)
+ {
+ int l;
+ *pip++ = pcp-baseoff;
+ l = strlen(*p)+1;
+ memcpy(pcp, *p, l);
+ pcp += l;
+ }
+ *pip++ = 0;
+
+ for(p=envp; p && *p; p++)
+ {
+ int l;
+ *pip++ = pcp-baseoff;
+ l = strlen(*p)+1;
+ memcpy(pcp, *p, l);
+ pcp += l;
+ }
+ *pip++ = 0;
+
+ rv = __exec(fname, stk_ptr, stack_bytes);
+ /* FIXME: This will probably have to interpret '#!' style exe's */
+ sbrk(-stack_bytes);
+ return rv;
+}
+#endif
+
+#ifdef L_execlp
+int
+execlp(fname, arg0)
+char * fname, *arg0;
+{
+ return execvp(fname, &arg0);
+}
+#endif
+
+#ifdef L_execvp
+int
+execvp(fname, argv)
+char * fname, **argv;
+{
+ char *pname = fname, *path;
+ int besterr = ENOENT;
+ int flen, plen;
+ char * bp = sbrk(0);
+
+ if( *fname != '/' && (path = getenv("PATH")) != 0 )
+ {
+ flen = strlen(fname)+2;
+
+ for(;path;)
+ {
+ if( *path == ':' || *path == '\0' )
+ {
+ tryrun(fname, argv);
+ if( errno == EACCES ) besterr = EACCES;
+ if( *path ) path++; else break;
+ }
+ else
+ {
+ char * p = strchr(path, ':');
+ if(p) *p = '\0';
+ plen = strlen(path);
+ pname = sbrk(plen+flen);
+
+ strcpy(pname, path);
+ strcat(pname, "/");
+ strcat(pname, fname);
+
+ tryrun(pname, argv);
+ if( errno == EACCES ) besterr = EACCES;
+
+ brk(pname);
+ pname = fname;
+ if(p) *p++ = ':';
+ path=p;
+ }
+ }
+ }
+
+ tryrun(pname, argv);
+ brk(bp);
+ if( errno == ENOENT || errno == 0 ) errno = besterr;
+ return -1;
+}
+
+static int tryrun(pname, argv)
+char * pname;
+char ** argv;
+{
+static char *shprog[] = {"/bin/sh", "", 0};
+ struct stat st;
+
+ if( stat(pname, &st) < 0 ) return;
+ if( !S_ISREG(st.st_mode) ) return;
+
+#ifdef __AS386_16__
+ __execvve(pname, (void*)0, argv, environ);
+ if( errno == ENOEXEC )
+ {
+ shprog[1] = pname;
+ __execvve(shprog[0], shprog, argv, environ);
+ }
+#else
+ execve(pname, argv, environ);
+ /* FIXME - running /bin/sh in 386 mode */
+#endif
+}
+
+#ifdef __AS386_16__
+static int
+__execvve(fname, interp, argv, envp)
+char * fname;
+char ** interp;
+char ** argv;
+char ** envp;
+{
+ char **p;
+ int argv_len=0, argv_count=0;
+ int envp_len=0, envp_count=0;
+ int stack_bytes;
+ unsigned short * pip;
+ char * pcp, * stk_ptr, *baseoff;
+ int rv;
+
+ /* How much space for argv */
+ for(p=interp; p && *p && argv_len >= 0; p++)
+ {
+ argv_count++; argv_len += strlen(*p)+1;
+ }
+ for(p=argv; p && *p && argv_len >= 0; p++)
+ {
+ argv_count++; argv_len += strlen(*p)+1;
+ }
+
+ /* How much space for envp */
+ for(p=envp; p && *p && envp_len >= 0; p++)
+ {
+ envp_count++; envp_len += strlen(*p)+1;
+ }
+
+ /* tot it all up */
+ stack_bytes = 2 /* argc */
+ + argv_count * 2 + 2 /* argv */
+ + argv_len
+ + envp_count * 2 + 2 /* envp */
+ + envp_len;
+
+ /* Allocate it */
+ if( argv_len < 0 || envp_len < 0 || stack_bytes <= 0
+ || (int)(stk_ptr = (char*)sbrk(stack_bytes)) == -1)
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+
+/* Sanity check
+ printf("Argv = (%d,%d), Envp=(%d,%d), stack=%d\n",
+ argv_count, argv_len, envp_count, envp_len, stack_bytes);
+*/
+
+ /* Now copy in the strings */
+ pip=(unsigned short *) stk_ptr;
+ pcp=stk_ptr+2*(1+argv_count+1+envp_count+1);
+
+ /* baseoff = stk_ptr + stack_bytes; */
+ baseoff = stk_ptr;
+ *pip++ = argv_count;
+ for(p=interp; p && *p; p++)
+ {
+ int l;
+ *pip++ = pcp-baseoff;
+ l = strlen(*p)+1;
+ memcpy(pcp, *p, l);
+ pcp += l;
+ }
+ for(p=argv; p && *p; p++)
+ {
+ int l;
+ *pip++ = pcp-baseoff;
+ l = strlen(*p)+1;
+ memcpy(pcp, *p, l);
+ pcp += l;
+ }
+ *pip++ = 0;
+
+ for(p=envp; p && *p; p++)
+ {
+ int l;
+ *pip++ = pcp-baseoff;
+ l = strlen(*p)+1;
+ memcpy(pcp, *p, l);
+ pcp += l;
+ }
+ *pip++ = 0;
+
+ rv = __exec(fname, stk_ptr, stack_bytes);
+ /* FIXME: This will probably have to interpret '#!' style exe's */
+ sbrk(-stack_bytes);
+ return rv;
+}
+#endif
+#endif
diff --git a/libc/syscall/mksys386 b/libc/i386sys/mksyscall
index 5abcbf8..d9b7f3a 100644
--- a/libc/syscall/mksys386
+++ b/libc/i386sys/mksyscall
@@ -13,9 +13,9 @@
# 0 = each is complete
# 1 = Short codes calling common function
-rm -f syscall.c syscall.mak call_tab.v defn_tab.v
+rm -f syscall.c syscall.mak
-tr '[A-Z]' '[a-z]' < sys386.dat | \
+tr '[A-Z]' '[a-z]' < syscall.dat | \
awk 'BEGIN{
print "# Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>" > "syscall.mak";
print "# This file is part of the Linux-8086 C library and is distributed" > "syscall.mak";
@@ -129,24 +129,15 @@ END{
cat >> syscall.mak <<\!
-TOP=..
-include $(TOP)/Make.defs
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
-all: $(OBJ)
+all: $(LIBC)($(OBJ))
+ @:
-libc.a: $(OBJ)
- ar r ../$(LIBC) $(OBJ)
- @touch libc.a
-
-$(OBJ): sys386.dat mksys386
- $(CC) $(CFLAGS) -c -DL_$* -o $@ syscall.c
+$(LIBC)($(OBJ)): syscall.dat
+ $(CC) $(CFLAGS) -DL_$* syscall.c -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
!
-rv=$?
-if [ "$rv" != 0 ]
-then exit $rv
-fi
-
-export MAKELEVEL
-MAKELEVEL=0
-exec make -f syscall.mak $1
+exit $?
diff --git a/libc/i386sys/signal.c b/libc/i386sys/signal.c
new file mode 100644
index 0000000..dad3389
--- /dev/null
+++ b/libc/i386sys/signal.c
@@ -0,0 +1,99 @@
+
+#ifndef __MSDOS__
+#ifdef __AS386_16__
+
+#include <errno.h>
+#include <signal.h>
+
+typedef __sighandler_t Sig;
+
+extern int __signal __P((int, __sighandler_t));
+static Sig system_signal();
+
+Sig __sigtable[_NSIG-1];
+
+/*
+ * Signal handler.
+ *
+ */
+
+/*
+ * KERNEL INTERFACE:
+ * It is assumed the kernel will never give us a signal we haven't
+ * _explicitly_ asked for!
+ *
+ * The Kernel need only save space for _one_ function pointer
+ * (to system_signal) and must deal with SIG_DFL and SIG_IGN
+ * in kernel space.
+ *
+ * When a signal is required the kernel must set all the registers as if
+ * returning from a interrupt normally then push the number of the signal
+ * to be generated, push the current pc value, then set the pc to the
+ * address of the 'system_signal' function.
+ */
+
+Sig
+signal(number, pointer)
+int number;
+Sig pointer;
+{
+ Sig old_sig;
+ int rv;
+ if( number < 1 || number >= _NSIG ) { errno=EINVAL; return SIG_ERR; }
+
+ if( pointer == SIG_DFL || pointer == SIG_IGN )
+ rv = __signal(number, pointer);
+ else
+ rv = __signal(number, (__sighandler_t) system_signal);
+
+ if( rv < 0 ) return SIG_ERR;
+
+ old_sig = __sigtable[number-1];
+ __sigtable[number-1] = pointer;
+
+ switch(rv)
+ {
+ case 0: return SIG_DFL;
+ case 1: return SIG_IGN;
+ return old_sig;
+ }
+}
+
+#asm
+ .text
+_system_signal: ! When this is called by the kernel the stack contains
+ pushf ! in order:
+ push ax !
+ push bx ! The signal number, (NOS)
+ push cx ! The program counter, (TOS)
+ push dx !
+ push si ! It does NOT contain the CS register or the flags.
+ push di ! This means it cannot be unraveled by an iret.
+ push bp
+ push es ! Note also only ES segment register is saved.
+ mov bx,sp ! Unlike minix the rv from a system call is in AX.
+ mov bx,[bx+20]
+#if __FIRST_ARG_IN_AX__
+ mov ax,bx
+#else
+ push bx ! NB this is _unchecked_, do we want to ?
+#endif
+ add bx,bx
+ mov bx,[bx+___sigtable-2] ! Offset by 2 cause no entry for signal 0
+ call bx ! Do we want to check BX for 0 or 1 ?
+ inc sp
+ inc sp
+ pop es
+ pop bp
+ pop di
+ pop si
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ popf
+ ret #2 ! Get rid of the signum too.
+#endasm
+
+#endif /* __AS386_16__ */
+#endif /* __MSDOS__ */
diff --git a/libc/syscall/sys386.dat b/libc/i386sys/syscall.dat
index da9ad6c..da9ad6c 100644
--- a/libc/syscall/sys386.dat
+++ b/libc/i386sys/syscall.dat
diff --git a/libc/i386sys/syslibc.c b/libc/i386sys/syslibc.c
new file mode 100644
index 0000000..60dda42
--- /dev/null
+++ b/libc/i386sys/syslibc.c
@@ -0,0 +1,255 @@
+/* Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/times.h>
+
+/* MSDOS has it's own versions */
+#ifndef __MSDOS__
+#ifdef __AS386_32__
+
+/********************** Function __cstartup *******************************/
+
+#ifdef L___cstart3
+
+void (*__cleanup)() = 0;
+char ** environ;
+
+#asm
+ loc 2
+call_main:
+ .long _main ! Segment 2 is the trailing pointers, main and the
+ .long call_exit ! routine to call exit.
+#if __FIRST_ARG_IN_AX__
+ .data
+saved_arg1:
+ .long 0
+#endif
+ .data
+loop_safe:
+ .long 0
+ .text
+
+export ___mkargv
+___mkargv: ! BCC Tells linker to init argv ... none needed.
+
+export ___cstartup
+___cstartup: ! Crt0 startup (Linux style)
+ mov eax,[esp]
+ test eax,eax
+ jz call_exit ! If argc == 0 this is being called by ldd, exit.
+ mov eax,[esp+8]
+ mov [_environ],eax
+#if __FIRST_ARG_IN_AX__
+ pop [saved_arg1] ! Argc will go into eax
+#endif
+
+ mov ebx,#auto_start ! Pointer to first autostart function
+auto_run:
+#if __FIRST_ARG_IN_AX__
+ mov eax,[saved_arg1]
+#endif
+ mov [loop_safe],ebx
+ mov ebx,[ebx]
+ test ebx,ebx
+ jz no_func
+ call ebx ! Call the function
+no_func:
+ mov ebx,[loop_safe]
+ add ebx,#4 ! next
+ jmp auto_run ! And round for the next.
+
+call_exit: ! Last item called by above.
+ pop ebx ! Be tidy.
+#if !__FIRST_ARG_IN_AX__
+ push eax ! At the end the last called was main() push it`s
+#endif
+ call _exit ! return val and call exit();
+bad_exit:
+ jmp bad_exit ! Exit returned !!
+
+export _exit
+export __exit
+_exit: ! exit(rv) function
+#if __FIRST_ARG_IN_AX__
+ mov [saved_arg1],eax
+#else
+ push [esp+4] ! Copy the `rv` for the exit fuctions.
+#endif
+ mov ebx,[___cleanup] ! Call exit, normally this is `__do_exit`
+ test ebx,ebx
+ je no_clean ! But it`s default is null
+ call ebx
+no_clean:
+#if __FIRST_ARG_IN_AX__
+ mov eax,[saved_arg1]
+#else
+ add esp,#4
+#endif
+__exit: ! _exit(rv)
+ br ___exit ! This is just an alias for __exit();
+
+#endasm
+#endif
+
+/********************** Function time ************************************/
+
+#ifdef L_time
+time_t time(where)
+time_t *where;
+{
+ struct timeval rv;
+ if( gettimeofday(&rv, (void*)0) < 0 ) return -1;
+ if(where) *where = rv.tv_sec;
+ return rv.tv_sec;
+}
+#endif
+
+/********************** Function abort ************************************/
+
+#ifdef L_abort
+#include <signal.h>
+
+int abort()
+{
+ signal(SIGABRT, SIG_DFL);
+ kill(SIGABRT, getpid()); /* Correct one */
+ pause(); /* System may just schedule */
+ signal(SIGKILL, SIG_DFL);
+ kill(SIGKILL, getpid()); /* Can't trap this! */
+ __exit(255); /* WHAT!! */
+}
+#endif
+
+/********************** Function wait ************************************/
+
+#ifdef L_wait
+int
+wait(status)
+int * status;
+{
+ return wait4(-1, status, 0, (void*)0);
+}
+#endif
+
+/********************** Function wait3 **************************************/
+
+#ifdef L_wait3
+int
+wait3(status, opts, usage)
+int * status;
+int opts;
+struct rusage * usage;
+{
+ return wait4(-1, status, opts, usage);
+}
+#endif
+
+/********************** Function waitpid ************************************/
+
+#ifdef L_waitpid
+int
+waitpid(pid, status, opts)
+int pid;
+int * status;
+int opts;
+{
+ return wait4(pid, status, opts, (void*)0);
+}
+#endif
+
+/********************** Function killpg ************************************/
+
+#ifdef L_killpg
+int
+killpg(pid, sig)
+int pid;
+int sig;
+{
+ if(pid == 0)
+ pid = getpgrp();
+ if(pid > 1)
+ return kill(-pid, sig);
+ errno = EINVAL;
+ return -1;
+}
+#endif
+
+/********************** Function setpgrp ************************************/
+
+#ifdef L_setpgrp
+int
+setpgrp()
+{
+ return setpgid(0,0);
+}
+#endif
+
+/********************** Function sleep ************************************/
+
+#ifdef L_sleep
+#include <signal.h>
+
+/* This uses SIGALRM, it does keep the previous alarm call but will lose
+ * any alarms that go off during the sleep
+ */
+
+static void alrm() { }
+
+unsigned int sleep(seconds)
+unsigned int seconds;
+{
+ void (*last_alarm)();
+ unsigned int prev_sec;
+
+ prev_sec = alarm(0);
+ if( prev_sec <= seconds ) prev_sec = 1; else prev_sec -= seconds;
+
+ last_alarm = signal(SIGALRM, alrm);
+ alarm(seconds);
+ pause();
+ seconds = alarm(prev_sec);
+ signal(SIGALRM, last_alarm);
+ return seconds;
+}
+#if 0
+ /* Is this a better way ? If we have select of course :-) */
+#include <sys/time.h>
+unsigned int
+sleep(seconds)
+unsigned int seconds;
+{
+ struct timeval timeout;
+ time_t start = time((void*)0);
+ timeout.tv_sec = seconds;
+ timeout.tv_usec = 0;
+ select(1, NULL, NULL, NULL, &timeout);
+ return seconds - (time((void*)0) - start);
+}
+#endif
+
+#endif
+
+/********************** Function usleep ************************************/
+
+#ifdef L_usleep
+#include <sys/time.h>
+void
+usleep(useconds)
+unsigned long useconds;
+{
+ struct timeval timeout;
+ timeout.tv_sec = useconds%1000000L;
+ timeout.tv_usec = useconds/1000000L;
+ select(1, NULL, NULL, NULL, &timeout);
+}
+#endif
+
+/********************** THE END ********************************************/
+
+#endif /* __MSDOS__ */
+#endif
diff --git a/libc/include/setjmp.h b/libc/include/setjmp.h
index c2bfadb..162743b 100644
--- a/libc/include/setjmp.h
+++ b/libc/include/setjmp.h
@@ -17,10 +17,14 @@ typedef struct
unsigned int di;
} jmp_buf[1];
-int setjmp __P((jmp_buf env));
-void longjmp __P((jmp_buf env, int rv));
+int _setjmp __P((jmp_buf env));
+void _longjmp __P((jmp_buf env, int rv));
/* LATER: Seems GNU beat me to it, must be OK then :-)
* Humm, what's this about setjmp being a macro !?
+ * Ok, use the BSD names as normal use the ANSI as macros
*/
+
+#define setjmp(a_env) _setjmp(a_env)
+#define longjmp(a_env, a_rv) _longjmp(a_env, a_rv)
#endif
diff --git a/libc/include/stdarg.h b/libc/include/stdarg.h
index d30fbd8..321e664 100644
--- a/libc/include/stdarg.h
+++ b/libc/include/stdarg.h
@@ -41,3 +41,7 @@
#endif
#endif /* __STDARG_H */
+
+#if __FIRST_ARG_IN_AX__
+#error First arg is in a register, stdarg.h cannot take its address
+#endif
diff --git a/libc/include/sys/stat.h b/libc/include/sys/stat.h
index d21f986..b1cf558 100644
--- a/libc/include/sys/stat.h
+++ b/libc/include/sys/stat.h
@@ -34,9 +34,9 @@ struct stat {
unsigned long __unused4;
unsigned long __unused5;
};
+#endif
-#else
-
+#ifdef __AS386_16__
struct stat
{
dev_t st_dev;
diff --git a/libc/kinclude/Makefile b/libc/kinclude/Makefile
index 8982f57..aa4ef72 100644
--- a/libc/kinclude/Makefile
+++ b/libc/kinclude/Makefile
@@ -2,14 +2,8 @@
# This file is part of the Linux-8086 C library and is distributed
# under the GNU Library General Public License.
-TOP=..
-include $(TOP)/Make.defs
-
-OBJ=
-
-all: $(OBJ)
-
-libc.a:
+all:
+ @:
transfer:
-@rm -f ../include/linuxmt
diff --git a/libc/malloc1/Makefile b/libc/malloc1/Makefile
index 6322454..a4107b8 100644
--- a/libc/malloc1/Makefile
+++ b/libc/malloc1/Makefile
@@ -1,24 +1,23 @@
-
-TOP=..
-include $(TOP)/Make.defs
+# Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+# This file is part of the Linux-8086 C library and is distributed
+# under the GNU Library General Public License.
ASRC=malloc.c
AOBJ=malloc.o alloca.o free.o calloc.o realloc.o
-OBJ=$(AOBJ)
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
-all: $(OBJ)
+all: $(LIBC)($(AOBJ))
+ @:
-libc.a: $(OBJ)
- ar r ../$(LIBC) $(OBJ)
- @touch libc.a
+$(LIBC)($(AOBJ)): $(ASRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
clean:
rm -f *.o libc.a
-$(AOBJ): $(ASRC)
- $(CC) $(CFLAGS) -c -DL_$* -o $@ $(ASRC)
-
transfer:
-@rm ../include/malloc.h
cp -p malloc.h ../include/.
diff --git a/libc/malloc2/Makefile b/libc/malloc2/Makefile
index 0396df2..ea944db 100644
--- a/libc/malloc2/Makefile
+++ b/libc/malloc2/Makefile
@@ -1,22 +1,12 @@
-TOP=..
-include $(TOP)/Make.defs
+OBJ=malloc.o stack.o
-MOBJ=malloc.o stack.o
-
-OBJ=$(MOBJ)
-
-all: $(OBJ)
-
-libc.a: $(OBJ)
- ar r ../$(LIBC) $(OBJ)
- @touch libc.a
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
+all: $(LIBC)($(OBJ))
+ @:
clean:
- rm -f $(OBJ) libc.a
-
-$(AOBJ): $(ASRC)
- $(CC) $(CFLAGS) -c -DL_$* -o $@ $(ASRC)
+ rm -f *.o libc.a
transfer:
-@rm ../include/malloc.h
diff --git a/libc/misc/Makefile b/libc/misc/Makefile
index c7ed8fa..9bb579c 100644
--- a/libc/misc/Makefile
+++ b/libc/misc/Makefile
@@ -2,9 +2,6 @@
# This file is part of the Linux-8086 C library and is distributed
# under the GNU Library General Public License.
-TOP=..
-include $(TOP)/Make.defs
-
MSRC=aliases.c
MOBJ=abs.o raise.o bcopy.o bzero.o bcmp.o index.o rindex.o remove.o creat.o
@@ -29,31 +26,37 @@ ifneq ($(LIB_CPU),i86)
OBJ+=strtod.o
endif
-all: $(OBJ)
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
+
+all: $(LIBC)
+ @:
+
+$(LIBC): $(LIBC)($(OBJ))
+
+$(LIBC)($(MOBJ)): $(MSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
-libc.a: $(OBJ)
- ar r ../$(LIBC) $(OBJ)
- @touch libc.a
+$(LIBC)($(EOBJ)): $(ESRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
clean:
rm -f *.o libc.a
-$(MOBJ): $(MSRC)
- $(CC) $(CFLAGS) -c -DL_$* -o $@ $(MSRC)
+$(LIBC)(strtol.o): strtol.c
+ $(CC) -c -ansi $(ARCH) $(CCFLAGS) $(DEFS) $*.c
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
-$(EOBJ): $(ESRC)
- $(CC) $(CFLAGS) -c -DL_$* -o $@ $(ESRC)
+$(LIBC)(strtod.o): strtod.c
+ $(CC) -c -ansi $(ARCH) $(CCFLAGS) $(DEFS) $*.c
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
-crypt.o: crypt.c
-ifeq ($(LIB_CPU),g386)
- $(CC) $(CFLAGS) $< -c -o $@ $(WALL)
-else
- $(CC) $(CFLAGS) $< -c -o $@ -ansi
-endif
-
-strto%.o: strto%.c
-ifeq ($(LIB_CPU),g386)
- $(CC) $(CFLAGS) $< -c -o $@ $(WALL)
-else
- $(CC) $(CFLAGS) $< -c -o $@ -ansi
-endif
+$(LIBC)(crypt.o): crypt.c
+ $(CC) -c -ansi $(ARCH) $(CCFLAGS) $(DEFS) $*.c
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
diff --git a/libc/misc/strtod.c b/libc/misc/strtod.c
index 8acb423..cef9d9f 100644
--- a/libc/misc/strtod.c
+++ b/libc/misc/strtod.c
@@ -20,6 +20,9 @@
#include <stdlib.h>
#include <ctype.h>
+#ifndef __AS386_16__
+/* BCC-16 has broken FP code */
+
double
strtod(const char *nptr, char ** endptr)
{
@@ -94,3 +97,4 @@ strtod(const char *nptr, char ** endptr)
}
return (negative ? -number:number);
}
+#endif
diff --git a/libc/msdos/Makefile b/libc/msdos/Makefile
index f069699..7a5eaa6 100644
--- a/libc/msdos/Makefile
+++ b/libc/msdos/Makefile
@@ -2,9 +2,6 @@
# This file is part of the Linux-8086 C library and is distributed
# under the GNU Library General Public License.
-TOP=..
-include $(TOP)/Make.defs
-
ASRC=msdos.c
AOBJ= dos_start.o __mkargv.o __mkenvp.o dos__fconv.o dos_read.o \
dos_write.o dos_open.o dos_close.o dos_unlink.o dos_lseek.o \
@@ -17,24 +14,32 @@ BOBJ= __seg_regs.o __peek_es.o __poke_es.o __deek_es.o __doke_es.o \
ifeq ($(LIB_CPU),i86)
ifeq ($(LIB_OS),DOS)
-OBJ=$(AOBJ) $(BOBJ)
+OBJ=$(AOBJ) $(BOBJ) time.o
else
OBJ=$(BOBJ)
endif
-endif
-all: $(OBJ)
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
-libc.a: $(OBJ)
- ar r ../$(LIBC) $(OBJ)
- @touch libc.a
+all: $(LIBC)
+ @:
-clean:
- rm -f *.o libc.a
+$(LIBC): $(LIBC)($(OBJ))
-$(AOBJ): $(ASRC)
- $(CC) $(CFLAGS) -c -DL_$* -o $@ $(ASRC)
+$(LIBC)($(AOBJ)): $(ASRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
-$(BOBJ): $(BSRC)
- $(CC) $(CFLAGS) -c -DL_$* -o $@ $(BSRC)
+$(LIBC)($(BOBJ)): $(BSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+else
+all:
+ @:
+endif
+
+clean:
+ rm -f *.o libc.a
diff --git a/libc/pwd/Config b/libc/pwd/Config
deleted file mode 100644
index b5aaad0..0000000
--- a/libc/pwd/Config
+++ /dev/null
@@ -1 +0,0 @@
-pwd: /etc/passwd managment
diff --git a/libc/regexp/Makefile b/libc/regexp/Makefile
index 71c2b81..0276aba 100644
--- a/libc/regexp/Makefile
+++ b/libc/regexp/Makefile
@@ -1,28 +1,27 @@
-TOP=..
-include $(TOP)/Make.defs
-
OBJ=regexp.o regsub.o
LSRC=regexp.c regsub.c regerror.c
-try: try.o $(OBJ)
- $(CC) $(CFLAGS) try.o $(OBJ) -o try
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
-# Regression test.
-test: try tests
- @echo 'No news is good news...'
- try <tests
+all: $(LIBC)
+ @:
-libc.a: $(OBJ)
- ar r ../$(LIBC) $(OBJ)
- @touch libc.a
+$(LIBC): $(LIBC)($(OBJ))
transfer:
-@rm -f ../include/regexp.h ../include/regmagic.h
cp -p regexp.h regmagic.h ../include/.
-regexp.o: regexp.c regexp.h regmagic.h
-regsub.o: regsub.c regexp.h regmagic.h
+$(LIBC)(regexp.o): regexp.c regexp.h regmagic.h
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+$(LIBC)(regsub.o): regsub.c regexp.h regmagic.h
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
clean:
rm -f libc.a *.o core mon.out timer.t.h dMakefile dtr try timer
diff --git a/libc/stdio2/Makefile b/libc/stdio2/Makefile
index f77df3a..80f2e3b 100644
--- a/libc/stdio2/Makefile
+++ b/libc/stdio2/Makefile
@@ -1,6 +1,6 @@
-
-TOP=..
-include $(TOP)/Make.defs
+# Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+# This file is part of the Linux-8086 C library and is distributed
+# under the GNU Library General Public License.
ifneq ($(LIB_CPU),i86)
CFLAGS=$(CCFLAGS) $(LIBDEFS) -DFLOATS
@@ -19,11 +19,27 @@ SOBJ=scanf.o sscanf.o fscanf.o vscanf.o vsscanf.o vfscanf.o
OBJ= $(AOBJ) $(POBJ) $(SOBJ)
-all: $(OBJ)
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
+
+all: $(LIBC)
+ @:
+
+$(LIBC): $(LIBC)($(OBJ))
+
+$(LIBC)($(AOBJ)): $(ASRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
-libc.a: $(OBJ)
- ar r ../$(LIBC) $(OBJ)
- @touch libc.a
+$(LIBC)($(POBJ)): $(PSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+$(LIBC)($(SOBJ)): $(SSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
transfer:
-@rm -f ../include/stdio.h
@@ -32,14 +48,5 @@ transfer:
clean:
rm -f *.o libc.a
-$(OBJ): stdio.h
-
-$(AOBJ): $(ASRC)
- $(CC) $(CFLAGS) -c -DL_$* -o $@ $(ASRC)
-
-$(POBJ): $(PSRC)
- $(CC) $(CFLAGS) -c -DL_$* -o $@ $(PSRC)
-
-$(SOBJ): $(SSRC)
- $(CC) $(CFLAGS) -c -DL_$* -o $@ $(SSRC)
+$(LIBC)($(OBJ)): stdio.h
diff --git a/libc/stdio2/printf.c b/libc/stdio2/printf.c
index 5a5744d..45c4aa7 100644
--- a/libc/stdio2/printf.c
+++ b/libc/stdio2/printf.c
@@ -19,7 +19,13 @@
#include <sys/types.h>
#include <fcntl.h>
+#ifdef __STDC__
#include <stdarg.h>
+#define va_strt va_start
+#else
+#include <varargs.h>
+#define va_strt(p,i) va_start(p)
+#endif
#include "stdio.h"
@@ -28,13 +34,14 @@
#ifdef __STDC__
int printf(const char * fmt, ...)
#else
-int printf(fmt)
+int printf(fmt, va_alist)
__const char *fmt;
+va_dcl
#endif
{
va_list ptr;
int rv;
- va_start(ptr, fmt);
+ va_strt(ptr, fmt);
rv = vfprintf(stdout,fmt,ptr);
va_end(ptr);
return rv;
@@ -45,9 +52,10 @@ __const char *fmt;
#ifdef __STDC__
int sprintf(char * sp, const char * fmt, ...)
#else
-int sprintf(sp, fmt)
+int sprintf(sp, fmt, va_alist)
char * sp;
__const char *fmt;
+va_dcl
#endif
{
static FILE string[1] =
@@ -58,7 +66,7 @@ static FILE string[1] =
va_list ptr;
int rv;
- va_start(ptr, fmt);
+ va_strt(ptr, fmt);
string->bufpos = sp;
rv = vfprintf(string,fmt,ptr);
va_end(ptr);
@@ -71,14 +79,15 @@ static FILE string[1] =
#ifdef __STDC__
int fprintf(FILE * fp, const char * fmt, ...)
#else
-int fprintf(fp, fmt)
+int fprintf(fp, fmt, va_alist)
FILE * fp;
__const char *fmt;
+va_dcl
#endif
{
va_list ptr;
int rv;
- va_start(ptr, fmt);
+ va_strt(ptr, fmt);
rv = vfprintf(fp,fmt,ptr);
va_end(ptr);
return rv;
diff --git a/libc/stdio2/scanf.c b/libc/stdio2/scanf.c
index c43320d..2d61ab2 100644
--- a/libc/stdio2/scanf.c
+++ b/libc/stdio2/scanf.c
@@ -1,19 +1,27 @@
#include <stdio.h>
#include <ctype.h>
-#include <stdarg.h>
#include <string.h>
+#ifdef __STDC__
+#include <stdarg.h>
+#define va_strt va_start
+#else
+#include <varargs.h>
+#define va_strt(p,i) va_start(p)
+#endif
+
#ifdef L_scanf
#ifdef __STDC__
int scanf(const char * fmt, ...)
#else
-int scanf(fmt)
+int scanf(fmt, va_alist)
__const char *fmt;
+va_dcl
#endif
{
va_list ptr;
int rv;
- va_start(ptr, fmt);
+ va_strt(ptr, fmt);
rv = vfscanf(stdin,fmt,ptr);
va_end(ptr);
return rv;
@@ -24,9 +32,10 @@ __const char *fmt;
#ifdef __STDC__
int sscanf(char * sp, const char * fmt, ...)
#else
-int sscanf(sp, fmt)
+int sscanf(sp, fmt, va_alist)
char * sp;
__const char *fmt;
+va_dcl
#endif
{
static FILE string[1] =
@@ -37,7 +46,7 @@ static FILE string[1] =
va_list ptr;
int rv;
- va_start(ptr, fmt);
+ va_strt(ptr, fmt);
string->bufpos = sp;
rv = vfscanf(string,fmt,ptr);
va_end(ptr);
@@ -49,14 +58,15 @@ static FILE string[1] =
#ifdef __STDC__
int fscanf(FILE * fp, const char * fmt, ...)
#else
-int fscanf(fp, fmt)
+int fscanf(fp, fmt, va_alist)
FILE * fp;
__const char *fmt;
+va_dcl
#endif
{
va_list ptr;
int rv;
- va_start(ptr, fmt);
+ va_strt(ptr, fmt);
rv = vfscanf(fp,fmt,ptr);
va_end(ptr);
return rv;
diff --git a/libc/stdio2/stdio.c b/libc/stdio2/stdio.c
index bab246b..156d3e3 100644
--- a/libc/stdio2/stdio.c
+++ b/libc/stdio2/stdio.c
@@ -506,12 +506,12 @@ int ref;
{
/* Use fflush to sync the pointers */
-#if 0
+#if 1
/* if __MODE_READING and no ungetc ever done can just move pointer */
/* This needs testing! */
if ( (fp->mode &(__MODE_READING | __MODE_UNGOT)) == __MODE_READING &&
- ( ref == SEEK_SET || ref == SEEK_CUR )
+ ( ref == SEEK_SET || ref == SEEK_CUR ))
{
long fpos = lseek(fp->fd, 0L, SEEK_CUR);
if( fpos == -1 ) return EOF;
diff --git a/libc/string/Makefile b/libc/string/Makefile
index d72c2e0..61fad41 100644
--- a/libc/string/Makefile
+++ b/libc/string/Makefile
@@ -2,9 +2,6 @@
# This file is part of the Linux-8086 C library and is distributed
# under the GNU Library General Public License.
-TOP=..
-include $(TOP)/Make.defs
-
SSRC=string.c
SOBJ=strlen.o strcat.o strcpy.o strcmp.o strncat.o strncpy.o strncmp.o \
strchr.o strrchr.o strdup.o memcpy.o memccpy.o memchr.o memset.o \
@@ -13,19 +10,21 @@ SOBJ=strlen.o strcat.o strcpy.o strcmp.o strncat.o strncpy.o strncmp.o \
OBJ=$(SOBJ) strpbrk.o strsep.o strstr.o strtok.o strcspn.o \
strspn.o strcasecmp.o strncasecmp.o
-all: $(OBJ)
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
+
+all: $(LIBC)
+ @:
+
+$(LIBC): $(LIBC)($(OBJ))
-libc.a: $(OBJ)
- ar r ../$(LIBC) $(OBJ)
- @touch libc.a
+$(LIBC)($(SOBJ)): $(SSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
transfer:
-@rm -f ../include/string.h
cp -p string.h ../include/.
clean:
- rm -f *.o libc.a
-
-$(SOBJ): $(SSRC)
- $(CC) $(CFLAGS) -c -DL_$* -o $@ $(SSRC)
-
+ rm -f *.o
diff --git a/libc/syscall/Makefile b/libc/syscall/Makefile
index b487655..fd1b187 100644
--- a/libc/syscall/Makefile
+++ b/libc/syscall/Makefile
@@ -2,67 +2,63 @@
# This file is part of the Linux-8086 C library and is distributed
# under the GNU Library General Public License.
-TOP=..
-include $(TOP)/Make.defs
-
LSRC=syslibc.c
-LOBJ=time.o abort.o wait.o waitpid.o killpg.o setpgrp.o sleep.o \
+LOBJ=time.o abort.o wait.o waitpid.o wait3.o killpg.o setpgrp.o sleep.o \
usleep.o
-LSRC3=syslib3.c
-LOBJ3=__cstart3.o
-
LSRC0=syslib0.c
LOBJ0=__cstartup.o lseek.o getpid.o getppid.o getuid.o geteuid.o getgid.o \
getegid.o dup2.o dup.o getpgrp.o times.o
ESRC=exec.c
-E2OBJ=execl.o execv.o execle.o execlp.o execvp.o
-EOBJ=execve.o $(E2OBJ)
+EOBJ=execve.o execl.o execv.o execle.o execlp.o execvp.o
DSRC=dirent.c
DOBJ=opendir.o closedir.o readdir.o
ifeq ($(LIB_CPU)-$(LIB_OS),i86-ELKS)
-SYSCALLS=sh mksyscall
OBJ=$(LOBJ0) $(LOBJ) $(DOBJ) $(EOBJ) signal.o setjmp.o
-DEP=mksyscall syscall.dat
-endif
-
-ifeq ($(LIB_CPU)-$(LIB_OS),i386-ELKS)
-SYSCALLS=sh mksys386
-OBJ=setjmp.o $(LOBJ3) $(LOBJ) $(E2OBJ) $(DOBJ)
-DEP=mksys386 sys386.dat
+SYSCALLS=call_i86
endif
ifeq ($(SYSCALLS),)
-SYSCALLS=true
OBJ=setjmp.o
-DEP=
endif
-all: $(DEP) $(OBJ)
- $(SYSCALLS)
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
-libc.a: $(DEP) $(OBJ)
- $(SYSCALLS) libc.a
- ar r ../$(LIBC) $(OBJ)
- @touch libc.a
+all: $(SYSCALLS) $(LIBC)
+ @:
-clean:
- rm -f *.o libc.a syscall.c syscall.mak call_tab.v defn_tab.v
+call_i86: syscall.mak
+ $(MAKE) -f syscall.mak LIBC="$(LIBC)" CFLAGS="$(CFLAGS)"
+
+syscall.mak: mksyscall syscall.dat
+ sh mksyscall
-$(LOBJ): $(LSRC)
- $(CC) $(CFLAGS) -c -DL_$* -o $@ $(LSRC)
+$(LIBC): $(LIBC)($(OBJ))
-$(DOBJ): $(DSRC)
- $(CC) $(CFLAGS) -c -DL_$* -o $@ $(DSRC)
+$(LIBC)($(LOBJ)): $(LSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
-$(EOBJ): $(ESRC)
- $(CC) $(CFLAGS) -c -DL_$* -o $@ $(ESRC)
+$(LIBC)($(DOBJ)): $(DSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
-$(LOBJ0): $(LSRC0)
- $(CC) $(CFLAGS) -c -DL_$* -o $@ $(LSRC0)
+$(LIBC)($(EOBJ)): $(ESRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
-$(LOBJ3): $(LSRC3)
- $(CC) $(CFLAGS) -c -DL_$* -o $@ $(LSRC3)
+$(LIBC)($(LOBJ0)): $(LSRC0)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+clean:
+ rm -f *.o libc.a
+ rm -f syscall.c syscall.mak
+ rm -f call_tab.v defn_tab.v
diff --git a/libc/syscall/TODO b/libc/syscall/TODO
index 90085d9..b178a96 100644
--- a/libc/syscall/TODO
+++ b/libc/syscall/TODO
@@ -1,5 +1,3 @@
-It appears that a 386 version of the syscall libs is also wanted ...
-
SYSV IPC, there's and __ipc syscall and the hardware can manage messages and
semaphores.
diff --git a/libc/syscall/getinfo.c b/libc/syscall/getinfo.c
deleted file mode 100644
index a5ab89a..0000000
--- a/libc/syscall/getinfo.c
+++ /dev/null
@@ -1,32 +0,0 @@
-
-#define PERM_GETINFO 0x100
-#define PERM_GETGROUP 0x200
-
-struct {
- int pid;
- int ppid;
- int uid;
- int gid;
- int euid;
- int egid;
-}
- __info_safe;
-
-getgroups(count, locn)
-int count;
-void * locn;
-{
- if( count < 0 ) {errno = EINVAL; return -1; }
- return __permissions(PERM_GETGROUP, count, locn);
-}
-
-getpid()
-{
- __permissions(PERM_GETINFO, 6, &__info_safe);
- return __info_safe.pid;
-}
-
-getppid()
-{
- return __permissions(PERM_GETITEM(1) /*, 0, 0 */);
-}
diff --git a/libc/syscall/mksyscall b/libc/syscall/mksyscall
index 1e98836..2005029 100644
--- a/libc/syscall/mksyscall
+++ b/libc/syscall/mksyscall
@@ -277,24 +277,13 @@ END{
cat >> syscall.mak <<\!
-TOP=..
-include $(TOP)/Make.defs
+all: $(LIBC)($(OBJ))
+ @:
-all: $(OBJ)
-
-libc.a: $(OBJ)
- ar r ../$(LIBC) $(OBJ)
- @touch libc.a
-
-$(OBJ): syscall.dat mksyscall
- $(CC) $(CFLAGS) -c -DL_$* -o $@ syscall.c
+$(LIBC)($(OBJ)): syscall.dat
+ $(CC) $(CFLAGS) -DL_$* syscall.c -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
!
-rv=$?
-if [ "$rv" != 0 ]
-then exit $rv
-fi
-
-export MAKELEVEL
-MAKELEVEL=0
-exec make -f syscall.mak $1
+exit $?
diff --git a/libc/syscall/setjmp.c b/libc/syscall/setjmp.c
index 52c3ff1..58b57ad 100644
--- a/libc/syscall/setjmp.c
+++ b/libc/syscall/setjmp.c
@@ -8,6 +8,9 @@ setjmp(env)
jmp_buf env;
{
#asm
+export __setjmp
+__setjmp:
+
pop cx ! PC
#if __FIRST_ARG_IN_AX__
mov bx,ax
@@ -31,6 +34,9 @@ jmp_buf env;
int rv;
{
#asm
+export __longjmp
+__longjmp:
+
pop cx ! pc
#if __FIRST_ARG_IN_AX__
mov bx,ax ! env->
diff --git a/libc/syscall/syscall.dat.chad b/libc/syscall/syscall.dat.chad
new file mode 100644
index 0000000..a6e8b06
--- /dev/null
+++ b/libc/syscall/syscall.dat.chad
@@ -0,0 +1,55 @@
+exit 1 1 * c exit does stdio, _exit in crt0
+fork 2 0
+read 3 3
+write 4 3
+open 5 3
+close 6 1
+wait 7 0 . THIS one is different
+creat 8 0 . THIS one is different
+link 9 2
+unlink 10 1
+exec 11 3 * minix style exec
+chdir 12 1
+time 13 0 . THIS one is different
+mknod 14 3
+chmod 15 2
+chown 16 3
+brk 17 1 * This is only to tell the system
+stat 18 2
+lseek 19 3 * nb 2nd arg is an io ptr to long not a long.
+getpid 20 1 * this gets both pid & ppid
+mount 21 5
+umount 22 1
+setuid 23 1
+getuid 24 1 * this gets both uid and euid
+stime 25 2 - this must not exist - even as a libc.
+ptrace 26 4
+alarm 27 2
+fstat 28 2
+pause 29 0
+utime 30 2
+access 33 2
+nice 34 1 .
+sleep 35 0 . THIS one is different
+sync 36 0
+kill 37 2
+rename 38 2
+mkdir 39 2
+rmdir 40 1
+dup 41 1 - using nasty fcntl function
+pipe 42 1
+times 43 2 * 2nd arg is pointer for long ret val.
+profil 44 0
+setgid 46 1
+getgid 47 1 * this gets both gid and egid
+signal 48 2 * have put the despatch table in user space.
+getinfo 49 1 - possible? gets pid,ppid,uid,euid etc
+fcntl 50 3
+acct 51 1 -
+phys 52 0 . THIS one is different
+lock 53 0 . THIS one is different
+ioctl 54 3 . make this and fcntl the same ?
+reboot 55 3 . the magic number is 0xfee1,0xdead,...
+mpx 56 0 . THIS one is different
+dup2 57 0 . THIS one is different
+umask 60 1
diff --git a/libc/syscall/syscall.dat.code b/libc/syscall/syscall.dat.code
new file mode 100644
index 0000000..a91ca86
--- /dev/null
+++ b/libc/syscall/syscall.dat.code
@@ -0,0 +1,70 @@
+(
+tr '[A-Z]' '[a-z]' < syscall.dat.rdb
+echo %%%
+cat <<!
+exit 1 0
+fork 2 0
+read 3 0
+write 4 0
+open 5 0
+close 6 0
+wait 7 0
+creat 8 0
+link 9 0
+unlink 10 0
+exec 11 0
+chdir 12 0
+time 13 0
+mknod 14 0
+chmod 15 0
+chown 16 0
+brk 17 0
+stat 18 0
+lseek 19 0
+getpid 20 0
+mount 21 0
+umount 22 0
+setuid 23 0
+getuid 24 0
+stime 25 0
+ptrace 26 0
+alarm 27 0
+fstat 28 0
+pause 29 0
+utime 30 0
+access 33 0
+nice 34 0
+sleep 35 0
+sync 36 0
+kill 37 0
+rename 38 0
+mkdir 39 0
+rmdir 40 0
+dup 41 0
+pipe 42 0
+times 43 0
+profil 44 0
+setgid 46 0
+getgid 47 0
+signal 48 0
+getinfo 49 0
+fcntl 50 0
+acct 51 0
+phys 52 0
+lock 53 0
+ioctl 54 0
+reboot 55 0
+mpx 56 0
+dup2 57 0
+umask 60 0
+!
+) | awk '/%%%/{ flg++; OFS="\t"; next;}
+flg==0 { save4[$1] = $4; save3[$1] = $3;
+ for(i=5; i<=NF; i++) saverest[$1] = saverest[$1] " " $i;
+}
+flg==1 {
+ if( $1 in save3 )
+ print $1, $2, save3[$1]+0, save4[$1] " " saverest[$1] ;
+ else
+ print $1, $2, "0", ". THIS one is different";
+ }'
diff --git a/libc/syscall/syscall.dat.rdb b/libc/syscall/syscall.dat.rdb
new file mode 100644
index 0000000..de5ed9b
--- /dev/null
+++ b/libc/syscall/syscall.dat.rdb
@@ -0,0 +1,142 @@
+#
+# Name No Args Flag, comment
+#
+# . = Ok, with comment
+# * = Needs libc code (Prefix __)
+# - = Obsolete/not required
+#
+# WARNING!
+# This file is used to generate includes for ELKSemu too.
+# This file is continually changing, when you upgrade you _MUST_ ensure
+# that ELKSemu is of a matching build!
+#
+# Calls that use one fd
+READ 3 3
+WRITE 4 3
+CLOSE 6 1
+LSEEK 19 3 * NB 2nd arg is an IO ptr to long not a long.
+FSTAT 28 2
+IOCTL 54 3 . Make this and fcntl the same ?
+FCNTL 55 3
+FTRUNCATE 93 3
+FCHMOD 94 2
+FCHOWN 95 3
+FSYNC 118 1
+FCHDIR 133 1
+LLSEEK 140 3 * 2nd arg is ptr to two longs
+READV 145 3
+WRITEV 146 3
+FLOCK 143 2 - Use fcntl
+DUP 41 1 - Using nasty fcntl function
+
+#
+SETUP 0 X
+EXIT 1 1 * C exit does stdio, _exit in crt0
+FORK 2 0
+OPEN 5 3
+WAIT4 7 4
+VFORK 8 0 . Needed for 8086
+GETINFO 49 1 - Possible? Gets pid,ppid,uid,euid etc
+LINK 9 2
+UNLINK 10 1
+EXEC 11 3 * Minix style exec
+CHDIR 12 1
+GETTIMEOFDAY 13 2 . time() exists only in libc
+MKNOD 14 3
+CHMOD 15 2
+CHOWN 16 3
+BRK 17 1 * This is only to tell the system
+STAT 18 2
+GETPID 20 1 * This gets both pid & ppid
+MOUNT 21 5
+UMOUNT 22 1
+SETUID 23 1
+GETUID 24 1 * This gets both uid and euid
+SETTIMEOFDAY 25 2 . STIME should _NOT_ exist even as a libc.
+STIME 25 2 - This must NOT exist - even as a libc.
+PTRACE 26 4
+ALARM 27 2
+PAUSE 29 0
+UTIME 30 2
+ACCESS 33 2
+NICE 34 1 .
+FTIME 35 1 - Use gettimeofday
+SYNC 36 0
+KILL 37 2
+RENAME 38 2
+MKDIR 39 2
+RMDIR 40 1
+PIPE 42 1
+TIMES 43 2 * 2nd arg is pointer for long ret val.
+SETGID 46 1
+GETGID 47 1 * This gets both gid and egid
+SIGNAL 48 2 * Have put the despatch table in user space.
+ACCT 51 1 -
+SETPGID 57 2
+ULIMIT 58 2
+UMASK 60 1
+CHROOT 61 1
+USTAT 62 2
+GETPGRP 65 0 - use getpgid(0)
+SETSID 66 0
+SIGACTION 67 X
+SGETMASK 68 X
+SSETMASK 69 X
+SETREUID 70 2
+SETREGID 71 2
+SIGSUSPEND 72 X
+SIGPENDING 73 X
+SETHOSTNAME 74 2
+SETRLIMIT 75 2
+GETRLIMIT 76 2
+GETRUSAGE 77 2
+GETGROUPS 80 2
+SETGROUPS 81 2
+SYMLINK 83 2
+LSTAT 84 2
+READLINK 85 3
+SWAPON 87 X
+REBOOT 88 3 . The magic number is 0xfee1,0xdead,...
+MUNMAP 91 X
+TRUNCATE 92 3
+GETPRIORITY 96 2
+SETPRIORITY 97 3
+PROFIL 98 X
+STATFS 99 2
+FSTATFS 100 2
+SOCKETCALL 102 X
+SYSLOG 103 X
+SETITIMER 104 3
+GETITIMER 105 2
+UNAME 109 1
+VHANGUP 111 0
+SWAPOFF 115 X
+SYSINFO 116 X - Use /proc
+IPC 117 5 * This is for all SYSV IPC
+SIGRETURN 119 X
+SETDOMAINNAME 121 X
+ADJTIMEX 124 X
+MPROTECT 125 X
+SIGPROCMASK 126 X
+QUOTACTL 131 X
+GETPGID 132 1
+SYSFS 135 X
+PERSONALITY 136 X
+SETFSUID 138 1
+SETFSGID 139 1
+GETDENTS 141 X
+SELECT 142 5 *
+MSYNC 144 X
+GETSID 147 X
+FDATASYNC 148 X
+SYSCTL 149 X
+MUNLOCK 151 X
+MUNLOCKALL 153 X
+SCHED_SETPARAM 154 X
+SCHED_GETPARAM 155 X
+SCHED_SETSCHEDULER 156 X
+SCHED_GETSCHEDULER 157 X
+SCHED_YIELD 158 X
+SCHED_GET_PRIORITY_MAX 159 X
+SCHED_GET_PRIORITY_MIN 160 X
+SCHED_RR_GET_INTERVAL 161 X
diff --git a/libc/syscall/syslib0.c b/libc/syscall/syslib0.c
index 98f59e6..1a92179 100644
--- a/libc/syscall/syslib0.c
+++ b/libc/syscall/syslib0.c
@@ -29,11 +29,9 @@ call_main:
saved_arg1:
.word 0
#endif
-#if __CALLER_SAVES__
.data
-loopy_safe:
+loop_safe:
.word 0
-#endif
.text
export ___cstartup
@@ -57,24 +55,20 @@ ___mkargv: ! BCC tells the linker to init argc,argv with this.
push cx ! Push argc
#endif
- mov si,#auto_start ! Pointer to first autostart function
+ mov bx,#auto_start ! Pointer to first autostart function
auto_run:
#if __FIRST_ARG_IN_AX__
mov ax,[saved_arg1]
#endif
-#if __CALLER_SAVES__
- mov [loopy_safe],si
-#endif
- mov bx,[si]
+ mov [loop_safe],bx
+ mov bx,[bx]
test bx,bx
jz no_entry
call bx ! Call the function
no_entry:
-#if __CALLER_SAVES__
- mov si,[loopy_safe]
-#endif
- inc si ! SI at next
- inc si
+ mov bx,[loop_safe]
+ inc bx ! next
+ inc bx
jmp auto_run ! And round for the next.
call_exit: ! Last item called by above.
diff --git a/libc/syscall/syslib3.c b/libc/syscall/syslib3.c
deleted file mode 100644
index c4df1fc..0000000
--- a/libc/syscall/syslib3.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/* Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk>
- * This file is part of the Linux-8086 C library and is distributed
- * under the GNU Library General Public License.
- */
-
-#include <sys/types.h>
-#include <errno.h>
-#include <time.h>
-#include <sys/times.h>
-
-/* MSDOS has it's own versions */
-#ifndef __MSDOS__
-#ifdef __AS386_32__
-
-/********************** Function __cstartup *******************************/
-
-#ifdef L___cstart3
-
-void (*__cleanup)() = 0;
-char ** environ;
-
-#asm
- loc 2
-call_main:
- .long _main ! Segment 2 is the trailing pointers, main and the
- .long call_exit ! routine to call exit.
-#if __FIRST_ARG_IN_AX__
- .data
-saved_arg1:
- .long 0
-#endif
-#if __CALLER_SAVES__
- .data
-loopy_safe:
- .long 0
-#endif
- .text
-
-export ___mkargv
-___mkargv: ! BCC Tells linker to init argv ... none needed.
-
-export ___cstartup
-___cstartup: ! Crt0 startup (Linux style)
- mov eax,[esp]
- test eax,eax
- jz call_exit ! If argc == 0 this is being called by ldd, exit.
- mov eax,[esp+8]
- mov [_environ],eax
-#if __FIRST_ARG_IN_AX__
- pop [saved_arg1] ! Argc will go into eax
-#endif
-
- mov esi,#auto_start ! Pointer to first autostart function
-auto_run:
-#if __FIRST_ARG_IN_AX__
- mov eax,[saved_arg1]
-#endif
-#if __CALLER_SAVES__
- mov [loopy_safe],esi
-#endif
- mov ebx,[esi]
- test ebx,ebx
- jz no_func
- call ebx ! Call the function
-no_func:
-#if __CALLER_SAVES__
- mov esi,[loopy_safe]
-#endif
- add esi,#4 ! SI at next
- jmp auto_run ! And round for the next.
-
-call_exit: ! Last item called by above.
- pop ebx ! Be tidy.
-#if !__FIRST_ARG_IN_AX__
- push eax ! At the end the last called was main() push it`s
-#endif
- call _exit ! return val and call exit();
-bad_exit:
- jmp bad_exit ! Exit returned !!
-
-export _exit
-export __exit
-_exit: ! exit(rv) function
-#if __FIRST_ARG_IN_AX__
- mov [saved_arg1],eax
-#else
- push [esp+4] ! Copy the `rv` for the exit fuctions.
-#endif
- mov ebx,[___cleanup] ! Call exit, normally this is `__do_exit`
- test ebx,ebx
- je no_clean ! But it`s default is null
- call ebx
-no_clean:
-#if __FIRST_ARG_IN_AX__
- mov eax,[saved_arg1]
-#else
- add esp,#4
-#endif
-__exit: ! _exit(rv)
- br ___exit ! This is just an alias for __exit();
-
-#endasm
-#endif
-
-/********************** Function ? ************************************/
-
-/*---*/
-#endif
-#endif
diff --git a/libc/syscall/syslibc.c b/libc/syscall/syslibc.c
index 68f5a0b..3486ef6 100644
--- a/libc/syscall/syslibc.c
+++ b/libc/syscall/syslibc.c
@@ -50,6 +50,19 @@ int * status;
}
#endif
+/********************** Function wait3 **************************************/
+
+#ifdef L_wait3
+int
+wait3(status, opts, usage)
+int * status;
+int opts;
+struct rusage * usage;
+{
+ return wait4(-1, status, opts, usage);
+}
+#endif
+
/********************** Function waitpid ************************************/
#ifdef L_waitpid
diff --git a/libc/termios/Makefile b/libc/termios/Makefile
index 7903bc2..cfc3baa 100644
--- a/libc/termios/Makefile
+++ b/libc/termios/Makefile
@@ -2,9 +2,6 @@
# This file is part of the Linux-8086 C library and is distributed
# under the GNU Library General Public License.
-TOP=..
-include $(TOP)/Make.defs
-
TSRC=termios.c
TOBJ=tcsetattr.o tcgetattr.o tcdrain.o tcflow.o tcflush.o tcsendbreak.o \
tcsetpgrp.o tcgetpgrp.o isatty.o \
@@ -12,19 +9,22 @@ TOBJ=tcsetattr.o tcgetattr.o tcdrain.o tcflow.o tcflush.o tcsendbreak.o \
ifeq ($(LIB_OS),ELKS)
OBJ=$(TOBJ) ttyname.o
-else
-OBJ=
-endif
-all: $(OBJ)
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
-libc.a: $(OBJ)
- ar r ../$(LIBC) $(OBJ)
- @touch libc.a
+all: $(LIBC)
+ @:
-clean:
- rm -f *.o libc.a
+$(LIBC): $(LIBC)($(OBJ))
-$(TOBJ): $(TSRC)
- $(CC) $(CFLAGS) -c -DL_$* -o $@ $(TSRC)
+$(LIBC)($(TOBJ)): $(TSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+else
+all:
+ @:
+endif
+clean:
+ rm -f *.o libc.a
diff --git a/libc/tests/Config b/libc/tests/Config
deleted file mode 100644
index 4bdf884..0000000
--- a/libc/tests/Config
+++ /dev/null
@@ -1,2 +0,0 @@
-
-tools: These are tools to test libc - make directly
diff --git a/libc/tests/Makefile b/libc/tests/Makefile
deleted file mode 100644
index 37e57b8..0000000
--- a/libc/tests/Makefile
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright (C) 1996 Robert de Bath <robert@mayday.compulink.co.uk>
-# This file is part of the Linux-8086 C library and is distributed
-# under the GNU Library General Public License.
-
-TOP=..
-include $(TOP)/Make.defs
-CFLAGS=$(CCFLAGS) -ansi
-
-default: all
-
-libc.a:
- @echo -n
-
-include Real_make
-
-fetch_them:
- cp -p $(SRC) Real_make $(TOPDIR)/tests/.
-
-clean:
- rm -f $(OBJ) $(EXE) $(LINK_FILES)
diff --git a/libc/tests/Real_make b/libc/tests/Real_make
deleted file mode 100644
index 38c4232..0000000
--- a/libc/tests/Real_make
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright (C) 1996 Robert de Bath <robert@mayday.compulink.co.uk>
-# This file is part of the Linux-8086 C library and is distributed
-# under the GNU Library General Public License.
-
-SRC=env.c ft.c hd.c size.c sync.c compr.c ucomp.c ouch.c lines.c \
- wc.c line2.c rand.c grab.c
-OBJ=
-EXE=env ft hd size sync compr ucomp ouch lines wc line2 rand grab
-
-LINK_FILES=cat chgrp chmod chown cp install ln mkdir mkfifo mknod mv rm
-
-all: $(EXE)
-
-links:
- for i in $(LINK_FILES) ; do ln -s ft $$i ; done
-
-no_links:
- rm -f $(LINK_FILES)
-
diff --git a/libc/tests/ls.c b/libc/tests/ls.c
deleted file mode 100644
index 8cae4d0..0000000
--- a/libc/tests/ls.c
+++ /dev/null
@@ -1,1049 +0,0 @@
-/* ls 3.2 - List files. Author: Kees J. Bot
- *
- * About the amount of bytes for heap + stack under Minix:
- * Ls needs a average amount of 42 bytes per unserviced directory entry, so
- * scanning 10 directory levels deep in an ls -R with 100 entries per directory
- * takes 42000 bytes of heap. So giving ls 10000 bytes is tight, 20000 is
- * usually enough, 40000 is pessimistic.
- */
-
-/* Compile with the proper -D flag for your system:
- *
- * _MINIX Minix (1.5 or later)
- * BSD BSD derived (has st_blocks)
- * AMOEBA Amoeba's emulation of UNIX
- */
-
-/* The array _ifmt[] is used in an 'ls -l' to map the type of a file to a
- * letter. This is done so that ls can list any future file or device type
- * other than symlinks, without recompilation. (Yes it's dirty.)
- */
-char _ifmt[] = "0pcCd?bB-?l?s???";
-
-#define ifmt(mode) _ifmt[((mode) >> 12) & 0xF]
-
-#define nil 0
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <unistd.h>
-#ifdef AMOEBA
-#undef S_IFLNK /* Liars */
-#endif
-#include <dirent.h>
-#include <time.h>
-#include <pwd.h>
-#include <grp.h>
-#include <errno.h>
-#include <fcntl.h>
-#if BSD || __minix_vmd
-#include <termios.h>
-#endif
-#if __minix_vmd
-#include <sys/ioctl.h>
-#endif
-
-#ifndef major
-#define major(dev) ((int) (((dev) >> 8) & 0xFF))
-#define minor(dev) ((int) (((dev) >> 0) & 0xFF))
-#endif
-
-#if !_MINIX
-#define SUPER_ID uid /* Let -A flag be default for SUPER_ID == 0. */
-#else
-#define SUPER_ID gid
-#endif
-
-#ifdef S_IFLNK
-int (*status)(const char *file, struct stat *stp);
-#else
-#define status stat
-#endif
-
-/* Basic disk block size is 512 except for one niche O.S. */
-#if _MINIX
-#define BLOCK 1024
-#else
-#define BLOCK 512
-#endif
-
-/* Some terminals ignore more than 80 characters on a line. Dumb ones wrap
- * when the cursor hits the side. Nice terminals don't wrap until they have
- * to print the 81st character. Wether we like it or not, no column 80.
- */
-#ifdef TIOCGWINSZ
-int ncols= 79;
-#else
-#define ncols 79
-#endif
-
-#define NSEP 2 /* # spaces between columns. */
-
-#ifdef TIOCGWINSZ
-#define MAXCOLS 150
-#else
-#define MAXCOLS (1 + (ncols / (1+NSEP))) /* Max # of files per line. */
-#endif
-
-char *arg0; /* Last component of argv[0]. */
-int uid, gid; /* callers id. */
-int ex= 0; /* Exit status to be. */
-int istty; /* Output is on a terminal. */
-
-/* Safer versions of malloc and realloc: */
-
-void heaperr(void)
-{
- fprintf(stderr, "%s: Out of memory\n", arg0);
- exit(-1);
-}
-
-void *allocate(size_t n)
-/* Deliver or die. */
-{
- void *a;
-
- if ((a= malloc(n)) == nil) heaperr();
- return a;
-}
-
-#define reallocate rllct /* Same as realloc under some compilers. */
-
-void *reallocate(void *a, size_t n)
-{
- if ((a= realloc(a, n)) == nil) heaperr();
- return a;
-}
-
-char allowed[] = "acdfgilnqrstu1ACFLMRTX";
-char flags[sizeof(allowed)];
-
-char arg0flag[] = "cfmrtx"; /* These in argv[0] go to upper case. */
-
-void setflags(char *flgs)
-{
- int c;
-
- while ((c= *flgs++) != 0) {
- if (strchr(allowed, c) == nil) {
- fprintf(stderr, "Usage: %s -[%s] [file ...]\n",
- arg0, allowed);
- exit(1);
- } else
- if (strchr(flags, c) == nil)
- flags[strlen(flags)] = c;
- }
-}
-
-int present(int f)
-{
- return f == 0 || strchr(flags, f) != nil;
-}
-
-void report(char *f)
-/* Like perror(3), but in the style: "ls: junk: No such file or directory. */
-{
- fprintf(stderr, "%s: %s: %s\n", arg0, f, strerror(errno));
- ex= 1;
-}
-
-/* Two functions, uidname and gidname, translate id's to readable names.
- * All names are remembered to avoid searching the password file.
- */
-#define NNAMES (1 << (sizeof(int) + sizeof(char *)))
-enum whatmap { PASSWD, GROUP };
-
-struct idname { /* Hash list of names. */
- struct idname *next;
- char *name;
- uid_t id;
-} *uids[NNAMES], *gids[NNAMES];
-
-char *idname(unsigned id, enum whatmap map)
-/* Return name for a given user/group id. */
-{
- struct idname *i;
- struct idname **ids= &(map == PASSWD ? uids : gids)[id % NNAMES];
-
- while ((i= *ids) != nil && id < i->id) ids= &i->next;
-
- if (i == nil || id != i->id) {
- /* Not found, go look in the password or group map. */
- char *name= nil;
- char noname[3 * sizeof(uid_t)];
-
- if (!present('n')) {
- if (map == PASSWD) {
- struct passwd *pw= getpwuid(id);
-
- if (pw != nil) name= pw->pw_name;
- } else {
- struct group *gr= getgrgid(id);
-
- if (gr != nil) name= gr->gr_name;
- }
- }
- if (name == nil) {
- /* Can't find it, weird. Use numerical "name." */
- sprintf(noname, "%u", id);
- name= noname;
- }
-
- /* Add a new id-to-name cell. */
- i= allocate(sizeof(*i));
- i->id= id;
- i->name= allocate(strlen(name) + 1);
- strcpy(i->name, name);
- i->next= *ids;
- *ids= i;
- }
- return i->name;
-}
-
-#define uidname(uid) idname((uid), PASSWD)
-#define gidname(gid) idname((gid), GROUP)
-
-/* Path name construction, addpath adds a component, delpath removes it.
- * The string path is used throughout the program as the file under examination.
- */
-
-char *path; /* Path name constructed in path[]. */
-int plen= 0, pidx= 0; /* Lenght/index for path[]. */
-
-void addpath(int *didx, char *name)
-/* Add a component to path. (name may also be a full path at the first call)
- * The index where the current path ends is stored in *pdi.
- */
-{
- if (plen == 0) path= (char *) allocate((plen= 32) * sizeof(path[0]));
-
- if (pidx == 1 && path[0] == '.') pidx= 0; /* Remove "." */
-
- *didx= pidx; /* Record point to go back to for delpath. */
-
- if (pidx > 0 && path[pidx-1] != '/') path[pidx++]= '/';
-
- do {
- if (*name != '/' || pidx == 0 || path[pidx-1] != '/') {
- if (pidx == plen)
- path= (char *) reallocate((void *) path,
- (plen*= 2) * sizeof(path[0]));
- path[pidx++]= *name;
- }
- } while (*name++ != 0);
-
- --pidx; /* Put pidx back at the null. The path[pidx++]= '/'
- * statement will overwrite it at the next call.
- */
-}
-
-#define delpath(didx) (path[pidx= didx]= 0) /* Remove component. */
-
-int field = 0; /* (used to be) Fields that must be printed. */
- /* (now) Effects triggered by certain flags. */
-
-#define F_INODE 0x001 /* -i */
-#define F_BLOCKS 0x002 /* -s */
-#define F_EXTRA 0x004 /* -X */
-#define F_MODE 0x008 /* -lMX */
-#define F_LONG 0x010 /* -l */
-#define F_GROUP 0x020 /* -g */
-#define F_BYTIME 0x040 /* -tuc */
-#define F_ATIME 0x080 /* -u */
-#define F_CTIME 0x100 /* -c */
-#define F_MARK 0x200 /* -F */
-#define F_TYPE 0x400 /* -T */
-#define F_DIR 0x800 /* -d */
-
-struct file { /* A file plus stat(2) information. */
- struct file *next; /* Lists are made of them. */
- char *name; /* Null terminated name. */
- ino_t ino;
- mode_t mode;
- uid_t uid;
- gid_t gid;
- nlink_t nlink;
- dev_t rdev;
- off_t size;
- time_t mtime;
- time_t atime;
- time_t ctime;
-#if BSD
- long blocks;
-#endif
-};
-
-void setstat(struct file *f, struct stat *stp)
-{
- f->ino= stp->st_ino;
- f->mode= stp->st_mode;
- f->nlink= stp->st_nlink;
- f->uid= stp->st_uid;
- f->gid= stp->st_gid;
- f->rdev= stp->st_rdev;
- f->size= stp->st_size;
- f->mtime= stp->st_mtime;
- f->atime= stp->st_atime;
- f->ctime= stp->st_ctime;
-#if BSD
- f->blocks= stp->st_blocks;
-#endif
-}
-
-#define PAST (26*7*24*3600L) /* Half a year ago. */
-/* Between PAST and FUTURE from now a time is printed, otherwise a year. */
-#define FUTURE (15*60L) /* Fifteen minutes. */
-
-static char *timestamp(struct file *f)
-/* Transform the right time field into something readable. */
-{
- struct tm *tm;
- time_t t;
- static time_t now;
- static int drift= 0;
- static char date[] = "Jan 19 2038";
- static char month[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
-
- t= f->mtime;
- if (field & F_ATIME) t= f->atime;
- if (field & F_CTIME) t= f->ctime;
-
- tm= localtime(&t);
- if (--drift < 0) { time(&now); drift= 50; } /* limit time() calls */
-
- if (t < now - PAST || t > now + FUTURE) {
- sprintf(date, "%.3s %2d %4d",
- month + 3*tm->tm_mon,
- tm->tm_mday,
- 1900 + tm->tm_year);
- } else {
- sprintf(date, "%.3s %2d %02d:%02d",
- month + 3*tm->tm_mon,
- tm->tm_mday,
- tm->tm_hour, tm->tm_min);
- }
- return date;
-}
-
-char *permissions(struct file *f)
-/* Compute long or short rwx bits. */
-{
- static char rwx[] = "drwxr-x--x";
-
- rwx[0] = ifmt(f->mode);
- /* Note that rwx[0] is a guess for the more alien file types. It is
- * correct for BSD4.3 and derived systems. I just don't know how
- * "standardized" these numbers are.
- */
-
- if (field & F_EXTRA) { /* Short style */
- int mode = f->mode, ucase= 0;
-
- if (uid == f->uid) /* What group of bits to use. */
- /* mode<<= 0, */
- ucase= (mode<<3) | (mode<<6);
- /* Remember if group or others have permissions. */
- else
- if (gid == f->gid)
- mode<<= 3;
- else
- mode<<= 6;
-
- rwx[1]= mode&S_IRUSR ? (ucase&S_IRUSR ? 'R' : 'r') : '-';
- rwx[2]= mode&S_IWUSR ? (ucase&S_IWUSR ? 'W' : 'w') : '-';
-
- if (mode&S_IXUSR) {
- static char sbit[]= { 'x', 'g', 'u', 's' };
-
- rwx[3]= sbit[(f->mode&(S_ISUID|S_ISGID))>>10];
- if (ucase&S_IXUSR) rwx[3] += 'A'-'a';
- } else
- rwx[3]= f->mode&(S_ISUID|S_ISGID) ? '=' : '-';
- rwx[4]= 0;
- } else { /* Long form. */
- char *p= rwx+1;
- int mode= f->mode;
-
- do {
- p[0] = (mode & S_IRUSR) ? 'r' : '-';
- p[1] = (mode & S_IWUSR) ? 'w' : '-';
- p[2] = (mode & S_IXUSR) ? 'x' : '-';
- mode<<= 3;
- } while ((p+=3) <= rwx+7);
-
- if (f->mode&S_ISUID) rwx[3]= f->mode&(S_IXUSR>>0) ? 's' : '=';
- if (f->mode&S_ISGID) rwx[6]= f->mode&(S_IXUSR>>3) ? 's' : '=';
- if (f->mode&S_ISVTX) rwx[9]= f->mode&(S_IXUSR>>6) ? 't' : '=';
- }
- return rwx;
-}
-
-void numeral(int i, char **pp)
-{
- char itoa[3*sizeof(int)], *a=itoa;
-
- do *a++ = i%10 + '0'; while ((i/=10) > 0);
-
- do *(*pp)++ = *--a; while (a>itoa);
-}
-
-#define K 1024L /* A kilobyte counts in multiples of K */
-#define T 1000L /* A megabyte in T*K, a gigabyte in T*T*K */
-
-char *cxsize(struct file *f)
-/* Try and fail to turn a 32 bit size into 4 readable characters. */
-{
- static char siz[] = "1.2m";
- char *p= siz;
- off_t z;
-
- siz[1]= siz[2]= siz[3]= 0;
-
- if (f->size <= 5*K) { /* <= 5K prints as is. */
- numeral((int) f->size, &p);
- return siz;
- }
- z= (f->size + K-1) / K;
-
- if (z <= 999) { /* Print as 123k. */
- numeral((int) z, &p);
- *p = 'k'; /* Can't use 'K', looks bad */
- } else
- if (z*10 <= 99*T) { /* 1.2m (Try ls -X /dev/at0) */
- z= (z*10 + T-1) / T; /* Force roundup */
- numeral((int) z / 10, &p);
- *p++ = '.';
- numeral((int) z % 10, &p);
- *p = 'm';
- } else
- if (z <= 999*T) { /* 123m */
- numeral((int) ((z + T-1) / T), &p);
- *p = 'm';
- } else { /* 1.2g */
- z= (z*10 + T*T-1) / (T*T);
- numeral((int) z / 10, &p);
- *p++ = '.';
- numeral((int) z % 10, &p);
- *p = 'g';
- }
- return siz;
-}
-
-/* Transform size of file to number of blocks. This was once a function that
- * guessed the number of indirect blocks, but that nonsense has been removed.
- */
-#if BSD
-#define nblocks(f) ((f)->blocks)
-#else
-#define nblocks(f) (((f)->size + BLOCK-1) / BLOCK)
-#endif
-
-/* From number of blocks to kilobytes. */
-#if BLOCK < 1024
-#define nblk2k(nb) (((nb) + (1024 / BLOCK - 1)) / (1024 / BLOCK))
-#else
-#define nblk2k(nb) ((nb) * (BLOCK / 1024))
-#endif
-
-static int (*CMP)(struct file *f1, struct file *f2);
-static int (*rCMP)(struct file *f1, struct file *f2);
-
-static void mergesort(struct file **al)
-/* This is either a stable mergesort, or thermal noise, I'm no longer sure.
- * It must be called like this: if (L != nil && L->next != nil) mergesort(&L);
- */
-{
- /* static */ struct file *l1, **mid; /* Need not be local */
- struct file *l2;
-
- l1= *(mid= &(*al)->next);
- do {
- if ((l1= l1->next) == nil) break;
- mid= &(*mid)->next;
- } while ((l1= l1->next) != nil);
-
- l2= *mid;
- *mid= nil;
-
- if ((*al)->next != nil) mergesort(al);
- if (l2->next != nil) mergesort(&l2);
-
- l1= *al;
- for (;;) {
- if ((*CMP)(l1, l2) <= 0) {
- if ((l1= *(al= &l1->next)) == nil) {
- *al= l2;
- break;
- }
- } else {
- *al= l2;
- l2= *(al= &l2->next);
- *al= l1;
- if (l2 == nil) break;
- }
- }
-}
-
-int namecmp(struct file *f1, struct file *f2)
-{
- return strcmp(f1->name, f2->name);
-}
-
-int mtimecmp(struct file *f1, struct file *f2)
-{
- return f1->mtime == f2->mtime ? 0 : f1->mtime > f2->mtime ? -1 : 1;
-}
-
-int atimecmp(struct file *f1, struct file *f2)
-{
- return f1->atime == f2->atime ? 0 : f1->atime > f2->atime ? -1 : 1;
-}
-
-int ctimecmp(struct file *f1, struct file *f2)
-{
- return f1->ctime == f2->ctime ? 0 : f1->ctime > f2->ctime ? -1 : 1;
-}
-
-int typecmp(struct file *f1, struct file *f2)
-{
- return ifmt(f1->mode) - ifmt(f2->mode);
-}
-
-int revcmp(struct file *f1, struct file *f2) { return (*rCMP)(f2, f1); }
-
-static void sort(struct file **al)
-/* Sort the files according to the flags. */
-{
- if (!present('f') && *al != nil && (*al)->next != nil) {
- CMP= namecmp;
-
- if (!(field & F_BYTIME)) {
- /* Sort on name */
-
- if (present('r')) { rCMP= CMP; CMP= revcmp; }
- mergesort(al);
- } else {
- /* Sort on name first, then sort on time. */
-
- mergesort(al);
- if (field & F_CTIME)
- CMP= ctimecmp;
- else
- if (field & F_ATIME)
- CMP= atimecmp;
- else
- CMP= mtimecmp;
-
- if (present('r')) { rCMP= CMP; CMP= revcmp; }
- mergesort(al);
- }
- /* Separate by file type if so desired. */
-
- if (field & F_TYPE) {
- CMP= typecmp;
- mergesort(al);
- }
- }
-}
-
-struct file *newfile(char *name)
-/* Create file structure for given name. */
-{
- struct file *new;
-
- new= (struct file *) allocate(sizeof(*new));
- new->name= strcpy((char *) allocate(strlen(name)+1), name);
- return new;
-}
-
-void pushfile(struct file **flist, struct file *new)
-/* Add file to the head of a list. */
-{
- new->next= *flist;
- *flist= new;
-}
-
-void delfile(struct file *old)
-/* Release old file structure. */
-{
- free((void *) old->name);
- free((void *) old);
-}
-
-struct file *popfile(struct file **flist)
-/* Pop file off top of file list. */
-{
- struct file *f;
-
- f= *flist;
- *flist= f->next;
- return f;
-}
-
-int dotflag(char *name)
-/* Return flag that would make ls list this name: -a or -A. */
-{
- if (*name++ != '.') return 0;
-
- switch (*name++) {
- case 0: return 'a'; /* "." */
- case '.': if (*name == 0) return 'a'; /* ".." */
- default: return 'A'; /* ".*" */
- }
-}
-
-int adddir(struct file **aflist, char *name)
-/* Add directory entries of directory name to a file list. */
-{
- DIR *d;
- struct dirent *e;
-
- if (access(name, 0) < 0) {
- report(name);
- return 0;
- }
-
- if ((d= opendir(name)) == nil) {
- report(name);
- return 0;
- }
- while ((e= readdir(d)) != nil) {
- if (e->d_ino != 0 && present(dotflag(e->d_name))) {
- pushfile(aflist, newfile(e->d_name));
- aflist= &(*aflist)->next;
- }
- }
- closedir(d);
- return 1;
-}
-
-off_t countblocks(struct file *flist)
-/* Compute total block count for a list of files. */
-{
- off_t cb = 0;
-
- while (flist != nil) {
- switch (flist->mode & S_IFMT) {
- case S_IFDIR:
- case S_IFREG:
-#ifdef S_IFLNK
- case S_IFLNK:
-#endif
- cb += nblocks(flist);
- }
- flist= flist->next;
- }
- return cb;
-}
-
-void printname(char *name)
-/* Print a name with control characters as '?' (unless -q). The terminal is
- * assumed to be eight bit clean.
- */
-{
- int c, q= present('q');
-
- while ((c= *name++) != 0) {
- if (q && (c <= ' ' || c == 0177)) c= '?';
- putchar(c);
- }
-}
-
-int mark(struct file *f, int doit)
-{
- int c;
-
- if (!(field & F_MARK)) return 0;
-
- switch (f->mode & S_IFMT) {
- case S_IFDIR: c= '/'; break;
-#ifdef S_IFIFO
- case S_IFIFO: c= '|'; break;
-#endif
-#ifdef S_IFLNK
- case S_IFLNK: c= '@'; break;
-#endif
-#ifdef S_IFSOCK
- case S_IFSOCK: c= '='; break;
-#endif
- case S_IFREG:
- if (f->mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
- c= '*';
- break;
- }
- default:
- c= 0;
- }
- if (doit && c != 0) putchar(c);
- return c;
-}
-
-int colwidth[MAXCOLS]; /* Need colwidth[i] spaces to print column i. */
-int sizwidth[MAXCOLS]; /* Spaces for the size field in a -X print. */
-int namwidth[MAXCOLS]; /* Name field. */
-
-int maxise(int *aw, int w)
-/* Set *aw to the larger of it and w. Then return it. */
-{
- if (w > *aw) *aw= w;
- return *aw;
-}
-
-static int nsp= 0; /* This many spaces have not been printed yet. */
-#define spaces(n) (nsp= (n))
-#define terpri() (nsp= 0, putchar('\n')) /* No trailing spaces */
-
-void print1(struct file *f, int col, int doit)
-/* Either compute the number of spaces needed to print file f (doit == 0) or
- * really print it (doit == 1).
- */
-{
- int width= 0, n;
- char *p;
-
- while (nsp>0) { putchar(' '); nsp--; }/* Fill gap between two columns */
-
- if (field & F_INODE) {
- if (doit) printf("%5d ", f->ino); else width+= 6;
- }
- if (field & F_BLOCKS) {
- if (doit) printf("%4ld ", nblk2k(nblocks(f))); else width+= 5;
- }
- if (field & F_MODE) {
- if (doit)
- printf("%s ", permissions(f));
- else
- width+= (field & F_EXTRA) ? 5 : 11;
- }
- if (field & F_EXTRA) {
- p= cxsize(f);
- n= strlen(p)+1;
-
- if (doit) {
- n= sizwidth[col] - n;
- while (n > 0) { putchar(' '); --n; }
- printf("%s ", p);
- } else
- width+= maxise(&sizwidth[col], n);
- }
- if (field & F_LONG) {
- if (doit) {
- printf("%2d %-8s ", f->nlink, uidname(f->uid));
- if (field & F_GROUP) printf("%-8s ", gidname(f->gid));
-
- switch (f->mode & S_IFMT) {
- case S_IFBLK:
- case S_IFCHR:
-#ifdef S_IFMPB
- case S_IFMPB:
-#endif
-#ifdef S_IFMPC
- case S_IFMPC:
-#endif
- printf("%3d, %3d ",
- major(f->rdev), minor(f->rdev));
- break;
- default:
- printf("%8ld ", (long) f->size);
- }
- printf("%s ", timestamp(f));
- } else
- width += (field & F_GROUP) ? 43 : 34;
- }
- n= strlen(f->name);
- if (doit) {
- printname(f->name);
- if (mark(f, 1) != 0) n++;
-#ifdef S_IFLNK
- if ((field & F_LONG) && (f->mode & S_IFMT) == S_IFLNK) {
- char *buf;
- int r, didx;
-
- buf= (char *) allocate(((size_t) f->size + 1)
- * sizeof(buf[0]));
- addpath(&didx, f->name);
- r= readlink(path, buf, (int) f->size);
- delpath(didx);
- if (r > 0) buf[r] = 0; else r=1, strcpy(buf, "?");
- printf(" -> ");
- printname(buf);
- free((void *) buf);
- n+= 4 + r;
- }
-#endif
- spaces(namwidth[col] - n);
- } else {
- if (mark(f, 0) != 0) n++;
-#ifdef S_IFLNK
- if ((field & F_LONG) && (f->mode & S_IFMT) == S_IFLNK) {
- n+= 4 + (int) f->size;
- }
-#endif
- width+= maxise(&namwidth[col], n + NSEP);
- maxise(&colwidth[col], width);
- }
-}
-
-int countfiles(struct file *flist)
-/* Return number of files in the list. */
-{
- int n= 0;
-
- while (flist != nil) { n++; flist= flist->next; }
-
- return n;
-}
-
-struct file *filecol[MAXCOLS]; /* filecol[i] is list of files for column i. */
-int nfiles, nlines; /* # files to print, # of lines needed. */
-
-int columnise(struct file *flist, int nplin)
-/* Chop list of files up in columns. Note that 3 columns are used for 5 files
- * even though nplin may be 4, filecol[3] will simply be nil.
- */
-{
- int i, j;
-
- nlines= (nfiles + nplin - 1) / nplin; /* nlines needed for nfiles */
-
- filecol[0]= flist;
-
- for (i=1; i<nplin; i++) { /* Give nlines files to each column. */
- for (j=0; j<nlines && flist != nil; j++) flist= flist->next;
-
- filecol[i]= flist;
- }
-}
-
-int print(struct file *flist, int nplin, int doit)
-/* Try (doit == 0), or really print the list of files over nplin columns.
- * Return true if it can be done in nplin columns or if nplin == 1.
- */
-{
- register struct file *f;
- register int i, totlen;
-
- columnise(flist, nplin);
-
- if (!doit) {
- if (nplin==1 && !(field & F_EXTRA))
- return 1; /* No need to try 1 column. */
-
- for (i=0; i<nplin; i++)
- colwidth[i]= sizwidth[i]= namwidth[i]= 0;
- }
- while (--nlines >= 0) {
- totlen=0;
-
- for (i=0; i<nplin; i++) {
- if ((f= filecol[i]) != nil) {
- filecol[i]= f->next;
- print1(f, i, doit);
- }
- if (!doit && nplin>1) {
- /* See if this line is not too long. */
- totlen+= colwidth[i];
- if (totlen > ncols+NSEP) return 0;
- }
- }
- if (doit) terpri();
- }
- return 1;
-}
-
-enum depth { SURFACE, SURFACE1, SUBMERGED };
-enum state { BOTTOM, SINKING, FLOATING };
-
-void listfiles(struct file *flist, enum depth depth, enum state state)
-/* Main workhorse of ls, it sorts and prints the list of files. Flags:
- * depth: working with the command line / just one file / listing dir.
- * state: How "recursive" do we have to be.
- */
-{
- struct file *dlist= nil, **afl= &flist, **adl= &dlist;
- int nplin;
- static int white = 1; /* Nothing printed yet. */
-
- /* Flush everything previously printed, so new error output will
- * not intermix with files listed earlier.
- */
- fflush(stdout);
-
- if (field != 0 || state != BOTTOM) { /* Need stat(2) info. */
- while (*afl != nil) {
- static struct stat st;
- int r, didx;
-
- addpath(&didx, (*afl)->name);
-
- if ((r= status(path, &st)) < 0
-#ifdef S_IFLNK
- && (status == lstat || lstat(path, &st) < 0)
-#endif
- ) {
- if (depth != SUBMERGED || errno != ENOENT)
- report((*afl)->name);
- delfile(popfile(afl));
- } else {
- setstat(*afl, &st);
- afl= &(*afl)->next;
- }
- delpath(didx);
- }
- }
- sort(&flist);
-
- if (depth == SUBMERGED && (field & (F_BLOCKS | F_LONG)))
- printf("total %ld\n", nblk2k(countblocks(flist)));
-
- if (state == SINKING || depth == SURFACE1) {
- /* Don't list directories themselves, list their contents later. */
- afl= &flist;
- while (*afl != nil) {
- if (((*afl)->mode & S_IFMT) == S_IFDIR) {
- pushfile(adl, popfile(afl));
- adl= &(*adl)->next;
- } else
- afl= &(*afl)->next;
- }
- }
-
- if ((nfiles= countfiles(flist)) > 0) {
- /* Print files in how many columns? */
- nplin= !present('C') ? 1 : nfiles < MAXCOLS ? nfiles : MAXCOLS;
-
- while (!print(flist, nplin, 0)) nplin--; /* Try first */
-
- print(flist, nplin, 1); /* Then do it! */
- white = 0;
- }
-
- while (flist != nil) { /* Destroy file list */
- if (state == FLOATING && (flist->mode & S_IFMT) == S_IFDIR) {
- /* But keep these directories for ls -R. */
- pushfile(adl, popfile(&flist));
- adl= &(*adl)->next;
- } else
- delfile(popfile(&flist));
- }
-
- while (dlist != nil) { /* List directories */
- if (dotflag(dlist->name) != 'a' || depth != SUBMERGED) {
- int didx;
-
- addpath(&didx, dlist->name);
-
- flist= nil;
- if (adddir(&flist, path)) {
- if (depth != SURFACE1) {
- if (!white) putchar('\n');
- printf("%s:\n", path);
- white = 0;
- }
- listfiles(flist, SUBMERGED,
- state == FLOATING ? FLOATING : BOTTOM);
- }
- delpath(didx);
- }
- delfile(popfile(&dlist));
- }
-}
-
-int main(int argc, char **argv)
-{
- struct file *flist= nil, **aflist= &flist;
- enum depth depth;
- char *lsflags;
-#ifdef TIOCGWINSZ
- struct winsize ws;
-#endif
-
- uid= geteuid();
- gid= getegid();
-
- if ((arg0= strrchr(argv[0], '/')) == nil) arg0= argv[0]; else arg0++;
- argv++;
-
- if (strcmp(arg0, "ls") != 0) {
- char *p= arg0+1;
-
- while (*p != 0) {
- if (strchr(arg0flag, *p) != nil) *p += 'A' - 'a';
- p++;
- }
- setflags(arg0+1);
- }
- while (*argv != nil && (*argv)[0] == '-') {
- if ((*argv)[1] == '-' && (*argv)[2] == 0) {
- argv++;
- break;
- }
- setflags(*argv++ + 1);
- }
-
- istty= isatty(1);
-
- if (istty && (lsflags= getenv("LSOPTS")) != nil) {
- if (*lsflags == '-') lsflags++;
- setflags(lsflags);
- }
-
- if (!present('1') && !present('C') && !present('l')
- && (istty || present('M') || present('X') || present('F'))
- ) setflags("C");
-
- if (istty) setflags("q");
-
- if (SUPER_ID == 0 || present('a')) setflags("A");
-
- if (present('i')) field|= F_INODE;
- if (present('s')) field|= F_BLOCKS;
- if (present('M')) field|= F_MODE;
- if (present('X')) field|= F_EXTRA|F_MODE;
- if (present('t')) field|= F_BYTIME;
- if (present('u')) field|= F_ATIME;
- if (present('c')) field|= F_CTIME;
- if (present('l')) {
- field= (field | F_MODE | F_LONG) & ~F_EXTRA;
- if (present('g')) field|= F_GROUP;
- }
- if (present('F')) field|= F_MARK;
- if (present('T')) field|= F_TYPE;
- if (present('d')) field|= F_DIR;
-
-#ifdef S_IFLNK
- status= present('L') ? stat : lstat;
-#endif
-
-#ifdef TIOCGWINSZ
- if (present('C')) {
- int t= istty ? 1 : open("/dev/tty", O_WRONLY);
-
- if (t >= 0 && ioctl(t, TIOCGWINSZ, &ws) == 0 && ws.ws_col > 0)
- ncols= ws.ws_col - 1;
-
- if (t != 1) close(t);
- }
-#endif
-
- depth= SURFACE;
-
- if (*argv == nil) {
- if (!(field & F_DIR)) depth= SURFACE1;
- pushfile(aflist, newfile("."));
- } else {
- if (argv[1] == nil && !(field & F_DIR)) depth= SURFACE1;
-
- do {
- pushfile(aflist, newfile(*argv++));
- aflist= &(*aflist)->next;
- } while (*argv!=nil);
- }
- listfiles(flist, depth,
- (field & F_DIR) ? BOTTOM : present('R') ? FLOATING : SINKING);
- exit(ex);
-}
-/* Kees J. Bot 25-4-89. */
diff --git a/libc/tests/size.c b/libc/tests/size.c
deleted file mode 100644
index 2d6676b..0000000
--- a/libc/tests/size.c
+++ /dev/null
@@ -1,51 +0,0 @@
-#include <fcntl.h>
-#include <a.out.h>
-
-void size(filename)
- char *filename;
-{
- int f;
- struct exec ex;
- long total;
- int cc;
-
- if ((f = open(filename, O_RDONLY)) < 0 )
- {
- perror(filename);
- return;
- }
- cc = read(f, &ex, sizeof(ex));
-
- if (cc == sizeof(ex) && !BADMAG(ex))
- {
- total = ex.a_text + ex.a_data + ex.a_bss;
- printf("%-ld\t%-ld\t%-ld\t%-ld\t%-lx\t%s\n",
- ex.a_text, ex.a_data, ex.a_bss, total, total,
- filename);
- }
- else if( cc > 16 && memcmp(&ex, "\243\206\001\000*", 5) == 0 )
- { /* *.o file */
- total = ((unsigned char*)&ex)[9] +
- ((unsigned char*)&ex)[10] * 256;
- printf("\t\t\t%-ld\t%-lx\t%s\n",
- total, total, filename);
- }
- else
- printf("%s: Not an a.out file\n", filename);
- close(f);
-}
-
-int main(argc, argv)
- int argc;
- char **argv;
-{
- if (argc < 2)
- {
- printf("Usage: %s file\n", argv[0]);
- exit(1);
- }
- printf("text\tdata\tbss\tdec\thex\tfilename\n");
- for (--argc, ++argv; argc > 0; --argc, ++argv)
- size(*argv);
- exit(0);
-}
diff --git a/libc/time/Makefile b/libc/time/Makefile
index d04e5f4..6e95444 100644
--- a/libc/time/Makefile
+++ b/libc/time/Makefile
@@ -2,16 +2,14 @@
# This file is part of the Linux-8086 C library and is distributed
# under the GNU Library General Public License.
-TOP=..
-include $(TOP)/Make.defs
-
OBJ=localtime.o gmtime.o asctime.o ctime.o asc_conv.o tm_conv.o
-all: $(OBJ)
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
+
+all: $(LIBC)
+ @:
-libc.a: $(OBJ)
- ar r ../$(LIBC) $(OBJ)
- @touch libc.a
+$(LIBC): $(LIBC)($(OBJ))
clean:
rm -f *.o libc.a
diff --git a/libc/utmp/Makefile b/libc/utmp/Makefile
deleted file mode 100644
index 2c88bd2..0000000
--- a/libc/utmp/Makefile
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright (C) 1996 Nat Friedman <ndf@aleph1.mit.edu>
-# This file is part of the Linux-8086 C library and is distributed
-# under the GNU Library General Public License.
-
-TOP=..
-include $(TOP)/Make.defs
-
-ifeq ($(LIB_OS),ELKS)
-OBJ=utent.o
-endif
-
-all: $(OBJ)
-
-libc.a: $(OBJ)
- ar r ../$(LIBC) $(OBJ)
- @touch libc.a
-
-%.o:%.c
-ifeq ($(PLATFORM),i386-Linux)
- $(CC) $(CFLAGS) $< -c -o $@ $(WALL)
-else
- $(CC) $(CFLAGS) $< -c -o $@ -ansi
-endif
-
-clean:
- rm -f *.o libc.a
diff --git a/makefile.in b/makefile.in
new file mode 100644
index 0000000..a382e30
--- /dev/null
+++ b/makefile.in
@@ -0,0 +1,226 @@
+#ifdef COMMENT
+##############################################################################
+#
+# This Makefile has been completely re-vamped. Two reasons, first to allow
+# for a full compile before installation, hence allowing us to make a binary
+# distribution without installing and second to allow proper dependancy trees
+# for the different versions of the library.
+#
+# As an aside, it would be useful if I could avoid GNU-make constucts.
+#
+##############################################################################
+#endif
+
+# Defaults, generic C
+ARFLAGS =r
+CFLAGS =-O
+LDFLAGS =-s
+MAKEARG =CC='$(CC)' CFLAGS='$(CFLAGS)' LDFLAGS='$(LDFLAGS)' PREFIX=$(PREFIX) \
+ LIBDIR='$(LIBDIR)' BINDIR='$(BINDIR)'
+MAKEC=$(MAKE) -C
+MAKEX=
+
+#ifdef __GNUC__
+WALL =-Wtraditional -Wshadow -Wid-clash-14 -Wpointer-arith \
+ -Wcast-qual -Wcast-align -Wconversion -Waggregate-return \
+ -Wstrict-prototypes -Wmissing-prototypes -Wredundant-decls \
+ -Wnested-externs -Winline
+
+# unproto is yukky, I've included '-w' in the local makefile.
+WALL =-Wstrict-prototypes
+
+CC =gcc $(GCCFLAG)
+CFLAGS =-Wall $(WALL) -O2 -fno-strength-reduce
+LDFLAGS =-s
+#endif
+
+#ifdef __minix
+# Minix make doesn't understand -C, cc runs out of memory with the headers.
+MAKEC=ash makec
+MAKEX=makec
+CFLAGS=-O -m -w -DPOSIX_HEADERS_MISSING
+#endif
+
+#ifdef __BCC__
+CC =bcc
+#ifdef __AS386_32__
+CFLAGS =-3
+LDFLAGS =-3 -s -N
+#else
+CFLAGS =-0
+LDFLAGS =-0 -s -H10000
+#endif
+#endif
+
+# Alter these if for some reason you don't want this done as root.
+INDAT=-o root -g root -m 644
+INEXE=-o root -g root -m 755
+
+all: check_config bcc unproto copt as86 ld86 library alt-libs elksemu
+
+install: check_config install-bcc install-man install-lib install-lib2 install-emu
+
+install-all: install install-other
+
+##############################################################################
+
+LIBARGS= CC=ncc CCFLAGS= ARFLAGS=$(ARFLAGS)
+
+# Season to taste
+PREFIX= /usr/bcc
+BINDIR= /usr/bin
+LIBDIR= $(PREFIX)/lib/bcc
+
+DISTBIN= $(DIST)$(BINDIR)
+DISTLIB= $(DIST)$(LIBDIR)
+DISTPRE= $(DIST)$(PREFIX)
+
+# Others to install
+OTHERS= tests dis88 doselks bootblocks
+
+CLEANLIST= bcc as ld unproto copt libc elksemu libbsd $(OTHERS)
+
+##############################################################################
+
+bindir: $(MAKEX)
+ @mkdir -p bin lib lib/i386
+ @rm -f include
+ @ln -s libc/include include 2>/dev/null || true
+
+phony:
+
+bcc: bindir
+ $(MAKEC) bcc $(MAKEARG) bcc ncc bcc-cc1
+ cp -p bcc/bcc bin/bcc
+ cp -p bcc/ncc bin/ncc
+ cp -p bcc/bcc-cc1 lib/bcc-cc1
+
+unproto: bindir
+ $(MAKEC) unproto $(MAKEARG) unproto
+ cp -p unproto/unproto lib/unproto
+
+copt: bindir
+ $(MAKEC) copt $(MAKEARG) copt
+ cp -p copt/copt lib/copt
+ cp -p copt/rules.* lib/.
+
+as86: bindir
+ $(MAKEC) as $(MAKEARG) all
+ cp -p as/as86 lib/as86
+ cp -p as/as86_encap bin/as86_encap
+
+ld86: bindir
+ $(MAKEC) ld $(MAKEARG) ld86
+ cp -p ld/ld86 lib/ld86
+
+elksemu: bindir
+ $(MAKEC) elksemu $(MAKEARG) elksemu
+ cp -p elksemu/elksemu bin/elksemu
+
+install-bcc: bcc unproto copt as86 ld86
+ install -d $(DISTBIN) $(DISTLIB) $(DISTLIB)/i86
+ install $(INEXE) bin/bcc $(DISTBIN)/bcc
+ install $(INEXE) lib/bcc-cc1 $(DISTLIB)/bcc-cc1
+ install $(INEXE) lib/unproto $(DISTLIB)/unproto
+ install $(INEXE) lib/as86 $(DISTLIB)/as86
+ install $(INEXE) bin/as86_encap $(DISTBIN)/as86_encap
+ install $(INEXE) lib/ld86 $(DISTLIB)/ld86
+ install $(INEXE) lib/copt $(DISTLIB)/copt
+ install $(INDAT) lib/rules.* $(DISTLIB)/i86
+
+install-emu: elksemu
+ install -d $(DIST)/lib
+ install $(INEXE) bin/elksemu $(DIST)/lib/elksemu
+
+install-man:
+ -$(MAKEC) man MANDIR=$(DIST)/usr/man install
+
+install-lib: lib/lib0-done
+ install -d $(DISTLIB)/i86
+ $(MAKEC) libc $(LIBARGS) BCCHOME=$(DISTPRE) install_incl
+ install $(INDAT) lib/crt0.o $(DISTLIB)/i86/crt0.o
+ install $(INDAT) lib/libc.a $(DISTLIB)/i86/libc.a
+ install -d $(DIST)/usr/lib
+ install $(INDAT) libc/error/liberror.txt $(DIST)/usr/lib/liberror.txt
+
+install-lib2: lib/lib1-done
+ install -d $(DISTLIB)/i86
+ install $(INDAT) lib/libbsd.a $(DISTLIB)/i86/libbsd.a
+ install $(INDAT) lib/libc_f.a $(DISTLIB)/i86/libc_f.a
+ install $(INDAT) lib/libc_s.a $(DISTLIB)/i86/libc_s.a
+ install $(INDAT) lib/libdos.a $(DISTLIB)/i86/libdos.a
+
+ install -d $(DISTLIB)/i386
+ install $(INDAT) lib/i386/crt0.o $(DISTLIB)/i386/crt0.o
+ install $(INDAT) lib/i386/libc.a $(DISTLIB)/i386/libc.a
+
+lib/lib0-done:
+ $(MAKE) -f make.fil library
+
+lib/lib1-done:
+ $(MAKE) -f make.fil alt-libs
+
+library: bindir
+ $(MAKEC) libc $(LIBARGS) PLATFORM=i86-ELKS
+ cp -p libc/crt0.o libc/libc.a lib/.
+ @touch lib/lib0-done
+
+alt-libs: lib-bsd lib-fast lib-stand lib-dos lib-386
+ @touch lib/lib1-done
+
+lib-bsd: bindir
+ $(MAKEC) libbsd $(LIBARGS)
+ cp -p libbsd/libbsd.a lib/libbsd.a
+
+lib-fast: bindir
+ $(MAKEC) libc $(LIBARGS) PLATFORM=i86-FAST
+ cp -p libc/libc_f.a lib/libc_f.a
+
+lib-stand: bindir
+ $(MAKEC) libc $(LIBARGS) PLATFORM=i86-BIOS
+ cp -p libc/libc_s.a lib/libc_s.a
+
+lib-dos: bindir
+ $(MAKEC) libc $(LIBARGS) PLATFORM=i86-DOS
+ cp -p libc/libdos.a lib/libdos.a
+
+lib-386: bindir
+ $(MAKEC) libc $(LIBARGS) PLATFORM=i386-BCC
+ cp -p libc/crt3.o lib/i386/crt0.o
+ cp -p libc/libc3.a lib/i386/libc.a
+
+##############################################################################
+
+check_config:
+ $(MAKEC) libc .config.dir
+
+config:
+ $(MAKEC) libc config
+
+makec:
+ echo 'cd $$1 ; shift ; make "$$@"' > makec
+ chmod +x makec
+
+##############################################################################
+
+install-other: phony
+ @for i in $(OTHERS) ; do \
+ $(MAKEC) $$i BCC=ncc DIST=$(DIST) install || exit 1 ; \
+ done
+
+other: phony
+ @for i in $(OTHERS) ; do \
+ $(MAKEC) $$i BCC=ncc || exit 1 ; done
+
+tests: phony
+ $(MAKEC) tests BCC=ncc
+
+clean:
+ -@for i in $(CLEANLIST) ; do $(MAKEC) $$i $@ ; true ; done
+
+realclean:
+ -@for i in $(CLEANLIST) ; do $(MAKEC) $$i $@ ; true ; done
+ rm -rf bin lib
+ rm -f include
+
+##############################################################################
diff --git a/man/Makefile b/man/Makefile
index 38faaaa..b4557a0 100644
--- a/man/Makefile
+++ b/man/Makefile
@@ -1,9 +1,5 @@
-ifneq ($(TOPDIR),)
-include $(TOPDIR)/Make.defs
-else
-MANDIR=/usr/man
-endif
+MANDIR=/usr/man
MAN1PG=as86.1 bcc.1 elks.1 elksemu.1 ld86.1
MAN1DIR=$(MANDIR)/man1
diff --git a/man/as86.1 b/man/as86.1
index e7fff3f..8edbdc7 100644
--- a/man/as86.1
+++ b/man/as86.1
@@ -1,4 +1,4 @@
-.TH as86 1 "Oct, 1996"
+.TH as86 1 "Jan, 1997"
.BY Bruce Evans
.nh
.SH NAME
@@ -124,6 +124,35 @@ take undefined symbols as imported-with-unspecified segment
don't print warnings
.P
.SH AS86 SOURCE
+Special characters
+.TP
+.B *
+Address of the start of the current line.
+.TP
+.B ; !
+Either of these marks the start of a comment. In addition any 'unexpected'
+character at the start of a line is assumed to be a comment.
+.TP
+.B #
+Prefix for immediate operands.
+.TP
+.B $
+Prefix for hexadecimal numbers, the 'C' syntax, eg\ 0x1234, is also accepted.
+.TP
+.B %
+Prefix for binary numbers.
+.TP
+.B [ ]
+Specifies an indirect operand.
+.br
+Offsets from registers are represented by adding the register to the
+expression inside the
+.B [ ]
+brackets. eg:
+.br
+ MOV AX,[BX+Table]
+.br
+.P
Conditionals
.TP
.B IF, ELSE, ELSEIF, ENDIF
@@ -142,7 +171,8 @@ Set current segment. These can be preceded by the keyword
.B .SECT
.TP
.B LOC
-Set numeric segment 0=TEXT, 3=DATA,ROM,BSS, 15=MAX
+Set numeric segment 0=TEXT, 3=DATA,ROM,BSS, 15=MAX. Only segment zero is
+in the text segment, all others are data.
.P
Label type definition
.TP
diff --git a/man/bcc.1 b/man/bcc.1
index ef4c4fb..84234e2 100644
--- a/man/bcc.1
+++ b/man/bcc.1
@@ -1,4 +1,4 @@
-.TH bcc 1 "Oct, 1996"
+.TH bcc 1 "Jan, 1997"
.BY Bruce Evans
.nh
.SH NAME
@@ -86,9 +86,12 @@ don't add default library to search list
.TP
.B -Md
alters the arguments for all passes to produce MSDOS executable COM files.
+These are small model executables, use
+.B -i-
+to get tiny model.
.TP
.B -Mf
-sets the code generator to pass the
+sets bcc to pass the
.B -c
and
.B -f
@@ -96,16 +99,31 @@ arguments to the code generator for smaller faster code. Note this code is
not compatible with the standard calling conventions so a different version
of the C library is linked too.
.TP
+.B -Mc
+sets bcc to pass the
+.B -c
+argument to the code generator for smaller faster code. Note the standard
+libc is normally transparent to this, but there are exceptions.
+.TP
.B -Ms
alters the arguments for all passes and selects C-library
to produce standalone Linux-86 executables
.TP
+.B -Ml
+switches to i386-Linux code generator and library.
+.TP
.B -N
makes the linker produce a native a.out file (Linux OMAGIC) if combined
with -3 the executable will run under Linux-i386.
.TP
.B -O
-optimize (does nothing)
+optimize, call
+.BR copt ( 1 )
+to optimize 8086 code. Specifiers to choose which rules
+.B copt
+should use can be appended to the
+.B -O
+and the option can be repeated.
.TP
.B -P
produce preprocessor output with no line numbers to standard output.
@@ -161,7 +179,7 @@ being searched.
allow the assembler to generate warnings, useful for finding 80186+
instructions.
.P
-Other options are passed to the linker, in particular -i-, -lx, -M, -m, -s.
+Other options are passed to the linker, in particular -i-, -lx, -M, -m, -s, -H.
The -i option is always passed to the linker but can be cancelled using -i-.
.SH CODE GENERATOR OPTIONS
diff --git a/man/elksemu.1 b/man/elksemu.1
index ad6eecc..5f00a44 100644
--- a/man/elksemu.1
+++ b/man/elksemu.1
@@ -1,4 +1,4 @@
-.TH elksemu 1 "Oct, 1996"
+.TH elksemu 1 "Jan, 1997"
.BY Me!
.nh
.SH NAME
diff --git a/man/ld86.1 b/man/ld86.1
index aa83919..de762dd 100644
--- a/man/ld86.1
+++ b/man/ld86.1
@@ -1,4 +1,4 @@
-.TH ld86 1 "Oct, 1996"
+.TH ld86 1 "Jan, 1997"
.BY Bruce Evans
.nh
.SH NAME
@@ -12,6 +12,7 @@ ld86 \- Linker for as86(1)
.RB [ -Llibdir ]
.RB [ -Olibfile ]
.RB [ -Ttextaddr ]
+.RB [ -Hheapsize ]
.RB [ -Ddataaddr ]
.B infile...
@@ -47,6 +48,9 @@ add file libdir-from-search/crtx.o to list of files linked
.B -D
data base address follows (in format suitable for strtoul)
.TP
+.B -H
+the top of heap (initial stack) address (in format suitable for strtoul)
+.TP
.B -Lx
add dir name x to the head of the list of library dirs searched
.TP
diff --git a/mkcompile b/mkcompile
index 6995880..493574e 100644
--- a/mkcompile
+++ b/mkcompile
@@ -27,7 +27,7 @@ main() {
CFLAGS='-nologo -O'
LDFLAGS='%LIB%\setargv.obj -link /NOE'
- ARCH=-Ml
+ ARCH=-Ms
build bcc bcc bin "$HDR_BCC" $SRC_BCC
CFLAGS='-nologo -O -DPOSIX_HEADERS_MISSING'
diff --git a/mkcompile2 b/mkcompile2
new file mode 100644
index 0000000..f61be39
--- /dev/null
+++ b/mkcompile2
@@ -0,0 +1,103 @@
+#!/bin/sh
+
+SRC_BCC='bcc.c'
+SRC_CC1='bcc-cc1.c assign.c codefrag.c debug.c declare.c express.c exptree.c
+ floatop.c function.c gencode.c genloads.c glogcode.c hardop.c input.c
+ label.c loadexp.c longop.c output.c preproc.c preserve.c scan.c
+ softop.c state.c table.c type.c'
+SRC_AS=' as.c assemble.c error.c express.c genbin.c genlist.c genobj.c gensym.c
+ keywords.c macro.c mops.c pops.c readsrc.c scan.c table.c typeconv.c'
+SRC_LD=' ld.c dumps.c io.c linksyms.c readobj.c table.c typeconv.c
+ writebin.c writex86.c'
+
+HDR_BCC=''
+HDR_CC1='align.h byteord.h condcode.h const.h gencode.h input.h label.h os.h
+ output.h parse.h proto.h reg.h sc.h scan.h sizes.h table.h type.h
+ types.h'
+HDR_AS=' address.h byteord.h const.h file.h flag.h globvar.h macro.h opcode.h
+ proto.h scan.h source.h syshead.h type.h'
+HDR_LD=' align.h ar.h bindef.h byteord.h config.h const.h globvar.h obj.h
+ syshead.h type.h x86_aout.h'
+
+main() {
+ echo '@echo off'
+ echo -n 'if not exist later.exe '
+ echo 'bcc -O later.c'
+ echo
+
+ CFLAGS='-O -D__STDC__=1 -DMSDOS'
+ LDFLAGS=''
+ ARCH=
+ build bcc bcc bin "$HDR_BCC" $SRC_BCC
+
+ CFLAGS='-O -D__STDC__=1 -DMSDOS -DPOSIX_HEADERS_MISSING'
+ LDFLAGS=
+ ARCH=-ml
+ build bcc bcc-cc1 lib "$HDR_CC1" $SRC_CC1
+ build as as86 bin "$HDR_AS" $SRC_AS
+ build ld ld86 lib "$HDR_LD" $SRC_LD
+ echo ":exit_now"
+}
+
+build() {
+ DIR="$1" ; shift
+ PRG="$1" ; shift
+ BIN="$1" ; shift
+ HDR="$1" ; shift
+ OBJ=
+ BOBJ=
+ COBJ=
+ LOBJ=
+ SRC="$*"
+
+ for i in $SRC
+ do
+ j=`basename $i .c`
+ check_time $DIR/$j.obj $i $HDR
+ echo -n "if errorlevel 1 "
+
+ echo "bcc $ARCH $CFLAGS -c -I$DIR -o$DIR\\$j.obj $DIR\\$i"
+ if [ "$BOBJ" = "" ]
+ then BOBJ="$DIR\\$j.obj"
+ else LOBJ="$LOBJ +$DIR\\$j.obj"
+ fi
+ COBJ="$COBJ $DIR\\$j.obj"
+ OBJ="$OBJ $j.obj"
+
+ echo "if errorlevel 1 goto exit_now"
+ done
+
+ if [ `echo $COBJ | wc -c` -lt 50 ]
+ then
+ check_time $BIN/$PRG.exe $OBJ
+ echo -n "if errorlevel 1 "
+ echo "bcc $ARCH -e$BIN\\$PRG.exe$COBJ $LDFLAGS"
+ echo "if errorlevel 1 goto exit_now"
+ else
+ check_time $BIN/$PRG.exe $OBJ
+ echo "if not errorlevel 1 goto done_$PRG"
+ echo "if exist doslib.lib del doslib.lib"
+ echo $LOBJ | fmt -62 | \
+ sed 's/\(.*\)/tlib doslib.lib \1/'
+ echo "bcc $ARCH -e$BIN\\$PRG.exe $BOBJ doslib.lib $LDFLAGS"
+ echo "if errorlevel 1 goto exit_now"
+ echo "if exist doslib.lib del doslib.lib"
+ echo "if exist doslib.bak del doslib.bak"
+ echo ":done_$PRG"
+ fi
+ echo
+}
+
+check_time() {
+ TARG="$1" ; shift
+
+ for i
+ do echo "$DIR/$i"
+ done | fmt -70 | \
+ sed -e "s;\(.*\);later $TARG \1@if errorlevel 3 goto exit_now;" \
+ -e '2,$s/^/if not errorlevel 1 /' | \
+ tr '@' '\012'
+}
+
+main "$@" | sed 's/$/ /' > compile.bat
+
diff --git a/tests/Makefile b/tests/Makefile
index 52eb94a..ceb884e 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -2,22 +2,25 @@
# This file is part of the Linux-8086 C library and is distributed
# under the GNU Library General Public License.
-CC=bcc
-CFLAGS=-O -ansi
-LDFLAGS=
+BCC=bcc
+CC=$(BCC)
+CFLAGS=-O -s
-ifeq (Real_make,$(wildcard Real_make))
-include Real_make
-endif
+SRC=env.c ft.c hd.c size.c sync.c compr.c ucomp.c ouch.c lines.c \
+ wc.c line2.c rand.c grab.c
+OBJ=
+EXE=env ft hd size sync compr ucomp ouch lines wc line2 rand grab
-ifneq ($(TOPDIR),)
-starter:
- make -C ../libc/tests fetch_them
- make all
-endif
+LINK_FILES=cat chgrp chmod chown cp install ln mkdir mkfifo mknod mv rm
-not_from_here:
- @echo Do make tests from the top directory
+all: $(EXE)
+
+install links:
+ for i in $(LINK_FILES) ; do ln -s ft $$i ; done
+
+no_links:
+ rm -f $(LINK_FILES)
+
+clean realclean:
+ rm -f $(OBJ) $(EXE) $(LINK_FILES)
-clean:
- rm -f Real_make $(SRC) $(OBJ) $(EXE) $(LINK_FILES)
diff --git a/libc/tests/README b/tests/README
index 4d308c7..1f9bcfd 100644
--- a/libc/tests/README
+++ b/tests/README
@@ -5,18 +5,20 @@ under the GNU Library General Public License.
These are user level tools, they're being used to test libc routines.
env.c Prints the environment and arguments (Plus some junk)
-compr.c Mini compression program (rather slow at times)
+compr.c Mini compression program (rather slow but squeezes better than compress)
ucomp.c Mini uncompression program (Very fast)
ft.c Multiple simple file tools.
hd.c Hex dump.
line2.c Print lines from /etc/passwd (stdio)
lines.c Print lines from /etc/passwd
ouch.c Signal test
-size.c Size of executables and object files.
+size.c Size of Linux-i86 executables and object files.
sync.c :-)
-wc.c Word count.
+wc.c Word,line and character counts.
+grab.c Grabs _all_ available memory (3GB+ on Linux-i386) then frees
+rand.c Generates random numbers and pipes them to 'hd'
BTW: i386 OMAGIC files can be converted to deformed ELFs with this:
- $ ld -N -Ttext 0 --defsym _start=0 sync -o sync1 -s
+ $ objcopy -O elf32-i386 sync
-Robert
diff --git a/libc/tests/compr.c b/tests/compr.c
index 8e53443..8e53443 100644
--- a/libc/tests/compr.c
+++ b/tests/compr.c
diff --git a/libc/tests/env.c b/tests/env.c
index c904969..c904969 100644
--- a/libc/tests/env.c
+++ b/tests/env.c
diff --git a/libc/tests/ft.c b/tests/ft.c
index 1bdc737..1bdc737 100644
--- a/libc/tests/ft.c
+++ b/tests/ft.c
diff --git a/libc/tests/grab.c b/tests/grab.c
index b65fa28..b65fa28 100644
--- a/libc/tests/grab.c
+++ b/tests/grab.c
diff --git a/libc/tests/hd.c b/tests/hd.c
index 341185f..341185f 100644
--- a/libc/tests/hd.c
+++ b/tests/hd.c
diff --git a/libc/tests/line2.c b/tests/line2.c
index 6cc11ff..6cc11ff 100644
--- a/libc/tests/line2.c
+++ b/tests/line2.c
diff --git a/libc/tests/lines.c b/tests/lines.c
index 6f3afb0..6f3afb0 100644
--- a/libc/tests/lines.c
+++ b/tests/lines.c
diff --git a/libc/tests/ouch.c b/tests/ouch.c
index c2925c6..c2925c6 100644
--- a/libc/tests/ouch.c
+++ b/tests/ouch.c
diff --git a/libc/tests/rand.c b/tests/rand.c
index c4fc6d2..c4fc6d2 100644
--- a/libc/tests/rand.c
+++ b/tests/rand.c
diff --git a/tests/size.c b/tests/size.c
new file mode 100644
index 0000000..6b08f46
--- /dev/null
+++ b/tests/size.c
@@ -0,0 +1,83 @@
+#include <fcntl.h>
+#include <a.out.h>
+
+int verbose = 0;
+
+void size(filename)
+ char *filename;
+{
+ int f;
+ struct exec ex;
+ long total;
+ int cc;
+
+ if ((f = open(filename, O_RDONLY)) < 0 )
+ {
+ perror(filename);
+ return;
+ }
+ cc = read(f, &ex, sizeof(ex));
+
+ if (cc == sizeof(ex) && !BADMAG(ex))
+ {
+ total = ex.a_text + ex.a_data + ex.a_bss;
+ if( verbose )
+ {
+ printf("Text segment of %s = %5ld (0x%lx)\n",
+ filename, ex.a_text, ex.a_text);
+ printf("Init data of %s = %5ld (0x%lx)\n",
+ filename, ex.a_data, ex.a_data);
+ printf("Uninit data of %s = %5ld (0x%lx)\n",
+ filename, ex.a_bss, ex.a_bss);
+ printf("Data segment of %s = %5ld (0x%lx)\n",
+ filename, ex.a_total, ex.a_total);
+ printf("Minimum size of %s = %5ld (0x%lx)\n",
+ filename, total, total);
+
+ total = ex.a_total;
+ if( ex.a_flags & A_SEP )
+ total += ex.a_text;
+ printf("Maximum size of %s = %5ld (0x%lx)\n",
+ filename, total, total);
+ }
+ else
+ printf("%-ld\t%-ld\t%-ld\t%-ld\t%-lx\t%s\n",
+ ex.a_text, ex.a_data, ex.a_bss, total, total,
+ filename);
+ }
+ else if( cc > 16 && memcmp(&ex, "\243\206\001\000*", 5) == 0 )
+ { /* *.o file */
+ total = ((unsigned char*)&ex)[9] +
+ ((unsigned char*)&ex)[10] * 256;
+ if( verbose )
+ printf("Size of object %s = %5ld (0x%lx)\n",
+ filename, total, total);
+ else
+ printf("\t\t\t%-ld\t%-lx\t%s\n",
+ total, total, filename);
+ }
+ else
+ printf("%s: Not an a.out file\n", filename);
+ close(f);
+}
+
+int main(argc, argv)
+ int argc;
+ char **argv;
+{
+ if (argc > 1 && strcmp(argv[1], "-v") == 0 )
+ {
+ verbose++;
+ argc--, argv++;
+ }
+ if (argc < 2)
+ {
+ printf("Usage: %s [-v] file\n", argv[0]);
+ exit(1);
+ }
+ if(!verbose)
+ printf("text\tdata\tbss\tdec\thex\tfilename\n");
+ for (--argc, ++argv; argc > 0; --argc, ++argv)
+ size(*argv);
+ exit(0);
+}
diff --git a/libc/tests/sync.c b/tests/sync.c
index 03ca096..03ca096 100644
--- a/libc/tests/sync.c
+++ b/tests/sync.c
diff --git a/libc/tests/ucomp.c b/tests/ucomp.c
index cc3eef8..cc3eef8 100644
--- a/libc/tests/ucomp.c
+++ b/tests/ucomp.c
diff --git a/libc/tests/wc.c b/tests/wc.c
index 08b93ca..08b93ca 100644
--- a/libc/tests/wc.c
+++ b/tests/wc.c
diff --git a/unproto/Makefile b/unproto/Makefile
index d704f8b..957209c 100644
--- a/unproto/Makefile
+++ b/unproto/Makefile
@@ -1,34 +1,68 @@
-# @(#) Makefile 1.3 91/12/01 12:37:57
+# @(#) Makefile 1.6 93/06/18 22:29:40
## BEGIN CONFIGURATION STUFF
-# For maximal flexibility, the "/lib/cpp | unproto" pipeline can be
-# packaged as an executable shell script (see the provided "cpp.sh" script)
-# that should be installed as "/whatever/cpp". This script should then be
-# specified to the C compiler as a non-default preprocessor.
+# In the unlikely case that your compiler has no hooks for alternate
+# compiler passes, use a "cc cflags -E file.c | unproto >file.i"
+# pipeline, then "cc cflags -c file.i" to compile the resulting
+# intermediate file.
+#
+# Otherwise, the "/lib/cpp | unproto" pipeline can be packaged as an
+# executable shell script (see the provided "cpp.sh" script) that should
+# be installed as "/whatever/cpp". This script should then be specified
+# to the C compiler as a non-default preprocessor.
#
PROG = unproto
-PIPE =
+PIPE =
-# For maximal performance, the overhead of shell script inpretation can
-# be eliminated by having the unprototyper program itself open the pipe
-# to the preprocessor. In that case, define the PIPE_THROUGH_CPP macro
-# as the path name of the default C preprocessor (usually "/lib/cpp"),
+# The overhead and problems of shell script interpretation can be
+# eliminated by having the unprototyper program itself open the pipe to
+# the preprocessor. In that case, define the PIPE_THROUGH_CPP macro as
+# the path name of the default C preprocessor (usually "/lib/cpp"),
# install the unprototyper as "/whatever/cpp" and specify that to the C
# compiler as a non-default preprocessor.
-#
+#
# PROG = cpp
# PIPE = -DPIPE_THROUGH_CPP=\"/lib/cpp\"
-# Some compilers complain about some #directives. The following is only a
+# Some compilers complain about some #directives. The following is only a
# partial solution, because the directives are still seen by /lib/cpp.
-# Be careful with filtering out #pragma, because some non-ANSI compilers
+# Be careful with filtering out #pragma, because some pre-ANSI compilers
# (SunOS) rely on its use.
#
# SKIP = -DIGNORE_DIRECTIVES=\"pragma\",\"foo\",\"bar\"
#
SKIP =
+# The bell character code depends on the character set. With ASCII, it is
+# 7. Specify a string constant with exactly three octal digits. If you
+# change this definition, you will have to update the example.out file.
+#
+BELL = -DBELL=\"007\"
+
+# Some C compilers have problems with "void". The nature of the problems
+# depends on the age of the compiler.
+#
+# If your compiler does not understand "void" at all, compile with
+# -DMAP_VOID. The unprototyper will replace "void *" by "char *", a
+# (void) argument list by an empty one, and will replace all other
+# instances of "void" by "int".
+#
+# If your compiler has problems with "void *" only, compile with
+# -DMAP_VOID_STAR. The unprototyper will replace "void *" by "char *",
+# and will replace a (void) argument list by an empty one. All other
+# instances of "void" will be left alone.
+#
+# If neither of these are defined, (void) argument lists will be replaced
+# by empty ones.
+#
+# MAP = -DMAP_VOID_STAR
+
+# Now that we have brought up the subject of antique C compilers, here's
+# a couple of aliases that may be useful, too.
+#
+# ALIAS = -Dstrchr=index
+
# If you need support for functions that implement ANSI-style variable
# length argument lists, edit the stdarg.h file provided with this
# package so that it contains the proper definitions for your machine.
@@ -37,43 +71,38 @@ SKIP =
SHELL = /bin/sh
-CFILES = tok_io.c tok_class.c tok_pool.c unproto.c vstring.c symbol.c error.c
+CFILES = unproto.c tok_io.c tok_class.c tok_pool.c vstring.c symbol.c error.c \
+ hash.c strsave.c
HFILES = error.h token.h vstring.h symbol.h
-SCRIPTS = cpp.sh
-SAMPLES = stdarg.h varargs.c example.c example.out
-SOURCES = README Makefile $(CFILES) $(HFILES) $(SCRIPTS) $(SAMPLES)
+SCRIPTS = cpp.sh acc.sh
+SAMPLES = stdarg.h stddef.h stdlib.h varargs.c example.c example.out
+SOURCES = README $(CFILES) $(HFILES) Makefile $(SCRIPTS) $(SAMPLES)
FILES = $(SOURCES) unproto.1
-OBJECTS = tok_io.o tok_class.o tok_pool.o unproto.o vstring.o symbol.o error.o
+OBJECTS = tok_io.o tok_class.o tok_pool.o unproto.o vstring.o symbol.o error.o \
+ hash.o strsave.o
-ifneq ($(TOPDIR),)
-include $(TOPDIR)/Make.defs
-CFLAGS=$(CCFLAGS) -w $(PIPE) $(SKIP)
-# I'm fed up, '-w' will shut GCC up about this nasty code!
-else
-CC=bcc
-CFLAGS=-O $(PIPE) $(SKIP)
-LDFLAGS=-s
-endif
+CFLAGS = -O
+LDFLAGS =
+CCFLAGS = $(CFLAGS) -w $(PIPE) $(SKIP) $(BELL) $(MAP) $(ALIAS) -DREOPEN
-#CFLAGS = -O -pg -Dstatic= $(PIPE) $(SKIP)
-#CFLAGS = -g $(PIPE) $(SKIP) -DDEBUG
+#CFLAGS = -O $(PIPE) $(SKIP) $(BELL) $(MAP) $(ALIAS) -p -Dstatic=
+#CFLAGS = -g $(PIPE) $(SKIP) $(BELL) $(MAP) $(ALIAS) -DDEBUG
$(PROG): $(OBJECTS)
- $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(MALLOC)
+ $(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(MALLOC)
-install: $(PROG)
- install -d $(LIBDIR)
- install -m 755 $(PROG) $(LIBDIR)/unproto
+.c.o:
+ $(CC) $(CCFLAGS) -c $< -o $@
# For linting, enable all bells and whistles.
lint:
lint -DPIPE_THROUGH_CPP=\"foo\" -DIGNORE_DIRECTIVES=\"foo\",\"bar\" \
- $(CFILES)
+ $(BELL) -DMAP_VOID $(ALIAS) $(CFILES)
-# Testing requires that the program is compiled with -DDEBUG
+# Testing requires that the program is compiled with -DDEBUG.
-test: $(PROG) example.c example.out
+test: $(PROG) cpp example.c example.out
./cpp example.c >example.tmp
@echo the following diff command should produce no output
diff -b example.out example.tmp
@@ -85,14 +114,16 @@ shar: $(FILES)
archive:
$(ARCHIVE) $(SOURCES)
-clean:
+clean realclean:
rm -f *.o core cpp unproto mon.out varargs.o varargs example.tmp
error.o : error.c token.h error.h Makefile
-symbol.o : symbol.c token.h symbol.h Makefile
+hash.o : hash.c Makefile
+strsave.o : strsave.c error.h Makefile
+symbol.o : symbol.c error.h token.h symbol.h Makefile
tok_class.o : tok_class.c error.h vstring.h token.h symbol.h Makefile
tok_io.o : tok_io.c token.h vstring.h error.h Makefile
-tok_pool.o : tok_pool.c token.h vstring.h Makefile
+tok_pool.o : tok_pool.c token.h vstring.h error.h Makefile
unproto.o : unproto.c vstring.h stdarg.h token.h error.h symbol.h Makefile
varargs.o : varargs.c stdarg.h Makefile
vstring.o : vstring.c vstring.h Makefile
diff --git a/unproto/Makefile.old b/unproto/Makefile.old
new file mode 100644
index 0000000..2d7a98c
--- /dev/null
+++ b/unproto/Makefile.old
@@ -0,0 +1,123 @@
+# @(#) Makefile 1.6 93/06/18 22:29:40
+
+## BEGIN CONFIGURATION STUFF
+
+# In the unlikely case that your compiler has no hooks for alternate
+# compiler passes, use a "cc cflags -E file.c | unproto >file.i"
+# pipeline, then "cc cflags -c file.i" to compile the resulting
+# intermediate file.
+#
+# Otherwise, the "/lib/cpp | unproto" pipeline can be packaged as an
+# executable shell script (see the provided "cpp.sh" script) that should
+# be installed as "/whatever/cpp". This script should then be specified
+# to the C compiler as a non-default preprocessor.
+#
+# PROG = unproto
+# PIPE =
+
+# The overhead and problems of shell script interpretation can be
+# eliminated by having the unprototyper program itself open the pipe to
+# the preprocessor. In that case, define the PIPE_THROUGH_CPP macro as
+# the path name of the default C preprocessor (usually "/lib/cpp"),
+# install the unprototyper as "/whatever/cpp" and specify that to the C
+# compiler as a non-default preprocessor.
+#
+PROG = cpp
+PIPE = -DPIPE_THROUGH_CPP=\"/lib/cpp\"
+
+# Some compilers complain about some #directives. The following is only a
+# partial solution, because the directives are still seen by /lib/cpp.
+# Be careful with filtering out #pragma, because some pre-ANSI compilers
+# (SunOS) rely on its use.
+#
+# SKIP = -DIGNORE_DIRECTIVES=\"pragma\",\"foo\",\"bar\"
+#
+SKIP =
+
+# The bell character code depends on the character set. With ASCII, it is
+# 7. Specify a string constant with exactly three octal digits. If you
+# change this definition, you will have to update the example.out file.
+#
+BELL = -DBELL=\"007\"
+
+# Some C compilers have problems with "void". The nature of the problems
+# depends on the age of the compiler.
+#
+# If your compiler does not understand "void" at all, compile with
+# -DMAP_VOID. The unprototyper will replace "void *" by "char *", a
+# (void) argument list by an empty one, and will replace all other
+# instances of "void" by "int".
+#
+# If your compiler has problems with "void *" only, compile with
+# -DMAP_VOID_STAR. The unprototyper will replace "void *" by "char *",
+# and will replace a (void) argument list by an empty one. All other
+# instances of "void" will be left alone.
+#
+# If neither of these are defined, (void) argument lists will be replaced
+# by empty ones.
+#
+# MAP = -DMAP_VOID_STAR
+
+# Now that we have brought up the subject of antique C compilers, here's
+# a couple of aliases that may be useful, too.
+#
+# ALIAS = -Dstrchr=index
+
+# If you need support for functions that implement ANSI-style variable
+# length argument lists, edit the stdarg.h file provided with this
+# package so that it contains the proper definitions for your machine.
+
+## END CONFIGURATION STUFF
+
+SHELL = /bin/sh
+
+CFILES = unproto.c tok_io.c tok_class.c tok_pool.c vstring.c symbol.c error.c \
+ hash.c strsave.c
+HFILES = error.h token.h vstring.h symbol.h
+SCRIPTS = cpp.sh acc.sh
+SAMPLES = stdarg.h stddef.h stdlib.h varargs.c example.c example.out
+SOURCES = README $(CFILES) $(HFILES) Makefile $(SCRIPTS) $(SAMPLES)
+FILES = $(SOURCES) unproto.1
+OBJECTS = tok_io.o tok_class.o tok_pool.o unproto.o vstring.o symbol.o error.o \
+ hash.o strsave.o
+
+CFLAGS = -O $(PIPE) $(SKIP) $(BELL) $(MAP) $(ALIAS)
+#CFLAGS = -O $(PIPE) $(SKIP) $(BELL) $(MAP) $(ALIAS) -p -Dstatic=
+#CFLAGS = -g $(PIPE) $(SKIP) $(BELL) $(MAP) $(ALIAS) -DDEBUG
+
+$(PROG): $(OBJECTS)
+ $(CC) $(CFLAGS) -o $@ $(OBJECTS) $(MALLOC)
+
+# For linting, enable all bells and whistles.
+
+lint:
+ lint -DPIPE_THROUGH_CPP=\"foo\" -DIGNORE_DIRECTIVES=\"foo\",\"bar\" \
+ $(BELL) -DMAP_VOID $(ALIAS) $(CFILES)
+
+# Testing requires that the program is compiled with -DDEBUG.
+
+test: $(PROG) cpp example.c example.out
+ ./cpp example.c >example.tmp
+ @echo the following diff command should produce no output
+ diff -b example.out example.tmp
+ rm -f example.tmp
+
+shar: $(FILES)
+ @shar $(FILES)
+
+archive:
+ $(ARCHIVE) $(SOURCES)
+
+clean:
+ rm -f *.o core cpp unproto mon.out varargs.o varargs example.tmp
+
+error.o : error.c token.h error.h Makefile
+hash.o : hash.c Makefile
+strsave.o : strsave.c error.h Makefile
+symbol.o : symbol.c error.h token.h symbol.h Makefile
+tok_class.o : tok_class.c error.h vstring.h token.h symbol.h Makefile
+tok_io.o : tok_io.c token.h vstring.h error.h Makefile
+tok_pool.o : tok_pool.c token.h vstring.h error.h Makefile
+unproto.o : unproto.c vstring.h stdarg.h token.h error.h symbol.h Makefile
+varargs.o : varargs.c stdarg.h Makefile
+vstring.o : vstring.c vstring.h Makefile
diff --git a/unproto/README b/unproto/README
index 6856d3a..1074874 100644
--- a/unproto/README
+++ b/unproto/README
@@ -1,76 +1,79 @@
-@(#) README 1.3 91/12/01 12:37:55
+@(#) README 1.6 93/06/18 22:29:34
-unproto - ANSI C to old C converter
+unproto - Compile ANSI C with traditional UNIX C compiler
-Purpose:
+Description:
+------------
-This is a filter that sits in between the C preprocessor and the next C
-compiler stage, and that on the fly rewrites ANSI C to old C. Its
-primary application is to compile ANSI C software in UNIX environments
-that do not (yet) have an ANSI C compiler and that cannot run GCC
-because of technical or political problems.
+This is a filter that sits in between the UNIX C preprocessor and the
+next UNIX C compiler stage, on the fly transforming ANSI C syntax to
+old C syntax. Line number information is preserved so that compiler
+diagnostics still make sense. It runs at roughly the same speed as
+/lib/cpp, so it has negligible impact on compilation time.
-The filter leaves old-style C alone, and de-ANSI-fies function
-headings, function pointer type declarations (and casts), function type
-declarations, and combinations thereof. Many freely-distributable
-unprotoizers have problems with the latter because they are based on a
-non-recursive algorithm or even make assumptions about code layout.
+Typically, the program is invoked by the native UNIX C compiler as an
+alternate preprocessor. The unprototyper in turn invokes the native C
+preprocessor and massages its output. Similar tricks can be used with
+the lint(1) command. Details are given below.
-The unprototyper has support for systems that require special tricks
-for variadic functions (fortunately, many don't). A sample `stdarg.h'
-file is provided with support for sparc, mc68k, 80x86, vax and others.
+The filter rewrites ANSI-style function headings, function pointer
+types and type casts, function prototypes, and combinations thereof.
+Unlike some other unprototypers, this one is fully recursive and does
+not depend on source file layout (see the example.c file).
-The program has been tested on a Sun SLC running SunOS 4.1.1 and on a
-80286 PC clone running Microport's version of System V Release 2. It
-runs at about the same speed as /lib/cpp, so it should have negigible
-impact on compilation times.
+Besides the rewriting of argument lists, the program does the following
+transformations: string concatenation, conversion of \a and \x escape
+sequences to their octal equivalents, translation of the __TIME__ and
+__DATE__ macros, optional mapping of `void *' to `char *', and optional
+mapping of plain `void' to `int'.
-Problems solved with this release:
+The unprototyper provides hooks for compilers that require special
+tricks for variadic functions (fortunately, many don't). <stdarg.h>
+support is provided for sparc, mips, mc68k, 80x86, vax, and others.
-Minor: the program was originally intended for the compilation of
-already tested ANSI C source, so that diagnostics from the native C
-compiler would be sufficient. The present release produces better
-diagnostics, so that it can also be used for program development.
-
-Major: the template Makefile suggested that all #pragma directives be
-filtered out. This turns out to be a bad idea because some non-ANSI
-compilers (SunOS) rely on #pragmas to correctly handle the unusual flow
-control caused by vfork(2), setjmp(3) etcetera. A warning to this
-effect has been added to the Makefile.
-
-No changes were made to the actual filter logic; output should be
-identical to that of the previous release.
+The program has been tested with SunOS 4.1.1 (sparc), Ultrix 4.0 and
+4.2 (mips), and Microport System V Release 2 (80286). It should work
+with almost every PCC-based UNIX C compiler.
Restrictions:
+-------------
-Other ANSI-isms are just passed on without modification, such as
-trigraphs, token pasting (##), #pragmas, stringizing (#text) and
-string concatenation ("string1" "string2").
+A description of restrictions and workarounds can be found in the
+unproto.1 manual page.
-The unprototyper does not understand declarations of (object). The
-result (the object disappears) will be a syntax error so this should
-not go by unnoticed.
+Problems fixed with this release:
+---------------------------------
-Some C programmers rely on ANSI-style prototypes for the automatic type
-conversion of function arguments. The unprototyper, however, does not
-generate casts. The lack of automatic conversion between integral
-and/or pointer argument types should not be a problem in environments
-where sizeof(int) == sizeof(long) == sizeof(pointer). A more serious
-problem is the lack of automatic type conversions beteen integral and
-floating-point function argument types. Let lint(1) be your friend.
+Prototypes and definitions of functions returning pointer to function
+were not rewritten to old style.
Operation:
+----------
-This package implements an non-default C preprocessor (the output from
+This package implements a non-default C preprocessor (the output from
the default C preprocessor being piped through the unprototyper). How
-one tells the C compiler to use an non-default preprocessor program is
+one tells the C compiler to use a non-default preprocessor program is
somewhat compiler-dependent:
- SunOS 4.x: cc -Qpath directory_with_non-default_cpp ...
+ SunOS 4.x: cc -Qpath directory_with_alternate_cpp ...
+
+ Ultrix 4.x: cc -tp -hdirectory_with_alternate_cpp -B ...
+
+ System V.2: cc -Bdirectory_with_alternate_cpp/ -tp ...
+
+Examples of these, and others, can be found in the acc.sh shell script
+that emulates an ANSI C compiler. Your C compiler manual page should
+provide the necessary information.
- SysV Rel2: cc -Bdirectory_with_non-default_cpp/ -tp ...
+A more portable, but less efficient, approach relies on the observation
+that almost every UNIX C compiler supports the -E (write preprocessor
+output to stdout) and -P options (preprocess file.c into file.i). Just
+add the following lines to your Makefiles:
-Your C compiler manual should provide the necessary information.
+ .c.o:
+ $(CC) $(CFLAGS) -E $*.c | unproto >$*.i # simulate -P option
+ $(CC) $(CFLAGS) -c $*.i
+ rm -f $*.i
On some systems the lint(1) command is just a shell script, and writing
a version that uses the unprototyper should not be too hard. With SunOS
@@ -82,49 +85,76 @@ You may have to do some research on the lint command provided with your
own machine.
Configuration:
+--------------
Check the contents of the `stdarg.h' file provided with this package.
-This file serves a dual purpose. It should be included by C source file
-that implements ANSI-style variadic functions. It is also used to
-configure the `unproto' program so that it emits the proper magic for
-the `...' construct.
+This file serves a dual purpose: (1) on systems that do not provide a
+stdarg.h file, it should be included by C source files that implements
+ANSI-style variadic functions; (2) it is also used to configure the
+unprototyper so that it emits the proper magic when it sees `...'.
-The `stdarg.h' file contains definitions for the sparc architecture and
-for architectures that pass arguments via the stack (usually OK for
-80*86, mc68k and vax C compilers). Risc processors often need special
-tricks. These are usually found in the file `/usr/include/varargs.h'.
+The `stdarg.h' file has support for sparc, mips, and for compilers that
+pass arguments via the stack (typical for 80*86, mc68k and vax). It
+gives general hints for other compilers.
-The file `varargs.c' provided with this package can be used to verify
-that the `stdarg.h' file has been set up correctly.
+The other sample header files (stddef.h and stdlib.h) are not required
+to build the unprototyper.
-For maximal flexibility, you can use the `cpp' shell script provided
-with this package to set up the pipe between the default C preprocessor
-and the unprototyper command. The script assumes that the unprototyper
-binary is called `unproto'. See the cpp.sh script and the Makefile for
-details.
+The `varargs.c' file provided with this package can be used to verify
+that the `stdarg.h' file has been set up correctly.
-The overhead of shell-script interpretation can be avoided by having
-the unprototyper itself open the pipe to the C preprocessor. In this
-case, the `unproto.c' source file should be compiled with the
-`PIPE_THROUGH_CPP' macro defined as the pathname of the C preprocessor
-(usually `/lib/cpp'), and the unprototyper binary should be called
-`cpp'. See the Makefile for details.
+If your C compiler has no hooks for an alternate preprocessor (the
+unprototyper will be used as: `cc cflags -E file.c | unproto >file.i'),
+build the `unproto' executable without the `PIPE_THROUGH_CPP' feature.
+Details are given in the Makefile.
+
+Otherwise, the `cpp.sh' shell script can be used to set up the pipe
+between the native C preprocessor and the unprototyper command. The
+script assumes that the unprototyper binary is called `unproto', and
+that it was compiled without the `PIPE_THROUGH_CPP' feature. See the
+Makefile and the `cpp.sh' script for details and for a description of
+possible problems with this approach.
+
+The overhead and problems of shell-script interpretation can be avoided
+by letting the unprototyper itself pipe its standard input through the
+C preprocessor. For this mode of operation, the unprototyper binary
+should be called `cpp', and the `unproto.c' source file should be
+compiled with the `PIPE_THROUGH_CPP' macro defined as the absolute
+pathname of the native C preprocessor (usually `/lib/cpp'). See the
+Makefile for details.
Installation:
+-------------
+
+Install the `unproto.1' manual page in a suitable place. If your system
+does not provide a `stdarg.h' file, find a suitable place for the one
+provided with the unprototyper and install it there. The same goes for
+the sample stddef.h and stdlib.h files; make sure that the definitions
+in there apply to your environment. Most or all of the latter files are
+already part of Ultrix 4.x and SunOS 4.1.1.
+
+The ANSI float.h and limits.h files can be generated with the config
+program by Steve Pemberton (comp.sources.misc volume 10, issue 62,
+available from ftp.uu.net as comp.sources.misc/volume10/config42.Z).
-Install the `stdarg.h' include file and the `unproto.1' manual page in
-suitable places.
+If you run the unprototyper with "cc -E" just install the `unproto'
+binary; the `cpp' and `acc' shell scripts will not be needed.
If you use the `cpp' shell script to pipe the preprocessor output
through the unprototyper program, install the `unproto' binary in a
place where the `cpp' shell script can find it, and install the `cpp'
-shell script in a suitable place.
+shell script in a suitable place. Edit the `acc' shell script and
+install it in a suitable place. From now on, type `acc' instead of
+`cc'.
If the unprototyper itself opens the pipe to the C preprocessor (i.e.
the unprototyper was built with the `PIPE_THROUGH_CPP' macro defined),
-install the `cpp' unprototyper binary in a suitable place.
+install the `cpp' unprototyper binary in a suitable place. Edit the
+`acc' shell script and install it in a suitable place. From now on,
+type `acc' instead of `cc'.
Wietse Venema
wietse@wzv.win.tue.nl
+ Mathematics and Computing Science
Eindhoven University of Technology
The Netherlands
diff --git a/unproto/Shar.Headers b/unproto/Shar.Headers
deleted file mode 100644
index d707a4f..0000000
--- a/unproto/Shar.Headers
+++ /dev/null
@@ -1,50 +0,0 @@
-Newsgroups: comp.sources.misc
-From: wietse@wzv.win.tue.nl (Wietse Venema)
-Subject: v26i094: unproto - compile ANSI C with old C compiler, Part01/02
-Message-ID: <csm-v26i094=unproto.083344@sparky.IMD.Sterling.COM>
-X-Md4-Signature: 69685c0673793ce6c539657a3d1de2ab
-Date: Sun, 1 Dec 1991 14:35:08 GMT
-Approved: kent@sparky.imd.sterling.com
-
-Submitted-by: wietse@wzv.win.tue.nl (Wietse Venema)
-Posting-number: Volume 26, Issue 94
-Archive-name: unproto/part01
-Environment: SYSV2, SunOS
-Supersedes: unproto: Volume 23, Issue 12-13
-
-This is a filter that sits in between the C preprocessor and the next C
-compiler stage, and that on the fly rewrites ANSI C to old C. Its
-primary application is to compile ANSI C software in UNIX environments
-that do not (yet) have an ANSI C compiler and that cannot run GCC
-because of technical or political problems.
-
-Problems solved with this release:
-
-Minor: the program was originally intended for the compilation of
-already tested ANSI C source, so that diagnostics from the native C
-compiler would be sufficient. The present release produces better
-diagnostics, so that it can also be used for program development.
-
-Major: the template Makefile suggested that all #pragma directives be
-filtered out. This turns out to be a bad idea because some non-ANSI
-compilers (SunOS) rely on #pragmas to correctly handle the unusual flow
-control caused by vfork(2), setjmp(3) etcetera. A warning to this
-effect has been added to the Makefile.
-
-No changes were made to the actual filter logic; output should be
-identical to that of the previous release.
-
-Newsgroups: comp.sources.misc
-From: wietse@wzv.win.tue.nl (Wietse Venema)
-Subject: v26i095: unproto - compile ANSI C with old C compiler, Part02/02
-Message-ID: <1991Dec1.143532.21763@sparky.imd.sterling.com>
-X-Md4-Signature: e41270a11de3ed19fd262a273924fc94
-Date: Sun, 1 Dec 1991 14:35:32 GMT
-Approved: kent@sparky.imd.sterling.com
-
-Submitted-by: wietse@wzv.win.tue.nl (Wietse Venema)
-Posting-number: Volume 26, Issue 95
-Archive-name: unproto/part02
-Environment: SYSV2, SunOS
-Supersedes: unproto: Volume 23, Issue 12-13
-
diff --git a/unproto/Sharheader b/unproto/Sharheader
new file mode 100644
index 0000000..6ed61fe
--- /dev/null
+++ b/unproto/Sharheader
@@ -0,0 +1,6 @@
+
+# Contents: README unproto.c tok_io.c tok_class.c tok_pool.c vstring.c
+# symbol.c error.c hash.c strsave.c error.h token.h vstring.h
+# symbol.h Makefile cpp.sh acc.sh stdarg.h stddef.h stdlib.h
+# varargs.c example.c example.out unproto.1
+# Wrapped by wietse@wzv on Fri Jun 18 22:48:56 1993
diff --git a/unproto/acc.sh b/unproto/acc.sh
new file mode 100644
index 0000000..124e700
--- /dev/null
+++ b/unproto/acc.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+# @(#) acc.sh 1.1 93/06/18 22:29:42
+#
+# Script to emulate most of an ANSI C compiler with a traditional UNIX
+# C compiler.
+
+# INCDIR should be the directory with auxiliary include files from the
+# unproto source distribution (stdarg.h, stdlib.h, stddef.h, and other
+# stuff that is missing from your compilation environment). With Ultrix
+# 4.[0-2] you need unproto's stdarg.h even though the system provides
+# one.
+#
+INCDIR=.
+
+# CPPDIR should be the directory with the unprototypeing cpp filter
+# (preferably the version with the PIPE_THROUGH_CPP feature).
+#
+CPPDIR=.
+
+# DEFINES: you will want to define volatile and const, and maybe even
+# __STDC__.
+#
+DEFINES="-Dvolatile= -Dconst= -D__STDC__"
+
+# Possible problem: INCDIR should be listed after the user-specified -I
+# command-line options, not before them as we do here. This is a problem
+# only if you attempt to redefine system libraries.
+#
+# Choose one of the commands below that is appropriate for your system.
+#
+exec cc -Qpath ${CPPDIR} -I${INCDIR} ${DEFINES} "$@" # SunOS 4.x
+exec cc -tp -h${CPPDIR} -B -I${INCDIR} ${DEFINES} "$@" # Ultrix 4.2
+exec cc -Yp,${CPPDIR} -I${INCDIR} ${DEFINES} "$@" # M88 SysV.3
+exec cc -B${CPPDIR}/ -tp -I${INCDIR} ${DEFINES} "$@" # System V.2
diff --git a/unproto/cpp.sh b/unproto/cpp.sh
index 8122b68..a039146 100644
--- a/unproto/cpp.sh
+++ b/unproto/cpp.sh
@@ -1,9 +1,35 @@
#!/bin/sh
-# @(#) cpp.sh 1.2 91/09/22 21:21:43
+# @(#) cpp.sh 1.3 92/01/15 21:53:22
-# Unprototypeing preprocessor for non-ANSI C compilers. Define __STDC__
-# if you have enough courage. You will have to modify this script if
-# your cc(1) command specifies output file names to the preprocessor.
+# Unprototypeing preprocessor for pre-ANSI C compilers. On some systems,
+# this script can be as simple as:
+#
+# /lib/cpp "$@" | unproto
+#
+# However, some cc(1) drivers specify output file names on the
+# preprocessor command line, so this shell script must be prepared to
+# intercept them. Depending on the driver program, the cpp options may
+# even go before or after the file name argument(s). The script below
+# tries to tackle all these cases.
+#
+# You may want to add -Ipath_to_stdarg.h_file, -Dvoid=, -Dvolatile=,
+# and even -D__STDC__.
-exec /lib/cpp "$@" -Dconst= -Dvolatile= | unproto
+cpp_args=""
+
+while :
+do
+ case $1 in
+ "") break;;
+ -*) cpp_args="$cpp_args $1";;
+ *) cpp_args="$cpp_args $1"
+ case $2 in
+ ""|-*) ;;
+ *) exec 1> $2 || exit 1; shift;;
+ esac;;
+ esac
+ shift
+done
+
+/lib/cpp $cpp_args | unproto
diff --git a/unproto/error.c b/unproto/error.c
index bc9702b..667d978 100644
--- a/unproto/error.c
+++ b/unproto/error.c
@@ -8,18 +8,22 @@
/* SYNOPSIS
/* #include "error.h"
/*
-/* void error(quit, text)
-/* int quit;
+/* int errcount;
+/*
+/* void error(text)
/* char *text;
/*
-/* void error_where(quit, path, line, text)
-/* int quit;
+/* void error_where(path, line, text)
/* char *path;
/* int line;
/* char *text;
+/*
+/* void fatal(text)
+/* char *text;
/* DESCRIPTION
-/* The routines in this file print a diagnostic (text) and optionally
-/* terminate the program (quit != 0) with exit status "quit".
+/* The routines in this file print a diagnostic (text). Some also
+/* terminate the program. Upon each error*() call, the errcount variable
+/* is incremented.
/*
/* error() provides a default context, i.e. the source-file
/* coordinate of the last read token.
@@ -27,6 +31,9 @@
/* error_where() allows the caller to explicitly specify context: path
/* is a source-file name, and line is a line number.
/*
+/* fatal() is like error() but terminates the program with a non-zero
+/* exit status.
+/*
/* context is ignored if the line number is zero or if the path
/* is an empty string.
/* AUTHOR(S)
@@ -35,44 +42,56 @@
/* Department of Mathematics and Computer Science
/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
/* LAST MODIFICATION
-/* 91/11/30 21:10:35
+/* 92/01/15 21:53:10
/* VERSION/RELEASE
-/* 1.1
+/* 1.2
/*--*/
-static char error_sccsid[] = "@(#) error.c 1.1 91/11/30 21:10:35";
+static char error_sccsid[] = "@(#) error.c 1.2 92/01/15 21:53:10";
/* C library */
#include <stdio.h>
-void exit();
+extern void exit();
/* Application-specific stuff */
#include "token.h"
#include "error.h"
-/* error - report problem (implicit context) and optionally quit */
+int errcount = 0; /* error counter */
-void error(quit, text)
-int quit;
+/* error - report problem (implicit context) */
+
+void error(text)
char *text;
{
- error_where(quit, curr_path, curr_line, text);
+ error_where(in_path, in_line, text);
}
-/* error_where - report problem (explicit context) and optionally quit */
+/* error_where - report problem (explicit context) */
-void error_where(quit, path, line, text)
-int quit;
+void error_where(path, line, text)
char *path;
int line;
char *text;
{
+ errcount++;
+
+ /* Suppress context info if there is none. */
+
if (line && path[0])
fprintf(stderr, "%s, line %d: ", path, line);
+
fprintf(stderr, "%s\n", text);
- if (quit)
- exit(quit);
+}
+
+/* fatal - report problem and terminate unsuccessfully */
+
+void fatal(text)
+char *text;
+{
+ error(text);
+ exit(1);
}
diff --git a/unproto/error.h b/unproto/error.h
index 579906d..dfb27e9 100644
--- a/unproto/error.h
+++ b/unproto/error.h
@@ -1,4 +1,6 @@
-/* @(#) error.h 1.1 91/11/30 21:10:36 */
+/* @(#) error.h 1.2 92/01/15 21:53:14 */
+extern int errcount; /* error counter */
extern void error(); /* default context */
extern void error_where(); /* user-specified context */
+extern void fatal(); /* fatal error */
diff --git a/unproto/example.c b/unproto/example.c
index 003df4a..bf2f838 100644
--- a/unproto/example.c
+++ b/unproto/example.c
@@ -1,9 +1,11 @@
/*
- * @(#) example.c 1.2 91/09/22 21:21:45
+ * @(#) example.c 1.5 93/06/18 22:29:46
*
* Examples of things that can be done with the unproto package
*/
+typedef char *charstar;
+
/*
* New-style argument list with structured argument, one field being pointer
* to function returning pointer to function with function-pointer argument
@@ -17,14 +19,23 @@ x(struct {
return (0);
}
+ /* New-style function-pointer declaration. */
+
+int (*(*bar0) (float)) (int);
+
+ /* Old-style argument list with new-style argument type. */
+
+baz0(bar)
+int (*(*bar) (float)) (int);
+{}
+
/*
- * Old-style argument list with new-style argument type, declaration
+ * New-style argument list with new-style argument type, declaration
* embedded within block. Plus a couple assignments with function calls that
* look like casts.
*/
-foo(bar)
-int (*(*bar) (float)) (int);
+foo(int (*(*bar) (float)) (int))
{
int (*baz) (int) = (int (*) (int)) 0,
y = (y * (*baz) (y)),
@@ -55,9 +66,9 @@ test1()
/* Discriminate declarations from executable statements */
-test2(char *y)
+test2(charstar y)
{
- int foo = 5,atoi(char *);
+ int foo = 5,atoi(charstar);
foo = 5,atoi(y);
}
@@ -103,7 +114,7 @@ test8(x)
{
struct {
int foo;
- } bar(int);
+ } bar(charstar);
}
{
do {
@@ -138,3 +149,74 @@ test11(int *x)
while (*x)
(putchar(*x++));
}
+
+test11a(int *x)
+{
+ for (*x;;)
+ (putchar(*x++));
+}
+
+/* #include directive between stuff that requires lookahead */
+
+test12()
+{
+ char *x = "\xf\0002\002\02\2" /* foo */
+#include "/dev/null"
+ "\abar";
+
+ printf("foo" /* 1 */ "bar" /* 2 */ "baz");
+
+ *x = '\a';
+ *x = '\xff';
+}
+
+int test13(void);
+
+/* line continuations in the middle of tokens */
+
+te\
+st14();
+charstar test15 = "foo\
+bar";
+char test16 = "foo\\
+abar";
+
+/* Array dimensions with unexpanded macros */
+
+test17(charstar foo[bar]){}
+
+int (*(*test18[bar])(charstar))(charstar) = \
+ (int (*(*[bar])(charstar))(charstar)) 0;
+
+/* Function returning pointer to function */
+
+int (*(*test19(long))(int))(double);
+
+/* GCC accepts the following stuff, K&R C does not... */
+
+void test20(int test21(double)) {}
+
+void test22(struct { int foo; } test23(short)) {}
+
+/* Do not blindly rewrite (*name(stuff))(otherstuff) */
+
+void test23()
+{
+ int (*test24(int)) (int),
+ y = (*test24(2)) (3),
+ z = ((*test24(2)) (3));
+}
+
+/* Function returning pointer to function */
+
+int (*(*test25(long foo))(int bar))(double baz){ /* body */ }
+
+int (*(*test26(foo))())()
+long foo;
+{ /* body */ }
+
+#define ARGSTR() struct {int l; char c[1];}
+
+void functie(ARGSTR() *cmdlin, ARGSTR() *c1)
+{
+}
diff --git a/unproto/example.out b/unproto/example.out
index 6dc75f3..0b14e1b 100644
--- a/unproto/example.out
+++ b/unproto/example.out
@@ -5,37 +5,54 @@
+typedef char *charstar;
+
-x
+x(
-(baz)
-# 16 "example.c"
-struct { struct { int (*(*foo)())(); } foo;} baz;
-# 16 "example.c"
+baz)
+# 14 "example.c"
+struct {
+ struct {
+ int (*(*foo)())();
+ } foo;
+} baz;
+# 18 "example.c"
{/*1*/
/* end dcls */return (0);
}/*1*/
+int (*(*bar0)())();
+
+
+
+baz0(bar)
+int (*(*bar)())();
+{/*1*/}/*1*/
+
+
+
-foo
-(bar)int (*(*bar)())();
+foo(bar)
+# 38 "example.c"
+int (*(*bar)())();
{/*1*/
- int (*baz)() = (int (*)()) 0,
+ int (*baz)()= (int (*)()) 0,
y = (y * (*baz)(y)),
- *(*z)() = (int *(*)()) 0;
+ *(*z)()= (int *(*)()) 0;
- struct {/*2*/ int (*foo)(); }/*2*/ *(*s)() =
+ struct {/*2*/ int (*foo)(); }/*2*/ *(*s)()=
(struct { int (*foo)(); } *(*)()) 0;
/* end dcls */{/*2*/
@@ -53,20 +70,16 @@ foo
-test1
-()
-# 52 "example.c"
+test1()
{/*1*/
int foo2,*(*(*bar)())(),*baz();
}/*1*/
-test2
-(y)
-# 59 "example.c"
-char *y;
-# 59 "example.c"
+test2(y)
+# 69 "example.c"
+charstar y;
{/*1*/
int foo = 5,atoi();
@@ -77,11 +90,9 @@ char *y;
test3,test4();
-test5
-(y)
-# 70 "example.c"
+test5(y)
+# 80 "example.c"
int y;
-# 70 "example.c"
{/*1*/
/* end dcls */{/*2*/
test3/* end dcls */;
@@ -93,11 +104,9 @@ int y;
test6[1],test7();
-test7
-(x)
-# 82 "example.c"
+test7(x)
+# 92 "example.c"
int x;
-# 82 "example.c"
{/*1*/
/* end dcls */{/*2*/
test6/* end dcls */[1];
@@ -113,13 +122,11 @@ struct {/*1*/
struct {/*2*/
int (*f)(), o;
}/*2*/ bar;
-}/*1*/ (*baz2)() = (struct { struct { int (*f)(), o; } bar; } (*)()) 0;
+}/*1*/ (*baz2)()= (struct { struct { int (*f)(), o; } bar; } (*)()) 0;
-test8
-(x)
-# 102 "example.c"
+test8(x)
{/*1*/
/* end dcls */{/*2*/
struct {/*3*/
@@ -135,22 +142,18 @@ test8
-test9
-(bar)
-# 118 "example.c"
+test9(bar)
+# 128 "example.c"
char *bar;
-# 118 "example.c"
{/*1*/
foo/* end dcls */(*bar);
}/*1*/
-test10
-(x)
-# 125 "example.c"
+test10(x)
+# 135 "example.c"
int x;
-# 125 "example.c"
{/*1*/
/* end dcls */{/*2*/
int test10();
@@ -162,12 +165,107 @@ int x;
}/*2*/
}/*1*/
-test11
-(x)
-# 137 "example.c"
+test11(x)
+# 147 "example.c"
int *x;
-# 137 "example.c"
{/*1*/
/* end dcls */while (*x)
(putchar(*x++));
}/*1*/
+
+test11a(x)
+# 153 "example.c"
+int *x;
+{/*1*/
+ /* end dcls */for (*x;;)
+ (putchar(*x++));
+}/*1*/
+
+
+
+test12()
+{/*1*/
+ char *x =
+# 1 "/dev/null" 1
+# 165 "example.c" 2
+# 163 "example.c"
+"\017\0002\002\002\002\007bar"
+
+ ;
+
+ printf/* end dcls */("foobarbaz" );
+
+ *x = '\007';
+ *x = '\377';
+}/*1*/
+
+int test13();
+
+
+
+test14();
+
+charstar test15 = "foobar";
+
+char test16 = "foo\007bar";
+
+
+
+
+test17(foo)
+# 186 "example.c"
+charstar foo[bar];
+# 186 "example.c"
+{/*1*/}/*1*/
+
+int (*(*test18[bar])())()= (int (*(*[bar])())()) 0;
+
+
+
+
+int (*(*test19())())();
+
+
+
+void test20(test21)
+# 197 "example.c"
+int test21();
+# 197 "example.c"
+{/*1*/}/*1*/
+
+void test22(test23)
+# 199 "example.c"
+struct { int foo; } test23();
+# 199 "example.c"
+{/*1*/}/*1*/
+
+
+
+void test23()
+{/*1*/
+ int (*test24())(),
+ y = (*test24(2)) (3),
+ z = ((*test24(2))(3));
+}/*1*/
+
+
+
+int (*(*test25(foo))())()
+# 212 "example.c"
+long foo;
+# 212 "example.c"
+{/*1*/ }/*1*/
+
+int (*(*test26(foo))())()
+long foo;
+{/*1*/ }/*1*/
+
+
+
+void functie(cmdlin,c1)
+# 220 "example.c"
+struct {int l; char c[1];} *cmdlin;
+# 220 "example.c"
+struct {int l; char c[1];} *c1;
+{/*1*/
+}/*1*/
diff --git a/unproto/hash.c b/unproto/hash.c
new file mode 100644
index 0000000..153f6b7
--- /dev/null
+++ b/unproto/hash.c
@@ -0,0 +1,54 @@
+/*++
+/* NAME
+/* hash 3
+/* SUMMARY
+/* compute hash value for string
+/* SYNOPSIS
+/* int hash(string, size)
+/* char *string;
+/* int size;
+/* DESCRIPTION
+/* This function computes for the given null-terminated string an
+/* integer hash value in the range 0..size-1.
+/* SEE ALSO
+/* .fi
+/* Alfred V. Aho, Ravi Sethi and Jeffrey D. Ullman: Compilers:
+/* principles, techniques and tools; Addison-Wesley, Amsterdam, 1986.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Eindhoven University of Technology
+/* Department of Mathematics and Computer Science
+/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
+/*
+/* Originally written by: P. J. Weinberger at Bell Labs.
+/* LAST MODIFICATION
+/* 92/01/15 21:53:12
+/* VERSION/RELEASE
+/* %I
+/*--*/
+
+static char hash_sccsid[] = "@(#) hash.c 1.1 92/01/15 21:53:12";
+
+/* hash - hash a string; original author: P. J. Weinberger at Bell Labs. */
+
+int hash(s, size)
+register char *s;
+unsigned size;
+{
+ register unsigned long h = 0;
+ register unsigned long g;
+
+ /*
+ * For a performance comparison with the hash function presented in K&R,
+ * first edition, see the "Dragon" book by Aho, Sethi and Ullman.
+ */
+
+ while (*s) {
+ h = (h << 4) + *s++;
+ if (g = (h & 0xf0000000)) {
+ h ^= (g >> 24);
+ h ^= g;
+ }
+ }
+ return (h % size);
+}
diff --git a/unproto/stdarg.h b/unproto/stdarg.h
index 978529b..1f8aae7 100644
--- a/unproto/stdarg.h
+++ b/unproto/stdarg.h
@@ -1,38 +1,85 @@
/*
- * @(#) stdarg.h 1.2 91/11/30 21:10:39
+ * @(#) stdarg.h 1.4 93/06/18 22:29:44
*
* Sample stdarg.h file for use with the unproto filter.
*
* This file serves two purposes.
*
- * 1 - As an include file for use with ANSI-style C source that implements
- * variadic functions.
+ * 1 - On systems that do not have a /usr/include/stdarg.h file, it should be
+ * included by C source files that implement ANSI-style variadic functions.
+ * Ultrix 4.[0-2] comes with stdarg.h but still needs the one that is
+ * provided with the unproto filter.
*
- * 2 - To configure the unproto filter itself. If the _VA_ALIST_ macro is
- * defined, its value will appear in the place of the "..." in argument
- * lists of variadic function *definitions* (not declarations).
+ * 2 - To configure the unprototyper itself. If the _VA_ALIST_ macro is
+ * defined, its value will appear in the place of the "..." at the end of
+ * argument lists of variadic function *definitions* (not declarations).
+ * Some compilers (such as Greenhills m88k) have a non-empty va_dcl
+ * definition in the system header file varargs.h. If that is the case,
+ * define "_VA_DCL_" with the same value as va_dcl. If _VA_DCL_ is defined,
+ * the unprototyper will emit its value just before the opening "{".
*
- * Compilers that pass arguments via the stack can use the default code at the
- * end of this file (this usually applies for the VAX, MC68k and 80*86
- * architectures).
+ * Compilers that always pass arguments via the stack can use the default code
+ * at the end of this file (this usually applies for the vax, mc68k and
+ * 80*86 architectures).
*
- * RISC-based systems often need special tricks. An example of the latter is
- * given for the SPARC architecture. Read your /usr/include/varargs.h for
- * more information.
+ * Special tricks are needed for compilers that pass some or all function
+ * arguments via registers. Examples of the latter are given for the mips
+ * and sparc architectures. Usually the compiler special-cases an argument
+ * declaration such as "va_alist" or "__builtin_va_alist". For inspiration,
+ * see the local /usr/include/varargs.h file.
*
* You can use the varargs.c program provided with the unproto package to
* verify that the stdarg.h file has been set up correctly.
*/
-#ifdef sparc
-# define _VA_ALIST_ "__builtin_va_alist"
- typedef char *va_list;
-# define va_start(ap, p) (ap = (char *) &__builtin_va_alist)
-# define va_arg(ap, type) ((type *) __builtin_va_arg_incr((type *) ap))[0]
-# define va_end(ap)
+#ifdef sparc /* tested with SunOS 4.1.1 */
+
+#define _VA_ALIST_ "__builtin_va_alist"
+typedef char *va_list;
+#define va_start(ap, p) (ap = (char *) &__builtin_va_alist)
+#define va_arg(ap, type) ((type *) __builtin_va_arg_incr((type *) ap))[0]
+#define va_end(ap)
+
+#else
+#ifdef mips /* tested with Ultrix 4.0 and 4.2 */
+
+#define _VA_ALIST_ "va_alist"
+#include "/usr/include/stdarg.h"
+
+#else
+#ifdef m88k /* Motorola SYSTEM V/88 R32V3 */
+
+#define _VA_ALIST_ "va_alist"
+#define _VA_DCL_ "va_type va_alist;"
+typedef struct _va_struct {
+ int va_narg;
+ int *va_stkaddr;
+ int *va_iregs;
+} va_list;
+#define va_start(ap, p) \
+((ap).va_narg=(int *)&va_alist-va_stkarg, \
+ (ap).va_stkaddr=va_stkarg, \
+ (ap).va_iregs=(int *)va_intreg)
+#define va_end(p)
+#if defined(LittleEndian)
+#define va_arg(p,mode) \
+ (*(mode *)_gh_va_arg(&p, va_align(mode), va_regtyp(mode), sizeof(mode)))
+#else /* defined(LittleEndian) */
+#define va_arg(p,mode) ( \
+ (p).va_narg += ((p).va_narg & (va_align(mode) == 8)) + \
+ (sizeof(mode)+3)/4, \
+ ((mode *)((va_regtyp(mode) && (p).va_narg <= 8 ? \
+ (p).va_iregs: \
+ (p).va_stkaddr) + (p).va_narg))[-1])
+#endif /* defined(LittleEndian) */
+
#else /* vax, mc68k, 80*86 */
- typedef char *va_list;
-# define va_start(ap, p) (ap = (char *) (&(p)+1))
-# define va_arg(ap, type) ((type *) (ap += sizeof(type)))[-1]
-# define va_end(ap)
-#endif
+
+typedef char *va_list;
+#define va_start(ap, p) (ap = (char *) (&(p)+1))
+#define va_arg(ap, type) ((type *) (ap += sizeof(type)))[-1]
+#define va_end(ap)
+
+#endif /* m88k */
+#endif /* mips */
+#endif /* sparc */
diff --git a/unproto/stddef.h b/unproto/stddef.h
new file mode 100644
index 0000000..97dbc01
--- /dev/null
+++ b/unproto/stddef.h
@@ -0,0 +1,23 @@
+/* @(#) stddef.h 1.1 92/02/15 17:25:46 */
+
+#ifndef _stddef_h_
+#define _stddef_h_
+
+/* NULL is also defined in <stdio.h> */
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* Structure member offset - some compilers barf on this. */
+
+#define offsetof(type, member) ((size_t) &((type *)0)->member)
+
+/* Some of the following types may already be defined in <sys/types.h>. */
+
+/* #include <sys/types.h> */
+/* typedef long ptrdiff_t; /* type of pointer difference */
+/* typedef unsigned short wchar_t; /* wide character type */
+/* typedef unsigned size_t; /* type of sizeof */
+
+#endif /* _stddef_h_ */
diff --git a/unproto/stdlib.h b/unproto/stdlib.h
new file mode 100644
index 0000000..78d99dd
--- /dev/null
+++ b/unproto/stdlib.h
@@ -0,0 +1,53 @@
+/* @(#) stdlib.h 1.1 92/02/15 17:25:45 */
+
+#ifndef _stdlib_h_
+#define _stdlib_h_
+
+/* NULL is also defined in <stdio.h> */
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/*
+ * Some functions in this file will be missing from the typical pre-ANSI
+ * UNIX library. Some pre-ANSI UNIX library functions have return types
+ * that differ from what ANSI requires.
+ */
+
+extern double atof();
+extern int atoi();
+extern long atol();
+extern double strtod();
+extern long strtol();
+extern unsigned long strtoul();
+extern int rand();
+extern void srand();
+extern char *calloc();
+extern char *malloc();
+extern char *realloc();
+extern void free();
+extern void abort();
+extern void exit();
+extern int atextit();
+extern int system();
+extern char *getenv();
+extern char *bsearch();
+extern void qsort();
+extern int abs();
+extern long labs();
+
+typedef struct {
+ int quot;
+ int rem;
+} div_t;
+
+typedef struct {
+ long quot;
+ long rem;
+} ldiv_t;
+
+extern div_t div();
+extern ldiv_t ldiv();
+
+#endif /* _stdlib_h_ */
diff --git a/unproto/strsave.c b/unproto/strsave.c
new file mode 100644
index 0000000..c2a4b15
--- /dev/null
+++ b/unproto/strsave.c
@@ -0,0 +1,71 @@
+/*++
+/* NAME
+/* strsave 3
+/* SUMMARY
+/* maintain unique copy of a string
+/* SYNOPSIS
+/* char *strsave(string)
+/* char *string;
+/* DESCRIPTION
+/* This function returns a pointer to an unique copy of its
+/* argument.
+/* DIAGNOSTISC
+/* strsave() calls fatal() when it runs out of memory.
+/* AUTHOR(S)
+/* Wietse Venema
+/* Eindhoven University of Technology
+/* Department of Mathematics and Computer Science
+/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
+/* LAST MODIFICATION
+/* 92/01/15 21:53:13
+/* VERSION/RELEASE
+/* 1.1
+/*--*/
+
+static char strsave_sccsid[] = "@(#) strsave.c 1.1 92/01/15 21:53:13";
+
+/* C library */
+
+extern char *strcpy();
+extern char *malloc();
+
+/* Application-specific stuff */
+
+#include "error.h"
+
+#define STR_TABSIZE 100
+
+struct string {
+ char *strval; /* unique string copy */
+ struct string *next; /* next one in hash chain */
+};
+
+static struct string *str_tab[STR_TABSIZE] = {0,};
+
+/* More string stuff. Maybe it should go to an #include file. */
+
+#define STREQ(x,y) (*(x) == *(y) && strcmp((x),(y)) == 0)
+
+/* strsave - save unique copy of string */
+
+char *strsave(str)
+register char *str;
+{
+ register struct string *s;
+ register int where = hash(str, STR_TABSIZE);
+
+ /* Look for existing entry. */
+
+ for (s = str_tab[where]; s; s = s->next)
+ if (STREQ(str, s->strval))
+ return (s->strval);
+
+ /* Add new entry. */
+
+ if ((s = (struct string *) malloc(sizeof(*s))) == 0
+ || (s->strval = malloc(strlen(str) + 1)) == 0)
+ fatal("out of memory");
+ s->next = str_tab[where];
+ str_tab[where] = s;
+ return (strcpy(s->strval, str));
+}
diff --git a/unproto/symbol.c b/unproto/symbol.c
index 0871f63..ce9f7d9 100644
--- a/unproto/symbol.c
+++ b/unproto/symbol.c
@@ -33,12 +33,12 @@
/* Department of Mathematics and Computer Science
/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
/* LAST MODIFICATION
-/* 91/11/30 21:10:33
+/* 92/02/15 18:59:56
/* VERSION/RELEASE
-/* 1.2
+/* 1.4
/*--*/
-static char symbol_sccsid[] = "@(#) symbol.c 1.2 91/11/30 21:10:33";
+static char symbol_sccsid[] = "@(#) symbol.c 1.4 92/02/15 18:59:56";
/* C library */
@@ -59,30 +59,6 @@ static struct symbol *sym_tab[SYM_TABSIZE] = {0,};
#define STREQ(x,y) (*(x) == *(y) && strcmp((x),(y)) == 0)
-/* hash - hash a string; original author: P. J. Weinberger at Bell Labs. */
-
-static unsigned hash(s, size)
-register char *s;
-unsigned size;
-{
- register unsigned long h = 0;
- register unsigned long g;
-
- /*
- * For a performance comparison with the hash function presented in K&R,
- * first edition, see the "Dragon" book by Aho, Sethi and Ullman.
- */
-
- while (*s) {
- h = (h << 4) + *s++;
- if (g = (h & 0xf0000000)) {
- h ^= (g >> 24);
- h ^= g;
- }
- }
- return (h % size);
-}
-
/* sym_enter - enter symbol into table */
void sym_enter(name, type)
@@ -94,7 +70,7 @@ int type;
if ((s = (struct symbol *) malloc(sizeof(*s))) == 0
|| (s->name = malloc(strlen(name) + 1)) == 0)
- error(1, "out of memory");
+ fatal("out of memory");
(void) strcpy(s->name, name);
s->type = type;
@@ -135,6 +111,7 @@ struct sym {
static struct sym syms[] = {
"if", TOK_CONTROL,
"else", TOK_CONTROL,
+ "for", TOK_CONTROL,
"while", TOK_CONTROL,
"do", TOK_CONTROL,
"switch", TOK_CONTROL,
@@ -146,6 +123,12 @@ static struct sym syms[] = {
"goto", TOK_CONTROL,
"struct", TOK_COMPOSITE,
"union", TOK_COMPOSITE,
+ "__DATE__", TOK_DATE,
+ "__TIME__", TOK_TIME,
+#if defined(MAP_VOID_STAR) || defined(MAP_VOID)
+ "void", TOK_VOID,
+#endif
+ "asm", TOK_OTHER,
0,
};
diff --git a/unproto/tok_class.c b/unproto/tok_class.c
index e25b695..38ccd0d 100644
--- a/unproto/tok_class.c
+++ b/unproto/tok_class.c
@@ -8,16 +8,26 @@
/* SYNOPSIS
/* #include "token.h"
/*
-/* struct token *tok_class(skip)
-/* int skip;
+/* void tok_unget(t)
+/* struct token *t;
+/*
+/* struct token *tok_class()
/* DESCRIPTION
-/* tok_class() collects a single and composite tokens, and
+/* tok_class() collects single and composite tokens, and
/* recognizes keywords.
/* At present, the only composite tokens are ()-delimited,
-/* comma-separated lists.
+/* comma-separated lists, and non-whitespace tokens with attached
+/* whitespace or comment tokens.
+/*
+/* Source transformations are: __DATE__ and __TIME__ are rewritten
+/* to string constants with the current date and time, respectively.
+/* Multiple string constants are concatenated. Optionally, "void *"
+/* is mapped to "char *", and plain "void" to "int".
/*
-/* The skip argument has the same meaning as with the tok_get()
-/* function.
+/* tok_unget() implements an arbitrary amount of token pushback.
+/* Only tokens obtained through tok_class() should be given to
+/* tok_unget(). This function accepts a list of tokens in
+/* last-read-first order.
/* DIAGNOSTICS
/* The code complains if input terminates in the middle of a list.
/* BUGS
@@ -29,18 +39,20 @@
/* Department of Mathematics and Computer Science
/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
/* LAST MODIFICATION
-/* 91/11/30 21:10:28
+/* 92/01/15 21:53:02
/* VERSION/RELEASE
-/* 1.3
+/* 1.4
/*--*/
-static char class_sccsid[] = "@(#) tok_class.c 1.3 91/11/30 21:10:28";
+static char class_sccsid[] = "@(#) tok_class.c 1.4 92/01/15 21:53:02";
/* C library */
#include <stdio.h>
extern char *strcpy();
+extern long time();
+extern char *ctime();
/* Application-specific stuff */
@@ -52,33 +64,107 @@ extern char *strcpy();
static struct token *tok_list();
static void tok_list_struct();
static void tok_list_append();
+static void tok_strcat();
+static void tok_time();
+static void tok_date();
+static void tok_space_append();
+
+#if defined(MAP_VOID_STAR) || defined(MAP_VOID)
+static void tok_void(); /* rewrite void keyword */
+#endif
+
+static struct token *tok_buf = 0; /* token push-back storage */
+
+/* TOK_PREPEND - add token to LIFO queue, return head */
-/* tok_space_append - append trailing space except after list */
+#define TOK_PREPEND(list,t) (t->next = list, list = t)
+
+/* tok_space_append - append trailing space except at start of or after list */
+
+static void tok_space_append(list, t)
+register struct token *list;
+register struct token *t;
+{
-#define tok_space_append(list,t) { \
- if (list == 0 /* leading space*/ \
- || list->tokno == TOK_LIST) \
- tok_free(t); \
- else \
- tok_list_append(list, t); \
- }
+ /*
+ * The head/tail fields of a token do triple duty. They are used to keep
+ * track of the members that make up a (list); to keep track of the
+ * non-blank tokens that make up one list member; and, finally, to tack
+ * whitespace and comment tokens onto the non-blank tokens that make up
+ * one list member.
+ *
+ * Within a (list), white space and comment tokens are always tacked onto
+ * the non-blank tokens to avoid parsing complications later on. For this
+ * reason, blanks and comments at the beginning of a list member are
+ * discarded because there is no token to tack them onto. (Well, we could
+ * start each list member with a dummy token, but that would mess up the
+ * whole unprototyper).
+ *
+ * Blanks or comments that follow a (list) are discarded, because the
+ * head/tail fields of a (list) are already being used for other
+ * purposes.
+ *
+ * Newlines within a (list) are discarded because they can mess up the
+ * output when we rewrite function headers. The output routines will
+ * regenerate discarded newlines, anyway.
+ */
+
+ if (list == 0 || list->tokno == TOK_LIST) {
+ tok_free(t);
+ } else {
+ tok_list_append(list, t);
+ }
+}
/* tok_class - discriminate single tokens, keywords, and composite tokens */
-struct token *tok_class(skip)
-int skip;
+struct token *tok_class()
{
register struct token *t;
register struct symbol *s;
- if (t = tok_get(skip)) {
+ /*
+ * Use push-back token, if available. Push-back tokens are already
+ * canonical and can be passed on to the caller without further
+ * inspection.
+ */
+
+ if (t = tok_buf) {
+ tok_buf = t->next;
+ t->next = 0;
+ return (t);
+ }
+ /* Read a new token and canonicalize it. */
+
+ if (t = tok_get()) {
switch (t->tokno) {
case '(': /* beginning of list */
t = tok_list(t);
break;
case TOK_WORD: /* look up keyword */
- if (s = sym_find(t->vstr->str))
- t->tokno = s->type;
+ if ((s = sym_find(t->vstr->str))) {
+ switch (s->type) {
+ case TOK_TIME: /* map __TIME__ to string */
+ tok_time(t);
+ tok_strcat(t); /* look for more strings */
+ break;
+ case TOK_DATE: /* map __DATE__ to string */
+ tok_date(t);
+ tok_strcat(t); /* look for more strings */
+ break;
+#if defined(MAP_VOID_STAR) || defined(MAP_VOID)
+ case TOK_VOID: /* optionally map void types */
+ tok_void(t);
+ break;
+#endif
+ default: /* other keyword */
+ t->tokno = s->type;
+ break;
+ }
+ }
+ break;
+ case '"': /* string, look for more */
+ tok_strcat(t);
break;
}
}
@@ -91,28 +177,35 @@ static struct token *tok_list(t)
struct token *t;
{
register struct token *list = tok_alloc();
- char filename[BUFSIZ];
+ char *filename;
int lineno;
/* Save context of '(' for diagnostics. */
- strcpy(filename, curr_path);
- lineno = curr_line;
+ filename = t->path;
+ lineno = t->line;
list->tokno = TOK_LIST;
list->head = list->tail = t;
+ list->path = t->path;
+ list->line = t->line;
#ifdef DEBUG
strcpy(list->vstr->str, "LIST");
#endif
- for (;;) {
- if ((t = tok_get(DO_WSPACE)) == 0) { /* skip blanks */
- error_where(0, filename, lineno, "unmatched '('");
- return (list); /* do not waste any data */
- }
+ /*
+ * Read until the matching ')' is found, accounting for structured stuff
+ * (enclosed by '{' and '}' tokens). Break the list up at each ',' token,
+ * and try to preserve as much whitespace as possible. Newlines are
+ * discarded so that they will not mess up the layout when we rewrite
+ * argument lists. The output routines will regenerate discarded
+ * newlines.
+ */
+
+ while (t = tok_class()) { /* skip blanks */
switch (t->tokno) {
case ')': /* end of list */
- tok_free(t);
+ tok_list_append(list, t);
return (list);
case '{': /* struct/union type */
tok_list_struct(list->tail, t);
@@ -120,20 +213,19 @@ struct token *t;
case TOK_WSPACE: /* preserve trailing blanks */
tok_space_append(list->tail->tail, t); /* except after list */
break;
- case '\n': /* preserve line count */
- tok_flush(t);
+ case '\n': /* fix newlines later */
+ tok_free(t);
break;
case ',': /* list separator */
tok_list_append(list, t);
break;
- case '(': /* beginning of list */
- tok_list_append(list->tail, tok_list(t));
- break;
- default: /* ordinary token */
+ default: /* other */
tok_list_append(list->tail, t);
break;
}
}
+ error_where(filename, lineno, "unmatched '('");
+ return (list); /* do not waste any data */
}
/* tok_list_struct - collect structured type info within list */
@@ -142,16 +234,35 @@ static void tok_list_struct(list, t)
register struct token *list;
register struct token *t;
{
+ char *filename;
+ int lineno;
+
+ /*
+ * Save context of '{' for diagnostics. This routine is called by the one
+ * that collects list members. If the '}' is not found, the list
+ * collector will not see the closing ')' either.
+ */
+
+ filename = t->path;
+ lineno = t->line;
+
tok_list_append(list, t);
- while (t = tok_class(DO_WSPACE)) {
+ /*
+ * Collect tokens until the matching '}' is found. Try to preserve as
+ * much whitespace as possible. Newlines are discarded so that they do
+ * not interfere when rewriting argument lists. The output routines will
+ * regenerate discarded newlines.
+ */
+
+ while (t = tok_class()) {
switch (t->tokno) {
- case '\n': /* preserve line count */
- tok_flush(t);
- break;
case TOK_WSPACE: /* preserve trailing blanks */
tok_space_append(list->tail, t); /* except after list */
break;
+ case '\n': /* fix newlines later */
+ tok_free(t);
+ break;
case '{': /* recurse */
tok_list_struct(list, t);
break;
@@ -163,6 +274,147 @@ register struct token *t;
break;
}
}
+ error_where(filename, lineno, "unmatched '{'");
+}
+
+/* tok_strcat - concatenate multiple string constants */
+
+static void tok_strcat(t1)
+register struct token *t1;
+{
+ register struct token *t2;
+ register struct token *lookahead = 0;
+
+ /*
+ * Read ahead past whitespace, comments and newlines. If we find a string
+ * token, concatenate it with the previous one and push back the
+ * intervening tokens (thus preserving as much information as possible).
+ * If we find something else, push back all lookahead tokens.
+ */
+
+#define PUSHBACK_AND_RETURN { if (lookahead) tok_unget(lookahead); return; }
+
+ while (t2 = tok_class()) {
+ switch (t2->tokno) {
+ case TOK_WSPACE: /* read past comments/blanks */
+ case '\n': /* read past newlines */
+ TOK_PREPEND(lookahead, t2);
+ break;
+ case '"': /* concatenate string tokens */
+ if (vs_strcpy(t1->vstr,
+ t1->vstr->str + strlen(t1->vstr->str) - 1,
+ t2->vstr->str + 1) == 0)
+ fatal("out of memory");
+ tok_free(t2);
+ PUSHBACK_AND_RETURN;
+ default: /* something else, push back */
+ tok_unget(t2);
+ PUSHBACK_AND_RETURN;
+ }
+ }
+ PUSHBACK_AND_RETURN; /* hit EOF */
+}
+
+#if defined(MAP_VOID_STAR) || defined(MAP_VOID)
+
+/* tok_void - support for compilers that have problems with "void" */
+
+static void tok_void(t)
+register struct token *t;
+{
+ register struct token *t2;
+ register struct token *lookahead = 0;
+
+ /*
+ * Look ahead beyond whitespace, comments and newlines until we see a '*'
+ * token. If one is found, replace "void" by "char". If we find something
+ * else, and if "void" should always be mapped, replace "void" by "int".
+ * Always push back the lookahead tokens.
+ *
+ * XXX The code also replaces the (void) argument list; this must be
+ * accounted for later on. The alternative would be to add (in unproto.c)
+ * TOK_VOID cases all over the place and that would be too error-prone.
+ */
+
+#define PUSHBACK_AND_RETURN { if (lookahead) tok_unget(lookahead); return; }
+
+ while (t2 = tok_class()) {
+ switch (TOK_PREPEND(lookahead, t2)->tokno) {
+ case TOK_WSPACE: /* read past comments/blanks */
+ case '\n': /* read past newline */
+ break;
+ case '*': /* "void *" -> "char *" */
+ if (vs_strcpy(t->vstr, t->vstr->str, "char") == 0)
+ fatal("out of memory");
+ PUSHBACK_AND_RETURN;
+ default:
+#ifdef MAP_VOID /* plain "void" -> "int" */
+ if (vs_strcpy(t->vstr, t->vstr->str, "int") == 0)
+ fatal("out of memory");
+#endif
+ PUSHBACK_AND_RETURN;
+ }
+ }
+ PUSHBACK_AND_RETURN; /* hit EOF */
+}
+
+#endif
+
+/* tok_time - rewrite __TIME__ to "hh:mm:ss" string constant */
+
+static void tok_time(t)
+struct token *t;
+{
+ long now;
+ char *cp;
+ char buf[BUFSIZ];
+
+ /*
+ * Using sprintf() to select parts of a string is gross, but this should
+ * be fast enough.
+ */
+
+ (void) time(&now);
+ cp = ctime(&now);
+ sprintf(buf, "\"%.8s\"", cp + 11);
+ if (vs_strcpy(t->vstr, t->vstr->str, buf) == 0)
+ fatal("out of memory");
+ t->tokno = buf[0];
+}
+
+/* tok_date - rewrite __DATE__ to "Mmm dd yyyy" string constant */
+
+static void tok_date(t)
+struct token *t;
+{
+ long now;
+ char *cp;
+ char buf[BUFSIZ];
+
+ /*
+ * Using sprintf() to select parts of a string is gross, but this should
+ * be fast enough.
+ */
+
+ (void) time(&now);
+ cp = ctime(&now);
+ sprintf(buf, "\"%.3s %.2s %.4s\"", cp + 4, cp + 8, cp + 20);
+ if (vs_strcpy(t->vstr, t->vstr->str, buf) == 0)
+ fatal("out of memory");
+ t->tokno = buf[0];
+}
+
+/* tok_unget - push back one or more possibly composite tokens */
+
+void tok_unget(t)
+register struct token *t;
+{
+ register struct token *next;
+
+ do {
+ next = t->next;
+ TOK_PREPEND(tok_buf, t);
+ } while (t = next);
}
/* tok_list_append - append data to list */
diff --git a/unproto/tok_io.c b/unproto/tok_io.c
index ab1129b..74ae6bc 100644
--- a/unproto/tok_io.c
+++ b/unproto/tok_io.c
@@ -8,11 +8,7 @@
/* SYNOPSIS
/* #include "token.h"
/*
-/* struct token *tok_get(skip_flag)
-/* int skip_flag;
-/*
-/* void tok_unget(t)
-/* struct token *t;
+/* struct token *tok_get()
/*
/* void tok_flush(t)
/* struct token *t;
@@ -20,44 +16,49 @@
/* void tok_show(t)
/* struct token *t;
/*
+/* void tok_show_ch(t)
+/* struct token *t;
+/*
/* void put_str(s)
/* char *s;
/*
/* void put_ch(c)
/* int c;
/*
-/* void show_line_control()
+/* void put_nl()
/*
-/* char curr_path[];
-/* int curr_line;
+/* char *in_path;
+/* int in_line;
/* DESCRIPTION
/* These functions read from stdin and write to stdout. The
-/* output functions maintain some memory so that two successive
-/* words will always be separated by white space.
-/*
-/* The input routines eliminate backslash-newline from the input.
+/* tokenizer keeps track of where the token appeared in the input
+/* stream; on output, this information is used to preserve correct
+/* line number information (even after lots of token lookahead or
+/* after function-header rewriting) so that diagnostics from the
+/* next compiler stage make sense.
/*
/* tok_get() reads the next token from standard input. It returns
-/* a null pointer when the end of input is reached. If the skip_flag
-/* argument is nonzero, white space (except newline) will be skipped.
-/*
-/* tok_unget() implements a limited amount of token push back.
+/* a null pointer when the end of input is reached.
/*
/* tok_show() displays the contents of a (possibly composite) token
/* on the standard output.
/*
+/* tok_show_ch() displays the contents of a single-character token
+/* on the standard output. The character should not be a newline.
+/*
/* tok_flush() displays the contents of a (possibly composite) token
/* on the standard output and makes it available for re-use.
/*
/* put_str() writes a null-terminated string to standard output.
+/* There should be no newline characters in the string argument.
/*
-/* put_ch() writes one character to standard output.
+/* put_ch() writes one character to standard output. The character
+/* should not be a newline.
/*
-/* show_line_control() displays the line number of the next line
-/* to be written to standard output, in a format suitable for the C
-/* compiler parser phase.
+/* put_nl() outputs a newline character and adjusts the program's idea of
+/* the current output line.
/*
-/* The curr_path[] and curr_line variables contain the input file name and
+/* The in_path and in_line variables contain the file name and
/* line number of the most recently read token.
/* BUGS
/* The tokenizer is just good enough for the unproto filter.
@@ -68,12 +69,12 @@
/* Department of Mathematics and Computer Science
/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
/* LAST MODIFICATION
-/* 91/11/30 21:10:26
+/* 92/01/15 21:52:59
/* VERSION/RELEASE
-/* 1.2
+/* 1.3
/*--*/
-static char io_sccsid[] = "@(#) tok_io.c 1.2 91/11/30 21:10:26";
+static char io_sccsid[] = "@(#) tok_io.c 1.3 92/01/15 21:52:59";
/* C library */
@@ -91,38 +92,55 @@ extern char *strcpy();
#include "vstring.h"
#include "error.h"
-/* Stuff to keep track of original source file name and position */
-
-char curr_path[BUFSIZ]; /* current file name */
-int curr_line = 0; /* # of last read line */
+extern char *strsave(); /* XXX need include file */
-/* Forward declarations */
-
-static void read_quoted();
-static void read_comment();
-
-/* Buffered i/o stuff */
-
-static struct vstring *buf = 0; /* read-ahead buffer */
-static char *bp = ""; /* buffer position */
-
-#ifdef DEBUG
-#define INITBUF 1 /* small initial buffer size */
-#else
-#define INITBUF BUFSIZ /* reasonable initial buffer size */
-#endif
+/* Stuff to keep track of original source file name and position */
-#define input() (*bp ? *bp++ : next_line())
-#define unput(c) (*--bp = (c))
+static char def_path[] = ""; /* default path name */
-#define TOK_BUFSIZE 5 /* token push-back buffer size */
+char *in_path = def_path; /* current input file name */
+int in_line = 1; /* current input line number */
-static struct token *tok_buf[TOK_BUFSIZE];
-static int tok_bufpos = 0;
+static char *out_path = def_path; /* last name in output line control */
+static int out_line = 1; /* current output line number */
+int last_ch; /* type of last output */
-/* Type of last token sent to output, for pretty printing */
+/* Forward declarations */
-static int last_tok = 0;
+static int read_quoted();
+static void read_comment();
+static int backslash_newline();
+static char *read_hex();
+static char *read_octal();
+static void fix_line_control();
+
+ /*
+ * Character input with one level of pushback. The INPUT() macro recursively
+ * strips backslash-newline pairs from the input stream. The UNPUT() macro
+ * should be used only for characters obtained through the INPUT() macro.
+ *
+ * After skipping a backslash-newline pair, the input line counter is not
+ * updated, and we continue with the same logical source line. We just
+ * update a counter with the number of backslash-newline sequences that must
+ * be accounted for (backslash_newline() updates the counter). At the end of
+ * the logical source line, an appropriate number of newline characters is
+ * pushed back (in tok_get()). I do not know how GCC handles this, but it
+ * seems to produce te same output.
+ *
+ * Because backslash_newline() recursively calls itself (through the INPUT()
+ * macro), we will run out of stack space, given a sufficiently long
+ * sequence of backslash-newline pairs.
+ */
+
+static char in_char = 0; /* push-back storage */
+static int in_flag = 0; /* pushback available */
+static int nl_compensate = 0; /* line continuation kluge */
+
+#define INPUT(c) (in_flag ? (in_flag = 0, c = in_char) : \
+ (c = getchar()) != '\\' ? c : \
+ (c = getchar()) != '\n' ? (ungetc(c, stdin), c = '\\') : \
+ (c = backslash_newline()))
+#define UNPUT(c) (in_flag = 1, in_char = c)
/* Directives that should be ignored. */
@@ -143,6 +161,8 @@ static char *ignore_directives[] = {
#define ISALPHA(c) (isalpha(c) || (c) == '_')
#define ISSPACE(c) (isspace(c) && c != '\n')
#define ISDOT(c) (c == '.')
+#define ISHEX(c) (isdigit(c) || strchr("abcdefABCDEF", c) != 0)
+#define ISOCTAL(c) (isdigit(c) && (c) != '8' && (c) != '9')
/* Collect all characters that satisfy one condition */
@@ -150,236 +170,246 @@ static char *ignore_directives[] = {
register struct vstring *vs = v; \
register char *cp = vs->str; \
*cp++ = c; \
- for (;;) { \
- if ((c = input()) == 0) { \
- break; \
- } else if (cond) { \
+ while (INPUT(c) != EOF) { \
+ if (cond) { \
if (VS_ADDCH(vs, cp, c) == 0) \
- error(1, "out of memory"); \
+ fatal("out of memory"); \
} else { \
- unput(c); \
+ UNPUT(c); \
break; \
} \
} \
*cp = 0; \
}
-/* do_control - parse control line, uses tok_get() */
+/* Ensure that output line information is correct */
+
+#define CHECK_LINE_CONTROL(p,l) { if (out_path != (p) || out_line != (l)) \
+ fix_line_control((p),(l)); }
+
+/* do_control - parse control line */
static int do_control()
{
- struct token *t1;
- struct token *t2;
- int pass_thru = 1; /* 0 = ignore, 1 = output */
+ struct token *t;
+ int line;
+ char *path;
+
+ /* Make sure that the directive shows up in the right place. */
- (void) input(); /* skip the hash */
+ CHECK_LINE_CONTROL(in_path, in_line);
+
+ while (t = tok_get()) {
+ switch (t->tokno) {
+
+ case TOK_WSPACE:
+ /* Ignore blanks after "#" token. */
+ tok_free(t);
+ break;
- if (t1 = tok_get(NO_WSPACE)) {
- switch (t1->tokno) {
+ case TOK_NUMBER:
/*
- * In case of line number control, the remainder of the line has
- * the format: linenumber "pathname".
+ * Line control is of the form: number pathname junk. Since we
+ * have no idea what junk the preprocessor may generate, we copy
+ * all line control tokens to stdout.
*/
- case TOK_NUMBER:
- if (t2 = tok_get(NO_WSPACE)) {
- if (t2->tokno == '"') {
- curr_line = atoi(t1->vstr->str) - 1;
- strcpy(curr_path, t2->vstr->str);
- }
- tok_free(t2);
+
+ put_str("# ");
+ line = atoi(t->vstr->str); /* extract line number */
+ tok_flush(t);
+ while ((t = tok_get()) && t->tokno == TOK_WSPACE)
+ tok_flush(t); /* copy white space */
+ if (t) { /* extract path name */
+ path = (t->tokno == '"') ? strsave(t->vstr->str) : in_path;
+ do {
+ tok_flush(t); /* copy until newline */
+ } while (t->tokno != '\n' && (t = tok_get()));
}
- break;
+ out_line = in_line = line; /* synchronize */
+ out_path = in_path = path; /* synchronize */
+ return;
#ifdef IGNORE_DIRECTIVES
+
case TOK_WORD:
- /* Optionally ignore other #directives, such as #pragma. */
+
+ /*
+ * Optionally ignore other #directives. This is only a partial
+ * solution, because the preprocessor will still see them.
+ */
{
char **cpp;
- char *cp = t1->vstr->str;
+ char *cp = t->vstr->str;
for (cpp = ignore_directives; *cpp; cpp++) {
if (STREQUAL(cp, *cpp)) {
- pass_thru = 0;
- break;
+ do {
+ tok_free(t);
+ } while (t->tokno != '\n' && (t = tok_get()));
+ return;
}
}
}
- break;
+ /* FALLTHROUGH */
#endif
+ default:
+ /* Pass through. */
+ put_ch('#');
+ do {
+ tok_flush(t);
+ } while (t->tokno != '\n' && (t = tok_get()));
+ return;
+
+ case 0:
+ /* Hit EOF, punt. */
+ put_ch('#');
+ return;
}
- tok_free(t1);
}
- return (pass_thru);
}
-/* next_line - read one logical line, handle #control */
+/* backslash_newline - fix up things after reading a backslash-newline pair */
-static int next_line()
+static int backslash_newline()
{
register int c;
- register char *cp;
-
- /* Allocate buffer upon first entry */
-
- if (buf == 0)
- buf = vs_alloc(INITBUF);
-
- for (;;) {
- cp = buf->str;
-
- /* Account for EOF and line continuations */
-
- while ((c = getchar()) != EOF) {
- if (VS_ADDCH(buf, cp, c) == 0) /* store character */
- error(1, "out of memory");
- if (c == '\n') { /* real end of line */
- curr_line++;
- break;
- } else if (c == '\\') {
- if ((c = getchar()) == EOF) { /* XXX strip backslash-EOF */
- break;
- } else if (c == '\n') { /* strip backslash-newline */
- curr_line++;
- put_ch('\n'); /* preserve line count */
- cp--; /* un-store backslash */
- } else {
- ungetc(c, stdin); /* keep backslash-other */
- }
- }
- }
- *cp = 0;
- bp = buf->str;
- /* Account for EOF and #control */
-
- switch (bp[0]) {
- case 0: /* EOF */
- return (0);
- case '#': /* control */
- if (do_control())
- fputs(buf->str, stdout); /* pass through */
- else
- putchar('\n'); /* filter out */
- break;
- default: /* non-control */
- return (input());
- }
- }
-}
-
-/* tok_unget - push back one token */
-
-void tok_unget(t)
-register struct token *t;
-{
- if (tok_bufpos >= TOK_BUFSIZE)
- error(1, "too much pushback");
- tok_buf[tok_bufpos++] = t;
+ nl_compensate++;
+ return (INPUT(c));
}
/* tok_get - get next token */
-struct token *tok_get(skip_flag)
-int skip_flag;
+static int last_tokno = '\n';
+
+struct token *tok_get()
{
register struct token *t;
register int c;
int d;
- /* Use push-back token, if any. */
-
- if (tok_bufpos) {
- t = tok_buf[--tok_bufpos];
- return (t);
- }
-
/*
- * Get one from the pool and fill it in. The loop is here in case we
- * should skip white-space tokens, which happens in a minority of all
- * cases.
+ * Get one from the pool and fill it in. The loop is here in case we hit
+ * a preprocessor control line, which happens in a minority of all cases.
+ * We update the token input path and line info *after* backslash-newline
+ * processing or the newline compensation would go wrong.
*/
t = tok_alloc();
for (;;) {
- if ((c = input()) == 0) {
+ if ((INPUT(c)) == EOF) {
tok_free(t);
return (0);
- } else if (!isascii(c)) {
+ } else if ((t->line = in_line, t->path = in_path), !isascii(c)) {
t->vstr->str[0] = c;
t->vstr->str[1] = 0;
t->tokno = TOK_OTHER;
- return (t);
- } else if (c == '"' || c == '\'') {
- read_quoted(t, c);
- t->tokno = c;
- return (t);
+ break;
+ } else if (ISSPACE(c)) {
+ COLLECT(t->vstr, c, ISSPACE(c));
+ t->tokno = TOK_WSPACE;
+ break;
} else if (ISALPHA(c)) {
COLLECT(t->vstr, c, ISALNUM(c));
t->tokno = TOK_WORD;
- return (t);
+ break;
} else if (isdigit(c)) {
COLLECT(t->vstr, c, isdigit(c));
t->tokno = TOK_NUMBER;
- return (t);
- } else if (ISSPACE(c)) {
- COLLECT(t->vstr, c, ISSPACE(c));
- if (skip_flag)
- continue;
- t->tokno = TOK_WSPACE;
- return (t);
+ break;
+ } else if (c == '"' || c == '\'') {
+ t->tokno = read_quoted(t->vstr, c); /* detect missing end quote */
+ break;
} else if (ISDOT(c)) {
COLLECT(t->vstr, c, ISDOT(c));
t->tokno = TOK_OTHER;
- return (t);
+ break;
+ } else if (c == '#' && last_tokno == '\n') {
+ do_control();
+ continue;
} else {
t->vstr->str[0] = c;
- if (c == '/') {
- if ((d = input()) == '*') {
+ if (c == '\n') {
+ in_line++;
+ if (nl_compensate > 0) { /* compensation for bs-nl */
+ UNPUT('\n');
+ nl_compensate--;
+ }
+ } else if (c == '/') {
+ if ((INPUT(d)) == '*') {
t->vstr->str[1] = d; /* comment */
read_comment(t->vstr);
- if (skip_flag)
- continue;
t->tokno = TOK_WSPACE;
- return (t);
+ break;
} else {
- unput(d);
+ if (d != EOF)
+ UNPUT(d);
}
+ } else if (c == '\\') {
+ t->vstr->str[1] = (INPUT(c) == EOF ? 0 : c);
+ t->vstr->str[2] = 0;
+ t->tokno = TOK_OTHER;
+ break;
}
t->vstr->str[1] = 0;
t->tokno = c;
- return (t);
+ break;
}
}
+ last_tokno = t->tokno;
+ t->end_line = in_line;
+ return (t);
}
-/* read_qouted - read string or character literal */
+/* read_quoted - read string or character literal, canonicalize escapes */
-static void read_quoted(t, ch)
-register struct token *t;
+static int read_quoted(vs, ch)
+register struct vstring *vs;
int ch;
{
- register char *cp = t->vstr->str;
+ register char *cp = vs->str;
register int c;
+ int ret = TOK_OTHER;
*cp++ = ch;
- while (c = input()) {
+ /*
+ * Clobber the token type in case of a premature newline or EOF. This
+ * prevents us from attempting to concatenate string constants with
+ * broken ones that have no closing quote.
+ */
+
+ while (INPUT(c) != EOF) {
if (c == '\n') { /* newline in string */
- unput(c);
+ UNPUT(c);
break;
}
- if (VS_ADDCH(t->vstr, cp, c) == 0) /* store character */
- error(1, "out of memory");
- if (c == ch) /* end of string */
+ if (VS_ADDCH(vs, cp, c) == 0) /* store character */
+ fatal("out of memory");
+ if (c == ch) { /* closing quote */
+ ret = c;
break;
- if (c == '\\') /* eat next character */
- if ((c = input()) != 0 && VS_ADDCH(t->vstr, cp, c) == 0)
- error(1, "out of memory");
+ }
+ if (c == '\\') { /* parse escape sequence */
+ if ((INPUT(c)) == EOF) { /* EOF, punt */
+ break;
+ } else if (c == 'a') { /* \a -> audible bell */
+ if ((cp = vs_strcpy(vs, cp, BELL)) == 0)
+ fatal("out of memory");
+ } else if (c == 'x') { /* \xhh -> \nnn */
+ cp = read_hex(vs, cp);
+ } else if (ISOCTAL(c) && ch != '\'') {
+ cp = read_octal(vs, cp, c); /* canonicalize \octal */
+ } else {
+ if (VS_ADDCH(vs, cp, c) == 0) /* \other: leave alone */
+ fatal("out of memory");
+ }
+ }
}
*cp = 0;
- return;
+ return (ret);
}
/* read_comment - stuff a whole comment into one huge token */
@@ -391,74 +421,192 @@ register struct vstring *vs;
register int c;
register int d;
- while (c = input()) {
+ while (INPUT(c) != EOF) {
if (VS_ADDCH(vs, cp, c) == 0)
- error(1, "out of memory");
+ fatal("out of memory");
if (c == '*') {
- if ((d = input()) == '/') {
+ if ((INPUT(d)) == '/') {
if (VS_ADDCH(vs, cp, d) == 0)
- error(1, "out of memory");
+ fatal("out of memory");
break;
} else {
- unput(d);
+ if (d != EOF)
+ UNPUT(d);
}
+ } else if (c == '\n') {
+ in_line++;
+ } else if (c == '\\') {
+ if ((INPUT(d)) != EOF && VS_ADDCH(vs, cp, d) == 0)
+ fatal("out of memory");
}
}
*cp = 0;
}
-/* put_str - output a string */
+/* read_hex - rewrite hex escape to three-digit octal escape */
-void put_str(s)
-char *s;
+static char *read_hex(vs, cp)
+struct vstring *vs;
+register char *cp;
{
- fputs(s, stdout);
- last_tok = s[0]; /* XXX */
-#ifdef DEBUG
- fflush(stdout);
-#endif
+ register int c;
+ register int i;
+ char buf[BUFSIZ];
+ int len;
+ unsigned val;
+
+ /*
+ * Eat up all subsequent hex digits. Complain later when there are too
+ * many.
+ */
+
+ for (i = 0; i < sizeof(buf) && (INPUT(c) != EOF) && ISHEX(c); i++)
+ buf[i] = c;
+ buf[i] = 0;
+
+ if (i < sizeof(buf) && c)
+ UNPUT(c);
+
+ /*
+ * Convert hex form to three-digit octal form. The three-digit form is
+ * used so that strings can be concatenated without problems. Complain
+ * about malformed input; truncate the result to at most three octal
+ * digits.
+ */
+
+ if (i == 0) {
+ error("\\x escape sequence without hexadecimal digits");
+ if (VS_ADDCH(vs, cp, 'x') == 0)
+ fatal("out of memory");
+ } else {
+ (void) sscanf(buf, "%x", &val);
+ sprintf(buf, "%03o", val);
+ if ((len = strlen(buf)) > 3)
+ error("\\x escape sequence yields non-character value");
+ if ((cp = vs_strcpy(vs, cp, buf + len - 3)) == 0)
+ fatal("out of memory");
+ }
+ return (cp);
}
-/* put_ch - put character */
+/* read_octal - convert octal escape to three-digit format */
+
+static char obuf[] = "00123";
-void put_ch(c)
-int c;
+static char *read_octal(vs, cp, c)
+register struct vstring *vs;
+register char *cp;
+register int c;
{
- last_tok = putchar(c);
-#ifdef DEBUG
- fflush(stdout);
-#endif
+ register int i;
+
+#define buf_input (obuf + 2)
+
+ /* Eat up at most three octal digits. */
+
+ buf_input[0] = c;
+ for (i = 1; i < 3 && (INPUT(c) != EOF) && ISOCTAL(c); i++)
+ buf_input[i] = c;
+ buf_input[i] = 0;
+
+ if (i < 3 && c)
+ UNPUT(c);
+
+ /*
+ * Leave three-digit octal escapes alone. Convert one-digit and two-digit
+ * octal escapes to three-digit form by prefixing them with a suitable
+ * number of '0' characters. This is done so that strings can be
+ * concatenated without problems.
+ */
+
+ if ((cp = vs_strcpy(vs, cp, buf_input + i - 3)) == 0)
+ fatal("out of memory");
+ return (cp);
+}
+
+/* put_nl - emit newline and adjust output line count */
+
+void put_nl()
+{
+ put_ch('\n');
+ out_line++;
+}
+
+/* fix_line_control - to adjust path and/or line count info in output */
+
+static void fix_line_control(path, line)
+register char *path;
+register int line;
+{
+
+ /*
+ * This function is called sporadically, so it should not be a problem
+ * that we repeat some of the tests that preceded this function call.
+ *
+ * Emit a newline if we are not at the start of a line.
+ *
+ * If we switch files, or if we jump backwards, emit line control. If we
+ * jump forward, emit the proper number of newlines to compensate.
+ */
+
+ if (last_ch != '\n') /* terminate open line */
+ put_nl();
+ if (path != out_path || line < out_line) { /* file switch or back jump */
+ printf("# %d %s\n", out_line = line, out_path = path);
+ last_ch = '\n';
+ } else { /* forward jump */
+ while (line > out_line)
+ put_nl();
+ }
+}
+
+/* tok_show_ch - output single-character token (not newline) */
+
+void tok_show_ch(t)
+register struct token *t;
+{
+ CHECK_LINE_CONTROL(t->path, t->line);
+
+ put_ch(t->tokno); /* show token contents */
}
/* tok_show - output (possibly composite) token */
void tok_show(t)
-struct token *t;
+register struct token *t;
{
register struct token *p;
- register struct token *s;
- switch (t->tokno) {
- case TOK_LIST:
+ if (t->tokno == TOK_LIST) {
+ register struct token *s;
+
+ /*
+ * This branch is completely in terms of tok_xxx() primitives, so
+ * there is no need to check the line control information.
+ */
+
for (s = t->head; s; s = s->next) {
- put_ch(s->tokno); /* opening paren or ',' */
+ tok_show_ch(s); /* '(' or ',' or ')' */
for (p = s->head; p; p = p->next)
- tok_show(p);
+ tok_show(p); /* show list element */
}
- put_ch(')'); /* closing paren */
- break;
- case TOK_WORD:
- if (ISALPHA(last_tok))
- putchar(' ');
- /* FALLTRHOUGH */
- default:
- fputs(t->vstr->str, stdout); /* token contents */
- last_tok = t->vstr->str[0];
-#ifdef DEBUG
- fflush(stdout);
-#endif
- if (t->head) /* trailing blanks */
- for (p = t->head; p; p = p->next)
- tok_show(p);
+ } else {
+ register char *cp = t->vstr->str;
+
+ /*
+ * Measurements show that it pays off to give special treatment to
+ * single-character tokens. Note that both types of token may cause a
+ * change of output line number.
+ */
+
+ CHECK_LINE_CONTROL(t->path, t->line);
+ if (cp[1] == 0) {
+ put_ch(*cp); /* single-character token */
+ } else {
+ put_str(cp); /* multi_character token */
+ }
+ out_line = t->end_line; /* may span multiple lines */
+ for (p = t->head; p; p = p->next)
+ tok_show(p); /* trailing blanks */
}
}
diff --git a/unproto/tok_pool.c b/unproto/tok_pool.c
index c2a9665..e2ed107 100644
--- a/unproto/tok_pool.c
+++ b/unproto/tok_pool.c
@@ -28,12 +28,12 @@
/* Department of Mathematics and Computer Science
/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
/* LAST MODIFICATION
-/* 91/09/01 23:08:36
+/* 92/01/15 21:53:04
/* VERSION/RELEASE
-/* 1.1
+/* 1.2
/*--*/
-static char pool_sccsid[] = "@(#) tok_pool.c 1.1 91/09/01 23:08:36";
+static char pool_sccsid[] = "@(#) tok_pool.c 1.2 92/01/15 21:53:04";
/* C library */
@@ -43,8 +43,7 @@ extern char *malloc();
#include "token.h"
#include "vstring.h"
-
-extern void error();
+#include "error.h"
#define TOKLEN 5 /* initial string buffer length */
@@ -62,7 +61,7 @@ struct token *tok_alloc()
} else { /* create a new one */
if ((t = (struct token *) malloc(sizeof(struct token))) == 0
|| (t->vstr = vs_alloc(TOKLEN)) == 0)
- error(1, "out of memory");
+ fatal("out of memory");
}
t->next = t->head = t->tail = 0;
#ifdef DEBUG
@@ -83,7 +82,7 @@ register struct token *t;
for (p = tok_pool; p; p = p->next)
if (p == t)
- error(1, "freeing free token");
+ fatal("freeing free token");
#endif
/* Free neighbours and subordinates first */
diff --git a/unproto/token.h b/unproto/token.h
index 672039d..bb2f50a 100644
--- a/unproto/token.h
+++ b/unproto/token.h
@@ -1,8 +1,10 @@
-/* @(#) token.h 1.3 91/11/30 21:10:37 */
+/* @(#) token.h 1.4 92/01/15 21:53:17 */
struct token {
int tokno; /* token value, see below */
- int len; /* string or list length */
+ char *path; /* file name */
+ int line; /* line number at token start */
+ int end_line; /* line number at token end */
struct vstring *vstr; /* token contents */
struct token *next;
struct token *head;
@@ -13,27 +15,33 @@ struct token {
#define TOK_LIST 256 /* () delimited list */
#define TOK_WORD 257 /* keyword or identifier */
-#define TOK_NUMBER 258 /* number */
-#define TOK_WSPACE 259 /* white space except newline */
-#define TOK_OTHER 260 /* other multi-char token */
+#define TOK_NUMBER 258 /* one or more digits */
+#define TOK_WSPACE 259 /* comment, white space, not newline */
+#define TOK_OTHER 260 /* other token */
#define TOK_CONTROL 261 /* flow control keyword */
-#define TOK_COMPOSITE 262 /* struct or union */
+#define TOK_COMPOSITE 262 /* struct or union keyword */
+#define TOK_DATE 263 /* date: Mmm dd yyyy */
+#define TOK_TIME 264 /* time: hh:mm:ss */
+#define TOK_VOID 265 /* void keyword */
/* Input/output functions and macros */
extern struct token *tok_get(); /* read next single token */
extern void tok_show(); /* display (composite) token */
extern struct token *tok_class(); /* classify tokens */
-extern void put_ch(); /* write character */
-extern void put_str(); /* write string */
extern void tok_unget(); /* stuff token back into input */
+extern void put_nl(); /* print newline character */
+extern void tok_show_ch(); /* emit single-character token */
#define tok_flush(t) (tok_show(t), tok_free(t))
-/* tok_get() and tok_class() options */
-
-#define DO_WSPACE 0 /* retain space, tab */
-#define NO_WSPACE 1 /* skip space, tab */
+#ifdef DEBUG
+#define put_ch(c) (putchar(last_ch = c),fflush(stdout))
+#define put_str(s) (fputs(s,stdout),last_ch = 0,fflush(stdout))
+#else
+#define put_ch(c) putchar(last_ch = c)
+#define put_str(s) (fputs(s,stdout),last_ch = 0)
+#endif
/* Memory management */
@@ -42,6 +50,6 @@ extern void tok_free(); /* re-cycle storage */
/* Context */
-extern char curr_path[]; /* current path name */
-extern int curr_line; /* current line number */
-#define show_line_control() printf("# %d %s\n", curr_line, curr_path);
+extern char *in_path; /* current input path name */
+extern int in_line; /* current input line number */
+extern int last_ch; /* type of last output */
diff --git a/unproto/unproto.1 b/unproto/unproto.1
index 671e917..31490c3 100644
--- a/unproto/unproto.1
+++ b/unproto/unproto.1
@@ -4,7 +4,7 @@
.SH NAME
unproto
\-
-ANSI C to old C converter
+compile ANSI C with traditional UNIX C compiler
.SH PACKAGE
.na
.nf
@@ -12,56 +12,129 @@ unproto
.SH SYNOPSIS
.na
.nf
-/lib/cpp ... | unproto
-
/somewhere/cpp ...
+
+cc cflags -E file.c | unproto >file.i; cc cflags -c file.i
.SH DESCRIPTION
.ad
.fi
-This document describes a filter that sits between the
-C preprocessor (usually \fI/lib/cpp\fP) and the next C compiler
-pass. It rewrites ANSI-C style function headers, function type
-declarations, function pointer types, and function pointer casts
-to old style. Other ANSI-isms are passed on without modification
-(token pasting, pragmas, etcetera).
+This document describes a filter that sits in between the UNIX
+C preprocessor and the next UNIX C compiler stage, on the fly rewriting
+ANSI-style syntax to old-style syntax. Typically, the program is
+invoked by the native UNIX C compiler as an alternate preprocessor.
+The unprototyper in turn invokes the native C preprocessor and
+massages its output. Similar tricks can be used with the lint(1)
+command.
+
+Language constructs that are always rewritten:
+.TP
+function headings, prototypes, pointer types
+ANSI-C style function headings, function prototypes, function
+pointer types and type casts are rewritten to old style.
+<stdarg.h> support is provided for functions with variable-length
+argument lists.
+.TP
+character and string constants
+The \\a and \\x escape sequences are rewritten to their (three-digit)
+octal equivalents.
+
+Multiple string tokens are concatenated; an arbitrary number of
+whitespace or comment tokens may appear between successive
+string tokens.
+
+Within string constants, octal escape sequences are rewritten to the
+three-digit \\ddd form, so that string concatenation produces correct
+results.
+.TP
+date and time
+The __DATE__ and __TIME__ tokens are replaced by string constants
+of the form "Mmm dd yyyy" and "hh:mm:ss", respectively. The result
+is subjected to string concatenation, just like any other string
+constant.
+.PP
+Language constructs that are rewritten only if the program has been
+configured to do so:
+.TP
+void types
+The unprototyper can be configured to rewrite "void *" to "char *",
+and even to rewrite plain "void" to "int".
+These features are configurable because many traditional UNIX C
+compilers do not need them.
+
+Note: (void) argument lists are always replaced by empty ones.
+.PP
+ANSI C constructs that are not rewritten because the traditional
+UNIX C preprocessor provides suitable workarounds:
+.TP
+const and volatile
+Use the "-Dconst=" and/or "-Dvolatile=" preprocessor directives to
+get rid of unimplemented keywords.
+.TP
+token pasting and stringizing
+The traditional UNIX C preprocessor provides excellent alternatives.
+For example:
-For maximal flexibility, the "cpp | unproto" pipeline can be
-packaged as an executable shell script named "/somewhere/cpp".
-This script should then be specified to the C compiler as a
-non-default preprocessor.
+.nf
+.ne 2
+#define string(bar) "bar" /* instead of: # x */
+#define paste(x,y) x/**\/y /* instead of: x##y */
+.fi
-The overhead of shell script interpretation can be avoided by
-having the unprototyper itself open the pipe to the preprocessor.
-In that case, the source should be compiled with the PIPE_THROUGH_CPP
-macro defined (usually as "/lib/cpp"), and the resulting binary
-should be installed as "/somewhere/cpp".
+There is a good reason why the # and ## operators are not implemented
+in the unprototyper.
+After program text has gone through a non-ANSI C preprocessor, all
+information about the grouping of the operands of # and ## is lost.
+Thus, if the unprototyper were to perform these operations, it would
+produce correct results only in the most trivial cases. Operands
+with embedded blanks, operands that expand to null tokens, and nested
+use of # and/or ## would cause all kinds of obscure problems.
+.PP
+Unsupported ANSI features:
+.TP
+trigraphs and #pragmas
+Trigraphs are useful only for systems with broken character sets.
+If the local compiler chokes on #pragma, insert a blank before the
+"#" character, and enclose the offending directive between #ifdef
+and #endif.
.SH SEE ALSO
.na
.nf
.ad
.fi
cc(1), how to specify a non-default C preprocessor.
-
-Some versions of the lint command are implemented as a shell
+Some versions of the lint(1) command are implemented as a shell
script. It should require only minor modification for integration
-with the unprotoizer. Other versions of the lint command accept the same
-command syntax as the C compiler for the specification of a non-default
-preprocessor. Some research may be needed.
+with the unprototyper. Other versions of the lint(1) command accept
+the same command syntax as the C compiler for the specification of a
+non-default preprocessor. Some research may be needed.
+.SH FILES
+.na
+.nf
+/wherever/stdarg.h, provided with the unproto filter.
.SH DIAGNOSTICS
.ad
.fi
-The progam will complain if it unexpectedly
-reaches the end of input.
+Problems are reported on the standard error stream.
+A non-zero exit status means that there was a problem.
.SH BUGS
.ad
.fi
-Should be run on preprocessed source only, i.e. after macro expansion.
+The unprototyper should be run on preprocessed source only:
+unexpanded macros may confuse the program.
+
+Declarations of (object) are misunderstood and will result in
+syntax errors: the objects between parentheses disappear.
-Declarations of (whatever) are misunderstood and will result in
-syntax errors.
+Sometimes does not preserve whitespace after parentheses and commas.
+This is a purely aesthetical matter, and the compiler should not care.
+Whitespace within string constants is, of course, left intact.
-Does not generate explicit type casts for function argument
-expressions.
+Does not generate explicit type casts for function-argument
+expressions. The lack of explicit conversions between integral
+and/or pointer argument types should not be a problem in environments
+where sizeof(int) == sizeof(long) == sizeof(pointer). A more serious
+problem is the lack of automatic type conversions between integral and
+floating-point argument types. Let lint(1) be your friend.
.SH AUTHOR(S)
.na
.nf
@@ -72,8 +145,8 @@ Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
.SH LAST MODIFICATION
.na
.nf
-91/09/22 21:21:35
+93/06/18 22:29:37
.SH VERSION/RELEASE
.na
.nf
-1.2
+1.6
diff --git a/unproto/unproto.c b/unproto/unproto.c
index 9ca26ce..f7c03f7 100644
--- a/unproto/unproto.c
+++ b/unproto/unproto.c
@@ -2,68 +2,140 @@
/* NAME
/* unproto 1
/* SUMMARY
-/* ANSI C to old C converter
+/* compile ANSI C with traditional UNIX C compiler
/* PACKAGE
/* unproto
/* SYNOPSIS
-/* /lib/cpp ... | unproto
-/*
/* /somewhere/cpp ...
+/*
+/* cc cflags -E file.c | unproto >file.i; cc cflags -c file.i
/* DESCRIPTION
-/* This document describes a filter that sits between the
-/* C preprocessor (usually \fI/lib/cpp\fP) and the next C compiler
-/* pass. It rewrites ANSI-C style function headers, function type
-/* declarations, function pointer types, and function pointer casts
-/* to old style. Other ANSI-isms are passed on without modification
-/* (token pasting, pragmas, etcetera).
+/* This document describes a filter that sits in between the UNIX
+/* C preprocessor and the next UNIX C compiler stage, on the fly rewriting
+/* ANSI-style syntax to old-style syntax. Typically, the program is
+/* invoked by the native UNIX C compiler as an alternate preprocessor.
+/* The unprototyper in turn invokes the native C preprocessor and
+/* massages its output. Similar tricks can be used with the lint(1)
+/* command.
+/*
+/* Language constructs that are always rewritten:
+/* .TP
+/* function headings, prototypes, pointer types
+/* ANSI-C style function headings, function prototypes, function
+/* pointer types and type casts are rewritten to old style.
+/* <stdarg.h> support is provided for functions with variable-length
+/* argument lists.
+/* .TP
+/* character and string constants
+/* The \\a and \\x escape sequences are rewritten to their (three-digit)
+/* octal equivalents.
+/*
+/* Multiple string tokens are concatenated; an arbitrary number of
+/* whitespace or comment tokens may appear between successive
+/* string tokens.
/*
-/* For maximal flexibility, the "cpp | unproto" pipeline can be
-/* packaged as an executable shell script named "/somewhere/cpp".
-/* This script should then be specified to the C compiler as a
-/* non-default preprocessor. It will not work if your C compiler
-/* specifies output file names to the preprocessor.
+/* Within string constants, octal escape sequences are rewritten to the
+/* three-digit \\ddd form, so that string concatenation produces correct
+/* results.
+/* .TP
+/* date and time
+/* The __DATE__ and __TIME__ tokens are replaced by string constants
+/* of the form "Mmm dd yyyy" and "hh:mm:ss", respectively. The result
+/* is subjected to string concatenation, just like any other string
+/* constant.
+/* .PP
+/* Language constructs that are rewritten only if the program has been
+/* configured to do so:
+/* .TP
+/* void types
+/* The unprototyper can be configured to rewrite "void *" to "char *",
+/* and even to rewrite plain "void" to "int".
+/* These features are configurable because many traditional UNIX C
+/* compilers do not need them.
+/*
+/* Note: (void) argument lists are always replaced by empty ones.
+/* .PP
+/* ANSI C constructs that are not rewritten because the traditional
+/* UNIX C preprocessor provides suitable workarounds:
+/* .TP
+/* const and volatile
+/* Use the "-Dconst=" and/or "-Dvolatile=" preprocessor directives to
+/* get rid of unimplemented keywords.
+/* .TP
+/* token pasting and stringizing
+/* The traditional UNIX C preprocessor provides excellent alternatives.
+/* For example:
+/*
+/* .nf
+/* .ne 2
+/* #define string(bar) "bar" /* instead of: # x */
+/* #define paste(x,y) x/**\/y /* instead of: x##y */
+/* .fi
/*
-/* The overhead of shell script interpretation can be avoided by
-/* having the unprototyper itself open the pipe to the preprocessor.
-/* In that case, the source should be compiled with the PIPE_THROUGH_CPP
-/* macro defined (usually as "/lib/cpp"), and the resulting binary
-/* should be installed as "/somewhere/cpp".
+/* There is a good reason why the # and ## operators are not implemented
+/* in the unprototyper.
+/* After program text has gone through a non-ANSI C preprocessor, all
+/* information about the grouping of the operands of # and ## is lost.
+/* Thus, if the unprototyper were to perform these operations, it would
+/* produce correct results only in the most trivial cases. Operands
+/* with embedded blanks, operands that expand to null tokens, and nested
+/* use of # and/or ## would cause all kinds of obscure problems.
+/* .PP
+/* Unsupported ANSI features:
+/* .TP
+/* trigraphs and #pragmas
+/* Trigraphs are useful only for systems with broken character sets.
+/* If the local compiler chokes on #pragma, insert a blank before the
+/* "#" character, and enclose the offending directive between #ifdef
+/* and #endif.
/* SEE ALSO
/* .ad
/* .fi
/* cc(1), how to specify a non-default C preprocessor.
-/*
-/* Some versions of the lint command are implemented as a shell
+/* Some versions of the lint(1) command are implemented as a shell
/* script. It should require only minor modification for integration
-/* with the unprotoizer. Other versions of the lint command accept the same
-/* command syntax as the C compiler for the specification of a non-default
-/* preprocessor. Some research may be needed.
+/* with the unprototyper. Other versions of the lint(1) command accept
+/* the same command syntax as the C compiler for the specification of a
+/* non-default preprocessor. Some research may be needed.
+/* FILES
+/* /wherever/stdarg.h, provided with the unproto filter.
/* DIAGNOSTICS
-/* The progam will complain if it unexpectedly
-/* reaches the end of input.
+/* Problems are reported on the standard error stream.
+/* A non-zero exit status means that there was a problem.
/* BUGS
-/* Should be run on preprocessed source only, i.e. after macro expansion.
+/* The unprototyper should be run on preprocessed source only:
+/* unexpanded macros may confuse the program.
+/*
+/* Declarations of (object) are misunderstood and will result in
+/* syntax errors: the objects between parentheses disappear.
/*
-/* Declarations of (whatever) are misunderstood and will result in
-/* syntax errors.
+/* Sometimes does not preserve whitespace after parentheses and commas.
+/* This is a purely aesthetical matter, and the compiler should not care.
+/* Whitespace within string constants is, of course, left intact.
/*
-/* Does not generate explicit type casts for function argument
-/* expressions.
+/* Does not generate explicit type casts for function-argument
+/* expressions. The lack of explicit conversions between integral
+/* and/or pointer argument types should not be a problem in environments
+/* where sizeof(int) == sizeof(long) == sizeof(pointer). A more serious
+/* problem is the lack of automatic type conversions between integral and
+/* floating-point argument types. Let lint(1) be your friend.
/* AUTHOR(S)
/* Wietse Venema (wietse@wzv.win.tue.nl)
/* Eindhoven University of Technology
/* Department of Mathematics and Computer Science
/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
/* LAST MODIFICATION
-/* 91/09/22 21:21:35
+/* 93/06/18 22:29:37
/* VERSION/RELEASE
-/* 1.2
+/* 1.6
/*--*/
-static char unproto_sccsid[] = "@(#) unproto.c 1.3 91/11/30 21:10:30";
+static char unproto_sccsid[] = "@(#) unproto.c 1.6 93/06/18 22:29:37";
/* C library */
+#include <sys/types.h>
+#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
@@ -91,6 +163,7 @@ static void show_arg_name();
static void show_type();
static void pair_flush();
static void check_cast();
+static void show_empty_list();
#define check_cast_flush(t) (check_cast(t), tok_free(t))
@@ -110,8 +183,8 @@ static int pipe_stdin_through_cpp();
#define STREQ(x,y) (*(x) == *(y) && !strcmp((x),(y)))
-#define LAST_ARG_AND_EQUAL(s,c) ((s)->next == 0 && (s)->head \
- && ((s)->head == (s)->tail) \
+#define LAST_ARG_AND_EQUAL(s,c) ((s)->next && (s)->next->next == 0 \
+ && (s)->head && ((s)->head == (s)->tail) \
&& (STREQ((s)->head->vstr->str, (c))))
#define LIST_BEGINS_WITH_STAR(s) (s->head->head && s->head->head->tokno == '*')
@@ -120,6 +193,14 @@ static int pipe_stdin_through_cpp();
&& s->next->tokno == TOK_LIST \
&& LIST_BEGINS_WITH_STAR(s))
+/* What to look for to detect a (void) argument list. */
+
+#ifdef MAP_VOID
+#define VOID_ARG "int" /* bare "void" is mapped to "int" */
+#else
+#define VOID_ARG "void" /* bare "void" is left alone */
+#endif
+
/* main - driver */
int main(argc, argv)
@@ -133,7 +214,8 @@ char **argv;
int cpp_pid;
cpp_pid = pipe_stdin_through_cpp(argv);
-#else
+#endif
+#ifdef REOPEN
if ( argc > 1 ) {
if( freopen(argv[1], "r", stdin) == 0 ) {
fprintf(stderr, "Cannot open '%s'\n", argv[1]);
@@ -150,7 +232,7 @@ char **argv;
sym_init(); /* prime the symbol table */
- while (t = tok_class(DO_WSPACE)) {
+ while (t = tok_class()) {
if (t = dcl_flush(t)) { /* try declaration */
if (t->tokno == '{') { /* examine rejected token */
block_flush(t); /* body */
@@ -163,9 +245,9 @@ char **argv;
#ifdef PIPE_THROUGH_CPP /* pipe through /lib/cpp */
while ((wait_pid = wait(&cpp_status)) != -1 && wait_pid != cpp_pid)
/* void */ ;
- return (wait_pid != cpp_pid || cpp_status != 0);
+ return (errcount != 0 || wait_pid != cpp_pid || cpp_status != 0);
#else
- return (0);
+ return (errcount != 0);
#endif
}
@@ -179,6 +261,22 @@ char **argv;
int pipefds[2];
int pid;
char **cpptr = argv;
+ int i;
+ struct stat st;
+
+ /*
+ * The code that sets up the pipe requires that file descriptors 0,1,2
+ * are already open. All kinds of mysterious things will happen if that
+ * is not the case. The following loops makes sure that descriptors 0,1,2
+ * are set up properly.
+ */
+
+ for (i = 0; i < 3; i++) {
+ if (fstat(i, &st) == -1 && open("/dev/null", 2) != i) {
+ perror("open /dev/null");
+ exit(1);
+ }
+ }
/*
* With most UNIX implementations, the second non-option argument to
@@ -226,20 +324,22 @@ char **argv;
case -1: /* error */
perror("fork");
exit(1);
+ /* NOTREACHED */
case 0: /* child */
- close(pipefds[0]); /* close reading end */
- close(1); /* connect stdout to pipe */
+ (void) close(pipefds[0]); /* close reading end */
+ (void) close(1); /* connect stdout to pipe */
if (dup(pipefds[1]) != 1)
- error(1, "dup() problem");
- close(pipefds[1]); /* close redundant fd */
- execv(PIPE_THROUGH_CPP, argv);
+ fatal("dup() problem");
+ (void) close(pipefds[1]); /* close redundant fd */
+ (void) execv(PIPE_THROUGH_CPP, argv);
perror(PIPE_THROUGH_CPP);
exit(1);
+ /* NOTREACHED */
default: /* parent */
- close(pipefds[1]); /* close writing end */
- close(0); /* connect stdin to pipe */
+ (void) close(pipefds[1]); /* close writing end */
+ (void) close(0); /* connect stdin to pipe */
if (dup(pipefds[0]) != 0)
- error(1, "dup() problem");
+ fatal("dup() problem");
close(pipefds[0]); /* close redundant fd */
return (pid);
}
@@ -247,47 +347,160 @@ char **argv;
#endif
-/* header_flush - rewrite new-style function header to old style */
+/* show_arg_names - display function argument names */
-static void header_flush(t)
+static void show_arg_names(t)
register struct token *t;
{
register struct token *s;
/* Do argument names, but suppress void and rewrite trailing ... */
- if (LAST_ARG_AND_EQUAL(t->head, "void")) {
- put_str("()\n"); /* no arguments */
+ if (LAST_ARG_AND_EQUAL(t->head, VOID_ARG)) {
+ show_empty_list(t); /* no arguments */
} else {
for (s = t->head; s; s = s->next) { /* foreach argument... */
if (LAST_ARG_AND_EQUAL(s, "...")) {
#ifdef _VA_ALIST_ /* see ./stdarg.h */
- put_ch(s->tokno); /* ',' */
+ tok_show_ch(s); /* ',' */
put_str(_VA_ALIST_); /* varargs magic */
#endif
} else {
- put_ch(s->tokno); /* opening '(' or ',' */
+ tok_show_ch(s); /* '(' or ',' or ')' */
show_arg_name(s); /* extract argument name */
}
}
- put_str(")\n"); /* closing ')' */
}
+}
+
+/* show_arg_types - display function argument types */
+
+static void show_arg_types(t)
+register struct token *t;
+{
+ register struct token *s;
/* Do argument types, but suppress void and trailing ... */
- if (!LAST_ARG_AND_EQUAL(t->head, "void")) {
+ if (!LAST_ARG_AND_EQUAL(t->head, VOID_ARG)) {
for (s = t->head; s; s = s->next) { /* foreach argument... */
- if (!LAST_ARG_AND_EQUAL(s, "...")) {
+ if (LAST_ARG_AND_EQUAL(s, "...")) {
+#ifdef _VA_DCL_ /* see ./stdarg.h */
+ put_str(_VA_DCL_); /* varargs magic */
+ put_nl(); /* make output look nicer */
+#endif
+ } else {
if (s->head != s->tail) { /* really new-style argument? */
- show_line_control(); /* fix line number */
show_type(s); /* rewrite type info */
- put_str(";\n");
+ put_ch(';');
+ put_nl(); /* make output look nicer */
}
}
}
}
- tok_free(t);
- show_line_control(); /* because '{' follows */
+}
+
+/* header_flush - rewrite new-style function heading to old style */
+
+static void header_flush(t)
+register struct token *t;
+{
+ show_arg_names(t); /* show argument names */
+ put_nl(); /* make output look nicer */
+ show_arg_types(t); /* show argument types */
+ tok_free(t); /* discard token */
+}
+
+/* fpf_header_names - define func returning ptr to func, no argument types */
+
+static void fpf_header_names(list)
+struct token *list;
+{
+ register struct token *s;
+ register struct token *p;
+
+ /*
+ * Recurse until we find the argument list. Account for the rare case
+ * that list is a comma-separated list (which should be a syntax error).
+ * Display old-style fuction argument names.
+ */
+
+ for (s = list->head; s; s = s->next) {
+ tok_show_ch(s); /* '(' or ',' or ')' */
+ for (p = s->head; p; p = p->next) {
+ if (p->tokno == TOK_LIST) {
+ if (IS_FUNC_PTR_TYPE(p)) { /* recurse */
+ fpf_header_names(p);
+ show_empty_list(p = p->next);
+ } else { /* display argument names */
+ show_arg_names(p);
+ }
+ } else { /* pass through other stuff */
+ tok_show(p);
+ }
+ }
+ }
+}
+
+/* fpf_header_types - define func returning ptr to func, argument types only */
+
+static void fpf_header_types(list)
+struct token *list;
+{
+ register struct token *s;
+ register struct token *p;
+
+ /*
+ * Recurse until we find the argument list. Account for the rare case
+ * that list is a comma-separated list (which should be a syntax error).
+ * Display old-style function argument types.
+ */
+
+ for (s = list->head; s; s = s->next) {
+ for (p = s->head; p; p = p->next) {
+ if (p->tokno == TOK_LIST) {
+ if (IS_FUNC_PTR_TYPE(p)) { /* recurse */
+ fpf_header_types(p);
+ p = p->next;
+ } else { /* display argument types */
+ show_arg_types(p);
+ }
+ }
+ }
+ }
+}
+
+/* fpf_header - define function returning pointer to function */
+
+static void fpf_header(l1, l2)
+struct token *l1;
+struct token *l2;
+{
+ fpf_header_names(l1); /* strip argument types */
+ show_empty_list(l2); /* strip prototype */
+ put_nl(); /* nicer output */
+ fpf_header_types(l1); /* show argument types */
+}
+
+/* skip_enclosed - skip over enclosed tokens */
+
+static struct token *skip_enclosed(p, stop)
+register struct token *p;
+register int stop;
+{
+ register int start = p->tokno;
+
+ /* Always return a pointer to the last processed token, never NULL. */
+
+ while (p->next) {
+ p = p->next;
+ if (p->tokno == start) {
+ p = skip_enclosed(p, stop); /* recurse */
+ } else if (p->tokno == stop) {
+ break; /* done */
+ }
+ }
+ return (p);
}
/* show_arg_name - extract argument name from argument type info */
@@ -304,6 +517,10 @@ register struct token *s;
for (p = s->head; p; p = p->next) {
if (p->tokno == TOK_WORD) {
t = p; /* remember last word */
+ } else if (p->tokno == '{') {
+ p = skip_enclosed(p, '}'); /* skip structured stuff */
+ } else if (p->tokno == '[') {
+ break; /* dimension may be a macro */
} else if (IS_FUNC_PTR_TYPE(p)) {
t = p; /* or function pointer */
p = p->next;
@@ -328,35 +545,60 @@ register struct token *s;
{
register struct token *p;
+ /*
+ * Rewrite (*stuff)(args) to (*stuff)(). Rewrite word(args) to word(),
+ * but only if the word was preceded by a word, '*' or '}'. Leave
+ * anything else alone.
+ */
+
for (p = s->head; p; p = p->next) {
if (IS_FUNC_PTR_TYPE(p)) {
- p = show_func_ptr_type(p); /* function pointer type */
+ p = show_func_ptr_type(p, p->next); /* function pointer type */
} else {
+ register struct token *q;
+ register struct token *r;
+
tok_show(p); /* other */
+ if ((p->tokno == TOK_WORD || p->tokno == '*' || p->tokno == '}')
+ && (q = p->next) && q->tokno == TOK_WORD
+ && (r = q->next) && r->tokno == TOK_LIST) {
+ tok_show(q); /* show name */
+ show_empty_list(p = r); /* strip args */
+ }
}
}
}
/* show_func_ptr_type - display function_pointer type using old-style syntax */
-static struct token *show_func_ptr_type(t)
-struct token *t;
+static struct token *show_func_ptr_type(t1, t2)
+struct token *t1;
+struct token *t2;
{
register struct token *s;
/*
- * Rewrite (list1) (list2) to (list1) (). Only (list1) is given to us;
- * the caller must have verified the presence of (list2). Account for the
- * rare case that (list1) is a comma-separated list. That should be an
- * error, but we do not want to waste any information.
+ * Rewrite (list1) (list2) to (list1) (). Account for the rare case that
+ * (list1) is a comma-separated list. That should be an error, but we do
+ * not want to waste any information.
*/
- for (s = t->head; s; s = s->next) {
- put_ch(s->tokno); /* opening paren or ',' */
+ for (s = t1->head; s; s = s->next) {
+ tok_show_ch(s); /* '(' or ',' or ')' */
show_type(s); /* recurse */
}
- put_str(")()"); /* closing paren */
- return (t->next);
+ show_empty_list(t2);
+ return (t2);
+}
+
+/* show_empty_list - display opening and closing parentheses (if available) */
+
+static void show_empty_list(t)
+register struct token *t;
+{
+ tok_show_ch(t->head); /* opening paren */
+ if (t->tail->tokno == ')')
+ tok_show_ch(t->tail); /* closing paren */
}
/* show_struct_type - display structured type, rewrite function-pointer types */
@@ -369,7 +611,7 @@ register struct token *p;
while (p->next) { /* XXX cannot return 0 */
p = p->next;
if (IS_FUNC_PTR_TYPE(p)) {
- p = show_func_ptr_type(p); /* function-pointer member */
+ p = show_func_ptr_type(p, p->next); /* function-pointer member */
} else if (p->tokno == '{') {
p = show_struct_type(p); /* recurse */
} else {
@@ -409,6 +651,8 @@ register struct token *t;
return (is_func_ptr_cast(p));
case TOK_WORD: /* name in list */
return (0);
+ case '[':
+ return (1); /* dimension may be a macro */
}
}
return (1); /* no name found */
@@ -430,13 +674,13 @@ struct token *t;
*/
for (s = t->head; s; s = s->next) {
- put_ch(s->tokno); /* opening paren or ',' */
+ tok_show_ch(s); /* '(' or ',' or ')' */
for (p = s->head; p; p = p->next) {
switch (p->tokno) {
case TOK_LIST:
if (is_func_ptr_cast(p)) { /* not: IS_FUNC_PTR_TYPE(p) */
- p = show_func_ptr_type(p); /* or we might take away */
- } else { /* function-call arguments */
+ p = show_func_ptr_type(p, p->next);
+ } else {
check_cast(p); /* recurse */
}
break;
@@ -449,7 +693,6 @@ struct token *t;
}
}
}
- put_ch(')'); /* closing paren */
}
/* block_dcls - on the fly rewrite decls/initializers at start of block */
@@ -469,7 +712,7 @@ static void block_dcls()
* "union" tokens to the type_dcl() function.
*/
- while (t = tok_class(DO_WSPACE)) {
+ while (t = tok_class()) {
switch (t->tokno) {
case TOK_WSPACE: /* preserve white space */
case '\n': /* preserve line count */
@@ -477,7 +720,8 @@ static void block_dcls()
break;
case TOK_WORD: /* type declarations? */
tok_flush(t); /* advance to next token */
- t = tok_class(DO_WSPACE); /* null return is ok */
+ t = tok_class(); /* null return is ok */
+ /* FALLTRHOUGH */
case TOK_COMPOSITE: /* struct or union */
if ((t = dcl_flush(t)) == 0)
break;
@@ -511,7 +755,7 @@ register struct token *t;
/* Remainder of block: only rewrite function pointer casts. */
- while (t = tok_class(DO_WSPACE)) {
+ while (t = tok_class()) {
if (t->tokno == TOK_LIST) {
check_cast_flush(t);
} else if (t->tokno == '{') {
@@ -536,7 +780,7 @@ register int stop;
{
tok_flush(t);
- while (t = tok_class(DO_WSPACE)) {
+ while (t = tok_class()) {
if (t->tokno == start) { /* recurse */
pair_flush(t, start, stop);
} else if (t->tokno == TOK_LIST) { /* expression or cast */
@@ -557,7 +801,7 @@ static void initializer()
{
register struct token *t;
- while (t = tok_class(DO_WSPACE)) {
+ while (t = tok_class()) {
switch (t->tokno) {
case ',': /* list separator */
case ';': /* list terminator */
@@ -566,7 +810,7 @@ static void initializer()
case TOK_LIST: /* expression or cast */
check_cast_flush(t);
break;
- case '[': /* array substript, may nest */
+ case '[': /* array subscript, may nest */
pair_flush(t, '[', ']');
break;
case '{': /* structured data, may nest */
@@ -579,28 +823,47 @@ static void initializer()
}
}
-/* func_ptr_dcl_flush - rewrite function pointer declaration */
+/* func_ptr_dcl_flush - rewrite function pointer stuff */
static struct token *func_ptr_dcl_flush(list)
register struct token *list;
{
register struct token *t;
+ register struct token *t2;
/*
- * Ignore blanks because they would be output earlier than the list that
- * preceded them... Recover gracefully from syntax errors.
+ * Ignore blanks and newlines because we are too lazy to maintain more
+ * than one token worth of lookahead. The output routines will regenerate
+ * discarded newline tokens.
*/
- while (t = tok_class(NO_WSPACE)) {
+ while (t = tok_class()) {
switch (t->tokno) {
- case '\n': /* preserve line count */
- tok_flush(t);
+ case TOK_WSPACE:
+ case '\n':
+ tok_free(t);
break;
case TOK_LIST:
- /* Function pointer type: (list1) (list2) -> (list1) () */
- (void) show_func_ptr_type(list); /* may be recursive */
+ /* Function pointer or function returning pointer to function. */
+ while ((t2 = tok_class()) /* skip blanks etc. */
+ &&(t2->tokno == TOK_WSPACE || t2->tokno == '\n'))
+ tok_free(t2);
+ switch (t2 ? t2->tokno : 0) {
+ case '{': /* function heading (new) */
+ fpf_header(list, t);
+ break;
+ case TOK_WORD: /* function heading (old) */
+ tok_show(list);
+ tok_show(t);
+ break;
+ default: /* func pointer type */
+ (void) show_func_ptr_type(list, t);
+ break;
+ }
tok_free(list);
tok_free(t);
+ if (t2)
+ tok_unget(t2);
return (0);
default: /* not a declaration */
tok_unget(t);
@@ -621,15 +884,16 @@ register struct token *list;
register struct token *t;
/*
- * Ignore blanks because they would be output earlier than the list that
- * preceded them...
+ * Ignore blanks and newlines because we are too lazy to maintain more
+ * than one token worth of lookahead. The output routines will regenerate
+ * ignored newline tokens.
*/
- while (t = tok_class(NO_WSPACE)) {
+ while (t = tok_class()) {
switch (t->tokno) {
+ case TOK_WSPACE:
case '\n':
- /* Preserve line count */
- tok_flush(t);
+ tok_free(t);
break;
case '{':
/* Function heading: word (list) { -> old style heading */
@@ -637,21 +901,21 @@ register struct token *list;
tok_unget(t);
return (0);
case TOK_WORD:
- /* Old-style function heading: word (list) word...{ */
+ /* Old-style function heading: word (list) word... */
tok_flush(list);
tok_unget(t);
return (0);
case TOK_LIST:
- /* Function typedef? word (list1) (list) -> word (list1) () */
+ /* Function pointer: word (list1) (list2) -> word (list1) () */
tok_flush(list);
- put_str("()");
+ show_empty_list(t);
tok_free(t);
return (0);
case ',':
case ';':
/* Function type declaration: word (list) -> word () */
+ show_empty_list(list);
tok_free(list);
- put_str("()");
tok_unget(t);
return (0);
default:
@@ -686,7 +950,7 @@ register struct token *t;
* level. The caller should give is the "struct" or "union" token.
*/
- for (got_word = 0; t; t = tok_class(DO_WSPACE)) {
+ for (got_word = 0; t; t = tok_class()) {
switch (t->tokno) {
case TOK_WSPACE: /* advance past blanks */
case '\n': /* advance past newline */
diff --git a/unproto/unproto.c.old b/unproto/unproto.c.old
new file mode 100644
index 0000000..2b2e764
--- /dev/null
+++ b/unproto/unproto.c.old
@@ -0,0 +1,999 @@
+/*++
+/* NAME
+/* unproto 1
+/* SUMMARY
+/* compile ANSI C with traditional UNIX C compiler
+/* PACKAGE
+/* unproto
+/* SYNOPSIS
+/* /somewhere/cpp ...
+/*
+/* cc cflags -E file.c | unproto >file.i; cc cflags -c file.i
+/* DESCRIPTION
+/* This document describes a filter that sits in between the UNIX
+/* C preprocessor and the next UNIX C compiler stage, on the fly rewriting
+/* ANSI-style syntax to old-style syntax. Typically, the program is
+/* invoked by the native UNIX C compiler as an alternate preprocessor.
+/* The unprototyper in turn invokes the native C preprocessor and
+/* massages its output. Similar tricks can be used with the lint(1)
+/* command.
+/*
+/* Language constructs that are always rewritten:
+/* .TP
+/* function headings, prototypes, pointer types
+/* ANSI-C style function headings, function prototypes, function
+/* pointer types and type casts are rewritten to old style.
+/* <stdarg.h> support is provided for functions with variable-length
+/* argument lists.
+/* .TP
+/* character and string constants
+/* The \\a and \\x escape sequences are rewritten to their (three-digit)
+/* octal equivalents.
+/*
+/* Multiple string tokens are concatenated; an arbitrary number of
+/* whitespace or comment tokens may appear between successive
+/* string tokens.
+/*
+/* Within string constants, octal escape sequences are rewritten to the
+/* three-digit \\ddd form, so that string concatenation produces correct
+/* results.
+/* .TP
+/* date and time
+/* The __DATE__ and __TIME__ tokens are replaced by string constants
+/* of the form "Mmm dd yyyy" and "hh:mm:ss", respectively. The result
+/* is subjected to string concatenation, just like any other string
+/* constant.
+/* .PP
+/* Language constructs that are rewritten only if the program has been
+/* configured to do so:
+/* .TP
+/* void types
+/* The unprototyper can be configured to rewrite "void *" to "char *",
+/* and even to rewrite plain "void" to "int".
+/* These features are configurable because many traditional UNIX C
+/* compilers do not need them.
+/*
+/* Note: (void) argument lists are always replaced by empty ones.
+/* .PP
+/* ANSI C constructs that are not rewritten because the traditional
+/* UNIX C preprocessor provides suitable workarounds:
+/* .TP
+/* const and volatile
+/* Use the "-Dconst=" and/or "-Dvolatile=" preprocessor directives to
+/* get rid of unimplemented keywords.
+/* .TP
+/* token pasting and stringizing
+/* The traditional UNIX C preprocessor provides excellent alternatives.
+/* For example:
+/*
+/* .nf
+/* .ne 2
+/* #define string(bar) "bar" /* instead of: # x */
+/* #define paste(x,y) x/**\/y /* instead of: x##y */
+/* .fi
+/*
+/* There is a good reason why the # and ## operators are not implemented
+/* in the unprototyper.
+/* After program text has gone through a non-ANSI C preprocessor, all
+/* information about the grouping of the operands of # and ## is lost.
+/* Thus, if the unprototyper were to perform these operations, it would
+/* produce correct results only in the most trivial cases. Operands
+/* with embedded blanks, operands that expand to null tokens, and nested
+/* use of # and/or ## would cause all kinds of obscure problems.
+/* .PP
+/* Unsupported ANSI features:
+/* .TP
+/* trigraphs and #pragmas
+/* Trigraphs are useful only for systems with broken character sets.
+/* If the local compiler chokes on #pragma, insert a blank before the
+/* "#" character, and enclose the offending directive between #ifdef
+/* and #endif.
+/* SEE ALSO
+/* .ad
+/* .fi
+/* cc(1), how to specify a non-default C preprocessor.
+/* Some versions of the lint(1) command are implemented as a shell
+/* script. It should require only minor modification for integration
+/* with the unprototyper. Other versions of the lint(1) command accept
+/* the same command syntax as the C compiler for the specification of a
+/* non-default preprocessor. Some research may be needed.
+/* FILES
+/* /wherever/stdarg.h, provided with the unproto filter.
+/* DIAGNOSTICS
+/* Problems are reported on the standard error stream.
+/* A non-zero exit status means that there was a problem.
+/* BUGS
+/* The unprototyper should be run on preprocessed source only:
+/* unexpanded macros may confuse the program.
+/*
+/* Declarations of (object) are misunderstood and will result in
+/* syntax errors: the objects between parentheses disappear.
+/*
+/* Sometimes does not preserve whitespace after parentheses and commas.
+/* This is a purely aesthetical matter, and the compiler should not care.
+/* Whitespace within string constants is, of course, left intact.
+/*
+/* Does not generate explicit type casts for function-argument
+/* expressions. The lack of explicit conversions between integral
+/* and/or pointer argument types should not be a problem in environments
+/* where sizeof(int) == sizeof(long) == sizeof(pointer). A more serious
+/* problem is the lack of automatic type conversions between integral and
+/* floating-point argument types. Let lint(1) be your friend.
+/* AUTHOR(S)
+/* Wietse Venema (wietse@wzv.win.tue.nl)
+/* Eindhoven University of Technology
+/* Department of Mathematics and Computer Science
+/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
+/* LAST MODIFICATION
+/* 93/06/18 22:29:37
+/* VERSION/RELEASE
+/* 1.6
+/*--*/
+
+static char unproto_sccsid[] = "@(#) unproto.c 1.6 93/06/18 22:29:37";
+
+/* C library */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <errno.h>
+
+extern void exit();
+extern int optind;
+extern char *optarg;
+extern int getopt();
+
+/* Application-specific stuff */
+
+#include "vstring.h"
+#include "stdarg.h"
+#include "token.h"
+#include "error.h"
+#include "symbol.h"
+
+/* Forward declarations. */
+
+static struct token *dcl_flush();
+static void block_flush();
+static void block_dcls();
+static struct token *show_func_ptr_type();
+static struct token *show_struct_type();
+static void show_arg_name();
+static void show_type();
+static void pair_flush();
+static void check_cast();
+static void show_empty_list();
+
+#define check_cast_flush(t) (check_cast(t), tok_free(t))
+
+#ifdef PIPE_THROUGH_CPP
+static int pipe_stdin_through_cpp();
+#endif
+
+/* Disable debugging printfs while preserving side effects. */
+
+#ifdef DEBUG
+#define DPRINTF printf
+#else
+#define DPRINTF (void)
+#endif
+
+/* An attempt to make some complicated expressions a bit more readable. */
+
+#define STREQ(x,y) (*(x) == *(y) && !strcmp((x),(y)))
+
+#define LAST_ARG_AND_EQUAL(s,c) ((s)->next && (s)->next->next == 0 \
+ && (s)->head && ((s)->head == (s)->tail) \
+ && (STREQ((s)->head->vstr->str, (c))))
+
+#define LIST_BEGINS_WITH_STAR(s) (s->head->head && s->head->head->tokno == '*')
+
+#define IS_FUNC_PTR_TYPE(s) (s->tokno == TOK_LIST && s->next \
+ && s->next->tokno == TOK_LIST \
+ && LIST_BEGINS_WITH_STAR(s))
+
+/* What to look for to detect a (void) argument list. */
+
+#ifdef MAP_VOID
+#define VOID_ARG "int" /* bare "void" is mapped to "int" */
+#else
+#define VOID_ARG "void" /* bare "void" is left alone */
+#endif
+
+/* main - driver */
+
+int main(argc, argv)
+int argc;
+char **argv;
+{
+ register struct token *t;
+#ifdef PIPE_THROUGH_CPP /* pipe through /lib/cpp */
+ int cpp_status;
+ int wait_pid;
+ int cpp_pid;
+
+ cpp_pid = pipe_stdin_through_cpp(argv);
+#endif
+
+ sym_init(); /* prime the symbol table */
+
+ while (t = tok_class()) {
+ if (t = dcl_flush(t)) { /* try declaration */
+ if (t->tokno == '{') { /* examine rejected token */
+ block_flush(t); /* body */
+ } else {
+ tok_flush(t); /* other, recover */
+ }
+ }
+ }
+
+#ifdef PIPE_THROUGH_CPP /* pipe through /lib/cpp */
+ while ((wait_pid = wait(&cpp_status)) != -1 && wait_pid != cpp_pid)
+ /* void */ ;
+ return (errcount != 0 || wait_pid != cpp_pid || cpp_status != 0);
+#else
+ return (errcount != 0);
+#endif
+}
+
+#ifdef PIPE_THROUGH_CPP /* pipe through /lib/cpp */
+
+/* pipe_stdin_through_cpp - avoid shell script overhead */
+
+static int pipe_stdin_through_cpp(argv)
+char **argv;
+{
+ int pipefds[2];
+ int pid;
+ char **cpptr = argv;
+ int i;
+ struct stat st;
+
+ /*
+ * The code that sets up the pipe requires that file descriptors 0,1,2
+ * are already open. All kinds of mysterious things will happen if that
+ * is not the case. The following loops makes sure that descriptors 0,1,2
+ * are set up properly.
+ */
+
+ for (i = 0; i < 3; i++) {
+ if (fstat(i, &st) == -1 && open("/dev/null", 2) != i) {
+ perror("open /dev/null");
+ exit(1);
+ }
+ }
+
+ /*
+ * With most UNIX implementations, the second non-option argument to
+ * /lib/cpp specifies the output file. If an output file other than
+ * stdout is specified, we must force /lib/cpp to write to stdout, and we
+ * must redirect our own standard output to the specified output file.
+ */
+
+#define IS_OPTION(cp) ((cp)[0] == '-' && (cp)[1] != 0)
+
+ /* Skip to first non-option argument, if any. */
+
+ while (*++cpptr && IS_OPTION(*cpptr))
+ /* void */ ;
+
+ /*
+ * Assume that the first non-option argument is the input file name. The
+ * next argument could be the output destination or an option (System V
+ * Release 2 /lib/cpp gets the options *after* the file arguments).
+ */
+
+ if (*cpptr && *++cpptr && **cpptr != '-') {
+
+ /*
+ * The first non-option argument is followed by another argument that
+ * is not an option ("-stuff") or a hyphen ("-"). Redirect our own
+ * standard output before we clobber the file name.
+ */
+
+ if (freopen(*cpptr, "w", stdout) == 0) {
+ perror(*cpptr);
+ exit(1);
+ }
+ /* Clobber the file name argument so that /lib/cpp writes to stdout */
+
+ *cpptr = "-";
+ }
+ /* Set up the pipe that connects /lib/cpp to our standard input. */
+
+ if (pipe(pipefds)) {
+ perror("pipe");
+ exit(1);
+ }
+ switch (pid = fork()) {
+ case -1: /* error */
+ perror("fork");
+ exit(1);
+ /* NOTREACHED */
+ case 0: /* child */
+ (void) close(pipefds[0]); /* close reading end */
+ (void) close(1); /* connect stdout to pipe */
+ if (dup(pipefds[1]) != 1)
+ fatal("dup() problem");
+ (void) close(pipefds[1]); /* close redundant fd */
+ (void) execv(PIPE_THROUGH_CPP, argv);
+ perror(PIPE_THROUGH_CPP);
+ exit(1);
+ /* NOTREACHED */
+ default: /* parent */
+ (void) close(pipefds[1]); /* close writing end */
+ (void) close(0); /* connect stdin to pipe */
+ if (dup(pipefds[0]) != 0)
+ fatal("dup() problem");
+ close(pipefds[0]); /* close redundant fd */
+ return (pid);
+ }
+}
+
+#endif
+
+/* show_arg_names - display function argument names */
+
+static void show_arg_names(t)
+register struct token *t;
+{
+ register struct token *s;
+
+ /* Do argument names, but suppress void and rewrite trailing ... */
+
+ if (LAST_ARG_AND_EQUAL(t->head, VOID_ARG)) {
+ show_empty_list(t); /* no arguments */
+ } else {
+ for (s = t->head; s; s = s->next) { /* foreach argument... */
+ if (LAST_ARG_AND_EQUAL(s, "...")) {
+#ifdef _VA_ALIST_ /* see ./stdarg.h */
+ tok_show_ch(s); /* ',' */
+ put_str(_VA_ALIST_); /* varargs magic */
+#endif
+ } else {
+ tok_show_ch(s); /* '(' or ',' or ')' */
+ show_arg_name(s); /* extract argument name */
+ }
+ }
+ }
+}
+
+/* show_arg_types - display function argument types */
+
+static void show_arg_types(t)
+register struct token *t;
+{
+ register struct token *s;
+
+ /* Do argument types, but suppress void and trailing ... */
+
+ if (!LAST_ARG_AND_EQUAL(t->head, VOID_ARG)) {
+ for (s = t->head; s; s = s->next) { /* foreach argument... */
+ if (LAST_ARG_AND_EQUAL(s, "...")) {
+#ifdef _VA_DCL_ /* see ./stdarg.h */
+ put_str(_VA_DCL_); /* varargs magic */
+ put_nl(); /* make output look nicer */
+#endif
+ } else {
+ if (s->head != s->tail) { /* really new-style argument? */
+ show_type(s); /* rewrite type info */
+ put_ch(';');
+ put_nl(); /* make output look nicer */
+ }
+ }
+ }
+ }
+}
+
+/* header_flush - rewrite new-style function heading to old style */
+
+static void header_flush(t)
+register struct token *t;
+{
+ show_arg_names(t); /* show argument names */
+ put_nl(); /* make output look nicer */
+ show_arg_types(t); /* show argument types */
+ tok_free(t); /* discard token */
+}
+
+/* fpf_header_names - define func returning ptr to func, no argument types */
+
+static void fpf_header_names(list)
+struct token *list;
+{
+ register struct token *s;
+ register struct token *p;
+
+ /*
+ * Recurse until we find the argument list. Account for the rare case
+ * that list is a comma-separated list (which should be a syntax error).
+ * Display old-style fuction argument names.
+ */
+
+ for (s = list->head; s; s = s->next) {
+ tok_show_ch(s); /* '(' or ',' or ')' */
+ for (p = s->head; p; p = p->next) {
+ if (p->tokno == TOK_LIST) {
+ if (IS_FUNC_PTR_TYPE(p)) { /* recurse */
+ fpf_header_names(p);
+ show_empty_list(p = p->next);
+ } else { /* display argument names */
+ show_arg_names(p);
+ }
+ } else { /* pass through other stuff */
+ tok_show(p);
+ }
+ }
+ }
+}
+
+/* fpf_header_types - define func returning ptr to func, argument types only */
+
+static void fpf_header_types(list)
+struct token *list;
+{
+ register struct token *s;
+ register struct token *p;
+
+ /*
+ * Recurse until we find the argument list. Account for the rare case
+ * that list is a comma-separated list (which should be a syntax error).
+ * Display old-style function argument types.
+ */
+
+ for (s = list->head; s; s = s->next) {
+ for (p = s->head; p; p = p->next) {
+ if (p->tokno == TOK_LIST) {
+ if (IS_FUNC_PTR_TYPE(p)) { /* recurse */
+ fpf_header_types(p);
+ p = p->next;
+ } else { /* display argument types */
+ show_arg_types(p);
+ }
+ }
+ }
+ }
+}
+
+/* fpf_header - define function returning pointer to function */
+
+static void fpf_header(l1, l2)
+struct token *l1;
+struct token *l2;
+{
+ fpf_header_names(l1); /* strip argument types */
+ show_empty_list(l2); /* strip prototype */
+ put_nl(); /* nicer output */
+ fpf_header_types(l1); /* show argument types */
+}
+
+/* skip_enclosed - skip over enclosed tokens */
+
+static struct token *skip_enclosed(p, stop)
+register struct token *p;
+register int stop;
+{
+ register int start = p->tokno;
+
+ /* Always return a pointer to the last processed token, never NULL. */
+
+ while (p->next) {
+ p = p->next;
+ if (p->tokno == start) {
+ p = skip_enclosed(p, stop); /* recurse */
+ } else if (p->tokno == stop) {
+ break; /* done */
+ }
+ }
+ return (p);
+}
+
+/* show_arg_name - extract argument name from argument type info */
+
+static void show_arg_name(s)
+register struct token *s;
+{
+ if (s->head) {
+ register struct token *p;
+ register struct token *t = 0;
+
+ /* Find the last interesting item. */
+
+ for (p = s->head; p; p = p->next) {
+ if (p->tokno == TOK_WORD) {
+ t = p; /* remember last word */
+ } else if (p->tokno == '{') {
+ p = skip_enclosed(p, '}'); /* skip structured stuff */
+ } else if (p->tokno == '[') {
+ break; /* dimension may be a macro */
+ } else if (IS_FUNC_PTR_TYPE(p)) {
+ t = p; /* or function pointer */
+ p = p->next;
+ }
+ }
+
+ /* Extract argument name from last interesting item. */
+
+ if (t) {
+ if (t->tokno == TOK_LIST)
+ show_arg_name(t->head); /* function pointer, recurse */
+ else
+ tok_show(t); /* print last word */
+ }
+ }
+}
+
+/* show_type - rewrite type to old-style syntax */
+
+static void show_type(s)
+register struct token *s;
+{
+ register struct token *p;
+
+ /*
+ * Rewrite (*stuff)(args) to (*stuff)(). Rewrite word(args) to word(),
+ * but only if the word was preceded by a word, '*' or '}'. Leave
+ * anything else alone.
+ */
+
+ for (p = s->head; p; p = p->next) {
+ if (IS_FUNC_PTR_TYPE(p)) {
+ p = show_func_ptr_type(p, p->next); /* function pointer type */
+ } else {
+ register struct token *q;
+ register struct token *r;
+
+ tok_show(p); /* other */
+ if ((p->tokno == TOK_WORD || p->tokno == '*' || p->tokno == '}')
+ && (q = p->next) && q->tokno == TOK_WORD
+ && (r = q->next) && r->tokno == TOK_LIST) {
+ tok_show(q); /* show name */
+ show_empty_list(p = r); /* strip args */
+ }
+ }
+ }
+}
+
+/* show_func_ptr_type - display function_pointer type using old-style syntax */
+
+static struct token *show_func_ptr_type(t1, t2)
+struct token *t1;
+struct token *t2;
+{
+ register struct token *s;
+
+ /*
+ * Rewrite (list1) (list2) to (list1) (). Account for the rare case that
+ * (list1) is a comma-separated list. That should be an error, but we do
+ * not want to waste any information.
+ */
+
+ for (s = t1->head; s; s = s->next) {
+ tok_show_ch(s); /* '(' or ',' or ')' */
+ show_type(s); /* recurse */
+ }
+ show_empty_list(t2);
+ return (t2);
+}
+
+/* show_empty_list - display opening and closing parentheses (if available) */
+
+static void show_empty_list(t)
+register struct token *t;
+{
+ tok_show_ch(t->head); /* opening paren */
+ if (t->tail->tokno == ')')
+ tok_show_ch(t->tail); /* closing paren */
+}
+
+/* show_struct_type - display structured type, rewrite function-pointer types */
+
+static struct token *show_struct_type(p)
+register struct token *p;
+{
+ tok_show(p); /* opening brace */
+
+ while (p->next) { /* XXX cannot return 0 */
+ p = p->next;
+ if (IS_FUNC_PTR_TYPE(p)) {
+ p = show_func_ptr_type(p, p->next); /* function-pointer member */
+ } else if (p->tokno == '{') {
+ p = show_struct_type(p); /* recurse */
+ } else {
+ tok_show(p); /* other */
+ if (p->tokno == '}') {
+ return (p); /* done */
+ }
+ }
+ }
+ DPRINTF("/* missing '}' */");
+ return (p);
+}
+
+/* is_func_ptr_cast - recognize function-pointer type cast */
+
+static int is_func_ptr_cast(t)
+register struct token *t;
+{
+ register struct token *p;
+
+ /*
+ * Examine superficial structure. Require (list1) (list2). Require that
+ * list1 begins with a star.
+ */
+
+ if (!IS_FUNC_PTR_TYPE(t))
+ return (0);
+
+ /*
+ * Make sure that there is no name in (list1). Do not worry about
+ * unexpected tokens, because the compiler will complain anyway.
+ */
+
+ for (p = t->head->head; p; p = p->next) {
+ switch (p->tokno) {
+ case TOK_LIST: /* recurse */
+ return (is_func_ptr_cast(p));
+ case TOK_WORD: /* name in list */
+ return (0);
+ case '[':
+ return (1); /* dimension may be a macro */
+ }
+ }
+ return (1); /* no name found */
+}
+
+/* check_cast - display ()-delimited, comma-separated list */
+
+static void check_cast(t)
+struct token *t;
+{
+ register struct token *s;
+ register struct token *p;
+
+ /*
+ * Rewrite function-pointer types and function-pointer casts. Do not
+ * blindly rewrite (*list1)(list2) to (*list1)(). Function argument lists
+ * are about the only thing we can discard without provoking diagnostics
+ * from the compiler.
+ */
+
+ for (s = t->head; s; s = s->next) {
+ tok_show_ch(s); /* '(' or ',' or ')' */
+ for (p = s->head; p; p = p->next) {
+ switch (p->tokno) {
+ case TOK_LIST:
+ if (is_func_ptr_cast(p)) { /* not: IS_FUNC_PTR_TYPE(p) */
+ p = show_func_ptr_type(p, p->next);
+ } else {
+ check_cast(p); /* recurse */
+ }
+ break;
+ case '{':
+ p = show_struct_type(p); /* rewrite func. ptr. types */
+ break;
+ default:
+ tok_show(p);
+ break;
+ }
+ }
+ }
+}
+
+/* block_dcls - on the fly rewrite decls/initializers at start of block */
+
+static void block_dcls()
+{
+ register struct token *t;
+
+ /*
+ * Away from the top level, a declaration should be preceded by type or
+ * storage-class information. That is why inside blocks, structs and
+ * unions we insist on reading one word before passing the _next_ token
+ * to the dcl_flush() function.
+ *
+ * Struct and union declarations look the same everywhere: we make an
+ * exception for these more regular constructs and pass the "struct" and
+ * "union" tokens to the type_dcl() function.
+ */
+
+ while (t = tok_class()) {
+ switch (t->tokno) {
+ case TOK_WSPACE: /* preserve white space */
+ case '\n': /* preserve line count */
+ tok_flush(t);
+ break;
+ case TOK_WORD: /* type declarations? */
+ tok_flush(t); /* advance to next token */
+ t = tok_class(); /* null return is ok */
+ /* FALLTRHOUGH */
+ case TOK_COMPOSITE: /* struct or union */
+ if ((t = dcl_flush(t)) == 0)
+ break;
+ /* FALLTRHOUGH */
+ default: /* end of declarations */
+ DPRINTF("/* end dcls */");
+ /* FALLTRHOUGH */
+ case '}': /* end of block */
+ tok_unget(t);
+ return;
+ }
+ }
+}
+
+/* block_flush - rewrite struct, union or statement block on the fly */
+
+static void block_flush(t)
+register struct token *t;
+{
+ static int count = 0;
+
+ tok_flush(t);
+ DPRINTF("/*%d*/", ++count);
+
+ /*
+ * Rewrite function pointer types in declarations and function pointer
+ * casts in initializers at start of block.
+ */
+
+ block_dcls();
+
+ /* Remainder of block: only rewrite function pointer casts. */
+
+ while (t = tok_class()) {
+ if (t->tokno == TOK_LIST) {
+ check_cast_flush(t);
+ } else if (t->tokno == '{') {
+ block_flush(t);
+ } else {
+ tok_flush(t);
+ if (t->tokno == '}') {
+ DPRINTF("/*%d*/", count--);
+ return;
+ }
+ }
+ }
+ DPRINTF("/* missing '}' */");
+}
+
+/* pair_flush - on the fly rewrite casts in grouped stuff */
+
+static void pair_flush(t, start, stop)
+register struct token *t;
+register int start;
+register int stop;
+{
+ tok_flush(t);
+
+ while (t = tok_class()) {
+ if (t->tokno == start) { /* recurse */
+ pair_flush(t, start, stop);
+ } else if (t->tokno == TOK_LIST) { /* expression or cast */
+ check_cast_flush(t);
+ } else { /* other, copy */
+ tok_flush(t);
+ if (t->tokno == stop) { /* done */
+ return;
+ }
+ }
+ }
+ DPRINTF("/* missing '%c' */", stop);
+}
+
+/* initializer - on the fly rewrite casts in initializer */
+
+static void initializer()
+{
+ register struct token *t;
+
+ while (t = tok_class()) {
+ switch (t->tokno) {
+ case ',': /* list separator */
+ case ';': /* list terminator */
+ tok_unget(t);
+ return;
+ case TOK_LIST: /* expression or cast */
+ check_cast_flush(t);
+ break;
+ case '[': /* array subscript, may nest */
+ pair_flush(t, '[', ']');
+ break;
+ case '{': /* structured data, may nest */
+ pair_flush(t, '{', '}');
+ break;
+ default: /* other, just copy */
+ tok_flush(t);
+ break;
+ }
+ }
+}
+
+/* func_ptr_dcl_flush - rewrite function pointer stuff */
+
+static struct token *func_ptr_dcl_flush(list)
+register struct token *list;
+{
+ register struct token *t;
+ register struct token *t2;
+
+ /*
+ * Ignore blanks and newlines because we are too lazy to maintain more
+ * than one token worth of lookahead. The output routines will regenerate
+ * discarded newline tokens.
+ */
+
+ while (t = tok_class()) {
+ switch (t->tokno) {
+ case TOK_WSPACE:
+ case '\n':
+ tok_free(t);
+ break;
+ case TOK_LIST:
+ /* Function pointer or function returning pointer to function. */
+ while ((t2 = tok_class()) /* skip blanks etc. */
+ &&(t2->tokno == TOK_WSPACE || t2->tokno == '\n'))
+ tok_free(t2);
+ switch (t2 ? t2->tokno : 0) {
+ case '{': /* function heading (new) */
+ fpf_header(list, t);
+ break;
+ case TOK_WORD: /* function heading (old) */
+ tok_show(list);
+ tok_show(t);
+ break;
+ default: /* func pointer type */
+ (void) show_func_ptr_type(list, t);
+ break;
+ }
+ tok_free(list);
+ tok_free(t);
+ if (t2)
+ tok_unget(t2);
+ return (0);
+ default: /* not a declaration */
+ tok_unget(t);
+ return (list);
+ }
+ }
+
+ /* Hit EOF; must be mistake, but do not waste any information. */
+
+ return (list);
+}
+
+/* function_dcl_flush - rewrite function { heading, type declaration } */
+
+static struct token *function_dcl_flush(list)
+register struct token *list;
+{
+ register struct token *t;
+
+ /*
+ * Ignore blanks and newlines because we are too lazy to maintain more
+ * than one token worth of lookahead. The output routines will regenerate
+ * ignored newline tokens.
+ */
+
+ while (t = tok_class()) {
+ switch (t->tokno) {
+ case TOK_WSPACE:
+ case '\n':
+ tok_free(t);
+ break;
+ case '{':
+ /* Function heading: word (list) { -> old style heading */
+ header_flush(list);
+ tok_unget(t);
+ return (0);
+ case TOK_WORD:
+ /* Old-style function heading: word (list) word... */
+ tok_flush(list);
+ tok_unget(t);
+ return (0);
+ case TOK_LIST:
+ /* Function pointer: word (list1) (list2) -> word (list1) () */
+ tok_flush(list);
+ show_empty_list(t);
+ tok_free(t);
+ return (0);
+ case ',':
+ case ';':
+ /* Function type declaration: word (list) -> word () */
+ show_empty_list(list);
+ tok_free(list);
+ tok_unget(t);
+ return (0);
+ default:
+ /* Something else, reject the list. */
+ tok_unget(t);
+ return (list);
+ }
+ }
+
+ /* Hit EOF; must be mistake, but do not waste any information. */
+
+ return (list);
+}
+
+/* dcl_flush - parse declaration on the fly, return rejected token */
+
+static struct token *dcl_flush(t)
+register struct token *t;
+{
+ register int got_word;
+
+ /*
+ * Away from the top level, type or storage-class information is required
+ * for an (extern or forward) function type declaration or a variable
+ * declaration.
+ *
+ * With our naive word-counting approach, this means that the caller should
+ * read one word before passing the next token to us. This is how we
+ * distinguish, for example, function declarations from function calls.
+ *
+ * An exception are structs and unions, because they look the same at any
+ * level. The caller should give is the "struct" or "union" token.
+ */
+
+ for (got_word = 0; t; t = tok_class()) {
+ switch (t->tokno) {
+ case TOK_WSPACE: /* advance past blanks */
+ case '\n': /* advance past newline */
+ case '*': /* indirection: keep trying */
+ tok_flush(t);
+ break;
+ case TOK_WORD: /* word: keep trying */
+ case TOK_COMPOSITE: /* struct or union */
+ got_word = 1;
+ tok_flush(t);
+ break;
+ default:
+
+ /*
+ * Function pointer types can be preceded by zero or more words
+ * (at least one when not at the top level). Other stuff can be
+ * accepted only after we have seen at least one word (two words
+ * when not at the top level). See also the above comment on
+ * structs and unions.
+ */
+
+ if (t->tokno == TOK_LIST && LIST_BEGINS_WITH_STAR(t)) {
+ if (t = func_ptr_dcl_flush(t)) {
+ return (t); /* reject token */
+ } else {
+ got_word = 1; /* for = and [ and , and ; */
+ }
+ } else if (got_word == 0) {
+ return (t); /* reject token */
+ } else {
+ switch (t->tokno) {
+ case TOK_LIST: /* function type */
+ if (t = function_dcl_flush(t))
+ return (t); /* reject token */
+ break;
+ case '[': /* dimension, does not nest */
+ pair_flush(t, '[', ']');
+ break;
+ case '=': /* initializer follows */
+ tok_flush(t);
+ initializer(); /* rewrite casts */
+ break;
+ case '{': /* struct, union, may nest */
+ block_flush(t); /* use code for stmt blocks */
+ break;
+ case ',': /* separator: keep trying */
+ got_word = 0;
+ tok_flush(t);
+ break;
+ case ';': /* terminator: succeed */
+ tok_flush(t);
+ return (0);
+ default: /* reject token */
+ return (t);
+ }
+ }
+ }
+ }
+ return (0); /* hit EOF */
+}
diff --git a/unproto/vstring.c b/unproto/vstring.c
index fb8d053..220bd53 100644
--- a/unproto/vstring.c
+++ b/unproto/vstring.c
@@ -15,13 +15,19 @@
/* struct vstring *vs;
/* char *wp;
/* int ch;
+/*
+/* char *vs_strcpy(vp, dst, src)
+/* struct vstring *vp;
+/* char *dst;
+/* char *src;
/* DESCRIPTION
/* These functions and macros implement a small library for
/* arbitrary-length strings that grow automatically when
/* they fill up. The allocation strategy is such that there
/* will always be place for the terminating null character.
/*
-/* vs_alloc() allocates storage for a variable-length string.
+/* vs_alloc() allocates storage for a variable-length string
+/* of at least "len" bytes.
/*
/* VS_ADDCH() adds a character to a variable-length string
/* and automagically extends the string if fills up.
@@ -30,11 +36,19 @@
/* array; \fIch\fP the character value to be written.
/* Note that VS_ADDCH() is a macro that evaluates some
/* arguments more than once.
+/*
+/* vs_strcpy() appends a null-terminated string to a variable-length
+/* string. \fIsrc\fP provides the data to be copied; \fIvp\fP is the
+/* target, and \fIdst\fP the current write position within the target.
+/* The result is null-terminated. The return value is the new write
+/* position.
/* DIAGNOSTICS
/* VS_ADDCH() returns zero if it was unable to dynamically
/* resize a string.
/*
/* vs_alloc() returns a null pointer in case of problems.
+/*
+/* vs_strcpy() returns a null pointer if the request failed.
/* BUGS
/* Auto-resizing may change the address of the string data in
/* a vstring structure. Beware of dangling pointers.
@@ -44,12 +58,12 @@
/* Department of Mathematics and Computer Science
/* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
/* LAST MODIFICATION
-/* 91/09/22 21:21:38
+/* 92/01/15 21:53:06
/* VERSION/RELEASE
-/* 1.2
+/* 1.3
/*--*/
-static char vstring_sccsid[] = "@(#) vstring.c 1.2 91/09/22 21:21:38";
+static char vstring_sccsid[] = "@(#) vstring.c 1.3 92/01/15 21:53:06";
/* C library */
@@ -89,3 +103,20 @@ char *cp;
vp->last = vp->str + len - 1;
return (vp->str + where);
}
+
+/* vs_strcpy - copy string */
+
+char *vs_strcpy(vp, dst, src)
+register struct vstring *vp;
+register char *dst;
+register char *src;
+{
+ while (*src) {
+ if (VS_ADDCH(vp, dst, *src) == 0)
+ return (0);
+ src++;
+ }
+ *dst = '\0';
+ return (dst);
+}
+
diff --git a/unproto/vstring.h b/unproto/vstring.h
index ec02a6e..c2e1f88 100644
--- a/unproto/vstring.h
+++ b/unproto/vstring.h
@@ -1,4 +1,4 @@
-/* @(#) vstring.h 1.1 91/09/01 23:08:42 */
+/* @(#) vstring.h 1.2 92/01/15 21:53:19 */
struct vstring {
char *str; /* string value */
@@ -7,6 +7,7 @@ struct vstring {
extern struct vstring *vs_alloc(); /* initial allocation */
extern char *vs_realloc(); /* string extension */
+extern char *vs_strcpy(); /* copy string */
/* macro to add one character to auto-resized string */