pax_global_header00006660000000000000000000000064151145374660014526gustar00rootroot0000000000000052 comment=f00afb21b2036f12a5a64ba3f39b6094aeacddd1 cdrdao-cdrdao-f00afb2/000077500000000000000000000000001511453746600146765ustar00rootroot00000000000000cdrdao-cdrdao-f00afb2/.gitignore000066400000000000000000000002641511453746600166700ustar00rootroot00000000000000Makefile Makefile.in config.cache config.h config.h.in config.log config.status configure pccts scsilib stamp-h1 autom4te.cache aclocal.m4 *.Po *.o *.a *~ specs/cdrdao.fedora.spec cdrdao-cdrdao-f00afb2/AUTHORS000066400000000000000000000005441511453746600157510ustar00rootroot00000000000000Andreas Mueller : - project founder, initial implementation of cdrdao (no longer an active developer) Manuel Clos - author of gcdmaster GUI front-end Denis Leroy - project maintenance, Gtk2 port of gcdmaster Jonathan Simpson - toc2cue updates cdrdao-cdrdao-f00afb2/COPYING000066400000000000000000000430761511453746600157430ustar00rootroot00000000000000 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. Copyright (C) 19yy 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. , 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. cdrdao-cdrdao-f00afb2/CREDITS000066400000000000000000000024601511453746600157200ustar00rootroot00000000000000To: Heiko Eissfeldt For: Data sector L-EC encoding library 'libedc_ecc'. To: Yasuhito Futatsuki For: Maintaining the FreeBSD port. To: Max Khon For: Direct SCSI interface implementation for FreeBSD. To: Cameron G. MacKinnon For: Implementation of the yamaha-cdr10x driver. To: Monty For: cdda_paranoia library for high quality DAE. To: Piergiorgio Sartor For: SCSI manual for the Sony CDU948 recorder. Implementation of sub-channel scanning for catalog number. To: Henk-Jan Slotboom For: Implementation of the taiyo-yuden driver. To: Michael Weber For: First implementation of on-the-fly writing. To: Leon Woestenberg For: Bitwise correct audio extraction with Plextor drives. To: José Carlos Garcķa Sogo For: The --keepimage option. To: ITOH Yasufumi and Martin Buck For: BURN Proof support To: Michael Reinelt For: Help screen rework and multi session improvements To: Giuseppe "Cowo" Corbelli For: Support for Plextor specific options in plextor driver. To: Matthias Czapla For: The cue2toc utility To: Joe Drew For: mpg321 code used in MP3 decoder cdrdao-cdrdao-f00afb2/ChangeLog000066400000000000000000000620571511453746600164620ustar00rootroot00000000000000-------------------------------------------------------------------------- cdrdao 1.2.6 (2025-12-05) -------------------------------------------------------------------------- o Many bugfixes related to CD-TEXT processing (Rasheeq Azad, Denis Leroy) o Windows native interface support (Denis Leroy) o Several crash fixes (Ole Bertram, Denis Leroy, Jan Solanti) o Fixed version command (Daniel Foster) o iconv detection improvement and cross-OS support (DL) o Ejects CD to allow source medium insertion with copy command (dhucul) o Fix burning issue with gcdmaster (Sven Geuer) o Many typos fixes (Sven Geuer, Michael Ortmann) o *BSDs support fixes (Michael Ortmann, Benjamin Jacobs, DL) o Do retries for blank and discid commands (DL) -------------------------------------------------------------------------- cdrdao 1.2.5 (2023-02-03) -------------------------------------------------------------------------- o gcdmaster port to GTK 3 (Stefan Roellin) o Support to specify encoding in TOC (Denis Leroy): - one of ENCODING_ISO_8859_1, ENCODING_ASCII, ENCODING_MS_JIS, ENCODING_KOREAN, ENCODING_MANDARIN may be specified on LANGUAGE section. - TOC always dumped in UTF-8, unless --no-utf8 is specified o Fix --swap argument with generic-mmc-raw driver (Alex Free) o MacOS fixes (DL) o cdrdao: - new cdtext command to dump CD-TEXT disc content - deprecate 0x10 driver option by checking device configuration o toc2cue: (Jonathan Simpson) - add option to convert bin file, removing subchannel data that isn't supported by cue/bin files - add option to swap byte order when creating new bin file o toc2mp3: (DL) - -J option to force specific text decoding - support for character encoding in filenames and id3v2 tags o Fix eject by first issuing PREVENT ALLOW MEDIUM REMOVAL (DL) o Removed scsilib snapshot from old cdrecord project, only use native interface. RIP Jƶrg Schilling. o Misc compile and warning fixes for newer C++ compilers (Fedora) o MacOS compile fixes, upstreamed from brew o Cddb server updates. -------------------------------------------------------------------------- cdrdao 1.2.4 (2016-05-16) -------------------------------------------------------------------------- o Ported to lame 3.100 (from Fedora) o G++ compile fixes (Nick Bailey) o Renamed xdao folder to gcdmaster (Denis Leroy) o pccts format security patch (from Fedora) o Gcdmaster segfault fix (Adrian Knoth) o Prevent a FTBFS on kfreebsd (Christoph Egger) o Also look in /etc/default/cdrdao config (Andrew Suffield) o Fix printf format security issues (Frantisek Kluknavsky Fedora) o Add missing options to man page (Honza HorĆ”k) o CD_TEXT fix for HL-DT-ST (Kees Cook) o Man page hyphen fixes (Markus Koschany) o Some updates to the old scsilib smake files (Ubuntu patches) o Fixed compile issues with glibc >= 2.12 -------------------------------------------------------------------------- cdrdao 1.2.3 (2009-10-05) -------------------------------------------------------------------------- o By default, cdrdao tries to build with a native SCSI interface. Use "--with-libscg" to use bundled libscg library. (Denis Leroy) o Complete rewrite of native Linux SG driver for SG 3.0 using SG_IO ioctl. That should make it behave better with ConsoleKit based permissions environment. Cdrdao should now be compiled on Linux without cdrtools by using "--without-scglib". (Denis Leroy) o Added support for new FIRST_TRACK_NO keyword to allow a CD to start with a track number other than 1. (Edgar Fuss) o Added native interfaces for Irix, Mac OSX and NetBSD. (Edgar Fuss) o Fixed old pregap length off-by-one error, see bug #604751 (Thomas Vander Stichele) o Fixed bug in Toc file parser track length computation. (Denis Leroy) o Man page typo fixes. (Denis Leroy) o Cygwin compilation fixes. Other various compilation warning fixes. (Denis Leroy) o Some scsilib fixes for FreeBSD, 32-bit and 64-bit SPARC. (Marius Strobl) o Some makefile changes to avoid conflict with installed system libs. (Marius Strobl) o Added patch to fix ARM and MIPS scsilib compile (Kedar Sovani, Debian) o Added man pages for toc2cue and toc2cddb, from Debian. o Move privilege drop earlier in main flow (based on Debian patch) o Commited Gentoo patch for CD-TEXT track check fix (Grant, Peter Alfredsen) GCDMaster changes: o Preferences now stored in GConf, exports schema file (Denis Leroy) o Added simple Preferences dialog to change temporary file directory (Denis Leroy) o Fixed GCC 4.3 compilation issues (Denis Leroy) -------------------------------------------------------------------------- cdrdao 1.2.2 (2006-09-20) -------------------------------------------------------------------------- o Added device locking for win32 (Giuseppe Corbelli) o Man page cleanup (Andrew Suffield) GCDMaster changes: o Fixed GCC 4.1 compilation issues o Fixed hang when inserting WAV file -------------------------------------------------------------------------- cdrdao 1.2.1 (2005-10-28) -------------------------------------------------------------------------- o Fixed bad bug with missing return statemements in recomputeLength and format conversion. o Fixed broken '-' STDIN input feature. o Fixed various gcc4-related compile problems. o Fixed copy problem with single device when read_device is specified. o Added autodetect of cdrtools header files in configure o Minor fixes to driver table. o pccts build is now better integrated with automake/autoconf. o Added FreeBSD 7 support to configure.ac. Fixed libao dependency. GCDMaster changes: o The crash when creating a new "Create Audio CD" view seemed to be related to gtkmm and libsigc++ and went away with newer releases of those packages. toc2cue changes: o toc2cue: fixed bug that was causing empty output files. o Added conversion of COPY to DCP flags. (Julio Sanchez Fernandez) -------------------------------------------------------------------------- cdrdao 1.2.0 (2005-05-12) -------------------------------------------------------------------------- o SECURITY FIX: cdrdao now gives up its root privileges after setting up real-time scheduling, as well as before saving settings through the --save option. This fixes a potential local root exploit when cdrdao is installed with the +s chmod flag. Using --save now also forces an early exit after the settings are saved. o Added MP3 and Ogg Vorbis file support (through respectively the libmad and libvorbis libraries). cdrdao will decode the MP3 and Ogg files into temporary WAV files that will be deleted upon exit (unless the new option --keep is used). The directory used to store those temporary WAV files can be specified with the --tmpdir option (default is /tmp). o Improved native CUE file support: replaced old incomplete existing parser with the one from Matthias Czapla's excellent cue2toc. Added support for cutting binary files. o Added --rspeed option to manually set the device reading speed. Be warned not all devices support this. o Packaged scsilib library upgraded from cdrtools 2.01 (previously was from 2.01a31). o Added --no-mode2-mixed option. Don't read a MODE2 disk as MODE2_FORM_MIXED, only read MODE2_FORM1 or MODE2_FORM2 (Matthieu Castet). o Added help for little-known drive-info command. GCDMaster changes: o MP3 and Ogg Vorbis support: you can drag and drop .mp3, .m3u and .ogg files from Nautilus into the sample display window. o Switched to gtkmm24 API. Improved file browsers. o CUE files support. o Sound output now uses libao library. o Added 'Select All' item in menu. o Added 'Eject' button to progress dialog o Bug fixes (sample selection weirdness, couldn't close window during play, problems with gcdmaster command-line argument, crashes with multiple project windows, drive status not reported correctly). -------------------------------------------------------------------------- cdrdao 1.1.9 (2004-06-07) -------------------------------------------------------------------------- o MMC-driver auto-detection. If no --driver option is specified, cdrdao will try to autodetect an MMC-compliant device and use the generic-mmc driver by default. (Denis Leroy) o Included scsilib upgraded from cdrtools 2.01a31 (Denis Leroy) o Added --eject option to the unlock command to eject the cd after unlocking. (Eric Benson) o New 'discid' command to display CDDB information. (Eric Benson, Denis Leroy). o Fixed scsilib compiling problems with Linux kernel 2.6 (Jim Gifford) o Fixed compiling problems with gcc 3.4 (Jim Gifford, Denis Leroy) o Added --full-burn and --capacity options to extend lead-out to entire disc, beyond 80 mins limit. (Vladimir Petrov) GCDMaster changes (Denis Leroy): o Device configuration dialog now scans for devices on both ATA and ATAPI interfaces. o Some bug fixes (manual driver configurations were not being saved correctly). cue2toc changes: o Version 0.2 released. Complete rewrite, should now handle most of all CUE files. (Matthias Czapla) -------------------------------------------------------------------------- cdrdao 1.1.8 (2004-02-12) -------------------------------------------------------------------------- o We have not heard from project founder and maintainer Andreas Mueller for a long time and do not know what his intentions are regarding cdrdao. Due to recent contributions to the project, we have decided to nonetheless continue development and to keep working towards future releases. Manuel Clos is now acting as project maintainer. We hope to hear from Andreas soon. o The latest state of the CVS tree before the merge with the Gnome2/Gtk2 branch has been tagged as 'Andreas_1_1_7'. o Improved performance of the new L-EC code by up to a factor 2 depending on the hardware. o 'read-test' runs L-EC encoder over mode 1 or mode 2 form 1 sectors to allow performance testing in conjunction with option --speed. o Fix for building on Mac OS X with gcc-3.1 (SF patch 611423). o Support for ATAPI drives: device is now specified as [path:], such as '--device 0,0,0' or '--device ATAPI:0,1,0'. If you run Linux 2.6, you can also use the latest /dev/hd* interface with '--device ATA:0,0,0' (Denis Leroy) GCDMaster changes (Denis Leroy): o gcdmaster was ported to Gnome2/Gtk+2 using the new C++ Gtk2 bindings (gtkmm2 and gnomeuimm2). o ATAPI drives support: gcdmaster will also scan for ATAPI devices. Devices are now specified as a '[path:]x,y,z' string. o The samples selection can now be cleared (i.e. unselected) by single-clicking the Audio view during Select mode (not in Zoom mode). o You can now select multiple files from the file selector when appending or inserting tracks/files from the main Audio Project menu. o Some features have been removed (temporarily): the multiple views feature, the 'zoom to selection' icon. Also the progress dialog is gone during import: progress is shown on the main status bar. mp32dao changes: o FLAC support. mp32dao now handles mp3/ogg/flac files. (Giuseppe Corbelli) o new: toc2cddb: translates a TOC file into a cddb file. (Giuseppe Corbelli) o new: cue2toc: convert CUE to TOC format for audio CDs. (Matthias Czapla) -------------------------------------------------------------------------- cdrdao 1.1.7 (2002-10-06) -------------------------------------------------------------------------- o Fixed crash in toc-file reader (only occurred for a certain type of syntactical error). o Fixed compilation problems of "toc2mp3.cc" with pre gcc-3.x compilers. o Updated driver table. -------------------------------------------------------------------------- cdrdao 1.1.6 (2002-09-16) -------------------------------------------------------------------------- o Fixed cue sheet setup for CD-TEXT writing. Some older drives did not like the cue sheet format as specified in the latest SCSI-3/mmc specification. o Added sub-channel writing for the 'generic-mmc' and 'generic-mmc-raw' driver. Currently only the R-W sub-channels can be written. The track image files may contain packed or raw R-W sub-channel data. For packed sub-channel data the L-EC data will be calculated and interleaving will be performed if required by the recording hardware. o Added sub-channel reading support for the generic-mmc(-raw) driver. Currently packed and raw R-W sub-channel reading is supported (option -read-subchan). o Added automatic check for support sub-channel reading modes to the 'generic-mmc(-raw)' driver. The driver options (0x1, 0x2 and 0x20) should be obsolete now, but are still available. o The data track extraction with the generic-mmc(-raw) driver is more robust against read errors now. The --tao-source/--tao-source-adjust option should be obsolete now - but is still available. o Added on-the-fly copying support for the Win32 version. o Default blanking mode is now 'minimal' (SF feature request 425321) o Updated paranoia libraries to version of cdparanoia-III-alpha9.8. o Fixed waiting loop that was used to wait until the lead-out was written and until a blanking operation is finished. Some drives do not indicate this activities with a "not ready" status. Affected drivers: generic-mmc and generic-mmc-raw (blanking only). o Fixed crash in cdrdao usage printing (SF bug 570156). o Fixed cue sheet setup for ISRC codes for the HP8100 recorder model. o Added/fixed SF patches 427753, 450058 and 534214. o New mp32dao version from Giuseppe Corbelli with these new features: - Ogg support - MP3/Ogg decoding supported only with external programs - Code modularization and bugfixes - cdrecord's .inf file support for CD-TEXT data o Cue parser accepts spaces and '\' characters in file name now. o The PCCTS package is now a part of the cdrdao source code distribution which should avoid some compilation hassle. o Updated scsilib version. o Added patches for compilation under Unixware (incl. patches for scsilib). o Created new utility 'toc2mp3' that converts an audio CD image to a set of mp3 files using the LAME encoder. The encoded mp3 files have no gap at the end so that they play in sequence without noise at the transition points. GCDMaster changes: o Gcdmaster hotkeys are now back. (SourceForge bug 470864). o Gcdmaster can now copy cds with just one drive, thanks to Das Poelzi for the patch. (SourceForge bug 566948). o Added switch to enable the overburn mode to the recording options box. o Added selection of the sub-channel reading mode the CD extraction options box. o Fixed the 'Cancel' button staying disabled in the Recording/Reading progress window. -------------------------------------------------------------------------- cdrdao 1.1.5 (2001-04-29) -------------------------------------------------------------------------- o Fixed bug in CD-TEXT writing code that caused the problems with the unreliable read back of the written CD-TEXT data o Added CD-TEXT writing capability to the 'generic-mmc-raw' driver; the recorder must support the 96 byte raw P-W sub-channel writing mode to make use of it o Fixed bug in generic-mmc-raw driver: the TOC type was not written correctly and some flags for data tracks were missing in the lead-in o Fixed handling of toc type for multi session CDs: the toc-type of a session that just contains audio tracks is always CD_DA, even in multi session mode o BURN Proof support added by ITOH Yasufumi/Martin Buck o Fixed bug in calculating the CDDB id (SourceForge bug 413467) o Added option --with-cddb to read CDDB data automatically with commands 'copy', 'read-toc' and 'read-cd'; it is now possible to add CD-TEXT data from CDDB while performing an on-the-fly copy o Updated to libscg-0.5 from cdrtools-1.10 o Handle drives that do not support the explicit power calibration command o Blanking of CD-RWs is now officially supported (command 'blank', option --blank-mode) o Updated CD-R vendor table o Settings are now first read from "/etc/cdrdao.conf" and "/etc/defaults/cdrdao" and then from "$HOME/.cdrdao" o Added command 'msinfo' to output multi session information suitable for 'mkisofs' o Overburning is now prevented by default and must be explicitly requested with option '--overburn'. Fix for Debian bug #79585 (http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=79585&repeatmerged=yes). o Fixed error in cdrdao's manual page (Debian bug #82816, http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=82816&repeatmerged=yes) o cdrdao's help screen was reworked by Michael Reinelt o Added Giuseppe Corbelli's enhancements for the 'mp32dao' script o Makefiles now use make variable 'datadir' to specify the share directory location o Fixed printing toc-file name with command 'copy --keepimage' GCDMaster changes: o Added missing 'toshiba' driver to the device configuration dialog (SourceForge bug 128633) o Removed the CD-TEXT table entry dialog from the 'Project Info' dialog; it is now a non modal dialog on its own o Enhanced progress display for extracting and recording o Major rework of the infra structure to support multiple projects (toc-files) and multiple views of a project o Gcdmaster starts with a project chooser now; this is the first step to support different project types like data CD, mixed mode CD, video CD etc. -------------------------------------------------------------------------- cdrdao 1.1.4 (2000-08-27) -------------------------------------------------------------------------- o Created new 'toshiba' driver for 'read-toc'/'read-cd' with Toshiba CD-ROM drives. o Added full multi session support to the 'cdd2600' driver. o CD-TEXT is written without any copy protection flags now. o Added CDDB access to add title and artist data as CD-TEXT to an existing toc-file. The direct cddbp and the http encapsulated protocol is supported. o Added support to better handle disks written in track-at-once mode with 'read-cd' and 'read-toc' (see options --tao-source and --tao-source-adjust). o Fixed bug that prevented recording of pure data CDs with the recent HP and Sony recorder models in single session mode. For multi session mode the restrictions mentioned in the README are still valid. o Fixed 'unit not ready' problems after writing with the 'generic-mmc' and 'generic-mmc-raw' driver. o Toc-files with tracks that are shorter than 4 seconds will be recorded if option '--force' is given. o Some of the command line options are now saved to a settings file "$HOME/.cdrdao" if option '--save' is given. o The driver database is now kept in an external file so it is possible to update the database between the cdrdao releases. Actual driver database files will be available from http://cdrdao.sourceforge.net/drives.html#dt o Added new option '--keepimage' which keeps the created image file after the command 'copy' finishes. o Fixed bug in CD-TEXT reading code: CD-TEXT fields with empty strings were only read for the first track. o Driver 'generic-mmc': If the power calibration fails the recording process will be aborted now. o Driver 'generic-mmc-raw': Added explicit power calibration. Xcdrdao changes: o Xcdrdao is now a Gnome application and will be called "Gnome CD Master" (gcdmaster) in future. o Added table wise entry of CD-TEXT title/performer data. o Added a dialog to extract a CD to the hard disk. o Added a dialog to do CD to CD copy, with "on the fly" as an option. o Speed and record buffer are now selectable in the GUI. o When reading/duplicating a CD you can set the paranoia mode. -------------------------------------------------------------------------- cdrdao 1.1.3 -------------------------------------------------------------------------- o Data track writing is available with all drivers, especially the 'ricoh-mp6200' and 'generic-mmc-raw' can write data tracks now. o Added DAE capability based on Monty's paranoia library to all drivers. The 'plextor' driver will still use the special Plextor method for DAE with Plextor drives but it is possible to force using the paranoia mode with a driver option (see README). The paranoia mode can customized with option '--paranoia-mode #'. Please read section 'Digital Audio Extraction' of the README. o 'read-cd' creates now a complete image of a session. All tracks are written to a single image file (comparable to a .bin file). Pre-gaps and index marks of audio tracks are extracted while ripping the audio data so that a 'read-toc' step is obsolete now. It may choke on CDs written in TAO mode. o Experimental: Added a 'copy' command that performs all steps for copying a CD session with a single or two drives. By default a temporary image file is created in the current working directory. On the fly copying can be selected with option '--on-the-fly' which avoids the temporary image file. Copying of mixed mode CDs should be fine. I expect problems with source CDs written in TAO mode but I did not make any tests up to now. On the fly copying is not available for the Win32 platform, yet. Please read section 'Example for CD Copying' of the README. o 'read-cd' ignores sectors with L-EC errors now if option '--read-raw' is given. The 'cdd2600', 'ricoh-mp6200' and 'generic-mmc-raw' driver will recreate the erroneous sectors when recording. o Added full multi session support to the 'teac-cdr55' driver. o Added multiple language support for CD-TEXT. However, I have currently no access to a CD-TEXT capable consumer CD-player so I am not sure if CD-TEXT recording still works. Reading the written CD-TEXT data with a CD-ROM drive gives the expected results. o ATAPI CD-ROM drives that were only working with the 'plextor' driver should now be supported by the 'generic-mmc' driver with driver option 0x20 (--driver generic-mmc:0x20). o A CD-R medium is automatically ejected now before writing to reset the disk status after a simulation run which is necessary e.g. for the Philips CDD2x00 recorder family. Xcdrdao changes: o Added dialogs for entering meta data like UPC/EAN, ISRC code and CD-TEXT. o It is now possible to insert and remove samples at any place without touching the audio files on the disk. o Added a dialog for configuration of all available CD-ROM/CD-R devices. o Recording can now be started from the GUI. Simultaneous recording with multiple CD-recorders is possible if the hardware is suitable for it. o Created a man page. -------------------------------------------------------------------------- cdrdao 1.1.2 -------------------------------------------------------------------------- o Added support for bin/cue images. A cue file can be used now wherever a toc-file is expected. The cue file must have exactly one FILE statement. The bin file name is constructed from the cue file name by replacing ".cue" with ".bin". Currently supported track modes: MODE1/2048, MODE1/2352, MODE2/2336, MODE2/2352. The 'cdd2600' driver uses the L-EC data contained in the MODEX/2352 track images when recording. All other drivers will ignore and regenerate the L-EC data. o The 'generic-mmc' driver has full multi session support now. The start address of the last and current session which must be used for the mkisofs option '-C x,y' can be retrieved with 'disk-info'. s o The 'sony-cdu948' driver is included in the source package. o read-cd will create raw data track images (2352 byte sectors) if option '--read-raw' is given. -------------------------------------------------------------------------- cdrdao 1.1.0 -------------------------------------------------------------------------- o Added data track support to 'generic-mmc' driver. o Added Henk-Jan Slotboom's driver for Taiyo-Yuden recorders. o Created driver for the Teac CD-R55S recorder. Data tracks should be supported, too, but it is not well tested. o Added Cam MacKinnon's driver for the Yamaha CDR10x drive family. Data track support is available, too, but also not well tested. o Added Leon Woestenberg's bitwise-exact digital audio extraction patch for Plextor drives (see README.PlexDAE). o 'read-toc' will analyze mixed mode CDs now, but it is currently not perfect. Please have a look at the README. o Fixed failed assertion problems with 'read-toc' that occured when the raw P-W sub-channel data passed the CRC check but was actually not consistent (happened quiet often with Teac CD-ROM CD-532S drives). o The SCSI interface can now use Joerg Schilling's SCSI library. Cdrdao is reported to work on Solaris 2.6 and FreeBSD using the SCSI library. Max Khon provided an independent SCSI interface implementation for FreeBSD which can be selected when configuring. o Added experimental CD-TEXT support to 'read-toc'. o Updated xcdrdao source to compile with Gtk-- 0.99.1. Known Limitations: o 'read-toc' does not work for multi session CDs. o 'read-toc' does not work well for CDs written in TAO mode. cdrdao-cdrdao-f00afb2/INSTALL000066400000000000000000000406701511453746600157360ustar00rootroot00000000000000Installation Instructions ************************* Build Dependencies ================== Mandatory: - a C++14 compiler - iconv (for UTF-8 conversion) Optional: - gtkmm3 (for gcdmaster) - libao (for gcdmaster) - libvorbis (for ogg/vorbis decoding support) - libmad (for MP3 decoding support) - lame library (for toc2mp3) Supported OSes ============== - Most Linux distributions - MacOS - Windows 10 and 11 using Cygwin or MSYS2 - *BSDs (but not heavily tested) Basic Installation ================== The following shell commands: test -f configure || ./autogen.sh ./configure make make install should configure, build, and install this package. The first line, which bootstraps, is intended for developers; when building from distribution tarballs it does nothing and can be skipped. The following more-detailed instructions are generic; see the ā€˜README’ file for instructions specific to this package. Some packages provide this ā€˜INSTALL’ file but do not implement all of the features documented below. The lack of an optional feature in a given package is not necessarily a bug. More recommendations for GNU packages can be found in the GNU Coding Standards. Many packages have scripts meant for developers instead of ordinary builders, as they may use developer tools that are less commonly installed, or they may access the network, which has privacy implications. If the ā€˜bootstrap’ shell script exists, it attempts to build the ā€˜configure’ shell script and related files, possibly using developer tools or the network. Because the output of ā€˜bootstrap’ is system-independent, it is normally run by a package developer so that its output can be put into the distribution tarball and ordinary builders and users need not run ā€˜bootstrap’. Some packages have commands like ā€˜./autopull.sh’ and ā€˜./autogen.sh’ that you can run instead of ā€˜./bootstrap’, for more fine-grained control over bootstrapping. The ā€˜configure’ shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a ā€˜Makefile’ in each directory of the package. It may also create one or more ā€˜.h’ files containing system-dependent definitions. Finally, it creates a shell script ā€˜config.status’ that you can run in the future to recreate the current configuration, and a file ā€˜config.log’ containing output useful for debugging ā€˜configure’. It can also use an optional file (typically called ā€˜config.cache’ and enabled with ā€˜--cache-file=config.cache’ or simply ā€˜-C’) that saves the results of its tests to speed up reconfiguring. Caching is disabled by default to prevent problems with accidental use of stale cache files. If you need to do unusual things to compile the package, please try to figure out how ā€˜configure’ could check whether to do them, and mail diffs or instructions to the address given in the ā€˜README’ so they can be considered for the next release. If you are using the cache, and at some point ā€˜config.cache’ contains results you don’t want to keep, you may remove or edit it. The ā€˜autoconf’ program generates ā€˜configure’ from the file ā€˜configure.ac’. Normally you should edit ā€˜configure.ac’ instead of editing ā€˜configure’ directly. The simplest way to compile this package is: 1. ā€˜cd’ to the directory containing the package’s source code. 2. If this is a developer checkout and file ā€˜configure’ does not yet exist, type ā€˜./bootstrap’ to create it. You may need special developer tools and network access to bootstrap, and the network access may have privacy implications. 3. Type ā€˜./configure’ to configure the package for your system. This might take a while. While running, ā€˜configure’ prints messages telling which features it is checking for. 4. Type ā€˜make’ to compile the package. 5. Optionally, type ā€˜make check’ to run any self-tests that come with the package, generally using the just-built uninstalled binaries. 6. Type ā€˜make install’ to install the programs and any data files and documentation. When installing into a prefix owned by root, it is recommended that the package be configured and built as a regular user, and only the ā€˜make install’ phase executed with root privileges. 7. Optionally, type ā€˜make installcheck’ to repeat any self-tests, but this time using the binaries in their final installed location. This target does not install anything. Running this target as a regular user, particularly if the prior ā€˜make install’ required root privileges, verifies that the installation completed correctly. 8. You can remove the program binaries and object files from the source code directory by typing ā€˜make clean’. To also remove the files that ā€˜configure’ created (so you can compile the package for a different kind of computer), type ā€˜make distclean’. There is also a ā€˜make maintainer-clean’ target, but that is intended mainly for the package’s developers. If you use it, you may have to bootstrap again. 9. If the package follows the GNU Coding Standards, you can type ā€˜make uninstall’ to remove the installed files. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the ā€˜configure’ script does not know about. Run ā€˜./configure --help’ for details on some of the pertinent environment variables. You can give ā€˜configure’ initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=gcc CFLAGS=-g LIBS=-lposix See ā€œDefining Variablesā€ for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each system in their own directory. To do this, you can use GNU ā€˜make’. ā€˜cd’ to the directory where you want the object files and executables to go and run the ā€˜configure’ script. ā€˜configure’ automatically checks for the source code in the directory that ā€˜configure’ is in and in ā€˜..’. This is known as a ā€œVPATHā€ build. With a non-GNU ā€˜make’, it is safer to compile the package for one system at a time in the source code directory. After you have installed the package for one system, use ā€˜make distclean’ before reconfiguring for another system. Some platforms, notably macOS, support ā€œfatā€ or ā€œuniversalā€ binaries, where a single binary can execute on different architectures. On these platforms you can configure and compile just once, with options specific to that platform. Installation Names ================== By default, ā€˜make install’ installs the package’s commands under ā€˜/usr/local/bin’, include files under ā€˜/usr/local/include’, etc. You can specify an installation prefix other than ā€˜/usr/local’ by giving ā€˜configure’ the option ā€˜--prefix=PREFIX’, where PREFIX must be an absolute file name. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you pass the option ā€˜--exec-prefix=PREFIX’ to ā€˜configure’, the package uses PREFIX as the prefix for installing programs and libraries. Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like ā€˜--bindir=DIR’ to specify different values for particular kinds of files. Run ā€˜configure --help’ for a list of the directories you can set and what kinds of files go in them. In general, the default for these options is expressed in terms of ā€˜${prefix}’, so that specifying just ā€˜--prefix’ will affect all of the other directory specifications that were not explicitly provided. The most portable way to affect installation locations is to pass the correct locations to ā€˜configure’; however, many packages provide one or both of the following shortcuts of passing variable assignments to the ā€˜make install’ command line to change installation locations without having to reconfigure or recompile. The first method involves providing an override variable for each affected directory. For example, ā€˜make install prefix=/alternate/directory’ will choose an alternate location for all directory configuration variables that were expressed in terms of ā€˜${prefix}’. Any directories that were specified during ā€˜configure’, but not in terms of ā€˜${prefix}’, must each be overridden at install time for the entire installation to be relocated. The approach of makefile variable overrides for each directory variable is required by the GNU Coding Standards, and ideally causes no recompilation. However, some platforms have known limitations with the semantics of shared libraries that end up requiring recompilation when using this method, particularly noticeable in packages that use GNU Libtool. The second method involves providing the ā€˜DESTDIR’ variable. For example, ā€˜make install DESTDIR=/alternate/directory’ will prepend ā€˜/alternate/directory’ before all installation names. The approach of ā€˜DESTDIR’ overrides is not required by the GNU Coding Standards, and does not work on platforms that have drive letters. On the other hand, it does better at avoiding recompilation issues, and works well even when some directory options were not specified in terms of ā€˜${prefix}’ at ā€˜configure’ time. Optional Features ================= If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving ā€˜configure’ the option ā€˜--program-prefix=PREFIX’ or ā€˜--program-suffix=SUFFIX’. Some packages pay attention to ā€˜--enable-FEATURE’ and ā€˜--disable-FEATURE’ options to ā€˜configure’, where FEATURE indicates an optional part of the package. They may also pay attention to ā€˜--with-PACKAGE’ and ā€˜--without-PACKAGE’ options, where PACKAGE is something like ā€˜gnu-ld’. ā€˜./configure --help’ should mention the ā€˜--enable-...’ and ā€˜--with-...’ options that the package recognizes. Some packages offer the ability to configure how verbose the execution of ā€˜make’ will be. For these packages, running ā€˜./configure --enable-silent-rules’ sets the default to minimal output, which can be overridden with ā€˜make V=1’; while running ā€˜./configure --disable-silent-rules’ sets the default to verbose, which can be overridden with ā€˜make V=0’. Specifying a System Type ======================== By default ā€˜configure’ builds for the current system. To create binaries that can run on a different system type, specify a ā€˜--host=TYPE’ option along with compiler variables that specify how to generate object code for TYPE. For example, to create binaries intended to run on a 64-bit ARM processor: ./configure --host=aarch64-linux-gnu \ CC=aarch64-linux-gnu-gcc \ CXX=aarch64-linux-gnu-g++ If done on a machine that can execute these binaries (e.g., via ā€˜qemu-aarch64’, ā€˜$QEMU_LD_PREFIX’, and Linux’s ā€˜binfmt_misc’ capability), the build behaves like a native build. Otherwise it is a cross-build: ā€˜configure’ will make cross-compilation guesses instead of running test programs, and ā€˜make check’ will not work. A system type can either be a short name like ā€˜mingw64’, or a canonical name like ā€˜x86_64-pc-linux-gnu’. Canonical names have the form CPU-COMPANY-SYSTEM where SYSTEM is either OS or KERNEL-OS. To canonicalize and validate a system type, you can run the command ā€˜config.sub’, which is often squirreled away in a subdirectory like ā€˜build-aux’. For example: $ build-aux/config.sub arm64-linux aarch64-unknown-linux-gnu $ build-aux/config.sub riscv-lnx Invalid configuration 'riscv-lnx': OS 'lnx' not recognized You can look at the ā€˜config.sub’ file to see which types are recognized. If the file is absent, this package does not need the system type. If ā€˜configure’ fails with the diagnostic ā€œcannot guess build typeā€. ā€˜config.sub’ did not recognize your system’s type. In this case, first fetch the newest versions of these files from the GNU config package (https://savannah.gnu.org/projects/config). If that fixes things, please report it to the maintainers of the package containing ā€˜configure’. Otherwise, you can try the configure option ā€˜--build=TYPE’ where TYPE comes close to your system type; also, please report the problem to . For more details about configuring system types, see the Autoconf documentation. Sharing Defaults ================ If you want to set default values for ā€˜configure’ scripts to share, you can create a site shell script called ā€˜config.site’ that gives default values for variables like ā€˜CC’, ā€˜cache_file’, and ā€˜prefix’. ā€˜configure’ looks for ā€˜PREFIX/share/config.site’ if it exists, then ā€˜PREFIX/etc/config.site’ if it exists. Or, you can set the ā€˜CONFIG_SITE’ environment variable to the location of the site script. A warning: not all ā€˜configure’ scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to ā€˜configure’. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the ā€˜configure’ command line, using ā€˜VAR=value’. For example: ./configure CC=/usr/local2/bin/gcc causes the specified ā€˜gcc’ to be used as the C compiler (unless it is overridden in the site shell script). Unfortunately, this technique does not work for ā€˜CONFIG_SHELL’ due to an Autoconf limitation. Until the limitation is lifted, you can use this workaround: CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash ā€˜configure’ Invocation ====================== ā€˜configure’ recognizes the following options to control how it operates. ā€˜--help’ ā€˜-h’ Print a summary of all of the options to ā€˜configure’, and exit. ā€˜--help=short’ ā€˜--help=recursive’ Print a summary of the options unique to this package’s ā€˜configure’, and exit. The ā€˜short’ variant lists options used only in the top level, while the ā€˜recursive’ variant lists options also present in any nested packages. ā€˜--version’ ā€˜-V’ Print the version of Autoconf used to generate the ā€˜configure’ script, and exit. ā€˜--cache-file=FILE’ Enable the cache: use and save the results of the tests in FILE, traditionally ā€˜config.cache’. FILE defaults to ā€˜/dev/null’ to disable caching. ā€˜--config-cache’ ā€˜-C’ Alias for ā€˜--cache-file=config.cache’. ā€˜--srcdir=DIR’ Look for the package’s source code in directory DIR. Usually ā€˜configure’ can determine that directory automatically. ā€˜--prefix=DIR’ Use DIR as the installation prefix. See ā€œInstallation Namesā€ for more details, including other options available for fine-tuning the installation locations. ā€˜--host=TYPE’ Build binaries for system TYPE. See ā€œSpecifying a System Typeā€. ā€˜--enable-FEATURE’ ā€˜--disable-FEATURE’ Enable or disable the optional FEATURE. See ā€œOptional Featuresā€. ā€˜--with-PACKAGE’ ā€˜--without-PACKAGE’ Use or omit PACKAGE when building. See ā€œOptional Featuresā€. ā€˜--quiet’ ā€˜--silent’ ā€˜-q’ Do not print messages saying which checks are being made. To suppress all normal output, redirect it to ā€˜/dev/null’ (any error messages will still be shown). ā€˜--no-create’ ā€˜-n’ Run the configure checks, but stop before creating any output files. ā€˜configure’ also recognizes several environment variables, and accepts some other, less widely useful, options. Run ā€˜configure --help’ for more details. Copyright notice ================ Copyright Ā© 1994–1996, 1999–2002, 2004–2017, 2020–2024 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without warranty of any kind. cdrdao-cdrdao-f00afb2/Makefile.am000066400000000000000000000010461511453746600167330ustar00rootroot00000000000000ACLOCAL_AMFLAGS = -I m4 if COND_GCDMASTER MAYBE_GCDMASTER = gcdmaster else MAYBE_GCDMASTER = endif if COND_PCCTS MAYBE_PCCTS = pccts else MAYBE_PCCTS = endif SUBDIRS = $(MAYBE_PCCTS) trackdb utils paranoia dao $(MAYBE_GCDMASTER) DIST_SUBDIRS = trackdb utils paranoia dao gcdmaster pccts EXTRA_DIST = \ AUTHORS \ ChangeLog \ COPYING \ CREDITS \ INSTALL \ NEWS \ README \ README.PlexDAE \ README.Win32 \ specs/*.in \ aspi.reg \ cdrdao.lsm \ testtocs/*.toc \ contrib dist-hook: rm -rf `find $(distdir)/contrib -name CVS` cdrdao-cdrdao-f00afb2/NEWS000066400000000000000000000000001511453746600153630ustar00rootroot00000000000000cdrdao-cdrdao-f00afb2/README000066400000000000000000001326521511453746600155670ustar00rootroot00000000000000Cdrdao - Write audio/data CD-Rs in disk-at-once mode ============================================================================= This file contains some additional information. See the manual page for usage of the tool. Please use the write simulation mode (command 'simulate') when trying this program the first time on your system. This will detect problems or incompatibilities without wasting a CD-recordable. Note that you may have to eject and reinsert the CD-R after a simulation run before a real write can start. Sources of Information --------------------- Cdrdao Homepage: http://cdrdao.sourceforge.net/ Download: https://github.com/cdrdao/cdrdao/ Mailing Lists: cdrdao-info@lists.sourceforge.net Moderated list for informing about new releases or serious bugs. For subscribing information send an email with 'help' in the body to or visit the info page http://lists.sourceforge.net/mailman/listinfo/cdrdao-info. cdrdao-devel@lists.sourceforge.net Open lists for discussion about problems, implementation of new features etc. For subscribing information send an email with 'help' in the body to or visit the info page http://lists.sourceforge.net/mailman/listinfo/cdrdao-devel. Please report bugs and suggestions to https://github.com/cdrdao/cdrdao/ Drivers ------- The following driver IDs may be used with option '--driver'. It is possible to specify option bits which modify the behavior of the driver. Global and driver specific options are available. Options flags can be combined by logical 'or' and appended to the '--driver' option, e.g. '--driver plextor-scan:0x03'. By default, cdrdao will try to detect if your device is MMC compliant and use the 'generic-mmc' driver is possible. Global Option Bits: read-toc/read-cd related: 0x00010000: Use the generic method to read the TOC of a CD for commands 'read-toc' and 'read-cd'. If this flag is selected multi session disks will not be handled properly but some drives do not work with the currently implemented method for reading the TOC of a specific session. 0x00020000: If the byte order of the audio data retrieved with 'read-cd' is wrong (i.e. not big endian samples) use this option. 0x00040000: Use this option if your drive cannot read audio data from the first track's pre-gap. You will get read error messages in this case which should vanish if this option is used. 0x00080000: Suppresses the automatic data type detection for the raw TOC data and assumes that the drive sends BCD data. Use this or the following option if cdrdao reports that it cannot "determine if raw toc data is BCD or HEX". 0x00100000: Suppresses the automatic data type detection for the raw TOC data and assumes that the drive sends HEX data. Use this or the previous option if cdrdao reports that it cannot "determine if raw toc data is BCD or HEX". 0x00200000: Do not try to read CD-TEXT data with command 'read-toc', 'read-cd' or 'copy'. Some drives lock up or send junk data when asked for the CD-TEXT data. Available Drivers: plextor Supports CD structure analysis (command 'read-toc') for Plextor CD-ROM readers. Pre-gaps and index marks are detected by performing a binary search over the Q sub-channel for each track. This method is fast and gives very exact results on Plextor drives. The driver uses generic SCSI commands (PLAY AUDIO and READ SUB-CHANNEL) so it may work on other models, too, but result and speed is directly correlated to the digital audio extraction capabilities. Option Bits: read-toc/read-cd related: 0x00000001: Force usage of the paranoia method for audio extraction instead of the special Plextor method that is used with Plextor drives. 0x00000002: Use the READ10 command to read audio data instead of the vendor specific READ CDDA command. Only used if the paranoia DAE method is selected. 0x00000010: Don't slow down after a read error. Available only on Plextor devices. Manufacturer default is to slow down. 0x00000020: Start data transfer before maximum speed is reached. Available only on Plextor PX-20 and later. Manufacturer default is to wait for maximum speed. 0x00000040: Don't slow down when drive pauses to avoid vibrations. Available only on Plextor PX-20 and later. Manufacturer default is to slow down. plextor-scan This is an alternate driver for CD structure analysis with Plextor drives. It scans the Q sub-channels of a track linearly like the 'generic-mmc' driver but is faster on Plextor drives. Option Bits: read-toc/read-cd related: 0x00000001: Read 16 bytes PQ sub-channel instead of 96 byte raw P-W sub-channel data. If 'read-toc'/'read-cd' fails on your drive try to select this option. 0x00000002: Only used if option '0x00000001' is selected. If set the read PQ sub-channel data is expected to contain BCD instead of HEX values. If the time count that is displayed while running 'read-toc' jumps you will have to toggle this option. 0x00000004: Do not take ISRC code from the sub-channel data but use the appropriate SCSI command for reading the ISRC code. This option is automatically selected if 16 byte PQ sub-channel data with HEX values is used. cdd2600 This is a native driver for the Philips CDD2000/CDD2600 drive family. 'read-toc' is implemented like in the 'plextor' driver but it is slow and not very exact due to poor digital audio extraction capabilities of these drives. Anyway, I don't recommend doing CD structure analysis with the CDD2x00 because it stresses the mechanism too much. generic-mmc This is a driver for SCSI-3/mmc compatible CD-recorders that support session-at-once (cue sheet based) writing. Most of the recent drives (ATAPI, SCSI, USB, Parallel Port) should be compatible with this or with the 'generic-mmc-raw' driver described below. Data track writing support is also available. 'read-toc' scans linearly the Q sub-channel of each track to retrieve the pre-gap length and index marks. This method is very accurate but takes the same time like digital audio extraction. It should also work with recent CD-ROM readers. Option Bits: read-toc/read-cd related: 0x00000001: See 'plextor-scan'. 0x00000002: See 'plextor-scan'. 0x00000004: See 'plextor-scan'. 0x00000008: Try to retrieve the media catalog number by scanning the sub-channels instead of using the appropriate SCSI command. This might be an option if the CD-R/CD-ROM drive does not extract the catalog number otherwise. Note: A media catalog number need not be present on on a CD. 0x00000020: Use this option if the drive cannot read sub-channel data along with audio data. A binary search method for pre-gap and index mark extraction will be selected in this case which has to play a sector before the sub-channel data can be retrieved. If 'read-toc'/'read-cd' works only with this option you should consider to use '--fast-toc' since the data retrieved with the binary search method is usually not very reliable and not worth the additional time. 0x00000100: Force using the raw R-W sub-channel reading mode for audio and data tracks. writing related: 0x00000010: Enable CD-TEXT writing. This is no longer necessary and is now auto-detected. This option can be forced off by using --driver generic-mmc:0x00. 0x00000040: Suppresses the activation of the BURN Proof feature. 0x00000080: If the drive does not support packed R-W sub-channel writing (the drive does not support the L-EC data creation and interleaving for R-W sub-channel data) you will have to specify this option. Cdrdao will perform all the encoding and write in raw R-W mode. If the drive does not support the raw R-W writing mode, too, it is not possible to write sub-channel data. generic-mmc-raw This is an alternate driver for SCSI-3/mmc compatible CD-recorders. It uses the raw writing interface where the driver has to provide the PQ sub-channel data in addition to the audio data. This writing mode allows using part of the lead-out area for audio data since the drive's firmware has no chance to prevent this. Of course, you will get some error message at the end of writing when the CD-R capacity is exhausted. Multi session recording is currently not supported. CD structure analysis is done like in the 'generic-mmc' driver. Option Bits: All of 'generic-mmc' except 0x00000010: CD-TEXT writing capability is automatically determined. 0x00000080: R-W sub-channel writing capability is automatically determined. ricoh-mp6200 Supports writing with the Ricoh MP6200S CD recorder. CD structure analysis is done like in the 'generic-mmc' driver. sony-cdu920 Driver for the Sony CDU920 recorder. Audio and data tracks are supported. The Sony CDU948 recorder will work with this driver, too. Use option '--speed 0' to get the full writing speed. 'read-toc' uses the Q sub-channel scanning method. sony-cdu948 Driver for the Sony CDU948 recorder. It extends the 'sony-cdu920' driver by CD-TEXT writing and multi session mode. taiyo-yuden This is an adapted 'cdd2600' driver for Taiyo-Yuden recorders. 'read-toc' is done with 'plextor' method. teac-cdr55 Driver for the Teac CD-R55 recorder. Audio and data tracks are supported. 'read-toc' uses the Q sub-channel scanning method. toshiba Read only driver for Toshiba SCSI CD-ROM drives. The Q sub-channel scanning method is used to detect pre-gaps and index marks. yamaha-cdr10x Driver for the Yamaha CDR10X recorder series that supports audio and data tracks. 'read-toc' uses the Q sub-channel scanning method. SCSI Device ----------- Cdrdao no longer uses Joerg Schilling's SCSI library and now relies exclusively on native interfaces. The scanbus command returns a list of available devices (available for Mac, Windows and Linux). If a single device is available, it is not necessary to specify the --device option as cdrdao will selects it automatically. On Unix-based systems, the device normally is the path to the device file, such as /dev/cdrom or /dev/sr0. On Windows systems, the device should be the drive letter (--device D). ATAPI Support ------------- ATAPI drives use the same command set as SCSI devices so that cdrdao also supports all ATAPI CD-ROM, CD-R and CD-RW drives. Either the 'generic-mmc' or the 'generic-mmc-raw' driver should work if the recorder supports DAO writing at all. Cdrdao access ATAPI devices through the same interface as used for SCSI devices. Therefore the operating system must emulate the ATAPI devices as SCSI devices. Some operating systems do this by default (e.g. Win32), other operating system must be told to do that (e.g. Linux, enable the IDE host adapter emulation) and some operating system may not support that. The same applies for USB and parallel port devices: cdrdao supports them but the operating system must present them as SCSI devices. Digital Audio Extraction ------------------------ The digital audio extraction is done with the help of Monty's paranoia library except the 'plextor' driver which uses a special method for Plextor drives. If you want to use the paranoia mode with the 'plextor' driver you will have to use option '--driver plextor:0x1'. The output file will always contain raw signed 16 bit audio samples with MSB-LSB (big endian) byte order. If the byte order of the output file is not MSB-LSB you will have to use the driver option '0x20000', e.g. '--driver plextor:0x20000'. Please do not try to use '--swap' for writing in this case because the byte order of the audio samples that are fed to the paranoia library is wrong, too, which will cause malfunction of the paranoia library routines. Even if you specify a file name with a ".wav" extension the resulting file will be a raw audio file without any header. 'read-cd' and 'copy' will read the first track's pre-gap, too. If your drive cannot access these audio sectors which is usually indicated by read errors you will have to use driver option 0x40000. Currently, cdrdao does not support as many CD-ROM drives as cdparanoia. If audio extraction works with cdparanoia but not with cdrdao please send me a log of a 'cdparanoia -v' run and I will implement the required access command. CD-TEXT Writing --------------- CD-TEXT data is read with 'read-toc' or 'read-cd' if your drive supports it (e.g. Teac CD-532e, HP CD-Writer+ 8100) and will be stored in the toc-file. It is also possible to create the CD-TEXT data manually by editing the toc-file or by using the gcdmaster GUI. If you want to create your own CD-TEXT data be sure to add the fields 'TITLE' and 'PERFORMER' to all tracks. By default, if the CD-TEXT data contains non-ascii characters (either ISO-8851 or MSJIS), cdrdao will translate them to UTF-8 and output UTF-8-encoded text in the TOC file for convenience. This behavior can be turned off with the --no-utf8 option. This option forces the TOC file to be pure ASCII (any non ascii characters are displayed as their octal value preceded by a backslash). The directory "testtocs" contains a template toc-file "cdtext.toc". Drives Known to Work -------------------- Recorders: Model Firmware Rev. Driver ---------------------------------------------------------------------------- ACER 10x8x32 ? generic-mmc-raw ACER 2010A ? generic-mmc-raw ACER 20x10x40 ? generic-mmc-raw ACER 4406EU A.AZ generic-mmc-raw ACER 4x4x6 ? generic-mmc-raw ACER 8X4X32 5.GV generic-mmc-raw ACER CD-R/RW 4X4X32 3.LS generic-mmc-raw AOPEN CD-RW CRW1632 1.11 generic-mmc AOPEN CD-RW CRW2040 1.01 generic-mmc AOPEN CD-RW CRW3248 1.12 generic-mmc-raw AOPEN CD-RW-241040 ? generic-mmc AOPEN CRW1232 ? generic-mmc-raw AOPEN CRW620 2.40 ricoh-mp6200 10 AOPEN CRW9624 1.70 generic-mmc ARTEC RW241040 1.02 generic-mmc-raw ARTEC WRA-WA48 ? generic-mmc-raw ARTEC WRR-4048 1.01 generic-mmc-raw ASUS CRW-1610A atapi generic-mmc-raw ASUS CRW-3212A 1.0 generic-mmc-raw ATAPI CD-R/RW 12X8X32 9.JB generic-mmc-raw ATAPI CD-R/RW 4X4X32 3.GS,3.HS generic-mmc-raw 7 ATAPI CD-R/RW CRW6206A 1.3A generic-mmc-raw BENQ CRW2410A P.MJ generic-mmc-raw BTC BCE1610IM 0.19,A.20 generic-mmc-raw BTC BCE2410IM A.22,A.23 generic-mmc-raw BTC BCE621E 2.0 generic-mmc-raw CD-RW CDR-2440MB 5SG1 generic-mmc CREATIVE CD-RW RW1210E LCS6 generic-mmc CREATIVE CD-RW RW4424 1.12 generic-mmc CREATIVE CD-RW RW8433E 1R04 generic-mmc CREATIVE CD5233E 1.00 generic-mmc CYBERDRV CW018D 120 generic-mmc-raw CYBERDRV CW038D 100C,110C generic-mmc-raw CYBERDRV CW058D 100D generic-mmc-raw DELTA OME-W141 1.40 generic-mmc GENERIC CRD-BP1600P 2.43 generic-mmc GENERIC CRD-R800S 1.10 generic-mmc GENERIC CRD-RW2 1.12 generic-mmc 9 Goldstar 8120B ? generic-mmc-raw GRUNDIG CDR100IPW 1.26 cdd2600 HL-DT-ST CD-RW GCE-8160B 1.02 generic-mmc-raw HL-DT-ST CD-RW GCE-8320B 1.00,1.01,1.04 generic-mmc-raw HL-DT-ST RW/DVD GCC-4120B 2.01 generic-mmc HP 9510i 1.0e generic-mmc HP CD-Writer 4020 1.27 cdd2600 HP CD-Writer 6020 1.07 cdd2600 HP CD-Writer+ 7100 3.01 generic-mmc-raw HP CD-Writer+ 7200 3.01 generic-mmc-raw HP CD-Writer+ 7570 1.0a generic-mmc 5 HP CD-Writer+ 8100 1.0g generic-mmc 5 HP CD-Writer+ 8200 1.0f generic-mmc 5 HP CD-Writer+ 8290 1.3c generic-mmc 5 HP CD-Writer+ 9100 1.0c generic-mmc 5 HP CD-Writer+ 9110 1.0 generic-mmc 5 HP CD-Writer+ 9200 1.0c, 1.0e generic-mmc 5 HP CD-Writer+ 9300 1.0b generic-mmc 5 HP CD-Writer+ 9600 1.0a generic-mmc 5 HP CD-Writer+ 9700 1.0M generic-mmc HP DVD Writer 100j 1.34 generic-mmc HP DVD Writer 200j 1.06 generic-mmc-raw IDE-CD R/RW 16x10A P1.5 generic-mmc IDE-CD R/RW 2x2x24 1.4 generic-mmc-raw IDE-CD R/RW 4x4x24 1.5C generic-mmc-raw IDE-CD R/RW 4x4x32 1.3B,1.4B generic-mmc-raw IDE-CD R/RW 8x4x32 1.3B,1.4B,1.5 generic-mmc-raw IDE-CD ReWritable-2x2x6 3.09 generic-mmc-raw IMATION IMW121032IAB 2.4B generic-mmc IMS 522 1.05 cdd2600 IMS CDD2000 1.25,1.26 cdd2600 IOMEGA ZIPCD 4x650 1.04 generic-mmc-raw JVC R2626 1.10,2.29 teac-cdr55 JVC XR-W2010 1.51 teac-cdr55 KODAK PCD-225 1.06 cdd2600 LG 8088B ? generic-mmc LG 8120B 1.03 generic-mmc LG CD-ROM CDR-8428B 1.0 generic-mmc LG CD-RW CED-8080B 1.05,1.06 generic-mmc LG CD-RW CED-8081B 1.00,1.05,1.06 generic-mmc LG CD-RW CED-8083B 1.06,1.09,1.1 generic-mmc LG CD-RW GCE-8240B 1.06 generic-mmc LG COMBO 1.0 generic-mmc LG HL-DT-ST RW/DVD GCC-4080N 0010 generic-mmc LITE-ON LTR-0841 MS10, MS84 generic-mmc LITE-ON LTR-12101B LS15 generic-mmc-raw LITE-ON LTR-16101B TSON generic-mmc-raw LITE-ON LTR-16102C US52 generic-mmc-raw LITE-ON LTR-24102B 5S07 generic-mmc LITE-ON LTR-32123S XS0X generic-mmc-raw LITE-ON LTR-32125W WBS4 generic-mmc LITE-ON LTR-40125S ZS08 generic-mmc-raw LITE-ON LTR-48125W VS04,VS06 generic-mmc-raw MATSHITA CD-R CW-7502 X.14, X.17 generic-mmc 5 MATSHITA CD-R CW-7503 1.04, 1.8 generic-mmc MATSHITA CD-R CW-7582 1.00, 1.05, 1.10 generic-mmc MATSHITA CD-R CW-7585 1.04 generic-mmc MATSHITA CD-R CW-7586 1.01,1.08 generic-mmc MATSHITA CDRRW01 1.34 generic-mmc MATSHITA UJDA360 ? generic-mmc MATSHITA UJDA710 1.50 generic-mmc MATSHITA UJDA720 ? generic-mmc MEMOREX 24MAX 1040 ? generic-mmc MEMOREX 40MAXX 1248AJ ZWS1 generic-mmc MEMOREX CD-RW4224 1.17 generic-mmc MEMOREX CDRW-2216 1.0b generic-mmc-raw MEMOREX CR-622 D4.0 generic-mmc-raw 5 MEMOREX CRW-1662 D4.0 generic-mmc-raw MEMOREX CRW620 1.20 ricoh-mp6200 MICROSOLUTIONS BACKPACK CD REWRITER ? generic-mmc MITSUMI 2801 1.10 generic-mmc-raw MITSUMI CR-4801 2.02 generic-mmc 2 MITSUMI CR-4802 1.2B, 1.4D generic-mmc-raw 4 MITSUMI CR-4804 2.4C generic-mmc-raw MITSUMI CR-48X5 1.2A generic-mmc MITSUMI CR-48X5TE 1.6A generic-mmc MITSUMI CR-48X8TE 1.1E generic-mmc MITSUMI CR-48XATE 1.0C generic-mmc OLYMPIC RWD RW4224 ? generic-mmc OTI -975 SOCRATES ? generic-mmc-raw PANASONIC CD-R CW-7582 1.05 generic-mmc PHILIPS CDD 3801/31 ? generic-mmc-raw PHILIPS CDD2000 1.25, 1.26 cdd2600 PHILIPS CDD2600 1.07 cdd2600 PHILIPS CDD3600 2.00 generic-mmc-raw PHILIPS CDD3610 2.02, 3.01, 3.09 generic-mmc-raw PHILIPS CDD4201 1.5C generic-mmc-raw PHILIPS CDD4801 C1.3 generic-mmc-raw PHILIPS CDD522 ? cdd2600 PHILIPS CDRW1610A P1.4 generic-mmc PHILIPS CDRW2412A P1.5 generic-mmc PHILIPS CDRW400 ? generic-mmc-raw PHILIPS OMNIWRITER26 1.20 ricoh-mp6200 PHILIPS PCA460RW 1.0e,1.0g generic-mmc PHILIPS PCRW1208 3.1,4.0 generic-mmc-raw PHILIPS PCRW120899 ? generic-mmc-raw PHILIPS PCRW404 1.06,1.4b generic-mmc-raw PHILIPS PCRW804 1.5,2.0 generic-mmc-raw PIONEER DVD-ROM DVD-114 2.06 generic-mmc PLEXTOR CD-R PX-R412 1.04, 1.06, 1.07 generic-mmc PLEXTOR CD-R PX-R820 1.03, 1.07 generic-mmc PLEXTOR CD-R PX-W1210 1.02,1.04,1.05 generic-mmc PLEXTOR CD-R PX-W124 1.02 generic-mmc PLEXTOR CD-R PX-W1610 1.00 generic-mmc PLEXTOR CD-R PX-W4220 1.01, 1.02 generic-mmc PLEXTOR CD-R PX-W8220 1.01 generic-mmc PLEXTOR CD-R PX-W8432 1.03, 1.05 generic-mmc PLEXTOR CD-R PX-W241040 1.04 generic-mmc PLEXTOR CD-R PX-W2410a 1.03,1.04 generic-mmc PLEXTOR CD-R PX-W4012A 1.00,1.01 generic-mmc QPS CRD-BP 1500P 6.38 generic-mmc-raw RICOH CD-R/RW MP7040 1.4 generic-mmc RICOH CD-R/RW MP7060 1.30, 1.50, 1.70 generic-mmc RICOH CD-R/RW MP7063A 1.80 generic-mmc RICOH CD-R/RW MP7080 1.10 generic-mmc RICOH CD-R/RW MP7083A 1.20 generic-mmc RICOH DVD/CDRW MP9060 1.50 generic-mmc RICOH MP6200 2.20, 2.03, 1.20, 2.40 ricoh-mp6200 RICOH MP6201 ? ricoh-mp6200 SAF CD-R2006PLUS 2.05 teac-cdr55 SAF CD-R4012 6.0J, 6.0L teac-cdr55 SAF CD-R8020 1.24 generic-mmc SAF CD-RW 226 1.12 teac-cdr55 SAF CD-RW4224A 1.20 generic-mmc SAF CD-RW6424 1.30 generic-mmc SAMSUNG CD-R/RW SW-204B BS21 generic-mmc-raw SAMSUNG CD-R/RW SW-206 1.40 generic-mmc SAMSUNG CD-R/RW SW-208 BS01, BS02 generic-mmc-raw SAMSUNG CD-R/RW SW-212B BS05,Q001 generic-mmc-raw SAMSUNG CD-R/RW SW-224 R201 generic-mmc-raw SAMSUNG CD-R/RW SW-408B BS02 generic-mmc SAMSUNG CDRW/DVD SM-308B BS03,BS04,T100 generic-mmc SAMSUNG SW-232 R300,R301 generic-mmc-raw SANYO CRD-BP3 1.03 generic-mmc SONY CD-R CDU920 ? sony-cdu920 SONY CD-R CDU924 1.1d sony-cdu920 SONY CD-R CDU948 1.0j sony-cdu948 5 SONY CD-RW CRX700E 1.4r generic-mmc SONY CRX-815 ? generic-mmc SONY CRX100 1.0m generic-mmc 5 SONY CRX120 1.0j generic-mmc 5 SONY CRX140 1.0n generic-mmc 5 SONY CRX145 1.0b generic-mmc 5 SONY CRX160E 1.0e,1.0g generic-mmc SONY CRX175A1 5YS2 generic-mmc SONY CRX175E ? generic-mmc SONY CRX185E1 XYS2 generic-mmc SONY CRX195E1 ? generic-mmc-raw T.YUDEN CD-WO EW-50 2.15, 2.16, 2.18 taiyo-yuden TDK 4800 s7s5 generic-mmc TDK CDRW121032 1.02 generic-mmc TDK CDRW321040B X7S2 generic-mmc TDK CDRW8432 1.07 generic-mmc TEAC CD-R50 ? teac-cdr55 TEAC CD-R55 1.0k,1.0n,1.0r teac-cdr55 TEAC CD-R56 ? generic-mmc TEAC CD-R58 1.0J, 1.0H generic-mmc TEAC CD-W216E 1.0A generic-mmc TEAC CD-W512EB 2.0B generic-mmc TEAC CD-W512SB 1.0H generic-mmc TEAC CD-W516EB 1.0A,1.0B generic-mmc TEAC CD-W516EC 1.8C generic-mmc TEAC CD-W524E 1.0b generic-mmc TEAC CD-W54E 1.1B generic-mmc TEAC CD-W58E 1.0A generic-mmc-raw TORiSAN CDW-U4424 1.10 generic-mmc 11 TOSHIBA DVD-ROM SD-M1612 1004 generic-mmc TOSHIBA DVD-ROM SD-R1002 1030 generic-mmc TOSHIBA DVD-ROM SD-R1202 1020 generic-mmc TOSHIBA DVD-ROM SD-R2002 ? toshiba TOSHIBA DVD-ROM SD-R2102 15 toshiba TOSHIBA R/RW 4x4x24 ? generic-mmc-raw TRAXDATA 241040 ? generic-mmc TRAXDATA 2832 ? generic-mmc-raw TRAXDATA CDR4120 5.0G, 5.0J, 5.0N teac-cdr55 TRAXDATA CDRW2260+ 3.01 generic-mmc-raw TRAXDATA CDRW4260 1.0f generic-mmc TRAXDATA CRW2260 PRO 2.0 generic-mmc-raw WAITEC WT2444EI 1.04 generic-mmc-raw WAITEC WT4424 1.01 generic-mmc-raw WAITEC WT624 7.0F generic-mmc YAMAHA CDR100 1.0, 1.1 yamaha-cdr10x YAMAHA CDR102 1.00, 1.01 yamaha-cdr10x YAMAHA CDR200 1.0k generic-mmc YAMAHA CDR400 1.0k, 1.0n generic-mmc 1,5 YAMAHA CRW2100 1.0D, 1.0H generic-mmc YAMAHA CRW2200 ? generic-mmc YAMAHA CRW2260 1.0f generic-mmc YAMAHA CRW3200 1.0d generic-mmc YAMAHA CRW4001 1.0q generic-mmc YAMAHA CRW4260 1.0h, 1.0q generic-mmc 5 YAMAHA CRW4416 1.0b generic-mmc YAMAHA CRW6416 1.0c, 1.0d generic-mmc 8 YAMAHA CRW8424 1.0d generic-mmc YAMAHA CRW8824 1.0 generic-mmc _NEC 7900 ? generic-mmc-raw _NEC NR-7700A 1.01 generic-mmc _NEC NR-7800A 1.01,1.0B generic-mmc-raw Readers (command 'read-toc', 'read-cd'): Model Firmware Rev. Driver -------------------------------------------------------------------------- ASUS CD-S340 1.60 generic-mmc ASUS CD-S400 2.40 generic-mmc ASUS CD-S500/A 1.0K generic-mmc ASUS DVD-ROM E608 1.10 generic-mmc E-IDE CD-950E/TKU A41 generic-mmc E-IDE CD-ROM 36X/AKU U23 generic-mmc 3 E-IDE CD-ROM 52X/AKH A6E generic-mmc FUNAI E295X 1.01 generic-mmc HITACHI CDR-7730 ? generic-mmc HITACHI CDR-8435 0010 generic-mmc HITACHI DVD-ROM GD-2500 A011 plextor LG CD-ROM CRD-8480C 1.04 generic-mmc LG CD-ROM CRD-8482B 1.00 generic-mmc LG CD-ROM CRD-8521B 1.01,1.06 generic-mmc LG DVD-ROM DRN8080B LAB8 generic-mmc LITE-ON CD-ROM ? generic-mmc LITE-ON LTD-163 ghr3 generic-mmc LITEON DVD-ROM LTD163D ? generic-mmc MATSHITA CD-ROM CR-506 8S04 plextor MATSHITA CD-ROM CR-588 LS15 generic-mmc MATSHITA CD-ROM CR-589 GS0H generic-mmc MATSHITA CR-8008 8.0e plextor MATSHITA DVD-ROM SR-8585 ? generic-mmc MEMOREX CD-233E U10A generic-mmc 6 MITSUMI CD-ROM FX4820 D02A generic-mmc NAKAMICH MJ-5.16S 1.07 plextor OPTICS_S 8622 ? generic-mmc PHILIPS 36X/AKU ? generic-mmc PHILIPS CD-ROM PCCD052 F50P generic-mmc PHILIPS E-IDE CD-ROM 36X U23 generic-mmc PIONEER CD-ROM DR-U03 1.01 plextor PIONEER CD-ROM DR-U06 1.05 plextor PIONEER CD-ROM DR-U10 1.07 plextor PIONEER CD-ROM DR-U12 1.06 plextor PIONEER CD-ROM DR-U16 1.06 plextor PIONEER CD-ROM DR-U32 1.00 generic-mmc PIONEER DVD-103 1.09, 1.15 generic-mmc PIONEER DVD-104 1.11 generic-mmc PIONEER DVD-105 1.11 generic-mmc PIONEER DVD-303 1.09 plextor PIONEER DVD-305 1.03 plextor PLEXTOR CD-ROM ? plextor-scan PLEXTOR PX-40TS 1.11 plextor-scan PLEXTOR PX-40TW ? plextor-scan PLEXTOR PX-63 ? plextor-scan SONY CD-ROM ? plextor SONY CD-ROM CDU-76 1.1c plextor SONY CD-ROM CDU31A-02 ? generic-mmc SONY CD-ROM CDU4821 S0.P generic-mmc SONY CDU5211 YYS2 generic-mmc TEAC CD-524E 3.0B generic-mmc TEAC CD-532E 1.0A generic-mmc TEAC CD-532S 1.0A teac-cdr55 TEAC CD-540E 1.0A,1.0C generic-mmc TEAC CD-ROM CD-532S 1.0A plextor-scan TOSHIBA 1504 1008 toshiba TOSHIBA CD-ROM XM-3206B ? generic-mmc TOSHIBA CD-ROM XM-3601B 1885 toshiba TOSHIBA CD-ROM XM-5302TA 1095 toshiba TOSHIBA CD-ROM XM-5701TA 0167 toshiba TOSHIBA CD-ROM XM-6102B 1112 generic-mmc TOSHIBA CD-ROM XM-6201TA 1037 toshiba TOSHIBA CD-ROM XM-6302B 1012 generic-mmc TOSHIBA CD-ROM XM-6401TA 1009 toshiba TOSHIBA CD-ROM XM-6402B 1008 generic-mmc TOSHIBA DVD-ROM SD-2102 1015 toshiba TOSHIBA DVD-ROM SD-C2202 1020,1021 generic-mmc TOSHIBA DVD-ROM SD-C2302 1021 generic-mmc TOSHIBA DVD-ROM SD-C2402 1317 generic-mmc TOSHIBA DVD-ROM SD-M1102 1426 generic-mmc TOSHIBA DVD-ROM SD-M1401 1008 generic-mmc TOSHIBA DVD-ROM SD-M1402 ? generic-mmc TOSHIBA XM-5401 1036 plextor Notes: 1) Writing with firmware revision 1.0i does not work. 2) read-toc with plextor driver. 3) Sold as Philips PCA36XCD CD-ROM. 4) The generic-mmc driver will also work but the firmware seems to create wrong sub-channel data in some cases. 5) See notes at the end of this file. 6) This drive seems to ignore ISRC Codes and the Catalog Number. 7) Firmware version 3.DS does not work well in DAO mode. Update to 3.GS! 8) With firmware 1.0c and Adaptec 2940U2W the transmission must be set to asynchron according to Adaptec and Yamaha. 9) Sanyo OEM 32x/12x/4x CD-RW drive. 10) The firmware reports an empty vendor string so that the driver will not be selected automatically. Please use the --driver option. 11) As with Toast and Nero it`s best to write and rewrite at 2x. Example for CD Copying ---------------------- The following command will copy the CD in the source drive specified with option '--source-device' to the CD-R/CD-RW inserted in the destination drive specified with option '--device'. Only a single session will be copied which can be selected with option '--session' (default: 1st session). If you want to keep the session open you will have to use option '--multi'. cdrdao copy --source-device 0,2,0 --device 0,5,0 --buffers 64 The option '--buffers' is used to adjust the ring buffer size. Each buffer holds 1 second audio data. Dividing the specified number of buffers by the writing speed gives the approx. time for which data input my be stalled, e.g. 64 buffers and writing at 4x speed results in 16 seconds. On the fly copying is selected with option '--on-the-fly'. No intermediate data will be stored on the disk in this case. If the source CD contains audio tracks and the source drive is slow you should consider to reduce the audio extraction quality with option '--paranoia-mode 0' or reduce the writing speed to 2x. For '--paranoia-mode 0' you will need a perfect CD-ROM drive that can provide an accurate audio stream. The standard generic SCSI interface of Linux kernels < 2.2.6 cannot handle multiple commands in parallel. Since the reading and the writing part of cdrdao use the generic SCSI interface mutual blocking will occur. This results in low fill rates of cdrdao's ring buffer and very likely produces buffer under runs. To avoid these problems you should apply Heiko Eissfeldt's sg-buffer patch which can be downloaded from: ftp://ftp.fokus.gmd.de/pub/unix/cdrecord/alpha/ It is available for 2.0.x and 2.1.x kernels. For 2.2.x kernels with x < 6 the "SG-2.2.tar.gz" patch should be used. Kernel versions >= 2.2.6 do not need any patch. I strongly recommend to perform some simulation runs before trying real writing. Example for composing an audio CD --------------------------------- Assume three existing audio files 'audio1.wav', 'audio2.wav' and 'audio3.wav' that go in three tracks. We do not want a pause between track 1 and 2 (no pre-gap). The first 10 seconds of 'audio1.wav' should be used as pre-gap for track 3. Here is the toc-file: // Track 1 TRACK AUDIO FILE "audio1.wav" 0 // take all audio data from 'audio1.wav', length is taken // from file // Track 2 TRACK AUDIO FILE "audio2.wav" 0 // take all audio data from 'audio2.wav', length is taken // from file, no pre-gap // Track 3 TRACK AUDIO FILE "audio1.wav" 0 0:10:0 // take first 10 seconds from 'audio1.wav' START // everything before this line goes into the pre-gap FILE "audio3.wav" 0 // take all audio data from 'audio3.wav', length is taken // from file Type 'cdrdao show-toc example.toc' to check for the correct syntax of the toc-file. Note that even for the command 'show-toc' the audio files must exist if the length of the audio files is not specified like in the example. Type 'cdrdao read-test example.toc' to check if all audio files can be read without error (optional). Type 'cdrdao simulate example.toc' to perform a write simulation (optional). Type 'cdrdao write example.toc' to create the audio CD. Notes about some CD recorder models ----------------------------------- MATSHITA/PANASONIC CW-7502 This drive will only produce useful disks with the recent firmware revision X.17. The X depends on the drive hardware revision. Thanks to Jeroen Steenblik for adapting the generic-mmc driver to the CW-7502 recorder. He spend a lot of time and wasted many CD-Rs until it was obvious that the pre-X.14 firmware does not completely comply with the SCSI-3/mmc standard. Here are Jeroen's notes for upgrading the firmware: The update can be found at the Plasmon technical website, http://tech.plasmon.co.uk/, choose 'Download Files' and obtain the X.17 firmware for the CDR480. This includes all instructions. One thing I might add, when downloading the two files in the sequence described in their document, my drive refused the second file. I had to reboot after downloading the first file and only then I could download the second. Quite scary stuff. Swapping the download sequence should prevent this (so I've read). MEMOREX CR-622 Submitted by Bryan E. Chafy : The drive as shipped comes with firmware that does not support DAO. The firmware lives on a PROM, it is not flashable. You need an EPROM burner, a 27c020 PLCC EPROM, and the D4.0 ROM image for the CRW-1622 (can download it from Memorex web site, the name of the image is d39e.dat). The ROM is socketed at the rear of the drive, you will see it when you remove the top cover. Mine had a sticker on it with the numbers E07/885B. Note, this is for the CR-622 (and its sister the CDR-622 wearnes drive), NOT the CRW-1622. The CRW-1622 drive is flash-upgradeable). IMHO, Wearnes/Memorex should be sending us new ROM's free of charge because the box clearly states the CR-622 supports DAO. The new firmware does not turn the CR-622 into a cd-rw capable drive. You can still only burn cd-r media. YAMAHA CDR400, CRW4260 These drives sometimes have problems with writing at 4x speed. The resulting disk is hard read for some reason. Disks written at 1x or 2x speed are fine. Yamaha's support is aware of this problem. It might be related to the actual firmware revision. I successfully wrote CD-Rs at 4x speed with a CDR400t and firmware revision 1.0k. HP CD-Writer+ 75XX, HP CD-Writer+ 8100, SONY CRX100, HP CD-Writer+ 8200 The firmware restricts the possible disk types in multi session mode (DAO only) to one of the following: o Pure audio CD. o CD-EXTRA where the 1st session contains only audio tracks and the 2nd session contains 1 data track. Further restrictions: o The length of the 1st track's pre-gap is restricted to a certain amount. o Cue sheets with ISRC codes are rejected of the COPY flag is set. This might be fixed in future versions. SONY CD-R CDU948 The firmware restricts the possible disk types in DAO mode to one of the following: o Pure audio CD. o Mixed mode CD where the 1st track is a data track followed by at least 1 audio track. o CD-EXTRA where the 1st session contains only audio tracks and the 2nd session contains 1 data track. The length of the 1st track's pre-gap is restricted to a certain amount, too. If you want to create a pure data CD you will have to append a dummy audio track to the toc-file, e.g. with: TRACK AUDIO PREGAP 0:2:0 SILENCE 0:4:0 cdrdao-cdrdao-f00afb2/README.PlexDAE000066400000000000000000000022051511453746600167760ustar00rootroot00000000000000Plextor CD-ROM digital audio extraction for cdrdao These patches enhance "cdrdao" with bitwise-exact digital audio extraction for "Plextor"-brand CD-ROM drives. It uses Plextor vendor unique SCSI command enhancements in order to implement this. These features are not known to exist in other brand drives (by me, as of 25-3-1999), or to be exploited in any other software at this moment. Status is alpha, and there are some known bugs and things to do. Currently known bugs: - Incremental extraction of a CDDA block (by collecting correct samples in successive reads of a partly errenous CDDA block) is known to fail in some cases (leading to non-unique CDDA extraction). Current things to do: - Include output formats other than raw (big-endian). - Include output to stdio (for on-the-fly application maybe). - ... Usage hints: This clones a CD-DA as exactly as possible (but see known bugs!): cdrdao read-cd --device /dev/sga --datafile data.cdr data.toc cdrdao write --swap --device /dev/sgb data.toc You may want to do a "md5sum" of "data.cdr" on two successive reads to ensure the known bug did not occur. Leon Woestenberg cdrdao-cdrdao-f00afb2/README.Win32000066400000000000000000000041141511453746600164570ustar00rootroot00000000000000The Win32 port of cdrdao is based on the Cygwin Unix environment for Windows. This package comes with the binary version of the cygwin1.dll. You can download the corresponding source code from http://sourceforge.net/projects/cdrdao in the download section or via www.cygwin.com. This port should work on all Win32 operation systems. If you will use "cdrdao.exe" in dos prompt under win9x, (or restart in MS-DOS mode also), you have to check off "Auto Insert Notification" of the CD-R drive property. When you do "cdrdao.exe read-xx" with "Auto Insert Notification" property, your PC will hang (write is O.K.). During writing you should avoid to open the Explorer and similar tools. Currently, cdrdao does not lock the recording device so that all access action from the Explorer will lead to a failure of the recording process. Cdrdao requires a working ASPI installation for operation. You can fetch an ASPI installation package from Adaptec's home page. After a successful ASPI installation the command cdrdao scanbus should list all of your CD-ROM, DVD and recorder devices. If not the following registry changes should make them visible: [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Aspi32] "ErrorControl"=dword:00000001 "Type"=dword:00000001 "Start"=dword:00000002 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Aspi32\Parameters] "ExcludeMiniports"="" You can also execute the file "aspi.reg" to make the registry updates automatically. A 'cdrdao scanbus' output looks like this: 1,0,0: E-IDE, CD-ROM 52X/AKH, A6E 1,1,0: ARTEC, WRR-4048, 1.01 The number triple (e.g. 1,0,0) is the address of the drive. It must be used with the --device option of cdrdao to select the recorder or reader device. For example copying a CD works like this: cdrdao copy --source-device 1,0,0 --device 1,1,0 For simple tests you can use test toc-files from the "testtocs" directory: cdrdao simulate --device x,y,z testtocs/t1.toc This will run a write simulation with the layout of a simple audio CD. It is very useful to verify the principal functionality of cdrdao on you system. cdrdao-cdrdao-f00afb2/acinclude.m4000066400000000000000000000060731511453746600170750ustar00rootroot00000000000000# Configure paths for GTK-- # Erik Andersen 30 May 1998 # Modified by Tero Pulkkinen (added the compiler checks... I hope they work..) dnl Check and configure include and link paths for lame library dnl AC_PATH_LAME(MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) dnl AC_DEFUN([AC_PATH_LAME], [dnl AC_ARG_ENABLE(lame-test,[ --disable-lame-test skip checking for right mp3lame library],lame_test=$enableval,lame_test=yes) AC_ARG_WITH(lame,[ --with-lame enable building of toc2mp3 (default is YES)],lame=$withval,lame="yes") AC_ARG_WITH(lame-lib,[ --with-lame-lib=dir set directory containing libmp3lame],lamelib=$withval,lamelib="") AC_ARG_WITH(lame-include,[ --with-lame-include=dir set directory containing lame include files],lameinc=$withval,lameinc="") if test x$lame = xyes ; then AC_MSG_CHECKING(for Lame library version >= $1) lame_ok=yes else lame_ok=no lame_test=no fi if test x$lame_test = xyes ; then AC_LANG_SAVE AC_LANG([C++]) ac_save_CXXFLAGS="$CXXFLAGS" ac_save_LIBS="$LIBS" if test "x$lameinc" != x ; then CXXFLAGS="$CXXFLAGS -I$lameinc" CFLAGS="$CFLAGS -I$lameinc" fi if test "x$lamelib" != x ; then LIBS="$LIBS -L$lamelib" fi LIBS="$LIBS -lmp3lame" AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include #include #include #include int main () { int major, minor; char *tmp_version; lame_version_t lame_version; /* HP/UX 0 (%@#!) writes to sscanf strings */ tmp_version = strdup("$1"); if (sscanf(tmp_version, "%d.%d", &major, &minor) != 2) { printf("%s, bad version string\n", "$1"); exit(1); } get_lame_version_numerical(&lame_version); if (lame_version.major > major || ((lame_version.major == major) && (lame_version.minor >= minor))) { return 0; } else { printf("\n*** An old version of LAME (%d.%d) was found.\n", lame_version.major, lame_version.minor); printf("*** You need a version of LAME newer than %d.%d. The latest version of\n", major, minor); printf("*** LAME is available from http://www.mp3dev.org/.\n"); printf("*** However, it is very likely that slightly older versions of LAME\n"); printf("*** will also work. If you want to try it, run configure with option\n"); printf("*** --disable-lame-test. This will skip this check and assume that\n"); printf("*** LAME is available for compiling.\n"); } return 1; } ]])],[],[lame_ok=no],[echo $ac_n "cross compiling; assumed OK... $ac_c"]) CXXFLAGS="$ac_save_CXXFLAGS" LIBS="$ac_save_LIBS" AC_LANG_RESTORE fi LAME_CFLAGS="" LAME_LIBS="" if test $lame_ok = yes ; then AC_MSG_RESULT(yes) if test "x$lameinc" != x ; then LAME_CFLAGS="-I$lameinc" fi if test "x$lamelib" != x ; then LAME_LIBS="-L$lamelib" fi LAME_LIBS="$LAME_LIBS -lmp3lame" ifelse([$2], , :, [$2]) else if test x$lame = xyes ; then AC_MSG_RESULT(no) fi ifelse([$3], , :, [$3]) fi AC_SUBST(LAME_CFLAGS) AC_SUBST(LAME_LIBS) ] ) cdrdao-cdrdao-f00afb2/ar-lib000077500000000000000000000140311511453746600157710ustar00rootroot00000000000000#! /bin/sh # Wrapper for Microsoft lib.exe me=ar-lib scriptversion=2024-06-19.01; # UTC # Copyright (C) 2010-2024 Free Software Foundation, Inc. # Written by Peter Rosin . # # 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, 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, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . # func_error message func_error () { echo "$me: $1" 1>&2 exit 1 } file_conv= # func_file_conv build_file # Convert a $build file to $host form and store it in $file # Currently only supports Windows hosts. func_file_conv () { file=$1 case $file in / | /[!/]*) # absolute file, and not a UNC file if test -z "$file_conv"; then # lazily determine how to convert abs files case `uname -s` in MINGW*) file_conv=mingw ;; CYGWIN* | MSYS*) file_conv=cygwin ;; *) file_conv=wine ;; esac fi case $file_conv in mingw) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; cygwin | msys) file=`cygpath -m "$file" || echo "$file"` ;; wine) file=`winepath -w "$file" || echo "$file"` ;; esac ;; esac } # func_at_file at_file operation archive # Iterate over all members in AT_FILE performing OPERATION on ARCHIVE # for each of them. # When interpreting the content of the @FILE, do NOT use func_file_conv, # since the user would need to supply preconverted file names to # binutils ar, at least for MinGW. func_at_file () { operation=$2 archive=$3 at_file_contents=`cat "$1"` eval set x "$at_file_contents" shift for member do $AR -NOLOGO $operation:"$member" "$archive" || exit $? done } case $1 in '') func_error "no command. Try '$0 --help' for more information." ;; -h | --h*) cat <. GNU Automake home page: . General help using GNU software: . EOF exit $? ;; -v | --v*) echo "$me (GNU Automake) $scriptversion" exit $? ;; esac if test $# -lt 3; then func_error "you must specify a program, an action and an archive" fi AR=$1 shift while : do if test $# -lt 2; then func_error "you must specify a program, an action and an archive" fi case $1 in -lib | -LIB \ | -ltcg | -LTCG \ | -machine* | -MACHINE* \ | -subsystem* | -SUBSYSTEM* \ | -verbose | -VERBOSE \ | -wx* | -WX* ) AR="$AR $1" shift ;; -nologo | -NOLOGO) # We always invoke AR with -nologo, so don't need to add it again. shift ;; *) action=$1 shift break ;; esac done orig_archive=$1 shift func_file_conv "$orig_archive" archive=$file # strip leading dash in $action action=${action#-} delete= extract= list= quick= replace= index= create= while test -n "$action" do case $action in d*) delete=yes ;; x*) extract=yes ;; t*) list=yes ;; q*) quick=yes ;; r*) replace=yes ;; s*) index=yes ;; S*) ;; # the index is always updated implicitly c*) create=yes ;; u*) ;; # TODO: don't ignore the update modifier v*) ;; # TODO: don't ignore the verbose modifier *) func_error "unknown action specified" ;; esac action=${action#?} done case $delete$extract$list$quick$replace,$index in yes,* | ,yes) ;; yesyes*) func_error "more than one action specified" ;; *) func_error "no action specified" ;; esac if test -n "$delete"; then if test ! -f "$orig_archive"; then func_error "archive not found" fi for member do case $1 in @*) func_at_file "${1#@}" -REMOVE "$archive" ;; *) func_file_conv "$1" $AR -NOLOGO -REMOVE:"$file" "$archive" || exit $? ;; esac done elif test -n "$extract"; then if test ! -f "$orig_archive"; then func_error "archive not found" fi if test $# -gt 0; then for member do case $1 in @*) func_at_file "${1#@}" -EXTRACT "$archive" ;; *) func_file_conv "$1" $AR -NOLOGO -EXTRACT:"$file" "$archive" || exit $? ;; esac done else $AR -NOLOGO -LIST "$archive" | tr -d '\r' | sed -e 's/\\/\\\\/g' \ | while read member do $AR -NOLOGO -EXTRACT:"$member" "$archive" || exit $? done fi elif test -n "$quick$replace"; then if test ! -f "$orig_archive"; then if test -z "$create"; then echo "$me: creating $orig_archive" fi orig_archive= else orig_archive=$archive fi for member do case $1 in @*) func_file_conv "${1#@}" set x "$@" "@$file" ;; *) func_file_conv "$1" set x "$@" "$file" ;; esac shift shift done if test -n "$orig_archive"; then $AR -NOLOGO -OUT:"$archive" "$orig_archive" "$@" || exit $? else $AR -NOLOGO -OUT:"$archive" "$@" || exit $? fi elif test -n "$list"; then if test ! -f "$orig_archive"; then func_error "archive not found" fi $AR -NOLOGO -LIST "$archive" || exit $? fi cdrdao-cdrdao-f00afb2/aspi.reg000066400000000000000000000004321511453746600163300ustar00rootroot00000000000000Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Aspi32] "ErrorControl"=dword:00000001 "Type"=dword:00000001 "Start"=dword:00000002 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Aspi32\Parameters] "ExcludeMiniports"="" cdrdao-cdrdao-f00afb2/autogen.sh000077500000000000000000000024041511453746600166770ustar00rootroot00000000000000#! /bin/sh # Run this to generate the configure script and unpack needed packages cleanup() { echo Cleaning up. make clean > /dev/null >& /dev/null make distclean > /dev/null >& /dev/null find . -name Makefile.in -exec rm {} \; rm -f Makefile dao/Makefile gcdmaster/Makefile pccts/antlr/Makefile pccts/dlg/Makefile trackdb/Makefile utils/Makefile find . -name .deps -exec rm -fr {} \; >& /dev/null rm -f aclocal.m4 configure config.h config.log stamp-h1 specs/cdrdao.fedora.spec config.status gcdmaster/gcdmaster.schemas rm -fr autom4te.cache } if (( $# > 0 )) && [[ "$1" == "clean" ]]; then cleanup exit 0 fi # Minimum version MAJOR_VERSION=1 MINOR_VERSION=7 AMVERSION=`automake --version | awk '/automake/ {print $4}'` if test `echo $AMVERSION | awk -F. '{print $1}'` -lt $MAJOR_VERSION; then echo "Your version of automake is too old, you need at least automake $MAJOR_VERSION.$MINOR_VERSION" exit -1 fi if test `echo $AMVERSION | awk -F. '{print $2}' | awk -F- '{print $1}'` -lt $MINOR_VERSION; then echo "Your version of automake is too old, you need at least automake $MAJOR_VERSION.$MINOR_VERSION" exit -1 fi # Calls aclocal, automake, autoconf and al. for you echo "Running autoreconf" rm -fr autom4te.cache autoreconf cdrdao-cdrdao-f00afb2/cdrdao.lsm000066400000000000000000000015511511453746600166510ustar00rootroot00000000000000Begin3 Title: cdrdao Version: 1.0 Entered-date: 03AUG98 Description: Writes audio CD-Rs in disc-at-once (DAO) mode allowing control over pre-gaps (length down to 0, nonzero audio data) and sub-channel information like ISRC codes. All data that is written to the disc must be specified with a text file. Audio data may be in WAVE or raw format. Keywords: CD-recording, audio, disc-at-once Author: mueller@daneb.ping.de (Andreas Mueller) Maintained-by: mueller@daneb.ping.de (Andreas Mueller) Primary-site: sunsite.unc.edu /pub/Linux/utils/disk-management/ 67 kB cdrdao-1.0.src.tar.gz 103 kB cdrdao-1.0.bin.x86.linux.tar.gz Alternate-site: Platforms: Linux Supported hardware: Philips CDD 2600 Copying-policy: GPL End cdrdao-cdrdao-f00afb2/compile000077500000000000000000000167051511453746600162650ustar00rootroot00000000000000#! /bin/sh # Wrapper for compilers which do not understand '-c -o'. scriptversion=2024-06-19.01; # UTC # Copyright (C) 1999-2024 Free Software Foundation, Inc. # Written by Tom Tromey . # # 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, 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, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . nl=' ' # We need space, tab and new line, in precisely that order. Quoting is # there to prevent tools from complaining about whitespace usage. IFS=" "" $nl" file_conv= # func_file_conv build_file lazy # Convert a $build file to $host form and store it in $file # Currently only supports Windows hosts. If the determined conversion # type is listed in (the comma separated) LAZY, no conversion will # take place. func_file_conv () { file=$1 case $file in / | /[!/]*) # absolute file, and not a UNC file if test -z "$file_conv"; then # lazily determine how to convert abs files case `uname -s` in MINGW*) file_conv=mingw ;; CYGWIN* | MSYS*) file_conv=cygwin ;; *) file_conv=wine ;; esac fi case $file_conv/,$2, in *,$file_conv,*) ;; mingw/*) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; cygwin/* | msys/*) file=`cygpath -m "$file" || echo "$file"` ;; wine/*) file=`winepath -w "$file" || echo "$file"` ;; esac ;; esac } # func_cl_dashL linkdir # Make cl look for libraries in LINKDIR func_cl_dashL () { func_file_conv "$1" if test -z "$lib_path"; then lib_path=$file else lib_path="$lib_path;$file" fi linker_opts="$linker_opts -LIBPATH:$file" } # func_cl_dashl library # Do a library search-path lookup for cl func_cl_dashl () { lib=$1 found=no save_IFS=$IFS IFS=';' for dir in $lib_path $LIB do IFS=$save_IFS if $shared && test -f "$dir/$lib.dll.lib"; then found=yes lib=$dir/$lib.dll.lib break fi if test -f "$dir/$lib.lib"; then found=yes lib=$dir/$lib.lib break fi if test -f "$dir/lib$lib.a"; then found=yes lib=$dir/lib$lib.a break fi done IFS=$save_IFS if test "$found" != yes; then lib=$lib.lib fi } # func_cl_wrapper cl arg... # Adjust compile command to suit cl func_cl_wrapper () { # Assume a capable shell lib_path= shared=: linker_opts= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. eat=1 case $2 in *.o | *.lo | *.[oO][bB][jJ]) func_file_conv "$2" set x "$@" -Fo"$file" shift ;; *) func_file_conv "$2" set x "$@" -Fe"$file" shift ;; esac ;; -I) eat=1 func_file_conv "$2" mingw set x "$@" -I"$file" shift ;; -I*) func_file_conv "${1#-I}" mingw set x "$@" -I"$file" shift ;; -l) eat=1 func_cl_dashl "$2" set x "$@" "$lib" shift ;; -l*) func_cl_dashl "${1#-l}" set x "$@" "$lib" shift ;; -L) eat=1 func_cl_dashL "$2" ;; -L*) func_cl_dashL "${1#-L}" ;; -static) shared=false ;; -Wl,*) arg=${1#-Wl,} save_ifs="$IFS"; IFS=',' for flag in $arg; do IFS="$save_ifs" linker_opts="$linker_opts $flag" done IFS="$save_ifs" ;; -Xlinker) eat=1 linker_opts="$linker_opts $2" ;; -*) set x "$@" "$1" shift ;; *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) func_file_conv "$1" set x "$@" -Tp"$file" shift ;; *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) func_file_conv "$1" mingw set x "$@" "$file" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -n "$linker_opts"; then linker_opts="-link$linker_opts" fi exec "$@" $linker_opts exit 1 } eat= case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: compile [--help] [--version] PROGRAM [ARGS] Wrapper for compilers which do not understand '-c -o'. Remove '-o dest.o' from ARGS, run PROGRAM with the remaining arguments, and rename the output as expected. If you are trying to build a whole package this is not the right script to run: please start by reading the file 'INSTALL'. Report bugs to . GNU Automake home page: . General help using GNU software: . EOF exit $? ;; -v | --v*) echo "compile (GNU Automake) $scriptversion" exit $? ;; cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \ clang-cl | *[/\\]clang-cl | clang-cl.exe | *[/\\]clang-cl.exe | \ icl | *[/\\]icl | icl.exe | *[/\\]icl.exe ) func_cl_wrapper "$@" # Doesn't return... ;; esac ofile= cfile= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. # So we strip '-o arg' only if arg is an object. eat=1 case $2 in *.o | *.obj) ofile=$2 ;; *) set x "$@" -o "$2" shift ;; esac ;; *.c) cfile=$1 set x "$@" "$1" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -z "$ofile" || test -z "$cfile"; then # If no '-o' option was seen then we might have been invoked from a # pattern rule where we don't need one. That is ok -- this is a # normal compilation that the losing compiler can handle. If no # '.c' file was seen then we are probably linking. That is also # ok. exec "$@" fi # Name of file we expect compiler to create. cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` # Create the lock directory. # Note: use '[/\\:.-]' here to ensure that we don't use the same name # that we are using for the .o file. Also, base the name on the expected # object file name, since that is what matters with a parallel build. lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d while true; do if mkdir "$lockdir" >/dev/null 2>&1; then break fi sleep 1 done # FIXME: race condition here if user kills between mkdir and trap. trap "rmdir '$lockdir'; exit 1" 1 2 15 # Run the compile. "$@" ret=$? if test -f "$cofile"; then test "$cofile" = "$ofile" || mv "$cofile" "$ofile" elif test -f "${cofile}bj"; then test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" fi rmdir "$lockdir" exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: cdrdao-cdrdao-f00afb2/config.guess000077500000000000000000001430721511453746600172250ustar00rootroot00000000000000#!/usr/bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2024 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale timestamp='2024-07-27' # This file 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 3 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, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # https://git.savannah.gnu.org/cgit/config.git/plain/config.guess # # Please send patches to . # The "shellcheck disable" line above the timestamp inhibits complaints # about features and limitations of the classic Bourne shell that were # superseded or lifted in POSIX. However, this script identifies a wide # variety of pre-POSIX systems that do not have POSIX shells at all, and # even some reasonably current systems (Solaris 10 as case-in-point) still # have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system '$me' is run on. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2024 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try '$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi # Just in case it came from the environment. GUESS= # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, 'CC_FOR_BUILD' used to be named 'HOST_CC'. We still # use 'HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. tmp= # shellcheck disable=SC2172 trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 set_cc_for_build() { # prevent multiple calls if $tmp is already set test "$tmp" && return 0 : "${TMPDIR=/tmp}" # shellcheck disable=SC2039,SC3028 { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } dummy=$tmp/dummy case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in ,,) echo "int x;" > "$dummy.c" for driver in cc gcc c17 c99 c89 ; do if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then CC_FOR_BUILD=$driver break fi done if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac } # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if test -f /.attbin/uname ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case $UNAME_SYSTEM in Linux|GNU|GNU/*) LIBC=unknown set_cc_for_build cat <<-EOF > "$dummy.c" #if defined(__ANDROID__) LIBC=android #else #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #elif defined(__GLIBC__) LIBC=gnu #elif defined(__LLVM_LIBC__) LIBC=llvm #else #include /* First heuristic to detect musl libc. */ #ifdef __DEFINED_va_list LIBC=musl #endif #endif #endif EOF cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` eval "$cc_set_libc" # Second heuristic to detect musl libc. if [ "$LIBC" = unknown ] && command -v ldd >/dev/null && ldd --version 2>&1 | grep -q ^musl; then LIBC=musl fi # If the system lacks a compiler, then just pick glibc. # We could probably try harder. if [ "$LIBC" = unknown ]; then LIBC=gnu fi ;; esac # Note: order is significant - the case branches are not exclusive. case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ /sbin/sysctl -n hw.machine_arch 2>/dev/null || \ /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \ echo unknown)` case $UNAME_MACHINE_ARCH in aarch64eb) machine=aarch64_be-unknown ;; armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` machine=${arch}${endian}-unknown ;; *) machine=$UNAME_MACHINE_ARCH-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently (or will in the future) and ABI. case $UNAME_MACHINE_ARCH in earm*) os=netbsdelf ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # Determine ABI tags. case $UNAME_MACHINE_ARCH in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case $UNAME_VERSION in Debian*) release='-gnu' ;; *) release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. GUESS=$machine-${os}${release}${abi-} ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE ;; *:SecBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE ;; *:LibertyBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE ;; *:MidnightBSD:*:*) GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE ;; *:ekkoBSD:*:*) GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE ;; *:SolidBSD:*:*) GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE ;; *:OS108:*:*) GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE ;; macppc:MirBSD:*:*) GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE ;; *:MirBSD:*:*) GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE ;; *:Sortix:*:*) GUESS=$UNAME_MACHINE-unknown-sortix ;; *:Twizzler:*:*) GUESS=$UNAME_MACHINE-unknown-twizzler ;; *:Redox:*:*) GUESS=$UNAME_MACHINE-unknown-redox ;; mips:OSF1:*.*) GUESS=mips-dec-osf1 ;; alpha:OSF1:*:*) # Reset EXIT trap before exiting to avoid spurious non-zero exit code. trap '' 0 case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case $ALPHA_CPU_TYPE in "EV4 (21064)") UNAME_MACHINE=alpha ;; "EV4.5 (21064)") UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") UNAME_MACHINE=alpha ;; "EV5 (21164)") UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` GUESS=$UNAME_MACHINE-dec-osf$OSF_REL ;; Amiga*:UNIX_System_V:4.0:*) GUESS=m68k-unknown-sysv4 ;; *:[Aa]miga[Oo][Ss]:*:*) GUESS=$UNAME_MACHINE-unknown-amigaos ;; *:[Mm]orph[Oo][Ss]:*:*) GUESS=$UNAME_MACHINE-unknown-morphos ;; *:OS/390:*:*) GUESS=i370-ibm-openedition ;; *:z/VM:*:*) GUESS=s390-ibm-zvmoe ;; *:OS400:*:*) GUESS=powerpc-ibm-os400 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) GUESS=arm-acorn-riscix$UNAME_RELEASE ;; arm*:riscos:*:*|arm*:RISCOS:*:*) GUESS=arm-unknown-riscos ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) GUESS=hppa1.1-hitachi-hiuxmpp ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. case `(/bin/universe) 2>/dev/null` in att) GUESS=pyramid-pyramid-sysv3 ;; *) GUESS=pyramid-pyramid-bsd ;; esac ;; NILE*:*:*:dcosx) GUESS=pyramid-pyramid-svr4 ;; DRS?6000:unix:4.0:6*) GUESS=sparc-icl-nx6 ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) GUESS=sparc-icl-nx7 ;; esac ;; s390x:SunOS:*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL ;; sun4H:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-hal-solaris2$SUN_REL ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-sun-solaris2$SUN_REL ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) GUESS=i386-pc-auroraux$UNAME_RELEASE ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) set_cc_for_build SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 fi fi SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=$SUN_ARCH-pc-solaris2$SUN_REL ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-sun-solaris3$SUN_REL ;; sun4*:SunOS:*:*) case `/usr/bin/arch -k` in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like '4.1.3-JL'. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` GUESS=sparc-sun-sunos$SUN_REL ;; sun3*:SunOS:*:*) GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 case `/bin/arch` in sun3) GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun4) GUESS=sparc-sun-sunos$UNAME_RELEASE ;; esac ;; aushp:SunOS:*:*) GUESS=sparc-auspex-sunos$UNAME_RELEASE ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) GUESS=m68k-milan-mint$UNAME_RELEASE ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) GUESS=m68k-hades-mint$UNAME_RELEASE ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) GUESS=m68k-unknown-mint$UNAME_RELEASE ;; m68k:machten:*:*) GUESS=m68k-apple-machten$UNAME_RELEASE ;; powerpc:machten:*:*) GUESS=powerpc-apple-machten$UNAME_RELEASE ;; RISC*:Mach:*:*) GUESS=mips-dec-mach_bsd4.3 ;; RISC*:ULTRIX:*:*) GUESS=mips-dec-ultrix$UNAME_RELEASE ;; VAX*:ULTRIX*:*:*) GUESS=vax-dec-ultrix$UNAME_RELEASE ;; 2020:CLIX:*:* | 2430:CLIX:*:*) GUESS=clipper-intergraph-clix$UNAME_RELEASE ;; mips:*:*:UMIPS | mips:*:*:RISCos) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`"$dummy" "$dummyarg"` && { echo "$SYSTEM_NAME"; exit; } GUESS=mips-mips-riscos$UNAME_RELEASE ;; Motorola:PowerMAX_OS:*:*) GUESS=powerpc-motorola-powermax ;; Motorola:*:4.3:PL8-*) GUESS=powerpc-harris-powermax ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) GUESS=powerpc-harris-powermax ;; Night_Hawk:Power_UNIX:*:*) GUESS=powerpc-harris-powerunix ;; m88k:CX/UX:7*:*) GUESS=m88k-harris-cxux7 ;; m88k:*:4*:R4*) GUESS=m88k-motorola-sysv4 ;; m88k:*:3*:R3*) GUESS=m88k-motorola-sysv3 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 then if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ test "$TARGET_BINARY_INTERFACE"x = x then GUESS=m88k-dg-dgux$UNAME_RELEASE else GUESS=m88k-dg-dguxbcs$UNAME_RELEASE fi else GUESS=i586-dg-dgux$UNAME_RELEASE fi ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) GUESS=m88k-dolphin-sysv3 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 GUESS=m88k-motorola-sysv3 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) GUESS=m88k-tektronix-sysv3 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) GUESS=m68k-tektronix-bsd ;; *:IRIX*:*:*) IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'` GUESS=mips-sgi-irix$IRIX_REL ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) GUESS=i386-ibm-aix ;; ia64:AIX:*:*) if test -x /usr/bin/oslevel ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include int main () { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` then GUESS=$SYSTEM_NAME else GUESS=rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then GUESS=rs6000-ibm-aix3.2.4 else GUESS=rs6000-ibm-aix3.2 fi ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if test -x /usr/bin/lslpp ; then IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \ awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi GUESS=$IBM_ARCH-ibm-aix$IBM_REV ;; *:AIX:*:*) GUESS=rs6000-ibm-aix ;; ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) GUESS=romp-ibm-bsd4.4 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) GUESS=rs6000-bull-bosx ;; DPX/2?00:B.O.S.:*:*) GUESS=m68k-bull-sysv3 ;; 9000/[34]??:4.3bsd:1.*:*) GUESS=m68k-hp-bsd ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) GUESS=m68k-hp-bsd4.4 ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` case $UNAME_MACHINE in 9000/31?) HP_ARCH=m68000 ;; 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if test -x /usr/bin/getconf; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case $sc_cpu_version in 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case $sc_kernel_bits in 32) HP_ARCH=hppa2.0n ;; 64) HP_ARCH=hppa2.0w ;; '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi if test "$HP_ARCH" = ""; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if test "$HP_ARCH" = hppa2.0w then set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH=hppa2.0w else HP_ARCH=hppa64 fi fi GUESS=$HP_ARCH-hp-hpux$HPUX_REV ;; ia64:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` GUESS=ia64-hp-hpux$HPUX_REV ;; 3050*:HI-UX:*:*) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } GUESS=unknown-hitachi-hiuxwe2 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) GUESS=hppa1.1-hp-bsd ;; 9000/8??:4.3bsd:*:*) GUESS=hppa1.0-hp-bsd ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) GUESS=hppa1.0-hp-mpeix ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) GUESS=hppa1.1-hp-osf ;; hp8??:OSF1:*:*) GUESS=hppa1.0-hp-osf ;; i*86:OSF1:*:*) if test -x /usr/sbin/sysversion ; then GUESS=$UNAME_MACHINE-unknown-osf1mk else GUESS=$UNAME_MACHINE-unknown-osf1 fi ;; parisc*:Lites*:*:*) GUESS=hppa1.1-hp-lites ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) GUESS=c1-convex-bsd ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) GUESS=c34-convex-bsd ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) GUESS=c38-convex-bsd ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) GUESS=c4-convex-bsd ;; CRAY*Y-MP:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=ymp-cray-unicos$CRAY_REL ;; CRAY*[A-Z]90:*:*:*) echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=t90-cray-unicos$CRAY_REL ;; CRAY*T3E:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=alphaev5-cray-unicosmk$CRAY_REL ;; CRAY*SV1:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=sv1-cray-unicos$CRAY_REL ;; *:UNICOS/mp:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=craynv-cray-unicosmp$CRAY_REL ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE ;; sparc*:BSD/OS:*:*) GUESS=sparc-unknown-bsdi$UNAME_RELEASE ;; *:BSD/OS:*:*) GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE ;; arm:FreeBSD:*:*) UNAME_PROCESSOR=`uname -p` set_cc_for_build if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi else FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf fi ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in amd64) UNAME_PROCESSOR=x86_64 ;; i386) UNAME_PROCESSOR=i586 ;; esac FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL ;; i*:CYGWIN*:*) GUESS=$UNAME_MACHINE-pc-cygwin ;; *:MINGW64*:*) GUESS=$UNAME_MACHINE-pc-mingw64 ;; *:MINGW*:*) GUESS=$UNAME_MACHINE-pc-mingw32 ;; *:MSYS*:*) GUESS=$UNAME_MACHINE-pc-msys ;; i*:PW*:*) GUESS=$UNAME_MACHINE-pc-pw32 ;; *:SerenityOS:*:*) GUESS=$UNAME_MACHINE-pc-serenity ;; *:Interix*:*) case $UNAME_MACHINE in x86) GUESS=i586-pc-interix$UNAME_RELEASE ;; authenticamd | genuineintel | EM64T) GUESS=x86_64-unknown-interix$UNAME_RELEASE ;; IA64) GUESS=ia64-unknown-interix$UNAME_RELEASE ;; esac ;; i*:UWIN*:*) GUESS=$UNAME_MACHINE-pc-uwin ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) GUESS=x86_64-pc-cygwin ;; prep*:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=powerpcle-unknown-solaris2$SUN_REL ;; *:GNU:*:*) # the GNU system GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'` GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'` GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL ;; *:GNU/*:*:*) # other systems with GNU libc and userland GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"` GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC ;; x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*) GUESS="$UNAME_MACHINE-pc-managarm-mlibc" ;; *:[Mm]anagarm:*:*) GUESS="$UNAME_MACHINE-unknown-managarm-mlibc" ;; *:Minix:*:*) GUESS=$UNAME_MACHINE-unknown-minix ;; aarch64:Linux:*:*) set_cc_for_build CPU=$UNAME_MACHINE LIBCABI=$LIBC if test "$CC_FOR_BUILD" != no_compiler_found; then ABI=64 sed 's/^ //' << EOF > "$dummy.c" #ifdef __ARM_EABI__ #ifdef __ARM_PCS_VFP ABI=eabihf #else ABI=eabi #endif #endif EOF cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` eval "$cc_set_abi" case $ABI in eabi | eabihf) CPU=armv8l; LIBCABI=$LIBC$ABI ;; esac fi GUESS=$CPU-unknown-linux-$LIBCABI ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC=gnulibc1 ; fi GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; arm*:Linux:*:*) set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then GUESS=$UNAME_MACHINE-unknown-linux-$LIBC else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi else GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf fi fi ;; avr32*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; cris:Linux:*:*) GUESS=$UNAME_MACHINE-axis-linux-$LIBC ;; crisv32:Linux:*:*) GUESS=$UNAME_MACHINE-axis-linux-$LIBC ;; e2k:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; frv:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; hexagon:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; i*86:Linux:*:*) GUESS=$UNAME_MACHINE-pc-linux-$LIBC ;; ia64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; k1om:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; kvx:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; kvx:cos:*:*) GUESS=$UNAME_MACHINE-unknown-cos ;; kvx:mbr:*:*) GUESS=$UNAME_MACHINE-unknown-mbr ;; loongarch32:Linux:*:* | loongarch64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m32r*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m68*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; mips:Linux:*:* | mips64:Linux:*:*) set_cc_for_build IS_GLIBC=0 test x"${LIBC}" = xgnu && IS_GLIBC=1 sed 's/^ //' << EOF > "$dummy.c" #undef CPU #undef mips #undef mipsel #undef mips64 #undef mips64el #if ${IS_GLIBC} && defined(_ABI64) LIBCABI=gnuabi64 #else #if ${IS_GLIBC} && defined(_ABIN32) LIBCABI=gnuabin32 #else LIBCABI=${LIBC} #endif #endif #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa64r6 #else #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa32r6 #else #if defined(__mips64) CPU=mips64 #else CPU=mips #endif #endif #endif #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) MIPS_ENDIAN=el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) MIPS_ENDIAN= #else MIPS_ENDIAN= #endif #endif EOF cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'` eval "$cc_set_vars" test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } ;; mips64el:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; openrisc*:Linux:*:*) GUESS=or1k-unknown-linux-$LIBC ;; or32:Linux:*:* | or1k*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; padre:Linux:*:*) GUESS=sparc-unknown-linux-$LIBC ;; parisc64:Linux:*:* | hppa64:Linux:*:*) GUESS=hppa64-unknown-linux-$LIBC ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;; PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;; *) GUESS=hppa-unknown-linux-$LIBC ;; esac ;; ppc64:Linux:*:*) GUESS=powerpc64-unknown-linux-$LIBC ;; ppc:Linux:*:*) GUESS=powerpc-unknown-linux-$LIBC ;; ppc64le:Linux:*:*) GUESS=powerpc64le-unknown-linux-$LIBC ;; ppcle:Linux:*:*) GUESS=powerpcle-unknown-linux-$LIBC ;; riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; s390:Linux:*:* | s390x:Linux:*:*) GUESS=$UNAME_MACHINE-ibm-linux-$LIBC ;; sh64*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; sh*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; sparc:Linux:*:* | sparc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; tile*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; vax:Linux:*:*) GUESS=$UNAME_MACHINE-dec-linux-$LIBC ;; x86_64:Linux:*:*) set_cc_for_build CPU=$UNAME_MACHINE LIBCABI=$LIBC if test "$CC_FOR_BUILD" != no_compiler_found; then ABI=64 sed 's/^ //' << EOF > "$dummy.c" #ifdef __i386__ ABI=x86 #else #ifdef __ILP32__ ABI=x32 #endif #endif EOF cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` eval "$cc_set_abi" case $ABI in x86) CPU=i686 ;; x32) LIBCABI=${LIBC}x32 ;; esac fi GUESS=$CPU-pc-linux-$LIBCABI ;; xtensa*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. GUESS=i386-sequent-sysv4 ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION ;; i*86:OS/2:*:*) # If we were able to find 'uname', then EMX Unix compatibility # is probably installed. GUESS=$UNAME_MACHINE-pc-os2-emx ;; i*86:XTS-300:*:STOP) GUESS=$UNAME_MACHINE-unknown-stop ;; i*86:atheos:*:*) GUESS=$UNAME_MACHINE-unknown-atheos ;; i*86:syllable:*:*) GUESS=$UNAME_MACHINE-pc-syllable ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) GUESS=i386-unknown-lynxos$UNAME_RELEASE ;; i*86:*DOS:*:*) GUESS=$UNAME_MACHINE-pc-msdosdjgpp ;; i*86:*:4.*:*) UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL else GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL fi ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL else GUESS=$UNAME_MACHINE-pc-sysv32 fi ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. GUESS=i586-pc-msdosdjgpp ;; Intel:Mach:3*:*) GUESS=i386-pc-mach3 ;; paragon:*:*:*) GUESS=i860-intel-osf1 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4 fi ;; mini*:CTIX:SYS*5:*) # "miniframe" GUESS=m68010-convergent-sysv ;; mc68k:UNIX:SYSTEM5:3.51m) GUESS=m68k-convergent-sysv ;; M680?0:D-NIX:5.3:*) GUESS=m68k-diab-dnix ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) GUESS=m68k-unknown-lynxos$UNAME_RELEASE ;; mc68030:UNIX_System_V:4.*:*) GUESS=m68k-atari-sysv4 ;; TSUNAMI:LynxOS:2.*:*) GUESS=sparc-unknown-lynxos$UNAME_RELEASE ;; rs6000:LynxOS:2.*:*) GUESS=rs6000-unknown-lynxos$UNAME_RELEASE ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) GUESS=powerpc-unknown-lynxos$UNAME_RELEASE ;; SM[BE]S:UNIX_SV:*:*) GUESS=mips-dde-sysv$UNAME_RELEASE ;; RM*:ReliantUNIX-*:*:*) GUESS=mips-sni-sysv4 ;; RM*:SINIX-*:*:*) GUESS=mips-sni-sysv4 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` GUESS=$UNAME_MACHINE-sni-sysv4 else GUESS=ns32k-sni-sysv fi ;; PENTIUM:*:4.0*:*) # Unisys 'ClearPath HMP IX 4000' SVR4/MP effort # says GUESS=i586-unisys-sysv4 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm GUESS=hppa1.1-stratus-sysv4 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. GUESS=i860-stratus-sysv4 ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. GUESS=$UNAME_MACHINE-stratus-vos ;; *:VOS:*:*) # From Paul.Green@stratus.com. GUESS=hppa1.1-stratus-vos ;; mc68*:A/UX:*:*) GUESS=m68k-apple-aux$UNAME_RELEASE ;; news*:NEWS-OS:6*:*) GUESS=mips-sony-newsos6 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if test -d /usr/nec; then GUESS=mips-nec-sysv$UNAME_RELEASE else GUESS=mips-unknown-sysv$UNAME_RELEASE fi ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. GUESS=powerpc-be-beos ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. GUESS=powerpc-apple-beos ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. GUESS=i586-pc-beos ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. GUESS=i586-pc-haiku ;; ppc:Haiku:*:*) # Haiku running on Apple PowerPC GUESS=powerpc-apple-haiku ;; *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat) GUESS=$UNAME_MACHINE-unknown-haiku ;; SX-4:SUPER-UX:*:*) GUESS=sx4-nec-superux$UNAME_RELEASE ;; SX-5:SUPER-UX:*:*) GUESS=sx5-nec-superux$UNAME_RELEASE ;; SX-6:SUPER-UX:*:*) GUESS=sx6-nec-superux$UNAME_RELEASE ;; SX-7:SUPER-UX:*:*) GUESS=sx7-nec-superux$UNAME_RELEASE ;; SX-8:SUPER-UX:*:*) GUESS=sx8-nec-superux$UNAME_RELEASE ;; SX-8R:SUPER-UX:*:*) GUESS=sx8r-nec-superux$UNAME_RELEASE ;; SX-ACE:SUPER-UX:*:*) GUESS=sxace-nec-superux$UNAME_RELEASE ;; Power*:Rhapsody:*:*) GUESS=powerpc-apple-rhapsody$UNAME_RELEASE ;; *:Rhapsody:*:*) GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE ;; arm64:Darwin:*:*) GUESS=aarch64-apple-darwin$UNAME_RELEASE ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac if command -v xcode-select > /dev/null 2> /dev/null && \ ! xcode-select --print-path > /dev/null 2> /dev/null ; then # Avoid executing cc if there is no toolchain installed as # cc will be a stub that puts up a graphical alert # prompting the user to install developer tools. CC_FOR_BUILD=no_compiler_found else set_cc_for_build fi if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_PPC >/dev/null then UNAME_PROCESSOR=powerpc fi elif test "$UNAME_PROCESSOR" = i386 ; then # uname -m returns i386 or x86_64 UNAME_PROCESSOR=$UNAME_MACHINE fi GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE ;; *:QNX:*:4*) GUESS=i386-pc-qnx ;; NEO-*:NONSTOP_KERNEL:*:*) GUESS=neo-tandem-nsk$UNAME_RELEASE ;; NSE-*:NONSTOP_KERNEL:*:*) GUESS=nse-tandem-nsk$UNAME_RELEASE ;; NSR-*:NONSTOP_KERNEL:*:*) GUESS=nsr-tandem-nsk$UNAME_RELEASE ;; NSV-*:NONSTOP_KERNEL:*:*) GUESS=nsv-tandem-nsk$UNAME_RELEASE ;; NSX-*:NONSTOP_KERNEL:*:*) GUESS=nsx-tandem-nsk$UNAME_RELEASE ;; *:NonStop-UX:*:*) GUESS=mips-compaq-nonstopux ;; BS2000:POSIX*:*:*) GUESS=bs2000-siemens-sysv ;; DS/*:UNIX_System_V:*:*) GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "${cputype-}" = 386; then UNAME_MACHINE=i386 elif test "x${cputype-}" != x; then UNAME_MACHINE=$cputype fi GUESS=$UNAME_MACHINE-unknown-plan9 ;; *:TOPS-10:*:*) GUESS=pdp10-unknown-tops10 ;; *:TENEX:*:*) GUESS=pdp10-unknown-tenex ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) GUESS=pdp10-dec-tops20 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) GUESS=pdp10-xkl-tops20 ;; *:TOPS-20:*:*) GUESS=pdp10-unknown-tops20 ;; *:ITS:*:*) GUESS=pdp10-unknown-its ;; SEI:*:*:SEIUX) GUESS=mips-sei-seiux$UNAME_RELEASE ;; *:DragonFly:*:*) DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case $UNAME_MACHINE in A*) GUESS=alpha-dec-vms ;; I*) GUESS=ia64-dec-vms ;; V*) GUESS=vax-dec-vms ;; esac ;; *:XENIX:*:SysV) GUESS=i386-pc-xenix ;; i*86:skyos:*:*) SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'` GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL ;; i*86:rdos:*:*) GUESS=$UNAME_MACHINE-pc-rdos ;; i*86:Fiwix:*:*) GUESS=$UNAME_MACHINE-pc-fiwix ;; *:AROS:*:*) GUESS=$UNAME_MACHINE-unknown-aros ;; x86_64:VMkernel:*:*) GUESS=$UNAME_MACHINE-unknown-esx ;; amd64:Isilon\ OneFS:*:*) GUESS=x86_64-unknown-onefs ;; *:Unleashed:*:*) GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE ;; *:Ironclad:*:*) GUESS=$UNAME_MACHINE-unknown-ironclad ;; esac # Do we have a guess based on uname results? if test "x$GUESS" != x; then echo "$GUESS" exit fi # No uname command or uname output not recognized. set_cc_for_build cat > "$dummy.c" < #include #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #include #if defined(_SIZE_T_) || defined(SIGLOST) #include #endif #endif #endif int main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) #if !defined (ultrix) #include #if defined (BSD) #if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); #else #if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); #else printf ("vax-dec-bsd\n"); exit (0); #endif #endif #else printf ("vax-dec-bsd\n"); exit (0); #endif #else #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname un; uname (&un); printf ("vax-dec-ultrix%s\n", un.release); exit (0); #else printf ("vax-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname *un; uname (&un); printf ("mips-dec-ultrix%s\n", un.release); exit (0); #else printf ("mips-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } echo "$0: unable to guess system type" >&2 case $UNAME_MACHINE:$UNAME_SYSTEM in mips:Linux | mips64:Linux) # If we got here on MIPS GNU/Linux, output extra information. cat >&2 <&2 <&2 </dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = "$UNAME_MACHINE" UNAME_RELEASE = "$UNAME_RELEASE" UNAME_SYSTEM = "$UNAME_SYSTEM" UNAME_VERSION = "$UNAME_VERSION" EOF fi exit 1 # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: cdrdao-cdrdao-f00afb2/config.rpath000066400000000000000000000000001511453746600171710ustar00rootroot00000000000000cdrdao-cdrdao-f00afb2/config.sub000077500000000000000000001154441511453746600166720ustar00rootroot00000000000000#!/usr/bin/sh # Configuration validation subroutine script. # Copyright 1992-2024 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268,SC2162 # see below for rationale timestamp='2024-05-27' # This file 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 3 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, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # https://git.savannah.gnu.org/cgit/config.git/plain/config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. # The "shellcheck disable" line above the timestamp inhibits complaints # about features and limitations of the classic Bourne shell that were # superseded or lifted in POSIX. However, this script identifies a wide # variety of pre-POSIX systems that do not have POSIX shells at all, and # even some reasonably current systems (Solaris 10 as case-in-point) still # have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2024 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try '$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; *local*) # First pass through any local machine types. echo "$1" exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Split fields of configuration type saved_IFS=$IFS IFS="-" read field1 field2 field3 field4 <&2 exit 1 ;; *-*-*-*) basic_machine=$field1-$field2 basic_os=$field3-$field4 ;; *-*-*) # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two # parts maybe_os=$field2-$field3 case $maybe_os in cloudabi*-eabi* \ | kfreebsd*-gnu* \ | knetbsd*-gnu* \ | kopensolaris*-gnu* \ | linux-* \ | managarm-* \ | netbsd*-eabi* \ | netbsd*-gnu* \ | nto-qnx* \ | os2-emx* \ | rtmk-nova* \ | storm-chaos* \ | uclinux-gnu* \ | uclinux-uclibc* \ | windows-* ) basic_machine=$field1 basic_os=$maybe_os ;; android-linux) basic_machine=$field1-unknown basic_os=linux-android ;; *) basic_machine=$field1-$field2 basic_os=$field3 ;; esac ;; *-*) case $field1-$field2 in # Shorthands that happen to contain a single dash convex-c[12] | convex-c3[248]) basic_machine=$field2-convex basic_os= ;; decstation-3100) basic_machine=mips-dec basic_os= ;; *-*) # Second component is usually, but not always the OS case $field2 in # Do not treat sunos as a manufacturer sun*os*) basic_machine=$field1 basic_os=$field2 ;; # Manufacturers 3100* \ | 32* \ | 3300* \ | 3600* \ | 7300* \ | acorn \ | altos* \ | apollo \ | apple \ | atari \ | att* \ | axis \ | be \ | bull \ | cbm \ | ccur \ | cisco \ | commodore \ | convergent* \ | convex* \ | cray \ | crds \ | dec* \ | delta* \ | dg \ | digital \ | dolphin \ | encore* \ | gould \ | harris \ | highlevel \ | hitachi* \ | hp \ | ibm* \ | intergraph \ | isi* \ | knuth \ | masscomp \ | microblaze* \ | mips* \ | motorola* \ | ncr* \ | news \ | next \ | ns \ | oki \ | omron* \ | pc533* \ | rebel \ | rom68k \ | rombug \ | semi \ | sequent* \ | siemens \ | sgi* \ | siemens \ | sim \ | sni \ | sony* \ | stratus \ | sun \ | sun[234]* \ | tektronix \ | tti* \ | ultra \ | unicom* \ | wec \ | winbond \ | wrs) basic_machine=$field1-$field2 basic_os= ;; zephyr*) basic_machine=$field1-unknown basic_os=$field2 ;; *) basic_machine=$field1 basic_os=$field2 ;; esac ;; esac ;; *) # Convert single-component short-hands not valid as part of # multi-component configurations. case $field1 in 386bsd) basic_machine=i386-pc basic_os=bsd ;; a29khif) basic_machine=a29k-amd basic_os=udi ;; adobe68k) basic_machine=m68010-adobe basic_os=scout ;; alliant) basic_machine=fx80-alliant basic_os= ;; altos | altos3068) basic_machine=m68k-altos basic_os= ;; am29k) basic_machine=a29k-none basic_os=bsd ;; amdahl) basic_machine=580-amdahl basic_os=sysv ;; amiga) basic_machine=m68k-unknown basic_os= ;; amigaos | amigados) basic_machine=m68k-unknown basic_os=amigaos ;; amigaunix | amix) basic_machine=m68k-unknown basic_os=sysv4 ;; apollo68) basic_machine=m68k-apollo basic_os=sysv ;; apollo68bsd) basic_machine=m68k-apollo basic_os=bsd ;; aros) basic_machine=i386-pc basic_os=aros ;; aux) basic_machine=m68k-apple basic_os=aux ;; balance) basic_machine=ns32k-sequent basic_os=dynix ;; blackfin) basic_machine=bfin-unknown basic_os=linux ;; cegcc) basic_machine=arm-unknown basic_os=cegcc ;; cray) basic_machine=j90-cray basic_os=unicos ;; crds | unos) basic_machine=m68k-crds basic_os= ;; da30) basic_machine=m68k-da30 basic_os= ;; decstation | pmax | pmin | dec3100 | decstatn) basic_machine=mips-dec basic_os= ;; delta88) basic_machine=m88k-motorola basic_os=sysv3 ;; dicos) basic_machine=i686-pc basic_os=dicos ;; djgpp) basic_machine=i586-pc basic_os=msdosdjgpp ;; ebmon29k) basic_machine=a29k-amd basic_os=ebmon ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson basic_os=ose ;; gmicro) basic_machine=tron-gmicro basic_os=sysv ;; go32) basic_machine=i386-pc basic_os=go32 ;; h8300hms) basic_machine=h8300-hitachi basic_os=hms ;; h8300xray) basic_machine=h8300-hitachi basic_os=xray ;; h8500hms) basic_machine=h8500-hitachi basic_os=hms ;; harris) basic_machine=m88k-harris basic_os=sysv3 ;; hp300 | hp300hpux) basic_machine=m68k-hp basic_os=hpux ;; hp300bsd) basic_machine=m68k-hp basic_os=bsd ;; hppaosf) basic_machine=hppa1.1-hp basic_os=osf ;; hppro) basic_machine=hppa1.1-hp basic_os=proelf ;; i386mach) basic_machine=i386-mach basic_os=mach ;; isi68 | isi) basic_machine=m68k-isi basic_os=sysv ;; m68knommu) basic_machine=m68k-unknown basic_os=linux ;; magnum | m3230) basic_machine=mips-mips basic_os=sysv ;; merlin) basic_machine=ns32k-utek basic_os=sysv ;; mingw64) basic_machine=x86_64-pc basic_os=mingw64 ;; mingw32) basic_machine=i686-pc basic_os=mingw32 ;; mingw32ce) basic_machine=arm-unknown basic_os=mingw32ce ;; monitor) basic_machine=m68k-rom68k basic_os=coff ;; morphos) basic_machine=powerpc-unknown basic_os=morphos ;; moxiebox) basic_machine=moxie-unknown basic_os=moxiebox ;; msdos) basic_machine=i386-pc basic_os=msdos ;; msys) basic_machine=i686-pc basic_os=msys ;; mvs) basic_machine=i370-ibm basic_os=mvs ;; nacl) basic_machine=le32-unknown basic_os=nacl ;; ncr3000) basic_machine=i486-ncr basic_os=sysv4 ;; netbsd386) basic_machine=i386-pc basic_os=netbsd ;; netwinder) basic_machine=armv4l-rebel basic_os=linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony basic_os=newsos ;; news1000) basic_machine=m68030-sony basic_os=newsos ;; necv70) basic_machine=v70-nec basic_os=sysv ;; nh3000) basic_machine=m68k-harris basic_os=cxux ;; nh[45]000) basic_machine=m88k-harris basic_os=cxux ;; nindy960) basic_machine=i960-intel basic_os=nindy ;; mon960) basic_machine=i960-intel basic_os=mon960 ;; nonstopux) basic_machine=mips-compaq basic_os=nonstopux ;; os400) basic_machine=powerpc-ibm basic_os=os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson basic_os=ose ;; os68k) basic_machine=m68k-none basic_os=os68k ;; paragon) basic_machine=i860-intel basic_os=osf ;; parisc) basic_machine=hppa-unknown basic_os=linux ;; psp) basic_machine=mipsallegrexel-sony basic_os=psp ;; pw32) basic_machine=i586-unknown basic_os=pw32 ;; rdos | rdos64) basic_machine=x86_64-pc basic_os=rdos ;; rdos32) basic_machine=i386-pc basic_os=rdos ;; rom68k) basic_machine=m68k-rom68k basic_os=coff ;; sa29200) basic_machine=a29k-amd basic_os=udi ;; sei) basic_machine=mips-sei basic_os=seiux ;; sequent) basic_machine=i386-sequent basic_os= ;; sps7) basic_machine=m68k-bull basic_os=sysv2 ;; st2000) basic_machine=m68k-tandem basic_os= ;; stratus) basic_machine=i860-stratus basic_os=sysv4 ;; sun2) basic_machine=m68000-sun basic_os= ;; sun2os3) basic_machine=m68000-sun basic_os=sunos3 ;; sun2os4) basic_machine=m68000-sun basic_os=sunos4 ;; sun3) basic_machine=m68k-sun basic_os= ;; sun3os3) basic_machine=m68k-sun basic_os=sunos3 ;; sun3os4) basic_machine=m68k-sun basic_os=sunos4 ;; sun4) basic_machine=sparc-sun basic_os= ;; sun4os3) basic_machine=sparc-sun basic_os=sunos3 ;; sun4os4) basic_machine=sparc-sun basic_os=sunos4 ;; sun4sol2) basic_machine=sparc-sun basic_os=solaris2 ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun basic_os= ;; sv1) basic_machine=sv1-cray basic_os=unicos ;; symmetry) basic_machine=i386-sequent basic_os=dynix ;; t3e) basic_machine=alphaev5-cray basic_os=unicos ;; t90) basic_machine=t90-cray basic_os=unicos ;; toad1) basic_machine=pdp10-xkl basic_os=tops20 ;; tpf) basic_machine=s390x-ibm basic_os=tpf ;; udi29k) basic_machine=a29k-amd basic_os=udi ;; ultra3) basic_machine=a29k-nyu basic_os=sym1 ;; v810 | necv810) basic_machine=v810-nec basic_os=none ;; vaxv) basic_machine=vax-dec basic_os=sysv ;; vms) basic_machine=vax-dec basic_os=vms ;; vsta) basic_machine=i386-pc basic_os=vsta ;; vxworks960) basic_machine=i960-wrs basic_os=vxworks ;; vxworks68) basic_machine=m68k-wrs basic_os=vxworks ;; vxworks29k) basic_machine=a29k-wrs basic_os=vxworks ;; xbox) basic_machine=i686-pc basic_os=mingw32 ;; ymp) basic_machine=ymp-cray basic_os=unicos ;; *) basic_machine=$1 basic_os= ;; esac ;; esac # Decode 1-component or ad-hoc basic machines case $basic_machine in # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) cpu=hppa1.1 vendor=winbond ;; op50n) cpu=hppa1.1 vendor=oki ;; op60c) cpu=hppa1.1 vendor=oki ;; ibm*) cpu=i370 vendor=ibm ;; orion105) cpu=clipper vendor=highlevel ;; mac | mpw | mac-mpw) cpu=m68k vendor=apple ;; pmac | pmac-mpw) cpu=powerpc vendor=apple ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) cpu=m68000 vendor=att ;; 3b*) cpu=we32k vendor=att ;; bluegene*) cpu=powerpc vendor=ibm basic_os=cnk ;; decsystem10* | dec10*) cpu=pdp10 vendor=dec basic_os=tops10 ;; decsystem20* | dec20*) cpu=pdp10 vendor=dec basic_os=tops20 ;; delta | 3300 | delta-motorola | 3300-motorola | motorola-delta | motorola-3300) cpu=m68k vendor=motorola ;; # This used to be dpx2*, but that gets the RS6000-based # DPX/20 and the x86-based DPX/2-100 wrong. See # https://oldskool.silicium.org/stations/bull_dpx20.htm # https://www.feb-patrimoine.com/english/bull_dpx2.htm # https://www.feb-patrimoine.com/english/unix_and_bull.htm dpx2 | dpx2[23]00 | dpx2[23]xx) cpu=m68k vendor=bull ;; dpx2100 | dpx21xx) cpu=i386 vendor=bull ;; dpx20) cpu=rs6000 vendor=bull ;; encore | umax | mmax) cpu=ns32k vendor=encore ;; elxsi) cpu=elxsi vendor=elxsi basic_os=${basic_os:-bsd} ;; fx2800) cpu=i860 vendor=alliant ;; genix) cpu=ns32k vendor=ns ;; h3050r* | hiux*) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) cpu=m68000 vendor=hp ;; hp9k3[2-9][0-9]) cpu=m68k vendor=hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) cpu=hppa1.1 vendor=hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; i*86v32) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv32 ;; i*86v4*) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv4 ;; i*86v) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv ;; i*86sol2) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=solaris2 ;; j90 | j90-cray) cpu=j90 vendor=cray basic_os=${basic_os:-unicos} ;; iris | iris4d) cpu=mips vendor=sgi case $basic_os in irix*) ;; *) basic_os=irix4 ;; esac ;; miniframe) cpu=m68000 vendor=convergent ;; *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) cpu=m68k vendor=atari basic_os=mint ;; news-3600 | risc-news) cpu=mips vendor=sony basic_os=newsos ;; next | m*-next) cpu=m68k vendor=next ;; np1) cpu=np1 vendor=gould ;; op50n-* | op60c-*) cpu=hppa1.1 vendor=oki basic_os=proelf ;; pa-hitachi) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; pbd) cpu=sparc vendor=tti ;; pbb) cpu=m68k vendor=tti ;; pc532) cpu=ns32k vendor=pc532 ;; pn) cpu=pn vendor=gould ;; power) cpu=power vendor=ibm ;; ps2) cpu=i386 vendor=ibm ;; rm[46]00) cpu=mips vendor=siemens ;; rtpc | rtpc-*) cpu=romp vendor=ibm ;; sde) cpu=mipsisa32 vendor=sde basic_os=${basic_os:-elf} ;; simso-wrs) cpu=sparclite vendor=wrs basic_os=vxworks ;; tower | tower-32) cpu=m68k vendor=ncr ;; vpp*|vx|vx-*) cpu=f301 vendor=fujitsu ;; w65) cpu=w65 vendor=wdc ;; w89k-*) cpu=hppa1.1 vendor=winbond basic_os=proelf ;; none) cpu=none vendor=none ;; leon|leon[3-9]) cpu=sparc vendor=$basic_machine ;; leon-*|leon[3-9]-*) cpu=sparc vendor=`echo "$basic_machine" | sed 's/-.*//'` ;; *-*) saved_IFS=$IFS IFS="-" read cpu vendor <&2 exit 1 ;; esac ;; esac # Here we canonicalize certain aliases for manufacturers. case $vendor in digital*) vendor=dec ;; commodore*) vendor=cbm ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if test x"$basic_os" != x then # First recognize some ad-hoc cases, or perhaps split kernel-os, or else just # set os. obj= case $basic_os in gnu/linux*) kernel=linux os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'` ;; os2-emx) kernel=os2 os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'` ;; nto-qnx*) kernel=nto os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'` ;; *-*) saved_IFS=$IFS IFS="-" read kernel os <&2 fi ;; *) echo "Invalid configuration '$1': OS '$os' not recognized" 1>&2 exit 1 ;; esac case $obj in aout* | coff* | elf* | pe*) ;; '') # empty is fine ;; *) echo "Invalid configuration '$1': Machine code format '$obj' not recognized" 1>&2 exit 1 ;; esac # Here we handle the constraint that a (synthetic) cpu and os are # valid only in combination with each other and nowhere else. case $cpu-$os in # The "javascript-unknown-ghcjs" triple is used by GHC; we # accept it here in order to tolerate that, but reject any # variations. javascript-ghcjs) ;; javascript-* | *-ghcjs) echo "Invalid configuration '$1': cpu '$cpu' is not valid with os '$os$obj'" 1>&2 exit 1 ;; esac # As a final step for OS-related things, validate the OS-kernel combination # (given a valid OS), if there is a kernel. case $kernel-$os-$obj in linux-gnu*- | linux-android*- | linux-dietlibc*- | linux-llvm*- \ | linux-mlibc*- | linux-musl*- | linux-newlib*- \ | linux-relibc*- | linux-uclibc*- | linux-ohos*- ) ;; uclinux-uclibc*- | uclinux-gnu*- ) ;; managarm-mlibc*- | managarm-kernel*- ) ;; windows*-msvc*-) ;; -dietlibc*- | -llvm*- | -mlibc*- | -musl*- | -newlib*- | -relibc*- \ | -uclibc*- ) # These are just libc implementations, not actual OSes, and thus # require a kernel. echo "Invalid configuration '$1': libc '$os' needs explicit kernel." 1>&2 exit 1 ;; -kernel*- ) echo "Invalid configuration '$1': '$os' needs explicit kernel." 1>&2 exit 1 ;; *-kernel*- ) echo "Invalid configuration '$1': '$kernel' does not support '$os'." 1>&2 exit 1 ;; *-msvc*- ) echo "Invalid configuration '$1': '$os' needs 'windows'." 1>&2 exit 1 ;; kfreebsd*-gnu*- | knetbsd*-gnu*- | netbsd*-gnu*- | kopensolaris*-gnu*-) ;; vxworks-simlinux- | vxworks-simwindows- | vxworks-spe-) ;; nto-qnx*-) ;; os2-emx-) ;; rtmk-nova-) ;; *-eabi*- | *-gnueabi*-) ;; none--*) # None (no kernel, i.e. freestanding / bare metal), # can be paired with an machine code file format ;; -*-) # Blank kernel with real OS is always fine. ;; --*) # Blank kernel and OS with real machine code file format is always fine. ;; *-*-*) echo "Invalid configuration '$1': Kernel '$kernel' not known to work with OS '$os'." 1>&2 exit 1 ;; esac # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. case $vendor in unknown) case $cpu-$os in *-riscix*) vendor=acorn ;; *-sunos* | *-solaris*) vendor=sun ;; *-cnk* | *-aix*) vendor=ibm ;; *-beos*) vendor=be ;; *-hpux*) vendor=hp ;; *-mpeix*) vendor=hp ;; *-hiux*) vendor=hitachi ;; *-unos*) vendor=crds ;; *-dgux*) vendor=dg ;; *-luna*) vendor=omron ;; *-genix*) vendor=ns ;; *-clix*) vendor=intergraph ;; *-mvs* | *-opened*) vendor=ibm ;; *-os400*) vendor=ibm ;; s390-* | s390x-*) vendor=ibm ;; *-ptx*) vendor=sequent ;; *-tpf*) vendor=ibm ;; *-vxsim* | *-vxworks* | *-windiss*) vendor=wrs ;; *-aux*) vendor=apple ;; *-hms*) vendor=hitachi ;; *-mpw* | *-macos*) vendor=apple ;; *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*) vendor=atari ;; *-vos*) vendor=stratus ;; esac ;; esac echo "$cpu-$vendor${kernel:+-$kernel}${os:+-$os}${obj:+-$obj}" exit # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: cdrdao-cdrdao-f00afb2/configure.ac000066400000000000000000000273101511453746600171670ustar00rootroot00000000000000dnl Process this file with autoconf to produce a configure script. AC_REVISION($Revision: 1.26 $)dnl AC_INIT([cdrdao],[1.2.6]) AC_CONFIG_MACRO_DIRS([m4]) AC_CONFIG_SRCDIR(dao/main.cc) AM_INIT_AUTOMAKE(subdir-objects) AC_CONFIG_HEADERS(config.h) AM_MAINTAINER_MODE AC_CANONICAL_HOST AC_ARG_WITH(pcctsbin,[ --with-pcctsbin=dir set directory of PCCTS parser generator executables],[pcctsbin=$withval],[pcctsbin=default]) AC_ARG_WITH(pcctsinc,[ --with-pcctsinc=dir set directory of PCCTS parser generator includes],[pcctsinc=$withval],[pcctsinc=default]) AC_ARG_WITH(linux-qnx-sched,[ --with-linux-qnx-sched enable QNX real time scheduling for Linux],[AC_DEFINE(LINUX_QNX_SCHEDULING,1,"Use real time scheduling for Linux")]) AC_ARG_WITH(posix-threads,[ --with-posix-threads use Posix threads for ring buffer (default is YES)],[use_pthreads=$withval],[use_pthreads=default]) AC_ARG_WITH(gcdmaster,[ --with-gcdmaster enable build of gcdmaster Gnome GUI front-end (default is YES)],[gcdmaster=$withval],[gcdmaster=default]) AC_ARG_WITH(ogg-support,[ --with-ogg-support enable OGG format support (default is YES)],[],[with_ogg_support=yes]) AC_ARG_WITH(mp3-support,[ --with-mp3-support enable MP3 format support (default is YES)],[],[with_mp3_support=yes]) dnl Checks for programs. AC_PROG_CC AC_PROG_CXX AX_CXX_COMPILE_STDCXX_14 AC_PROG_CPP AC_PROG_INSTALL AC_PROG_RANLIB AM_PROG_AR AC_PROG_MAKE_SET AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) dnl Checks for header files. AC_CHECK_INCLUDES_DEFAULT AC_PROG_EGREP AC_FUNC_ALLOCA AC_HEADER_SYS_WAIT AC_CHECK_HEADERS(fcntl.h getopt.h malloc.h unistd.h sys/mman.h sched.h) dnl Checks for typedefs, structures, and compiler characteristics. AC_C_BIGENDIAN AC_CACHE_CHECK([return type of signal handlers],[ac_cv_type_signal],[AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([#include #include ], [return *(signal (0, 0)) (0) == 1;])], [ac_cv_type_signal=int], [ac_cv_type_signal=void])]) AC_DEFINE_UNQUOTED([RETSIGTYPE],[$ac_cv_type_signal],[Define as the return type of signal handlers (`int' or `void').]) AC_CHECK_SIZEOF(short) AC_CHECK_SIZEOF(int) AC_CHECK_SIZEOF(long) AC_CHECK_SIZEOF(long long) case 2 in $ac_cv_sizeof_short) AC_DEFINE(size16,short,"") SIZE16="short";; $ac_cv_sizeof_int) AC_DEFINE(size16,int,"") SIZE16="int";; esac case 4 in $ac_cv_sizeof_short) SIZE32="short";; $ac_cv_sizeof_int) SIZE32="int";; $ac_cv_sizeof_long) SIZE32="long";; esac AC_CHECK_TYPE(u_int8_t, unsigned char) AC_CHECK_TYPE(int16_t,,AC_DEFINE_UNQUOTED(int16_t,$SIZE16,"")) AC_CHECK_TYPE(int32_t,,AC_DEFINE_UNQUOTED(int32_t,$SIZE32,"")) AC_CHECK_TYPE(u_int16_t,,AC_DEFINE_UNQUOTED(u_int16_t,$SIZE16,"")) AC_CHECK_TYPE(u_int32_t,,AC_DEFINE_UNQUOTED(u_int32_t,$SIZE32,"")) if test -z "$SIZE16"; then AC_MSG_ERROR(No 16 bit type found on this platform!) fi dnl Check for additionally required libraries AC_CHECK_FUNCS(sched_getparam) AC_CHECK_FUNCS(sched_get_priority_max) AC_CHECK_FUNCS(sched_setscheduler) AC_CHECK_LIB(socket,socket,[use_libsocket=yes]) AC_CHECK_LIB(socket,connect,[use_libsocket=yes]) dnl Add 'libsocket' if required if test "$use_libsocket" = yes; then LIBS="$LIBS -lsocket" fi dnl Check if libposix4 must be linked if test "$use_libposix4" = yes; then LIBS="$LIBS -lposix4" fi dnl Checks for library functions. AC_CHECK_FUNCS(strerror) AC_CHECK_FUNCS(mlockall munlockall) AC_CHECK_FUNCS(getpagesize) AC_CHECK_FUNCS(usleep) AC_CHECK_FUNCS(setreuid setregid seteuid setegid setuid setgid) AC_CHECK_FUNCS(inet_aton) dnl check if Posix threads should be used if test "$use_pthreads" = default; then use_pthreads=yes fi if test "$use_pthreads" = yes; then AX_PTHREAD([have_pthread_std=yes],[have_pthread_std=no]) LIBS="$PTHREAD_LIBS $PTHREAD_CFLAGS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS" if test "$have_pthread_std" = yes; then AC_DEFINE(USE_POSIX_THREADS,1,"") thread_libs="" thread_test_lib="" else AC_CHECK_LIB(pthread,pthread_create,have_pthread=yes,have_pthread=no) if test "$have_pthread" = yes; then AC_DEFINE(USE_POSIX_THREADS,1,"") thread_libs="-lpthread" thread_test_lib="pthread" else AC_CHECK_LIB(pthread32,pthread_create,have_pthread32=yes,have_pthread32=no) if test "$have_pthread32" = yes; then AC_DEFINE(USE_POSIX_THREADS) thread_libs="-lpthread32" thread_test_lib="pthread32" else AC_CHECK_LIB(c_r,pthread_create,have_c_r=yes,have_c_r=no) if test "$have_c_r" = yes; then AC_DEFINE(USE_POSIX_THREADS) thread_libs="-lc_r" thread_test_lib="c_r" else use_pthreads=no fi fi fi fi if test "$use_pthreads" = yes; then if test "$have_pthread_std" = yes; then AC_CHECK_FUNCS(pthread_sigmask pthread_attr_setschedpolicy) AC_CHECK_FUNCS(pthread_attr_setschedparam pthread_getschedparam) AC_CHECK_FUNCS(pthread_setschedparam) else AC_CHECK_LIB($thread_test_lib,pthread_sigmask,AC_DEFINE(HAVE_PTHREAD_SIGMASK)) AC_CHECK_LIB($thread_test_lib,pthread_attr_setschedpolicy,AC_DEFINE(HAVE_PTHREAD_ATTR_SETSCHEDPOLICY)) AC_CHECK_LIB($thread_test_lib,pthread_attr_setschedparam,AC_DEFINE(HAVE_PTHREAD_ATTR_SETSCHEDPARAM)) AC_CHECK_LIB($thread_test_lib,pthread_getschedparam,AC_DEFINE(HAVE_PTHREAD_GETSCHEDPARAM)) AC_CHECK_LIB($thread_test_lib,pthread_setschedparam,AC_DEFINE(HAVE_PTHREAD_SETSCHEDPARAM)) fi fi fi if test "$use_pthreads" = yes; then mydefs="-D_THREAD_SAFE -D_REENTRANT $mydefs" fi dnl Checks for pccts parser generator en_pccts="no" if test "$pcctsbin" = default; then antlr_path='$(srcdir)/../pccts/antlr/antlr' dlg_path='$(srcdir)/../pccts/dlg/dlg' en_pccts="yes" else AC_PATH_PROG(antlr_path,antlr,no,$pcctsbin) AC_PATH_PROG(dlg_path,dlg,no,$pcctsbin) if test $antlr_path = "no" || test $dlg_path = "no"; then AC_MSG_WARN([PCCTS: antlr or dlg not found in path, using own.]) antlr_path='$(srcdir)/../pccts/antlr/antlr' dlg_path='$(srcdir)/../pccts/dlg/dlg' en_pccts="yes" fi fi if test "$pcctsinc" = default; then pcctsinc='$(srcdir)/../pccts/h' antlr_path='$(srcdir)/../pccts/antlr/antlr' dlg_path='$(srcdir)/../pccts/dlg/dlg' en_pccts="yes" else ac_save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS -I$pcctsinc" AC_CHECK_HEADER(pcctscfg.h,,[ AC_MSG_WARN([PCCTS: headers not found in path, using own.]) pcctsinc='$(srcdir)/../pccts/h' antlr_path='$(srcdir)/../pccts/antlr/antlr' en_pccts="yes"]) CPPFLAGS="$ac_save_CPPFLAGS" fi utiltools="toc2cue cue2toc" en_cdrdao=yes en_toc2cue=yes en_cue2toc=yes en_toc2mp3=no AC_PATH_LAME(3.100, [utiltools="$utiltools toc2mp3" en_toc2mp3=yes], [echo "Building of toc2mp3 disabled"]) dnl Determine whether we're building the gcdaster GUI front-end en_gcdmaster=no if test "$gcdmaster" = default; then gcdmaster=yes fi if test "$gcdmaster" = yes; then en_gcdmaster=yes PKG_CHECK_MODULES(SIGCPP2, sigc++-2.0 >= 2.0.0,[], [echo "Building of gcdmaster disabled"; en_gcdmaster=no]) PKG_CHECK_MODULES([GTKMM], [gtkmm-3.0], [], [echo "Building of gcdmaster disabled"; en_gcdmaster=no]) fi AM_ICONV if test "$am_func_iconv" = no; then AC_MSG_ERROR("No iconv library found") fi dnl Determine source for scsi interface class scsilib_libs="" case "$host" in *-linux*) scsilib_libs="" scsilib_objs="ScsiIf-linux.o sg_err.o" ;; *-freebsd*) scsilib_libs="-lcam" scsilib_objs="ScsiIf-freebsd-cam.o" ;; *-netbsd* | *-openbsd*) scsilib_libs="-lutil" scsilib_objs="ScsiIf-netbsd.o" ;; *-irix*) scsilib_libs="" scsilib_objs="ScsiIf-irix.o" ;; *-darwin*) scsilib_libs="-framework IOKit -framework CoreFoundation" scsilib_objs="ScsiIf-osx.o" ;; *-pc-cygwin* | *mingw*) scsilib_libs="" scsilib_objs="ScsiIf-nt.o" ;; *) AC_MSG_ERROR([No native SCSI interface for operating system $host_os]) ;; esac dnl Selection of buffer code case "$host" in *) dao_src=dao.cc ;; esac dnl Additional operating system dependent selections case "$host" in *-freebsd*) if test "$use_pthreads" = yes; then LDFLAGS="-pthread $LDFLAGS" dnl -lc_r is automatically done by the linker thread_libs="" fi ;; *darwin*) AC_DEFINE(_P1003_1B_VISIBLE,1,"") LIBS="$LIBS -framework CoreServices -framework IOKit" CXXFLAGS="$CXXFLAGS -std=c++11" ;; *-openbsd*) CPPFLAGS="$CPPFLAGS -I/usr/local/include" LDFLAGS="$LDFLAGS -L/usr/local/lib" ;; esac dnl Sound device selection for xcdrdao case "$host" in *-linux* | *-freebsd* | *-solaris*) sound_if_obj=SoundIF-ao.o ;; *) sound_if_obj=SoundIF-none.o ;; esac dnl Check for libao PKG_CHECK_MODULES(AO, ao >= 0.8, [AC_DEFINE(HAVE_AO,1,"")], [echo "gcdmaster, MP3 and Ogg support disabled"; en_gcdmaster=no; with_ogg_support=no; with_mp3_support=no]) dnl Check for OGG support if test "$with_ogg_support" = yes; then PKG_CHECK_MODULES(VORBISFILE, vorbisfile >= 1.0, [], [echo "OGG support disabled"; with_ogg_support=no]) fi dnl Check for MP3 support if test "$with_mp3_support" = yes; then PKG_CHECK_MODULES(MAD, mad >= 0.10, [], [echo "libMAD detection via pkg-config failed"; with_mp3_support=no]) if test "$with_mp3_support" = no; then AC_CHECK_LIB(mad, mad_stream_init, [AC_CHECK_HEADER([mad.h])]) if test "$ac_cv_lib_mad_mad_stream_init" = yes; then AC_ARG_VAR(MAD_LIBS,"") AC_ARG_VAR(MAD_CFLAGS,"") MAD_LIBS="-lmad" MAD_CFLAGS="" with_mp3_support=yes else echo "MP3 support disabled"; with_mp3_support=no fi fi fi dnl Check for libao support if test "$with_mp3_support" = yes || test "$with_ogg_support" = yes || test "$en_gcdmaster" = yes; then PKG_CHECK_MODULES(AO, ao >= 0.8, [AC_DEFINE(HAVE_AO,1,"")], [echo "Building of gcdmaster disabled"; en_gcdmaster=no]) fi if test "$with_ogg_support" = yes; then AC_DEFINE(HAVE_OGG_SUPPORT,1,"") fi if test "$with_mp3_support" = yes; then AC_DEFINE(HAVE_MP3_SUPPORT,1,"") fi dnl General platform specific setup case "$host" in *-sysv4*) mydefs="-DUNIXWARE $mydefs" LIBS="$LIBS -L/usr/ucblib -lucb" ;; esac AC_SUBST(en_gcdmaster) AC_SUBST(en_toc2mp3) AC_SUBST(en_toc2cue) AC_SUBST(en_cue2toc) AC_SUBST(en_cdrdao) AC_SUBST(scsilib_libs) AC_SUBST(scsilib_objs) AC_SUBST(pcctsinc) AC_SUBST(dao_src) AC_SUBST(sound_if_obj) AC_SUBST(thread_libs) AC_SUBST(mydefs) AC_SUBST(antlr_path) AC_SUBST(dlg_path) AM_CONDITIONAL([COND_GCDMASTER], [test "$en_gcdmaster" = yes]) AM_CONDITIONAL([COND_TOC2MP3], [test "$en_toc2mp3" = yes]) AM_CONDITIONAL([COND_PCCTS], [test "$en_pccts" = yes]) AM_CONDITIONAL([COND_MP3], [test "$with_mp3_support" = yes]) AM_CONDITIONAL([COND_OGG], [test "$with_ogg_support" = yes]) if test "$en_gcdmaster" = yes; then GLIB_GSETTINGS fi AC_CONFIG_FILES([ trackdb/Makefile dao/Makefile utils/Makefile gcdmaster/Makefile gcdmaster/stock/Makefile paranoia/Makefile pccts/Makefile pccts/antlr/Makefile pccts/dlg/Makefile Makefile specs/cdrdao.fedora.spec ]) AC_OUTPUT echo echo "------------------------------------------------------" echo " Building pccts : $en_pccts" echo " Building cdrdao : $en_cdrdao" echo " OGG support : $with_ogg_support" echo " MP3 support : $with_mp3_support" echo " Building toc2cue : $en_toc2cue" echo " Building cue2toc : $en_cue2toc" echo " Building toc2mp3 : $en_toc2mp3" echo " Building gcdmaster : $en_gcdmaster" echo "------------------------------------------------------" cdrdao-cdrdao-f00afb2/contrib/000077500000000000000000000000001511453746600163365ustar00rootroot00000000000000cdrdao-cdrdao-f00afb2/contrib/mp32dao/000077500000000000000000000000001511453746600176035ustar00rootroot00000000000000cdrdao-cdrdao-f00afb2/contrib/mp32dao/BaseInfo.pm000066400000000000000000000054071511453746600216350ustar00rootroot00000000000000# # 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # #Copyright 2001 Giuseppe Corbelli - cowo@lugbs.linux.it # # This package is inherited by both mp3handler and ogghandler. It simply provides # uniform autoloaded access methods to common information fields. package BaseInfo; use strict; use vars qw($AUTOLOAD); sub new { my ($proto) = shift; my ($class) = ref($proto) || $proto; my ($self) = {}; bless ($self, $class); return $self; } # Autoloads methods with the same name as attribs. Standard args setup. # 1 arg returns the actual value, 2 args to set the new one. sub AUTOLOAD { my ($self) = shift; return if $AUTOLOAD =~ /::DESTROY$/; $AUTOLOAD =~ s/^.*:://; ($AUTOLOAD =~ /^\s*filename\s*$/i) ? $AUTOLOAD = 'Filename' : 1; ($AUTOLOAD =~ /^\s*outfile\s*$/i) ? $AUTOLOAD = 'Outfile' : 1; ($AUTOLOAD =~ /^\s*debug\s*$/i) ? $AUTOLOAD = 'debug' : 1; ($AUTOLOAD =~ /^\s*decoder\s*$/i) ? $AUTOLOAD = 'decoder' : 1; ($AUTOLOAD =~ /^\s*decoder_type\s*$/i) ? $AUTOLOAD = 'decoder_type' : 1; ($AUTOLOAD =~ /^\s*artist\s*$/i) ? $AUTOLOAD = 'Artist' : 1; ($AUTOLOAD =~ /^\s*album\s*$/i) ? $AUTOLOAD = 'Album' : 1; ($AUTOLOAD =~ /^\s*title\s*$/i) ? $AUTOLOAD = 'Title' : 1; ($AUTOLOAD =~ /^\s*avgbr\s*$/i) ? $AUTOLOAD = 'Avgbr' : 1; ($AUTOLOAD =~ /^\s*year\s*$/i) ? $AUTOLOAD = 'Year' : 1; ($AUTOLOAD =~ /^\s*comment\s*$/i) ? $AUTOLOAD = 'Comment' : 1; ($AUTOLOAD =~ /^\s*genre\s*$/i) ? $AUTOLOAD = 'Genre' : 1; ($AUTOLOAD =~ /^\s*durationmm\s*$/i) ? $AUTOLOAD = 'durationMM' : 1; ($AUTOLOAD =~ /^\s*durationss\s*$/i) ? $AUTOLOAD = 'durationSS' : 1; ($AUTOLOAD =~ /^\s*duration\s*$/i) ? $AUTOLOAD = 'duration' : 1; ($AUTOLOAD =~ /^\s*channels\s*$/i) ? $AUTOLOAD = 'channels' : 1; ($AUTOLOAD =~ /^\s*frequency\s*$/i) ? $AUTOLOAD = 'frequency' : 1; ($AUTOLOAD =~ /^\s*debug\s*$/i) ? $AUTOLOAD = 'debug' : 1; ($AUTOLOAD =~ /^\s*error\s*$/i) ? $AUTOLOAD = 'Error' : 1; ($AUTOLOAD =~ /^\s*decoder_type\s*$/i) ? $AUTOLOAD = 'decoder_type' : 1; ($AUTOLOAD =~ /^\s*decoder\s*$/i) ? $AUTOLOAD = 'decoder' : 1; @_ ? $self->{$AUTOLOAD} = shift : return ($self->{$AUTOLOAD}); } 1; cdrdao-cdrdao-f00afb2/contrib/mp32dao/MediaHandler.pm000066400000000000000000000054211511453746600224600ustar00rootroot00000000000000# # 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # #Copyright 2001 Giuseppe Corbelli - cowo@lugbs.linux.it #builds a list of handlers for all mediafiles in a directory package MediaHandler; require mp3handler; require ogghandler; require flachandler; @ISA = qw(mp3handler ogghandler flachandler); use strict; use vars qw ( @ext $AUTOLOAD ); #These are supported media files. Each time a new one is added #its extension is put here and appropriate handler is instantiated in #MediaHandler constructor. @ext = ('.mp3', '.ogg', '.flac'); #2 args: self name and directory name #returns blessed reference #reads all filenames (extensions in @ext) in given directory, #creates an handler for each one and puts istances in $self->{'LIST'} sub new { my ($proto, $dirname) = @_; my ($class) = ref($proto)||$proto; my ($filename, $dh, @filelist, $self); my ($total)=0; $self->{'DIR'} = $dirname; die ("Cannot open directory $dirname\n") if (!opendir (my ($DH), "$dirname")); die ("No write permissions for directory $dirname\n") if (!-w "$dirname"); while ($filename = readdir ($DH)) { next if ( (!-r "$dirname/$filename" ) || (-z "$dirname/$filename") || (-d "$dirname/$filename") ); chomp ($filename); foreach (@ext) { if ($filename =~ m/\Q$_\E/i) { push (@filelist, $filename); $total++; } } } $self->{'TOTAL'} = $total; @filelist=sort(@filelist); foreach $filename (@filelist) { if ($filename =~ m/\.ogg/i) { push (@{$self->{'LIST'}}, ogghandler->new("$dirname/$filename")); } if ($filename =~ m/\.wav/i) { } if ($filename =~ m/\.mp3/i) { push (@{$self->{'LIST'}}, mp3handler->new("$dirname/$filename")); } if ($filename =~ m/\.flac/i) { push (@{$self->{'LIST'}}, flachandler->new("$dirname/$filename")); } } bless ($self, $class); return $self; } sub AUTOLOAD { my ($self) = shift; return if $AUTOLOAD =~ /::DESTROY$/; $AUTOLOAD =~ s/^.*:://; ($AUTOLOAD =~ /^\s*dir\s*$/i) ? $AUTOLOAD = 'DIR' : 1; ($AUTOLOAD =~ /^\s*list\s*$/i) ? $AUTOLOAD = 'LIST' : 1; ($AUTOLOAD =~ /^\s*total\s*$/i) ? $AUTOLOAD = 'TOTAL' : 1; return ($self->{$AUTOLOAD}); } 1; cdrdao-cdrdao-f00afb2/contrib/mp32dao/docs/000077500000000000000000000000001511453746600205335ustar00rootroot00000000000000cdrdao-cdrdao-f00afb2/contrib/mp32dao/docs/README000066400000000000000000000016671511453746600214250ustar00rootroot00000000000000This Perl script automates the process of making CDs from MP3/Ogg/Flac files. It will scan the current directory for MP3/Ogg/Flac files, parse the tags (if present), decode all files to wav and produce: [*] a suitable TOC file for cdrdao (with cd-text info if possible) [*] a list of .inf files for cdrecord with cdtext info (if possible) Some of the code is taken from Joe Steward's mp32dao, using to pad one track with the next. MP3 decoding is done using any of the supported programs: * lame * mpg123 * mpg321 Ogg decoding is done using: * ogg123 Flac decoding is done using: * flac * metaflac (to gather info) In order to use mp32dao you need: -MP3::Info Perl module -Ogg::Vorbis Perl module -Cwd Perl module -FindBin Perl module -Audio::Wav Perl module -Audio::Tools::Time Perl module Please send comments/bug reports to Giuseppe Corbelli mp32dao is distributed as a part of cdrdao (see http://cdrdao.sourceforge.net) cdrdao-cdrdao-f00afb2/contrib/mp32dao/docs/THANKS000066400000000000000000000002071511453746600214450ustar00rootroot00000000000000All the people that helped in developing mp32dao: [*] Kalen Petersen Pointed out a bug in Mediahandler.pm. cdrdao-cdrdao-f00afb2/contrib/mp32dao/docs/UML_diagram.dia000066400000000000000000000063751511453746600233460ustar00rootroot00000000000000‹ķ]ßsŚø}ßæ‚”}”Žml ĶŅLowŚķL;½sÓ½3÷‰F€·ĘņŹ")ū°ū• 1IJ•€““™6?„?}¶ĻwŽ,ŽÄƗ?AėšņŲgį°mf»ECMüp6l’ńżć›AūņŻ/æN|ņVž›q²hÉ#Ā8łmŲž ½=;»¹¹1‚ULćFą/˜žżC‚€œÉµßŻ>zBÉž@„ąžx)h+$ :l‰÷cĘŁ2œäGx,`¼uM‚aūÕ4żjŸ½ūõģαŔ"Q¾‰²ˆXģĖ6±ŠvŚvKžĻ›bŁĪ޽zļ¼ŹŗĢ’PŖ± |ę‡y(NI†m lŪ.{c-Q-Qø–(~<Šœų"4f, $Ģ‚ ¾¤eCÅ äżø—U6ĄŌ‚e1%A\˜ĘŁ8•ėeĘżÉ ŽjŚ=źĘŸˆłč罓3 ·ģée!VuB\ū±?č&?Š×xaU*B„ė»ō'4Žw…o7ī9Ļ[Ļö¤¾m~(ƳBz Ȋņ<ŲՔ…Önå×#Gzö:6ž“z"ĻųÆ_ZoZĒķ-+KNö'Ćö7sϩȲ®Ö'±Ķeīnē¼ü OāŒĒČx‚„³€®C9I,ǽ°{Ė1ŗ„£Ņ€.Fćį†v«g˜ĘJ”}æš29„8sźĻęā^ Ē” S ‹Ø;'į$ ¼‚nĂrŹ(ģD­KvACQ?ĖWO(qeįŁ-£ˆÓ8mb}1™Tu"d¹Ō¹f-i®CĪRE’ÖóŪ\?Å)ć4~ŅWĮ ĢLæJ_6ć¹½ÕFu!“£`$¹tÅäĒ֔,ü`5l/XČāˆx“݊Å*aYɛّŲ’ū’~ĪŌÆŠÕ`P±Æˆ«ćŃÜ÷Tŗ«Ų›—(KņćŽ¾b"±¹é¦öTķ°ņ‰eeP²—Š$÷©†Y^5vo¹†w«!ŽŻŪ¶/ Uµć޾ėõ“Ü„ūŻįärl^Sž29¶Ź#äżA@ö½B,y–ć”c*Rłņ_¬ hø\TDUméKQ9Š=¶¹ä÷@xoP€²ĶkŹ£,¤7GoD©5>€S‘Nh ģ‡sŹ}ł`åŃŃ­+¶=·Ņs)-)_ śÅ³nņ˜JH€öę5唽ьdŃcRč3Sś@iģņ”¾{ó9Œ–ā£ąŽčŗ7ļ]ÉØ80ydĶȾ_Kķx ՀjTe¦+LOabR'&6ŗ!×§GM~(ĄH`$0Ņ‹c¤H~£©ēŽüpŹNšĄKą%šRCx©ŌÕ„‹( ¢>hց¶N†Ģp l>°TͶiøS‡÷@FrÜĪÓ0Ż‹ī¹Ńu;Ž1Šć?PKņ°ż`p|÷ĮW*ƒ’žųą?€’žų^ŗ’ąĖē«ļz†÷„s²j±i+`ÄĻ`”’,}śĄóŪē’ą=¦<`¾ūžžĖQ§Ūžzś5}ģžV'LÅĀźō\­N‰Ė ·¦‘oßM|~ŖF'ØŌāųoÜÕ|ۜ¤ĪI‹Ó#%-S<ą'šų©ń&LAx0AI $PRŻN{Q3MßÅÆ€'qj–ŗŗ8ø>ŃPŅ}ą’Qž}+—­jåźv ×tsŅ!?W×6zn®ļ^8}£kŁN² Lłjø˜ŅüNvOkæ M¦b÷d*‡ŚT¶ÓI²dÜßčĪÜAµU|‡@\ėh·ĒĀPŽåd¾÷łĆDŠ?ĮR+akŪ:l÷Ö'^pˆ•āŽ=Äŗµ/Ó­~µTG÷ČÕa›†DZŻd§%ūŖ#Ék_u¬ŪPG©S[uģs’:ŖEa :¶–Ē¬¾qīvlGžį8†ķvĖ0õø•’<`žµ{†­Ćükõj@ś_$¦Ÿæ:åIž“”vŠ„ķ¶_Ų~aū…ķ¶ßcūPM(čöc°ä¬…3G@ŠĄŌ<&j¾-Å›‡4J yĻE5ļ 0ór1Œ— @QXÉä ( £Ä2׳1×ęs¢³gį,fbę”2€Œ d>d×ŚŠ”Ķ'r g•‰ąeö¦ńׯ(§p®®§pĄF6ޜ„! bĄ°Q€Ķ”Óæ–4ōVĄ p£d/gz0“ŸŠ&ĢX 6ŗzŌå·5<ęYƒ«b‡~p ®‰%øŲ柣l PĆåõČÄt™żp b1˜žŻę{—r44ĶÉē÷§qĀQŻč Ż€n@7 Š—Ø•½Ž Čd²Q]6HJ=ŠFÅÅŠ h4šQC3ęd4O2Ŗ.ö‚d@2 Œź’!ęd4š)£ābĻĒ–ŒÜ†Ķ€f@3žécFB=—p-7O4*®ö†f@3 Ќš±’ĢÉh dTßķ“S ˆD£ŗhä'„é©~ęuĶ;š¼é€t@:jHĒ–šŌŃ`łØ“…äņł€|h«+ČGƒåāń€x@<Ž#ŽJGĶü H¤£Ī;9ū@:(u6ō„v@; ŠŽ:¬éāŃÄ)«Š»ś>¶pä4į€p@8žé|UB=—ŲQ¼ŖA9gŽ\ˆD¢ń¤¢‘2œ¹M|ŠšŲ„ņ”‡NO9ŖCŗŻ€n4ąacK?ĘŹ”Źå+=½r@4žJ4J]Yŗˆ"źõ:P¼9€’¤žČ^żœCčÆ_ZoZ’rm·®% HKN¹åO†ķoīTÉ#yfykÄüPdivĆķœnŁL“@ćq‡Ė“H8 č&–“sÜ ·Ū±£[:, čbä1nź¢FŽi°"ę›.²zĢtąPi®CĪRe “Ž˜ßęś)N§3Ī–įDĘ ߌAäĻYøWfśU6ą˜x?8MæJWć Œ¦lƒźäĒ֔,ü`5l/XČāˆx“݊Å* )ufG~`KīKžQü¼T…®ƒŠ}E,X-ę¾§Ņ]ÅŽ6cĮ½}ÅDbsÓMķ+ØŚaåĖŹ d/;I"īS ³¼jģŽr !ļ VC¼»·m_@«&jǽ}×ė'¹K÷z>Öŗā|tĮ @-š)čų@ė&| u­Qpc&®” öąĢ•™+Ģ\5fęźs-ÅĒj>Š{sÜ÷:Nł-ņįk©Æ”PŖĢtEƒé)Œb@LźÄÄF7äśōØÉÆ“Q, ŒFj6#Eņ›%Ÿu=ņĆ);=j/—ĄKphp|¢”äĒĄ’;ćČū„žŖĮź}ŪMż:\–k śi8Ū½čZ†åvl×0Ė;ø˜ŅōεøÕ63ÆĀ®AęrøM-GĘż-’węĒ `Yq½€žXß<†ņ'sā»he|’‚O0 >ł}Ū:l÷Ö'^pˆ•āÜ=d{aīō«„4śŖ„įō »g;ŚjCĀĢ\—†30,KĘÖW»ŁīiFy­<Üc–Ēo4¢į$Ł£” 4ŹŖaĪĄéKÄč(Œ~Z]cą^ČĄn7 ¬M4§Ńź4ö ÷@ƒ )¼¤ŠŲ5įäfD8g7Ŗ~*•ڲ̂Jy øvq«×·ōO…u®ZX®™`«Æ£Ŗd('°qī^ø®aw¬sĆÖć UĢņ€%Ō1zZ”¶a—t’{žŃn5Ż/‰ņ;åšm6{ūö挏ż*›6ī3Bī“ą¾Cīw\Sį{¤ģ‰ź°AAŌ6zÉ(|`ønł¹vE9ŗ›…‹½,ŖćŃN'óџ±Ų>%֙€IׄٗT³cž >M]ųō摏t]ī!ž³›Ü?]ߙ¼XĀŖ"ńµ„Uź½¢²žk¬¤ž&R*UÕźvl[—¦Ŗäw@P»2±ę ź×wß¾ż\mæ”,e™Fæļvl r 9…œBNQNNY–ņĆŖm lm«¶±žr»†#£=-@w²ÜÓÖ+n;?܄) Sš:WŸŚ™‘ķWŸŚ·$Ų²•‹ŖÆkE°›Lżd+‚ū®¬+‹‚Õ’<¼$xpüĮӀxXŒ%ĮXŒ%ĮXŒ%ĮXŒ%Įŗ–'c‹ē½&ŲĚąg²&øŽ8¦e˜–±(‹‚į(‘‹‚ńĄŖ`ČĘ ¬u©9Ž5aY0( ”JĀŗ`¬ 1˜@LM_luU½žń8k{}ĆÖ¹,ųN¢EmXóx“5–}Ņk‚-GyĖž®įvōlŲo=·ć$Fņ„é&ūz b›cQC_™ģmPń#”ŠA½[ePžåłĻņßLŽżņš[›¬½Rcdrdao-cdrdao-f00afb2/contrib/mp32dao/docs/mp32dao.sgml000066400000000000000000000200511511453746600226620ustar00rootroot00000000000000 mp32dao documentation Corbelli Giuseppe Steward Joe Everything is under GPL. What is it? mp32dao is a simple perl script designed to help you in the task of creating audio CDs from MP3/Ogg/Flac files. It will decode compressed audio files to wav and create a TOC file suitable for burning with cdrdao. Authors The beginning and nowadays</> <para> The creator of mp32dao is <emphasis>Joe Steward</>. He had the idea of track padding. It seems he's not maintaining mp32dao anymore, or at least I'm unable to contact him. </para> <para> My name is <emphasis>Giuseppe Corbelli</> but I bet you saw it on the very first page of this document ;-). I made some hacking on the original program adding CD-Text and Ogg decoding, and reworking all the script. The original track padding code is still here. You should not think of finding a good programming example, though :-). You can contact me at <email>cowo@lugbs.linux.it</>. </para> </sect1> </chapter> <chapter id="features"><title>Features Why you'll love mp32dao</> <para> Suppose you have downloaded a bunch of mp3/ogg/flac files. Suppose you want to burn them on a CD, without those annoying clicks between the tracks and with CD-Text support. This is why you're going to use mp32dao. </para> <para> Samples from the ending of a track are padded together with the beginning of the next to avoid leaving a CD sector half-filled with zeroes. You can avoid clicks between tracks this way. </para> <para> By using tags in the compressed source files (e.g. ALBUM, AUTHOR, TITLE) mp32dao will generate a toc-file with CD-Text info ready to use with cdrdao. If all the source files do not have the same AUTHOR and ALBUM tags the resulting toc will show "Compilation" as title, and "Various Artists" as author. Cdtext support requires the ALBUM, TITLE and ARTIST tags in all the source files. </para> </sect1> </chapter> <chapter id="installation"><title>Installation Requirements</> <para> In order to be able to use <productname>mp32dao</> you must have, installed and working, the following software on your system: <variablelist> <varlistentry><term>Perl interpreter</> <listitem><para> I currently use: <programlisting> Summary of my perl5 (revision 5.0 version 6 subversion 0) configuration: Platform: osname=linux, osvers=2.4.9-xfs, archname=i686-linux uname='linux braveheart.cowo.net 2.4.9-xfs #5 \mar ago 21 23:12:16 edt 2001 i686 unknown ' config_args='' hint=recommended, useposix=true, d_sigaction=define usethreads=undef use5005threads=undef \useithreads=undef usemultiplicity=undef useperlio=undef d_sfio=undef uselargefiles=define use64bitint=undef use64bitall=undef \uselongdouble=undef usesocks=undef </programlisting> and it works for me. Please note I compiled Perl myself, disabling thread support. </para></listitem> </varlistentry> <varlistentry><term>MP3::Info Perl Module</> <listitem><para> It is used to access MP3 informations such as playing length, ID3 tags and more. </para></listitem> </varlistentry> <varlistentry><term>Ogg::Vorbis Perl Module</> <listitem><para> It is used to access Ogg informations such as playing length, comments and more. </para></listitem> </varlistentry> <varlistentry><term>Audio::Wav Perl Module</> <listitem><para> It is used to access Wav file information such as length. </para></listitem> </varlistentry> <varlistentry><term>Audio::Tools::Time Perl Module</> <listitem><para> Almost the same as above. </para></listitem> </varlistentry> <varlistentry><term>FindBin Perl Module</> <listitem><para> It is used to fetch mp32dao.pl location, searching for modules here. You should already have it. </para></listitem> </varlistentry> <varlistentry><term>Cwd Perl Module</> <listitem><para> It is used to fetch current working directory. You should already have it. </para></listitem> </varlistentry> <varlistentry><term>mp3handler.pm, ogghandler.pm, flachandler.pm, MediaHandler.pm, Baseinfo.pm Perl Modules</> <listitem><para> They are part of <productname>mp32dao</> distribution. Leave them in the same directory where mp32dao.pl is or install them in the perl search path. </para></listitem> </varlistentry> </variablelist> </para> </sect1> <sect1><title>Installation You can put the main program file, mp32dao.pl anywhere you like. But it expets to find its components in the perl search path or in its same directory. The needed components are: ogghandler.pm mp3handler.pm flachandler.pm MediaHandler.pm BaseInfo.pm Usage</> <sect1><title>Command line options</> <para>The usage is fairly straightforward: <orderedlist> <listitem><para>put all and only the mp3 and/or ogg and/or flac files you want on the CD in a single directory. </para></listitem> <listitem><para>change to this directory </para></listitem> <listitem><para>launch mp32dao.pl [tocfile]. If you specify a tocfile it will be used to write the file .toc used by cdrdao. If you don't <filename>cd.toc</> will be used. Other arguments are ignored. </para></listitem> </orderedlist> The script should work with all filenames but you'll live happier if you don't name your files like this: <screen>Iced % Earth - Burning ^ Times - [01].mp3</screen> Avoid stupid naming schemes. Please note the program will compose the CD using the files in the same order as their name suggests. I <emphasis>strongly</> advise you to put the tracknumber at the beginning of the filename. Example: <screen> 01-The_Quickening.mp3 02-Heart_Of_Storm.mp3 03-Sworn_In_The_Metal_Wind.mp3 04-The_Song_Of_Air.mp3 05-World_Through_My_Fateless_Eyes.mp3 </screen> </para> </sect1> </chapter> <chapter id="internals"><title>Internals</> <sect1><title>Program structure The Mediahandler constructor takes as input a directory name, scans for all supported media files, and returns a list containing handlers for all common operations, such as wav decoding, information access etc. This info is collected by the three lower level modules mp3handler, ogghandler and flachandler using MP3::Info, Ogg::Vorbis and system program metaflac. The main program builds the TOC. In the distribution you will find a simple UML diagram which should make it somewhat clearer. The future</> <sect1><title>Next release plans</> <para> <variablelist> <varlistentry><term>On-the-fly decoding</term> <listitem><para> No more huge wav files. It should be possible to do the decoding on the fly using a FIFO. </para></listitem> </varlistentry> <varlistentry><term>GUI</term> <listitem><para> Some GUIs using Perl/Tk and/or Perl/GTK. </para></listitem> </varlistentry> <varlistentry><term>Binary</term> <listitem><para> Compile the script to have it available in binary form. </para></listitem> </varlistentry> </variablelist> </para> </sect1> </chapter> <chapter id="troubleshooting"><title>Troubleshooting</> <sect1><title>segfaults and nasty bugs here</> <para>There's no point in writing such a section since I develop high quality software :-)). </para> </sect1> </chapter> <chapter id="developing"><title>Developing</> <sect1><title>Wanna help me?</> <para>I'm working on mp32dao alone. I always need help and knowledge. Please drop me a mail at <email>cowo@lugbs.linux.it</> </para> </sect1> </chapter> </book> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/contrib/mp32dao/flachandler.pm������������������������������������������������0000664�0000000�0000000�00000014165�15114537466�0022413�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # Copyright 2003 Giuseppe Corbelli - cowo@lugbs.linux.it # # This package is inherited by Mediahandler and provides flac info access # and decoding. See the attached UML diagram for access methods. # Everything should be done using methods. package flachandler; require BaseInfo; @ISA = qw(BaseInfo); #use Data::Dumper; use strict; use File::Basename; use vars qw($AUTOLOAD); # 2 Args # 1: self name # 2: scalar containing filename sub new { my ($proto) = shift; my ($class) = ref($proto)||$proto; #Inherit from BaseInfo my $self = $class->SUPER::new(); #Checks on input file $self->Filename(shift); if (! $self->Filename) { $self->Error("No input file defined."); return -1; } if (! -r $self->Filename) { $self->Error("Input file is not readable"); return -1; } if (-z $self->Filename) { $self->Error("Input file has 0 size"); return -1; } #Identify available flac decoder foreach my $dir (split (/\:/, $ENV{'PATH'})) { if ( (-x "$dir/flac") && (-s "$dir/flac") ) { $self->decoder_type('flac'); $self->decoder("$dir/flac"); last; } } if ( !$self->decoder ) { $self->Error("Cannot find any of the supported flac decoders in \$PATH."); return -1; } #Identify available metaflac decoder foreach my $dir (split (/\:/, $ENV{'PATH'})) { if ( (-x "$dir/metaflac") && (-s "$dir/metaflac") ) { $self->metaflac("$dir/metaflac"); last; } } if ( !$self->metaflac ) { $self->Error("Cannot find metaflac program in \$PATH."); return -1; } #Use a pipe to get metaflac data my $cmdline = sprintf ("%s --list --block-type=STREAMINFO,VORBIS_COMMENT %s |", $self->metaflac, $self->Filename); my $pid = open (METAFLAC, $cmdline); if ( (!$pid) or ($pid < 0)) { $self->Error ("Cannot get info from metaflac program."); return -1; } while (<METAFLAC>) { if (m/^\s*comment\[\d+\]\:\s*(\w+)\=(.+)$/) { my $tag = $1; my $value = $2; foreach my $n (qw(artist album title year comment genre)) { if ($n =~ /\Q$tag\E/i) { $self->$n ($value); printf ("%s matches %s value %s\n", $n, $tag, $value); } } } elsif (m/^\s*sample\_rate\:\s*(\d+).*$/) { my $freq = $1; $self->frequency($freq); # printf ("Frequency %d\n", $self->frequency); } elsif (m/^\s*channels\:\s*(\d).*$/) { my $chan = $1; $self->channels($chan); # printf ("Channels %d\n", $self->channels); } elsif (m/^\s*total\ssamples\:\s*(\d+).*$/) { my $samples = $1; my $secs = $samples / $self->frequency; $self->mm($secs / 60); $self->ss($secs % 60); $self->secs($secs); # printf ("MM %d SS %d secs %d\n", $self->mm, $self->ss, $self->secs); } } close (METAFLAC) or warn $! ? "Error closing metaflac pipe: $!" : "Exit status $? from metaflac"; $self->debug(1); bless ($self, $class); return $self; } sub type { return "flac"; } #Decodes the file in mp3handler instance to the file specified as Outputfile in same instance #Use system() and external decoder to do the work. Return value is external tool's one. sub to_wav { my ($self) = shift; my (@temp, $cmdline); if (! -w dirname($self->Filename) ) { $self->Error("Output directory is not writable"); return -1; } printf ("\nDecoding file %s", $self->Filename) if ($self->debug); if (!$self->Outfile) { $_ = $self->Filename; s/\.flac/\.wav/i; $self->Outfile ($_); print ("\n\tNo outputfile defined. Used ".$self->Outfile."\n") if ($self->debug); } else { printf (" to file %s\n", $self->Outfile) if ($self->debug); } if ( (-e $self->Outfile) && (-s $self->Outfile) && ($self->debug) ) { print $self->Outfile." exists, skipping flac decode\n" if ($self->debug); return 0; } if ($self->decoder_type =~ /flac/i) { $cmdline = sprintf ("%s -d -o %s %s", $self->decoder, quotemeta ($self->Outfile), quotemeta ($self->Filename)); } system ("".$cmdline); return $? >> 8; } #No args #Returns 0 sub print_file_info { my ($self) = @_; printf ("\nFilename : %s, type %s\n", $self->Filename, $self->type); printf ("\tArtist name: %s\t", $self->artist); printf ("Album name: %s\t", $self->album); printf ("Song title: %s\n", $self->title); printf ("\tYear: %s\t", $self->year); printf ("Song comment: %s\t", $self->comment); printf ("Genre: %s\n", $self->genre); printf ("\tDuration: %d min and %d sec\t", $self->durationMM, $self->durationSS); printf ("Average Bitrate: %d kb/s\n", $self->Avgbr); printf ("\t%d channel(s), %d HZ", $self->channels, ($self->frequency) * 1000); return 0; } #Arguments # $trackno: Track number # Optional: $filename: filename of .inf file sub write_inf { my ($self) = shift; my ($trackno) = shift; my ($inffilename); if (@_) { $inffilename = shift; } else { $inffilename = $self->Filename; $inffilename =~ s/flac/inf/i; } my ($inffilehandle); open ($inffilehandle, ">$inffilename"); if (!$inffilehandle) {last}; my (@tl) = localtime (time ()); $_ = sprintf ("#Created by mp32dao.pl on %02d/%02d/%d %02d:%02d:%02d\n", $tl[3], $tl[4]+1, $tl[5]+1900, $tl[2], $tl[1], $tl[0]); print $inffilehandle $_; print $inffilehandle "#Source file is ".$self->Filename."\n"; print $inffilehandle "#Report bugs to Giuseppe \"Cowo\" Corbelli <cowo\@lugbs.linux.it>\n\n"; print $inffilehandle "Performer=\t'".$self->Artist."'\n"; print $inffilehandle "Tracktitle=\t'".$self->Title."'\n"; print $inffilehandle "Albumtitle=\t'".$self->Album."'\n"; print $inffilehandle "Tracknumber=\t".($trackno)."\n"; close ($inffilehandle); } 1; �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/contrib/mp32dao/mp32dao.pl����������������������������������������������������0000664�0000000�0000000�00000012712�15114537466�0021410�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/perl # # 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #Modified version of the original mp32dao distributed with cdrdao. #Now with cdtext, mp3 and ogg support #Support for cdrecord: builds .inf files #Giuseppe Corbelli <cowo@lugbs.linux.it> #Original code by Joe Steward <mp32dao@httptech.com> use FindBin; use lib $FindBin::Bin; use Cwd; use strict; use MediaHandler; use Audio::Wav; use Audio::Tools::Time; my $wav = new Audio::Wav; my ($count, $totalsamples, $divided, $rounded, $remainder, $artist, $album, $total, $song, $fh); my $cdtext = 1; my $samplestart = 0; my (@tracklist, @filelist); print "-------- MP3-to-DAO Helper Script ---------\n"; print "Usage: mp32dao.pl [tocfile]\n"; my $tocfile = $ARGV[0]; unless ($tocfile) { $tocfile = "cd.toc"; warn "No toc file specified, using default \"cd.toc\"\n"; } my ($list) = MediaHandler->new (getcwd()); die "No supported media files found!\n" if ($list->total == 0); #Creates array of mediahandlers, sets artist and album. foreach my $file (@{$list->list}) { if (!$file->artist || !$file->title || !$file->album) {$cdtext = 0}; #Sets artist and album name if ($cdtext) { #If artist is still not defined define as in first song tag if (!$artist) { $artist=$file->artist; } #If different artists mark as VVAA if ( ! $artist =~ /\s*\Q$file->artist\E\s*/i) { $artist = "Various Artists"; } #Same for album name if (!$album) { $album = $file->album } if (! $album =~ m/\Q$file->album\E/i) {$album = "Compilation"}; } } open ($fh, ">$tocfile") or die "Couldn't open $tocfile for write!\n"; tocfile_header($fh, $cdtext, $album, $artist); #Set outputfiles and decode to wav. print "\nDecoding compressed files to wav\n"; foreach my $file (@{$list->list}) { if ( $_=($file->to_wav) != 0 ) { printf ("\n\tWARNING: decoder for file %s exited with code %d\n", $file->Filename, $_); } } $count=0; print "\nAnalyzing wav files and creating toc\n\n"; while ($count <= ($list->total-1)) { my $file = ${$list->list}[$count]; my $read = $wav->read($file->Outfile); my $audio_bytes = $read->length; my $time = Audio::Tools::Time->new (44100, 16, 2); my $sample = $time->bytes_to_samples($audio_bytes); tocfile_entry ($fh, $cdtext, $file, $samplestart, $count+1); #if ($cdtext) {build_inf ($file, $count)}; if ($cdtext) {$file->write_inf ($count+1)}; $totalsamples = $sample - $samplestart; $divided = $totalsamples / 588; $rounded = int($divided) * 588; $remainder = $totalsamples - $rounded; printf ("\tNeed to pad up %d samples for track %d\n", $remainder, $count+1); if (($remainder != 0) && ($count ne ($list->total-1))) { my $nextfile = ${$list->list}[$count+1]; print $fh "FILE \"".$nextfile->Outfile."\" "; print $fh "0 $remainder\n\n"; $samplestart = $remainder; } $count++; } print "\nFinished writing TOC/inf files. You may now burn the CD using\n\ \tcdrdao write $tocfile\ \tcdrecord dev=X,Y,Z -useinfo -dao -text -audio *.wav\n\n"; print "You may want to normalize wav files right now.\n"; close ($fh); exit; sub seconds_to_cd_time { my $seconds = shift; my ($minutes, $frames); my $minute_increment = int($seconds / 60); if ($minute_increment) { $seconds = $seconds - ($minute_increment * 60); $minutes = $minutes + $minute_increment; } my $decimal = $seconds - int($seconds); if ($decimal) { $frames = int($decimal * 75); } return sprintf ("%02d:%02d:%02d", $minutes, $seconds, $frames); } #Arguments: # fh: filehandle opened for writing # cdtext: if != 0 cdtext info wanted # title: only if cdtext wanted, is the album title # performer: only if cdtext wanted, is the album performer sub tocfile_header { my ($fh, $cdtext, $title, $performer) = @_; print $fh "CD_DA\n"; if ($cdtext) { print $fh "CD_TEXT \{\n"; print $fh "\tLANGUAGE_MAP \{\n"; print $fh "\t\t0 : EN\n"; print $fh "\t\}\n\n"; print $fh "\tLANGUAGE 0 \{\n"; print $fh "\t\tTITLE \"$title\"\n"; print $fh "\t\tPERFORMER \"$performer\"\n"; #print $fh "\t\tDISC_ID \"XY12345\"\n"; #print $fh "\t\tUPC_EAN \"\"\n"; print $fh "\t\}\n"; print $fh "\}\n"; } } #Arguments: # fh: Filehandle opened for writing # cdtext: scalar != 0 if cdtext ON # song: reference to song structure # samplestart: scalar containing sample offset # count: track number sub tocfile_entry { my ($fh, $cdtext, $song, $samplestart, $count) = @_; print $fh "// Track $count\n"; print $fh "TRACK AUDIO\n"; print $fh "TWO_CHANNEL_AUDIO\n"; if ($cdtext) { print $fh "CD_TEXT {\n"; print $fh "\tLANGUAGE 0 {\n"; print $fh "\t\tTITLE \"".$song->title."\"\n"; print $fh "\t\tPERFORMER \"".$song->artist."\"\n"; #print $fh "\t\tISRC \"US-XX1-98-01234\"\n"; print $fh "\t}\n}\n"; } print $fh "FILE \"".$song->Outfile."\" "; print $fh "$samplestart"; print $fh "\n"; } ������������������������������������������������������cdrdao-cdrdao-f00afb2/contrib/mp32dao/mp3handler.pm�������������������������������������������������0000664�0000000�0000000�00000013305�15114537466�0022200�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # #Copyright 2001 Giuseppe Corbelli - cowo@lugbs.linux.it # # This package is inherited by Mediahandler and provides mp3 info access # and decoding. See the attached UML diagram for access methods. # Everything should be done using methods. package mp3handler; require BaseInfo; @ISA = qw(BaseInfo); use MP3::Info; #use Data::Dumper; use strict; use File::Basename; use vars qw($AUTOLOAD); # 2 Args # 1: self name # 2: scalar containing filename sub new { my ($proto) = shift; my ($class) = ref($proto)||$proto; #Inherit from BaseInfo my $self = $class->SUPER::new(); #Checks on input file $self->Filename(shift); if (! $self->Filename) { $self->Error("No input file defined."); return -1; } if (! -r $self->Filename) { $self->Error("Input file is not readable"); return -1; } if (-z $self->Filename) { $self->Error("Input file has 0 size"); return -1; } #Identify available mp3 decoder foreach my $dir (split (/\:/, $ENV{'PATH'})) { if ( (-x "$dir/lame") && (-s "$dir/lame") ) { $self->decoder_type('lame'); $self->decoder("$dir/lame"); last; } if ( (-x "$dir/mpg321") && (-s "$dir/mpg321") ) { $self->decoder_type('mpg321'); $self->decoder("$dir/mpg321"); last; } if ( (-x "$dir/mpg123") && (-s "$dir/mpg123") ) { $self->decoder_type('mpg123'); $self->decoder("$dir/mpg123"); last; } } if ( !$self->decoder ) { $self->Error("Cannot find any of the supported mp3 decoders in \$PATH."); return -1; } my $ID3tagref = MP3::Info::get_mp3tag ($self->Filename); my $MP3info = MP3::Info::get_mp3info ($self->Filename); #First try the lowercase version, then the first char uppercase, last the all-uppercase foreach my $n (qw(artist album title bitrate year comment genre mm ss secs frequency)) { if ($ID3tagref->{$n}) { $self->$n ($ID3tagref->{"$n"}); } elsif ($ID3tagref->{"\u$n"}) { $self->$n ($ID3tagref->{"\u$n"}); } elsif ($ID3tagref->{"\U$n"}) { $self->$n ($ID3tagref->{"\U$n"}); } else { $self->$n (''); } } $MP3info->{"STEREO"} ? $self->channels(2) : $self->channels(1); $self->debug(1); bless ($self, $class); return $self; } sub type { return "mp3"; } #Decodes the file in mp3handler instance to the file specified as Outputfile in same instance #Use system() and external decoder to do the work. Return value is external tool's one. sub to_wav { my ($self) = shift; my (@temp, $cmdline); if (! -w dirname($self->Filename) ) { $self->Error("Output directory is not writable"); return -1; } printf ("\nDecoding file %s", $self->Filename) if ($self->debug); if (!$self->Outfile) { $_ = $self->Filename; s/\.mp3/\.wav/i; $self->Outfile ($_); print ("\n\tNo outputfile defined. Used ".$self->Outfile."\n") if ($self->debug); } else { printf (" to file %s\n", $self->Outfile) if ($self->debug); } if ( (-e $self->Outfile) && (-s $self->Outfile) && ($self->debug) ) { print $self->Outfile." exists, skipping mp3 decode\n" if ($self->debug); return 0; } if ($self->decoder_type =~ /lame/i) { $cmdline = $self->decoder." --decode --mp3input -S ".quotemeta ($self->Filename)." ".quotemeta ($self->Outfile); } elsif ($self->decoder_type =~ /mpg321/i) { $cmdline = $self->decoder." -q -w ".quotemeta ($self->Outfile)." ".quotemeta ($self->Filename); } else { $cmdline = $self->decoder." -q -s ".quotemeta ($self->Filename)." \> ".quotemeta ($self->Outfile); } system ("".$cmdline); return $? >> 8; } #No args #Returns 0 sub print_file_info { my ($self) = @_; printf ("\nFilename : %s, type %s\n", $self->Filename, $self->type); printf ("\tArtist name: %s\t", $self->artist); printf ("Album name: %s\t", $self->album); printf ("Song title: %s\n", $self->title); printf ("\tYear: %s\t", $self->year); printf ("Song comment: %s\t", $self->comment); printf ("Genre: %s\n", $self->genre); printf ("\tDuration: %d min and %d sec\t", $self->durationMM, $self->durationSS); printf ("Average Bitrate: %d kb/s\n", $self->Avgbr); printf ("\t%d channel(s), %d HZ", $self->channels, ($self->frequency) * 1000); return 0; } #Arguments # $trackno: Track number # Optional: $filename: filename of .inf file sub write_inf { my ($self) = shift; my ($trackno) = shift; my ($inffilename); if (@_) { $inffilename = shift; } else { $inffilename = $self->Filename; $inffilename =~ s/mp3/inf/i; } my ($inffilehandle); open ($inffilehandle, ">$inffilename"); if (!$inffilehandle) {last}; my (@tl) = localtime (time ()); $_ = sprintf ("#Created by mp32dao.pl on %02d/%02d/%d %02d:%02d:%02d\n", $tl[3], $tl[4]+1, $tl[5]+1900, $tl[2], $tl[1], $tl[0]); print $inffilehandle $_; print $inffilehandle "#Source file is ".$self->Filename."\n"; print $inffilehandle "#Report bugs to Giuseppe \"Cowo\" Corbelli <cowo\@lugbs.linux.it>\n\n"; print $inffilehandle "Performer=\t'".$self->Artist."'\n"; print $inffilehandle "Tracktitle=\t'".$self->Title."'\n"; print $inffilehandle "Albumtitle=\t'".$self->Album."'\n"; print $inffilehandle "Tracknumber=\t".($trackno)."\n"; close ($inffilehandle); } 1; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/contrib/mp32dao/ogghandler.pm�������������������������������������������������0000664�0000000�0000000�00000012160�15114537466�0022253�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # #Copyright 2001 Giuseppe Corbelli - cowo@lugbs.linux.it # Please look at mp3handler.pm for comments. This is almost the same, # only difference is Ogg::Vorbis backend package ogghandler; require BaseInfo; @ISA = qw(BaseInfo); use strict; #use Data::Dumper; use vars qw($AUTOLOAD); use Ogg::Vorbis; use File::Basename; # 1 Arg, scalar containing filename sub new { my ($proto) = shift; my ($class) = ref($proto)||$proto; my $self = $class->SUPER::new(); $self->Filename(shift); if (! $self->Filename) { $self->Error("No input file defined."); return -1; } if (! -r $self->Filename) { $self->Error("Input file is not readable"); return -1; } if (-z $self->Filename) { $self->Error("Input file has 0 size"); return -1; } #Identify available ogg decoder foreach my $dir (split (/\:/, $ENV{'PATH'})) { if ( (-x "$dir/ogg123") && (-s "$dir/ogg123") ) { $self->decoder_type('ogg123'); $self->decoder("$dir/ogg123"); last; } } if ( !$self->decoder ) { $self->Error("Cannot find any of the supported ogg decoders in \$PATH."); return -1; } open (my ($fh), "<".$self->Filename); my $handle = Ogg::Vorbis->new; $handle->open ($fh); #First try the lowercase version, then the first char uppercase, last the all-uppercase foreach my $n (qw(artist album title date comment genre)) { if ($handle->comment->{$n}) { $self->$n ($handle->comment->{"$n"}); } elsif ($handle->comment->{"\u$n"}) { $self->$n ($handle->comment->{"\u$n"}); } elsif ($handle->comment->{"\U$n"}) { $self->$n ($handle->comment->{"\U$n"}); } else { $self->$n (''); } } $self->Avgbr($handle->bitrate); $self->durationMM($handle->time_total/60); $self->durationSS($handle->time_total%60); $self->duration($handle->time_total); $self->channels($handle->info->channels); $self->frequency($handle->info->rate); $self->debug(1); bless ($self, $class); return $self; } sub type { return 'ogg'; } sub print_file_info { my ($self) = @_; printf ("\nFilename : %s, type %s\n", $self->Filename, $self->type); printf ("\tArtist name: %s\t", $self->artist); printf ("Album name: %s\t", $self->album); printf ("Song title: %s\n", $self->title); printf ("\tYear: %s\t", $self->year); printf ("Song comment: %s\t", $self->comment); printf ("Genre: %s\n", $self->genre); printf ("\tDuration: %d min and %d sec\t", $self->durationMM, $self->durationSS); printf ("Average Bitrate: %d kb/s\n", $self->Avgbr/1024); printf ("\t%d channel(s), %d HZ", $self->channels, $self->frequency); return 0; } sub to_wav { my ($self) = shift; my (@temp, $cmdline); if (! -w dirname($self->Filename) ) { $self->Error("Output directory is not writable"); return -1; } printf ("\nDecoding file %s", $self->Filename) if ($self->debug); if (!$self->Outfile) { $_ = $self->Filename; s/\.ogg/\.wav/i; $self->Outfile ($_); print ("\n\tNo outputfile defined. Used ".$self->Outfile."\n") if ($self->debug); } else { printf (" to file %s\n", $self->Outfile) if ($self->debug); } if ( (-e $self->Outfile) && (-s $self->Outfile) && ($self->debug) ) { print $self->Outfile." exists, skipping mp3 decode\n" if ($self->debug); return 0; } if ($self->decoder_type =~ /ogg123/i) { $cmdline = $self->decoder." -q -d wav -f ".quotemeta ($self->Outfile)." ".quotemeta ($self->Filename); } #print $cmdline; #my ($ret)=(system ("".$cmdline))/256; #print "$ret"; #return $? >> 8; return (system ("".$cmdline))/256; } #Arguments # $trackno: Track number # Optional: $filename: filename of .inf file sub write_inf { my ($self) = shift; my ($trackno) = shift; my ($inffilename); if (@_) { $inffilename = shift; } else { $inffilename = $self->Filename; $inffilename =~ s/ogg/inf/i; } my ($inffilehandle); open ($inffilehandle, ">$inffilename"); if (!$inffilehandle) {last}; my (@tl) = localtime (time ()); $_ = sprintf ("#Created by mp32dao.pl on %02d/%02d/%d %02d:%02d:%02d\n", $tl[3], $tl[4]+1, $tl[5]+1900, $tl[2], $tl[1], $tl[0]); print $inffilehandle $_; print $inffilehandle "#Source file is ".$self->Filename."\n"; print $inffilehandle "#Report bugs to Giuseppe \"Cowo\" Corbelli <cowo\@lugbs.linux.it>\n\n"; print $inffilehandle "Performer=\t'".$self->Artist."'\n"; print $inffilehandle "Tracktitle=\t'".$self->Title."'\n"; print $inffilehandle "Albumtitle=\t'".$self->Album."'\n"; print $inffilehandle "Tracknumber=\t".($trackno)."\n"; close ($inffilehandle); } 1; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/contrib/psxcopy-0.2/����������������������������������������������������������0000775�0000000�0000000�00000000000�15114537466�0020340�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/contrib/psxcopy-0.2/Makefile��������������������������������������������������0000664�0000000�0000000�00000001001�15114537466�0021770�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Makefile - Fabio Baracca # CC = gcc #-DDEBUG #-ggdb CFLAGS = -O2 -s -fno-strength-reduce LDFLAGS = CNTFLGS = EDITOR = joe default: cdjob psxdump remainder cdjob: cdjob.c $(CC) $(CFLAGS) cdjob.c -o cdjob psxdump: psxdump.c $(CC) $(CFLAGS) psxdump.c -o psxdump remainder: @echo "Make completed." @echo "Please also execute make batchconf to revise configuration of batch files." batchconf: $(EDITOR) write-psx $(EDITOR) read-psx clean: rm -f *~ rm -f *.o distclean: rm -f psxdump rm -f cdjob�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/contrib/psxcopy-0.2/README����������������������������������������������������0000664�0000000�0000000�00000000267�15114537466�0021225�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������These tools can be used to make backup copies of PSX CDs. The implementation is currently Linux specific. Please send comments/bug reports to Fabio Baracca <fabiobar@tiscalinet.it>. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/contrib/psxcopy-0.2/cdjob.c���������������������������������������������������0000664�0000000�0000000�00000011775�15114537466�0021600�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdjob.c * * Copyright (C) 1999 Fabio Baracca <fabiobar@tiscalinet.it> * * 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. */ #include <stdio.h> #include <string.h> #define BUF_S 1024 #define DATA_SIGN "DATAFILE" #define AUDIO_SIGN "FILE" #define TRACKTYPE_SIGN "TRACK" #define MODE1_SIGN "MODE1" #define MODE2_SIGN "MODE2" #define SECT_SIZE 2048 FILE *inf, *outf, *device; char *fname, *track_info, *cdrom_device; char buf[BUF_S], file_to_read[BUF_S]; int is_data_track = 0, line_count = 0; int i, j, k, x, data_size, chr; int min, sec, frame, size_in_sect, rcode = 0, rem, readin; int audio_begin = 0, audio_end = 0, tracks = 0, prevseek = 0; int main(int argc, char *argv[]) { if (argc != 3) { fprintf(stderr, "Usage: %s <cue-sheet> <cdrom device>\n", argv[0]); return 1; } fname = argv[1]; cdrom_device = argv[2]; inf = (FILE *) fopen(fname, "r+"); if (inf == NULL) { fprintf(stderr, "Unable to open \"%s\" cue-sheet!\n", fname); return 2; } device = (FILE *) fopen(cdrom_device, "r"); /* if (device == NULL) { fprintf(stderr, "Unable to open \"%s\" for reading!\n", cdrom_device); return 4; } fclose (device); */ /* Testing for PSX CD */ sprintf (buf, "psxdump -T -d %s", cdrom_device); i=system (buf); if (i!=0) { fprintf(stderr, "Unable to read from %s or disk is not PSX, please check and retry.\n", cdrom_device); exit (1); } /* Total bytes (about to) read */ readin = 0; printf("cdjob 0.2 - Fabio Baracca <fabiobar@tiscalinet.it>\n\n"); while (!feof(inf)) { prevseek=ftell (inf); fgets(buf, BUF_S, inf); if (!feof(inf)) { line_count++; /* Store data type */ if (strncasecmp(buf, TRACKTYPE_SIGN, strlen(TRACKTYPE_SIGN)) == 0) { if (strstr(buf, MODE1_SIGN)) is_data_track = 1; else if (strstr(buf, MODE2_SIGN)) { /* HACK IT! */ is_data_track = 1; buf[11]=0x20; buf[12]='/'; buf[13]='/'; fseek (inf, prevseek, SEEK_SET); fputs (buf, inf); } else is_data_track = 0; } /* Data to be read.. */ if ((strncasecmp(buf, DATA_SIGN, strlen(DATA_SIGN)) == 0) || (strncasecmp(buf, AUDIO_SIGN, strlen(AUDIO_SIGN)) == 0)) { /* Zero vars */ i = j = k = x = 0; /* Search the name */ for (j = 0, i = 0; i < strlen(buf); i++) { if (buf[i] == '"') { j++; if (j == 1) k = i + 1; else if (j >= 2) { x = i - 1; break; } } } /* Check the name */ if (j != 2) { fprintf(stderr, "Bogus characters at line %d\n", line_count); rcode = 100; } else if ((x - k + 1) > BUF_S) { fprintf(stderr, "Ooppss.. filename too long..\n"); rcode = 101; } else { strcpy(file_to_read, buf + k); /* Track size info */ track_info = buf + x + 2; for (j = 0, i = x + 2; i < strlen(buf); i++) { if (buf[i] == ':') { j++; if (j >= 2) { track_info[i - x + 1] = 0; break; } } } x -= k; file_to_read[++x] = 0; if (!is_data_track) { /* audio ? :-D */ tracks++; if (audio_begin != 0) audio_end = tracks; else audio_begin = tracks; } if (is_data_track) { tracks++; /* printf("About data file: \"%s\"..", file_to_read);*/ if ((sscanf(track_info, "%d:%d:%d", &min, &sec, &frame)) != 3) { printf("bogus size info!\n"); rcode = 102; } else { char toshell[1024]; /* HACK!!! */ size_in_sect = (((min * 60 + sec) * 75 + frame) * SECT_SIZE); track_info[1]=0x20; track_info[2]='/'; track_info[3]='/'; fseek (inf, prevseek, SEEK_SET); fputs (buf, inf); sprintf (toshell, "psxdump -f %s -d %s", file_to_read, cdrom_device); system (toshell); } } else { /* Silenty trash garbage */ /* printf ("mm.. not a data file.. ignoring!\n"); */ /* rcode=200; */ } } } } } fclose(inf); fclose(device); if (audio_begin != 0) { /* Start cdparanoia */ printf("Ok.. now reading audio part of the disk.\n\n"); sprintf(buf, "cdparanoia -z %d- data.wav", audio_begin); if (system(buf) != 0) fprintf(stderr, "\n\nCdparanoia execution error. - CD dump can be corrupted.\n"); } printf ("\n"); return rcode; } ���cdrdao-cdrdao-f00afb2/contrib/psxcopy-0.2/psxdump.c�������������������������������������������������0000664�0000000�0000000�00000016730�15114537466�0022213�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * psxdump.c - Dumps playstation disks to file * * Portions (c) 1999 Fabio Baracca <fabiobar@tiscalinet.it> * * *HEAVILY BASED* on code from readxa.c * that's (c) 1996,1997 Gerd Knorr <kraxel@cs.tu-berlin.de> * */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <getopt.h> #include <fcntl.h> #include <errno.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <linux/cdrom.h> #include <linux/fs.h> /* Ugly, I know.. */ extern char *sys_errlist[]; typedef unsigned char u8bit; typedef unsigned short u16bit; typedef unsigned u32bit; unsigned char psx_sign[] = {0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x43, 0x44, 0x30, 0x30, 0x31, 0x01, 0x00, 0x50, 0x4C, 0x41, 0x59, 0x53, 0x54, 0x41, 0x54, 0x49, 0x4F, 0x4E, 0x20, 0x20, 0x20, 0x20, 0x20}; typedef struct tag_iso_dir_entry { u8bit len_dr; u8bit XAR_len; u32bit loc_extentI; u32bit loc_extentM; u32bit data_lenI; u32bit data_lenM; u8bit record_time[7]; u8bit file_flags_iso; u8bit il_size; u8bit il_skip; u16bit VSSNI; u16bit VSSNM; u8bit len_fi; u8bit file_id[32]; u8bit padding; } iso_dir_entry; iso_dir_entry dir_entry; static const char *device_list[] = { /* try most common first ... */ "/dev/cdrom", "/dev/scd0", "/dev/sr0", "/dev/hdc", "/dev/hdd", "/dev/scd1", "/dev/sr1", "/dev/scd2", "/dev/sr2", "/dev/scd3", "/dev/sr3", "/dev/hda", "/dev/hdb", "/dev/hde", "/dev/hdf", "/dev/hdg", "/dev/hdh", NULL }; int print_info = 0; int dump_raw = 0; void about(void) { fprintf(stderr, "psxdump.c - Dumps playstation disks to file\n\nA quick hack that's (c) 1999 Fabio Baracca <fabiobar@tiscalinet.it>\nLicensed under GNU GPL - *HEAVILY BASED* on code from readxa.c\nthat's (c) 1996,1997 Gerd Knorr <kraxel@cs.tu-berlin.de>\n\n"); } void usage(void) { fprintf(stderr, "syntax: psxdump -d <device> -f <output file>\n\n" " -d <device> give device name\n" " -f <output file> file to put track dump\n" " -F force the program to proceed even if it's not a PSX disk\n" " -T test type of disc (PSX or non) and report it as exit code\n" " -h display this banner :-)\n"); } int read_raw_frame(int fd, int lba, unsigned char *buf) { struct cdrom_msf *msf; int rc; msf = (struct cdrom_msf *) buf; msf->cdmsf_min0 = (lba + CD_MSF_OFFSET) / CD_FRAMES / CD_SECS; msf->cdmsf_sec0 = (lba + CD_MSF_OFFSET) / CD_FRAMES % CD_SECS; msf->cdmsf_frame0 = (lba + CD_MSF_OFFSET) % CD_FRAMES; rc = ioctl(fd, CDROMREADMODE2, buf); if (-1 == rc) perror("ioctl CDROMREADMODE2"); return rc; } int main(int argc, char *argv[]) { int forcepsx = 0, ofile, cdrom, rc, c, size, percent, maxsize, testpsx = 0; unsigned long block; unsigned char *buf; struct stat st, dev_st; int device; long seek = -1; struct cdrom_tocentry toc, toc2; char *outfile = NULL, *devname = NULL; /* parse options */ for (;;) { c = getopt(argc, argv, "TFd:f:"); if (c == -1) break; switch (c) { case 'f': outfile = optarg; break; case 'd': devname = optarg; break; case 'F': forcepsx = 1; break; case 'T': testpsx = 1; break; case 'h': default: usage(); exit(1); } } /* Malloc-ing memory */ if (NULL == (buf = malloc(CD_FRAMESIZE_RAW0))) { fprintf(stderr, "Out of memory\n"); exit(1); } if ((testpsx) && (devname)) { if (-1 == (cdrom = open(devname ? devname : device_list[device], O_RDONLY | O_NONBLOCK))) { fprintf(stderr, "open %s: %s\n", devname ? devname : device_list[device], sys_errlist[errno]); exit(2); } if (0 != (rc = read_raw_frame(cdrom, 16, buf))) { perror("read error"); exit(2); } close(rc); if (memcmp(psx_sign, buf, sizeof(psx_sign)) == 0) exit(0); else exit(1); } about(); if ((!outfile) || (!devname)) { fprintf(stderr, "Please specify *either* the file name (or -T flag) *and* the device of the CD reader.\n\n"); usage(); exit(2); } /* Opening the CDROM reader */ if (-1 == (cdrom = open(devname ? devname : device_list[device], O_RDONLY | O_NONBLOCK))) { fprintf(stderr, "open %s: %s\n", devname ? devname : device_list[device], sys_errlist[errno]); exit(1); } if (!forcepsx) { /* Checking if it's a PSX disk */ printf("Checking if the disk is a PSX disk.."); fflush(stdout); if (0 != (rc = read_raw_frame(cdrom, 16, buf))) { /* Safe PSX signature is at 0x9200 */ perror("read error"); exit(1); } /* Checking PSX signature */ if (memcmp(psx_sign, buf, sizeof(psx_sign)) == 0) { printf("okay, found a PSX disk.\n"); } else { printf("sorry.. this doesn't seem a PSX disk.\n\nIf you think it's a bug, use -F flag and send a dump of the sector 16\nto me, Fabio Baracca <fabiobar@tiscalinet.it>. Thanks!\n"); exit(3); } close(rc); } else { printf("-F specified: assuming that the disk is a PSX disk.\n"); } /* Checking the limits of the track */ if (-1 == (rc = open(devname, O_RDONLY | O_NONBLOCK))) { fprintf(stderr, "open %s: %s\n", devname, sys_errlist[errno]); exit(1); } toc.cdte_track = 1; toc.cdte_format = CDROM_LBA; if (-1 == ioctl(rc, CDROMREADTOCENTRY, &toc)) { perror("ioctl CDROMREADTOCENTRY [start]"); exit(1); } toc2.cdte_track = 2; toc2.cdte_format = CDROM_LBA; if (-1 == ioctl(rc, CDROMREADTOCENTRY, &toc2)) { toc2.cdte_track = CDROM_LEADOUT; toc2.cdte_format = CDROM_LBA; if (-1 == ioctl(rc, CDROMREADTOCENTRY, &toc2)) { perror("ioctl CDROMREADTOCENTRY [stop]"); exit(1); } } block = toc.cdte_addr.lba; /* Should be zero */ if (block) { fprintf(stderr, "Hei!.. S-T-R-A-N-G-E.. starting sector is NOT zero !??!\n"); } size = (toc2.cdte_addr.lba - block) * 2048; close(rc); /* Opening the output file */ if (-1 == (ofile = open(outfile, O_WRONLY | O_CREAT))) { fprintf(stderr, "open %s: %s\n", outfile, sys_errlist[errno]); exit(1); } /* Finnally dump the track */ if (-1 == (rc = open(devname ? devname : device_list[device], O_RDONLY | O_NONBLOCK))) { fprintf(stderr, "open %s: %s\n", devname ? devname : device_list[device], sys_errlist[errno]); exit(1); } if (0 != (rc = read_raw_frame(cdrom, block, buf))) { perror("read error"); exit(1); } printf("\nDumping %d bytes (or maybe a bit less..) to disk..\n", (toc2.cdte_addr.lba - block) * 2336); printf("Please IGNORE any error! Your disk WILL BE OK! 100%% Assured!\n\n"); maxsize = size; percent = 0; /* Status bar */ printf("Completed: %d%%\r", percent); fflush(stdout); for (;;) { int offset, len, tmp; if (buf[0] == buf[4] && buf[1] == buf[5] && buf[2] == buf[6] && buf[3] == buf[7] && buf[2] != 0 && buf[0] < 8 && buf[1] < 8) { offset = 8; len = (buf[2] & 0x20) ? 2324 : 2048; } else { offset = 0; len = 2048; } write(ofile, buf, CD_FRAMESIZE_RAW0); /* dump to disk */ size -= 2048 /* len */ ; block++; if (size <= 0) break; tmp = (int) 100 - (((double) size / (double) maxsize) * 100); if (tmp != percent) { percent = tmp; printf("Completed: %d%%\r", percent); fflush(stdout); } if (0 != (rc = read_raw_frame(cdrom, block, buf))) { perror("read error (hei! the disk is 99.9%% ok if we are in the last part of the disk)"); exit(1); } } printf("PSX data track dump complete.\n"); free(buf); exit(0); } ����������������������������������������cdrdao-cdrdao-f00afb2/contrib/psxcopy-0.2/read-psx��������������������������������������������������0000664�0000000�0000000�00000000400�15114537466�0022000�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh echo read-psx - v.0.3 reader_sg="/dev/sg0" reader_cd="/dev/scd0" if psxdump -T -d $reader_cd then rm -f $1.toc cdrdao read-toc --device $reader_sg $1.toc cp $1.toc $1.toc.backup cdjob $1.toc $reader_cd else echo This is not a PSX disk.. fi����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/contrib/psxcopy-0.2/write-psx�������������������������������������������������0000664�0000000�0000000�00000000322�15114537466�0022222�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh echo write-psx - v.0.4 writer='/dev/sg2' driver='generic-mmc' cdrdao write --device $writer --speed 4 --buffers 128 -v 1 $1.toc cp -f $1.toc.backup $1.toc 2> /dev/null rm -f $1.toc.backup 2> /dev/null��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/contrib/wav2dao/��������������������������������������������������������������0000775�0000000�0000000�00000000000�15114537466�0017701�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/contrib/wav2dao/wav2dao.pl����������������������������������������������������0000664�0000000�0000000�00000003772�15114537466�0021612�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/perl use strict 'subs'; use strict 'refs'; @dev = ('--device', '/dev/pg0:0,0'); sub help { print "Syntax: $0 [-H] [options] audiofiles\n"; print <<"EOF" ; Use cdrdao on the wav audio file arguments, making an appropriate toc file. -d cdrw Use cdrw as the CDRW device (default: $dev[1]). -o file Output the toc file on this file - do not use a temporary file. -p Perform a 'print-size' cdrdao command. -i Perform a 'toc-info' cdrdao command. -c Perform a 'show-toc' cdrdao command. -t Perform a 'read-test' cdrdao command. -w Write the CD in DAO mode (default, if no other action is specified). -s Simulate writing only ('simulate' instead of 'write' command). -j Do not eject the CD after writing it. -n Print the cdrdao commands, instead of executing them. EOF } require 'getopts.pl'; &Getopts('o:pictwsjnH'); if ($opt_H) { &help ; exit } $dev[1] = $opt_d if $opt_d; $opt_w = 1 unless $opt_p || $opt_i || $opt_c || $opt_t || $opt_w || $opt_s || $opt_o ne ""; die "Usage: $0 [options] audiofiles" unless @ARGV; $fname = $opt_o ne "" ? $opt_o : "/tmp/toc$$"; open(F, "> $fname") || die "open($fname): $!, stopped"; print F "CD_DA\n"; foreach (@ARGV) { print F "\nTRACK AUDIO\nNO COPY\n"; # print F "NO PRE_EMPHASIS\nTWO_CHANNEL_AUDIO\n"; print F "FILE \"$_\" 0\n"; # print F "START 00:02:00\n" if $no++; } close F; if ($opt_p) { if ($opt_n) { print "cdrdao print-size $fname\n" } else { system 'cdrdao', 'print-size', $fname} } if ($opt_i) { if ($opt_n) { print "cdrdao toc-info $fname\n" } else { system 'cdrdao', 'toc-info', $fname} } if ($opt_c) { if ($opt_n) { print "cdrdao show-toc $fname\n" } else { system 'cdrdao', 'show-toc', $fname} } if ($opt_t) { if ($opt_n) { print "cdrdao read-test $fname\n" } else { system 'cdrdao', 'read-test', $fname} } if ($opt_w || $opt_s) { unshift @dev, $opt_s ? 'simulate' : 'write'; push @dev, '--eject' unless $opt_s || $opt_j; push @dev, $fname; if ($opt_n) { print "cdrdao @dev\n" } else { system 'cdrdao', @dev } } unlink $fname unless $opt_o ne ""; __END__ ������cdrdao-cdrdao-f00afb2/dao/��������������������������������������������������������������������������0000775�0000000�0000000�00000000000�15114537466�0015441�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/.cvsignore����������������������������������������������������������������0000664�0000000�0000000�00000000042�15114537466�0017435�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������Makefile Makefile.in .deps cdrdao ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/.gitignore����������������������������������������������������������������0000664�0000000�0000000�00000000007�15114537466�0017426�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/CDD2600.cc����������������������������������������������������������������0000664�0000000�0000000�00000050436�15114537466�0016662�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #include <config.h> #include <string.h> #include <assert.h> #include "CDD2600.h" #include "SubChannel.h" #include "PQSubChannel16.h" #include "Toc.h" #include "log.h" CDD2600::CDD2600(ScsiIf *scsiIf, unsigned long options) : CdrDriver(scsiIf, options|OPT_DRV_NO_PREGAP_READ), CDD2600Base(this) { driverName_ = "CDD2600 - Version 1.1"; leadInLength_ = leadOutLength_ = 0; speed_ = 2; simulate_ = true; encodingMode_ = 0; // reads big endian samples audioDataByteOrder_ = 1; memset(&diskInfo_, 0, sizeof(DiskInfo)); } CDD2600::~CDD2600() { } // static constructor CdrDriver *CDD2600::instance(ScsiIf *scsiIf, unsigned long options) { return new CDD2600(scsiIf, options); } // sets speed // return: 0: OK // 1: illegal speed int CDD2600::speed(int s) { if (s >= 0 && s <= 2) { speed_ = s; return 0; } else if (s > 2) { speed_ = 2; return 0; } else { return 1; } } // loads ('unload' == 0) or ejects ('unload' == 1) tray // return: 0: OK // 1: scsi command failed int CDD2600::loadUnload(int unload) const { unsigned char cmd[10]; memset(cmd, 0, 10); cmd[0] = 0xe7; // MEDIUM LOAD/UNLOAD if (unload) { cmd[8] |= 0x01; } if (sendCmd(cmd, 10, NULL, 0, NULL, 0) != 0) { log_message(-2, "Cannot load/unload medium."); return 1; } return 0; } // sets various audio play parameters, output channels are set to stereo mode // and given volume // immediate: 0: wait until audio play command finished // 1: command finishs immediately after playback has started // sotc: 0: play across track boundaries // 1: stop playing at track boundaries int CDD2600::modeSelectPlay(int immediate, int sotc, unsigned char volume) { unsigned char mp[16]; memset(mp, 0, 16); mp[0] = 0x0e; // PLAY page code mp[1] = 14; // parameter length if (immediate != 0) { mp[2] |= 0x04; } if (sotc != 0) { mp[2] |= 0x02; } mp[8] = 1; mp[9] = volume; mp[10] = 2; mp[11] = volume; if (setModePage(mp, NULL, NULL, 1) != 0) { log_message(-2, "Cannot set play parameters."); return 1; } return 0; } int CDD2600::initDao(const Toc *toc) { long n; blockLength_ = AUDIO_BLOCK_LEN; blocksPerWrite_ = scsiIf_->maxDataLen() / blockLength_; assert(blocksPerWrite_ > 0); toc_ = toc; diskInfo(); if (!diskInfo_.valid.empty || !diskInfo_.valid.append) { log_message(-2, "Cannot determine status of inserted medium."); return 1; } if (!diskInfo_.append) { log_message(-2, "Inserted medium is not appendable."); return 1; } if (modeSelectBlockSize(blockLength_, 1) != 0 || modeSelectSpeed(-1, speed_, simulate_, 1) != 0 || modeSelectCatalog(toc_) != 0 || readSessionInfo(&leadInLength_, &leadOutLength_, 1) != 0) { return 1; } // allocate buffer for write zeros n = blocksPerWrite_ * blockLength_; delete[] zeroBuffer_; zeroBuffer_ = new char[n]; memset(zeroBuffer_, 0, n); return 0; } int CDD2600::startDao() { long lba; if (writeSession(toc_, multiSession_, diskInfo_.thisSessionLba) != 0) { return 1; } log_message(2, "Writing lead-in and gap..."); lba = diskInfo_.thisSessionLba - 150 - leadInLength_; // write lead-in if (writeZeros(toc_->leadInMode(), TrackData::SUBCHAN_NONE, lba, lba + 150, leadInLength_) != 0) { flushCache(); return 1; } log_message(5, "Lba after lead-in: %ld", lba); // write gap (2 seconds) if (writeZeros(toc_->leadInMode(), TrackData::SUBCHAN_NONE, lba, lba + 150, 150) != 0) { flushCache(); return 1; } log_message(2, ""); return 0; } int CDD2600::finishDao() { long lba = diskInfo_.thisSessionLba + toc_->length().lba(); log_message(2, "Writing lead-out..."); // write lead-out if (writeZeros(toc_->leadOutMode(), TrackData::SUBCHAN_NONE, lba, lba + 150, leadOutLength_) != 0) { flushCache(); return 1; } log_message(2, "\nFlushing cache..."); if (flushCache() != 0) { return 1; } log_message(2, ""); blockLength_ = MODE1_BLOCK_LEN; modeSelectBlockSize(blockLength_, 1); delete[] zeroBuffer_, zeroBuffer_ = NULL; return 0; } void CDD2600::abortDao() { flushCache(); blockLength_ = MODE1_BLOCK_LEN; modeSelectBlockSize(blockLength_, 1); } // Writes data to target, the block length depends on the actual writing mode // and is stored internally. 'len' is number of blocks to write. // 'lba' specifies the next logical block address for writing and is updated // by this function but not used for writing // return: 0: OK // 1: scsi command failed int CDD2600::writeData(TrackData::Mode mode, TrackData::SubChannelMode sm, long &lba, const char *buf, long len) { assert(blocksPerWrite_ > 0); assert(blockLength_ > 0); assert(mode == TrackData::AUDIO); int nwritten = 0; int writeLen = 0; unsigned char cmd[10]; memset(cmd, 0, 10); cmd[0] = 0x2a; // WRITE1 while (len > 0) { writeLen = (len > blocksPerWrite_ ? blocksPerWrite_ : len); cmd[7] = writeLen >> 8; cmd[8] = writeLen & 0xff; if (sendCmd(cmd, 10, (unsigned char *)(buf + (nwritten * blockLength_)), writeLen * blockLength_, NULL, 0) != 0) { log_message(-2, "Write data failed."); return 1; } lba += writeLen; len -= writeLen; nwritten += writeLen; } return 0; } Toc *CDD2600::readDiskToc(int session, const char *audioFilename) { blockLength_ = AUDIO_BLOCK_LEN; if (modeSelectBlockSize(blockLength_, 1) != 0) { return NULL; } modeSelectSpeed(2, -1, 1, 0); Toc *toc = CdrDriver::readDiskToc(session, audioFilename); setBlockSize(MODE1_BLOCK_LEN); return toc; } Toc *CDD2600::readDisk(int session, const char *fname) { Toc *toc = CdrDriver::readDisk(session, fname); setBlockSize(MODE1_BLOCK_LEN); return toc; } int CDD2600::readIsrc(int trackNr, char *buf) { unsigned char cmd[10]; unsigned short dataLen = 0x30; unsigned char data[0x30]; int i; memset(cmd, 0, 10); cmd[0] = 0x42; // READ SUB CHANNEL cmd[2] = 0x40; // get sub channel data cmd[3] = 0x03; // get ISRC code cmd[6] = trackNr; cmd[7] = dataLen >> 8; cmd[8] = dataLen; if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) { log_message(-1, "Cannot read ISRC code."); return 1; } else { if (data[0x08] & 0x80) { for (i = 0; i < 12; i++) { buf[i] = data[0x09 + i]; } buf[12] = 0; } } return 0; } // tries to read catalog number from disk and adds it to 'toc' // return: 1 if valid catalog number was found, else 0 int CDD2600::readCatalog(Toc *toc, long startLba, long endLba) { unsigned char cmd[10]; unsigned short dataLen = 0x30; unsigned char data[0x30]; char catalog[14]; int i; // read sub channel information memset(cmd, 0, 10); cmd[0] = 0x42; // READ SUB CHANNEL cmd[2] = 0x40; // get sub channel data cmd[3] = 0x02; // get media catalog number cmd[7] = dataLen >> 8; cmd[8] = dataLen; if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) { log_message(-2, "Cannot read sub channel data."); return 0; } if (data[0x08] & 0x80) { for (i = 0; i < 13; i++) { catalog[i] = data[0x09 + i]; } catalog[13] = 0; if (toc->catalog(catalog) == 0) { return 1; } } return 0; } int CDD2600::analyzeTrack(TrackData::Mode mode, int trackNr, long startLba, long endLba, Msf *index, int *indexCnt, long *pregap, char *isrcCode, unsigned char *ctl) { blockLength_ = AUDIO_BLOCK_LEN; modeSelectBlockSize(blockLength_, 1); int ret = analyzeTrackSearch(mode, trackNr, startLba, endLba, index, indexCnt, pregap, isrcCode, ctl); *isrcCode = 0; if (mode == TrackData::AUDIO) { // read ISRC code from sub channel readIsrc(trackNr, isrcCode); } return ret; } int CDD2600::getTrackIndex(long lba, int *trackNr, int *indexNr, unsigned char *ctl) { long relPos; readBlock(lba); return readSubChannelData(trackNr, indexNr, &relPos, ctl); } int CDD2600::readSubChannelData(int *trackNr, int *indexNr, long *relPos, unsigned char *ctl) { unsigned char cmd[10]; unsigned short dataLen = 0x30; unsigned char data[0x30]; // read sub channel information memset(cmd, 0, 10); cmd[0] = 0x42; // READ SUB CHANNEL cmd[2] = 0x40; // get sub channel data cmd[3] = 0x00; // get sub Q channel data cmd[6] = 0; cmd[7] = dataLen >> 8; cmd[8] = dataLen; if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) { log_message(-2, "Cannot read sub Q channel data."); return 1; } *trackNr = data[6]; *indexNr = data[7]; *relPos = 0; *relPos |= data[0x0c] << 24; *relPos |= data[0x0d] << 16; *relPos |= data[0x0e] << 8; *relPos |= data[0x0f]; if (ctl != NULL) { *ctl = data[5] & 0x0f; } return 0; } // reads a single block of length 'blockLength_' from given sector // return: 0: OK // 1: error occured void CDD2600::readBlock(unsigned long sector) { unsigned char cmd[10]; unsigned long dataLen = 2 * blockLength_; unsigned char *data = new unsigned char[dataLen]; // read sub channel information memset(cmd, 0, 10); cmd[0] = 0x28; // READ10 cmd[2] = sector >> 24; cmd[3] = sector >> 16; cmd[4] = sector >> 8; cmd[5] = sector; cmd[7] = 0; cmd[8] = 2; if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) { log_message(-2, "Cannot read block - ignored."); } delete[] data; } int CDD2600::nextWritableAddress(long *lba, int showError) { unsigned char cmd[10]; unsigned char data[6]; memset(data, 0, 6); memset(cmd, 0, 10); cmd[0] = 0xe2; // FIRST WRITABLE ADDRESS cmd[3] = 1 /*<< 2*/; // AUDIO // cmd[7] = 1; // NPA cmd[8] = 6; // allocation length if (sendCmd(cmd, 10, NULL, 0, data, 6, showError) != 0) { if (showError) log_message(-2, "Cannot retrieve next writable address."); return 1; } *lba = (data[1] << 24) | (data[2] << 16) | (data[3] << 8) | data[4]; return 0; } // Retrieve disk information. // return: DiskInfo structure or 'NULL' on error DiskInfo *CDD2600::diskInfo() { unsigned char cmd[10]; unsigned char data[34]; long nwa; int i; memset(&diskInfo_, 0, sizeof(DiskInfo)); if (readCapacity(&(diskInfo_.capacity), 0) == 0) { diskInfo_.valid.capacity = 1; } if (readSessionInfo(&leadInLength_, &leadOutLength_, 0) == 0) { diskInfo_.valid.manufacturerId = 1; // start time of lead-in diskInfo_.manufacturerId = Msf(450150 - leadInLength_ - 150 ); diskInfo_.append = 1; // this is for the CDD2000 which does not support // READ DISK INFORMATION } else { diskInfo_.append = 0; // this is for the CDD2000 which does not support // READ DISK INFORMATION } diskInfo_.valid.empty = 1; diskInfo_.valid.append = 1; memset(cmd, 0, 10); memset(data, 0, 4); cmd[0] = 0x43; // READ TOC cmd[6] = 0; cmd[8] = 4; if (sendCmd(cmd, 10, NULL, 0, data, 4, 0) == 0) { log_message(5, "First track %u, last track %u", data[2], data[3]); diskInfo_.lastTrackNr = data[3]; } else { log_message(5, "READ TOC (format 0) failed."); } if (diskInfo_.lastTrackNr > 0) { // the lead-in length does not specify the manufacturer ID anymore diskInfo_.valid.manufacturerId = 0; diskInfo_.empty = 0; // CD-R is not empty diskInfo_.diskTocType = 0xff; // undefined if (diskInfo_.lastTrackNr < 99 && nextWritableAddress(&nwa, 0) == 0) { log_message(5, "NWA: %ld", nwa); diskInfo_.thisSessionLba = nwa; diskInfo_.append = 1; } else { diskInfo_.append = 0; } memset(cmd, 0, 10); memset(data, 0, 12); cmd[0] = 0x43; // READ TOC cmd[6] = 0; cmd[8] = 12; cmd[9] = 1 << 6; if (sendCmd(cmd, 10, NULL, 0, data, 12) == 0) { diskInfo_.sessionCnt = data[3]; diskInfo_.lastSessionLba = (data[8] << 24) | (data[9] << 16) | (data[10] << 8) | data[11]; log_message(5, "First session %u, last session %u, last session start %ld", data[2], data[3], diskInfo_.lastSessionLba); } else { log_message(5, "READ TOC (format 1) failed."); } if (diskInfo_.sessionCnt > 0) { int len; CdRawToc *toc = getRawToc(diskInfo_.sessionCnt, &len); if (toc != NULL) { for (i = 0; i < len; i++) { if (toc[i].sessionNr == diskInfo_.sessionCnt) { #if 0 if (toc[i].point == 0xb0 && toc[i].min != 0xff && toc[i].sec != 0xff && toc[i].frame != 0xff) { int m = toc[i].min; int s = toc[i].sec; int f = toc[i].frame; if (m < 90 && s < 60 && f < 75) { diskInfo_.thisSessionLba = Msf(m, s, f).lba(); // + 150 - 150 diskInfo_.thisSessionLba += leadInLength_; } } #endif if (toc[i].point == 0xa0) { diskInfo_.diskTocType = toc[i].psec; } } // The point C0 entry may be only stored in the first session's // lead-in if (toc[i].point == 0xc0 && toc[i].pmin <= 99 && toc[i].psec < 60 && toc[i].pframe < 75) { diskInfo_.manufacturerId = Msf(toc[i].pmin, toc[i].psec, toc[i].pframe); diskInfo_.valid.manufacturerId = 1; } } #if 0 if (diskInfo_.thisSessionLba > 0) { if (diskInfo_.lastTrackNr < 99) diskInfo_.append = 1; } else { log_message(4, "Did not find BO pointer in session %d.", diskInfo_.sessionCnt); } #endif delete[] toc; } else { log_message(5, "getRawToc failed."); } } } else { // disk is empty and appendable diskInfo_.empty = 1; } if (diskInfo_.append == 0) diskInfo_.empty = 0; return &diskInfo_; } CdRawToc *CDD2600::getRawToc(int sessionNr, int *len) { unsigned char cmd[10]; unsigned short dataLen; unsigned char *data = NULL;; unsigned char reqData[4]; // buffer for requestion the actual length unsigned char *p = NULL; int i; CdRawToc *rawToc; int entries; assert(sessionNr >= 1); // read disk toc length memset(cmd, 0, 10); cmd[0] = 0x43; // READ TOC cmd[6] = sessionNr; cmd[8] = 4; cmd[9] |= 2 << 6; // get Q subcodes if (sendCmd(cmd, 10, NULL, 0, reqData, 4) != 0) { log_message(-2, "Cannot read raw disk toc."); return NULL; } dataLen = ((reqData[0] << 8) | reqData[1]) + 2; log_message(5, "Raw toc data len: %d", dataLen); data = new unsigned char[dataLen]; // read disk toc cmd[7] = dataLen >> 8; cmd[8] = dataLen; if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) { log_message(-2, "Cannot read raw disk toc."); delete[] data; return NULL; } entries = (((data[0] << 8) | data[1]) - 2) / 11; rawToc = new CdRawToc[entries]; for (i = 0, p = data + 4; i < entries; i++, p += 11 ) { #if 0 log_message(0, "%d %02x %02d %2x %02d:%02d:%02d %02x %02d:%02d:%02d", p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10]); #endif rawToc[i].sessionNr = p[0]; rawToc[i].adrCtl = p[1]; rawToc[i].point = p[3]; rawToc[i].min = p[4]; rawToc[i].sec = p[5]; rawToc[i].frame = p[6]; rawToc[i].pmin = p[8]; rawToc[i].psec = p[9]; rawToc[i].pframe = p[10]; } delete[] data; *len = entries; return rawToc; } long CDD2600::readTrackData(TrackData::Mode mode, TrackData::SubChannelMode, long lba, long len, unsigned char *buf) { unsigned char cmd[10]; long blockLen = 2340; long i; TrackData::Mode actMode; int ok = 0; const unsigned char *sense; int senseLen; int softError; if (setBlockSize(blockLen) != 0) return 0; memset(cmd, 0, 10); cmd[0] = 0x28; // READ10 cmd[2] = lba >> 24; cmd[3] = lba >> 16; cmd[4] = lba >> 8; cmd[5] = lba; /* if (mode == TrackData::MODE2_FORM1 || mode == TrackData::MODE2_FORM2) cmd[9] = 1 << 6; // MIX flag */ while (len > 0 && !ok) { cmd[7] = len >> 8; cmd[8] = len; memset(transferBuffer_, 0, len * blockLen); switch (sendCmd(cmd, 10, NULL, 0, transferBuffer_, len * blockLen, 0)) { case 0: ok = 1; break; case 2: softError = 0; sense = scsiIf_->getSense(senseLen); if (senseLen > 0x0c) { if ((sense[2] &0x0f) == 5) { switch (sense[12]) { case 0x64: // Illegal mode for this track softError = 1; break; } } else if ((sense[2] & 0x0f) == 3) { // Medium error switch (sense[12]) { case 0x02: // No seek complete, sector not found case 0x11: // L-EC error return -2; break; } } } if (!softError) { scsiIf_->printError(); return -1; } break; default: log_message(-2, "Read error at LBA %ld, len %ld", lba, len); return -1; break; } if (!ok) { len--; } } unsigned char *sector = transferBuffer_; for (i = 0; i < len; i++) { actMode = determineSectorMode(sector); if (!(actMode == mode || (mode == TrackData::MODE2_FORM_MIX && (actMode == TrackData::MODE2_FORM1 || actMode == TrackData::MODE2_FORM2)) || (mode == TrackData::MODE1_RAW && actMode == TrackData::MODE1) || (mode == TrackData::MODE2_RAW && (actMode == TrackData::MODE2 || actMode == TrackData::MODE2_FORM1 || actMode == TrackData::MODE2_FORM2)))) { return i; } if (buf != NULL) { switch (mode) { case TrackData::MODE1: memcpy(buf, sector + 4, MODE1_BLOCK_LEN); buf += MODE1_BLOCK_LEN; break; case TrackData::MODE2: case TrackData::MODE2_FORM_MIX: memcpy(buf, sector + 4, MODE2_BLOCK_LEN); buf += MODE2_BLOCK_LEN; break; case TrackData::MODE2_FORM1: memcpy(buf, sector + 12, MODE2_FORM1_DATA_LEN); buf += MODE2_FORM1_DATA_LEN; break; case TrackData::MODE2_FORM2: memcpy(buf, sector + 12, MODE2_FORM2_DATA_LEN); buf += MODE2_FORM2_DATA_LEN; break; case TrackData::MODE1_RAW: case TrackData::MODE2_RAW: memcpy(buf, syncPattern, 12); memcpy(buf + 12, sector, 2340); buf += AUDIO_BLOCK_LEN; break; case TrackData::MODE0: case TrackData::AUDIO: log_message(-3, "CDD2600::readTrackData: Illegal mode."); return 0; break; } } sector += blockLen; } return len; } int CDD2600::readSubChannels(TrackData::SubChannelMode, long lba, long len, SubChannel ***chans, Sample *audioData) { unsigned char cmd[10]; int tries = 5; int ret; if (setBlockSize(AUDIO_BLOCK_LEN) != 0) return 1; memset(cmd, 0, 10); cmd[0] = 0x28; // READ10 cmd[2] = lba >> 24; cmd[3] = lba >> 16; cmd[4] = lba >> 8; cmd[5] = lba; cmd[7] = len >> 8; cmd[8] = len; do { ret = sendCmd(cmd, 10, NULL, 0, (unsigned char*)audioData, len * AUDIO_BLOCK_LEN, (tries == 1) ? 1 : 0); if (ret != 0 && tries == 1) { log_message(-2, "Reading of audio data failed at sector %ld.", lba); return 1; } tries--; } while (ret != 0 && tries > 0); *chans = NULL; return 0; } int CDD2600::readAudioRange(ReadDiskInfo *rinfo, int fd, long start, long end, int startTrack, int endTrack, TrackInfo *info) { if (!onTheFly_) { int t; log_message(1, "Analyzing..."); for (t = startTrack; t <= endTrack; t++) { long totalProgress; totalProgress = t * 1000; totalProgress /= rinfo->tracks; sendReadCdProgressMsg(RCD_ANALYZING, rinfo->tracks, t + 1, 0, totalProgress); log_message(2, "Track %d...", t + 1); info[t].isrcCode[0] = 0; readIsrc(t + 1, info[t].isrcCode); if (info[t].isrcCode[0] != 0) log_message(2, "Found ISRC code."); totalProgress = (t + 1) * 1000; totalProgress /= rinfo->tracks; sendReadCdProgressMsg(RCD_ANALYZING, rinfo->tracks, t + 1, 1000, totalProgress); } log_message(1, "Reading..."); } return CdrDriver::readAudioRangeParanoia(rinfo, fd, start, end, startTrack, endTrack, info); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/CDD2600.h�����������������������������������������������������������������0000664�0000000�0000000�00000005252�15114537466�0016520�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __CDD2600_H__ #define __CDD2600_H__ #include "CdrDriver.h" #include "CDD2600Base.h" class Toc; class Track; class CDD2600 : public CdrDriver, private CDD2600Base { public: CDD2600(ScsiIf *scsiIf, unsigned long options); ~CDD2600(); static CdrDriver *instance(ScsiIf *scsiIf, unsigned long options); unsigned long getReadCapabilities(const CdToc *, int) const { return 0; } // CDD2600 takes big endian samples int bigEndianSamples() const { return 1; } int speed(int); DiskInfo *diskInfo(); int loadUnload(int) const; int initDao(const Toc *); int startDao(); int finishDao(); void abortDao(); int writeData(TrackData::Mode, TrackData::SubChannelMode, long &lba, const char *buf, long len); Toc *readDiskToc(int, const char *); Toc *readDisk(int, const char *); protected: DiskInfo diskInfo_; CdRawToc *getRawToc(int sessionNr, int *len); int readCatalog(Toc *, long startLba, long endLba); int readIsrc(int, char *); int getTrackIndex(long lba, int *trackNr, int *indexNr, unsigned char *ctl); int analyzeTrack(TrackData::Mode, int trackNr, long startLba, long endLba, Msf *index, int *indexCnt, long *pregap, char *isrcCode, unsigned char *ctl); int readSubChannels(TrackData::SubChannelMode, long lba, long len, SubChannel ***, Sample *); private: long leadInLength_; long leadOutLength_; int modeSelectPlay(int immediate, int sotc, unsigned char volume); int readSubChannelData(int *trackNr, int *indexNr, long *, unsigned char *ctl); void readBlock(unsigned long sector); long readTrackData(TrackData::Mode, TrackData::SubChannelMode, long lba, long len, unsigned char *buf); int readAudioRange(ReadDiskInfo *, int fd, long start, long end, int startTrack, int endTrack, TrackInfo *); int nextWritableAddress(long *lba, int showError); }; #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/CDD2600Base.cc������������������������������������������������������������0000664�0000000�0000000�00000017064�15114537466�0017455�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #include <config.h> #include <string.h> #include <assert.h> #include "CDD2600Base.h" #include "SubChannel.h" #include "Toc.h" #include "log.h" CDD2600Base::CDD2600Base(CdrDriver *driver) { driver_ = driver; } CDD2600Base::~CDD2600Base() { driver_ = NULL; } // sets the block length // return: 0: OK // 1: scsi command failed int CDD2600Base::modeSelectBlockSize(int blockSize, int showMsg) { unsigned char cmd[6]; unsigned char data[12]; memset(cmd, 0, 6); memset(data, 0, 12); cmd[0] = 0x15; // MODE SELECT cmd[4] = 12; data[3] = 8; data[9] = blockSize >> 16; data[10] = blockSize >> 8; data[11] = blockSize; if (driver_->sendCmd(cmd, 6, data, 12, NULL, 0, showMsg) != 0) { if (showMsg) log_message(-2, "Cannot set block size to %d.", blockSize); return 1; } return 0; } // sets read/write speed and simulation mode // return: 0: OK // 1: scsi command failed int CDD2600Base::modeSelectSpeed(int readSpeed, int writeSpeed, int simulate, int showMessage) { unsigned char mp[8]; memset(mp, 0, 8); mp[0] = 0x23; mp[1] = 0x06; if (writeSpeed >= 0) { mp[2] = writeSpeed; } mp[3] = (simulate != 0 ? 1 : 0); if (readSpeed >= 0) { mp[4] = readSpeed; } if (driver_->setModePage(mp, NULL, NULL, showMessage) != 0) { if (showMessage) { log_message(-2, "Cannot set speed/simulation mode."); } return 1; } return 0; } // Sets catalog number if valid in given TOC. // return: 0: OK // 1: scsi command failed int CDD2600Base::modeSelectCatalog(const Toc *toc) { unsigned char mp[10]; memset(mp, 0, 10); mp[0] = 0x22; mp[1] = 0x08; if (toc->catalogValid()) { mp[2] = 0x01; mp[3] = (toc->catalog(0) << 4) | toc->catalog(1); mp[4] = (toc->catalog(2) << 4) | toc->catalog(3); mp[5] = (toc->catalog(4) << 4) | toc->catalog(5); mp[6] = (toc->catalog(6) << 4) | toc->catalog(7); mp[7] = (toc->catalog(8) << 4) | toc->catalog(9); mp[8] = (toc->catalog(10) << 4) | toc->catalog(11); mp[9] = (toc->catalog(12) << 4); } if (driver_->setModePage(mp, NULL, NULL, 1) != 0) { log_message(-2, "Cannot set catalog number."); return 1; } return 0; } // Requests length of lead-in and lead-out. // return: 0: OK // 1: scsi command failed int CDD2600Base::readSessionInfo(long *leadInLen, long *leadOutLen, int showMessage) { unsigned char cmd[10]; unsigned char data[4]; memset(cmd, 0, 10); memset(data, 0, 4); cmd[0] = 0xee; // READ SESSION INFO cmd[8] = 4; if (driver_->sendCmd(cmd, 10, NULL, 0, data, 4, showMessage) != 0) { if (showMessage) log_message(-2, "Cannot read session info."); return 1; } *leadInLen = (data[0] << 8) | data[1]; *leadOutLen = (data[2] << 8) | data[3]; log_message(4, "Lead-in length: %ld, lead-out length: %ld", *leadInLen, *leadOutLen); return 0; } // Sends initiating write session command for disk at once writing. This // includes the complete table of contents with all related data. // return: 0: OK // 1: scsi command failed int CDD2600Base::writeSession(const Toc *toc, int multiSession, long lbaOffset) { unsigned char cmd[10]; unsigned char *data = NULL; unsigned int dataLen = 0; unsigned char *tp = NULL; unsigned int tdl = 0; // track descriptor length int cdromMode = 0; int indexCount = 0; int i; int n; const Track *t; Msf start, end, index; TrackIterator itr(toc); // count total number of index increments for (t = itr.first(start, end); t != NULL; t = itr.next(start, end)) { indexCount += t->nofIndices(); } dataLen = toc->nofTracks() * 20 + indexCount * 4; /* log_message(0, "%d tracks, %d indexes -> dataLen %u", toc->nofTracks(), indexCount, dataLen); */ data = new unsigned char[dataLen]; memset(data, 0, dataLen); tp = data; memset(cmd, 0, 10); cmd[0] = 0xed; // write session cmd[7] = dataLen >> 8; cmd[8] = dataLen; // setup toc-type, lead-out type and multi session flag cmd[6] = 0; switch (toc->tocType()) { case Toc::Type::CD_DA: case Toc::Type::CD_ROM: cmd[6] = 0; break; case Toc::Type::CD_ROM_XA: cmd[6] = 3; break; case Toc::Type::CD_I: cmd[6] = 4; break; } if (cdromMode) { // Programming manual says that lead-out fixation parameter is only // valid if the toc-type is CD-ROM. Unfortunately it does not tell // which values to set. #if 0 switch (toc->leadOutMode()) { case TrackData::MODE1: cmd[6] |= 1 << 4; break; case TrackData::MODE2: case TrackData::MODE2_FORM1: case TrackData::MODE2_FORM2: case TrackData::MODE2_FORM_MIX: cmd[6] |= 2 << 4; break; default: break; } #endif } if (multiSession != 0) cmd[6] |= 1 << 3; // open next session for (t = itr.first(start, end); t != NULL; t = itr.next(start, end)) { n = t->nofIndices(); tdl = 20 + n * 4; tp[0] = tdl >> 8; tp[1] = tdl; start = Msf(start.lba() + lbaOffset); end = Msf(end.lba() + lbaOffset); tp[2] = 0; if (t->copyPermitted()) { tp[2] |= 0x02; } if (t->type() == TrackData::AUDIO) { // audio track if (t->preEmphasis()) { tp[2] |= 0x01; } if (t->audioType() == 1) { tp[2] |= 0x08; } if (t->isrcValid()) { tp[2] |= 0x80; tp[3] = SubChannel::ascii2Isrc(t->isrcCountry(0)); tp[4] = SubChannel::ascii2Isrc(t->isrcCountry(1)); tp[5] = SubChannel::ascii2Isrc(t->isrcOwner(0)); tp[6] = SubChannel::ascii2Isrc(t->isrcOwner(1)); tp[7] = SubChannel::ascii2Isrc(t->isrcOwner(2)); tp[8] = (t->isrcYear(0) << 4) | t->isrcYear(1); tp[9] = (t->isrcSerial(0) << 4) | t->isrcSerial(1); tp[10] = (t->isrcSerial(2) << 4) | t->isrcSerial(3); tp[11] = (t->isrcSerial(4) << 4); } } else { // data track tp[2] |= 0x04; } log_message(4, "Track start: %s(0x%06lx)", start.str(), start.lba()); tp[12] = start.lba() >> 24; tp[13] = start.lba() >> 16; tp[14] = start.lba() >> 8; tp[15] = start.lba(); for (i = 0; i < n; i++) { index = start + t->getIndex(i); log_message(4, " index: %s(0x%06lx)", index.str(), index.lba()); tp[16 + i * 4] = index.lba() >> 24; tp[17 + i * 4] = index.lba() >> 16; tp[18 + i * 4] = index.lba() >> 8; tp[19 + i * 4] = index.lba(); } log_message(4, " end : %s(0x%06lx)", end.str(), end.lba()); tp[16 + n * 4] = end.lba() >> 24; tp[17 + n * 4] = end.lba() >> 16; tp[18 + n * 4] = end.lba() >> 8; tp[19 + n * 4] = end.lba(); tp += tdl; } //log_message(0, "tp: %d", tp - data); if (driver_->sendCmd(cmd, 10, data, dataLen, NULL, 0) != 0) { log_message(-2, "Cannot write disk toc."); delete[] data; return 1; } delete[] data; return 0; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/CDD2600Base.h�������������������������������������������������������������0000664�0000000�0000000�00000002724�15114537466�0017314�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <mueller@daneb.ping.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 * (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. */ /* Basic disk-at-once writing methods for CDD2x00 writing interface. */ #ifndef __CDD2600_BASE_H__ #define __CDD2600_BASE_H__ #include "CdrDriver.h" class Toc; class Track; class CDD2600Base { public: CDD2600Base(CdrDriver *); ~CDD2600Base(); protected: int modeSelectBlockSize(int blockSize, int showMsg); int modeSelectSpeed(int readSpeed, int writeSpeed, int simulate, int showMessage); int modeSelectCatalog(const Toc *); int readSessionInfo(long *, long *, int showMessage); int writeSession(const Toc *, int multiSession, long lbaOffset); private: CdrDriver *driver_; // driver for sending SCSI commands }; #endif ��������������������������������������������cdrdao-cdrdao-f00afb2/dao/CdTextEncoder.cc����������������������������������������������������������0000664�0000000�0000000�00000040426�15114537466�0020451�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #include "CdTextEncoder.h" #include <stddef.h> #include <string.h> #include <assert.h> #include "log.h" #include "Toc.h" #include "CdTextItem.h" #include "PWSubChannel96.h" unsigned short CdTextEncoder::CRCTAB_[256] = { 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 }; class CdTextPackEntry { public: CdTextPackEntry(CdTextItem::PackType, unsigned char trackNr, unsigned char packId); int blockNr(); void blockNr(int); void characterPos(int); union { CdTextPack pack; unsigned char packData[18]; }; CdTextPackEntry *next_; }; CdTextPackEntry::CdTextPackEntry(CdTextItem::PackType packType, unsigned char trackNr, unsigned char packId) { memset(&pack, 0, sizeof(pack)); next_ = NULL; pack.packType = (u8)packType; pack.trackNumber = trackNr; pack.sequenceNumber = packId; } int CdTextPackEntry::blockNr() { return (pack.blockCharacter >> 4) & 0x07; } void CdTextPackEntry::blockNr(int blockNr) { pack.blockCharacter &= 0x8f; pack.blockCharacter |= (blockNr << 4) & 0x70; } void CdTextPackEntry::characterPos(int pos) { pack.blockCharacter &= 0xf0; if (pos > 15) { pack.blockCharacter |= 0x0f; } else { pack.blockCharacter |= pos; } } CdTextEncoder::CdTextEncoder(const Toc *toc) { int i; toc_ = toc; packCount_ = 0; packs_ = lastPack_ = NULL; lastPackPos_ = 0; subChannels_ = NULL; subChannelCount_ = 0; for (i = 0; i < 8; i++) memset(&(sizeInfo_[i]), 0, sizeof(CdTextSizeInfo)); } CdTextEncoder::~CdTextEncoder() { long i; CdTextPackEntry *pnext; toc_ = NULL; while (packs_ != NULL) { pnext = packs_->next_; delete packs_; packs_ = pnext; } lastPack_ = NULL; if (subChannels_ != NULL) { for (i = 0; i < subChannelCount_; i++) { delete subChannels_[i]; subChannels_[i] = NULL; } delete[] subChannels_; subChannels_ = NULL; } } int CdTextEncoder::encode() { buildPacks(); calcCrcs(); if (packs_ != NULL) { log_message(4, "\nCD-TEXT packs:"); CdTextPackEntry *prun; for (prun = packs_; prun != NULL; prun = prun->next_) { log_message(4, "%02x %02x %02x %02x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x CRC: %02x %02x", prun->pack.packType, prun->pack.trackNumber, prun->pack.sequenceNumber, prun->pack.blockCharacter, prun->pack.data[0], prun->pack.data[1], prun->pack.data[2], prun->pack.data[3], prun->pack.data[4], prun->pack.data[5], prun->pack.data[6], prun->pack.data[7], prun->pack.data[8], prun->pack.data[9], prun->pack.data[10], prun->pack.data[11], prun->pack.crc0, prun->pack.crc1); } } buildSubChannels(); return 0; } const PWSubChannel96 **CdTextEncoder::getSubChannels(long *subChannelCount) { *subChannelCount = subChannelCount_; return (const PWSubChannel96 **)subChannels_; } void CdTextEncoder::buildPacks() { int blockNr; for (blockNr = 0; blockNr <= 7; blockNr++) { if (toc_->cdTextLanguage(blockNr) >= 0) { // only build the packs if the language code is defined packId_ = 0; buildPacks(blockNr, CdTextItem::PackType::TITLE); buildPacks(blockNr, CdTextItem::PackType::PERFORMER); buildPacks(blockNr, CdTextItem::PackType::SONGWRITER); buildPacks(blockNr, CdTextItem::PackType::COMPOSER); buildPacks(blockNr, CdTextItem::PackType::ARRANGER); buildPacks(blockNr, CdTextItem::PackType::MESSAGE); buildPacks(blockNr, CdTextItem::PackType::DISK_ID); buildPacks(blockNr, CdTextItem::PackType::GENRE); buildPacks(blockNr, CdTextItem::PackType::TOC_INFO1); buildPacks(blockNr, CdTextItem::PackType::TOC_INFO2); buildPacks(blockNr, CdTextItem::PackType::UPCEAN_ISRC); } } buildSizeInfoPacks(); } // Build packs for specified language (blockNr) and pack type. First the // global pack is created and then the track specific packs. void CdTextEncoder::buildPacks(int blockNr, CdTextItem::PackType type) { const CdTextItem *globalItem; const CdTextItem *item; int i; int n = toc_->nofTracks(); int tracks; int offset = toc_->firstTrackNo() == 0 ? 0 : toc_->firstTrackNo() - 1; if ((globalItem = toc_->getCdTextItem(0, blockNr, type)) != NULL) { encodeCdTextItem(0, blockNr, globalItem); } if (type != CdTextItem::PackType::SIZE_INFO) { // count tracks that have the current pack type defined tracks = 0; for (i = 1; i <= n; i++) { if (toc_->getCdTextItem(i, blockNr, type) != NULL) tracks++; } if (tracks > 0) { if (globalItem == NULL && type == CdTextItem::PackType::UPCEAN_ISRC) { // Special handling for UPC/EAN field. If this field is not defined // but ISRC codes are defined for the tracks an pack with an empty // string is created. CdTextItem upcEan(CdTextItem::PackType::UPCEAN_ISRC, blockNr); encodeCdTextItem(0, blockNr, &upcEan); } for (i = 1; i <= n; i++) { if ((item = toc_->getCdTextItem(i, blockNr, type)) == NULL) item = globalItem; if (item != NULL) encodeCdTextItem(offset + i, blockNr, item); } } } } // Build CD-TEXT packs for a CdTextItem. Space from the last pack is // used if the pack type and language are matching. void CdTextEncoder::encodeCdTextItem(int trackNr, int blockNr, const CdTextItem *item) { long dataLen = item->dataLen(); const unsigned char *data = item->data(); long pos, n; CdTextPackEntry *pack = NULL; int first = 1; if (CdTextItem::isBinaryPack(item->packType())) { pos = 0; while (dataLen > 0) { switch (item->packType()) { case CdTextItem::PackType::GENRE: pack = new CdTextPackEntry(item->packType(), 0, packId_++); if (pos > 0) pack->characterPos((pos * 12) - 2); break; case CdTextItem::PackType::TOC_INFO1: if (pos == 0) pack = new CdTextPackEntry(item->packType(), 0, packId_++); else pack = new CdTextPackEntry(item->packType(), ((pos - 1) * 4) + 1, packId_++); break; default: pack = new CdTextPackEntry(item->packType(), pos, packId_++); break; } n = (dataLen > 12) ? 12 : dataLen; memcpy(pack->pack.data, data, n); pack->blockNr(blockNr); appendPack(pack); lastPackPos_ = 12; data += n; dataLen -= n; pos++; } } else { pos = 0; while (dataLen > 0) { if (first && lastPack_ != NULL && lastPack_->pack.packType == (u8)item->packType() && lastPack_->blockNr() == blockNr && lastPackPos_ < 12) { // we can use space from previous block pack = lastPack_; } else { pack = new CdTextPackEntry(item->packType(), trackNr, packId_++); pack->blockNr(blockNr); pack->characterPos(pos); appendPack(pack); lastPackPos_ = 0; } n = (dataLen > 12 - lastPackPos_) ? 12 - lastPackPos_ : dataLen; memcpy(pack->pack.data + lastPackPos_, data, n); data += n; lastPackPos_ += n; pos += n; dataLen -= n; first = 0; } } } // Create the SIZE_INFO CD-TEXT packs which contains a summary about all // CD-TEXT packs. void CdTextEncoder::buildSizeInfoPacks() { CdTextItem *sizeInfoItem; int i; int b; if (lastPack_ == NULL) { // no packs at all -> nothing to do return; } for (b = 0; b < 8; b++) { sizeInfo_[b].characterCode = characterCode(toc_->cdTextEncoding(b)); sizeInfo_[b].firstTrack = toc_->firstTrackNo() == 0 ? 1 : toc_->firstTrackNo(); sizeInfo_[b].lastTrack = toc_->firstTrackNo() == 0 ? toc_->nofTracks() : toc_->firstTrackNo() + toc_->nofTracks() - 1; sizeInfo_[b].copyright = 0; // no copy protection for (i = 0; i < 8; i++) { if (sizeInfo_[b].lastSequenceNumber[i] > 0) { // set language code if we have at least one pack for this language sizeInfo_[b].languageCode[i] = toc_->cdTextLanguage(i); // adjust the last sequence number for the packs we will create sizeInfo_[b].lastSequenceNumber[i] += 3; } } // adjust the counter for the packs we're currently creating sizeInfo_[b].packTypeCount[15] += 3; // we create 3 packs } for (b = 0; b < 8; b++) { if (sizeInfo_[b].lastSequenceNumber[b] > 0) { // ' - 3' because we've already adjusted the pack count packId_ = sizeInfo_[b].lastSequenceNumber[b] - 3 + 1; sizeInfoItem = new CdTextItem(CdTextItem::PackType::SIZE_INFO, b); sizeInfoItem->setData((u8*)&(sizeInfo_[b]), sizeof(CdTextSizeInfo)); encodeCdTextItem(0, b, sizeInfoItem); delete sizeInfoItem; } } } // Calculates checksum for each CD-TEXT pack. void CdTextEncoder::calcCrcs() { CdTextPackEntry *prun; unsigned char data; unsigned short crc; int i; for (prun = packs_; prun != NULL; prun = prun->next_) { crc = 0; for (i = 0; i < 16; i++) { data = prun->packData[i]; crc = CRCTAB_[(crc >> 8) ^ data] ^ (crc << 8); } crc = ~crc; prun->pack.crc0 = crc >> 8; prun->pack.crc1 = crc; } } // Builds the R-W sub-channel data for all CD-TEXT packs. The sub-channel // data of each sector can hold 4 CD-TEXT packs. void CdTextEncoder::buildSubChannels() { long i, j; CdTextPackEntry *prun; unsigned char buf[72]; switch (packCount_ % 4) { case 0: subChannelCount_ = packCount_ / 4; break; case 2: subChannelCount_ = packCount_ / 2; break; default: subChannelCount_ = packCount_; break; } if (subChannelCount_ == 0) { subChannels_ = NULL; return; } subChannels_ = new PWSubChannel96*[subChannelCount_]; prun = packs_; for (i = 0; i < subChannelCount_; i++) { subChannels_[i] = new PWSubChannel96; for (j = 0; j < 4; j++) { memcpy(buf + j * 18, prun->packData, 18); if ((prun = prun->next_) == NULL) prun = packs_; } subChannels_[i]->setRawRWdata(buf); #if 0 int k; for (j = 0; j < 6; j++) { log_message(0, "%ld:%d: ", i, j); for (k = 0; k < 16; k++) { log_message(0, "%02x ", subChannels_[i]->data()[j * 16 + k]); } log_message(0, ""); } unsigned char buf1[72]; subChannels_[i]->getRawRWdata(buf1); log_message(0, "Match: %d", memcmp(buf, buf1, 72)); #endif } assert(prun == packs_); } void CdTextEncoder::appendPack(CdTextPackEntry *pack) { int b; assert(pack->blockNr() >= 0 && pack->blockNr() <= 7); pack->next_ = NULL; if (packs_ == NULL) { packs_ = lastPack_ = pack; } else { if (pack->blockNr() >= lastPack_->blockNr()) { lastPack_->next_ = pack; lastPack_ = pack; } else { CdTextPackEntry *prun, *ppred; for (ppred = NULL, prun = packs_; prun != NULL; ppred = prun, prun = prun->next_) { if (pack->blockNr() < prun->blockNr()) break; } if (prun == NULL) { // this case should have been handled above lastPack_->next_ = pack; lastPack_ = pack; } else { if (ppred == NULL) { pack->next_ = packs_; packs_ = pack; } else { ppred->next_ = pack; pack->next_ = prun; } } } } packCount_++; // update summary data used for creating the SIZE_INFO pack sizeInfo_[pack->blockNr()].packTypeCount[pack->pack.packType - 0x80] += 1; for (b = 0; b < 8; b++) { if (pack->pack.sequenceNumber > sizeInfo_[b].lastSequenceNumber[pack->blockNr()]) { sizeInfo_[b].lastSequenceNumber[pack->blockNr()] = pack->pack.sequenceNumber; } } } // Values coming from Sony patent. u8 CdTextEncoder::characterCode(Util::Encoding enctype) { switch (enctype) { case Util::Encoding::ASCII: return 0x01; case Util::Encoding::MSJIS: return 0x80; case Util::Encoding::KOREAN: return 0x82; case Util::Encoding::MANDARIN: return 0x83; default: return 0; // Always default to ISO-8859-1 } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/CdTextEncoder.h�����������������������������������������������������������0000664�0000000�0000000�00000004441�15114537466�0020310�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998, 1999 Andreas Mueller <mueller@daneb.ping.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 * (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. */ /* * $Log: CdTextEncoder.h,v $ * Revision 1.1 2000/02/05 01:34:49 llanero * Initial revision * * Revision 1.1 1999/06/13 19:31:15 mueller * Initial revision * */ #ifndef __CD_TEXT_ENCODER_H__ #define __CD_TEXT_ENCODER_H__ #include "CdrDriver.h" #include "CdTextItem.h" #include "CdTextContainer.h" class CdTextItem; class PWSubChannel96; class CdTextEncoder { public: CdTextEncoder(const Toc *); ~CdTextEncoder(); int encode(); const PWSubChannel96 **getSubChannels(long *subChannelCount); static u8 characterCode(Util::Encoding); private: struct CdTextSizeInfo { unsigned char characterCode; unsigned char firstTrack; unsigned char lastTrack; unsigned char copyright; unsigned char packTypeCount[16]; unsigned char lastSequenceNumber[8]; unsigned char languageCode[8]; }; const Toc *toc_; CdTextSizeInfo sizeInfo_[8]; long packCount_; class CdTextPackEntry *packs_; class CdTextPackEntry *lastPack_; int lastPackPos_; // number of characters written to last pack long packId_; PWSubChannel96 **subChannels_; long subChannelCount_; static unsigned short CRCTAB_[256]; void appendPack(CdTextPackEntry *); void buildPacks(); void buildPacks(int blockNr, CdTextItem::PackType type); void buildSizeInfoPacks(); void calcCrcs(); void buildSubChannels(); void encodeCdTextItem(int, int, const CdTextItem *); }; #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/CdrDriver.cc��������������������������������������������������������������0000664�0000000�0000000�00000361501�15114537466�0017642�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #include <config.h> #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <assert.h> #include <fcntl.h> #include <unistd.h> #include <ctype.h> #include <ostream> #include <vector> #include <string> #include "CdrDriver.h" #include "PWSubChannel96.h" #include "Toc.h" #include "util.h" #include "log.h" #include "CdTextItem.h" #include "data.h" #include "port.h" // all drivers #include "CDD2600.h" #include "PlextorReader.h" #include "PlextorReaderScan.h" #include "GenericMMC.h" #include "GenericMMCraw.h" #include "RicohMP6200.h" #include "TaiyoYuden.h" #include "YamahaCDR10x.h" #include "TeacCdr55.h" #include "SonyCDU920.h" #include "SonyCDU948.h" #include "ToshibaReader.h" // Paranoia DAE related #include "cdda_interface.h" #include "../paranoia/cdda_paranoia.h" using namespace std; typedef CdrDriver *(*CdrDriverConstructor)(ScsiIf *, unsigned long); struct DriverSelectTable { const char *driverId; const char *vendor; const char *model; unsigned long options; struct DriverSelectTable *next; }; struct DriverTable { const char *driverId; CdrDriverConstructor constructor; }; static DriverSelectTable *READ_DRIVER_TABLE = NULL; static DriverSelectTable *WRITE_DRIVER_TABLE = NULL; static DriverSelectTable BUILTIN_READ_DRIVER_TABLE[] = { { "generic-mmc", "ASUS", "CD-S340", 0, NULL }, { "generic-mmc", "ASUS", "CD-S400", 0, NULL }, { "generic-mmc", "ASUS", "CD-S500/A", OPT_MMC_NO_SUBCHAN, NULL }, { "generic-mmc", "ASUS", "DVD-ROM E608", 0, NULL }, { "generic-mmc", "E-IDE", "CD-950E/TKU", 0, NULL }, { "generic-mmc", "E-IDE", "CD-ROM 36X/AKU", 0, NULL }, { "generic-mmc", "E-IDE", "CD-ROM 52X/AKH", 0, NULL }, { "generic-mmc", "FUNAI", "E295X", 0, NULL }, { "generic-mmc", "Goldstar", "CD-RW CED-8042B", 0, NULL }, { "generic-mmc", "HITACHI", "CDR-7730", 0, NULL }, { "generic-mmc", "HITACHI", "CDR-8435", OPT_MMC_NO_SUBCHAN, NULL }, { "generic-mmc", "LG", "CD-ROM CRD-8480C", OPT_MMC_NO_SUBCHAN, NULL }, { "generic-mmc", "LG", "CD-ROM CRD-8482B", OPT_MMC_NO_SUBCHAN, NULL }, { "generic-mmc", "LG", "CD-ROM CRD-8521B", 0, NULL }, { "generic-mmc", "LG", "DVD-ROM DRN8080B", OPT_DRV_GET_TOC_GENERIC, NULL }, { "generic-mmc", "LITE-ON", "CD-ROM", OPT_DRV_GET_TOC_GENERIC, NULL }, { "generic-mmc", "LITE-ON", "LTD-163", 0, NULL }, { "generic-mmc", "LITEON", "DVD-ROM LTD163D", 0, NULL }, { "generic-mmc", "MATSHITA", "CD-ROM CR-588", 0, NULL }, { "generic-mmc", "MATSHITA", "CD-ROM CR-589", OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD, NULL }, { "generic-mmc", "MATSHITA", "DVD-ROM SR-8585", OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD, NULL }, { "generic-mmc", "MEMOREX", "CD-233E", 0, NULL }, { "generic-mmc", "MITSUMI", "CD-ROM FX4820", OPT_MMC_NO_SUBCHAN, NULL }, { "generic-mmc", "OPTICS_S", "8622", 0, NULL }, { "generic-mmc", "PHILIPS", "36X/AKU", 0, NULL }, { "generic-mmc", "PHILIPS", "CD-ROM PCCD052", 0, NULL }, { "generic-mmc", "PHILIPS", "E-IDE CD-ROM 36X", 0, NULL }, { "generic-mmc", "PIONEER", "CD-ROM DR-U32", OPT_DRV_GET_TOC_GENERIC|OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD, NULL }, { "generic-mmc", "PIONEER", "DVD-103", OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD, NULL }, { "generic-mmc", "PIONEER", "DVD-104", OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD, NULL }, { "generic-mmc", "PIONEER", "DVD-105", OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD, NULL }, { "generic-mmc", "SONY", "CD-ROM CDU31A-02", 0, NULL }, { "generic-mmc", "SONY", "CD-ROM CDU4821", 0, NULL }, { "generic-mmc", "SONY", "CDU5211", 0, NULL }, { "generic-mmc", "TEAC", "CD-524E", OPT_DRV_GET_TOC_GENERIC|OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD, NULL }, { "generic-mmc", "TEAC", "CD-532E", OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD, NULL }, { "generic-mmc", "TEAC", "CD-540E", 0, NULL }, { "generic-mmc", "TOSHIBA", "CD-ROM XM-3206B", 0, NULL }, { "generic-mmc", "TOSHIBA", "CD-ROM XM-6102B", 0, NULL }, { "generic-mmc", "TOSHIBA", "CD-ROM XM-6302B", 0, NULL }, { "generic-mmc", "TOSHIBA", "CD-ROM XM-6402B", 0, NULL }, { "generic-mmc", "TOSHIBA", "DVD-ROM SD-C2202", 0, NULL }, { "generic-mmc", "TOSHIBA", "DVD-ROM SD-C2302", 0, NULL }, { "generic-mmc", "TOSHIBA", "DVD-ROM SD-C2402", 0, NULL }, { "generic-mmc", "TOSHIBA", "DVD-ROM SD-M1102", 0, NULL }, { "generic-mmc", "TOSHIBA", "DVD-ROM SD-M1401", 0, NULL }, { "generic-mmc", "TOSHIBA", "DVD-ROM SD-M1402", 0, NULL }, { "plextor", "HITACHI", "DVD-ROM GD-2500", 0, NULL }, { "plextor", "MATSHITA", "CD-ROM CR-506", OPT_PLEX_DAE_D4_12, NULL }, { "plextor", "MATSHITA", "CR-8008", 0, NULL }, { "plextor", "NAKAMICH", "MJ-5.16S", 0, NULL }, { "plextor", "PIONEER", "CD-ROM DR-U03", OPT_DRV_GET_TOC_GENERIC, NULL }, { "plextor", "PIONEER", "CD-ROM DR-U06", OPT_DRV_GET_TOC_GENERIC, NULL }, { "plextor", "PIONEER", "CD-ROM DR-U10", OPT_DRV_GET_TOC_GENERIC, NULL }, { "plextor", "PIONEER", "CD-ROM DR-U12", OPT_DRV_GET_TOC_GENERIC, NULL }, { "plextor", "PIONEER", "CD-ROM DR-U16", OPT_DRV_GET_TOC_GENERIC, NULL }, { "plextor", "PIONEER", "DVD-303", 0, NULL }, { "plextor", "PIONEER", "DVD-305", 0, NULL }, { "plextor", "SAF", "CD-R2006PLUS", 0, NULL }, { "plextor", "SONY", "CD-ROM", 0, NULL }, { "plextor", "SONY", "CD-ROM CDU-76", 0, NULL }, { "plextor", "TOSHIBA", "XM-5401", 0, NULL }, { "plextor-scan", "PLEXTOR", "CD-ROM", 0, NULL }, { "plextor-scan", "PLEXTOR", "PX-40TS", 0, NULL }, { "plextor-scan", "PLEXTOR", "PX-40TW", 0, NULL }, { "plextor-scan", "PLEXTOR", "PX-63", 0, NULL }, { "plextor-scan", "TEAC", "CD-ROM CD-532S", OPT_PLEX_USE_PQ|OPT_PLEX_PQ_BCD, NULL }, { "teac-cdr55", "TEAC", "CD-532S", 0, NULL }, { "toshiba", "TOSHIBA", "1504", 0, NULL }, { "toshiba", "TOSHIBA", "CD-ROM XM-3601B", 0, NULL }, { "toshiba", "TOSHIBA", "CD-ROM XM-5302TA", 0, NULL }, { "toshiba", "TOSHIBA", "CD-ROM XM-5701TA", 0, NULL }, { "toshiba", "TOSHIBA", "CD-ROM XM-6201TA", 0, NULL }, { "toshiba", "TOSHIBA", "CD-ROM XM-6401TA", 0, NULL }, { "toshiba", "TOSHIBA", "DVD-ROM SD-2102", 0, NULL }, { NULL, NULL, NULL, 0, NULL }}; static DriverSelectTable BUILTIN_WRITE_DRIVER_TABLE[] = { { "cdd2600", "GRUNDIG", "CDR100IPW", 0, NULL }, { "cdd2600", "HP", "CD-Writer 4020", 0, NULL }, { "cdd2600", "HP", "CD-Writer 6020", 0, NULL }, { "cdd2600", "IMS", "522", 0, NULL }, { "cdd2600", "IMS", "CDD2000", 0, NULL }, { "cdd2600", "KODAK", "PCD-225", 0, NULL }, { "cdd2600", "PHILIPS", "CDD2000", 0, NULL }, { "cdd2600", "PHILIPS", "CDD2600", 0, NULL }, { "cdd2600", "PHILIPS", "CDD522", 0, NULL }, { "generic-mmc", "AOPEN", "CD-RW CRW1632", 0, NULL }, { "generic-mmc", "AOPEN", "CD-RW CRW2040", 0, NULL }, { "generic-mmc", "AOPEN", "CD-RW-241040", 0, NULL }, { "generic-mmc", "AOPEN", "CRW9624", 0, NULL }, { "generic-mmc", "CD-RW", "CDR-2440MB", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "CREATIVE", "CD-RW RW1210E", 0, NULL }, { "generic-mmc", "CREATIVE", "CD-RW RW4424", 0, NULL }, { "generic-mmc", "CREATIVE", "CD-RW RW8433E", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "CREATIVE", "CD5233E", 0, NULL }, { "generic-mmc", "DELTA", "OME-W141", 0, NULL }, { "generic-mmc", "GENERIC", "CRD-BP1600P", 0, NULL }, { "generic-mmc", "GENERIC", "CRD-R800S", 0, NULL }, { "generic-mmc", "GENERIC", "CRD-RW2", 0, NULL }, { "generic-mmc", "HL-DT-ST", "RW/DVD GCC-4120B", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "HP", "9510i", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "HP", "CD-Writer+ 7570", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "HP", "CD-Writer+ 8100", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "HP", "CD-Writer+ 8200", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "HP", "CD-Writer+ 8290", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "HP", "CD-Writer+ 9100", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "HP", "CD-Writer+ 9110", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "HP", "CD-Writer+ 9200", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "HP", "CD-Writer+ 9300", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "HP", "CD-Writer+ 9600", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "HP", "CD-Writer+ 9700", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "HP", "DVD Writer 100j", 0, NULL }, { "generic-mmc", "IDE-CD", "R/RW 16x10A", 0, NULL }, { "generic-mmc", "IMATION", "IMW121032IAB", 0, NULL }, { "generic-mmc", "LG", "8088B", 0, NULL }, { "generic-mmc", "LG", "8120B", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "LG", "CD-ROM CDR-8428B", 0, NULL }, { "generic-mmc", "LG", "CD-RW CED-8080B", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "LG", "CD-RW CED-8081B", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "LG", "CD-RW CED-8083B", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "LG", "CD-RW GCE-8240B", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "LG", "COMBO", 0, NULL }, { "generic-mmc", "LG", "HL-DT-ST RW/DVD GCC-4080N", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "LITE-ON", "LTR-0841", OPT_MMC_CD_TEXT|OPT_MMC_NO_SUBCHAN, NULL }, { "generic-mmc", "LITE-ON", "LTR-24102B", 0, NULL }, { "generic-mmc", "LITE-ON", "LTR-32125W", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "MATSHITA", "CD-R CW-7502", 0, NULL }, { "generic-mmc", "MATSHITA", "CD-R CW-7503", 0, NULL }, { "generic-mmc", "MATSHITA", "CD-R CW-7582", 0, NULL }, { "generic-mmc", "MATSHITA", "CD-R CW-7585", 0, NULL }, { "generic-mmc", "MATSHITA", "CD-R CW-7586", 0, NULL }, { "generic-mmc", "MATSHITA", "CDRRW01", 0, NULL }, { "generic-mmc", "MATSHITA", "UJDA360", 0, NULL }, { "generic-mmc", "MATSHITA", "UJDA710", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "MATSHITA", "UJDA720", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "MEMOREX", "24MAX 1040", 0, NULL }, { "generic-mmc", "MEMOREX", "40MAXX 1248AJ", 0, NULL }, { "generic-mmc", "MEMOREX", "CD-RW4224", 0, NULL }, { "generic-mmc", "MICROSOLUTIONS", "BACKPACK CD REWRITER", 0, NULL }, { "generic-mmc", "MITSUMI", "CR-4801", 0, NULL }, { "generic-mmc", "MITSUMI", "CR-48X5", 0, NULL }, { "generic-mmc", "MITSUMI", "CR-48X5TE", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "MITSUMI", "CR-48X8TE", 0, NULL }, { "generic-mmc", "MITSUMI", "CR-48XATE", 0, NULL }, { "generic-mmc", "OLYMPIC", "RWD RW4224", OPT_DRV_GET_TOC_GENERIC|OPT_MMC_USE_PQ, NULL }, { "generic-mmc", "PANASONIC", "CD-R CW-7582", 0, NULL }, { "generic-mmc", "PHILIPS", "CDRW1610A", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "PHILIPS", "CDRW2412A", 0, NULL }, { "generic-mmc", "PHILIPS", "PCA460RW", 0, NULL }, { "generic-mmc", "PIONEER", "DVD-ROM DVD-114", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "PLEXTOR", "CD-R PX-R412", OPT_MMC_USE_PQ|OPT_MMC_READ_ISRC, NULL }, { "generic-mmc", "PLEXTOR", "CD-R PX-R820", 0, NULL }, { "generic-mmc", "PLEXTOR", "CD-R PX-W1210", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "PLEXTOR", "CD-R PX-W124", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "PLEXTOR", "CD-R PX-W1610", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "PLEXTOR", "CD-R PX-W4220", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "PLEXTOR", "CD-R PX-W8220", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "PLEXTOR", "CD-R PX-W8432", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "PLEXTOR", "CD-R PX-W241040", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "PLEXTOR", "CD-R PX-W2410a", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "PLEXTOR", "CD-R PX-W4012A", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "RICOH", "CD-R/RW MP7040", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "RICOH", "CD-R/RW MP7060", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "RICOH", "CD-R/RW MP7063A", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "RICOH", "CD-R/RW MP7080", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "RICOH", "CD-R/RW MP7083A", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "RICOH", "DVD/CDRW MP9060", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "SAF", "CD-R8020", 0, NULL }, { "generic-mmc", "SAF", "CD-RW4224A", 0, NULL }, { "generic-mmc", "SAF", "CD-RW6424", 0, NULL }, { "generic-mmc", "SAMSUNG", "CD-R/RW SW-206", 0, NULL }, { "generic-mmc", "SAMSUNG", "CD-R/RW SW-408B", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "SAMSUNG", "CDRW/DVD SM-308B", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "SANYO", "CRD-BP3", 0, NULL }, { "generic-mmc", "SONY", "CD-RW CRX700E", 0, NULL }, { "generic-mmc", "SONY", "CRX-815", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "SONY", "CRX100", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "SONY", "CRX120", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "SONY", "CRX140", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "SONY", "CRX145", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "SONY", "CRX160E", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "SONY", "CRX175A1", 0, NULL }, { "generic-mmc", "SONY", "CRX175E", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "SONY", "CRX185E1", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "TDK", "4800", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "TDK", "CDRW121032", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "TDK", "CDRW321040B", 0, NULL }, { "generic-mmc", "TDK", "CDRW8432", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "TEAC", "CD-R56", OPT_MMC_USE_PQ|OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "TEAC", "CD-R58", OPT_MMC_USE_PQ|OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "TEAC", "CD-W216E", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "TEAC", "CD-W512EB", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "TEAC", "CD-W512SB", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "TEAC", "CD-W516EB", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "TEAC", "CD-W516EC", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "TEAC", "CD-W524E", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "TEAC", "CD-W54E", 0, NULL }, { "generic-mmc", "TORiSAN", "CDW-U4424", 0, NULL }, { "generic-mmc", "TOSHIBA", "DVD-ROM SD-M1612", 0, NULL }, { "generic-mmc", "TOSHIBA", "DVD-ROM SD-R1002", 0, NULL }, { "generic-mmc", "TOSHIBA", "DVD-ROM SD-R1202", 0, NULL }, { "generic-mmc", "TRAXDATA", "241040", 0, NULL }, { "generic-mmc", "TRAXDATA", "CDRW4260", 0, NULL }, { "generic-mmc", "WAITEC", "WT624", OPT_MMC_NO_SUBCHAN, NULL }, { "generic-mmc", "YAMAHA", "CDR200", 0, NULL }, { "generic-mmc", "YAMAHA", "CDR400", 0, NULL }, { "generic-mmc", "YAMAHA", "CRW2100", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "YAMAHA", "CRW2200", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "YAMAHA", "CRW2260", 0, NULL }, { "generic-mmc", "YAMAHA", "CRW3200", OPT_MMC_CD_TEXT, NULL }, { "generic-mmc", "YAMAHA", "CRW4001", 0, NULL }, { "generic-mmc", "YAMAHA", "CRW4260", 0, NULL }, { "generic-mmc", "YAMAHA", "CRW4416", 0, NULL }, { "generic-mmc", "YAMAHA", "CRW6416", 0, NULL }, { "generic-mmc", "YAMAHA", "CRW8424", 0, NULL }, { "generic-mmc", "YAMAHA", "CRW8824", 0, NULL }, { "generic-mmc", "_NEC", "NR-7700A", 0, NULL }, { "generic-mmc-raw", "ACER", "10x8x32", 0, NULL }, { "generic-mmc-raw", "ACER", "2010A", 0, NULL }, { "generic-mmc-raw", "ACER", "20x10x40", 0, NULL }, { "generic-mmc-raw", "ACER", "4406EU", 0, NULL }, { "generic-mmc-raw", "ACER", "4x4x6", 0, NULL }, { "generic-mmc-raw", "ACER", "8X4X32", 0, NULL }, { "generic-mmc-raw", "ACER", "CD-R/RW 4X4X32", OPT_MMC_NO_SUBCHAN, NULL }, { "generic-mmc-raw", "AOPEN", "CD-RW CRW3248", 0, NULL }, { "generic-mmc-raw", "AOPEN", "CRW1232", 0, NULL }, { "generic-mmc-raw", "ARTEC", "RW241040", 0, NULL }, { "generic-mmc-raw", "ARTEC", "WRA-WA48", 0, NULL }, { "generic-mmc-raw", "ARTEC", "WRR-4048", 0, NULL }, { "generic-mmc-raw", "ASUS", "CRW-1610A", 0, NULL }, { "generic-mmc-raw", "ASUS", "CRW-3212A", 0, NULL }, { "generic-mmc-raw", "ATAPI", "CD-R/RW 12X8X32", 0, NULL }, { "generic-mmc-raw", "ATAPI", "CD-R/RW 4X4X32", 0, NULL }, { "generic-mmc-raw", "ATAPI", "CD-R/RW CRW6206A", 0, NULL }, { "generic-mmc-raw", "BENQ", "CRW2410A", 0, NULL }, { "generic-mmc-raw", "BTC", "BCE1610IM", 0, NULL }, { "generic-mmc-raw", "BTC", "BCE2410IM", 0, NULL }, { "generic-mmc-raw", "BTC", "BCE621E", 0, NULL }, { "generic-mmc-raw", "CyberDrv", "CW018D", 0, NULL }, { "generic-mmc-raw", "CyberDrv", "CW038D", 0, NULL }, { "generic-mmc-raw", "CyberDrv", "CW058D", 0, NULL }, { "generic-mmc-raw", "Goldstar", "8120B", 0, NULL }, { "generic-mmc-raw", "HL-DT-ST", "CD-RW GCE-8160B", 0, NULL }, { "generic-mmc-raw", "HL-DT-ST", "CD-RW GCE-8320B", 0, NULL }, { "generic-mmc-raw", "HP", "CD-Writer+ 7100", 0, NULL }, { "generic-mmc-raw", "HP", "CD-Writer+ 7200", 0, NULL }, { "generic-mmc-raw", "HP", "DVD Writer 200j", 0, NULL }, { "generic-mmc-raw", "IDE-CD", "R/RW 2x2x24", 0, NULL }, { "generic-mmc-raw", "IDE-CD", "R/RW 4x4x24", 0, NULL }, { "generic-mmc-raw", "IDE-CD", "R/RW 4x4x32", 0, NULL }, { "generic-mmc-raw", "IDE-CD", "R/RW 8x4x32", 0, NULL }, { "generic-mmc-raw", "IDE-CD", "ReWritable-2x2x6", 0, NULL }, { "generic-mmc-raw", "IOMEGA", "ZIPCD 4x650", 0, NULL }, { "generic-mmc-raw", "LITE-ON", "LTR-12101B", 0, NULL }, { "generic-mmc-raw", "LITE-ON", "LTR-16101B", 0, NULL }, { "generic-mmc-raw", "LITE-ON", "LTR-16102C", 0, NULL }, { "generic-mmc-raw", "LITE-ON", "LTR-32123S", 0, NULL }, { "generic-mmc-raw", "LITE-ON", "LTR-40125S", 0, NULL }, { "generic-mmc-raw", "LITE-ON", "LTR-48125W", 0, NULL }, { "generic-mmc-raw", "MEMOREX", "CDRW-2216", 0, NULL }, { "generic-mmc-raw", "MEMOREX", "CR-622", 0, NULL }, { "generic-mmc-raw", "MEMOREX", "CRW-1662", 0, NULL }, { "generic-mmc-raw", "MITSUMI", "2801", 0, NULL }, { "generic-mmc-raw", "MITSUMI", "CR-4802", 0, NULL }, { "generic-mmc-raw", "MITSUMI", "CR-4804", 0, NULL }, { "generic-mmc-raw", "OTI", "-975 SOCRATES", 0, NULL }, { "generic-mmc-raw", "PHILIPS", "CDD 3801/31", 0, NULL }, { "generic-mmc-raw", "PHILIPS", "CDD3600", 0, NULL }, { "generic-mmc-raw", "PHILIPS", "CDD3610", 0, NULL }, { "generic-mmc-raw", "PHILIPS", "CDD4201", OPT_MMC_NO_SUBCHAN, NULL }, { "generic-mmc-raw", "PHILIPS", "CDD4801", 0, NULL }, { "generic-mmc-raw", "PHILIPS", "CDRW400", 0, NULL }, { "generic-mmc-raw", "PHILIPS", "PCRW1208", 0, NULL }, { "generic-mmc-raw", "PHILIPS", "PCRW120899", 0, NULL }, { "generic-mmc-raw", "PHILIPS", "PCRW404", 0, NULL }, { "generic-mmc-raw", "PHILIPS", "PCRW804", 0, NULL }, { "generic-mmc-raw", "QPS", "CRD-BP 1500P", 0, NULL }, { "generic-mmc-raw", "SAMSUNG", "CD-R/RW SW-204B", 0, NULL }, { "generic-mmc-raw", "SAMSUNG", "CD-R/RW SW-208", 0, NULL }, { "generic-mmc-raw", "SAMSUNG", "CD-R/RW SW-212B", 0, NULL }, { "generic-mmc-raw", "SAMSUNG", "CD-R/RW SW-224", 0, NULL }, { "generic-mmc-raw", "SAMSUNG", "SW-232", 0, NULL }, { "generic-mmc-raw", "SONY", "CRX195E1", 0, NULL }, { "generic-mmc-raw", "TEAC", "CD-W58E", OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD, NULL }, { "generic-mmc-raw", "TOSHIBA", "R/RW 4x4x24", 0, NULL }, { "generic-mmc-raw", "TRAXDATA", "2832", 0, NULL }, { "generic-mmc-raw", "TRAXDATA", "CDRW2260+", 0, NULL }, { "generic-mmc-raw", "TRAXDATA", "CRW2260 PRO", 0, NULL }, { "generic-mmc-raw", "WAITEC", "WT2444EI", 0, NULL }, { "generic-mmc-raw", "WAITEC", "WT4424", 0, NULL }, { "generic-mmc-raw", "_NEC", "7900", 0, NULL }, { "generic-mmc-raw", "_NEC", "NR-7800A", 0, NULL }, { "ricoh-mp6200", "AOPEN", "CRW620", 0, NULL }, { "ricoh-mp6200", "MEMOREX", "CRW620", 0, NULL }, { "ricoh-mp6200", "PHILIPS", "OMNIWRITER26", 0, NULL }, { "ricoh-mp6200", "RICOH", "MP6200", 0, NULL }, { "ricoh-mp6200", "RICOH", "MP6201", 0, NULL }, { "sony-cdu920", "SONY", "CD-R CDU920", 0, NULL }, { "sony-cdu920", "SONY", "CD-R CDU924", 0, NULL }, { "sony-cdu948", "SONY", "CD-R CDU948", 0, NULL }, { "taiyo-yuden", "T.YUDEN", "CD-WO EW-50", 0, NULL }, { "teac-cdr55", "JVC", "R2626", 0, NULL }, { "teac-cdr55", "JVC", "XR-W2010", 0, NULL }, { "teac-cdr55", "SAF", "CD-R2006PLUS", 0, NULL }, { "teac-cdr55", "SAF", "CD-R4012", 0, NULL }, { "teac-cdr55", "SAF", "CD-RW 226", 0, NULL }, { "teac-cdr55", "TEAC", "CD-R50", 0, NULL }, { "teac-cdr55", "TEAC", "CD-R55", 0, NULL }, { "teac-cdr55", "TRAXDATA", "CDR4120", 0, NULL }, { "toshiba", "TOSHIBA", "DVD-ROM SD-R2002", 0, NULL }, { "toshiba", "TOSHIBA", "DVD-ROM SD-R2102", 0, NULL }, { "yamaha-cdr10x", "YAMAHA", "CDR100", 0, NULL }, { "yamaha-cdr10x", "YAMAHA", "CDR102", 0, NULL }, { NULL, NULL, NULL, 0, NULL }}; static DriverTable DRIVERS[] = { { "cdd2600", &CDD2600::instance }, { "generic-mmc", &GenericMMC::instance }, { "generic-mmc-raw", &GenericMMCraw::instance }, { "plextor", &PlextorReader::instance }, { "plextor-scan", &PlextorReaderScan::instance }, { "ricoh-mp6200", &RicohMP6200::instance }, { "sony-cdu920", &SonyCDU920::instance }, { "sony-cdu948", &SonyCDU948::instance }, { "taiyo-yuden", &TaiyoYuden::instance }, { "teac-cdr55", &TeacCdr55::instance }, { "toshiba", &ToshibaReader::instance }, { "yamaha-cdr10x", &YamahaCDR10x::instance }, { NULL, NULL }}; struct CDRVendorTable { char m1, s1, f1; // 1st vendor code char m2, s2, f2; // 2nd vendor code const char *id; // vendor ID }; static CDRVendorTable VENDOR_TABLE[] = { // permanent codes { 97,28,30, 97,46,50, "Auvistar Industry Co.,Ltd." }, { 97,26,60, 97,46,60, "CMC Magnetics Corporation" }, { 97,23,10, 0,0,0, "Doremi Media Co., Ltd." }, { 97,26,00, 97,45,00, "FORNET INTERNATIONAL PTE LTD." }, { 97,46,40, 97,46,40, "FUJI Photo Film Co., Ltd." }, { 97,26,40, 0,0,0, "FUJI Photo Film Co., Ltd." }, { 97,28,10, 97,49,10, "GIGASTORAGE CORPORATION" }, { 97,25,20, 97,47,10, "Hitachi Maxell, Ltd." }, { 97,27,40, 97,48,10, "Kodak Japan Limited" }, { 97,26,50, 97,48,60, "Lead Data Inc." }, { 97,27,50, 97,48,50, "Mitsui Chemicals, Inc." }, { 97,34,20, 97,50,20, "Mitsubishi Chemical Corporation" }, { 97,28,20, 97,46,20, "Multi Media Masters & Machinery SA" }, { 97,21,40, 0,0,0, "Optical Disc Manufacturing Equipment" }, { 97,27,30, 97,48,30, "Pioneer Video Corporation" }, { 97,27,10, 97,48,20, "Plasmon Data systems Ltd." }, { 97,26,10, 97,47,40, "POSTECH Corporation" }, { 97,27,20, 97,47,20, "Princo Corporation" }, { 97,32,10, 0,0,0, "Prodisc Technology Inc." }, { 97,27,60, 97,48,00, "Ricoh Company Limited" }, { 97,31,00, 97,47,50, "Ritek Co." }, { 97,26,20, 0,0,0, "SKC Co., Ltd." }, { 97,24,10, 0,0,0, "SONY Corporation" }, { 97,24,00, 97,46,00, "Taiyo Yuden Company Limited" }, { 97,32,00, 97,49,00, "TDK Corporation" }, { 97,25,60, 97,45,60, "Xcitek Inc." }, // tentative codes { 97,22,60, 97,45,20, "Acer Media Technology, Inc" }, { 97,25,50, 0,0,0, "AMS Technology Inc." }, { 97,23,30, 0,0,0, "AUDIO DISTRIBUTORS CO., LTD." }, { 97,21,30, 0,0,0, "Bestdisc Technology Corporation" }, { 97,30,10, 97,50,30, "CDA Datentraeger Albrechts GmbH" }, { 97,22,40, 97,45,40, "CIS Technology Inc." }, { 97,24,20, 97,46,30, "Computer Support Italy s.r.l." }, { 97,23,60, 0,0,0, "Customer Pressing Oosterhout" }, { 97,28,50, 0,0,0, "DELPHI TECHNOLOGY INC." }, { 97,27,00, 97,48,40, "DIGITAL STORAGE TECHNOLOGY CO.,LTD" }, { 97,22,30, 0,0,0, "EXIMPO" }, { 97,28,60, 0,0,0, "Friendly CD-Tek Co." }, { 97,31,30, 97,51,10, "Grand Advance Technology Ltd." }, { 97,29,50, 0,0,0, "General Magnetics Ld" }, { 97,24,50, 97,45,50, "Guann Yinn Co.,Ltd." }, { 97,29,00, 0,0,0, "Harmonic Hall Optical Disc Ltd." }, { 97,29,30, 97,51,50, "Hile Optical Disc Technology Corp." }, { 97,46,10, 97,22,50, "Hong Kong Digital Technology Co., Ltd." }, { 97,25,30, 97,51,20, "INFODISC Technology Co., Ltd." }, { 97,24,40, 0,0,0, "kdg mediatech AG" }, { 97,28,40, 97,49,20, "King Pro Mediatek Inc." }, { 97,23,00, 97,49,60, "Matsushita Electric Industrial Co., Ltd." }, { 97,15,20, 0,0,0, "Mitsubishi Chemical Corporation" }, { 97,25,00, 0,0,0, "MPO" }, { 97,23,20, 0,0,0, "Nacar Media sr" }, { 97,26,30, 0,0,0, "OPTICAL DISC CORPRATION" }, { 97,28,00, 97,49,30, "Opti.Me.S. S.p.A." }, { 97,23,50, 0,0,0, "OPTROM.INC." }, { 97,47,60, 0,0,0, "Prodisc Technology Inc." }, { 97,15,10, 0,0,0, "Ritek Co." }, { 97,22,10, 0,0,0, "Seantram Technology Inc." }, { 97,21,50, 0,0,0, "Sound Sound Multi-Media Development Limited" }, { 97,29,00, 0,0,0, "Taeil Media Co.,Ltd." }, { 97,18,60, 0,0,0, "TAROKO INTERNATIONAL CO.,LTD." }, { 97,15,00, 0,0,0, "TDK Corporation." }, { 97,29,20, 0,0,0, "UNIDISC TECHNOLOGY CO.,LTD" }, { 97,24,30, 97,45,10, "UNITECH JAPAN INC." }, { 97,29,10, 97,50,10, "Vanguard Disc Inc." }, { 97,49,40, 97,23,40, "VICTOR COMPANY OF JAPAN, LIMITED" }, { 97,29,40, 0,0,0, "VIVA MAGNETICS LIMITED" }, { 97,25,40, 0,0,0, "VIVASTAR AG" }, { 97,18,10, 0,0,0, "WEALTH FAIR INVESTMENT LIMITED" }, { 97,22,00, 0,0,0, "Woongjin Media corp." }, { 0, 0, 0, 0, 0, 0, NULL} }; unsigned char CdrDriver::syncPattern[12] = { 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0 }; unsigned char CdrDriver::REMOTE_MSG_SYNC_[4] = { 0xff, 0x00, 0xff, 0x00 }; /* Maps a string to the corresponding driver option value * Return: 0: string is not a valid driver option sting * else: option value for string */ static unsigned long string2DriverOption(const char *s) { if (strcmp(s, "OPT_DRV_GET_TOC_GENERIC") == 0) return OPT_DRV_GET_TOC_GENERIC; else if (strcmp(s, "OPT_DRV_SWAP_READ_SAMPLES") == 0) return OPT_DRV_SWAP_READ_SAMPLES; else if (strcmp(s, "OPT_DRV_NO_PREGAP_READ") == 0) return OPT_DRV_NO_PREGAP_READ; else if (strcmp(s, "OPT_DRV_RAW_TOC_BCD") == 0) return OPT_DRV_RAW_TOC_BCD; else if (strcmp(s, "OPT_DRV_RAW_TOC_HEX") == 0) return OPT_DRV_RAW_TOC_HEX; else if (strcmp(s, "OPT_MMC_USE_PQ") == 0) return OPT_MMC_USE_PQ; else if (strcmp(s, "OPT_MMC_PQ_BCD") == 0) return OPT_MMC_PQ_BCD; else if (strcmp(s, "OPT_MMC_READ_ISRC") == 0) return OPT_MMC_READ_ISRC; else if (strcmp(s, "OPT_MMC_SCAN_MCN") == 0) return OPT_MMC_SCAN_MCN; else if (strcmp(s, "OPT_MMC_CD_TEXT") == 0) return OPT_MMC_CD_TEXT; else if (strcmp(s, "OPT_MMC_NO_SUBCHAN") == 0) return OPT_MMC_NO_SUBCHAN; else if (strcmp(s, "OPT_MMC_NO_BURNPROOF") == 0) return OPT_MMC_NO_BURNPROOF; else if (strcmp(s, "OPT_MMC_NO_RW_PACKED") == 0) return OPT_MMC_NO_RW_PACKED; else if (strcmp(s, "OPT_MMC_USE_RAW_RW") == 0) return OPT_MMC_USE_RAW_RW; else if (strcmp(s, "OPT_MMC_YAMAHA_FORCE_SPEED") == 0) return OPT_MMC_YAMAHA_FORCE_SPEED; else if (strcmp(s, "OPT_PLEX_USE_PARANOIA") == 0) return OPT_PLEX_USE_PARANOIA; else if (strcmp(s, "OPT_PLEX_DAE_READ10") == 0) return OPT_PLEX_DAE_READ10; else if (strcmp(s, "OPT_PLEX_DAE_D4_12") == 0) return OPT_PLEX_DAE_D4_12; else if (strcmp(s, "OPT_PLEX_USE_PQ") == 0) return OPT_PLEX_USE_PQ; else if (strcmp(s, "OPT_PLEX_PQ_BCD") == 0) return OPT_PLEX_PQ_BCD; else if (strcmp(s, "OPT_PLEX_READ_ISRC") == 0) return OPT_PLEX_READ_ISRC; else return 0; } /* Checks if 'n' is a valid driver name and returns the driver id string * from the 'DRIVERS' on success. * Return: driver id string * NULL: if 'n' is not a valid driver id */ static const char *checkDriverName(const char *n) { DriverTable *run = DRIVERS; while (run->driverId != NULL) { if (strcmp(run->driverId, n) == 0) return run->driverId; run++; } return NULL; } /* Reads driver table from specified file. Return: 0: OK, driver table file could be opened 1: could not open driver table file */ #define MAX_DRIVER_TABLE_LINE_LEN 1024 static int readDriverTable(const char *filename) { FILE *fp; DriverSelectTable *ent; long i; int lineNr = 0; int count = 0; int rw; int err; char buf[MAX_DRIVER_TABLE_LINE_LEN]; char *p, *l; const char *sep = "|"; char *vendor; char *model; char *driver; const char *lastDriverName = NULL; const char *driverName; unsigned long opt, options; if ((fp = fopen(filename, "r")) == NULL) return 1; log_message(4, "Reading driver table from file \"%s\".", filename); while (fgets(buf, MAX_DRIVER_TABLE_LINE_LEN, fp) != NULL) { lineNr++; vendor = model = driver = NULL; rw = 0; options = 0; err = 0; // remove comment if ((p = strchr(buf, '#')) != NULL) *p = 0; // remove leading white space for (l = buf; *l != 0 && isspace(*l); l++) ; // remove trailing white space for (i = strlen(l) - 1; i >= 0 && isspace(l[i]); i--) l[i] = 0; if ((p = strtok(l, sep)) != NULL) { if (strcmp(p, "R") == 0) { rw = 1; } else if (strcmp(p, "W") == 0) { rw = 2; } else { log_message(-1, "%s:%d: Expecting 'R' or 'W' as first token - line ignored.", filename, lineNr); } if (rw > 0) { if ((p = strtok(NULL, sep)) != NULL) { vendor = strdupCC(p); if ((p = strtok(NULL, sep)) != NULL) { model = strdupCC(p); if ((p = strtok(NULL, sep)) != NULL) { driver = strdupCC(p); if (lastDriverName == NULL || strcmp(lastDriverName, driver) != 0) { if ((driverName = checkDriverName(driver)) == NULL) { log_message(-1, "%s:%d: Driver '%s' not defined - line ignored.", filename, lineNr, driver); err = 1; } else { lastDriverName = driverName; } } while (!err && (p = strtok(NULL, sep)) != NULL) { if ((opt = string2DriverOption(p)) == 0) { log_message(-1, "%s:%d: Driver option string '%s' not defined - line ignored.", filename, lineNr, p); err = 1; } options |= opt; } if (!err) { ent = new DriverSelectTable; ent->vendor = vendor; vendor = NULL; ent->model = model; model = NULL; ent->driverId = driver; driver = NULL; ent->options = options; if (rw == 1) { ent->next = READ_DRIVER_TABLE; READ_DRIVER_TABLE = ent; } else { ent->next = WRITE_DRIVER_TABLE; WRITE_DRIVER_TABLE = ent; } count++; } } else { log_message(-1, "%s:%d: Missing driver name - line ignored.", filename, lineNr); } } else { log_message(-1, "%s:%d: Missing model name - line ignored.", filename, lineNr); } } else { log_message(-1, "%s:%d: Missing vendor name - line ignored.", filename, lineNr); } delete[] vendor; delete[] model; delete[] driver; } } } fclose(fp); log_message(4, "Found %d valid driver table entries.", count); return 0; } /* Create driver tables from built-in driver table data. */ static void createDriverTable() { DriverSelectTable *run; DriverSelectTable *ent; for (run = BUILTIN_READ_DRIVER_TABLE; run->driverId != NULL; run++) { ent = new DriverSelectTable; ent->driverId = strdupCC(run->driverId); ent->vendor = strdupCC(run->vendor); ent->model = strdupCC(run->model); ent->options = run->options; ent->next = READ_DRIVER_TABLE; READ_DRIVER_TABLE = ent; } for (run = BUILTIN_WRITE_DRIVER_TABLE; run->driverId != NULL; run++) { ent = new DriverSelectTable; ent->driverId = strdupCC(run->driverId); ent->vendor = strdupCC(run->vendor); ent->model = strdupCC(run->model); ent->options = run->options; ent->next = WRITE_DRIVER_TABLE; WRITE_DRIVER_TABLE = ent; } } /* Initialize driver table. First try to read the driver table from file * 'DRIVER_TABLE_FILE'. If it does not exist the built-in driver table data * will be used. After that an user specific driver table file is loaded if * available. */ static void initDriverTable() { static int initialized = 0; const char *home; char *path; if (initialized) return; if (readDriverTable(DRIVER_TABLE_FILE) != 0) { log_message(3, "Cannot read driver table from file \"%s\" - using built-in table.", DRIVER_TABLE_FILE); createDriverTable(); } /* read driver table from $HOME/.cdrdao-drivers */ if ((home = getenv("HOME")) != NULL) { path = strdup3CC(home, "/.cdrdao-drivers", NULL); readDriverTable(path); delete[] path; } initialized = 1; } const char *CdrDriver::selectDriver(int readWrite, const char *vendor, const char *model, unsigned long *options) { DriverSelectTable *run; DriverSelectTable *match = NULL; unsigned int matchLen = 0; unsigned int len = 0; initDriverTable(); run = (readWrite == 0) ? READ_DRIVER_TABLE : WRITE_DRIVER_TABLE; while (run != NULL) { if (strcmp(run->vendor, vendor) == 0 && strstr(model, run->model) != NULL) { if (match == NULL || (len = strlen(run->model)) > matchLen) { matchLen = (match == NULL) ? strlen(run->model) : len; match = run; } } run = run->next; } if (match != NULL) { *options = match->options; return match->driverId; } return NULL; } CdrDriver *CdrDriver::createDriver(const char *driverId, unsigned long options, ScsiIf *scsiIf) { DriverTable *run = DRIVERS; while (run->driverId != NULL) { if (strcmp(run->driverId, driverId) == 0) return run->constructor(scsiIf, options); run++; } return NULL; } const char *CdrDriver::detectDriver(ScsiIf *scsiIf, unsigned long *options) { if (scsiIf->checkMmc()) { *options |= OPT_MMC_CD_TEXT; return "generic-mmc"; } return NULL; } void CdrDriver::printDriverIds() { DriverTable *run = DRIVERS; while (run->driverId != NULL) { log_message(0, "%s", run->driverId); run++; } } CdrDriver::CdrDriver(ScsiIf *scsiIf, unsigned long options) { size16 byteOrderTest = 1; char *byteOrderTestP = (char*)&byteOrderTest; options_ = options; scsiIf_ = scsiIf; toc_ = NULL; if (*byteOrderTestP == 1) hostByteOrder_ = 0; // little endian else hostByteOrder_ = 1; // big endian enableBufferUnderRunProtection_ = 1; enableWriteSpeedControl_ = 1; readCapabilities_ = 0; // reading capabilities are determined dynamically audioDataByteOrder_ = 0; // default to little endian fastTocReading_ = false; rawDataReading_ = false; mode2Mixed_ = true; subChanReadMode_ = TrackData::SUBCHAN_NONE; taoSource_ = 0; taoSourceAdjust_ = 2; // usually we have 2 unreadable sectors between tracks // written in TAO mode padFirstPregap_ = 1; onTheFly_ = 0; onTheFlyFd_ = -1; multiSession_ = false; encodingMode_ = 0; force_ = false; remote_ = 0; remoteFd_ = -1; blockLength_ = 0; blocksPerWrite_ = 0; zeroBuffer_ = NULL; userCapacity_ = 0; fullBurn_ = false; scsiMaxDataLen_ = scsiIf_->maxDataLen(); transferBuffer_ = new unsigned char[scsiMaxDataLen_]; maxScannedSubChannels_ = scsiMaxDataLen_ / (AUDIO_BLOCK_LEN + PW_SUBCHANNEL_LEN); scannedSubChannels_ = new SubChannel*[maxScannedSubChannels_]; paranoia_ = NULL; paranoiaDrive_ = NULL; paranoiaMode(3); // full paranoia but allow skip } CdrDriver::~CdrDriver() { toc_ = NULL; delete[] zeroBuffer_; zeroBuffer_ = NULL; delete[] transferBuffer_; transferBuffer_ = NULL; delete [] scannedSubChannels_; scannedSubChannels_ = NULL; } // Sets multi session mode. 0: close session, 1: open next session // Return: 0: OK // 1: multi session not supported by driver int CdrDriver::multiSession(bool m) { multiSession_ = m; return 0; } // Sets number of adjust sectors for reading TAO source disks. void CdrDriver::taoSourceAdjust(int val) { if (val >= 0 && val < 100) { taoSourceAdjust_ = val; } } void CdrDriver::onTheFly(int fd) { if (fd >= 0) { onTheFly_ = 1; onTheFlyFd_ = fd; } else { onTheFly_ = 0; onTheFlyFd_ = -1; } } void CdrDriver::remote(int f, int fd) { if (f != 0 && fd >= 0) { int flags; remote_ = 1; remoteFd_ = fd; // switch 'fd' to non blocking IO mode if ((flags = fcntl(fd, F_GETFL)) == -1) { log_message(-1, "Cannot get flags of remote stream: %s", strerror(errno)); remote_ = 0; remoteFd_ = -1; return; } flags |= O_NONBLOCK; if (fcntl(fd, F_SETFL, flags) < 0) { log_message(-1, "Cannot set flags of remote stream: %s", strerror(errno)); remote_ = 0; remoteFd_ = -1; } } else { remote_ = 0; remoteFd_ = -1; } } // Returns acceptable sub-channel encoding mode for given sub-channel type: // -1: writing of sub-channel type not supported at all // 0: accepts plain data without encoding // 1: accepts only completely encoded data int CdrDriver::subChannelEncodingMode(TrackData::SubChannelMode sm) const { if (sm == TrackData::SUBCHAN_NONE) return 0; else return -1; } int CdrDriver::cdrVendor(Msf &code, const char **vendorId, const char **mediumType) { CDRVendorTable *run = VENDOR_TABLE; *vendorId = NULL; char m = code.min(); char s = code.sec(); char f = code.frac(); char type = f % 10; f -= type; while (run->id != NULL) { if ((run->m1 == m && run->s1 == s && run->f1 == f) || (run->m2 == m && run->s2 == s && run->f2 == f)) { *vendorId = run->id; break; } run++; } if (*vendorId != NULL) { if (type < 5) { *mediumType = "Long Strategy Type, e.g. Cyanine"; } else { *mediumType = "Short Strategy Type, e.g. Phthalocyanine"; } return 1; } return 0; } // Sends SCSI command via 'scsiIf_'. // return: see 'ScsiIf::sendCmd()' int CdrDriver::sendCmd(const unsigned char *cmd, int cmdLen, const unsigned char *dataOut, int dataOutLen, unsigned char *dataIn, int dataInLen, int showErrorMsg) const { return scsiIf_->sendCmd(cmd, cmdLen, dataOut, dataOutLen, dataIn, dataInLen, showErrorMsg); } // checks if unit is ready // return: 0: OK // 1: scsi command failed // 2: not ready // 3: not ready, no disk in drive // 4: not ready, tray out int CdrDriver::testUnitReady(int ignoreUnitAttention) const { unsigned char cmd[6]; const unsigned char *sense; int senseLen; memset(cmd, 0, 6); switch (scsiIf_->sendCmd(cmd, 6, NULL, 0, NULL, 0, 0)) { case 1: return 1; case 2: sense = scsiIf_->getSense(senseLen); int code = sense[2] & 0x0f; if (code == 0x02) { // not ready return 2; } else if (code != 0x06) { scsiIf_->printError(); return 1; } else { return 0; } } return 0; } bool CdrDriver::rspeed(int a) { rspeed_ = a; return true; } int CdrDriver::speed2Mult(int speed) { return speed / 176; } int CdrDriver::mult2Speed(int mult) { return mult * 177; } // start unit ('startStop' == 1) or stop unit ('startStop' == 0) // return: 0: OK // 1: scsi command failed int CdrDriver::startStopUnit(int startStop) const { unsigned char cmd[6]; memset(cmd, 0, 6); cmd[0] = 0x1b; if (startStop != 0) { cmd[4] |= 0x01; } if (sendCmd(cmd, 6, NULL, 0, NULL, 0) != 0) { log_message(-2, "Cannot start/stop unit."); return 1; } return 0; } // blocks or unblocks tray // return: 0: OK // 1: scsi command failed int CdrDriver::preventMediumRemoval(int block) const { unsigned char cmd[6]; memset(cmd, 0, 6); cmd[0] = 0x1e; if (block != 0) { cmd[4] |= 0x01; } if (sendCmd(cmd, 6, NULL, 0, NULL, 0) != 0) { log_message(-2, "Cannot prevent/allow medium removal."); return 1; } return 0; } // reset device to initial state // return: 0: OK // 1: scsi command failed int CdrDriver::rezeroUnit(int showMessage) const { unsigned char cmd[6]; memset(cmd, 0, 6); cmd[0] = 0x01; if (sendCmd(cmd, 6, NULL, 0, NULL, 0, showMessage) != 0) { if (showMessage) log_message(-2, "Cannot rezero unit."); return 1; } return 0; } // Flushs cache of drive which inidcates end of write action. Errors resulting // from this command are ignored because everything is already done and // at most the last part of the lead-out track may be affected. // return: 0: OK int CdrDriver::flushCache() const { unsigned char cmd[10]; memset(cmd, 0, 10); cmd[0] = 0x35; // FLUSH CACHE // Print no message if the flush cache command fails because some drives // report errors even if all went OK. sendCmd(cmd, 10, NULL, 0, NULL, 0, 0); return 0; } // Reads the cd-rom capacity and stores the total number of available blocks // in 'length'. // return: 0: OK // 1: SCSI command failed int CdrDriver::readCapacity(long *length, int showMessage) { unsigned char cmd[10]; unsigned char data[8]; memset(cmd, 0, 10); memset(data, 0, 8); cmd[0] = 0x25; // READ CD-ROM CAPACITY if (sendCmd(cmd, 10, NULL, 0, data, 8, showMessage) != 0) { if (showMessage) log_message(-2, "Cannot read capacity."); return 1; } *length = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; // *length += 1; return 0; } int CdrDriver::getPerformance() { u8 cmd[12]; u8 data[512]; int ret; long length; memset(cmd, 0, sizeof(cmd)); cmd[0] = 0xac; // GET PERFORMANCE cmd[9] = 10; cmd[1] = 4; cmd[10] = 0; if ((ret = sendCmd(cmd, 12, NULL, 0, data, sizeof(data)))) { log_message(-2, "Cannot get performance (%d)", ret); return 1; } length = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; return 0; } int CdrDriver::blankDisk(BlankingMode) { log_message(-2, "Blanking is not supported by this driver."); return 1; } // Writes data to target, the block length depends on the actual writing mode // 'mode'. 'len' is number of blocks to write. // 'lba' specifies the next logical block address for writing and is updated // by this function. // return: 0: OK // 1: scsi command failed int CdrDriver::writeData(TrackData::Mode mode, TrackData::SubChannelMode sm, long &lba, const char *buf, long len) { assert(blocksPerWrite_ > 0); int writeLen = 0; unsigned char cmd[10]; long blockLength = blockSize(mode, sm); #if 0 long sum, i; sum = 0; for (i = 0; i < len * blockLength; i++) { sum += buf[i]; } log_message(0, "W: %ld: %ld, %ld, %ld", lba, blockLength, len, sum); #endif memset(cmd, 0, 10); cmd[0] = 0x2a; // WRITE1 while (len > 0) { writeLen = (len > blocksPerWrite_ ? blocksPerWrite_ : len); cmd[2] = lba >> 24; cmd[3] = lba >> 16; cmd[4] = lba >> 8; cmd[5] = lba; cmd[7] = writeLen >> 8; cmd[8] = writeLen & 0xff; if (sendCmd(cmd, 10, (unsigned char *)buf, writeLen * blockLength, NULL, 0) != 0) { log_message(-2, "Write data failed."); return 1; } buf += writeLen * blockLength; lba += writeLen; len -= writeLen; } return 0; } // Writes 'count' blocks with zero data with 'writeData'. // m: mode for encoding zero data // lba: logical block address for the write command, will be updated // encLba: logical block address used by the LE-C encoder for the // sector headers // count: number of zero blocks to write // Return: 0: OK // 1: SCSI error occured int CdrDriver::writeZeros(TrackData::Mode m, TrackData::SubChannelMode sm, long &lba, long encLba, long count) { assert(blocksPerWrite_ > 0); assert(zeroBuffer_ != NULL); int n, i; long cnt = 0; long total; long cntMb; long lastMb = 0; long blockLen; unsigned char *buf; blockLen = blockSize(m, sm); total = count * blockLen; #if 0 static int wcount = 0; char fname[100]; snprintf(fname, sizeof(fname), "zeros%d.out", wcount++); FILE *fp = fopen(fname, "w"); #endif while (count > 0) { n = (count > blocksPerWrite_ ? blocksPerWrite_ : count); buf = (unsigned char *)zeroBuffer_; for (i = 0; i < n; i++) { Track::encodeZeroData(encodingMode_, m, sm, encLba++, buf); if (encodingMode_ == 0 && bigEndianSamples() == 0) { // swap encoded data blocks swapSamples((Sample *)buf, SAMPLES_PER_BLOCK); } buf += blockLen; } //fwrite(zeroBuffer_, blockLen, n, fp); if (writeData(encodingMode_ == 0 ? TrackData::AUDIO : m, sm, lba, zeroBuffer_, n) != 0) { return 1; } cnt += n * blockLen; cntMb = cnt >> 20; if (cntMb > lastMb) { log_message(1, "Wrote %ld of %ld MB.\r", cntMb, total >> 20); fflush(stdout); lastMb = cntMb; } count -= n; } //fclose(fp); return 0; } // Requests mode page 'pageCode' from device and places it into given // buffer of maximum length 'bufLen'. // modePageHeader: if != NULL filled with mode page header (8 bytes) // blockDesc : if != NULL filled with block descriptor (8 bytes), // buffer is zeroed if no block descriptor is received // return: 0: OK // 1: scsi command failed // 2: buffer too small for requested mode page int CdrDriver::getModePage(int pageCode, unsigned char *buf, long bufLen, unsigned char *modePageHeader, unsigned char *blockDesc, int showErrorMsg) { unsigned char cmd[10]; long dataLen = bufLen + 8/*mode parameter header*/ + 100/*spare for block descriptors*/; unsigned char *data = new unsigned char[dataLen]; memset(cmd, 0, 10); memset(data, 0, dataLen); memset(buf, 0, bufLen); cmd[0] = 0x5a; // MODE SENSE cmd[2] = pageCode & 0x3f; cmd[7] = dataLen >> 8; cmd[8] = dataLen; if (sendCmd(cmd, 10, NULL, 0, data, dataLen, showErrorMsg) != 0) { delete[] data; return 1; } long modeDataLen = (data[0] << 8) | data[1]; long blockDescLen = (data[6] << 8) | data[7]; if (modePageHeader != NULL) memcpy(modePageHeader, data, 8); if (blockDesc != NULL) { if (blockDescLen >= 8) memcpy(blockDesc, data + 8, 8); else memset(blockDesc, 0, 8); } if (modeDataLen > blockDescLen + 6) { unsigned char *modePage = data + blockDescLen + 8; long modePageLen = modePage[1] + 2; if (modePageLen > bufLen) modePageLen = bufLen; memcpy(buf, modePage, modePageLen); delete[] data; return 0; } else { log_message(-2, "No mode page data received."); delete[] data; return 1; } } // Sets mode page in device specified in buffer 'modePage' // modePageHeader: if != NULL used as mode page header (8 bytes) // blockDesc : if != NULL used as block descriptor (8 bytes), // Return: 0: OK // 1: SCSI command failed int CdrDriver::setModePage(const unsigned char *modePage, const unsigned char *modePageHeader, const unsigned char *blockDesc, int showErrorMsg) { long pageLen = modePage[1] + 2; unsigned char cmd[10]; long dataLen = pageLen + 8/*mode parameter header*/; if (blockDesc != NULL) dataLen += 8; unsigned char *data = new unsigned char[dataLen]; memset(cmd, 0, 10); memset(data, 0, dataLen); if (modePageHeader != NULL) memcpy(data, modePageHeader, 8); data[0] = 0; data[1] = 0; data[4] = 0; data[5] = 0; if (blockDesc != NULL) { memcpy(data + 8, blockDesc, 8); memcpy(data + 16, modePage, pageLen); data[6] = 0; data[7] = 8; } else { memcpy(data + 8, modePage, pageLen); data[6] = 0; data[7] = 0; } cmd[0] = 0x55; // MODE SELECT cmd[1] = 1 << 4; cmd[7] = dataLen >> 8; cmd[8] = dataLen; if (sendCmd(cmd, 10, data, dataLen, NULL, 0, showErrorMsg) != 0) { delete[] data; return 1; } delete[] data; return 0; } // As above, but implemented with six byte mode commands // Requests mode page 'pageCode' from device and places it into given // buffer of maximum length 'bufLen'. // modePageHeader: if != NULL filled with mode page header (4 bytes) // blockDesc : if != NULL filled with block descriptor (8 bytes), // buffer is zeroed if no block descriptor is received // return: 0: OK // 1: scsi command failed // 2: buffer too small for requested mode page int CdrDriver::getModePage6(int pageCode, unsigned char *buf, long bufLen, unsigned char *modePageHeader, unsigned char *blockDesc, int showErrorMsg) { unsigned char cmd[6]; long dataLen = bufLen + 4/*mode parameter header*/ + 100/*spare for block descriptors*/; unsigned char *data = new unsigned char[dataLen]; memset(cmd, 0, 6); memset(data, 0, dataLen); memset(buf, 0, bufLen); cmd[0] = 0x1a; // MODE SENSE(6) cmd[2] = pageCode & 0x3f; cmd[4] = (dataLen > 255) ? 0 : dataLen; if (sendCmd(cmd, 6, NULL, 0, data, dataLen, showErrorMsg) != 0) { delete[] data; return 1; } long modeDataLen = data[0]; long blockDescLen = data[3]; if (modePageHeader != NULL) memcpy(modePageHeader, data, 4); if (blockDesc != NULL) { if (blockDescLen >= 8) memcpy(blockDesc, data + 4, 8); else memset(blockDesc, 0, 8); } if (modeDataLen > blockDescLen + 4) { unsigned char *modePage = data + blockDescLen + 4; long modePageLen = modePage[1] + 2; if (modePageLen > bufLen) modePageLen = bufLen; memcpy(buf, modePage, modePageLen); delete[] data; return 0; } else { log_message(-2, "No mode page data received."); delete[] data; return 1; } } // Sets mode page in device specified in buffer 'modePage' // modePageHeader: if != NULL used as mode page header (4 bytes) // blockDesc : if != NULL used as block descriptor (8 bytes), // Return: 0: OK // 1: SCSI command failed int CdrDriver::setModePage6(const unsigned char *modePage, const unsigned char *modePageHeader, const unsigned char *blockDesc, int showErrorMsg) { long pageLen = modePage[1] + 2; unsigned char cmd[6]; long dataLen = pageLen + 4/*mode parameter header*/; if (blockDesc != NULL) dataLen += 8; unsigned char *data = new unsigned char[dataLen]; memset(cmd, 0, 6); memset(data, 0, dataLen); if (modePageHeader != NULL) memcpy(data, modePageHeader, 4); data[0] = 0; if (blockDesc != NULL) { memcpy(data + 4, blockDesc, 8); memcpy(data + 12, modePage, pageLen); data[3] = 8; } else { memcpy(data + 4, modePage, pageLen); data[3] = 0; } cmd[0] = 0x15; // MODE SELECT(6) cmd[1] = 1 << 4; cmd[4] = dataLen; if (sendCmd(cmd, 6, data, dataLen, NULL, 0, showErrorMsg) != 0) { delete[] data; return 1; } delete[] data; return 0; } // Retrieves TOC data of inserted CD. It won't distinguish between different // sessions. // The track information is returned either for all sessions or for the // first session depending on the drive. 'cdTocLen' is filled with number // of entries including the lead-out track. // Return: 'NULL' on error, else array of 'CdToc' structures with '*cdTocLen' // entries CdToc *CdrDriver::getTocGeneric(int *cdTocLen) { unsigned char cmd[10]; unsigned short dataLen; unsigned char *data = NULL;; unsigned char reqData[4]; // buffer for requestion the actual length unsigned char *p = NULL; int i; CdToc *toc; int nTracks; // read disk toc length memset(cmd, 0, 10); cmd[0] = 0x43; // READ TOC cmd[6] = 0; // return info for all tracks cmd[8] = 4; if (sendCmd(cmd, 10, NULL, 0, reqData, 4) != 0) { log_message(-2, "Cannot read disk toc."); return NULL; } dataLen = (reqData[0] << 8) | reqData[1]; dataLen += 2; log_message(4, "getTocGeneric: data len %d", dataLen); if (dataLen < 12) { dataLen = (100 * 8) + 4; } data = new unsigned char[dataLen]; memset(data, 0, dataLen); // read disk toc cmd[7] = dataLen >> 8; cmd[8] = dataLen; if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) { log_message(-2, "Cannot read disk toc."); delete[] data; return NULL; } nTracks = data[3] - data[2] + 1; if (nTracks > 99) { log_message(-2, "Got illegal toc data."); delete[] data; return NULL; } toc = new CdToc[nTracks + 1]; for (i = 0, p = data + 4; i <= nTracks; i++, p += 8) { toc[i].track = p[2]; toc[i].adrCtl = p[1]; toc[i].start = (p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7]; } *cdTocLen = nTracks + 1; delete[] data; return toc; } // Retrieves TOC data of inserted CD. The track information is returend for // specified session number only. The lead-out start is taken from the // correct session so that it can be used to calculate the length of the // last track. // 'cdTocLen' is filled with number of entries including the lead-out track. // Return: 'NULL' on error, else array of 'CdToc' structures with '*cdTocLen' // entries #define IS_BCD(v) (((v) & 0xf0) <= 0x90 && ((v) & 0x0f) <= 0x09) CdToc *CdrDriver::getToc(int sessionNr, int *cdTocLen) { int rawTocLen; int completeTocLen; CdToc *completeToc; // toc retrieved with generic method to verify with raw // toc data CdToc *cdToc; CdRawToc *rawToc; int i, j, tocEnt; int nTracks = 0; int trackNr; long trackStart; int isBcd = -1; int lastTrack; int min, sec, frame; if ((completeToc = getTocGeneric(&completeTocLen)) == NULL) return NULL; if (options_ & OPT_DRV_GET_TOC_GENERIC) { *cdTocLen = completeTocLen; return completeToc; } if ((rawToc = getRawToc(1, &rawTocLen)) == NULL) { *cdTocLen = completeTocLen; return completeToc; } // Try to determine if raw toc data contains BCD or HEX numbers. for (i = 0; i < rawTocLen; i++) { if ((rawToc[i].adrCtl & 0xf0) == 0x10) { // only process QMODE1 entries if (rawToc[i].point < 0xa0 && !IS_BCD(rawToc[i].point)) { isBcd = 0; } if (rawToc[i].point < 0xa0 || rawToc[i].point == 0xa2) { if (!IS_BCD(rawToc[i].pmin) || !IS_BCD(rawToc[i].psec) || !IS_BCD(rawToc[i].pframe)) { isBcd = 0; break; } } } } if (options_ & OPT_DRV_RAW_TOC_BCD) { if (isBcd == 0) { log_message(-2, "The driver option 0x%lx indicates that the raw TOC data", OPT_DRV_RAW_TOC_BCD); log_message(-2, "contains BCD values but a non BCD value was found."); log_message(-2, "Please adjust the driver options."); log_message(-1, "Using TOC data retrieved with generic method (no multi session support)."); delete[] rawToc; *cdTocLen = completeTocLen; return completeToc; } isBcd = 1; } else if (options_ & OPT_DRV_RAW_TOC_HEX) { isBcd = 0; } else { if (isBcd == -1) { // We still don't know if the values are BCD or HEX but we've ensured // so far that all values are valid BCD numbers. // Assume that we have BCD numbers and compare with the generic toc data. isBcd = 1; for (i = 0; i < rawTocLen && isBcd == 1; i++) { if ((rawToc[i].adrCtl & 0xf0) == 0x10 && // only process QMODE1 entries rawToc[i].point < 0xa0) { trackNr = SubChannel::bcd2int(rawToc[i].point); for (j = 0; j < completeTocLen; j++) { if (completeToc[j].track == trackNr) { break; } } if (j < completeTocLen) { min = SubChannel::bcd2int(rawToc[i].pmin); sec = SubChannel::bcd2int(rawToc[i].psec); frame = SubChannel::bcd2int(rawToc[i].pframe); if (min <= 99 && sec < 60 && frame < 75) { trackStart = Msf(min, sec, frame).lba() - 150; if (completeToc[j].start != trackStart) { // start does not match -> values are not BCD isBcd = 0; } } else { // bogus time code -> values are not BCD isBcd = 0; } } else { // track not found -> values are not BCD isBcd = 0; } } } if (isBcd == 1) { // verify last lead-out pointer trackStart = 0; // start of lead-out for (i = rawTocLen - 1; i >= 0; i--) { if ((rawToc[i].adrCtl & 0xf0) == 0x10 && // QMODE1 entry rawToc[i].point == 0xa2) { min = SubChannel::bcd2int(rawToc[i].pmin); sec = SubChannel::bcd2int(rawToc[i].psec); frame = SubChannel::bcd2int(rawToc[i].pframe); if (min <= 99 && sec < 60 && frame < 75) trackStart = Msf(min, sec, frame).lba() - 150; break; } } if (i < 0) { log_message(-1, "Found bogus toc data (no lead-out entry in raw data)."); log_message(-1, "Your drive probably does not support raw toc reading."); log_message(-1, "Using TOC data retrieved with generic method (no multi session support)."); log_message(-1, "Use driver option 0x%lx to suppress this message.", OPT_DRV_GET_TOC_GENERIC); delete[] rawToc; *cdTocLen = completeTocLen; return completeToc; } for (j = 0; j < completeTocLen; j++) { if (completeToc[j].track == 0xaa) { break; } } if (j < completeTocLen) { if (trackStart != completeToc[j].start) { // lead-out start does not match -> values are not BCD isBcd = 0; } } else { log_message(-2, "Found bogus toc data (no lead-out entry)."); delete[] completeToc; delete[] rawToc; return NULL; } } } if (isBcd == 0) { // verify that the decision is really correct. for (i = 0; i < rawTocLen && isBcd == 0; i++) { if ((rawToc[i].adrCtl & 0xf0) == 0x10 && // only process QMODE1 entries rawToc[i].point < 0xa0) { trackNr = rawToc[i].point; for (j = 0; j < completeTocLen; j++) { if (completeToc[j].track == trackNr) { break; } } if (j < completeTocLen) { min = rawToc[i].pmin; sec = rawToc[i].psec; frame = rawToc[i].pframe; if (min <= 99 && sec < 60 && frame < 75) { trackStart = Msf(min, sec, frame).lba() - 150; if (completeToc[j].start != trackStart) { // start does not match -> values are not HEX isBcd = -1; } } else { // bogus time code -> values are not HEX isBcd = -1; } } else { // track not found -> values are not BCD isBcd = -1; } } } // verify last lead-out pointer trackStart = 0; // start of lead-out for (i = rawTocLen - 1; i >= 0; i--) { if ((rawToc[i].adrCtl & 0xf0) == 0x10 && // QMODE1 entry rawToc[i].point == 0xa2) { min = rawToc[i].pmin; sec = rawToc[i].psec; frame = rawToc[i].pframe; if (min <= 99 && sec < 60 && frame < 75) trackStart = Msf(min, sec, frame).lba() - 150; break; } } if (i < 0) { log_message(-1, "Found bogus toc data (no lead-out entry in raw data)."); log_message(-1, "Your drive probably does not support raw toc reading."); log_message(-1, "Using TOC data retrieved with generic method (no multi session support)."); log_message(-1, "Use driver option 0x%lx to suppress this message.", OPT_DRV_GET_TOC_GENERIC); delete[] rawToc; *cdTocLen = completeTocLen; return completeToc; } for (j = 0; j < completeTocLen; j++) { if (completeToc[j].track == 0xaa) { break; } } if (j < completeTocLen) { if (trackStart != completeToc[j].start) { // lead-out start does not match -> values are not BCD isBcd = -1; } } else { log_message(-1, "Found bogus toc data (no lead-out entry)."); delete[] rawToc; delete[] completeToc; return NULL; } } if (isBcd == -1) { log_message(-1, "Could not determine if raw toc data is BCD or HEX. Please report!"); log_message(-1, "Using TOC data retrieved with generic method (no multi session support)."); log_message(-1, "Use driver option 0x%lx or 0x%lx to assume BCD or HEX data.", OPT_DRV_RAW_TOC_BCD, OPT_DRV_RAW_TOC_HEX); delete[] rawToc; *cdTocLen = completeTocLen; return completeToc; } } log_message(4, "Raw toc contains %s values.", isBcd == 0 ? "HEX" : "BCD"); for (i = 0; i < rawTocLen; i++) { if (rawToc[i].sessionNr == sessionNr && (rawToc[i].adrCtl & 0xf0) == 0x10 && /* QMODE1 entry */ rawToc[i].point < 0xa0) { nTracks++; } } if (nTracks == 0 || nTracks > 99) { log_message(-1, "Found bogus toc data (0 or > 99 tracks). Please report!"); log_message(-1, "Your drive probably does not support raw toc reading."); log_message(-1, "Using TOC data retrieved with generic method (no multi session support)."); log_message(-1, "Use driver option 0x%lx to suppress this message.", OPT_DRV_GET_TOC_GENERIC); delete[] rawToc; *cdTocLen = completeTocLen; return completeToc; } cdToc = new CdToc[nTracks + 1]; tocEnt = 0; lastTrack = -1; for (i = 0; i < rawTocLen; i++) { if (rawToc[i].sessionNr == sessionNr && (rawToc[i].adrCtl & 0xf0) == 0x10 && // QMODE1 entry rawToc[i].point < 0xa0) { if (isBcd) { trackNr = SubChannel::bcd2int(rawToc[i].point); trackStart = Msf(SubChannel::bcd2int(rawToc[i].pmin), SubChannel::bcd2int(rawToc[i].psec), SubChannel::bcd2int(rawToc[i].pframe)).lba(); } else { trackNr = rawToc[i].point; trackStart = Msf(rawToc[i].pmin, rawToc[i].psec, rawToc[i].pframe).lba(); } if (lastTrack != -1 && trackNr != lastTrack + 1) { log_message(-1, "Found bogus toc data (track number sequence). Please report!"); log_message(-1, "Your drive probably does not support raw toc reading."); log_message(-1, "Using TOC data retrieved with generic method (no multi session support)."); log_message(-1, "Use driver option 0x%lx to suppress this message.", OPT_DRV_GET_TOC_GENERIC); delete[] cdToc; delete[] rawToc; *cdTocLen = completeTocLen; return completeToc; } lastTrack = trackNr; cdToc[tocEnt].adrCtl = rawToc[i].adrCtl; cdToc[tocEnt].track = trackNr; cdToc[tocEnt].start = trackStart - 150; tocEnt++; } } // find lead-out pointer for (i = 0; i < rawTocLen; i++) { if (rawToc[i].sessionNr == sessionNr && (rawToc[i].adrCtl & 0xf0) == 0x10 && // QMODE1 entry rawToc[i].point == 0xa2 /* Lead-out pointer */) { if (isBcd) { trackStart = Msf(SubChannel::bcd2int(rawToc[i].pmin), SubChannel::bcd2int(rawToc[i].psec), SubChannel::bcd2int(rawToc[i].pframe)).lba(); } else { trackStart = Msf(rawToc[i].pmin, rawToc[i].psec, rawToc[i].pframe).lba(); } cdToc[tocEnt].adrCtl = rawToc[i].adrCtl; cdToc[tocEnt].track = 0xaa; cdToc[tocEnt].start = trackStart - 150; tocEnt++; break; } } if (tocEnt != nTracks + 1) { log_message(-1, "Found bogus toc data (no lead-out pointer for session). Please report!"); log_message(-1, "Your drive probably does not support raw toc reading."); log_message(-1, "Using TOC data retrieved with generic method (no multi session support)."); log_message(-1, "Use driver option 0x%lx to suppress this message.", OPT_DRV_GET_TOC_GENERIC); delete[] cdToc; delete[] rawToc; *cdTocLen = completeTocLen; return completeToc; } delete[] rawToc; delete[] completeToc; *cdTocLen = nTracks + 1; return cdToc; } static char *buildDataFileName(int trackNr, CdToc *toc, int nofTracks, const char *basename, const char *extension) { char buf[30]; int start, end; int run; int onlyOneAudioRange = 1; // don't modify the STDIN filename if (strcmp(basename, "-") == 0) return strdupCC(basename); if ((toc[trackNr].adrCtl & 0x04) != 0) { // data track snprintf(buf, sizeof(buf), "_%d", trackNr + 1); return strdup3CC(basename, buf, NULL); } // audio track, find continues range of audio tracks start = trackNr; while (start > 0 && (toc[start - 1].adrCtl & 0x04) == 0) start--; if (start > 0) { run = start - 1; while (run >= 0) { if ((toc[run].adrCtl & 0x04) == 0) { onlyOneAudioRange = 0; break; } run--; } } end = trackNr; while (end < nofTracks - 1 && (toc[end + 1].adrCtl & 0x04) == 0) end++; if (onlyOneAudioRange && end < nofTracks - 1) { run = end + 1; while (run < nofTracks) { if ((toc[run].adrCtl & 0x04) == 0) { onlyOneAudioRange = 0; break; } run++; } } if (onlyOneAudioRange) { return strdup3CC(basename, extension, NULL); } else { snprintf(buf, sizeof(buf), "_%d-%d", start + 1, end + 1); return strdup3CC(basename, buf, extension); } } /* Checks if drive's capabilites support the selected sub-channel reading mode for given track mode. mode: track mode caps: capabilities bits Return: 1: current sub-channel reading mode is supported 0: current sub-channel reading mode is not supported */ int CdrDriver::checkSubChanReadCaps(TrackData::Mode mode, unsigned long caps) { int ret = 0; switch (subChanReadMode_) { case TrackData::SUBCHAN_NONE: ret = 1; break; case TrackData::SUBCHAN_RW_RAW: if (mode == TrackData::AUDIO) { if ((caps & (CDR_READ_CAP_AUDIO_RW_RAW|CDR_READ_CAP_AUDIO_PW_RAW)) != 0) ret = 1; } else { if ((caps & (CDR_READ_CAP_DATA_RW_RAW|CDR_READ_CAP_DATA_PW_RAW)) != 0) ret = 1; } break; case TrackData::SUBCHAN_RW: if (mode == TrackData::AUDIO) { if ((caps & CDR_READ_CAP_AUDIO_RW_COOKED) != 0) ret = 1; } else { if ((caps & CDR_READ_CAP_DATA_RW_COOKED) != 0) ret = 1; } break; } return ret; } // Creates 'Toc' object for inserted CD. // session: session that should be analyzed // audioFilename: name of audio file that is placed into TOC // Return: newly allocated 'Toc' object or 'NULL' on error Toc *CdrDriver::readDiskToc(int session, const char *dataFilename) { int nofTracks = 0; int i, j; CdToc *cdToc = getToc(session, &nofTracks); Msf indexIncrements[98]; int indexIncrementCnt = 0; char isrcCode[13]; unsigned char trackCtl; // control nibbles of track int ctlCheckOk; char *fname; char *extension = NULL; char *p; TrackInfo *trackInfos; if (cdToc == NULL) { return NULL; } if (nofTracks <= 1) { log_message(-1, "No tracks on disk."); delete[] cdToc; return NULL; } log_message(1, ""); printCdToc(cdToc, nofTracks); log_message(1, ""); //return NULL; nofTracks -= 1; // do not count lead-out readCapabilities_ = getReadCapabilities(cdToc, nofTracks); fname = strdupCC(dataFilename); if ((p = strrchr(fname, '.')) != NULL) { extension = strdupCC(p); *p = 0; } trackInfos = new TrackInfo[nofTracks + 1]; memset(trackInfos, 0, (nofTracks + 1) * sizeof(TrackInfo)); for (i = 0; i < nofTracks; i++) { TrackData::Mode trackMode; if ((cdToc[i].adrCtl & 0x04) != 0) { if ((trackMode = getTrackMode(i + 1, cdToc[i].start)) == TrackData::MODE0) { log_message(-1, "Cannot determine mode of data track %d - assuming MODE1.", i + 1); trackMode = TrackData::MODE1; } if (rawDataReading_) { if (trackMode == TrackData::MODE1) { trackMode = TrackData::MODE1_RAW; } else if (trackMode == TrackData::MODE2) { trackMode = TrackData::MODE2_RAW; } else if (trackMode == TrackData::MODE2_FORM1 || trackMode == TrackData::MODE2_FORM2 || trackMode == TrackData::MODE2_FORM_MIX) { trackMode = TrackData::MODE2_RAW; } } else if (mode2Mixed_) { if (trackMode == TrackData::MODE2_FORM1 || trackMode == TrackData::MODE2_FORM2) { trackMode = TrackData::MODE2_FORM_MIX; } } } else { trackMode = TrackData::AUDIO; } if (!checkSubChanReadCaps(trackMode, readCapabilities_)) { log_message(-2, "This drive does not support %s sub-channel reading.", TrackData::subChannelMode2String(subChanReadMode_)); delete[] cdToc; delete[] trackInfos; delete[] fname; return NULL; } trackInfos[i].trackNr = cdToc[i].track; trackInfos[i].ctl = cdToc[i].adrCtl & 0x0f; trackInfos[i].mode = trackMode; trackInfos[i].start = cdToc[i].start; trackInfos[i].pregap = 0; trackInfos[i].fill = 0; trackInfos[i].indexCnt = 0; trackInfos[i].isrcCode[0] = 0; trackInfos[i].filename = buildDataFileName(i, cdToc, nofTracks, fname, extension); trackInfos[i].bytesWritten = 0; } // lead-out entry trackInfos[nofTracks].trackNr = 0xaa; trackInfos[nofTracks].ctl = 0; trackInfos[nofTracks].mode = trackInfos[nofTracks - 1].mode; trackInfos[nofTracks].start = cdToc[nofTracks].start; if (taoSource()) { trackInfos[nofTracks].start -= taoSourceAdjust_; } trackInfos[nofTracks].pregap = 0; trackInfos[nofTracks].fill = 0; trackInfos[nofTracks].indexCnt = 0; trackInfos[nofTracks].isrcCode[0] = 0; trackInfos[nofTracks].filename = NULL; trackInfos[nofTracks].bytesWritten = 0; long pregap = 0; long defaultPregap; long slba, elba; if (session == 1) { pregap = cdToc[0].start; // pre-gap of first track } for (i = 0; i < nofTracks; i++) { trackInfos[i].pregap = pregap; slba = trackInfos[i].start; elba = trackInfos[i + 1].start; defaultPregap = 0; if (taoSource()) { // assume always a pre-gap of 150 + # link blocks between two tracks // except between two audio tracks if ((trackInfos[i].mode != TrackData::AUDIO || trackInfos[i + 1].mode != TrackData::AUDIO) && i < nofTracks - 1) { defaultPregap = 150 + taoSourceAdjust_; } } else { // assume a pre-gap of 150 between tracks of different mode if (trackInfos[i].mode != trackInfos[i + 1].mode) { defaultPregap = 150; } } elba -= defaultPregap; Msf trackLength(elba - slba); log_message(1, "Analyzing track %02d (%s): start %s, ", i + 1, TrackData::mode2String(trackInfos[i].mode), Msf(cdToc[i].start).str()); log_message(1, "length %s...", trackLength.str()); if (pregap > 0) { log_message(2, "Found pre-gap: %s", Msf(pregap).str()); } isrcCode[0] = 0; indexIncrementCnt = 0; pregap = 0; trackCtl = 0; if (!fastTocReading_) { // Find index increments and pre-gap of next track if (trackInfos[i].mode == TrackData::AUDIO) { analyzeTrack(TrackData::AUDIO, i + 1, slba, elba, indexIncrements, &indexIncrementCnt, i < nofTracks - 1 ? &pregap : 0, isrcCode, &trackCtl); if (defaultPregap != 0) pregap = defaultPregap; } } else { if (trackInfos[i].mode == TrackData::AUDIO) { if (readIsrc(i + 1, isrcCode) != 0) { isrcCode[0] = 0; } } } if (pregap == 0) { pregap = defaultPregap; } if (isrcCode[0] != 0) { log_message(2, "Found ISRC code."); memcpy(trackInfos[i].isrcCode, isrcCode, 13); } for (j = 0; j < indexIncrementCnt; j++) trackInfos[i].index[j] = indexIncrements[j].lba(); trackInfos[i].indexCnt = indexIncrementCnt; if ((trackCtl & 0x80) != 0) { // Check track against TOC control nibbles ctlCheckOk = 1; if ((trackCtl & 0x01) != (cdToc[i].adrCtl & 0x01)) { log_message(-1, "Pre-emphasis flag of track differs from TOC - toc file contains TOC setting."); ctlCheckOk = 0; } if ((trackCtl & 0x08) != (cdToc[i].adrCtl & 0x08)) { log_message(-1, "2-/4-channel-audio flag of track differs from TOC - toc file contains TOC setting."); ctlCheckOk = 0; } if (ctlCheckOk) { log_message(2, "Control nibbles of track match CD-TOC settings."); } } } int padFirstPregap; if (onTheFly_) { if (session == 1 && (options_ & OPT_DRV_NO_PREGAP_READ) == 0) padFirstPregap = 0; else padFirstPregap = 1; } else { padFirstPregap = (session != 1) || padFirstPregap_; } Toc *toc = buildToc(trackInfos, nofTracks + 1, padFirstPregap); if (toc != NULL) { if ((options_ & OPT_DRV_NO_CDTEXT_READ) == 0) readCdTextData(toc); if (readCatalog(toc, trackInfos[0].start, trackInfos[nofTracks].start)) log_message(2, "Found disk catalogue number."); } // overwrite last time message log_message(1, " \t"); delete[] cdToc; delete[] trackInfos; delete[] fname; if (extension != NULL) delete[] extension; return toc; } // Implementation is based on binary search over all sectors of actual // track. ISRC codes are not extracted here. int CdrDriver::analyzeTrackSearch(TrackData::Mode, int trackNr, long startLba, long endLba, Msf *index, int *indexCnt, long *pregap, char *isrcCode, unsigned char *ctl) { isrcCode[0] = 0; *ctl = 0; if (pregap != NULL) { *pregap = findIndex(trackNr + 1, 0, startLba, endLba - 1); if (*pregap >= endLba) { *pregap = 0; } else if (*pregap > 0) { *pregap = endLba - *pregap; } } // check for index increments int ind = 2; long indexLba = startLba; *indexCnt = 0; do { if ((indexLba = findIndex(trackNr, ind, indexLba, endLba - 1)) > 0) { log_message(2, "Found index %d at %s", ind, Msf(indexLba).str()); if (*indexCnt < 98 && indexLba > startLba) { index[*indexCnt] = Msf(indexLba - startLba); *indexCnt += 1; } ind++; } } while (indexLba > 0 && indexLba < endLba); // Retrieve control nibbles of track, add 75 to track start so we // surely get a block of current track. int dummy, track; if (getTrackIndex(startLba + 75, &track, &dummy, ctl) == 0 && track == trackNr) { *ctl |= 0x80; } return 0; } int CdrDriver::getTrackIndex(long lba, int *trackNr, int *indexNr, unsigned char *ctl) { return 1; } // Scan from lba 'trackStart' to 'trackEnd' for the position at which the // index switchs to 'index' of track number 'track'. // return: lba of index start postion or 0 if index was not found long CdrDriver::findIndex(int track, int index, long trackStart, long trackEnd) { int actTrack; int actIndex; long start = trackStart; long end = trackEnd; long mid; //log_message(0, "findIndex: %ld - %ld", trackStart, trackEnd); while (start < end) { mid = start + ((end - start) / 2); //log_message(0, "Checking block %ld...", mid); if (getTrackIndex(mid, &actTrack, &actIndex, NULL) != 0) { return 0; } //log_message(0, "Found track %d, index %d", actTrack, actIndex); if ((actTrack < track || actIndex < index) && mid + 1 < trackEnd) { //log_message(0, " Checking block %ld...", mid + 1); if (getTrackIndex(mid + 1, &actTrack, &actIndex, NULL) != 0) { return 0; } //log_message(0, " Found track %d, index %d", actTrack, actIndex); if (actTrack == track && actIndex == index) { //log_message(0, "Found pregap at %ld", mid + 1); return mid; } else { start = mid + 1; } } else { end = mid; } } return 0; } int CdrDriver::analyzeTrackScan(TrackData::Mode, int trackNr, long startLba, long endLba, Msf *index, int *indexCnt, long *pregap, char *isrcCode, unsigned char *ctl) { SubChannel **subChannels; int n, i; int actIndex = 1; long length; long crcErrCnt = 0; long timeCnt = 0; int ctlSet = 0; int isrcCodeFound = 0; long trackStartLba = startLba; *isrcCode = 0; if (pregap != NULL) *pregap = 0; *indexCnt = 0; *ctl = 0; //startLba -= 75; if (startLba < 0) { startLba = 0; } length = endLba - startLba; while (length > 0) { n = (length > maxScannedSubChannels_) ? maxScannedSubChannels_ : length; if (readSubChannels(TrackData::SUBCHAN_NONE, startLba, n, &subChannels, NULL) != 0 || subChannels == NULL) { return 1; } for (i = 0; i < n; i++) { SubChannel *chan = subChannels[i]; //chan->print(); if (chan->checkCrc() && chan->checkConsistency()) { if (chan->type() == SubChannel::QMODE1DATA) { int t = chan->trackNr(); Msf time(chan->min(), chan->sec(), chan->frame()); // track rel time Msf atime(chan->amin(), chan->asec(), chan->aframe()); // abs time if (timeCnt > 74) { log_message(1, "%s\r", time.str()); timeCnt = 0; } if (t == trackNr && !ctlSet) { *ctl = chan->ctl(); *ctl |= 0x80; ctlSet = 1; } if (t == trackNr && chan->indexNr() == actIndex + 1) { actIndex = chan->indexNr(); log_message(2, "Found index %d at: %s", actIndex, time.str()); if ((*indexCnt) < 98) { index[*indexCnt] = time; *indexCnt += 1; } } else if (t == trackNr + 1) { if (chan->indexNr() == 0) { if (pregap != NULL) { // don't use time.lba() to calculate pre-gap length; it would // count one frame too many if the CD counts the pre-gap down // to 00:00:00 instead of 00:00:01 // Instead, count number of frames until start of Index 01 // See http://sourceforge.net/tracker/?func=detail&aid=604751&group_id=2171&atid=102171 // atime starts at 02:00, so subtract it *pregap = endLba - (atime.lba() - 150); } if (crcErrCnt != 0) log_message(2, "Found %ld Q sub-channels with CRC errors.", crcErrCnt); return 0; } } } else if (chan->type() == SubChannel::QMODE3) { if (!isrcCodeFound && startLba > trackStartLba) { strcpy(isrcCode, chan->isrc()); isrcCodeFound = 1; } } } else { crcErrCnt++; #if 0 if (chan->type() == SubChannel::QMODE1DATA) { log_message(2, "Q sub-channel data at %02d:%02d:%02d failed CRC check - ignored", chan->min(), chan->sec(), chan->frame()); } else { log_message(2, "Q sub-channel data failed CRC check - ignored."); } chan->print(); #endif } timeCnt++; } length -= n; startLba += n; } if (crcErrCnt != 0) log_message(2, "Found %ld Q sub-channels with CRC errors.", crcErrCnt); return 0; } // Checks if toc is suitable for writing. Usually all tocs are OK so // return just 0 here. // Return: 0: OK // 1: toc may not be suitable // 2: toc is not suitable int CdrDriver::checkToc(const Toc *toc) { int ret = 0; if (multiSession_ && toc->tocType() != Toc::Type::CD_ROM_XA) { log_message(-1, "The toc type should be set to CD_ROM_XA if a multi session"); log_message(-1, "CD is recorded."); ret = 1; } TrackIterator itr(toc); const Track *run; int tracknr; for (run = itr.first(), tracknr = 1; run != NULL; run = itr.next(), tracknr++) { if (run->subChannelType() != TrackData::SUBCHAN_NONE) { if (subChannelEncodingMode(run->subChannelType()) == -1) { log_message(-2, "Track %d: sub-channel writing mode is not supported by driver.", tracknr); ret = 2; } } } return ret; } // Returns block size for given mode and actual 'encodingMode_' that must // be used to send data to the recorder. long CdrDriver::blockSize(TrackData::Mode m, TrackData::SubChannelMode sm) const { long bsize = 0; if (encodingMode_ == 0) { // only audio blocks are written bsize = AUDIO_BLOCK_LEN; } else if (encodingMode_ == 1) { // encoding for SCSI-3/mmc drives in session-at-once mode switch (m) { case TrackData::AUDIO: bsize = AUDIO_BLOCK_LEN; break; case TrackData::MODE1: case TrackData::MODE1_RAW: bsize = MODE1_BLOCK_LEN; break; case TrackData::MODE2: case TrackData::MODE2_RAW: case TrackData::MODE2_FORM1: case TrackData::MODE2_FORM2: case TrackData::MODE2_FORM_MIX: bsize = MODE2_BLOCK_LEN; break; case TrackData::MODE0: log_message(-3, "Illegal mode in 'CdrDriver::blockSize()'."); break; } } else { log_message(-3, "Illegal encoding mode in 'CdrDriver::blockSize()'."); } bsize += TrackData::subChannelSize(sm); return bsize; } void CdrDriver::printCdToc(CdToc *toc, int tocLen) { int t; long len; log_message(1, "Track Mode Flags Start Length"); log_message(1, "------------------------------------------------------------"); for (t = 0; t < tocLen; t++) { if (t == tocLen - 1) { log_message(1, "Leadout %s %x %s(%6ld)", (toc[t].adrCtl & 0x04) != 0 ? "DATA " : "AUDIO", toc[t].adrCtl & 0x0f, Msf(toc[t].start).str(), toc[t].start); } else { len = toc[t + 1].start - toc[t].start; log_message(1, "%2d %s %x %s(%6ld) ", toc[t].track, (toc[t].adrCtl & 0x04) != 0 ? "DATA " : "AUDIO", toc[t].adrCtl & 0x0f, Msf(toc[t].start).str(), toc[t].start); log_message(1, " %s(%6ld)", Msf(len).str(), len); } } } TrackData::Mode CdrDriver::getTrackMode(int, long trackStartLba) { unsigned char cmd[10]; unsigned char data[2340]; int blockLength = 2340; TrackData::Mode mode; if (setBlockSize(blockLength) != 0) { return TrackData::MODE0; } memset(cmd, 0, 10); cmd[0] = 0x28; // READ10 cmd[2] = trackStartLba >> 24; cmd[3] = trackStartLba >> 16; cmd[4] = trackStartLba >> 8; cmd[5] = trackStartLba; cmd[8] = 1; if (sendCmd(cmd, 10, NULL, 0, data, blockLength) != 0) { setBlockSize(MODE1_BLOCK_LEN); return TrackData::MODE0; } setBlockSize(MODE1_BLOCK_LEN); mode = determineSectorMode(data); if (mode == TrackData::MODE0) { log_message(-2, "Found illegal mode in sector %ld.", trackStartLba); } return mode; } TrackData::Mode CdrDriver::determineSectorMode(unsigned char *buf) { switch (buf[3]) { case 1: return TrackData::MODE1; break; case 2: return analyzeSubHeader(buf + 4); break; } // illegal mode found return TrackData::MODE0; } // Analyzes given 8 byte sub head and tries to determine if it belongs // to a form 1, form 2 or a plain mode 2 sector. TrackData::Mode CdrDriver::analyzeSubHeader(unsigned char *sh) { if (sh[0] == sh[4] && sh[1] == sh[5] && sh[2] == sh[6] && sh[3] == sh[7]) { // check first copy //if (sh[0] < 8 && sh[1] < 8 && sh[2] != 0) { if ((sh[2] & 0x20) != 0) return TrackData::MODE2_FORM2; else return TrackData::MODE2_FORM1; //} #if 0 // check second copy if (sh[4] < 8 && sh[5] < 8 && sh[6] != 0) { if (sh[6] & 0x20 != 0) return TrackData::MODE2_FORM2; else return TrackData::MODE2_FORM1; } #endif } else { // no valid sub-header data, sector is a plain MODE2 sector return TrackData::MODE2; } } // Sets block size for read/write operation to given value. // blocksize: block size in bytes // density: (optional, default: 0) density code // Return: 0: OK // 1: SCSI command failed int CdrDriver::setBlockSize(long blocksize, unsigned char density) { unsigned char cmd[10]; unsigned char ms[16]; if (blockLength_ == blocksize) return 0; memset(ms, 0, 16); ms[3] = 8; ms[4] = density; ms[10] = blocksize >> 8; ms[11] = blocksize; memset(cmd, 0, 10); cmd[0] = 0x15; // MODE SELECT6 cmd[4] = 12; if (sendCmd(cmd, 6, ms, 12, NULL, 0) != 0) { log_message(-2, "Cannot set block size."); return 1; } blockLength_ = blocksize; return 0; } // Returns control flags for given track. unsigned char CdrDriver::trackCtl(const Track *track) { unsigned char ctl = 0; if (track->copyPermitted()) { ctl |= 0x20; } if (track->type() == TrackData::AUDIO) { // audio track if (track->preEmphasis()) { ctl |= 0x10; } if (track->audioType() == 1) { ctl |= 0x80; } } else { // data track ctl |= 0x40; } return ctl; } // Returns session format for point A0 toc entry depending on Toc type. unsigned char CdrDriver::sessionFormat() { unsigned char ret = 0; int nofMode1Tracks; int nofMode2Tracks; switch (toc_->tocType()) { case Toc::Type::CD_DA: case Toc::Type::CD_ROM: ret = 0x00; break; case Toc::Type::CD_I: ret = 0x10; break; case Toc::Type::CD_ROM_XA: /* The toc type can only be set to CD_ROM_XA if the session contains at least one data track. Otherwise the toc type must be CD_DA even in multi session mode. */ toc_->trackSummary(NULL, &nofMode1Tracks, &nofMode2Tracks); if (nofMode1Tracks + nofMode2Tracks > 0) ret = 0x20; else ret = 0x0; break; } log_message(3, "Session format: %x", ret); return ret; } // Generic method to read CD-TEXT packs according to the MMC-2 specification. // nofPacks: filled with number of found CD-TEXT packs // return: array of CD-TEXT packs or 'NULL' if no packs where retrieved CdTextPack *CdrDriver::readCdTextPacks(int *nofPacks) { unsigned char cmd[12]; unsigned char *data; unsigned char reqData[4]; *nofPacks = 0; #if 0 memset(cmd, 0, 12); cmd[0] = 0xbe; cmd[2] = 0xf0; cmd[3] = 0x00; cmd[4] = 0x00; cmd[5] = 0x00; cmd[8] = 15; cmd[9] = 0x0; cmd[10] = 0x1; long len1 = 15 * (AUDIO_BLOCK_LEN + 96); data = new unsigned char [len1]; if (sendCmd(cmd, 12, NULL, 0, data, len1) != 0) { log_message(1, "Cannot read raw CD-TEXT data."); } long i, j; unsigned char *p = data + AUDIO_BLOCK_LEN; log_message(0, "Raw CD-TEXT data"); for (i = 0; i < 15; i++) { unsigned char packs[72]; PWSubChannel96 chan(p); chan.getRawRWdata(packs); for (j = 0; j < 4; j++) { log_message(0, "%02x %02x %02x %02x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x CRC: %02x %02x", packs[j*18+0], packs[j*18+1], packs[j*18+2], packs[j*18+3], packs[j*18+4], packs[j*18+5], packs[j*18+6], packs[j*18+7], packs[j*18+8], packs[j*18+9], packs[j*18+10], packs[j*18+11], packs[j*18+12], packs[j*18+13], packs[j*18+14], packs[j*18+15], packs[j*18+16], packs[j*18+17]); } p += AUDIO_BLOCK_LEN + 96; } delete[] data; log_message(0, "Raw CD-TEXT data - end"); #endif memset(cmd, 0, 10); cmd[0] = 0x43; // READ TOC/PMA/ATIP cmd[2] = 5; // CD-TEXT cmd[8] = 4; if (sendCmd(cmd, 10, NULL, 0, reqData, 4, 0) != 0) { log_message(3, "Cannot read CD-TEXT data - maybe not supported by drive."); return NULL; } long len = ((reqData[0] << 8 ) | reqData[1]) + 2; log_message(4, "CD-TEXT data len: %ld", len); if (len <= 4) return NULL; if (len > scsiMaxDataLen_) { log_message(-2, "CD-TEXT data too big for maximum SCSI transfer length."); return NULL; } data = new unsigned char[len]; cmd[7] = len >> 8; cmd[8] = len; if (sendCmd(cmd, 10, NULL, 0, data, len, 1) != 0) { log_message(-2, "Reading of CD-TEXT data failed."); delete[] data; return NULL; } *nofPacks = (len - 4) / sizeof(CdTextPack); CdTextPack *packs = new CdTextPack[*nofPacks]; memcpy(packs, data + 4, *nofPacks * sizeof(CdTextPack)); delete[] data; return packs; } vector<CdTextItem*> processPacks(CdTextPack* packs, int nofPacks) { int pos = 0; unsigned char lastType; int lastBlockNumber; int lastTrackNumber; int actTrack = 0; unsigned char buf[256 * 12]; vector<CdTextItem*> items; if (nofPacks == 0) return items; lastType = packs[0].packType; lastBlockNumber = (packs[0].blockCharacter >> 4) & 0x07; lastTrackNumber = packs[0].trackNumber; while (nofPacks--) { CdTextPack& p = *packs++; log_message(4, "%02x %02x %02x %02x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x CRC: %02x %02x", p.packType, p.trackNumber, p.sequenceNumber, p.blockCharacter, p.data[0], p.data[1], p.data[2], p.data[3], p.data[4], p.data[5], p.data[6], p.data[7], p.data[8], p.data[9], p.data[10], p.data[11], p.crc0, p.crc1); int blockNumber = (p.blockCharacter >> 4) & 0x07; int trackNumber = p.trackNumber; if (lastType != p.packType || lastBlockNumber != blockNumber) { // Starting a new type section. if (lastType >= 0x80 && lastType <= 0x8f) { auto packType = CdTextItem::int2PackType(lastType); if (CdTextItem::isBinaryPack(packType)) { // finish binary data if (packType == CdTextItem::PackType::GENRE) { // The two genre codes may be followed by a string. Adjust // 'pos' so that all extra 0 bytes at the end of the data // are stripped off. int i; for (i = 2; i < pos && buf[i] != 0; i++); if (i < pos) pos = i+1; } { auto item = new CdTextItem(packType, lastBlockNumber); item->setData(buf, pos); if (packType != CdTextItem::PackType::SIZE_INFO) item->trackNr(lastTrackNumber); items.push_back(item); } } } else { log_message(-2, "CD-TEXT: Found invalid pack type: %02x", lastType); return items; } lastType = p.packType; lastBlockNumber = blockNumber; lastTrackNumber = trackNumber; pos = 0; actTrack = 0; } if (p.packType >= 0x80 && p.packType <= 0x8f) { auto packType = CdTextItem::int2PackType(p.packType); if (CdTextItem::isBinaryPack(packType)) { memcpy(buf + pos, p.data, 12); pos += 12; } else { // pack contains text -> read all string from it int i = 0; while (i < 12) { for (; i < 12 && p.data[i] != 0; i++) buf[pos++] = p.data[i]; if (i < 12) { // string is finished buf[pos] = 0; { auto item = new CdTextItem(packType, blockNumber); item->setRawText((u8*)buf, pos+1); item->trackNr(trackNumber); items.push_back(item); } pos = 0; trackNumber++; if (!CdTextItem::isBinaryPack(packType)) { // Skip zeroes while (i < 12 && p.data[i] == 0) i++; } else { i = 12; } } } } } else { log_message(-2, "CD-TEXT: Found invalid pack type: %02x", p.packType); return items; } } // Done processing the packs, process any leftover in the buffer. if (pos > 0 && lastType >= 0x80 && lastType <= 0x8f) { auto packType = CdTextItem::int2PackType(lastType); if (CdTextItem::isBinaryPack(packType)) { // finish binary data if (packType == CdTextItem::PackType::GENRE) { // The two genre codes may be followed by a string. Adjust // 'pos' so that all extra 0 bytes at the end of the data are // stripped off. int i; for (i = 2; i < pos && buf[i] != 0; i++); if (i < pos) pos = i + 1; } { auto item = new CdTextItem(packType, lastBlockNumber); item->setData(buf, pos); if (packType != CdTextItem::PackType::SIZE_INFO) item->trackNr(lastTrackNumber); items.push_back(item); } } } return items; } vector<CdTextItem*> CdrDriver::generateCdTextItems() { int nofPacks = 0; CdTextPack* packs = readCdTextPacks(&nofPacks); return processPacks(packs, nofPacks); } // Analyzes CD-TEXT packs and stores read data in given 'Toc' object. // Return: 0: OK // 1: error occured int CdrDriver::readCdTextData(Toc *toc) { bool languagesSet = false; vector<Util::Encoding> encodings(8, Util::Encoding::LATIN); auto items = generateCdTextItems(); if (items.size() == 0) return 1; log_message(1, "Found CD-TEXT data."); // First pass, collect SIZE_INFO information for (auto& item : items) { if (item->packType() == CdTextItem::PackType::SIZE_INFO) { const unsigned char *data = item->data(); // Update language mapping if (!languagesSet && item->dataLen() >= 36) { for (int i = 0; i < 8; i++) { if (data[28 + i] > 0) toc->cdTextLanguage(i, data[28 + i]); else toc->cdTextLanguage(i, -1); } languagesSet = true; } // Collect encodings if (item->dataLen() >= 1) { if (item->blockNr() >= 0 && item->blockNr() <= 8) encodings[item->blockNr()] = Util::characterCodeToEncoding(data[0]); } } } for (auto& item : items) { if (item->dataType() == CdTextItem::DataType::SBCC) item->encoding(encodings[item->blockNr()]); toc->addCdTextItem(item->trackNr(), item); } if (!languagesSet) { log_message(-1, "Cannot determine language mapping from CD-TEXT data."); log_message(-1, "Using default mapping."); } toc->enforceTextEncoding(); return 0; } int CdrDriver::analyzeDataTrack(TrackData::Mode mode, int trackNr, long startLba, long endLba, long *pregap) { long maxLen = scsiMaxDataLen_ / AUDIO_BLOCK_LEN; long lba = startLba; long len = endLba - startLba; long actLen, n; *pregap = 0; while (len > 0) { n = len > maxLen ? maxLen : len; if ((actLen = readTrackData(mode, TrackData::SUBCHAN_NONE, lba, n, transferBuffer_)) < 0) { log_message(-2, "Analyzing of track %d failed.", trackNr); return 1; } log_message(1, "%s\r", Msf(lba).str()); if (actLen != n) { //log_message(0, "Data track pre-gap: %ld", len - actLen); *pregap = len - actLen; if (*pregap > 300) { log_message(-1, "The pre-gap of the following track appears to have length %s.", Msf(*pregap).str()); log_message(-1, "This value is probably bogus and may be caused by unexpected"); log_message(-1, "behavior of the drive. Try to verify with other tools how"); log_message(-1, "much data can be read from the current track and compare it"); log_message(-1, "to the value stored in the toc-file. Usually, the pre-gap"); log_message(-1, "should have length 00:02:00."); } return 0; } len -= n; lba += n; } return 0; } /* Reads toc and audio data from CD for specified 'session' number. * The data is written to file 'dataFilename' unless on-the-fly writing * is active in which case the data is written to the file descriptor * 'onTheFlyFd'. * Return: newly created 'Toc' object or 'NULL' if an error occured */ Toc *CdrDriver::readDisk(int session, const char *dataFilename) { int padFirstPregap = 1; int nofTracks = 0; int i; CdToc *cdToc = getToc(session, &nofTracks); //unsigned char trackCtl; // control nibbles of track //int ctlCheckOk; TrackInfo *trackInfos; TrackData::Mode trackMode; int fp = -1; char *fname = strdupCC(dataFilename); Toc *toc = NULL; int trs = 0; int tre = 0; long slba, elba; ReadDiskInfo info; if (cdToc == NULL) { return NULL; } if (nofTracks <= 1) { log_message(-1, "No tracks on disk."); delete[] cdToc; return NULL; } log_message(1, ""); printCdToc(cdToc, nofTracks); log_message(1, ""); //return NULL; nofTracks -= 1; // do not count lead-out readCapabilities_ = getReadCapabilities(cdToc, nofTracks); trackInfos = new TrackInfo[nofTracks + 1]; for (i = 0; i < nofTracks; i++) { if ((cdToc[i].adrCtl & 0x04) != 0) { if ((trackMode = getTrackMode(i + 1, cdToc[i].start)) == TrackData::MODE0) { log_message(-1, "Cannot determine mode of data track %d - assuming MODE1.", i + 1); trackMode = TrackData::MODE1; } if (rawDataReading_) { if (trackMode == TrackData::MODE1) { trackMode = TrackData::MODE1_RAW; } else if (trackMode == TrackData::MODE2_FORM1 || trackMode == TrackData::MODE2_FORM2 || trackMode == TrackData::MODE2_FORM_MIX) { trackMode = TrackData::MODE2_RAW; } } else if (mode2Mixed_) { if (trackMode == TrackData::MODE2_FORM1 || trackMode == TrackData::MODE2_FORM2 || trackMode == TrackData::MODE2_FORM_MIX) { trackMode = TrackData::MODE2_FORM_MIX; } } } else { trackMode = TrackData::AUDIO; } if (!checkSubChanReadCaps(trackMode, readCapabilities_)) { log_message(-2, "This drive does not support %s sub-channel reading.", TrackData::subChannelMode2String(subChanReadMode_)); goto fail; } trackInfos[i].trackNr = cdToc[i].track; trackInfos[i].ctl = cdToc[i].adrCtl & 0x0f; trackInfos[i].mode = trackMode; trackInfos[i].start = cdToc[i].start; trackInfos[i].pregap = 0; trackInfos[i].fill = 0; trackInfos[i].indexCnt = 0; trackInfos[i].isrcCode[0] = 0; trackInfos[i].filename = fname; trackInfos[i].bytesWritten = 0; } // lead-out entry trackInfos[nofTracks].trackNr = 0xaa; trackInfos[nofTracks].ctl = 0; trackInfos[nofTracks].mode = trackInfos[nofTracks - 1].mode; trackInfos[nofTracks].start = cdToc[nofTracks].start; if (taoSource()) { trackInfos[nofTracks].start -= taoSourceAdjust_; } trackInfos[nofTracks].pregap = 0; trackInfos[nofTracks].indexCnt = 0; trackInfos[nofTracks].isrcCode[0] = 0; trackInfos[nofTracks].filename = NULL; trackInfos[nofTracks].bytesWritten = 0; if (onTheFly_) { fp = onTheFlyFd_; } else { giveUpRootPrivileges(); #ifdef __CYGWIN__ if ((fp = open(dataFilename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666)) < 0) #else if ((fp = open(dataFilename, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) #endif { log_message(-2, "Cannot open \"%s\" for writing: %s", dataFilename, strerror(errno)); delete[] cdToc; return NULL; } } info.tracks = nofTracks; info.startLba = trackInfos[0].start; info.endLba = trackInfos[nofTracks].start; while (trs < nofTracks) { if (trackInfos[trs].mode != TrackData::AUDIO) { if (trs == 0) { if (session == 1) trackInfos[trs].pregap = trackInfos[trs].start; } else { if (taoSource()) { trackInfos[trs].pregap = 150 + taoSourceAdjust_; } else { if (trackInfos[trs].mode != trackInfos[trs - 1].mode) trackInfos[trs].pregap = 150; } } slba = trackInfos[trs].start; elba = trackInfos[trs + 1].start; if (taoSource()) { if (trs < nofTracks - 1) elba -= 150 + taoSourceAdjust_; } else { if (trackInfos[trs].mode != trackInfos[trs + 1].mode) { elba -= 150; } } log_message(1, "Copying data track %d (%s): start %s, ", trs + 1, TrackData::mode2String(trackInfos[trs].mode), Msf(cdToc[trs].start).str()); log_message(1, "length %s to \"%s\"...", Msf(elba - slba).str(), trackInfos[trs].filename); if (readDataTrack(&info, fp, slba, elba, &trackInfos[trs]) != 0) goto fail; trs++; } else { // find continuous range of audio tracks tre = trs; while (tre < nofTracks && trackInfos[tre].mode == TrackData::AUDIO) tre++; if (trs == 0) { if (session == 1) trackInfos[trs].pregap = trackInfos[trs].start; } else { // previous track must be of different mode so assume a standard // pre-gap here if (taoSource()) { trackInfos[trs].pregap = 150 + taoSourceAdjust_; } else { trackInfos[trs].pregap = 150; } } slba = cdToc[trs].start; elba = cdToc[tre].start; // If we have the first track of the first session we can start ripping // from lba 0 to extract the pre-gap data. // But only if the drive supports it as indicated by 'options_'. if (session == 1 && trs == 0 && (options_ & OPT_DRV_NO_PREGAP_READ) == 0) { slba = 0; } // Assume that the pre-gap length conforms to the standard if the track // mode changes. if (taoSource()) { if (tre < nofTracks) elba -= 150 + taoSourceAdjust_; } else { if (trackInfos[tre - 1].mode != trackInfos[tre].mode) { elba -= 150; } } log_message(1, "Copying audio tracks %d-%d: start %s, ", trs + 1, tre, Msf(slba).str()); log_message(1, "length %s to \"%s\"...", Msf(elba - slba).str(), trackInfos[trs].filename); if (readAudioRange(&info, fp, slba, elba, trs, tre - 1, trackInfos) != 0) goto fail; trs = tre; } } // if the drive allows to read audio data from the first track's // pre-gap the data will be written to the output file and // 'buildToc()' must not create zero data for the pre-gap padFirstPregap = 1; if (session == 1 && (options_ & OPT_DRV_NO_PREGAP_READ) == 0) padFirstPregap = 0; toc = buildToc(trackInfos, nofTracks + 1, padFirstPregap); if (!onTheFly_ && toc != NULL) { if ((options_ & OPT_DRV_NO_CDTEXT_READ) == 0) readCdTextData(toc); if (readCatalog(toc, trackInfos[0].start, trackInfos[nofTracks].start)) { log_message(2, "Found disk catalogue number."); } } sendReadCdProgressMsg(RCD_EXTRACTING, nofTracks, nofTracks, 1000, 1000); fail: delete[] cdToc; delete[] trackInfos; delete[] fname; if (!onTheFly_ && fp >= 0) { if (close(fp) != 0) { log_message(-2, "Writing to \"%s\" failed: %s", dataFilename, strerror(errno)); delete toc; return NULL; } } return toc; } Toc *CdrDriver::buildToc(TrackInfo *trackInfos, long nofTrackInfos, int padFirstPregap) { long i, j; long nofTracks = nofTrackInfos - 1; int foundDataTrack = 0; int foundAudioTrack = 0; int foundXATrack = 0; long modeStartLba = 0; // start LBA for current mode unsigned long dataLen; TrackData::Mode trackMode; TrackData::Mode lastMode = TrackData::MODE0; // illegal in this context TrackData::SubChannelMode trackSubChanMode; int newMode; long byteOffset = 0; if (nofTrackInfos < 2) return NULL; Toc *toc = new Toc; // build the Toc for (i = 0; i < nofTracks; i++) { TrackInfo &ati = trackInfos[i]; // actual track info TrackInfo &nti = trackInfos[i + 1]; // next track info newMode = 0; trackMode = ati.mode; trackSubChanMode = subChanReadMode_; switch (trackMode) { case TrackData::AUDIO: foundAudioTrack = 1; break; case TrackData::MODE1: case TrackData::MODE1_RAW: case TrackData::MODE2: foundDataTrack = 1; break; case TrackData::MODE2_RAW: case TrackData::MODE2_FORM1: case TrackData::MODE2_FORM2: case TrackData::MODE2_FORM_MIX: foundXATrack = 1; break; case TrackData::MODE0: // should not happen break; } if (trackMode != lastMode) { newMode = 1; if (i == 0 && !padFirstPregap) modeStartLba = 0; else modeStartLba = ati.start; lastMode = trackMode; } Track t(trackMode, trackSubChanMode); t.preEmphasis(ati.ctl & 0x01); t.copyPermitted(ati.ctl & 0x02); t.audioType(ati.ctl & 0x08); if (ati.isrcCode[0] != 0) t.isrc(ati.isrcCode); if (trackMode == TrackData::AUDIO) { if (trackSubChanMode == TrackData::SUBCHAN_NONE) { if (newMode && (i > 0 || padFirstPregap)) { Msf trackLength(nti.start - ati.start - nti.pregap); if (ati.pregap > 0) { t.append(SubTrack(SubTrack::DATA, TrackData(Msf(ati.pregap).samples()))); } t.append(SubTrack(SubTrack::DATA, TrackData(ati.filename, byteOffset, 0, trackLength.samples()))); } else { Msf trackLength(nti.start - ati.start - nti.pregap + ati.pregap); t.append(SubTrack(SubTrack::DATA, TrackData(ati.filename, byteOffset, Msf(ati.start - modeStartLba - ati.pregap).samples(), trackLength.samples()))); } } else { if (newMode && (i > 0 || padFirstPregap)) { long trackLength = nti.start - ati.start - nti.pregap; if (ati.pregap > 0) { dataLen = ati.pregap * TrackData::dataBlockSize(trackMode, trackSubChanMode); t.append(SubTrack(SubTrack::DATA, TrackData(trackMode, trackSubChanMode, dataLen))); } dataLen = trackLength * TrackData::dataBlockSize(trackMode, trackSubChanMode); t.append(SubTrack(SubTrack::DATA, TrackData(trackMode, trackSubChanMode, ati.filename, byteOffset, dataLen))); } else { long trackLength = nti.start - ati.start - nti.pregap + ati.pregap; dataLen = trackLength * TrackData::dataBlockSize(trackMode, trackSubChanMode); long offset = (ati.start - modeStartLba - ati.pregap) * TrackData::dataBlockSize(trackMode, trackSubChanMode); t.append(SubTrack(SubTrack::DATA, TrackData(trackMode, trackSubChanMode, ati.filename, byteOffset + offset, dataLen))); } } t.start(Msf(ati.pregap)); } else { long trackLength = nti.start - ati.start - nti.pregap - ati.fill; if (ati.pregap != 0) { // add zero data for pre-gap dataLen = ati.pregap * TrackData::dataBlockSize(trackMode, trackSubChanMode); t.append(SubTrack(SubTrack::DATA, TrackData(trackMode, trackSubChanMode, dataLen))); } dataLen = trackLength * TrackData::dataBlockSize(trackMode, trackSubChanMode); t.append(SubTrack(SubTrack::DATA, TrackData(trackMode, trackSubChanMode, ati.filename, byteOffset, dataLen))); if (ati.fill > 0) { dataLen = ati.fill * TrackData::dataBlockSize(trackMode, trackSubChanMode); t.append(SubTrack(SubTrack::DATA, TrackData(trackMode, trackSubChanMode, dataLen))); } t.start(Msf(ati.pregap)); } for (j = 0; j < ati.indexCnt; j++) t.appendIndex(Msf(ati.index[j])); toc->append(&t); byteOffset += ati.bytesWritten; } if (foundXATrack) toc->tocType(Toc::Type::CD_ROM_XA); else if (foundDataTrack) toc->tocType(Toc::Type::CD_ROM); else toc->tocType(Toc::Type::CD_DA); return toc; } // Reads a complete data track. // start: start of data track from TOC // end: start of next track from TOC // trackInfo: info about current track, updated by this function // Return: 0: OK // 1: error occured int CdrDriver::readDataTrack(ReadDiskInfo *info, int fd, long start, long end, TrackInfo *trackInfo) { long len = end - start; long totalLen = len; long lba; long lastLba; long blockLen = 0; long blocking; long burst; long iterationsWithoutError = 0; long n, ret; long act; int foundLECError; unsigned char *buf; TrackData::Mode mode = TrackData::AUDIO; switch (trackInfo->mode) { case TrackData::MODE1: mode = TrackData::MODE1; blockLen = MODE1_BLOCK_LEN; break; case TrackData::MODE1_RAW: mode = TrackData::MODE1_RAW; blockLen = AUDIO_BLOCK_LEN; break; case TrackData::MODE2: mode = TrackData::MODE2; blockLen = MODE2_BLOCK_LEN; break; case TrackData::MODE2_RAW: mode = TrackData::MODE2_RAW; blockLen = AUDIO_BLOCK_LEN; break; case TrackData::MODE2_FORM1: mode = TrackData::MODE2_FORM1; blockLen = MODE2_FORM1_DATA_LEN; break; case TrackData::MODE2_FORM2: mode = TrackData::MODE2_FORM2; blockLen = MODE2_FORM2_DATA_LEN; break; case TrackData::MODE2_FORM_MIX: mode = TrackData::MODE2_FORM_MIX; blockLen = MODE2_BLOCK_LEN; break; case TrackData::MODE0: case TrackData::AUDIO: log_message(-3, "CdrDriver::readDataTrack: Illegal mode."); return 1; break; } blockLen += TrackData::subChannelSize(subChanReadMode_); // adjust mode in 'trackInfo' trackInfo->mode = mode; trackInfo->bytesWritten = 0; blocking = scsiMaxDataLen_ / (AUDIO_BLOCK_LEN + PW_SUBCHANNEL_LEN); assert(blocking > 0); buf = new unsigned char[blocking * blockLen]; lba = lastLba = start; burst = blocking; while (len > 0) { if (burst != blocking && iterationsWithoutError > 2 * blocking) burst = blocking; n = (len > burst) ? burst : len; foundLECError = 0; if ((act = readTrackData(mode, subChanReadMode_, lba, n, buf)) == -1) { log_message(-2, "Read error while copying data from track."); delete[] buf; return 1; } if (act == -2) { // L-EC error encountered if (trackInfo->mode == TrackData::MODE1_RAW || trackInfo->mode == TrackData::MODE2_RAW) { if (n > 1) { // switch to single step mode iterationsWithoutError = 0; burst = 1; continue; } else { foundLECError = 1; act = n = 0; } } else { log_message(-2, "L-EC error around sector %ld while copying data from track.", lba); log_message(-2, "Use option '--read-raw' to ignore L-EC errors."); delete[] buf; return 1; } } if (foundLECError) { iterationsWithoutError = 0; log_message(2, "Found L-EC error at sector %ld - ignored.", lba); // create a dummy sector for the sector with L-EC errors Msf m(lba + 150); memcpy(buf, syncPattern, 12); buf[12] = SubChannel::bcd(m.min()); buf[13] = SubChannel::bcd(m.sec()); buf[14] = SubChannel::bcd(m.frac()); if (trackInfo->mode == TrackData::MODE1_RAW) buf[15] = 1; else buf[15] = 2; memcpy(buf + 16, SECTOR_ERROR_DATA, blockLen - 16); if ((ret = fullWrite(fd, buf, blockLen)) != blockLen) { if (ret < 0) log_message(-2, "Writing of data failed: %s", strerror(errno)); else log_message(-2, "Writing of data failed: Disk full"); delete[] buf; return 1; } trackInfo->bytesWritten += blockLen; lba += 1; len -= 1; } else { iterationsWithoutError++; if (act > 0) { if ((ret = fullWrite(fd, buf, blockLen * act)) != blockLen * act) { if (ret < 0) log_message(-2, "Writing of data failed: %s", strerror(errno)); else log_message(-2, "Writing of data failed: Disk full"); delete[] buf; return 1; } } trackInfo->bytesWritten += blockLen * act; if (lba > lastLba + 75) { Msf lbatime(lba); log_message(1, "%02d:%02d:00\r", lbatime.min(), lbatime.sec()); lastLba = lba; if (remote_) { long totalProgress; long progress; progress = (totalLen - len) * 1000; progress /= totalLen; totalProgress = lba - info->startLba; if (totalProgress > 0) { totalProgress *= 1000; totalProgress /= (info->endLba - info->startLba); } else { totalProgress = 0; } sendReadCdProgressMsg(RCD_EXTRACTING, info->tracks, trackInfo->trackNr, progress, totalProgress); } } lba += act; len -= act; if (act != n) break; } } // pad remaining blocks with zero data, e.g. for disks written in TAO mode if (len > 0) { log_message(-1, "Padding with %ld zero sectors.", len); if (mode == TrackData::MODE1_RAW || mode == TrackData::MODE2_RAW) { memcpy(buf, syncPattern, 12); if (mode == TrackData::MODE1_RAW) buf[15] = 1; else buf[15] = 2; memset(buf + 16, 0, blockLen - 16); } else { memset(buf, 0, blockLen); } while (len > 0) { if (mode == TrackData::MODE1_RAW || mode == TrackData::MODE2_RAW) { Msf m(lba + 150); buf[12] = SubChannel::bcd(m.min()); buf[13] = SubChannel::bcd(m.sec()); buf[14] = SubChannel::bcd(m.frac()); } if ((ret = fullWrite(fd, buf, blockLen)) != blockLen) { if (ret < 0) log_message(-2, "Writing of data failed: %s", strerror(errno)); else log_message(-2, "Writing of data failed: Disk full"); delete[] buf; return 1; } trackInfo->bytesWritten += blockLen; len--; lba++; } } delete[] buf; return 0; } // Tries to read the catalog number from the sub-channels starting at LBA 0. // If a catalog number is found it will be placed into the provided 14 byte // buffer 'mcnCode'. Otherwise 'mcnCode[0]' is set to 0. // Return: 0: OK // 1: SCSI error occured #define N_ELEM 11 #define MCN_LEN 13 #define MAX_MCN_SCAN_LENGTH 5000 static int cmpMcn(const void *p1, const void *p2) { const char *s1 = (const char *)p1; const char *s2 = (const char *)p2; return strcmp(s1, s2); } int CdrDriver::readCatalogScan(char *mcnCode, long startLba, long endLba) { SubChannel **subChannels; int n, i; long length; int mcnCodeFound = 0; char mcn[N_ELEM][MCN_LEN+1]; *mcnCode = 0; length = endLba - startLba; if (length > MAX_MCN_SCAN_LENGTH) length = MAX_MCN_SCAN_LENGTH; while ((length > 0) && (mcnCodeFound < N_ELEM)) { n = (length > maxScannedSubChannels_ ? maxScannedSubChannels_ : length); if (readSubChannels(TrackData::SUBCHAN_NONE, startLba, n, &subChannels, NULL) != 0 || subChannels == NULL) { return 1; } for (i = 0; i < n; i++) { SubChannel *chan = subChannels[i]; //chan->print(); if (chan->checkCrc() && chan->checkConsistency()) { if (chan->type() == SubChannel::QMODE2) { if (mcnCodeFound < N_ELEM) { strcpy(mcn[mcnCodeFound++], chan->catalog()); } } } } length -= n; startLba += n; } if(mcnCodeFound > 0) { qsort(mcn, mcnCodeFound, MCN_LEN + 1, cmpMcn); strcpy(mcnCode, mcn[(mcnCodeFound >> 1)]); } return 0; } #undef N_ELEM #undef MCN_LEN #undef MAX_MCN_SCAN_LENGTH // Sends a read cd progress message without blocking the actual process. void CdrDriver::sendReadCdProgressMsg(ReadCdProgressType type, int totalTracks, int track, int trackProgress, int totalProgress) { if (remote_) { int fd = remoteFd_; ProgressMsg p; p.status = type; p.totalTracks = totalTracks; p.track = track; p.trackProgress = trackProgress; p.totalProgress = totalProgress; p.bufferFillRate = 0; p.writerFillRate = 0; if (write(fd, REMOTE_MSG_SYNC_, sizeof(REMOTE_MSG_SYNC_)) != sizeof(REMOTE_MSG_SYNC_) || write(fd, (const char*)&p, sizeof(p)) != sizeof(p)) { log_message(-1, "Failed to send read CD remote progress message."); } } } // Sends a write cd progress message without blocking the actual process. int CdrDriver::sendWriteCdProgressMsg(WriteCdProgressType type, int totalTracks, int track, int trackProgress, int totalProgress, int bufferFillRate, int writeFill) { if (remote_) { int fd = remoteFd_; ProgressMsg p; p.status = type; p.totalTracks = totalTracks; p.track = track; p.trackProgress = trackProgress; p.totalProgress = totalProgress; p.bufferFillRate = bufferFillRate; p.writerFillRate = writeFill; if (write(fd, REMOTE_MSG_SYNC_, sizeof(REMOTE_MSG_SYNC_)) != sizeof(REMOTE_MSG_SYNC_) || write(fd, (const char*)&p, sizeof(p)) != sizeof(p)) { log_message(-1, "Failed to send write CD remote progress message."); return 1; } } return 0; } // Sends a blank cd progress message without blocking the actual process. int CdrDriver::sendBlankCdProgressMsg(int totalProgress) { if (remote_) { int fd = remoteFd_; ProgressMsg p; p.status = PGSMSG_BLK; p.totalTracks = 0; p.track = 0; p.trackProgress = 0; p.totalProgress = totalProgress; p.bufferFillRate = 0; p.writerFillRate = 0; if (write(fd, REMOTE_MSG_SYNC_, sizeof(REMOTE_MSG_SYNC_)) != sizeof(REMOTE_MSG_SYNC_) || write(fd, (const char*)&p, sizeof(p)) != sizeof(p)) { log_message(-1, "Failed to send write CD remote progress message."); return 1; } } return 0; } long CdrDriver::audioRead(TrackData::SubChannelMode sm, int byteOrder, Sample *buffer, long startLba, long len) { SubChannel **chans; int i; int swap; long blockLen = AUDIO_BLOCK_LEN + TrackData::subChannelSize(sm); if (readSubChannels(sm, startLba, len, &chans, buffer) != 0) { memset(buffer, 0, len * blockLen); audioReadError_ = 1; return len; } swap = (audioDataByteOrder_ == byteOrder) ? 0 : 1; if (options_ & OPT_DRV_SWAP_READ_SAMPLES) swap = !swap; if (swap) { unsigned char *b = (unsigned char*)buffer; for (i = 0; i < len; i++) { swapSamples((Sample *)b, SAMPLES_PER_BLOCK); b += blockLen; } } if (remote_ && startLba > audioReadLastLba_) { long totalTrackLen = audioReadTrackInfo_[audioReadActTrack_ + 1].start - audioReadTrackInfo_[audioReadActTrack_ ].start; long progress = startLba - audioReadTrackInfo_[audioReadActTrack_ ].start; long totalProgress; if (progress > 0) { progress *= 1000; progress /= totalTrackLen; } else { progress = 0; } totalProgress = startLba + len - audioReadInfo_->startLba; if (totalProgress > 0) { totalProgress *= 1000; totalProgress /= audioReadInfo_->endLba - audioReadInfo_->startLba; } else { totalProgress = 0; } sendReadCdProgressMsg(RCD_EXTRACTING, audioReadInfo_->tracks, audioReadActTrack_ + 1, progress, totalProgress); audioReadLastLba_ = startLba; } if (chans == NULL) { // drive does not provide sub channel data so that's all we could do here: if (startLba > audioReadTrackInfo_[audioReadActTrack_ + 1].start) { audioReadActTrack_++; log_message(1, "Track %d...", audioReadActTrack_ + 1); } if (startLba - audioReadProgress_ > 75) { audioReadProgress_ = startLba; Msf m(audioReadProgress_); log_message(1, "%02d:%02d:00\r", m.min(), m.sec()); } return len; } // analyze sub-channels to find pre-gaps, index marks and ISRC codes for (i = 0; i < len; i++) { SubChannel *chan = chans[i]; //chan->print(); if (chan->checkCrc() && chan->checkConsistency()) { if (chan->type() == SubChannel::QMODE1DATA) { int t = chan->trackNr() - 1; Msf atime = Msf(chan->amin(), chan->asec(), chan->aframe()); //log_message(0, "LastLba: %ld, ActLba: %ld", audioReadActLba_, atime.lba()); if (t >= audioReadStartTrack_ && t <= audioReadEndTrack_ && atime.lba() > audioReadActLba_ && atime.lba() - 150 < audioReadTrackInfo_[t + 1].start) { Msf time(chan->min(), chan->sec(), chan->frame()); // track rel time audioReadActLba_ = atime.lba(); if (audioReadActLba_ - audioReadProgress_ > 75) { audioReadProgress_ = audioReadActLba_; Msf m(audioReadProgress_ - 150); log_message(1, "%02d:%02d:00\r", m.min(), m.sec()); } if (t == audioReadActTrack_ && chan->indexNr() == audioReadActIndex_ + 1) { if (chan->indexNr() > 1) { log_message(2, "Found index %d at: %s", chan->indexNr(), time.str()); if (audioReadTrackInfo_[t].indexCnt < 98) { audioReadTrackInfo_[t].index[audioReadTrackInfo_[t].indexCnt] = time.lba(); audioReadTrackInfo_[t].indexCnt += 1; } } } else if (t == audioReadActTrack_ + 1) { log_message(1, "Track %d...", t + 1); //chan->print(); if (chan->indexNr() == 0) { // don't use time.lba() to calculate pre-gap length; it would // count one frame too many if the CD counts the pre-gap down // to 00:00:00 instead of 00:00:01 // Instead, count number of frames until start of Index 01 // See http://sourceforge.net/tracker/?func=detail&aid=604751&group_id=2171&atid=102171 // atime starts at 02:00, so subtract it audioReadTrackInfo_[t].pregap = (startLba + len + 1) - \ (atime.lba() - 150); log_message(2, "Found pre-gap: %s", Msf(audioReadTrackInfo_[t].pregap).str()); } } audioReadActIndex_ = chan->indexNr(); audioReadActTrack_ = t; } } else if (chan->type() == SubChannel::QMODE3) { if (audioReadTrackInfo_[audioReadActTrack_].isrcCode[0] == 0) { log_message(2, "Found ISRC code."); strcpy(audioReadTrackInfo_[audioReadActTrack_].isrcCode, chan->isrc()); } } } else { audioReadCrcCount_++; } } return len; } int CdrDriver::readAudioRangeStream(ReadDiskInfo *info, int fd, long start, long end, int startTrack, int endTrack, TrackInfo *trackInfo) { long startLba = start; long endLba = end - 1; long len, ret; long blocking, blockLen; long lba = startLba; unsigned char *buf; blockLen = AUDIO_BLOCK_LEN + TrackData::subChannelSize(subChanReadMode_); blocking = scsiMaxDataLen_ / blockLen; assert(blocking > 0); buf = new unsigned char[blocking * blockLen]; audioReadInfo_ = info; audioReadTrackInfo_ = trackInfo; audioReadStartTrack_ = startTrack; audioReadEndTrack_ = endTrack; audioReadLastLba_ = audioReadActLba_ = startLba + 149; audioReadActTrack_ = startTrack; audioReadActIndex_ = 1; audioReadCrcCount_ = 0; audioReadError_ = 0; audioReadProgress_ = 0; len = endLba - startLba + 1; log_message(1, "Track %d...", startTrack + 1); trackInfo[endTrack].bytesWritten = 0; while (len > 0) { long n = len > blocking ? blocking : len; long bytesToWrite = n * blockLen; CdrDriver::audioRead(subChanReadMode_, 1/*big endian byte order*/, (Sample *)buf, lba, n); lba += n; if ((ret = fullWrite(fd, buf, bytesToWrite)) != bytesToWrite) { if (ret < 0) log_message(-2, "Writing of data failed: %s", strerror(errno)); else log_message(-2, "Writing of data failed: Disk full"); delete[] buf; return 1; } trackInfo[endTrack].bytesWritten += bytesToWrite; len -= n; } if (audioReadCrcCount_ != 0) log_message(2, "Found %ld Q sub-channels with CRC errors.", audioReadCrcCount_); delete[] buf; return 0; } // read cdda paranoia related: void CdrDriver::paranoiaMode(int mode) { paranoiaMode_ = PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP; switch (mode) { case 0: paranoiaMode_ = PARANOIA_MODE_DISABLE; break; case 1: paranoiaMode_ |= PARANOIA_MODE_OVERLAP; paranoiaMode_ &= ~PARANOIA_MODE_VERIFY; break; case 2: paranoiaMode_ &= ~(PARANOIA_MODE_SCRATCH|PARANOIA_MODE_REPAIR); break; } } int CdrDriver::readAudioRangeParanoia(ReadDiskInfo *info, int fd, long start, long end, int startTrack, int endTrack, TrackInfo *trackInfo) { long startLba = start; long endLba = end - 1; long len, ret; size16 *buf; if (paranoia_ == NULL) { // first time -> allocate paranoia structure paranoiaDrive_ = new cdrom_drive; paranoiaDrive_->cdr = this; paranoiaDrive_->nsectors = maxScannedSubChannels_; paranoia_ = paranoia_init(paranoiaDrive_); } paranoia_set_range(paranoia_, startLba, endLba); paranoia_modeset(paranoia_, paranoiaMode_); audioReadInfo_ = info; audioReadTrackInfo_ = trackInfo; audioReadStartTrack_ = startTrack; audioReadEndTrack_ = endTrack; audioReadLastLba_ = audioReadActLba_ = startLba + 149; audioReadActTrack_ = startTrack; audioReadActIndex_ = 1; audioReadCrcCount_ = 0; audioReadError_ = 0; audioReadProgress_ = 0; len = endLba - startLba + 1; log_message(1, "Track %d...", startTrack + 1); trackInfo[endTrack].bytesWritten = 0; while (len > 0) { buf = paranoia_read(paranoia_, &CdrDriver::paranoiaCallback); // The returned samples are always in host byte order. We want to // output in big endian byte order so swap if we are a little // endian host. if (hostByteOrder_ == 0) swapSamples((Sample*)buf, SAMPLES_PER_BLOCK); if ((ret = fullWrite(fd, buf, AUDIO_BLOCK_LEN)) != AUDIO_BLOCK_LEN) { if (ret < 0) log_message(-2, "Writing of data failed: %s", strerror(errno)); else log_message(-2, "Writing of data failed: Disk full"); return 1; } trackInfo[endTrack].bytesWritten += AUDIO_BLOCK_LEN; len--; } if (audioReadCrcCount_ != 0) log_message(2, "Found %ld Q sub-channels with CRC errors.", audioReadCrcCount_); return 0; } long cdda_read(cdrom_drive *d, void *buffer, long beginsector, long sectors) { CdrDriver *cdr = (CdrDriver*)d->cdr; return cdr->audioRead(TrackData::SUBCHAN_NONE, cdr->hostByteOrder(), (Sample*)buffer, beginsector, sectors); } void CdrDriver::paranoiaCallback(long, int) { } std::ostream& operator<<(std::ostream& os, const CdTextPack& pack) { static char line[80]; snprintf(line, sizeof(line), "type %02x track %2d seq %3d bc %02x : ", pack.packType, pack.trackNumber, pack.sequenceNumber, pack.blockCharacter); os << line; for (int i = 0; i < 12; i++) { snprintf(line, sizeof(line), "%02x ", pack.data[i]); os << line; } return os; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/CdrDriver.h���������������������������������������������������������������0000664�0000000�0000000�00000061007�15114537466�0017502�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #ifndef __CDRDRIVER_H__ #define __CDRDRIVER_H__ #include <vector> #include "ScsiIf.h" #include "Msf.h" #include "TrackData.h" #include "SubChannel.h" #include "remote.h" class Toc; class Track; class CdTextItem; #define OPT_DRV_GET_TOC_GENERIC 0x00010000 #define OPT_DRV_SWAP_READ_SAMPLES 0x00020000 #define OPT_DRV_NO_PREGAP_READ 0x00040000 #define OPT_DRV_RAW_TOC_BCD 0x00080000 #define OPT_DRV_RAW_TOC_HEX 0x00100000 #define OPT_DRV_NO_CDTEXT_READ 0x00200000 // reading capabilities #define CDR_READ_CAP_AUDIO_PW_RAW 0x001 #define CDR_READ_CAP_AUDIO_RW_COOKED 0x002 #define CDR_READ_CAP_AUDIO_RW_RAW 0x004 #define CDR_READ_CAP_AUDIO_PQ_BCD 0x008 #define CDR_READ_CAP_AUDIO_PQ_HEX 0x010 #define CDR_READ_CAP_DATA_PW_RAW 0x020 #define CDR_READ_CAP_DATA_RW_COOKED 0x040 #define CDR_READ_CAP_DATA_RW_RAW 0x080 #define CDR_READ_CAP_DATA_PQ_BCD 0x100 #define CDR_READ_CAP_DATA_PQ_HEX 0x200 #define CDR_AUDIO_SCAN_CAP (CDR_READ_CAP_AUDIO_PW_RAW|CDR_READ_CAP_AUDIO_PQ_BCD|CDR_READ_CAP_AUDIO_PQ_HEX) struct DiskInfo { long capacity; // recordable capacity of medium Msf manufacturerId; // disk identification int recSpeedLow; // lowest recording speed int recSpeedHigh; // highest recording speed int sessionCnt; // number of closed sessions int lastTrackNr; // number of last track on disk long lastSessionLba; // start lba of first track of last closed session long thisSessionLba; // start lba of this session int diskTocType; // type of CD TOC, only valid if CD-R is not empty unsigned int empty : 1; // 1 for empty disk, else 0 unsigned int append : 1; // 1 if CD-R is appendable, else 0 unsigned int cdrw : 1; // 1 if disk is a CD-RW struct { unsigned int empty : 1; unsigned int append : 1; unsigned int cdrw : 1; unsigned int capacity : 1; unsigned int manufacturerId : 1; unsigned int recSpeed : 1; } valid; }; struct DriveInfo { int maxReadSpeed; int currentReadSpeed; int maxWriteSpeed; int currentWriteSpeed; unsigned int accurateAudioStream : 1; unsigned int burnProof : 1; unsigned int ricohJustLink : 1; unsigned int ricohJustSpeed : 1; }; struct CdTextPack { unsigned char packType; unsigned char trackNumber; unsigned char sequenceNumber; unsigned char blockCharacter; unsigned char data[12]; unsigned char crc0; unsigned char crc1; }; std::ostream& operator<<(std::ostream& os, const CdTextPack& pack); struct CdToc { int track; // number long start; // LBA of track start unsigned char adrCtl; // ADR/CTL field }; struct CdRawToc { int sessionNr; int point; int min; int sec; int frame; int pmin; int psec; int pframe; unsigned char adrCtl; }; struct TrackInfo { int trackNr; // track number unsigned char ctl; // flags TrackData::Mode mode; // track data mode long start; // absolute start position from CD TOC long pregap; // pre-gap length of track in blocks long fill; // number of blocks to fill with zero data at end int indexCnt; // number of index increments long index[98]; // index marks char isrcCode[13]; // ISRC code, valid if 'isrcCode[0] != 0' char *filename; // data file name long bytesWritten; // number of bytes written to file }; class CdrDriver { public: CdrDriver(ScsiIf *scsiIf, unsigned long options); virtual ~CdrDriver(); // returns stored SCSI interface object virtual ScsiIf *scsiIf() const { return scsiIf_; } // sets SCSI interface object void scsiIf(ScsiIf *i) { scsiIf_ = i; } // returns name of driver virtual const char *driverName() const { return driverName_; } // returns options flags virtual unsigned long options() const { return options_; } // returns 1 if drive takes audio samples in big endian byte order or // 0 for little endian byte order virtual int bigEndianSamples() const = 0; // return information about drive virtual const DriveInfo *driveInfo(bool showErrorMsg) { return NULL; } // returns current writing speed virtual int speed() { return speed_; } // returns current reading speed virtual int rspeed() { return rspeed_; } // sets writing speed, returns 0 for OK or 1 for illegal speed, // this function may send SCSI commands to the drive virtual int speed(int) = 0; // sets reading speed, returns 0 for OK or 1 for illegal speed, // this function may send SCSI commands to the drive virtual bool rspeed(int); // sets/return buffer under run protection setting (if supported by // the drive: 1 = enabled, 0 = disbaled virtual int bufferUnderRunProtection() const { return enableBufferUnderRunProtection_; } virtual void bufferUnderRunProtection(int s) { enableBufferUnderRunProtection_ = s != 0 ? 1 : 0; } // sets/return writing speed control setting (if supported by // the drive: 1 = enabled, 0 = disbaled virtual int writeSpeedControl() const { return enableWriteSpeedControl_; } virtual void writeSpeedControl(int s) { enableWriteSpeedControl_ = s != 0 ? 1 : 0; } // returns 1 if simulation mode, 0 for real writing virtual bool simulate() const { return simulate_; } // sets simulation mode, returns 0 for OK, 1 if given mode is not supported virtual void simulate(bool s) { simulate_ = s; } // Sets multi session mode (0: close session, 1: open next session). // Returns 1 if multi session is not supported by driver, else 0 virtual int multiSession(bool); // Returns mutli session mode. virtual bool multiSession() const { return multiSession_; } // Returns/sets fast toc reading flag (no sub-channel analysis) virtual bool fastTocReading() const { return fastTocReading_; } virtual void fastTocReading(bool f) { fastTocReading_ = f; } // Returns/sets raw data track reading flag virtual bool rawDataReading() const { return rawDataReading_; } virtual void rawDataReading(bool f) { rawDataReading_ = f; } // Returns/sets mode2 mixed track reading flag virtual bool mode2Mixed() const { return mode2Mixed_; } virtual void mode2Mixed(bool f) { mode2Mixed_ = f; } virtual TrackData::SubChannelMode subChanReadMode() const { return subChanReadMode_; } virtual void subChanReadMode(TrackData::SubChannelMode m) { subChanReadMode_ = m; } // Sets/returns the pad first pre-gap flag virtual int padFirstPregap() const { return padFirstPregap_; } virtual void padFirstPregap(int f) { padFirstPregap_ = f != 0 ? 1 : 0; } // Returns the on-thy-fly flag. virtual int onTheFly() const { return onTheFly_; } // Sets file descriptor for on the fly data and sets the on-the-fly flag // if 'fd' is >= 0 and clears it otherwise virtual void onTheFly(int fd); // Returns force flag virtual bool force() const { return force_; } // Sets force flag virtual void force(bool f) { force_ = f; } // Returns TAO source flag virtual bool taoSource() const { return taoSource_; } // Sets TAO source flag virtual void taoSource(bool f) { taoSource_ = f; } // Return number of adjust sectors for reading TAO source disks virtual int taoSourceAdjust() const { return taoSourceAdjust_; } // Sets number of adjust sectors for reading TAO source disks virtual void taoSourceAdjust(int val); // Sets remote mode virtual void remote(int flag, int fd); // Return remote mode flag virtual int remote() { return remote_; } // Sets cdda paranoia mode void paranoiaMode(int); // Sets user defined capacity virtual void userCapacity(int c) { userCapacity_ = c; } // Sets burning to the outer edge mode virtual void fullBurn(bool f) { fullBurn_ = f; } // Return byte order of host (0: little endian, 1: big endian) int hostByteOrder() const { return hostByteOrder_; } // general commands virtual int testUnitReady(int) const; virtual int startStopUnit(int) const; virtual int preventMediumRemoval(int) const; virtual int rezeroUnit(int showMessage = 1) const; virtual int loadUnload(int) const = 0; virtual int flushCache() const; virtual int readCapacity(long *length, int showMessage = 1); virtual int getPerformance(); virtual bool readBufferCapacity(long* total, long* available) { return false; } // CD-RW specific commands enum BlankingMode { BLANK_FULL, BLANK_MINIMAL }; virtual int blankDisk(BlankingMode); // disk at once recording related commands // Returns acceptable sub-channel encoding mode for given sub-channel type: // -1: writing of sub-channel type not supported at all // 0: accepts plain data without encoding // 1: accepts only completely encoded data virtual int subChannelEncodingMode(TrackData::SubChannelMode) const; // Should check if toc is suitable for DAO writing with the actual driver. // Returns 0 if toc is OK, else 1. // Usually all tocs are suitable for writing so that the base class // implementation simply returns 0. virtual int checkToc(const Toc *); // Used to make necessary initializations but without touching the CD-R. // It should be possible to abort the writing process after this function // has been called without destroying the CD-R. virtual int initDao(const Toc *) = 0; // Performs all steps that must be done before the first user data block // is written, e.g. sending cue sheet, writing lead-in. virtual int startDao() = 0; // Performs all steps for successfully finishing the writing process, // e.g. writing lead-out, flushing the cache. virtual int finishDao() = 0; // Aborts writing process. Called if an error occurs or the user aborts // recording prematurely. virtual void abortDao() = 0; // Sends given data to drive. 'lba' should be the current writing address // and will be updated according to the written number of blocks. virtual int writeData(TrackData::Mode, TrackData::SubChannelMode sm, long &lba, const char *buf, long len); // returns mode for main channel data encoding, the value is used by // Track::readData() // 0: raw audio mode, all sectors must be encoded as audio sectors // 1: no encoding for MODE1 and MODE2 sectors, MODE2_FORM1 and MODE2_FORM2 // are extended by sub header and zero EDC/ECC data int encodingMode() const { return encodingMode_; } // disk read commands // analyzes the CD structure (Q sub-channels) of the inserted CD virtual Toc *readDiskToc(int session, const char *); // analyzes the CD structure and reads data virtual Toc *readDisk(int session, const char *); // returns information about inserted medium virtual DiskInfo *diskInfo() { return 0; } // returns CDTEXT information std::vector<CdTextItem*> generateCdTextItems(); // Returns block size depending on given sector mode and 'encodingMode_' // that must be used to send data to the recorder. virtual long blockSize(TrackData::Mode, TrackData::SubChannelMode) const; // sends a status message to the driving application if in remote mode enum WriteCdProgressType { WCD_LEADIN = PGSMSG_WCD_LEADIN, WCD_DATA = PGSMSG_WCD_DATA, WCD_LEADOUT = PGSMSG_WCD_LEADOUT }; int sendWriteCdProgressMsg(WriteCdProgressType type, int totalTracks, int track, int trackProgress, int totalProgress, int bufferFillRate, int writeBufferFill = 0); int sendBlankCdProgressMsg(int totalProgress); // static functions // Selects driver id for given vendor/model string. NULL is returned if // no driver could be selected. // readWrite: 0: select a driver for read operations // 1: select a driver for write operations // options: filled with option flags for vendor/model static const char *selectDriver(int readWrite, const char *vendor, const char *model, unsigned long *options); // Creates instance of driver with specified id. static CdrDriver *createDriver(const char *driverId, unsigned long options, ScsiIf *); // Try to autodetect a driver on given Scsi interface. static const char *detectDriver(ScsiIf *, unsigned long *options); // Prints list of all available driver ids. static void printDriverIds(); // returns vendor/type of CD-R medium static int cdrVendor(Msf &, const char **vendor, const char** mediumType); // Generic function to retrieve basic TOC data. Cannot distinguish // between different sessions. CdToc *getTocGeneric(int *nofTracks); // reads CD-TEXT data and adds it to given 'Toc' object int readCdTextData(Toc *); protected: struct ReadDiskInfo { int tracks; // total number of tracks long startLba; // LBA where extraction starts long endLba; // LBA where extraction ends }; unsigned long options_; // driver option flags ScsiIf *scsiIf_; int scsiMaxDataLen_; const char *driverName_; int hostByteOrder_; // 0: little endian, 1: big endian unsigned long readCapabilities_; int blockLength_; // length of data block for 'writeData' command long blocksPerWrite_; // number of blocks that can be written with a // single SCSI WRITE command char *zeroBuffer_; // zeroed buffer for writing zeros int enableBufferUnderRunProtection_; int enableWriteSpeedControl_; int speed_; int rspeed_; bool simulate_; bool multiSession_; int encodingMode_; // mode for encoding data sectors bool fastTocReading_; bool rawDataReading_; int mode2Mixed_; TrackData::SubChannelMode subChanReadMode_; int padFirstPregap_; // used by 'read-toc': defines if the first audio // track's pre-gap is padded with zeros in the toc-file // or if it is taken from the data file int onTheFly_; // 1 if operating in on-the-fly mode int onTheFlyFd_; // file descriptor for on the fly data bool force_; // force flag to allow certain operations int remote_; // 1 for remote mode, else 0 int remoteFd_; // file descriptor for remote messages bool taoSource_; // 1 to indicate a TAO writting source CD for read-cd/read-toc int taoSourceAdjust_; // number of unreadable sectors between two tracks // written in TAO mode const Toc *toc_; SubChannel **scannedSubChannels_; long maxScannedSubChannels_; unsigned char *transferBuffer_; // Byte order of audio samples read from the drive, e.g. with // 'readSubChannels()'. 0: little endian, 1: big endian int audioDataByteOrder_; int userCapacity_; bool fullBurn_; static unsigned char syncPattern[12]; static unsigned char REMOTE_MSG_SYNC_[4]; static int speed2Mult(int); static int mult2Speed(int); virtual int sendCmd(const unsigned char *cmd, int cmdLen, const unsigned char *dataOut, int dataOutLen, unsigned char *dataIn, int dataInLen, int showErrorMsg = 1) const; virtual int getModePage(int pageCode, unsigned char *buf, long bufLen, unsigned char *modePageHeader, unsigned char *blockDesc, int showErrorMsg); virtual int setModePage(const unsigned char *buf, const unsigned char *modePageHeader, const unsigned char *blockDesc, int showErrorMsg); // some drives (e.g. Yamaha CDR100) don't implement mode sense/select(10) virtual int getModePage6(int pageCode, unsigned char *buf, long bufLen, unsigned char *modePageHeader, unsigned char *blockDesc, int showErrorMsg); virtual int setModePage6(const unsigned char *buf, const unsigned char *modePageHeader, const unsigned char *blockDesc, int showErrorMsg); virtual int writeZeros(TrackData::Mode, TrackData::SubChannelMode, long &lba, long encLba, long count); // Returns track control flags for given track, bits 0-3 are always zero virtual unsigned char trackCtl(const Track *track); // Returns session format code for point A0 TOC entry, generated from // stored 'toc_' object. virtual unsigned char sessionFormat(); // readToc related functions: // returns TOC data of specified session of inserted CD, // a generic function is implemented in 'CdrDriver.cc', it will return // the tracks of all session or of the first session depending on the // drive virtual CdToc *getToc(int sessionNr, int *nofTracks); // Reads raw toc data of inserted CD. Used by base implementation of // 'getToc()' and must be implemented by the actual driver. virtual CdRawToc *getRawToc(int sessionNr, int *len) = 0; // Tries to determine the data mode of specified track. virtual TrackData::Mode getTrackMode(int trackNr, long trackStartLba); // Determines mode of given sector, 'buf' should contain the sector header // at the first 4 bytes followed by the sub-header for XA tracks. // If an illegal mode is found in the sector header 'MODE0' will be // returned. TrackData::Mode determineSectorMode(unsigned char *buf); // analyzes given 8 byte sub header and returns wether the sector is // a MODE2, MODE2_FORM1 or MODE2_FORM2 sector TrackData::Mode analyzeSubHeader(unsigned char *); virtual unsigned long getReadCapabilities(const CdToc *, int) const = 0; // Called by 'readDiskToc()' to retrieve following information about // the track 'trackNr' with given start/end lba addresses: // - all index increments, filled into 'index'/'indexCnt' // - ISRC Code, filled into provided buffer 'isrcCode' (13 bytes) // - length of pre-gap of next track, filled into 'pregap' // - control nibbles read from track, filled into bits 0-3 of 'ctrl', // bit 7 must be set to indicate valid data // This function must be overloaded by an actual driver. // return: 0: OK, 1: error occured virtual int analyzeTrack(TrackData::Mode, int trackNr, long startLba, long endLba, Msf *index, int *indexCnt, long *pregap, char *isrcCode, unsigned char *ctl) = 0; // Track analysis algorithm using the binary search method. The base // class implements the basic algorithm. It uses 'findIndex()' which // can be implemented by an actual driver to get the track and index // number at a specific block address. This base class contains an // implementation of 'findIndex()', too, that can be usually used. // It'll be always better to use the linear scan algorithm (see below) // if possible. int analyzeTrackSearch(TrackData::Mode, int trackNr, long startLba, long endLba, Msf *index, int *indexCnt, long *pregap, char *isrcCode, unsigned char *ctl); // finds position (lba) where index for given track number switches to // 'index' (binary search, base algorithm is implemented in 'CdrDriver'). // It uses the method 'getTrackIndex()' which must be overloaded by // the actual driver. virtual long findIndex(int track, int index, long trackStart, long trackEnd); // Retrieves track, index and control nibbles at given lba address. Must // be implemented by the driver if the binary search method // ('analyzeTrackSearch()') should be used. virtual int getTrackIndex(long lba, int *trackNr, int *indexNr, unsigned char *ctl); // Basic track analyzis using the linear scan algorithm. The base class // implements the basic algorithm which calls 'readSubChannels()' to // read the sub-channel data. Actual drivers should overload the // 'readSubChannels()' function. int analyzeTrackScan(TrackData::Mode, int trackNr, long startLba, long endLba, Msf *index, int *indexCnt, long *pregap, char *isrcCode, unsigned char *ctl); // Reads 'len' sub-channels from sectors starting at 'lba'. // The returned vector contains 'len' pointers to 'SubChannel' objects. // Audio data that is usually retrieved with the sub-channels is placed // in 'buf' if it is not NULL. // Used by 'analyzeTrackScan()' and 'readAudioRangeParanoia()'. virtual int readSubChannels(TrackData::SubChannelMode, long lba, long len, SubChannel ***, Sample *buf) = 0; // Determines the readable length of a data track and the pre-gap length // of the following track. The implementation in the base class should // be suitable for all drivers. virtual int analyzeDataTrack(TrackData::Mode mode, int trackNr, long startLba, long endLba, long *pregap); // Reads 'len' data sectors starting at 'lba' and returns the number of // successfully read sectors. If the end of the current track is encountered // the returned value will be smaller than 'len' down to 0. If a read // error occus -1 is returned. If a L-EC error occures -2 is returned. // This method is used by 'readDataTrack'/'analyzeDataTrack' and must be // overloaded by the driver. virtual long readTrackData(TrackData::Mode, TrackData::SubChannelMode, long lba, long len, unsigned char *buf) = 0; // Reads a complete data track and saves data to a file. virtual int readDataTrack(ReadDiskInfo *, int fp, long start, long end, TrackInfo *trackInfo); // Reads the audio data of given audio track range 'startTrack', 'endTrack'. // 'trackInfo' is am array of TrackInfo structures for all tracks. // This function is called by 'readDisk()' and must be overloaded by the // actual driver. virtual int readAudioRange(ReadDiskInfo *, int fp, long start, long end, int startTrack, int endTrack, TrackInfo *) = 0; virtual int readAudioRangeStream(ReadDiskInfo *, int fd, long start, long end, int startTrack, int endTrack, TrackInfo *); // Reads catalog number by scanning the sub-channels. // Uses 'readSubChannels()' to read the the sub-channels. int readCatalogScan(char *mcnCode, long startLba, long endLba); // Reads catalog number and stores it in given 'Toc' object. Must be // implemented by the actual driver. 'startLba' and 'endLba' specify // the allowed range for sub-channel scanning. virtual int readCatalog(Toc *toc, long startLba, long endLba) = 0; // Reads ISRC code and writes into provided 13 bytes buffer. Must be // implemented by the actual driver. virtual int readIsrc(int trackNr, char *) = 0; // Build Toc object from gathered TrackInfo data Toc *buildToc(TrackInfo *trackInfos, long nofTrackInfos, int padFirstPregap); // sets block size for read/write operations virtual int setBlockSize(long blocksize, unsigned char density = 0); // checks if drive capabilities support requested sub-channel reading mode int checkSubChanReadCaps(TrackData::Mode, unsigned long caps); // Reads CD-TEXT packs from the lead-in of a CD. The base implementation // uses the SCSI-3/mmc commands. virtual CdTextPack *readCdTextPacks(int *); void printCdToc(CdToc *toc, int tocLen); enum ReadCdProgressType { RCD_ANALYZING = PGSMSG_RCD_ANALYZING, RCD_EXTRACTING = PGSMSG_RCD_EXTRACTING }; void sendReadCdProgressMsg(ReadCdProgressType, int totalTracks, int track, int trackProgress, int totalProgress); public: // function to read audio data and also the sub-channel data from // specified lba, // this function is called from 'cdda_read()', so that it is currently // public because I did not manage to define a friend function that has // C linkage :) long audioRead(TrackData::SubChannelMode, int byteOrder, Sample *buffer, long startLba, long len); // Interface for Monty's paranoia library: protected: // Extracts audio data for given track range with the help of // Monty's paranoia library. int readAudioRangeParanoia(ReadDiskInfo *, int fp, long start, long end, int startTrack, int endTrack, TrackInfo *trackInfo); private: // dynamic data void *paranoia_; // paranoia structure struct cdrom_drive *paranoiaDrive_; // paranoia device int paranoiaMode_; // paranoia mode ReadDiskInfo *audioReadInfo_; TrackInfo *audioReadTrackInfo_; int audioReadStartTrack_; int audioReadEndTrack_; long audioReadLastLba_; long audioReadActLba_; int audioReadActTrack_; int audioReadActIndex_; long audioReadCrcCount_; int audioReadError_; long audioReadProgress_; // callback for the paranoia library, does nothing, currently static void paranoiaCallback(long, int); // friend classes: friend class CDD2600Base; }; #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/GenericMMC.cc�������������������������������������������������������������0000664�0000000�0000000�00000177131�15114537466�0017673�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #include <config.h> #include <string.h> #include <time.h> #include <assert.h> #include "GenericMMC.h" #include "port.h" #include "Toc.h" #include "log.h" #include "PQSubChannel16.h" #include "PWSubChannel96.h" #include "CdTextEncoder.h" // Variants for cue sheet generation // do not set ctl flags for ISRC cue sheet entries #define CUE_VAR_ISRC_NO_CTL 0x1 // do not set start of lead-in time in lead-in cue sheet entry #define CUE_VAR_CDTEXT_NO_TIME 0x2 #define CUE_VAR_MAX 0x3 // Variants for write parameters mode page //do not set data block type to block size 2448 if a CD-TEXT lead-in is written #define WMP_VAR_CDTEXT_NO_DATA_BLOCK_TYPE 0x1 #define WMP_VAR_MAX 0x1 GenericMMC::GenericMMC(ScsiIf *scsiIf, unsigned long options) : CdrDriver(scsiIf, options) { int i; driverName_ = "Generic SCSI-3/MMC - Version 2.0"; speed_ = 0; rspeed_ = 0; simulate_ = true; encodingMode_ = 1; scsiTimeout_ = 0; cdTextEncoder_ = NULL; driveInfo_ = NULL; memset(&diskInfo_, 0, sizeof(DiskInfo)); for (i = 0; i < maxScannedSubChannels_; i++) { if (options_ & OPT_MMC_USE_PQ) scannedSubChannels_[i] = new PQSubChannel16; else scannedSubChannels_[i] = new PWSubChannel96; } cdtextEnabled_ = (options_ & OPT_MMC_CD_TEXT); // MMC drives usually return little endian samples audioDataByteOrder_ = 0; // Check if drive supports R-W subchannels-TEXT writing (i.e. CD-TEXT) u8 cdMasteringFeature[8]; if (getFeature(0x2e, cdMasteringFeature, 8, 1) == 0) { if (cdMasteringFeature[4] & 0x01) { log_message(2, "CD-TEXT writing is supported."); cdtextEnabled_ = true; } } } GenericMMC::~GenericMMC() { int i; for (i = 0; i < maxScannedSubChannels_; i++) { delete scannedSubChannels_[i]; scannedSubChannels_[i] = NULL; } delete cdTextEncoder_; cdTextEncoder_ = NULL; delete driveInfo_; driveInfo_ = NULL; } // static constructor CdrDriver *GenericMMC::instance(ScsiIf *scsiIf, unsigned long options) { return new GenericMMC(scsiIf, options); } int GenericMMC::checkToc(const Toc *toc) { int err = CdrDriver::checkToc(toc); int e; if (cdtextEnabled_) { if ((e = toc->checkCdTextData()) > err) err = e; } return err; } int GenericMMC::subChannelEncodingMode(TrackData::SubChannelMode sm) const { int ret = 0; switch (sm) { case TrackData::SUBCHAN_NONE: ret = 0; break; case TrackData::SUBCHAN_RW: #if 0 if (options_ & OPT_MMC_NO_RW_PACKED) ret = 1; // have to encode the R-W sub-channel data else ret = 0; #endif ret = 0; break; case TrackData::SUBCHAN_RW_RAW: // raw R-W sub-channel writing is assumed to be always supported ret = 1; break; } return ret; } // sets speed // return: 0: OK // 1: illegal speed int GenericMMC::speed(int s) { speed_ = s; if (selectSpeed() != 0) return 1; return 0; } int GenericMMC::speed() { const DriveInfo *di; delete driveInfo_; driveInfo_ = NULL; if ((di = driveInfo(true)) == NULL) { return 0; } return speed2Mult(di->currentWriteSpeed); } // sets fspeed // return: true: OK // false: illegal speed bool GenericMMC::rspeed(int s) { rspeed_ = s; if (selectSpeed() != 0) return false; return true; } int GenericMMC::rspeed() { const DriveInfo *di; delete driveInfo_; driveInfo_ = NULL; if ((di = driveInfo(true)) == NULL) { return 0; } return speed2Mult(di->currentReadSpeed); } // loads ('unload' == 0) or ejects ('unload' == 1) tray // return: 0: OK // 1: scsi command failed int GenericMMC::loadUnload(int unload) const { u8 cmd[6]; // First send an ALLOW MEDIUM REMOVAL command // sg_utils equivalent: // sg_prevent --allow <dev> // memset(cmd, 0, 6); cmd[0] = 0x1e; // PREVENT ALLOW MEDIUM REMOVAL sendCmd(cmd, 6, NULL, 0, NULL, 0); // Next, the START/STOP unit. // sg_utils Equivalent: // sg_start --eject <dev> // memset(cmd, 0, 6); cmd[0] = 0x1b; // START/STOP UNIT if (unload) { cmd[4] = 0x02; // LoUnlo=1, Start=0 } else { cmd[4] = 0x03; // LoUnlo=1, Start=1 } if (sendCmd(cmd, 6, NULL, 0, NULL, 0) != 0) { log_message(-2, "Cannot load/unload medium."); return 1; } return 0; } // Checks for ready status of the drive after a write operation // Return: 0: drive ready // 1: error occured // 2: drive not ready int GenericMMC::checkDriveReady() const { unsigned char cmd[10]; unsigned char data[4]; int ret; ret = testUnitReady(0); if (ret == 0) { // testUnitReady reports ready status but this might actually not // be the truth -> additionally check the READ DISK INFO command memset(cmd, 0, 10); cmd[0] = 0x51; // READ DISK INFORMATION cmd[8] = 4; ret = sendCmd(cmd, 10, NULL, 0, data, 4, 0); if (ret == 2) { const u8 *sense; int senseLen; ret = 0; // indicates ready status sense = scsiIf_->getSense(senseLen); if (senseLen >= 14 && (sense[2] & 0x0f) == 0x2 && sense[7] >= 6 && sense[12] == 0x4 && (sense[13] == 0x8 || sense[13] == 0x7)) { // Not Ready, long write in progress ret = 2; // indicates not ready status } } } return ret; } // Performs complete blanking of a CD-RW. // return: 0: OK // 1: scsi command failed int GenericMMC::blankDisk(BlankingMode mode) { u8 cmd[12]; int ret, progress; time_t startTime, endTime; setSimulationMode(0); memset(cmd, 0, 12); cmd[0] = 0xa1; // BLANK switch (mode) { case BLANK_FULL: cmd[1] = 0x0; // erase complete disk break; case BLANK_MINIMAL: cmd[1] = 0x1; // erase PMA, lead-in and 1st track's pre-gap break; } cmd[1] |= 1 << 4; // immediate return sendBlankCdProgressMsg(0); if (sendCmd(cmd, 12, NULL, 0, NULL, 0, 1) != 0) { log_message(-2, "Cannot erase CD-RW."); return 1; } time(&startTime); progress = 0; do { mSleep(2000); ret = checkDriveReady(); if (ret == 1) { log_message(-2, "Test Unit Ready command failed."); } progress += 10; sendBlankCdProgressMsg(progress); if (progress >= 1000) progress = 0; } while (ret == 2); if (ret == 0) sendBlankCdProgressMsg(1000); time(&endTime); log_message(2, "Blanking time: %ld seconds", endTime - startTime); return ret; } // sets read/write speed and simulation mode // return: 0: OK // 1: scsi command failed int GenericMMC::selectSpeed() { u8 cmd[12]; int spd; memset(cmd, 0, 12); cmd[0] = 0xbb; // SET CD SPEED // select maximum read speed if (rspeed_ == 0) { cmd[2] = 0xff; cmd[3] = 0xff; } else { spd = mult2Speed(rspeed_); cmd[2] = spd >> 8; cmd[3] = spd; } // select maximum write speed if (speed_ == 0) { cmd[4] = 0xff; cmd[5] = 0xff; } else { spd = mult2Speed(speed_); cmd[4] = spd >> 8; cmd[5] = spd; } if ((options_ & OPT_MMC_YAMAHA_FORCE_SPEED) != 0 && writeSpeedControl()) cmd[11] = 0x80; // enable Yamaha's force speed if (sendCmd(cmd, 12, NULL, 0, NULL, 0) != 0) { log_message(-2, "Cannot set cd speed."); return 1; } return 0; } // Determins start and length of lead-in and length of lead-out. // return: 0: OK // 1: SCSI command failed int GenericMMC::getSessionInfo() { u8 cmd[10]; unsigned long dataLen = 34; u8 data[34]; memset(cmd, 0, 10); memset(data, 0, dataLen); cmd[0] = 0x51; // READ DISK INFORMATION cmd[7] = dataLen >> 8; cmd[8] = dataLen; if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) { log_message(-2, "Cannot retrieve disk information."); return 1; } leadInStart_ = Msf(data[17], data[18], data[19]); if (leadInStart_.lba() >= Msf(80, 0, 0).lba()) { leadInLen_ = 450000 - leadInStart_.lba(); if (fullBurn_) { leadOutLen_ = (userCapacity_ ? Msf(userCapacity_, 0, 0).lba() : diskInfo_.capacity) + Msf(1, 30, 0).lba() - toc_->length().lba() - diskInfo_.thisSessionLba - 150; // Fill all rest space <vladux> if (leadOutLen_ < Msf(1, 30, 0).lba()) { leadOutLen_ = Msf(1, 30, 0).lba(); // 90 seconds lead-out } } else { leadOutLen_ = Msf(1, 30, 0).lba(); // 90 seconds lead-out } } else { leadInLen_ = Msf(1, 0, 0).lba(); leadOutLen_ = Msf(0, 30, 0).lba(); } log_message(4, "Lead-in start: %s length: %ld", leadInStart_.str(), leadInLen_); log_message(4, "Lead-out length: %ld", leadOutLen_); return 0; } bool GenericMMC::readBufferCapacity(long *capacity, long *available) { u8 cmd[10]; u8 data[12]; long bufsize; memset(cmd, 0, 10); memset(data, 0, 12); cmd[0] = 0x5c; // READ BUFFER CAPACITY cmd[8] = 12; if (sendCmd(cmd, 10, NULL, 0, data, 12) != 0) { log_message(-2, "Read buffer capacity failed."); return false; } *capacity = (data[4] << 24) | (data[5] << 16) | (data[6] << 8) | data[7]; *available = (data[8] << 24) | (data[9] << 16) | (data[10] << 8) | data[11]; return true; } int GenericMMC::performPowerCalibration() { u8 cmd[10]; int ret; long old_timeout; memset(cmd, 0, 10); cmd[0] = 0x54; // SEND OPC INFORMATION cmd[1] = 1; log_message(2, "Executing power calibration..."); old_timeout = scsiIf_->timeout(30); ret = sendCmd(cmd, 10, NULL, 0, NULL, 0); (void)scsiIf_->timeout(old_timeout); if (ret == 0) { log_message(2, "Power calibration successful."); return 0; } if (ret == 2) { const u8 *sense; int senseLen; sense = scsiIf_->getSense(senseLen); if (senseLen >= 14 && (sense[2] & 0x0f) == 0x5 && sense[7] >= 6 && sense[12] == 0x20 && sense[13] == 0x0) { log_message(2, "Power calibration not supported."); return 0; } /* else fall trough */ } log_message(-2, "Power calibration failed."); return 1; } // Sets write parameters via mode page 0x05. // return: 0: OK // 1: scsi command failed int GenericMMC::setWriteParameters(unsigned long variant) { u8 mp[0x38]; u8 mpHeader[8]; u8 blockDesc[8]; if (getModePage(5/*write parameters mode page*/, mp, 0x38, mpHeader, blockDesc, 1) != 0) { log_message(-2, "Cannot retrieve write parameters mode page."); return 1; } mp[0] &= 0x7f; // clear PS flag mp[2] &= 0xe0; mp[2] |= 0x02; // write type: Session-at-once if (simulate_) { mp[2] |= 1 << 4; // test write } const DriveInfo *di; if ((di = driveInfo(true)) != NULL) { if (di->burnProof) { // This drive has BURN-Proof function. // Enable it unless explicitly disabled. if (bufferUnderRunProtection()) { log_message(2, "Turning BURN-Proof on"); mp[2] |= 0x40; } else { log_message(2, "Turning BURN-Proof off"); mp[2] &= ~0x40; } } RicohSetWriteOptions(di); } mp[3] &= 0x3f; // Multi-session: No B0 pointer, next session not allowed if (multiSession_) mp[3] |= 0x03 << 6; // open next session else if (!diskInfo_.empty) mp[3] |= 0x01 << 6; // use B0=FF:FF:FF when closing last session of a // multi session CD-R log_message(4, "Multi session mode: %d", mp[3] >> 6); mp[4] &= 0xf0; // Data Block Type: raw data, block size: 2352 (I think not // used for session at once writing) if (cdTextEncoder_ != NULL) { if ((variant & WMP_VAR_CDTEXT_NO_DATA_BLOCK_TYPE) == 0) mp[4] |= 3; /* Data Block Type: raw data with raw P-W sub-channel data, block size 2448, required for CD-TEXT lead-in writing according to the SCSI/MMC-3 manual */ } log_message(4, "Data block type: %u", mp[4] & 0x0f); mp[8] = sessionFormat(); if (!diskInfo_.empty) { // use the toc type of the already recorded sessions switch (diskInfo_.diskTocType) { case 0x00: case 0x10: case 0x20: mp[8] = diskInfo_.diskTocType; break; } } log_message(4, "Toc type: 0x%x", mp[8]); if (setModePage(mp, mpHeader, NULL, 0) != 0) { log_message(-2, "Cannot set write parameters mode page."); return 1; } return 0; } // Sets simulation mode via mode page 0x05. // return: 0: OK // 1: scsi command failed int GenericMMC::setSimulationMode(int showMessage) { u8 mp[0x38]; u8 mpHeader[8]; if (getModePage(5/*write parameters mode page*/, mp, 0x38, mpHeader, NULL, showMessage) != 0) { if (showMessage) log_message(-2, "Cannot retrieve write parameters mode page."); return 1; } mp[0] &= 0x7f; // clear PS flag if (simulate_) mp[2] |= 1 << 4; // test write else mp[2] &= ~(1 << 4); if (setModePage(mp, mpHeader, NULL, showMessage) != 0) { if (showMessage) log_message(-2, "Cannot set write parameters mode page."); return 1; } return 0; } int GenericMMC::getNWA(long *nwa) { u8 cmd[10]; int infoblocklen = 16; u8 info[16]; long lba = 0; cmd[0] = 0x52; // READ TRACK INFORMATION cmd[1] = 0x01; // track instead of lba designation cmd[2] = 0x00; cmd[3] = 0x00; cmd[4] = 0x00; cmd[5] = 0xff; // invisible track cmd[6] = 0x00; // reserved cmd[7] = infoblocklen << 8; cmd[8] = infoblocklen; // alloc length cmd[9] = 0x00; // Control Byte if (sendCmd(cmd, 10, NULL, 0, info, infoblocklen) != 0) { log_message(-2, "Cannot get Track Information Block."); return 1; } #if 0 log_message(3,"Track Information Block"); for (int i=0;i<infoblocklen;i++) log_message(3,"byte %02x : %02x",i,info[i]); #endif if ((info[6] & 0x40) && (info[7] & 0x01) && !(info[6] & 0xb0)) { log_message(4,"Track is Blank, Next Writable Address is valid"); lba |= info[12] << 24; // MSB of LBA lba |= info[13] << 16; lba |= info[14] << 8; lba |= info[15]; // LSB of LBA } log_message(4, "NWA: %ld", lba); if (nwa != NULL) *nwa = lba; return 0; } // Determines first writable address of data area of current empty session. // lba: set to start of data area // return: 0: OK // 1: error occured int GenericMMC::getStartOfSession(long *lba) { u8 mp[0x38]; u8 mpHeader[8]; // first set the writing mode because it influences which address is // returned with 'READ TRACK INFORMATION' if (getModePage(5/*write parameters mode page*/, mp, 0x38, mpHeader, NULL, 0) != 0) { return 1; } mp[0] &= 0x7f; // clear PS flag mp[2] &= 0xe0; mp[2] |= 0x02; // write type: Session-at-once if (setModePage(mp, mpHeader, NULL, 1) != 0) { log_message(-2, "Cannot set write parameters mode page."); return 1; } return getNWA(lba); } static u8 leadInOutDataMode(TrackData::Mode mode) { u8 ret = 0; switch (mode) { case TrackData::AUDIO: ret = 0x01; break; case TrackData::MODE0: // should not happen case TrackData::MODE1: case TrackData::MODE1_RAW: ret = 0x14; break; case TrackData::MODE2_FORM1: case TrackData::MODE2_FORM2: case TrackData::MODE2_FORM_MIX: case TrackData::MODE2_RAW: // assume it contains XA sectors ret = 0x24; break; case TrackData::MODE2: ret = 0x34; break; } return ret; } u8 GenericMMC::subChannelDataForm(TrackData::SubChannelMode sm, int encodingMode) { u8 ret = 0; switch (sm) { case TrackData::SUBCHAN_NONE: break; case TrackData::SUBCHAN_RW: case TrackData::SUBCHAN_RW_RAW: if (encodingMode == 0) ret = 0xc0; else ret = 0x40; break; } return ret; } // Creates cue sheet for current toc. // cueSheetLen: filled with length of cue sheet in bytes // return: newly allocated cue sheet buffer or 'NULL' on error u8 *GenericMMC::createCueSheet(unsigned long variant, long *cueSheetLen) { const Track *t; int trackNr; Msf start, end, index; u8 *cueSheet; long len = 3; // entries for lead-in, gap, lead-out long n; // index into cue sheet u8 ctl; // control nibbles of cue sheet entry CTL/ADR long i; u8 dataMode; int trackOffset; long lbaOffset; if (!diskInfo_.empty && diskInfo_.append) { if (toc_->firstTrackNo() != 0 && toc_->firstTrackNo() != diskInfo_.lastTrackNr + 1) { log_message(-2, "Number of first track doesn't match"); return NULL; } #if 0 /* for progress message */ toc_->firstTrackNo(diskInfo_.lastTrackNr + 1); #endif trackOffset = diskInfo_.lastTrackNr; lbaOffset = diskInfo_.thisSessionLba; } else { trackOffset = toc_->firstTrackNo() == 0 ? 0 : toc_->firstTrackNo() - 1; lbaOffset = 0; } if (trackOffset + toc_->nofTracks() > 99) { log_message(-2, "Track numbers too large"); return NULL; } TrackIterator itr(toc_); if (itr.first(start, end) == NULL) { return NULL; } if (toc_->catalogValid()) { len += 2; } for (t = itr.first(start, end), trackNr = 1; t != NULL; t = itr.next(start, end), trackNr++) { len += 1; // entry for track if (t->start().lba() != 0 && trackNr > 1) { len += 1; // entry for pre-gap } if (t->type() == TrackData::AUDIO && t->isrcValid()) { len += 2; // entries for ISRC code } len += t->nofIndices(); // entry for each index increment } cueSheet = new u8[len * 8]; n = 0; if (toc_->leadInMode() == TrackData::AUDIO) { ctl = 0; } else { ctl = 0x40; } if (toc_->catalogValid()) { // fill catalog number entry cueSheet[n*8] = 0x02 | ctl; cueSheet[(n+1)*8] = 0x02 | ctl; for (i = 1; i <= 13; i++) { if (i < 8) { cueSheet[n*8 + i] = toc_->catalog(i-1) + '0'; } else { cueSheet[(n+1)*8 + i - 7] = toc_->catalog(i-1) + '0'; } } cueSheet[(n+1)*8+7] = 0; n += 2; } // entry for lead-in cueSheet[n*8] = 0x01 | ctl; // CTL/ADR cueSheet[n*8+1] = 0; // Track number cueSheet[n*8+2] = 0; // Index if (cdTextEncoder_ != NULL) { cueSheet[n*8+3] = 0x41; // Data Form: CD-DA with P-W sub-channels, // main channel data generated by device } else { cueSheet[n*8+3] = leadInOutDataMode(toc_->leadInMode()); } cueSheet[n*8+4] = 0; // Serial Copy Management System if (cdTextEncoder_ != NULL && (variant & CUE_VAR_CDTEXT_NO_TIME) == 0) { cueSheet[n*8+5] = leadInStart_.min(); cueSheet[n*8+6] = leadInStart_.sec(); cueSheet[n*8+7] = leadInStart_.frac(); } else { cueSheet[n*8+5] = 0; // MIN cueSheet[n*8+6] = 0; // SEC cueSheet[n*8+7] = 0; // FRAME } n++; int firstTrack = 1; for (t = itr.first(start, end), trackNr = trackOffset + 1; t != NULL; t = itr.next(start, end), trackNr++) { if (encodingMode_ == 0) { // just used for some experiments with raw writing dataMode = 0; } else { switch (t->type()) { case TrackData::AUDIO: dataMode = 0; break; case TrackData::MODE1: case TrackData::MODE1_RAW: dataMode = 0x10; break; case TrackData::MODE2: dataMode = 0x30; break; case TrackData::MODE2_RAW: // assume it contains XA sectors case TrackData::MODE2_FORM1: case TrackData::MODE2_FORM2: case TrackData::MODE2_FORM_MIX: dataMode = 0x20; break; default: dataMode = 0; break; } } // add mode for sub-channel writing dataMode |= subChannelDataForm(t->subChannelType(), subChannelEncodingMode(t->subChannelType())); ctl = 0; if (t->copyPermitted()) { ctl |= 0x20; } if (t->type() == TrackData::AUDIO) { // audio track if (t->preEmphasis()) { ctl |= 0x10; } if (t->audioType() == 1) { ctl |= 0x80; } if (t->isrcValid()) { if ((variant & CUE_VAR_ISRC_NO_CTL) == 0) cueSheet[n*8] = ctl | 0x03; else cueSheet[n*8] = 0x03; cueSheet[n*8+1] = trackNr; cueSheet[n*8+2] = t->isrcCountry(0); cueSheet[n*8+3] = t->isrcCountry(1); cueSheet[n*8+4] = t->isrcOwner(0); cueSheet[n*8+5] = t->isrcOwner(1); cueSheet[n*8+6] = t->isrcOwner(2); cueSheet[n*8+7] = t->isrcYear(0) + '0'; n++; if ((variant & CUE_VAR_ISRC_NO_CTL) == 0) cueSheet[n*8] = ctl | 0x03; else cueSheet[n*8] = 0x03; cueSheet[n*8+1] = trackNr; cueSheet[n*8+2] = t->isrcYear(1) + '0'; cueSheet[n*8+3] = t->isrcSerial(0) + '0'; cueSheet[n*8+4] = t->isrcSerial(1) + '0'; cueSheet[n*8+5] = t->isrcSerial(2) + '0'; cueSheet[n*8+6] = t->isrcSerial(3) + '0'; cueSheet[n*8+7] = t->isrcSerial(4) + '0'; n++; } } else { // data track ctl |= 0x40; } if (firstTrack) { Msf sessionStart(lbaOffset); // entry for gap before first track cueSheet[n*8] = ctl | 0x01; cueSheet[n*8+1] = trackNr; cueSheet[n*8+2] = 0; // Index 0 cueSheet[n*8+3] = dataMode; // Data Form cueSheet[n*8+4] = 0; // Serial Copy Management System cueSheet[n*8+5] = sessionStart.min(); cueSheet[n*8+6] = sessionStart.sec(); cueSheet[n*8+7] = sessionStart.frac(); n++; } else if (t->start().lba() != 0) { // entry for pre-gap Msf pstart(lbaOffset + start.lba() - t->start().lba() + 150); cueSheet[n*8] = ctl | 0x01; cueSheet[n*8+1] = trackNr; cueSheet[n*8+2] = 0; // Index 0 indicates pre-gap cueSheet[n*8+3] = dataMode; // Data Form cueSheet[n*8+4] = 0; // no alternate copy bit cueSheet[n*8+5] = pstart.min(); cueSheet[n*8+6] = pstart.sec(); cueSheet[n*8+7] = pstart.frac(); n++; } Msf tstart(lbaOffset + start.lba() + 150); cueSheet[n*8] = ctl | 0x01; cueSheet[n*8+1] = trackNr; cueSheet[n*8+2] = 1; // Index 1 cueSheet[n*8+3] = dataMode; // Data Form cueSheet[n*8+4] = 0; // no alternate copy bit cueSheet[n*8+5] = tstart.min(); cueSheet[n*8+6] = tstart.sec(); cueSheet[n*8+7] = tstart.frac(); n++; for (i = 0; i < t->nofIndices(); i++) { index = tstart + t->getIndex(i); cueSheet[n*8] = ctl | 0x01; cueSheet[n*8+1] = trackNr; cueSheet[n*8+2] = i+2; // Index cueSheet[n*8+3] = dataMode; // Data Form cueSheet[n*8+4] = 0; // no alternate copy bit cueSheet[n*8+5] = index.min(); cueSheet[n*8+6] = index.sec(); cueSheet[n*8+7] = index.frac(); n++; } firstTrack = 0; } assert(n == len - 1); // entry for lead out Msf lostart(lbaOffset + toc_->length().lba() + 150); ctl = toc_->leadOutMode() == TrackData::AUDIO ? 0 : 0x40; cueSheet[n*8] = ctl | 0x01; cueSheet[n*8+1] = 0xaa; cueSheet[n*8+2] = 1; // Index 1 cueSheet[n*8+3] = leadInOutDataMode(toc_->leadOutMode()); cueSheet[n*8+4] = 0; // no alternate copy bit cueSheet[n*8+5] = lostart.min(); cueSheet[n*8+6] = lostart.sec(); cueSheet[n*8+7] = lostart.frac(); log_message(3, "\nCue Sheet (variant %lx):", variant); log_message(3, "CTL/ TNO INDEX DATA SCMS MIN SEC FRAME"); log_message(3, "ADR FORM"); for (n = 0; n < len; n++) { log_message(3, "%02x %02x %02x %02x %02x %02d %02d %02d", cueSheet[n*8], cueSheet[n*8+1], cueSheet[n*8+2], cueSheet[n*8+3], cueSheet[n*8+4], cueSheet[n*8+5], cueSheet[n*8+6], cueSheet[n*8+7]); } *cueSheetLen = len * 8; return cueSheet; } int GenericMMC::sendCueSheet() { u8 cmd[10]; long cueSheetLen; unsigned long variant; u8 *cueSheet; int cueSheetSent = 0; for (variant = 0; variant <= CUE_VAR_MAX; variant++) { if (cdTextEncoder_ == NULL && (variant & CUE_VAR_CDTEXT_NO_TIME) != 0) { // skip CD-TEXT variants if no CD-TEXT has to be written continue; } cueSheet = createCueSheet(variant, &cueSheetLen); if (cueSheet != NULL) { memset(cmd, 0, 10); cmd[0] = 0x5d; // SEND CUE SHEET cmd[6] = cueSheetLen >> 16; cmd[7] = cueSheetLen >> 8; cmd[8] = cueSheetLen; if (sendCmd(cmd, 10, cueSheet, cueSheetLen, NULL, 0, 0) != 0) { delete[] cueSheet; } else { log_message(3, "Drive accepted cue sheet variant %lx.", variant); delete[] cueSheet; cueSheetSent = 1; break; } } } if (cueSheetSent) { return 0; } else { log_message(-2, "Drive does not accept any cue sheet variant - please report."); return 1; } } int GenericMMC::initDao(const Toc *toc) { long n; blockLength_ = AUDIO_BLOCK_LEN + MAX_SUBCHANNEL_LEN; blocksPerWrite_ = scsiIf_->maxDataLen() / blockLength_; assert(blocksPerWrite_ > 0); toc_ = toc; if (cdtextEnabled_) { delete cdTextEncoder_; cdTextEncoder_ = new CdTextEncoder(toc_); if (cdTextEncoder_->encode() != 0) { log_message(-2, "CD-TEXT encoding failed."); return 1; } if (cdTextEncoder_->getSubChannels(&n) == NULL || n == 0) { delete cdTextEncoder_; cdTextEncoder_ = NULL; } //return 1; } diskInfo(); if (!diskInfo_.valid.empty || !diskInfo_.valid.append) { log_message(-2, "Cannot determine status of inserted medium."); return 1; } if (!diskInfo_.append) { log_message(-2, "Inserted medium is not appendable."); return 1; } if ((!diskInfo_.empty && diskInfo_.append) && toc_->firstTrackNo() != 0 ) { log_message(-1, "Cannot choose number of first track in append mode."); return 1; } if (selectSpeed() != 0 || getSessionInfo() != 0) { return 1; } // allocate buffer for writing zeros n = blocksPerWrite_ * blockLength_; delete[] zeroBuffer_; zeroBuffer_ = new char[n]; memset(zeroBuffer_, 0, n); return 0; } int GenericMMC::startDao() { unsigned long variant; int writeParametersSet = 0; scsiTimeout_ = scsiIf_->timeout(3 * 60); for (variant = 0; variant <= WMP_VAR_MAX; variant++) { if (cdTextEncoder_ == NULL && (variant & WMP_VAR_CDTEXT_NO_DATA_BLOCK_TYPE) != 0) { // skip CD-TEXT variants if no CD-TEXT has to be written continue; } if (setWriteParameters(variant) == 0) { log_message(3, "Drive accepted write parameter mode page variant %lx.", variant); writeParametersSet = 1; break; } } if (!writeParametersSet) { log_message(-2, "Cannot setup write parameters for session-at-once mode."); log_message(-2, "Please try to use the 'generic-mmc-raw' driver."); return 1; } if (!simulate_) { if (performPowerCalibration() != 0) { if (!force()) { log_message(-2, "Use option --force to ignore this error."); return 1; } else { log_message(-2, "Ignored because of option --force."); } } } // It does not hurt if the following command fails. // The Panasonic CW-7502 needs it, unfortunately it returns the wrong // data so we ignore the returned data and start writing always with // LBA -150. getNWA(NULL); if (sendCueSheet() != 0) return 1; //log_message(2, "Writing lead-in and gap..."); if (writeCdTextLeadIn() != 0) { return 1; } long lba = diskInfo_.thisSessionLba - 150; TrackData::Mode mode = TrackData::AUDIO; TrackData::SubChannelMode subChanMode = TrackData::SUBCHAN_NONE; TrackIterator itr(toc_); const Track *tr; if ((tr = itr.first()) != NULL) { mode = tr->type(); subChanMode = tr->subChannelType(); } if (writeZeros(mode, subChanMode, lba, lba + 150, 150) != 0) { return 1; } return 0; } int GenericMMC::finishDao() { int ret; flushCache(); /* Some drives never return to a ready state after writing * the lead-out. This is a try to solve this problem. */ while ((ret = checkDriveReady()) == 2) { mSleep(2000); } if (ret != 0) log_message(-1, "TEST UNIT READY failed after recording."); log_message(2, "Flushing cache..."); if (flushCache() != 0) { return 1; } scsiIf_->timeout(scsiTimeout_); delete cdTextEncoder_; cdTextEncoder_ = NULL; delete[] zeroBuffer_, zeroBuffer_ = NULL; return 0; } void GenericMMC::abortDao() { flushCache(); delete cdTextEncoder_; cdTextEncoder_ = NULL; } // Writes data to target, the block length depends on the actual writing // 'mode'. 'len' is number of blocks to write. // 'lba' specifies the next logical block address for writing and is updated // by this function. // return: 0: OK // 1: scsi command failed int GenericMMC::writeData(TrackData::Mode mode, TrackData::SubChannelMode sm, long &lba, const char *buf, long len) { assert(blocksPerWrite_ > 0); int writeLen = 0; u8 cmd[10]; long blockLength = blockSize(mode, sm); int retry; int ret; #if 0 long bufferCapacity; int waitForBuffer; int speedFrac; if (speed_ > 0) speedFrac = 75 * speed_; else speedFrac = 75 * 10; // adjust this value when the first >10x burner is out #endif #if 0 long sum, i; sum = 0; for (i = 0; i < len * blockLength; i++) { sum += buf[i]; } log_message(0, "W: %ld: %ld, %ld, %ld", lba, blockLength, len, sum); #endif memset(cmd, 0, 10); cmd[0] = 0x2a; // WRITE1 while (len > 0) { writeLen = (len > blocksPerWrite_ ? blocksPerWrite_ : len); cmd[2] = lba >> 24; cmd[3] = lba >> 16; cmd[4] = lba >> 8; cmd[5] = lba; cmd[7] = writeLen >> 8; cmd[8] = writeLen & 0xff; #if 0 do { long available waitForBuffer = 0; if (readBufferCapacity(&bufferCapacity, &available) == 0) { //log_message(0, "Buffer Capacity: %ld", bufferCapacity); if (bufferCapacity < writeLen * blockLength) { long t = 1000 * writeLen; t /= speedFrac; if (t <= 0) t = 1; log_message(0, "Waiting for %ld msec at lba %ld", t, lba); mSleep(t); waitForBuffer = 1; } } } while (waitForBuffer); #endif do { retry = 0; ret = sendCmd(cmd, 10, (u8 *)buf, writeLen * blockLength, NULL, 0, 0); if(ret == 2) { const u8 *sense; int senseLen; sense = scsiIf_->getSense(senseLen); // check if drive rejected the command because the internal buffer // is filled if(senseLen >= 14 && (sense[2] & 0x0f) == 0x2 && sense[7] >= 6 && sense[12] == 0x4 && sense[13] == 0x8) { // Not Ready, long write in progress mSleep(40); retry = 1; } else { scsiIf_->printError(); } } } while (retry); if (ret != 0) { log_message(-2, "Write data failed."); return 1; } buf += writeLen * blockLength; lba += writeLen; len -= writeLen; } return 0; } int GenericMMC::writeCdTextLeadIn() { u8 cmd[10]; const PWSubChannel96 **cdTextSubChannels; long cdTextSubChannelCount; long channelsPerCmd; long scp = 0; long lba = -150 - leadInLen_; long len = leadInLen_; long n; long i; int retry; int ret; u8 *p; if (cdTextEncoder_ == NULL) return 0; channelsPerCmd = scsiIf_->maxDataLen() / 96; cdTextSubChannels = cdTextEncoder_->getSubChannels(&cdTextSubChannelCount); assert(channelsPerCmd > 0); assert(cdTextSubChannels != NULL); assert(cdTextSubChannelCount > 0); log_message(2, "Writing CD-TEXT lead-in..."); log_message(4, "Start LBA: %ld, length: %ld", lba, len); memset(cmd, 0, 10); cmd[0] = 0x2a; // WRITE1 while (len > 0) { n = (len > channelsPerCmd) ? channelsPerCmd : len; cmd[2] = lba >> 24; cmd[3] = lba >> 16; cmd[4] = lba >> 8; cmd[5] = lba; cmd[7] = n >> 8; cmd[8] = n; p = transferBuffer_; for (i = 0; i < n; i++) { memcpy(p, cdTextSubChannels[scp]->data(), 96); p += 96; scp++; if (scp >= cdTextSubChannelCount) scp = 0; } log_message(5, "Writing %ld CD-TEXT sub-channels at LBA %ld.", n, lba); do { retry = 0; ret = sendCmd(cmd, 10, transferBuffer_, n * 96, NULL, 0, 0); if(ret == 2) { const u8 *sense; int senseLen; sense = scsiIf_->getSense(senseLen); // check if drive rejected the command because the internal buffer // is filled if(senseLen >= 14 && (sense[2] & 0x0f) == 0x2 && sense[7] >= 6 && sense[12] == 0x4 && sense[13] == 0x8) { // Not Ready, long write in progress mSleep(40); retry = 1; } else { scsiIf_->printError(); } } } while (retry); if (ret != 0) { log_message(-2, "Writing of CD-TEXT data failed."); return 1; } len -= n; lba += n; } return 0; } DiskInfo *GenericMMC::diskInfo() { u8 cmd[10]; unsigned long dataLen = 34; u8 data[34]; char spd; memset(&diskInfo_, 0, sizeof(DiskInfo)); // perform READ DISK INFORMATION memset(cmd, 0, 10); memset(data, 0, dataLen); cmd[0] = 0x51; // READ DISK INFORMATION cmd[7] = dataLen >> 8; cmd[8] = dataLen; if (sendCmd(cmd, 10, NULL, 0, data, dataLen, 0) == 0) { diskInfo_.cdrw = (data[2] & 0x10) ? 1 : 0; diskInfo_.valid.cdrw = 1; switch (data[2] & 0x03) { case 0: // disc is empty diskInfo_.empty = 1; diskInfo_.append = 1; diskInfo_.manufacturerId = Msf(data[17], data[18], data[19]); diskInfo_.valid.manufacturerId = 1; break; case 1: // disc is not empty but appendable diskInfo_.sessionCnt = data[4]; diskInfo_.lastTrackNr = data[6]; diskInfo_.diskTocType = data[8]; switch ((data[2] >> 2) & 0x03) { case 0: // last session is empty diskInfo_.append = 1; // don't count the empty session and invisible track diskInfo_.sessionCnt -= 1; diskInfo_.lastTrackNr -= 1; if (getStartOfSession(&(diskInfo_.thisSessionLba)) == 0) { // reserve space for pre-gap after lead-in diskInfo_.thisSessionLba += 150; } else { // try to guess start of data area from start of lead-in // reserve space for 4500 lead-in and 150 pre-gap sectors diskInfo_.thisSessionLba = Msf(data[17], data[18], data[19]).lba() - 150 + 4650; } break; case 1: // last session is incomplete (not fixated) // we cannot append in DAO mode, just update the statistic data diskInfo_.diskTocType = data[8]; // don't count the invisible track diskInfo_.lastTrackNr -= 1; break; } break; case 2: // disk is complete diskInfo_.sessionCnt = data[4]; diskInfo_.lastTrackNr = data[6]; diskInfo_.diskTocType = data[8]; break; } diskInfo_.valid.empty = 1; diskInfo_.valid.append = 1; if (data[21] != 0xff || data[22] != 0xff || data[23] != 0xff) { diskInfo_.valid.capacity = 1; diskInfo_.capacity = Msf(data[21], data[22], data[23]).lba() - 150; } } // perform READ TOC to get session info memset(cmd, 0, 10); dataLen = 12; memset(data, 0, dataLen); cmd[0] = 0x43; // READ TOC cmd[2] = 1; // get session info cmd[8] = dataLen; // allocation length if (sendCmd(cmd, 10, NULL, 0, data, dataLen, 0) == 0) { diskInfo_.lastSessionLba = (data[8] << 24) | (data[9] << 16) | (data[10] << 8) | data[11]; if (!diskInfo_.valid.empty) { diskInfo_.valid.empty = 1; diskInfo_.empty = (data[3] == 0) ? 1 : 0; diskInfo_.sessionCnt = data[3]; } } // read ATIP data dataLen = 28; memset(cmd, 0, 10); memset(data, 0, dataLen); cmd[0] = 0x43; // READ TOC/PMA/ATIP cmd[1] = 0x00; cmd[2] = 4; // get ATIP cmd[7] = 0; cmd[8] = dataLen; // data length if (sendCmd(cmd, 10, NULL, 0, data, dataLen, 0) == 0) { if (data[6] & 0x04) { diskInfo_.valid.recSpeed = 1; spd = (data[16] >> 4) & 0x07; diskInfo_.recSpeedLow = spd == 1 ? 2 : 0; spd = (data[16] & 0x0f); diskInfo_.recSpeedHigh = spd >= 1 && spd <= 4 ? spd * 2 : 0; } if (data[8] >= 80 && data[8] <= 99) { diskInfo_.manufacturerId = Msf(data[8], data[9], data[10]); diskInfo_.valid.manufacturerId = 1; } } return &diskInfo_; } // tries to read catalog number from disk and adds it to 'toc' // return: 1 if valid catalog number was found, else 0 int GenericMMC::readCatalog(Toc *toc, long startLba, long endLba) { u8 cmd[10]; u8 data[24]; char catalog[14]; int i; if (options_ & OPT_MMC_SCAN_MCN) { if (readCatalogScan(catalog, startLba, endLba) == 0) { if (catalog[0] != 0) { if (toc->catalog(catalog) == 0) return 1; else log_message(-1, "Found illegal MCN data: %s", catalog); } } } else { memset(cmd, 0, 10); memset(data, 0, 24); cmd[0] = 0x42; // READ SUB-CHANNEL cmd[2] = 1 << 6; cmd[3] = 0x02; // get media catalog number cmd[8] = 24; // transfer length if (sendCmd(cmd, 10, NULL, 0, data, 24) != 0) { log_message(-2, "Cannot get catalog number."); return 0; } if (data[8] & 0x80) { for (i = 0; i < 13; i++) { catalog[i] = data[0x09 + i]; } catalog[13] = 0; if (toc->catalog(catalog) == 0) { return 1; } } } return 0; } int GenericMMC::readIsrc(int trackNr, char *buf) { u8 cmd[10]; u8 data[24]; int i; buf[0] = 0; memset(cmd, 0, 10); memset(data, 0, 24); cmd[0] = 0x42; // READ SUB-CHANNEL cmd[2] = 1 << 6; cmd[3] = 0x03; // get ISRC cmd[6] = trackNr; cmd[8] = 24; // transfer length if (sendCmd(cmd, 10, NULL, 0, data, 24) != 0) { log_message(-2, "Cannot get ISRC code."); return 0; } if (data[8] & 0x80) { for (i = 0; i < 12; i++) { buf[i] = data[0x09 + i]; } buf[12] = 0; } return 0; } int GenericMMC::analyzeTrack(TrackData::Mode mode, int trackNr, long startLba, long endLba, Msf *indexIncrements, int *indexIncrementCnt, long *pregap, char *isrcCode, u8 *ctl) { int ret; int noScan = 0; selectSpeed(); if ((readCapabilities_ & CDR_AUDIO_SCAN_CAP) == 0) { ret = analyzeTrackSearch(mode, trackNr, startLba, endLba, indexIncrements, indexIncrementCnt, pregap, isrcCode, ctl); noScan = 1; } else { ret = analyzeTrackScan(mode, trackNr, startLba, endLba, indexIncrements, indexIncrementCnt, pregap, isrcCode, ctl); } if (noScan || (options_ & OPT_MMC_READ_ISRC) != 0 || (readCapabilities_ & CDR_READ_CAP_AUDIO_PQ_HEX) != 0) { // The ISRC code is usually not usable if the PQ channel data is // converted to hex numbers by the drive. Read them with the // appropriate command in this case *isrcCode = 0; if (mode == TrackData::AUDIO) readIsrc(trackNr, isrcCode); } return ret; } int GenericMMC::readSubChannels(TrackData::SubChannelMode sm, long lba, long len, SubChannel ***chans, Sample *audioData) { int retries = 5; u8 cmd[12]; int i; long blockLen = 0; unsigned long subChanMode = 0; cmd[0] = 0xbe; // READ CD cmd[1] = 0; cmd[2] = lba >> 24; cmd[3] = lba >> 16; cmd[4] = lba >> 8; cmd[5] = lba; cmd[6] = len >> 16; cmd[7] = len >> 8; cmd[8] = len; cmd[9] = 0xf8; cmd[11] = 0; switch (sm) { case TrackData::SUBCHAN_NONE: // no sub-channel data selected choose what is available if ((readCapabilities_ & CDR_READ_CAP_AUDIO_PW_RAW) != 0) { // reading of raw P-W sub-channel data is supported blockLen = AUDIO_BLOCK_LEN + 96; cmd[10] = 0x01; // raw P-W sub-channel data subChanMode = CDR_READ_CAP_AUDIO_PW_RAW; } else if ((readCapabilities_ & (CDR_READ_CAP_AUDIO_PQ_BCD|CDR_READ_CAP_AUDIO_PQ_HEX)) != 0) { // reading of PQ sub-channel data is supported blockLen = AUDIO_BLOCK_LEN + 16; cmd[10] = 0x02; // PQ sub-channel data if ((readCapabilities_ & CDR_READ_CAP_AUDIO_PQ_BCD) != 0) subChanMode = CDR_READ_CAP_AUDIO_PQ_BCD; else subChanMode = CDR_READ_CAP_AUDIO_PQ_HEX; } else { // no usable sub-channel reading mode is supported blockLen = AUDIO_BLOCK_LEN; cmd[10] = 0; subChanMode = 0; } break; case TrackData::SUBCHAN_RW: blockLen = AUDIO_BLOCK_LEN + 96; cmd[10] = 0x04; break; case TrackData::SUBCHAN_RW_RAW: blockLen = AUDIO_BLOCK_LEN + 96; cmd[10] = 0x01; break; } while (1) { if (sendCmd(cmd, 12, NULL, 0, transferBuffer_, len * blockLen, retries == 0 ? 1 : 0) != 0) { if (retries == 0) return 1; } else { break; } retries--; } #if 0 if (lba > 5000) { char fname[200]; sprintf(fname, "testout_%ld", lba); FILE *fp = fopen(fname, "w"); fwrite(transferBuffer_, blockLen, len, fp); fclose(fp); } #endif if (subChanMode != 0) { u8 *buf = transferBuffer_ + AUDIO_BLOCK_LEN; for (i = 0; i < len; i++) { switch (subChanMode) { case CDR_READ_CAP_AUDIO_PQ_HEX: // All numbers in sub-channel data are hex conforming to the // MMC standard. We have to convert them back to BCD for the // 'SubChannel' class. buf[1] = SubChannel::bcd(buf[1]); buf[2] = SubChannel::bcd(buf[2]); buf[3] = SubChannel::bcd(buf[3]); buf[4] = SubChannel::bcd(buf[4]); buf[5] = SubChannel::bcd(buf[5]); buf[6] = SubChannel::bcd(buf[6]); buf[7] = SubChannel::bcd(buf[7]); buf[8] = SubChannel::bcd(buf[8]); buf[9] = SubChannel::bcd(buf[9]); // fall through case CDR_READ_CAP_AUDIO_PQ_BCD: ((PQSubChannel16*)scannedSubChannels_[i])->init(buf); if (scannedSubChannels_[i]->type() != SubChannel::QMODE_ILLEGAL) { // the CRC of the sub-channel data is usually invalid -> mark the // sub-channel object that it should not try to verify the CRC scannedSubChannels_[i]->crcInvalid(); } break; case CDR_READ_CAP_AUDIO_PW_RAW: ((PWSubChannel96*)scannedSubChannels_[i])->init(buf); break; } #if 0 if (subChanMode == CDR_READ_CAP_AUDIO_PW_RAW) { // xxam! int j, k; log_message(0, ""); for (j = 0; j < 4; j++) { for (k = 0; k < 24; k++) { u8 data = buf[j * 24 + k]; log_message(0, "%02x ", data&0x3f); } log_message(0, ""); } } #endif buf += blockLen; } } if (audioData != NULL) { u8 *p = transferBuffer_; for (i = 0; i < len; i++) { memcpy(audioData, p, AUDIO_BLOCK_LEN); audioData += SAMPLES_PER_BLOCK; switch (sm) { case TrackData::SUBCHAN_NONE: break; case TrackData::SUBCHAN_RW: case TrackData::SUBCHAN_RW_RAW: memcpy(audioData, p + AUDIO_BLOCK_LEN, PW_SUBCHANNEL_LEN); audioData += PW_SUBCHANNEL_LEN / SAMPLE_LEN; break; } p += blockLen; } } if (subChanMode == 0) *chans = NULL; else *chans = scannedSubChannels_; return 0; } // Tries to retrieve configuration feature 'feature' and fills data to // provided buffer 'buf' with maximum length 'bufLen'. // Return: 0: OK // 1: feature not available // 2: SCSI error int GenericMMC::getFeature(unsigned int feature, u8 *buf, unsigned long bufLen, int showMsg) { u8 header[8]; u8 *data; u8 cmd[10]; unsigned long len; memset(cmd, 0, 10); memset(header, 0, 8); cmd[0] = 0x46; // GET CONFIGURATION cmd[1] = 0x02; // return single feature descriptor cmd[2] = feature >> 8; cmd[3] = feature; cmd[8] = 8; // allocation length if (sendCmd(cmd, 10, NULL, 0, header, 8, showMsg) != 0) { if (showMsg) log_message(-2, "Cannot get feature 0x%x.", feature); return 2; } len = (header[0] << 24) | (header[1] << 16) | (header[2] << 8) | header[3]; log_message(4, "getFeature: data len: %lu", len); if (len < 8) return 1; // feature not defined if (bufLen == 0) return 0; len -= 4; if (len > bufLen) len = bufLen; data = new u8[len + 8]; cmd[7] = (len + 8) >> 8; cmd[8] = (len + 8); if (sendCmd(cmd, 10, NULL, 0, data, len + 8, showMsg) != 0) { if (showMsg) log_message(-2, "Cannot get data for feature 0x%x.", feature); delete[] data; return 2; } len = (header[0] << 24) | (header[1] << 16) | (header[2] << 8) | header[3]; log_message(4, "getFeature: data len: %lu", len); if (len < 8) { delete[] data; return 1; // feature not defined } len -= 4; if (len > bufLen) len = bufLen; memcpy(buf, data + 8, len); delete[] data; return 0; } const DriveInfo *GenericMMC::driveInfo(bool showErrorMsg) { u8 mp[32]; if (driveInfo_ != NULL) return driveInfo_; driveInfo_ = new DriveInfo; if (getModePage(0x2a, mp, 32, NULL, NULL, showErrorMsg) != 0) { if (showErrorMsg) { log_message(-2, "Cannot retrieve drive capabilities mode page."); } delete driveInfo_; driveInfo_ = NULL; return NULL; } driveInfo_->burnProof = (mp[4] & 0x80) ? 1 : 0; driveInfo_->accurateAudioStream = mp[5] & 0x02 ? 1 : 0; driveInfo_->maxReadSpeed = (mp[8] << 8) | mp[9]; driveInfo_->currentReadSpeed = (mp[14] << 8) | mp[15]; driveInfo_->maxWriteSpeed = (mp[18] << 8) | mp[19]; driveInfo_->currentWriteSpeed = (mp[20] << 8) | mp[21]; RicohGetWriteOptions(); return driveInfo_; } TrackData::Mode GenericMMC::getTrackMode(int, long trackStartLba) { u8 cmd[12]; u8 data[AUDIO_BLOCK_LEN]; memset(cmd, 0, 12); cmd[0] = 0xbe; // READ CD cmd[2] = trackStartLba >> 24; cmd[3] = trackStartLba >> 16; cmd[4] = trackStartLba >> 8; cmd[5] = trackStartLba; cmd[8] = 1; cmd[9] = 0xf8; if (sendCmd(cmd, 12, NULL, 0, data, AUDIO_BLOCK_LEN) != 0) { log_message(-2, "Cannot read sector of track."); return TrackData::MODE0; } if (memcmp(CdrDriver::syncPattern, data, 12) != 0) { // cannot be a data sector return TrackData::MODE0; } TrackData::Mode mode = determineSectorMode(data + 12); if (mode == TrackData::MODE0) { // illegal log_message(-2, "Found illegal mode in sector %ld.", trackStartLba); } return mode; } CdRawToc *GenericMMC::getRawToc(int sessionNr, int *len) { u8 cmd[10]; u16 dataLen; u8 *data = NULL;; u8 reqData[4]; // buffer for requestion the actual length u8 *p; int i, entries; CdRawToc *rawToc; assert(sessionNr >= 1); // read disk toc length memset(cmd, 0, 10); cmd[0] = 0x43; // READ TOC cmd[2] = 2; cmd[6] = sessionNr; cmd[8] = 4; if (sendCmd(cmd, 10, NULL, 0, reqData, 4) != 0) { log_message(-2, "Cannot read disk toc."); return NULL; } dataLen = ((reqData[0] << 8) | reqData[1]) + 2; log_message(4, "Raw toc data len: %d", dataLen); data = new u8[dataLen]; // read disk toc cmd[7] = dataLen >> 8; cmd[8] = dataLen; if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) { log_message(-2, "Cannot read disk toc."); delete[] data; return NULL; } entries = (((data[0] << 8) | data[1]) - 2) / 11; rawToc = new CdRawToc[entries]; for (i = 0, p = data + 4; i < entries; i++, p += 11 ) { #if 0 log_message(5, "%d %02x %02d %2x %02d:%02d:%02d %02d %02d:%02d:%02d", p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10]); #endif rawToc[i].sessionNr = p[0]; rawToc[i].adrCtl = p[1]; rawToc[i].point = p[3]; rawToc[i].pmin = p[8]; rawToc[i].psec = p[9]; rawToc[i].pframe = p[10]; } delete[] data; *len = entries; return rawToc; } long GenericMMC::readTrackData(TrackData::Mode mode, TrackData::SubChannelMode sm, long lba, long len, u8 *buf) { long i; long inBlockLen = AUDIO_BLOCK_LEN; u8 cmd[12]; const u8 *sense; int senseLen; memset(cmd, 0, 12); cmd[0] = 0xbe; // READ CD cmd[1] = 0; cmd[2] = lba >> 24; cmd[3] = lba >> 16; cmd[4] = lba >> 8; cmd[5] = lba; cmd[6] = len >> 16; cmd[7] = len >> 8; cmd[8] = len; cmd[9] = 0xf8; switch (sm) { case TrackData::SUBCHAN_NONE: cmd[10] = 0; // no sub-channel reading break; case TrackData::SUBCHAN_RW: cmd[10] = 0x4; inBlockLen += PW_SUBCHANNEL_LEN; break; case TrackData::SUBCHAN_RW_RAW: cmd[10] = 0x1; inBlockLen += PW_SUBCHANNEL_LEN; break; } switch (sendCmd(cmd, 12, NULL, 0, transferBuffer_, len * inBlockLen, 0)) { case 0: break; case 2: sense = scsiIf_->getSense(senseLen); if (senseLen > 0x0c) { if ((sense[2] & 0x0f) == 5) { // Illegal request switch (sense[12]) { case 0x63: // End of user area encountered on this track case 0x64: // Illegal mode for this track return -2; break; case 0x20: // INVALID COMMAND OPERATION CODE case 0x24: // INVALID FIELD IN CDB case 0x26: // INVALID FIELD IN PARAMETER LIST /* These error codes mean that something was wrong with the * command we are sending. Report them as hard errors to the * upper level. */ scsiIf_->printError(); return -1; break; } } else if ((sense[2] & 0x0f) == 4) { // Hardware Error switch (sense[12]) { case 0x9: // focus servo failure return -2; break; } } else if ((sense[2] & 0x0f) == 3) { // Medium error switch (sense[12]) { case 0x02: // No seek complete, sector not found case 0x06: // no reference position found case 0x11: // L-EC error case 0x15: // random positioning error return -2; break; } } } /* All other errors are unexpected. They will be treated like L-EC errors * by the upper layer. Just print the error code so that we can decice * later to add the errors to the known possible error list. */ scsiIf_->printError(); return -2; break; default: log_message(-2, "Read error at LBA %ld, len %ld", lba, len); return -2; break; } u8 *sector = transferBuffer_; for (i = 0; i < len; i++) { if (buf != NULL) { switch (mode) { case TrackData::MODE1: memcpy(buf, sector + 16, MODE1_BLOCK_LEN); buf += MODE1_BLOCK_LEN; break; case TrackData::MODE1_RAW: memcpy(buf, sector, AUDIO_BLOCK_LEN); buf += AUDIO_BLOCK_LEN; break; case TrackData::MODE2: case TrackData::MODE2_FORM_MIX: memcpy(buf, sector + 16, MODE2_BLOCK_LEN); buf += MODE2_BLOCK_LEN; break; case TrackData::MODE2_FORM1: memcpy(buf, sector + 24, MODE2_FORM1_DATA_LEN); buf += MODE2_FORM1_DATA_LEN; break; case TrackData::MODE2_FORM2: memcpy(buf, sector + 24, MODE2_FORM2_DATA_LEN); buf += MODE2_FORM2_DATA_LEN; break; case TrackData::MODE2_RAW: memcpy(buf, sector, AUDIO_BLOCK_LEN); buf += AUDIO_BLOCK_LEN; break; case TrackData::MODE0: case TrackData::AUDIO: log_message(-3, "GenericMMC::readTrackData: Illegal mode."); return 0; break; } // copy sub-channel data switch (sm) { case TrackData::SUBCHAN_NONE: break; case TrackData::SUBCHAN_RW: case TrackData::SUBCHAN_RW_RAW: memcpy(buf, sector + AUDIO_BLOCK_LEN, PW_SUBCHANNEL_LEN); buf += PW_SUBCHANNEL_LEN; break; } } #if 0 // xxam! int j, k; log_message(0, ""); for (j = 0; j < 4; j++) { for (k = 0; k < 24; k++) { u8 data = sector[AUDIO_BLOCK_LEN + j * 24 + k]; log_message(0, "%02x ", data&0x3f); } log_message(0, ""); } #endif sector += inBlockLen; } return len; } int GenericMMC::readAudioRange(ReadDiskInfo *rinfo, int fd, long start, long end, int startTrack, int endTrack, TrackInfo *info) { if (!onTheFly_) { if (((readCapabilities_ & CDR_READ_CAP_AUDIO_PQ_BCD) == 0 && (readCapabilities_ & CDR_READ_CAP_AUDIO_PW_RAW) == 0) || (options_ & OPT_MMC_READ_ISRC) != 0) { int t; long pregap = 0; // The ISRC code is usually not usable if the PQ channel data is // converted to hex numbers by the drive. Read them with the // appropriate command in this case log_message(1, "Analyzing..."); for (t = startTrack; t <= endTrack; t++) { long totalProgress; log_message(1, "Track %d...", t + 1); totalProgress = t * 1000; totalProgress /= rinfo->tracks; sendReadCdProgressMsg(RCD_ANALYZING, rinfo->tracks, t + 1, 0, totalProgress); if ((readCapabilities_ & CDR_AUDIO_SCAN_CAP) == 0) { // we have to use the binary search method to find pre-gap and // index marks if the drive cannot read sub-channel data if (!fastTocReading_) { long slba, elba; int i, indexCnt; Msf index[98]; u8 ctl; if (pregap > 0) log_message(2, "Found pre-gap: %s", Msf(pregap).str()); slba = info[t].start; if (info[t].mode == info[t + 1].mode) elba = info[t + 1].start; else elba = info[t + 1].start - 150; pregap = 0; if (analyzeTrackSearch(TrackData::AUDIO, t + 1, slba, elba, index, &indexCnt, &pregap, info[t].isrcCode, &ctl) != 0) return 1; for (i = 0; i < indexCnt; i++) info[t].index[i] = index[i].lba(); info[t].indexCnt = indexCnt; if (t < endTrack) info[t + 1].pregap = pregap; } else { info[t].indexCnt = 0; info[t + 1].pregap = 0; } } info[t].isrcCode[0] = 0; readIsrc(t + 1, info[t].isrcCode); if (info[t].isrcCode[0] != 0) log_message(2, "Found ISRC code."); totalProgress = (t + 1) * 1000; totalProgress /= rinfo->tracks; sendReadCdProgressMsg(RCD_ANALYZING, rinfo->tracks, t + 1, 1000, totalProgress); } log_message(1, "Reading..."); } } if (subChanReadMode_ == TrackData::SUBCHAN_NONE) { return CdrDriver::readAudioRangeParanoia(rinfo, fd, start, end, startTrack, endTrack, info); } else { return CdrDriver::readAudioRangeStream(rinfo, fd, start, end, startTrack, endTrack, info); } } int GenericMMC::getTrackIndex(long lba, int *trackNr, int *indexNr, u8 *ctl) { u8 cmd[12]; u16 dataLen = 0x30; u8 data[0x30]; int waitLoops = 10; int waitFailed = 0; // play one audio block memset(cmd, 0, 10); cmd[0] = 0x45; // PLAY AUDIO cmd[2] = lba >> 24; cmd[3] = lba >> 16; cmd[4] = lba >> 8; cmd[5] = lba; cmd[7] = 0; cmd[8] = 1; if (sendCmd(cmd, 10, NULL, 0, NULL, 0) != 0) { log_message(-2, "Cannot play audio block."); return 1; } // wait until the play command finished memset(cmd, 0, 12); cmd[0] = 0xbd; // MECHANISM STATUS cmd[9] = 8; while (waitLoops > 0) { if (sendCmd(cmd, 12, NULL, 0, data, 8, 0) == 0) { //log_message(0, "%d, %x", waitLoops, data[1]); if ((data[1] >> 5) == 1) // still playing? waitLoops--; else waitLoops = 0; } else { waitFailed = 1; waitLoops = 0; } } if (waitFailed) { // The play operation immediately returns success status and the waiting // loop above failed. Wait here for a while until the desired block is // played. It takes ~13 msecs to play a block but access time is in the // order of several 100 msecs mSleep(300); } // read sub channel information memset(cmd, 0, 10); cmd[0] = 0x42; // READ SUB CHANNEL cmd[2] = 0x40; // get sub channel data cmd[3] = 0x01; // get sub Q channel data cmd[6] = 0; cmd[7] = dataLen >> 8; cmd[8] = dataLen; if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) { log_message(-2, "Cannot read sub Q channel data."); return 1; } *trackNr = data[6]; *indexNr = data[7]; if (ctl != NULL) { *ctl = data[5] & 0x0f; } //log_message(0, "%d %d", *trackNr, *indexNr); return 0; } /* * Checks if a certain sub-channel reading mode is supported. * lba: start address for reading * len: maximum number of sectors available for testing * subChanMode: 1: read PQ sub-channels * 2: read raw P-W sub-channels * 3: read cooked R-W sub-channels * Return: 0 sub-channel read mode not supported * 1 sub-channel read mode supported (BCD for PQ) * 2 sub-channel read mode supported (HEX for PQ) * 3 sub-channel read mode PQ supported but cannot determine data * format */ int GenericMMC::readCdTest(long lba, long len, int subChanMode) const { u8 cmd[12]; long blockLen; int ret; int successRead = 0; int pqSubChanBcdOk = 0; int pqSubChanHexOk = 0; memset(cmd, 0, sizeof(cmd)); if (len <= 0) return 0; cmd[0] = 0xbe; // READ CD cmd[8] = 1; // transfer length: 1 cmd[9] = 0xf8; blockLen = AUDIO_BLOCK_LEN; switch (subChanMode) { case 1: // PQ blockLen += PQ_SUBCHANNEL_LEN; cmd[10] = 0x02; if (len > 300) len = 300; /* we have to check many sub-channels here to determine the * data mode (BCD or HEX) */ break; case 2: // PW_RAW cmd[10] = 0x01; blockLen += PW_SUBCHANNEL_LEN; if (len > 10) len = 10; break; case 3: // RW_COOKED cmd[10] = 0x04; blockLen += PW_SUBCHANNEL_LEN; if (len > 10) len = 10; break; } while (len > 0) { cmd[2] = lba >> 24; cmd[3] = lba >> 16; cmd[4] = lba >> 8; cmd[5] = lba; if ((ret = sendCmd(cmd, 12, NULL, 0, transferBuffer_, blockLen, 0)) == 0) { successRead++; if (subChanMode == 1) { u8 *buf = transferBuffer_ + AUDIO_BLOCK_LEN; #if 0 { PQSubChannel16 chan; chan.init(buf); chan.print(); } #endif // check if Q sub-channel values are in BCD or HEX format if (SubChannel::isBcd(buf[1]) && SubChannel::isBcd(buf[2]) && SubChannel::isBcd(buf[3]) && SubChannel::isBcd(buf[4]) && SubChannel::isBcd(buf[5]) && SubChannel::isBcd(buf[6]) && SubChannel::isBcd(buf[7]) && SubChannel::isBcd(buf[8]) && SubChannel::isBcd(buf[9])) { PQSubChannel16 chan; chan.init(buf); chan.type(SubChannel::QMODE1DATA); int min = chan.amin(); int sec = chan.asec(); int frac = chan.aframe(); if ((frac >= 0 && frac < 75) && (sec >= 0 && sec < 60) && (min >= 0)) { long pqlba = Msf(min, sec, frac).lba() - 150; long diff = pqlba - lba; if (diff < 0) diff = -diff; if (diff < 20) { pqSubChanBcdOk++; } } } if (buf[7] < 100 && buf[8] < 60 && buf[9] < 75) { long pqlba = Msf(buf[7], buf[8], buf[9]).lba() - 150; long diff = pqlba - lba; if (diff < 0) diff = -diff; if (diff < 20) { pqSubChanHexOk++; } } } } len--; lba++; } if (successRead) { if (subChanMode == 1) { if (pqSubChanBcdOk > pqSubChanHexOk) return 1; else if (pqSubChanHexOk > pqSubChanBcdOk) return 2; else return 3; } else { return 1; } } return 0; } unsigned long GenericMMC::getReadCapabilities(const CdToc *toc, int nofTracks) const { unsigned long caps = 0; int audioRawPWChecked = 0; int audioPQChecked = 0; int audioCookedRWChecked = 0; int dataRawPWChecked = 0; int dataPQChecked = 0; int dataCookedRWChecked = 0; int t; if ((options_ & OPT_MMC_NO_SUBCHAN) != 0) { // driver options indicate that PQ and raw RW sub-channel reading for // audio tracks is not supported so skip all corresponding tests audioPQChecked = 1; audioRawPWChecked = 1; } else if ((options_ & OPT_MMC_USE_PQ) != 0) { // driver options indicated that PQ sub-channel reading is supported for // audio/data tracks and RW sub-channel reading is not supported, skip // the corresponding checks and set the capabilities appropriately audioPQChecked = 1; audioRawPWChecked = 1; dataPQChecked = 1; if ((options_ & OPT_MMC_PQ_BCD) != 0) caps |= CDR_READ_CAP_AUDIO_PQ_BCD | CDR_READ_CAP_DATA_PQ_BCD; else caps |= CDR_READ_CAP_AUDIO_PQ_HEX | CDR_READ_CAP_DATA_PQ_HEX; } else if ((options_ & OPT_MMC_USE_RAW_RW) != 0) { // driver options indicated that raw PW sub-channel reading is supported // audio tracks and raw PW sub-channel reading is not supported, skip // the corresponding checks and set the capabilities appropriately audioPQChecked = 1; audioRawPWChecked = 1; caps |= CDR_READ_CAP_DATA_PW_RAW; } for (t = 0; t < nofTracks; t++) { long tlen = toc[t+1].start - toc[t].start; if ((toc[t].adrCtl & 0x04) != 0) { // data track if (!dataPQChecked) { dataPQChecked = 1; log_message(3, "Checking for PQ sub-channel reading support (data track)..."); switch (readCdTest(toc[t].start, tlen, 1)) { case 0: log_message(3, "PQ sub-channel reading (data track) not supported."); break; case 1: log_message(2, "PQ sub-channel reading (data track) is supported, data format is BCD."); caps |= CDR_READ_CAP_DATA_PQ_BCD; break; case 2: log_message(2, "PQ sub-channel reading (data track) is supported, data format is HEX."); caps |= CDR_READ_CAP_DATA_PQ_HEX; break; case 3: log_message(2, "PQ sub-channel reading (data track) seems to be supported but cannot determine data format."); log_message(2, "Please use driver option '--driver generic-mmc:0x1' or '--driver generic-mmc:0x3' to set the data format explicitly."); break; } } if (!dataRawPWChecked) { dataRawPWChecked = 1; log_message(3, "Checking for raw P-W sub-channel reading support (data track)..."); if (readCdTest(toc[t].start, tlen, 2)) { log_message(2, "Raw P-W sub-channel reading (data track) is supported."); caps |= CDR_READ_CAP_DATA_PW_RAW; } else { log_message(3, "Raw P-W sub-channel reading (data track) is not supported."); } } if (!dataCookedRWChecked) { dataCookedRWChecked = 1; log_message(3, "Checking for cooked R-W sub-channel reading support (data track)..."); if (readCdTest(toc[t].start, tlen, 3)) { log_message(2, "Cooked R-W sub-channel reading (data track) is supported."); caps |= CDR_READ_CAP_DATA_RW_COOKED; } else { log_message(3, "Cooked R-W sub-channel reading (data track) is not supported."); } } } else { // audio track if (!audioPQChecked) { audioPQChecked = 1; log_message(3, "Checking for PQ sub-channel reading support (audio track)..."); switch (readCdTest(toc[t].start, tlen, 1)) { case 0: log_message(3, "PQ sub-channel reading (audio track) is not supported."); break; case 1: log_message(2, "PQ sub-channel reading (audio track) is supported, data format is BCD."); caps |= CDR_READ_CAP_AUDIO_PQ_BCD; break; case 2: log_message(2, "PQ sub-channel reading (audio track) is supported, data format is HEX."); caps |= CDR_READ_CAP_AUDIO_PQ_HEX; break; case 3: log_message(2, "PQ sub-channel reading (audio track) seems to be supported but cannot determine data format."); log_message(2, "Please use driver option '--driver generic-mmc:0x1' or '--driver generic-mmc:0x3' to set the data format explicitly."); break; } } if (!audioRawPWChecked) { audioRawPWChecked = 1; log_message(3, "Checking for raw P-W sub-channel reading support (audio track)..."); if (readCdTest(toc[t].start, tlen, 2)) { log_message(2, "Raw P-W sub-channel reading (audio track) is supported."); caps |= CDR_READ_CAP_AUDIO_PW_RAW; } else { log_message(3, "Raw P-W sub-channel reading (audio track) is not supported."); } } if (!audioCookedRWChecked) { audioCookedRWChecked = 1; log_message(3, "Checking for cooked R-W sub-channel reading support (audio track)..."); if (readCdTest(toc[t].start, tlen, 3)) { log_message(2, "Cooked R-W sub-channel reading (audio track) is supported."); caps |= CDR_READ_CAP_AUDIO_RW_COOKED; } else { log_message(3, "Raw R-W sub-channel reading (audio track) is not supported."); } } } } return caps; } int GenericMMC::RicohGetWriteOptions() { u8 mp[14]; driveInfo_->ricohJustLink = 0; driveInfo_->ricohJustSpeed = 0; if (getModePage(0x30, mp, 14, NULL, NULL, 0) != 0) { return 1; } if (mp[1] != 14) return 1; if (mp[2] & (1 << 5)) driveInfo_->ricohJustSpeed = 1; if (mp[2] & 0x01) driveInfo_->ricohJustLink = 1; return 0; } int GenericMMC::RicohSetWriteOptions(const DriveInfo *di) { u8 mp[14]; if (di->ricohJustLink == 0 && di->ricohJustSpeed == 0) return 0; if (getModePage(0x30, mp, 14, NULL, NULL, 1) != 0) { log_message(-2, "Cannot retrieve Ricoh mode page 30."); return 1; } if (di->ricohJustLink) { if (bufferUnderRunProtection()) { log_message(2, "Enabling JustLink."); mp[3] |= 0x1; } else { log_message(2, "Disabling JustLink."); mp[3] &= ~0x1; } } if (di->ricohJustSpeed) { if (writeSpeedControl()) { log_message(2, "Enabling JustSpeed."); mp[3] &= ~(1 << 5); // clear bit to enable write speed control } else { log_message(2, "Disabling JustSpeed."); mp[3] |= (1 << 5); // set bit to disable write speed control } } if (setModePage(mp, NULL, NULL, 1) != 0) { log_message(-2, "Cannot set Ricoh mode page 30."); return 1; } return 0; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/GenericMMC.h��������������������������������������������������������������0000664�0000000�0000000�00000035671�15114537466�0017537�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #ifndef __GENERIC_MMC_H__ #define __GENERIC_MMC_H__ #include "CdrDriver.h" class Toc; class Track; class CdTextEncoder; // use PQ sub-channel data for scanning #define OPT_MMC_USE_PQ 0x0001 // PQ sub-channel contains BCD numbers #define OPT_MMC_PQ_BCD 0x0002 // force reading of ISRC code with READ SUB CHANNEL instead taking it // from the sub-channel data #define OPT_MMC_READ_ISRC 0x0004 // take MCN from the sub-channel data instead using READ SUB CHANNEL #define OPT_MMC_SCAN_MCN 0x0008 // drive supports CD-TEXT writing #define OPT_MMC_CD_TEXT 0x0010 // drive does not support #define OPT_MMC_NO_SUBCHAN 0x0020 // disable BURN-Proof #define OPT_MMC_NO_BURNPROOF 0x0040 // drive does not support the packed R-W sub-channel writing mode #define OPT_MMC_NO_RW_PACKED 0x0080 // use RW sub-channel data for scanning #define OPT_MMC_USE_RAW_RW 0x0100 // drive supports Yamaha's Force Speed feature #define OPT_MMC_YAMAHA_FORCE_SPEED 0x0200 // Driver for Generic MMC units class GenericMMC : public CdrDriver { public: GenericMMC(ScsiIf *scsiIf, unsigned long options); ~GenericMMC(); static CdrDriver *instance(ScsiIf *scsiIf, unsigned long options); /*! \brief See what subchannel reading modes are available For each data/audio track it tries PQ subchannel (using GenericMMC::readCdTest); it may result in: - not supported - BCD format - HEX format - unknown (error printout) Then it tries - Raw PW - Cooked PW You may skip some tests if you have initialized the driver with something like OPT_MMC_USE_PQ. \param CdToc* Toc of the disc, used to compute track lengths \param int Number of tracks to use for the test \return Binary OR of the capabilities. \sa CDR_READ_CAP_DATA_PW_RAW and similar. */ unsigned long getReadCapabilities(const CdToc *, int) const; /*! \brief MMC compatible drives take little endian samples \return 0 */ int bigEndianSamples() const { return 0; } /*! \brief Sanity checking of the TOC A first check is done using CdrDriver::checkToc. Then, if CD TEXT capabilities are available, it checks CD TEXT using Toc::checkCdTextData. \return 0 if OK, 1 if some warning, 2 on error */ int checkToc(const Toc *); /*! \brief Sets read/write speed Uses SET CD SPEED command 0xBB. Speeds are specified as multipliers, using 0 as means max value. Write speed is set from protected variable GenericMMC::speed_. \param int Read speed as multiplier. \return 0 on success, 1 if SCSI command error */ int speed(int); /*! \brief Returns current write speed Rebuilds the GenericMMC::driveInfo_ structure by reading mode page 0x2A. Information is extracted from this structure. \return Write speed (as multiplier) or 0 if SCSI error occurred. */ int speed(); bool rspeed(int); int rspeed(); /*! \brief Gathers various info about inserted disk. - Issues READ DISK INFORMATION 0x51. Obtains number of tracks and sessions and disk completion status. - Issues READ TOC 0x43 with parameter 1 to get session info. - Reads ATIP data (READ TOC 0x43, parameter 4) \return Pointer to protected attribute GenericMMC::diskInfo_ */ DiskInfo *diskInfo(); /*! \brief Loads or ejects tray Uses START/STOP unit command 0x1B. \param int 0 to load tray, 1 to eject \return 0 on success, 1 on error */ int loadUnload(int) const; /*! \brief Blanks a CDRW First the drive is put in simulation or write mode, as specified in GenericMMC::simulate_ attribute. Then the disk is blanked with BLANK 0xA1. The IMMED bit is not set, and the call will block until the operation is completed. Drive status will be polled every 2 seconds. \param BlankingMode Either BLANK_FULL or BLANK_MINIMAL \return 0 on success or 1 on error */ int blankDisk(BlankingMode); /*! \brief Initializes internal stuff before a write session. - Setup CD-TEXT encoder if specified in GenericMMC::options_ - Gets inserted disk info with GenericMMC::diskInfo - Sets write speed with GenericMMC::selectSpeed - Allocates new data buffer into GenericMMC::zeroBuffer_ \param Toc* TOC of the disk you want to write \return 0 on success, 1 on error */ int initDao(const Toc *); /*! \brief Begins write process Sets write parameters (MP 0x05), performs power calibration if not in simulation mode, sends cue sheet and writes leadin. The session LBA is always -150. First 150 sectors are zeroed. \return 0 on success, 1 on error */ int startDao(); /*! \brief Finishes a writing Flush device cache and wait for device to become ready. Since some drives do not return to ready after writing a leadout the cache flush is done twice, before and after the wait unit ready. Then the CD-TEXT encoder and the zero buffer are deleted. \return 0 on success, 1 on error */ int finishDao(); /*! \brief Aborts a writing Flush device cache and delete CD-TEXT encoder. */ void abortDao(); /*! \brief Writes data to target The block length depends on the actual writing. Writing is done using WRITE10 (0x2A) command. Command is retried if device buffer is full. \param TrackData::Mode Main channel writing mode \param TrackData::SubChannelMode Subchannel writing mode \param lba specifies the next logical block address for writing and is updated by this function. \param buf Data to be written \param len Number of blocks to write \return 0 if OK, 1 if WRITE command failed */ int writeData(TrackData::Mode, TrackData::SubChannelMode, long &lba, const char *buf, long len); /*! \brief Gets useful parameters about the device. Gets mode page 0x2A and info about - Burnproof - Accurate audio stream - Maximum read speed - Current read speed - Maximum write speed - Maximum read speed \param showErrorMsg If true print out errors \return Pointer to the protected variable driveInfo_ */ const DriveInfo *driveInfo(bool showErrorMsg); /*! Returns 0 or 1 depending on the SubChannelMode parameter. - 0 if SUBCHAN_NONE - 0 if SUBCHAN_RW - 1 if SUBCHAN_RW_RAW \param SubChannelMode One of TrackData::SubChannelMode \return 0 or 1 (see above) */ int subChannelEncodingMode(TrackData::SubChannelMode) const; protected: int scsiTimeout_; // Timeout for commands on the target Msf leadInStart_; // Start of lead-in long leadInLen_; // Length of lead-in long leadOutLen_; // Length if lead-out DiskInfo diskInfo_; // Various info about the inserted media DriveInfo *driveInfo_; // Various info about the device CdTextEncoder *cdTextEncoder_; // Called by GenericMMC::initDao if needed. bool cdtextEnabled_; // Write CD-TEXT subchannels /*! \brief Determines start and length of lead-in and length of lead-out. Uses READ DISK INFORMATION cmd 0x51. \return 0 on success, 1 on SCSI error */ virtual int getSessionInfo(); /*! \brief Gets next writable address Uses READ TRACK INFORMATION 0x52 on incomplete track 0xFF. Must return RT=1 and NWA_V=1. LBA of next writable address is taken from bytes 12-15. \param long* LBA of next writable address. \return 0 on success, 1 on SCSI error */ virtual int getNWA(long *); /*! \brief Determines first writable address of data area of current empty session. Places the device in Session At Once write type and calls GenericMMC::getNWA \param long* LBA of the beginning of data area \return 0 on success, 1 on SCSI error. */ virtual int getStartOfSession(long *); /*! \brief Still unused */ virtual int getFeature(unsigned int feature, u8 *buf, unsigned long bufLen, int showMsg); /*! \brief Reads Media Catalog Number If option OPT_MMC_SCAN_MCN is specified uses CdrDriver::readCatalogScan to scan subchannels of sectors from startlba to endlba to find MCN and (if valid) saves it into Toc. If OPT_MMC_SCAN_MCN isn't asserted uses proper command READ SUBCHANNEL 0x42 with parameter 0x02 to do the same (and startlba, endlba are unused). \param Toc* Toc of the disk. MCN can be saved here \param startLba Start subchannel scan here \param endLba End subchannel scan here \return 1 if valid MCN found, else 0 */ int readCatalog(Toc *, long startLba, long endLba); /*! \brief Reads media ISRC Uses READ SUBCHANNEL 0x42 with parameter 0x03. Track is specified by the int parameter. If TCVAL == 1 ISRC is valid and is copied to char* parameter. \param int Track to read ISRC of. \param char* Pre-allocated buffer to store ISRC (12 bytes) \return Always 0 */ int readIsrc(int, char *); /*! \brief Sets read/write speed Sets the read speed from readSpeed parameter, and write speed from GenericMMC::speed_ protected attribute. Both can be specified as 0 for maximum or as multiplier. \param readSpeed Read speed to set: use 0 for max or multiplier \todo This documentation needs to be updated \return 1 on SCSI error, 0 on success */ virtual int selectSpeed(); /*! \brief Sets write parameters in page 0x05 - Write type is 0x02 (SAO). - Simulation is set from GenericMMC::simulate_ protected attrib. - BurnFree is set if drive supports it, unless explicitly disabled. - Next session opened if GenericMMC::multiSession_ - Data block type ranges from 0 to 3, depending on the CD-TEXT encoder. \param variant Ranges from 0 to 3, defining modes 0-3 of Data Block Type Codes in Write Mode Page 0x05. \return 0 on success, 1 on SCSI error. */ virtual int setWriteParameters(unsigned long variant); /*! \brief Puts drive in simulation/write mode Based on GenericMMC::simulate_ attrib. \param showMessage If asserted print out errors. \return 0 on success, 1 on SCSI errors */ int setSimulationMode(int showMessage); /*! \brief Asks unit to perform power calibration Uses SEND OPC INFORMATION (0x54) command with DoOpc set to 1. \return 0 if command not supported or power calibration successful, 1 on error */ int performPowerCalibration(); /*! \brief Free data bytes available in the device's buffer. Uses READ BUFFER CAPACITY 0x5C command. \param capacity Will hold number of bytes. \todo This documentation needs to be updated \return 0 on success, 1 on SCSI command error. */ bool readBufferCapacity(long *capacity, long *available); /*! \brief Creates cue sheet for current toc Called by GenericMMC::sendCueSheet to build cuesheets. \param variant Ranges from 0 to 3, defining modes 0-3 of Data Block Type Codes in Write Mode Page 0x05. \param cueSheetLen Filled with cue sheet length in bytes \return Newly allocated cue sheet buffer or 'NULL' on error */ unsigned char *createCueSheet(unsigned long variant, long *cueSheetLen); /*! \brief Builds and sends cuesheet For each of the 4 available variants builds (using GenericMMC::sendCueSheet) a cuesheet and sends to the device using SEND CUE SHEET 0x5D. Stops when device accepts a variant. \return 0 on success, 1 on error (no variants accepted) */ int sendCueSheet(); /*! \brief Returns subchannel SCSI standard code for cuesheet Used in GenericMMC::createCueSheet to obtain code for cuesheet. \param TrackData::SubChannelMode One of SUBCHAN_NONE,SUBCHAN_RW,SUBCHAN_RW_RAW \param encodingMode 0 or 1 \return int - 0 if SUBCHAN_NONE - 0x40 if encodingMode==0 and SUBCHAN_RW(_RAW) - 0x40 if encodingMode==1 and SUBCHAN_RW(_RAW) */ unsigned char subChannelDataForm(TrackData::SubChannelMode, int encodingMode); /*! \brief Writes the subchannel data in the leadin section, used in CD-TEXT Issues WRITE (0x2A) commands to write PW subchannels starting at LBA = -150 - leadInLen_ \return int - 0 if cdTextEncoder_ == NULL or everything OK - 1 if some error occurred (message output) */ int writeCdTextLeadIn(); int analyzeTrack(TrackData::Mode, int trackNr, long startLba, long endLba, Msf *index, int *indexCnt, long *pregap, char *isrcCode, unsigned char *ctl); int getTrackIndex(long lba, int *trackNr, int *indexNr, unsigned char *ctl); int readSubChannels(TrackData::SubChannelMode, long lba, long len, SubChannel ***, Sample *); /*! \brief retrieve mode of the track that starts at the specified trackStartLba. Uses READ CD (0xBE) command with byte 9 == 0xF8 (SYNC + Header + Userdata + EDC_ECC + C2 and block errors, No subchannels) to retrieve the sector addressed as trackStartLba. Uses CdrDriver::determineSectorMode to identify track mode. \return TrackData::Mode */ TrackData::Mode getTrackMode(int, long trackStartLba); CdRawToc *getRawToc(int sessionNr, int *len); long readTrackData(TrackData::Mode, TrackData::SubChannelMode, long lba, long len, unsigned char *buf); int readAudioRange(ReadDiskInfo *, int fd, long start, long end, int startTrack, int endTrack, TrackInfo *); int readCdTest(long lba, long len, int subChanMode) const; /*! \brief Checks for ready status of the drive after a write operation. Disc must be inserted. Unit should return successfully from TEST UNIT READY command, and from READ DISC INFORMATION. \return int - 0 drive ready - 1 error occured at os level, no sense data - 2 NOT READY,LONG WRITE IN PROGRESS */ int checkDriveReady() const; int RicohGetWriteOptions(); int RicohSetWriteOptions(const DriveInfo *); }; #endif �����������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/GenericMMCraw.cc����������������������������������������������������������0000664�0000000�0000000�00000047063�15114537466�0020405�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #include <config.h> #include <string.h> #include <assert.h> #include "GenericMMCraw.h" #include "PQSubChannel16.h" #include "PWSubChannel96.h" #include "CdTextEncoder.h" #include "Toc.h" #include "log.h" #include "port.h" GenericMMCraw::GenericMMCraw(ScsiIf *scsiIf, unsigned long options) : GenericMMC(scsiIf, options), PQChannelEncoder() { driverName_ = "Generic SCSI-3/MMC (raw writing) - Version 2.0"; encodingMode_ = 0; subChannelMode_ = 0; leadInLen_ = leadOutLen_ = 0; subChannel_ = NULL; encSubChannel_ = NULL; encodeBuffer_ = NULL; // CD-TEXT dynamic data cdTextStartLba_ = 0; cdTextEndLba_ = 0; cdTextSubChannels_ = NULL; cdTextSubChannelCount_ = 0; cdTextSubChannelAct_ = 0; } GenericMMCraw::~GenericMMCraw() { delete subChannel_, subChannel_ = NULL; delete[] encodeBuffer_, encodeBuffer_ = NULL; delete[] encSubChannel_; encSubChannel_ = NULL; cdTextStartLba_ = 0; cdTextEndLba_ = 0; cdTextSubChannels_ = NULL; cdTextSubChannelCount_ = 0; cdTextSubChannelAct_ = 0; } int GenericMMCraw::multiSession(bool m) { if (m) { // multi session mode is currently not support for raw writing return 1; } return 0; } // static constructor CdrDriver *GenericMMCraw::instance(ScsiIf *scsiIf, unsigned long options) { return new GenericMMCraw(scsiIf, options); } int GenericMMCraw::subChannelEncodingMode(TrackData::SubChannelMode sm) const { int ret = 0; if (subChannelMode_ == 0) { // The supported sub-channel writing mode has not been determined, yet, // so just return the plain mode here. 'initDao' will finally check if // writing of the sub-channel data defined in 'toc_' is supported by the // drive. return 0; } switch (sm) { case TrackData::SUBCHAN_NONE: ret = 0; break; case TrackData::SUBCHAN_RW: switch (subChannelMode_) { case 2: ret = 0; // plain break; case 3: ret = -1; // currently not supported //ret = 1; // have to create parity and perform interleaving break; default: ret = -1; // not supported break; } break; case TrackData::SUBCHAN_RW_RAW: if (subChannelMode_ == 3) ret = 1; else ret = -1; break; } return ret; } // Sets write parameters via mode page 0x05. // return: 0: OK // 1: scsi command failed int GenericMMCraw::setWriteParameters(int dataBlockType) { u8 mp[0x38]; if (getModePage(5/*write parameters mode page*/, mp, 0x38, NULL, NULL, 1) != 0) { log_message(-2, "Cannot retrieve write parameters mode page."); return 1; } mp[0] &= 0x7f; // clear PS flag mp[2] &= 0xe0; mp[2] |= 0x03; // write type: raw if (simulate_) { mp[2] |= 1 << 4; // test write } const DriveInfo *di; if ((di = driveInfo(1)) != NULL) { if (di->burnProof) { // This drive has BURN-Proof function. // Enable it unless explicitly disabled. if (bufferUnderRunProtection()) { log_message(2, "Turning BURN-Proof on"); mp[2] |= 0x40; } else { log_message(2, "Turning BURN-Proof off"); mp[2] &= ~0x40; } } RicohSetWriteOptions(di); } mp[3] &= 0x3f; // Multi-session: No B0 pointer, next session not allowed mp[3] = 0; mp[4] &= 0xf0; mp[4] = dataBlockType & 0x0f; // Data Block Type: // 1: raw data, block size: 2368 PQ sub chan // 2: raw data, block size: 2448 // 3: raw data, block size: 2448 mp[8] = 0; // session format: CD-DA or CD-ROM if (setModePage(mp, NULL, NULL, 0) != 0) { //log_message(-2, "Cannot set write parameters mode page."); return 1; } return 0; } int GenericMMCraw::getMultiSessionInfo(int sessionNr, int multi, SessionInfo *info) { int err = 0; memset(info, 0, sizeof(SessionInfo)); info->sessionNr = 1; if (getSessionInfo() != 0) return 1; info->leadInStart = leadInStart_.lba() - 150; if (leadInStart_.min() >= 80) { info->leadInStart = leadInStart_.lba() - 450000; } info->leadInLen = leadInLen_; info->leadOutLen = leadOutLen_; if (multi) { u8 cmd[10]; u8 data[4]; u8 *buf = NULL; long dataLen; // read ATIP data memset(cmd, 0, 10); memset(data, 0, 4); cmd[0] = 0x43; // READ TOC/PMA/ATIP cmd[1] = 0x00; cmd[2] = 4; // get ATIP cmd[7] = 0; cmd[8] = 4; // data length if (sendCmd(cmd, 10, NULL, 0, data, 4, 0) != 0) { log_message(-2, "Cannot read ATIP data."); return 1; } dataLen = (data[0] << 8) | data[1]; dataLen += 2; log_message(4, "ATIP data len: %ld", dataLen); if (sessionNr == 1) { if (dataLen < 19) { log_message(-2, "Cannot read ATIP data."); return 1; } } else { if (dataLen < 15) { log_message(-2, "Cannot read ATIP data."); return 1; } } buf = new u8[dataLen]; memset(buf, 0, dataLen); cmd[7] = dataLen >> 8; cmd[8] = dataLen; if (sendCmd(cmd, 10, NULL, 0, buf, dataLen, 0) != 0) { log_message(-2, "Cannot read ATIP data."); delete[] buf; return 1; } info->lastLeadoutStart = Msf(buf[12], buf[13], buf[14]); if (sessionNr == 1) { info->optimumRecordingPower = buf[4]; if (buf[8] >= 80 && buf[8] <= 99) { info->atipLeadinStart = Msf(buf[8], buf[9], buf[10]); } else { log_message(-2, "Invalid start time of lead-in in ATIP."); err = 1; } info->cdrw = (buf[6] & 0x40) ? 1 : 0; if (info->cdrw) { if (buf[6] & 0x04) { info->atipA1[0] = buf[16]; info->atipA1[1] = buf[17]; info->atipA1[2] = buf[18]; } else { log_message(-2, "ATIP data does not contain point A1 data."); err = 1; } } } delete[] buf; buf = NULL; } log_message(4, "SI: session nr: %d", info->sessionNr); log_message(4, "SI: lead-in start: %ld", info->leadInStart); log_message(4, "SI: lead-in len: %ld", info->leadInLen); log_message(4, "SI: lead-out len: %ld", info->leadOutLen); log_message(4, "SI: last lead-out start: %d %d %d", info->lastLeadoutStart.min(), info->lastLeadoutStart.sec(), info->lastLeadoutStart.frac()); log_message(4, "SI: cdrw: %d", info->cdrw); log_message(4, "SI: atip lead-in start: %d %d %d", info->atipLeadinStart.min(), info->atipLeadinStart.sec(), info->atipLeadinStart.frac()); log_message(4, "SI: optimum recording power: %u", info->optimumRecordingPower); log_message(4, "SI: atip A1: %u %u %u", info->atipA1[0], info->atipA1[1], info->atipA1[2]); return err; } int GenericMMCraw::getSubChannelModeFromToc() { TrackIterator itr(CdrDriver::toc_); const Track *tr; int mode = 0; for (tr = itr.first(); tr != NULL; tr = itr.next()) { switch (tr->subChannelType()) { case TrackData::SUBCHAN_NONE: break; case TrackData::SUBCHAN_RW: // we need at least packed RW writing if (mode < 2) mode = 2; break; case TrackData::SUBCHAN_RW_RAW: // we need raw PW writing mode = 3; break; } } log_message(5, "Sub-channel mode requested by toc: %d", mode); return mode; } int GenericMMCraw::setSubChannelMode() { delete subChannel_; subChannel_ = NULL; subChannelMode_ = 0; #if 1 if (cdTextEncoder_ != NULL) { if (setWriteParameters(3) == 0) { subChannel_ = new PWSubChannel96; subChannelMode_ = 3; } else { delete cdTextEncoder_; cdTextEncoder_ = NULL; log_message(force() ? -1 : -2, "Cannot write CD-TEXT data because the 96 byte raw P-W sub-channel data mode is not supported."); if (force()) { log_message(-1, "Ignored because of --force option."); } else { log_message(-2, "Use option --force to ignore this error."); return 1; } } } // check if the toc requires a certain sub-channel mode and try to set it if (subChannel_ == NULL) { int tocMode = getSubChannelModeFromToc(); if (tocMode > 0) { for (; tocMode <= 3 && subChannel_ == NULL; tocMode++) { if (setWriteParameters(tocMode) == 0) { if (tocMode == 1) subChannel_ = new PQSubChannel16; else subChannel_ = new PWSubChannel96; subChannelMode_ = tocMode; } } if (subChannel_ == NULL) { log_message(-2, "Cannot setup sub-channel writing mode for sub-channel data defined in the toc-file."); return 1; } } } // select any available sub-channel mode if (subChannel_ == NULL) { if (setWriteParameters(1) == 0) { subChannel_ = new PQSubChannel16; subChannelMode_ = 1; } else if (setWriteParameters(3) == 0) { subChannel_ = new PWSubChannel96; subChannelMode_ = 3; } else if (setWriteParameters(2) == 0) { subChannel_ = new PWSubChannel96; subChannelMode_ = 2; } else { log_message(-2, "Cannot setup disk-at-once writing for this drive."); return 1; } } #else //subChannel_ = new PWSubChannel96; subChannel_ = new PQSubChannel16; subChannelMode_ = 1; #endif switch (subChannelMode_) { case 1: log_message(2, "Using 16 byte P-Q sub-channel data mode."); break; case 2: log_message(2, "Using 96 byte packed P-W sub-channel data mode."); break; case 3: if (cdTextEncoder_ != NULL) log_message(2, "Using 96 byte raw P-W sub-channel data mode for CD-TEXT."); else log_message(2, "Using 96 byte raw P-W sub-channel data mode."); break; } return 0; } int GenericMMCraw::initDao(const Toc *toc) { long n; CdrDriver::toc_ = toc; if (selectSpeed() != 0 || getSessionInfo() != 0) { return 1; } delete cdTextEncoder_; cdTextEncoder_ = new CdTextEncoder(toc); if (cdTextEncoder_->encode() != 0) { log_message(-2, "CD-TEXT encoding failed."); return 1; } if (cdTextEncoder_->getSubChannels(&n) == NULL || n == 0) { delete cdTextEncoder_; cdTextEncoder_ = NULL; } if (setSubChannelMode() != 0) return 1; blockLength_ = AUDIO_BLOCK_LEN + subChannel_->dataLength(); blocksPerWrite_ = scsiIf_->maxDataLen() / blockLength_; assert(blocksPerWrite_ > 0); log_message(4, "Block length: %ld", blockLength_); long cueSheetLen; u8 *cueSheet = createCueSheet(0, &cueSheetLen); if (cueSheet == NULL) { return 1; } if (setCueSheet(subChannel_, sessionFormat(), cueSheet, cueSheetLen, leadInStart_) != 0) { return 1; } if (cdTextEncoder_ != NULL) { cdTextStartLba_ = leadInStart_.lba() - 450150; cdTextEndLba_ = cdTextStartLba_ + leadInLen_; cdTextSubChannels_ = cdTextEncoder_->getSubChannels(&cdTextSubChannelCount_); cdTextSubChannelAct_ = 0; } else { cdTextStartLba_ = 0; cdTextEndLba_ = 0; cdTextSubChannels_ = NULL; cdTextSubChannelCount_ = 0; cdTextSubChannelAct_ = 0; } // allocate buffer for write zeros n = blocksPerWrite_ * (AUDIO_BLOCK_LEN + subChannel_->dataLength()); delete[] zeroBuffer_; zeroBuffer_ = new char[n]; memset(zeroBuffer_, 0, n); // allocate buffer for sub-channel encoding n = blocksPerWrite_ * blockLength_; delete[] encodeBuffer_; encodeBuffer_ = new u8[n]; delete[] encSubChannel_; encSubChannel_ = new u8[blocksPerWrite_ * subChannel_->dataLength()]; /* SessionInfo sessInfo; getMultiSessionInfo(1, 1, &sessInfo); return 1; */ if (!simulate_) { if (performPowerCalibration() != 0) { if (!force()) { log_message(-2, "Use option --force to ignore this error."); return 1; } else { log_message(-2, "Ignored because of option --force."); } } } return 0; } int GenericMMCraw::startDao() { log_message(2, "Writing lead-in and gap..."); long lba = leadInStart_.lba() - 450150; if (writeZeros(CdrDriver::toc_->leadInMode(), TrackData::SUBCHAN_NONE, lba, 0, leadInLen_) != 0) { return 1; } TrackData::SubChannelMode subChanMode = TrackData::SUBCHAN_NONE; TrackIterator itr(CdrDriver::toc_); const Track *tr; if ((tr = itr.first()) != NULL) { subChanMode = tr->subChannelType(); } if (writeZeros(CdrDriver::toc_->leadInMode(), subChanMode, lba, 0, 150) != 0) { return 1; } return 0; } int GenericMMCraw::finishDao() { int ret; log_message(2, "Writing lead-out..."); long lba = CdrDriver::toc_->length().lba(); writeZeros(CdrDriver::toc_->leadOutMode(), TrackData::SUBCHAN_NONE, lba, lba + 150, leadOutLen_); log_message(2, "\nFlushing cache..."); if (flushCache() != 0) { return 1; } while ((ret = checkDriveReady()) == 2) mSleep(2000); if (ret != 0) log_message(-1, "TEST UNIT READY failed after recording."); delete cdTextEncoder_, cdTextEncoder_ = NULL; delete[] zeroBuffer_, zeroBuffer_ = NULL; delete[] encodeBuffer_, encodeBuffer_ = NULL; return 0; } long GenericMMCraw::nextWritableAddress() { u8 cmd[10]; u8 data[28]; long lba = 0xffffffff; memset(cmd, 0, 10); memset(data, 0, 28); cmd[0] = 0x52; // READ TRACK INFORMATION cmd[1] = 0; cmd[2] = lba >> 24; cmd[3] = lba >> 16; cmd[4] = lba >> 8; cmd[5] = lba; cmd[8] = 28; if (sendCmd(cmd, 10, NULL, 0, data, 28) != 0) { log_message(-2, "Cannt get track information."); return 0; } long adr = (data[12] << 24) | (data[13] << 16) | (data[14] << 8) | data[15]; return adr; } // Writes data to target. The encoded sub-channel data is appended to each // block. // return: 0: OK // 1: scsi command failed int GenericMMCraw::writeData(TrackData::Mode mode, TrackData::SubChannelMode sm, long &lba, const char *buf, long len) { assert(blockLength_ > 0); assert(blocksPerWrite_ > 0); assert(mode == TrackData::AUDIO); int writeLen = 0; u8 cmd[10]; int i, j; long iblen = blockSize(mode, sm); long slen = subChannel_->dataLength(); /* log_message(0, "lba: %ld, len: %ld, bpc: %d, bl: %d ", lba, len, blocksPerCmd, blockLength_); */ memset(cmd, 0, 10); cmd[0] = 0x2a; // WRITE1 while (len > 0) { writeLen = (len > blocksPerWrite_ ? blocksPerWrite_ : len); cmd[2] = lba >> 24; cmd[3] = lba >> 16; cmd[4] = lba >> 8; cmd[5] = lba; cmd[7] = writeLen >> 8; cmd[8] = writeLen; // encode the PQ sub-channel data encode(lba, encSubChannel_, writeLen); for (i = 0; i < writeLen; i++) { memcpy(encodeBuffer_ + i * blockLength_, buf + i * iblen, AUDIO_BLOCK_LEN); memcpy(encodeBuffer_ + i * blockLength_ + AUDIO_BLOCK_LEN, encSubChannel_ + i * slen, slen); if (cdTextSubChannels_ != NULL && lba >= cdTextStartLba_ && lba + i < cdTextEndLba_) { const u8 *data = cdTextSubChannels_[cdTextSubChannelAct_]->data(); long dataLen = cdTextSubChannels_[cdTextSubChannelAct_]->dataLength(); u8 *actBuf = encodeBuffer_ + i * blockLength_ + AUDIO_BLOCK_LEN; //log_message(0, "Adding CD-TEXT channel %ld for LBA %ld", cdTextSubChannelAct_, lba + i); for (j = 0; j < dataLen; j++) { *actBuf |= (*data & 0x3f); actBuf++; data++; } cdTextSubChannelAct_++; if (cdTextSubChannelAct_ >= cdTextSubChannelCount_) cdTextSubChannelAct_ = 0; } else { switch (sm) { case TrackData::SUBCHAN_NONE: break; case TrackData::SUBCHAN_RW: case TrackData::SUBCHAN_RW_RAW: { u8 *oBuf = encodeBuffer_ + i * blockLength_ + AUDIO_BLOCK_LEN; const char *iBuf = buf + i * iblen + AUDIO_BLOCK_LEN; for (j = 0; j < PW_SUBCHANNEL_LEN; j++) { *oBuf |= (*iBuf & 0x3f); oBuf++; iBuf++; } } break; } } } #if 0 // consistency checks long sum1, sum2; int n; const char *p; for (i = 0; i < writeLen; i++) { log_message(0, "%ld: ", lba + i); SubChannel *chan = subChannel_->makeSubChannel(encodeBuffer_ + i * blockLength_ + AUDIO_BLOCK_LEN); chan->print(); delete chan; sum1 = 0; for (p = buf + i * iblen, n = 0; n < AUDIO_BLOCK_LEN; n++, p++) { sum1 += *p; } sum2 = 0; for (n = 0; n < AUDIO_BLOCK_LEN; n++) { sum2 += *(char *)(encodeBuffer_ + i * blockLength_ + n); } //log_message(0, "%ld - %ld", sum1, sum2); assert(sum1 == sum2); } #endif #if 1 if (sendCmd(cmd, 10, encodeBuffer_, writeLen * blockLength_, NULL, 0) != 0) { log_message(-2, "Write data failed."); return 1; } #endif //log_message(0, ". "); lba += writeLen; len -= writeLen; buf += writeLen * iblen; } //log_message(0, ""); return 0; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/GenericMMCraw.h�����������������������������������������������������������0000664�0000000�0000000�00000004450�15114537466�0020240�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __GENERIC_MMC_RAW_H__ #define __GENERIC_MMC_RAW_H__ #include "GenericMMC.h" #include "PQChannelEncoder.h" #include "PWSubChannel96.h" class GenericMMCraw : public GenericMMC, private PQChannelEncoder { public: GenericMMCraw(ScsiIf *scsiIf, unsigned long options); ~GenericMMCraw(); static CdrDriver *instance(ScsiIf *scsiIf, unsigned long options); int multiSession(bool); int subChannelEncodingMode(TrackData::SubChannelMode) const; int initDao(const Toc *); int startDao(); int finishDao(); int writeData(TrackData::Mode, TrackData::SubChannelMode, long &lba, const char *buf, long len); protected: int setWriteParameters(int); private: u8 *encodeBuffer_; // buffer for encoding sub-channels u8 *encSubChannel_; // holds encoded sub-channels SubChannel *subChannel_; // sub channel template int subChannelMode_; /* selected sub-channel writing mode: 0: undefined 1: 16 byte PQ 2: 96 byte PW packed 3: 96 byte PW raw */ long cdTextStartLba_; long cdTextEndLba_; const PWSubChannel96 **cdTextSubChannels_; long cdTextSubChannelCount_; long cdTextSubChannelAct_; long nextWritableAddress(); int getMultiSessionInfo(int sessionNr, int multi, SessionInfo *info); int getSubChannelModeFromToc(); int setSubChannelMode(); }; #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/Makefile.am���������������������������������������������������������������0000664�0000000�0000000�00000004211�15114537466�0017473�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������noinst_LIBRARIES = libdao.a bin_PROGRAMS = cdrdao cdrdao_SOURCES = \ main.cc libdao_a_SOURCES = \ main.cc \ dao.cc \ port.cc \ data.cc \ CdrDriver.cc \ CDD2600Base.cc \ CDD2600.cc \ PlextorReader.cc \ GenericMMC.cc \ SubChannel.cc \ PQSubChannel16.cc \ PWSubChannel96.cc \ PQChannelEncoder.cc \ GenericMMCraw.cc \ PlextorReaderScan.cc \ RicohMP6200.cc \ TaiyoYuden.cc \ YamahaCDR10x.cc \ TeacCdr55.cc \ SonyCDU920.cc \ SonyCDU948.cc \ ToshibaReader.cc \ CdTextEncoder.cc \ Settings.cc \ CDD2600Base.h \ CDD2600.h \ cdda_interface.h \ CdrDriver.h \ CdTextEncoder.h \ dao.h \ data.h \ GenericMMC.h \ GenericMMCraw.h \ PlextorReader.h \ PlextorReaderScan.h \ port.h \ PQChannelEncoder.h \ PQSubChannel16.h \ PWSubChannel96.h \ remote.h \ RicohMP6200.h \ ScsiIf.h \ Settings.h \ sg_err.h \ SonyCDU920.h \ SonyCDU948.h \ SubChannel.h \ TaiyoYuden.h \ TeacCdr55.h \ ToshibaReader.h \ YamahaCDR10x.h EXTRA_libdao_a_SOURCES = \ dao-win32.cc \ decodeSense.cc \ sg_err.cc \ ScsiIf-common.cc \ ScsiIf-linux.cc \ ScsiIf-freebsd-cam.cc \ ScsiIf-netbsd.cc \ ScsiIf-irix.cc \ ScsiIf-osx.cc \ ScsiIf-nt.cc libdao_a_LIBADD = \ @scsilib_objs@ libdao_a_DEPENDENCIES = \ @scsilib_objs@ cdrdao_LDADD = \ ./libdao.a \ $(top_builddir)/paranoia/libcdda_paranoia.a \ $(top_builddir)/trackdb/libtrackdb.a \ @thread_libs@ \ @scsilib_libs@ \ @LIBICONV@ if COND_MP3 cdrdao_LDADD += @MAD_LIBS@ endif if COND_OGG cdrdao_LDADD += @VORBISFILE_LIBS@ endif cdrdao_LDADD += @AO_LIBS@ cdrdao_DEPENDENCIES = \ $(top_builddir)/paranoia/libcdda_paranoia.a \ $(top_builddir)/trackdb/libtrackdb.a \ @scsilib_objs@ \ libdao.a drivertabledir = $(datadir)/cdrdao drivertable_DATA = cdrdao.drivers CDRDAO_DATA_DIR = $(datadir)/cdrdao DRIVER_TABLE_FILE = $(CDRDAO_DATA_DIR)/drivers install-data-hook: cd $(DESTDIR)$(datadir)/cdrdao && \ mv cdrdao.drivers drivers AM_CPPFLAGS = \ -I$(srcdir)/../trackdb \ -I$(srcdir)/../paranoia AM_CXXFLAGS = -DDRIVER_TABLE_FILE=\"$(DRIVER_TABLE_FILE)\" man1_MANS = cdrdao.man EXTRA_DIST = $(man1_MANS) cdrdao.drivers ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/PQChannelEncoder.cc�������������������������������������������������������0000664�0000000�0000000�00000030631�15114537466�0021064�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <andreas@daneb.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 * (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. */ #include <config.h> #include <stdio.h> #include <string.h> #include <assert.h> #include "PQChannelEncoder.h" #include "Msf.h" #include "Track.h" #include "log.h" PQChannelEncoder::PQChannelEncoder() { cueSheet_ = NULL; cueSheetLen_ = 0; toc_ = NULL; tocLen_ = 0; discType_ = 0; current_ = NULL; catalog_ = NULL; isrc_ = NULL; } PQChannelEncoder::~PQChannelEncoder() { int i; for (i = 0; i < tocLen_; i++) { delete toc_[i]; } delete[] toc_; delete[] cueSheet_; delete current_; delete catalog_; delete isrc_; } int PQChannelEncoder::setCueSheet(SubChannel *chan, unsigned char discType, const unsigned char *sheet, int len, const Msf &leadInStart) { int tocEnt, i; subChannel_ = chan; // Convert toc type to decimal numbers so that they look like the // corresponding hex value when stored as BCD in the sub-channel switch (discType) { case 0: break; case 0x10: discType = 10; break; case 0x20: discType = 20; break; default: log_message(-3, "Illegal disc type."); return 1; } if ((len % sizeof(CueSheetEntry)) != 0) { log_message(-3, "Illegal cue sheet length."); return 1; } discType_ = discType; cueSheetLen_ = len / sizeof(CueSheetEntry); cueSheet_ = new CueSheetEntry[cueSheetLen_ + 1]; memcpy(cueSheet_, sheet, len); // mark end of queue sheet with a zeroed entry memset(cueSheet_ + cueSheetLen_, 0, sizeof(CueSheetEntry)); // create some sub channel objects catalog_ = subChannel_->makeSubChannel(SubChannel::QMODE2); isrc_ = subChannel_->makeSubChannel(SubChannel::QMODE3); current_ = subChannel_->makeSubChannel(SubChannel::QMODE1DATA); if (analyzeCueSheet() != 0) { return 1; } // create PQ sub channels for toc in lead-in tocLen_ = lastTrackNr_ - firstTrackNr_ + 1 + 3/*A0, A1, A2*/; toc_ = new SubChannel*[tocLen_]; for (i = 0; i < tocLen_; i++) { toc_[i] = subChannel_->makeSubChannel(SubChannel::QMODE1TOC); } CueSheetEntry *run; for (run = actCueSheetEntry_, tocEnt = 0; (run->ctlAdr & 0x0f) != 1 || run->trackNr != 0xaa; run++) { if ((run->ctlAdr & 0x0f) == 1 && run->trackNr > 0 && run->trackNr <= 99 && run->indexNr == 1) { toc_[tocEnt]->ctl(run->ctlAdr & 0xf0); toc_[tocEnt]->point(run->trackNr); toc_[tocEnt]->pmin(run->min); toc_[tocEnt]->psec(run->sec); toc_[tocEnt]->pframe(run->frame); tocEnt++; } } toc_[tocEnt]->point(0xa0); toc_[tocEnt]->pmin(firstTrackNr_); toc_[tocEnt]->psec(discType_); toc_[tocEnt]->ctl(firstTrackCtlAdr_ & 0xf0); tocEnt++; toc_[tocEnt]->point(0xa1); toc_[tocEnt]->pmin(lastTrackNr_); toc_[tocEnt]->ctl(lastTrackCtlAdr_ & 0xf0); tocEnt++; toc_[tocEnt]->point(0xa2); toc_[tocEnt]->pmin(leadOutStart_.min()); toc_[tocEnt]->psec(leadOutStart_.sec()); toc_[tocEnt]->pframe(leadOutStart_.frac()); toc_[tocEnt]->ctl(leadOutCtlAdr_ & 0xf0); tocEnt++; assert(tocEnt == tocLen_); // setup encoder dynamic data abslba_ = leadInStart.lba() - 450150; trlba_ = 0; writeIsrc_ = 0; deferredCatalog_ = 0; deferredIsrc_ = 0; actTocEnt_ = actTocCount_ = 0; run = nextCueSheetEntry(actCueSheetEntry_, 1); assert(run != NULL); nextTransitionLba_ = Msf(run->min, run->sec, run->frame).lba() - 150; run = nextCueSheetEntry(actCueSheetEntry_, firstTrackNr_, 1); assert(run != NULL); nextTrackStartLba_ = Msf(run->min, run->sec, run->frame).lba() - 150; return 0; } int PQChannelEncoder::analyzeCueSheet() { int i; CueSheetEntry *ent; int prevTrackNr = -1; long prevLba = -1; long lba; firstTrackNr_ = 0; firstTrackCtlAdr_ = 0; lastTrackNr_ = 0; lastTrackCtlAdr_ = 0; leadOutStart_ = 0; leadOutCtlAdr_ = 0; actCueSheetEntry_ = NULL; writeCatalog_ = 0; for (ent = cueSheet_, i = 0; i < cueSheetLen_; ent++, i++) { switch (ent->ctlAdr & 0x0f) { case 1: if (ent->min > 99 || ent->sec > 59 || ent->frame > 74) { log_message(-3, "Illegal time field value at cue sheet entry: %d", i); return 1; } if (ent->trackNr == 0) { // indicates lead-in if (i == 0 || (writeCatalog_ && i == 2)) { // must be first entry actCueSheetEntry_ = ent; } else { log_message(-3, "Illegal track number at cue sheet entry: %d", i); return 1; } } else if (ent->trackNr == 0xaa) { // indicates lead-out if (i == cueSheetLen_ - 1) { // must be last entry leadOutStart_ = Msf(ent->min, ent->sec, ent->frame); leadOutCtlAdr_ = ent->ctlAdr; } else { log_message(-3, "Illegal track number at cue sheet entry: %d", i); return 1; } } else if (ent->trackNr <= 99) { // data track if (firstTrackNr_ == 0) { firstTrackNr_ = ent->trackNr; firstTrackCtlAdr_ = ent->ctlAdr; prevTrackNr = ent->trackNr; } else { if (ent->trackNr != prevTrackNr && ent->trackNr != prevTrackNr + 1) { log_message(-3, "Wrong track number sequence at cue sheet entry: %d", i); return 1; } prevTrackNr = ent->trackNr; } lastTrackNr_ = ent->trackNr; lastTrackCtlAdr_ = ent->ctlAdr; } else { log_message(-3, "Illegal track number at cue sheet entry: %d", i); return 1; } if (ent->trackNr != 0) { lba = Msf(ent->min, ent->sec, ent->frame).lba(); if (lba <= prevLba) { log_message(-3, "Time field does not increase at cue sheet entry: %d", i); return 1; } prevLba = lba; } break; case 2: if (i != 0) { log_message(-3, "Catalog number must be first cue sheet entry."); return 1; } if ((cueSheet_[1].ctlAdr & 0x0f) != 2) { log_message(-3, "Missing second catalog number entry."); return 1; } writeCatalog_ = 1; catalog_->catalog(ent->trackNr, ent->indexNr, ent->dataForm, ent->scms, ent->min, ent->sec, ent->frame, cueSheet_[1].trackNr, cueSheet_[1].indexNr, cueSheet_[1].dataForm, cueSheet_[1].scms, cueSheet_[1].min, cueSheet_[1].sec); // skip next entry ent++; i++; break; case 3: if (((ent + 1)->ctlAdr & 0x0f) != 3) { log_message(-3, "Missing second ISRC code entry."); return 1; } // skip next entry ent++; i++; break; default: log_message(-3, "Illegal adr field at cue sheet entry: %d.", i); return 1; break; } } if (actCueSheetEntry_ == NULL) { log_message(-3, "Cue sheet contains no lead-in entry."); return 1; } if (leadOutStart_.lba() == 0) { log_message(-3, "Cue sheet contains no lead-out entry."); return 1; } if (firstTrackNr_ == 0) { log_message(-3, "Cue sheet contains no data track."); return 1; } return 0; } void PQChannelEncoder::encode(long lba, unsigned char *out, long blocks) { long clen = subChannel_->dataLength(); const SubChannel *chan; long i; for (i = 0; i < blocks; i++, lba++) { chan = encodeSubChannel(lba); memcpy(out, chan->data(), clen); out += clen; } } const SubChannel *PQChannelEncoder::encodeSubChannel(long lba) { int newTransition = 0; SubChannel *chan = NULL; // check consistency of internal lba with external lba assert(lba == abslba_); if (lba == nextTransitionLba_) { // switch to next transition //log_message(3, "Switching to next transition at lba: %ld", lba); nextTransition(); newTransition = 1; } if (actCueSheetEntry_->trackNr == 0) { // lead-in sector chan = toc_[actTocEnt_]; Msf m(trlba_); chan->min(m.min()); chan->sec(m.sec()); chan->frame(m.frac()); // advance to next to entry if (++actTocCount_ == 3) { actTocCount_ = 0; if (++actTocEnt_ == tocLen_) { actTocEnt_ = 0; } } } else { // data or lead-out sector // Q channel setup // catalog number if (writeCatalog_ && (deferredCatalog_ || (abslba_ % 90) == 0)) { if (newTransition) { deferredCatalog_ = 1; } else { deferredCatalog_ = 0; chan = catalog_; chan->aframe(Msf(abslba_ + 150).frac()); } } // ISRC code if (writeIsrc_ && (deferredIsrc_ || (abslba_ % 90) == 50 || (abslba_ % 90) == -40)) { if (newTransition) { deferredIsrc_ = 1; } else { deferredIsrc_ = 0; chan = isrc_; chan->aframe(Msf(abslba_ + 150).frac()); } } if (chan == NULL) { // Current position chan = current_; Msf m(trlba_ < 0 ? -trlba_ : trlba_); chan->min(m.min()); chan->sec(m.sec()); chan->frame(m.frac()); m = Msf(abslba_ + 150); chan->amin(m.min()); chan->asec(m.sec()); chan->aframe(m.frac()); } // P channel setup if (trlba_ <= 0 || (abslba_ >= nextTrackStartLba_ - 150 && abslba_ <= nextTrackStartLba_)) { // set P channel flag in pre-gap and 2 seconds before next track starts chan->pChannel(1); } else if (abslba_ >= leadOutStart_.lba() ) { // P channel flag is 0 2 secs from start of lead-out, after that // flag alternates at 2 Hz. chan->pChannel(((trlba_ - 150) % 38) < 19 ? 1 : 0); } else { chan->pChannel(0); } } abslba_++; trlba_++; assert(chan != NULL); chan->calcCrc(); return chan; } void PQChannelEncoder::nextTransition() { CueSheetEntry *nextEnt, *ent , *ent1; nextEnt = nextCueSheetEntry(actCueSheetEntry_, 1); assert(nextEnt != NULL); if (nextEnt->trackNr != actCueSheetEntry_->trackNr) { // new track started // check for ISRC code cue sheet entry if ((ent = nextCueSheetEntry(actCueSheetEntry_, 3)) != NULL && ent->trackNr == nextEnt->trackNr) { ent1 = ent + 1; isrc_->isrc(ent->indexNr, ent->dataForm, ent->scms, ent->min, ent->sec, ent->frame, ent1->indexNr, ent1->dataForm, ent1->scms, ent1->min, ent1->sec, ent1->frame); writeIsrc_ = 1; } else { writeIsrc_ = 0; } deferredIsrc_ = 0; // setup 'trlba' if (nextEnt->indexNr == 0) { // track has a pre-gap -> determine length ent = nextCueSheetEntry(nextEnt, nextEnt->trackNr, 1); assert(ent != NULL); trlba_ = Msf(nextEnt->min, nextEnt->sec, nextEnt->frame).lba() - Msf(ent->min, ent->sec, ent->frame).lba(); } else { trlba_ = 0; } } actCueSheetEntry_ = nextEnt; current_->ctl(actCueSheetEntry_->ctlAdr & 0xf0); current_->trackNr(actCueSheetEntry_->trackNr); current_->indexNr(actCueSheetEntry_->indexNr); if (writeCatalog_) catalog_->ctl(actCueSheetEntry_->ctlAdr & 0xf0); if (writeIsrc_) isrc_->ctl(actCueSheetEntry_->ctlAdr & 0xf0); if (actCueSheetEntry_->trackNr != 0xaa) { // find next transition point ent = nextCueSheetEntry(actCueSheetEntry_, 1); assert(ent != NULL); nextTransitionLba_ = Msf(ent->min, ent->sec, ent->frame).lba() - 150; if (actCueSheetEntry_->indexNr == 1) { // find next track start lba if (actCueSheetEntry_->trackNr == lastTrackNr_) ent = nextCueSheetEntry(actCueSheetEntry_, 0xaa, 1); else ent = nextCueSheetEntry(actCueSheetEntry_, actCueSheetEntry_->trackNr + 1, 1); assert(ent != NULL); nextTrackStartLba_ = Msf(ent->min, ent->sec, ent->frame).lba() - 150; } } } CueSheetEntry *PQChannelEncoder::nextCueSheetEntry(CueSheetEntry *act, int adr) { if (act->trackNr == 0xaa) { return NULL; } act++; while (act->ctlAdr != 0) { if ((act->ctlAdr & 0x0f) == adr) { return act; } act++; } return NULL; } CueSheetEntry *PQChannelEncoder::nextCueSheetEntry(CueSheetEntry *act, int trackNr, int indexNr) { if (act->trackNr == 0xaa) { return NULL; } act++; while (act->ctlAdr != 0) { if ((act->ctlAdr & 0x0f) == 1 && act->trackNr == trackNr && act->indexNr == indexNr) { return act; } act++; } return NULL; } �������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/PQChannelEncoder.h��������������������������������������������������������0000664�0000000�0000000�00000006133�15114537466�0020726�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <andreas@daneb.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 * (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. */ #ifndef __PQ_CHANNEL_ENCODER_H__ #define __PQ_CHANNEL_ENCODER_H__ #include "Msf.h" #include "SubChannel.h" struct CueSheetEntry { unsigned char ctlAdr; unsigned char trackNr; unsigned char indexNr; unsigned char dataForm; unsigned char scms; unsigned char min; unsigned char sec; unsigned char frame; }; class PQChannelEncoder { public: struct SessionInfo { // required for all sessions int sessionNr; long leadInStart; long leadInLen; long leadOutLen; // required for all sessions of a multi session disk Msf lastLeadoutStart; // required for 1st session of a multi session disk int cdrw; Msf atipLeadinStart; unsigned char optimumRecordingPower; // required for a CD-RW for 1st session of a multi session disk unsigned char atipA1[3]; }; PQChannelEncoder(); ~PQChannelEncoder(); // sets cue sheet and initializes the module, 'len' is length of cure // sheet in bytes int setCueSheet(SubChannel *, unsigned char discType, const unsigned char *, int len, const Msf &leadInStart); // encodes 'blocks' blocks of data in 'in' and places them appended by // PQ sub channel data in caller provided buffer 'out' void encode(long lba, unsigned char *out, long blocks); private: SubChannel *subChannel_; // template for all sub channel objects CueSheetEntry *cueSheet_; int cueSheetLen_; unsigned char discType_; int firstTrackNr_; int lastTrackNr_; Msf leadOutStart_; unsigned char firstTrackCtlAdr_; unsigned char lastTrackCtlAdr_; unsigned char leadOutCtlAdr_; CueSheetEntry *actCueSheetEntry_; long trlba_; // track relative lba long abslba_; // absolute lba on disc long nextTransitionLba_; long nextTrackStartLba_; SubChannel **toc_; int tocLen_; int actTocEnt_; // actual toc entry int actTocCount_; // counter for reapeating each toc entry three times SubChannel *catalog_; int writeCatalog_; int deferredCatalog_; SubChannel *isrc_; int writeIsrc_; int deferredIsrc_; SubChannel *current_; int analyzeCueSheet(); const SubChannel *encodeSubChannel(long lba); void nextTransition(); CueSheetEntry *nextCueSheetEntry(CueSheetEntry *act, int adr); CueSheetEntry *nextCueSheetEntry(CueSheetEntry *act, int trackNr, int indexNr); }; #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/PQSubChannel16.cc���������������������������������������������������������0000664�0000000�0000000�00000020115�15114537466�0020401�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #include "PQSubChannel16.h" #include <stdio.h> #include <string.h> #include <assert.h> #include "log.h" PQSubChannel16::PQSubChannel16() { memset(data_, 0, 16); type_ = QMODE1DATA; } PQSubChannel16::~PQSubChannel16() { } SubChannel *PQSubChannel16::makeSubChannel(Type t) { PQSubChannel16 *chan = new PQSubChannel16; chan->type_ = t; switch (t) { case QMODE1TOC: case QMODE1DATA: chan->data_[0] = 0x01; break; case QMODE2: chan->data_[0] = 0x02; break; case QMODE3: chan->data_[0] = 0x03; break; case QMODE5TOC: chan->data_[0] = 0x05; break; case QMODE_ILLEGAL: chan->data_[0] = 0x00; break; } return chan; } void PQSubChannel16::init(unsigned char *buf) { memcpy(data_, buf, 16); switch (data_[0] & 0x0f) { case 1: type_ = QMODE1DATA; break; case 2: type_ = QMODE2; break; case 3: type_ = QMODE3; break; case 5: type_ = QMODE5TOC; break; default: type_ = QMODE_ILLEGAL; break; } } SubChannel *PQSubChannel16::makeSubChannel(unsigned char *buf) { PQSubChannel16 *chan = new PQSubChannel16; chan->init(buf); return chan; } const unsigned char *PQSubChannel16::data() const { return data_; } long PQSubChannel16::dataLength() const { return 16; } // calculate the crc over Q sub channel bytes 0-9 and stores it in byte 10,11 void PQSubChannel16::calcCrc() { unsigned short crc = 0; int i; for (i = 0; i < 10; i++) { crc = crctab[(crc >> 8) ^ data_[i]] ^ (crc << 8); } data_[10] = crc >> 8; data_[11] = crc; } int PQSubChannel16::checkCrc() const { unsigned short crc = 0; int i; if (!crcValid_) { return 1; } for (i = 0; i < 10; i++) { crc = crctab[(crc >> 8) ^ data_[i]] ^ (crc << 8); } if (data_[10] == (crc >> 8) && data_[11] == (crc & 0xff)) return 1; else return 0; } // returns Q type SubChannel::Type PQSubChannel16::type() const { return type_; } // set Q type void PQSubChannel16::type(unsigned char type) { switch (type & 0x0f) { case 1: type_ = QMODE1DATA; break; case 2: type_ = QMODE2; break; case 3: type_ = QMODE3; break; case 5: type_ = QMODE5TOC; break; default: type_ = QMODE_ILLEGAL; break; } data_[0] &= 0xf0; data_[0] |= type & 0x0f; } // sets P channel bit void PQSubChannel16::pChannel(int f) { data_[15] = f != 0 ? 0x80 : 0; } // function for setting various Q sub channel fields void PQSubChannel16::ctl(int c) { assert((c & 0x0f) == 0); data_[0] &= 0x0f; data_[0] |= c & 0xf0; } unsigned char PQSubChannel16::ctl() const { return data_[0] >> 4; } void PQSubChannel16::trackNr(int t) { assert(type_ == QMODE1DATA); data_[1] = bcd(t); } int PQSubChannel16::trackNr() const { assert(type_ == QMODE1DATA); return bcd2int(data_[1]); } void PQSubChannel16::indexNr(int i) { assert(type_ == QMODE1DATA); data_[2] = bcd(i); } int PQSubChannel16::indexNr() const { assert(type_ == QMODE1DATA); return bcd2int(data_[2]); } void PQSubChannel16::point(int p) { assert(type_ == QMODE1TOC || type_ == QMODE5TOC); data_[2] = bcd(p); } void PQSubChannel16::min(int m) { assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC); data_[3] = bcd(m); } int PQSubChannel16::min() const { assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC); return bcd2int(data_[3]); } void PQSubChannel16::sec(int s) { assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC); data_[4] = bcd(s); } int PQSubChannel16::sec() const { assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC); return bcd2int(data_[4]); } void PQSubChannel16::frame(int f) { assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC); data_[5] = bcd(f); } int PQSubChannel16::frame() const { assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC); return bcd2int(data_[5]); } void PQSubChannel16::zero(int z) { assert(type_ == QMODE5TOC); data_[6] = bcd(z); } void PQSubChannel16::amin(int am) { assert(type_ == QMODE1DATA); data_[7] = bcd(am); } int PQSubChannel16::amin() const { assert(type_ == QMODE1DATA); return bcd2int(data_[7]); } void PQSubChannel16::asec(int as) { assert(type_ == QMODE1DATA); data_[8] = bcd(as); } int PQSubChannel16::asec() const { assert(type_ == QMODE1DATA); return bcd2int(data_[8]); } void PQSubChannel16::aframe(int af) { assert(type_ == QMODE1DATA || type_ == QMODE2 || type_ == QMODE3); data_[9] = bcd(af); } int PQSubChannel16::aframe() const { assert(type_ == QMODE1DATA || type_ == QMODE2 || type_ == QMODE3); return bcd2int(data_[9]); } void PQSubChannel16::pmin(int pm) { assert(type_ == QMODE1TOC || type_ == QMODE5TOC); data_[7] = bcd(pm); } void PQSubChannel16::psec(int ps) { assert(type_ == QMODE1TOC || type_ == QMODE5TOC); data_[8] = bcd(ps); } void PQSubChannel16::pframe(int pf) { assert(type_ == QMODE1TOC || type_ == QMODE5TOC); data_[9] = bcd(pf); } void PQSubChannel16::catalog(char n1, char n2, char n3, char n4, char n5, char n6, char n7, char n8, char n9, char n10, char n11, char n12, char n13) { assert(type_ == QMODE2); encodeCatalogNumber(data_ + 1, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13); data_[8] = 0; } const char *PQSubChannel16::catalog() const { static char buf[14]; assert(type_ == QMODE2); decodeCatalogNumber(data_ + 1, &buf[0], &buf[1], &buf[2], &buf[3], &buf[4], &buf[5], &buf[6], &buf[7], &buf[8], &buf[9], &buf[10], &buf[11], &buf[12]); buf[13] = 0; return buf; } void PQSubChannel16::isrc(char c1, char c2, char o1, char o2, char o3, char y1, char y2, char s1, char s2, char s3, char s4, char s5) { assert(type_ == QMODE3); encodeIsrcCode(data_ + 1, c1, c2, o1, o2, o3, y1, y2, s1, s2, s3, s4, s5); } const char *PQSubChannel16::isrc() const { static char buf[13]; assert(type_ == QMODE3); decodeIsrcCode(data_ + 1, &buf[0], &buf[1], &buf[2], &buf[3], &buf[4], &buf[5], &buf[6], &buf[7], &buf[8], &buf[9], &buf[10], &buf[11]); buf[12] = 0; return buf; } void PQSubChannel16::print() const { if (type_ != QMODE_ILLEGAL) log_message(0, "P:%02x ", data_[15]); switch (type_) { case QMODE1TOC: case QMODE1DATA: case QMODE5TOC: log_message(0, "Q: (%02x) %02x,%02x %02x:%02x:%02x %02x %02x:%02x:%02x ", data_[0], data_[1], data_[2], data_[3], data_[4], data_[5], data_[6], data_[7], data_[8], data_[9]); break; case QMODE2: log_message(0, "Q: (%02x) MCN: %s %02x ", data_[0], catalog(), data_[9]); break; case QMODE3: log_message(0, "Q: (%02x) ISRC: %s %02x ", data_[0], isrc(), data_[9]); break; case QMODE_ILLEGAL: log_message(0, "INVALID QMODE: %02x", data_[0]); break; } if (type_ != QMODE_ILLEGAL) log_message(0, "%04x %d", (data_[10] << 8) | data_[11], checkCrc()); } int PQSubChannel16::checkConsistency() { switch (type_) { case QMODE1DATA: if (!isBcd(data_[3]) || !isBcd(data_[4]) || !isBcd(data_[5]) || !isBcd(data_[7]) || !isBcd(data_[8]) || !isBcd(data_[9])) return 0; break; case QMODE1TOC: case QMODE2: case QMODE3: case QMODE5TOC: case QMODE_ILLEGAL: // no checks, yet break; } return SubChannel::checkConsistency(); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/PQSubChannel16.h����������������������������������������������������������0000664�0000000�0000000�00000007705�15114537466�0020255�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998 Andreas Mueller <mueller@daneb.ping.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 * (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. */ /* * $Log: PQSubChannel16.h,v $ * Revision 1.3 2002/06/29 17:23:09 andreasm * Some cosmetic fixes. * * Revision 1.2 2000/12/17 10:51:22 andreasm * Default verbose level is now 2. Adaopted message levels to have finer * grained control about the amount of messages printed by cdrdao. * Added CD-TEXT writing support to the GenericMMCraw driver. * Fixed CD-TEXT cue sheet creating for the GenericMMC driver. * * Revision 1.1.1.1 2000/02/05 01:35:04 llanero * Uploaded cdrdao 1.1.3 with pre10 patch applied. * * Revision 1.4 1999/04/05 11:04:48 mueller * Added decoding of media catalog number and ISRC code. * * Revision 1.3 1999/03/27 20:58:55 mueller * Added various access functions. * * Revision 1.2 1998/08/30 19:10:32 mueller * Added handling of Catalog Number and ISRC codes. * * Revision 1.1 1998/08/29 21:31:36 mueller * Initial revision * * */ #ifndef __PQ_SUB_CHANNEL_16_H__ #define __PQ_SUB_CHANNEL_16_H__ #include "SubChannel.h" class PQSubChannel16 : public SubChannel { public: PQSubChannel16(); virtual ~PQSubChannel16(); // virtual constructors: // create sub channel with specified q-mode SubChannel *makeSubChannel(Type); // create sub channel with reading sub channel data from given buffer SubChannel *makeSubChannel(unsigned char *); // initialize sub-channel from given buffer (16 bytes) void init(unsigned char *); void type(unsigned char); // set Q type Type type() const; // returns Q mode type long dataLength() const; // returns number of sub channel bytes void pChannel(int); // sets P channel bit void ctl(int); // sets control flags unsigned char ctl() const; // return control nibbles in bits 0-3 void trackNr(int); // sets track number (QMODE1DATA) int trackNr() const; // returns track number (QMODE1DATA) void indexNr(int); // sets index number (QMODE1DATA) int indexNr() const; // returns index number (QMODE1DATA) void point(int); // sets point filed (QMODE1TOC) void min(int); // track relative time (QMODE1TOC, QMODE1DATA) int min() const; void sec(int); // track relative time (QMODE1TOC, QMODE1DATA) int sec() const; void frame(int); // track relative time (QMODE1TOC, QMODE1DATA) int frame() const; void amin(int); // absolute time (QMODE1DATA) int amin() const; void asec(int); // absolute time (QMODE1DATA) int asec() const; void aframe(int); // absolute time (QMODE1DATA) int aframe() const; void pmin(int); // track start time (QMODE1TOC) void psec(int); // track start time (QMODE1TOC) void pframe(int); // track start time (QMODE1TOC) void zero(int); // zero field (QMODE5TOC) void catalog(char, char, char, char, char, char, char, char, char, char, char, char, char); const char *catalog() const; void isrc(char, char, char, char, char, char, char, char, char, char, char, char); const char *isrc() const; void print() const; void calcCrc(); // calculates crc and stores it in crc fields int checkCrc() const; int checkConsistency(); const unsigned char *data() const; protected: unsigned char data_[16]; // P and Q sub channel data }; #endif �����������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/PWSubChannel96.cc���������������������������������������������������������0000664�0000000�0000000�00000025627�15114537466�0020434�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #include "PWSubChannel96.h" #include <stdio.h> #include <string.h> #include <assert.h> #include "log.h" PWSubChannel96::PWSubChannel96() { memset(data_, 0, 96); type_ = QMODE1DATA; } PWSubChannel96::PWSubChannel96(unsigned char *buf) { init(buf); } void PWSubChannel96::init(unsigned char *buf) { memcpy(data_, buf, 96); switch (getChannelByte(Q_CHAN, 0) & 0x0f) { case 1: type_ = QMODE1DATA; break; case 2: type_ = QMODE2; break; case 3: type_ = QMODE3; break; case 5: type_ = QMODE5TOC; break; default: type_ = QMODE_ILLEGAL; break; } } PWSubChannel96::~PWSubChannel96() { } SubChannel *PWSubChannel96::makeSubChannel(Type t) { PWSubChannel96 *chan = new PWSubChannel96; chan->type_ = t; switch (t) { case QMODE1TOC: case QMODE1DATA: chan->setChannelByte(Q_CHAN, 0, 0x01); break; case QMODE2: chan->setChannelByte(Q_CHAN, 0, 0x02); break; case QMODE3: chan->setChannelByte(Q_CHAN, 0, 0x03); break; case QMODE5TOC: chan->setChannelByte(Q_CHAN, 0, 0x05); break; case QMODE_ILLEGAL: chan->setChannelByte(Q_CHAN, 0, 0x00); break; } return chan; } SubChannel *PWSubChannel96::makeSubChannel(unsigned char *buf) { PWSubChannel96 *chan = new PWSubChannel96(buf); return chan; } void PWSubChannel96::setChannelByte(Channel chan, int byteNr, unsigned char value) { assert(byteNr >= 0 && byteNr < 12); unsigned char setMask = 1 << chan; unsigned char clearMask = ~setMask; unsigned char *p = data_ + (byteNr * 8); int i; for (i = 0; i < 8; i++) { if (value & 0x80) *p |= setMask; else *p &= clearMask; p++; value <<= 1; } } unsigned char PWSubChannel96::getChannelByte(Channel chan, int byteNr) const { assert(byteNr >= 0 && byteNr < 12); unsigned char testMask = 1 << chan; const unsigned char *p = data_ + (byteNr * 8); unsigned char val = 0; int i; for (i = 0; i < 8; i++) { val <<= 1; if ((*p) & testMask) val |= 0x01; p++; } return val; } const unsigned char *PWSubChannel96::data() const { return data_; } long PWSubChannel96::dataLength() const { return 96; } // calculate the crc over Q sub channel bytes 0-9 and stores it in byte 10,11 void PWSubChannel96::calcCrc() { unsigned short crc = 0; int i; for (i = 0; i < 10; i++) { unsigned char data = getChannelByte(Q_CHAN, i); crc = crctab[(crc >> 8) ^ data] ^ (crc << 8); } crc = ~crc; setChannelByte(Q_CHAN, 10, crc >> 8); setChannelByte(Q_CHAN, 11, crc); } int PWSubChannel96::checkCrc() const { unsigned short crc = 0; int i; if (!crcValid_) { return 1; } for (i = 0; i < 10; i++) { unsigned char data = getChannelByte(Q_CHAN, i); crc = crctab[(crc >> 8) ^ data] ^ (crc << 8); } crc = ~crc; if (getChannelByte(Q_CHAN, 10) == (crc >> 8) && getChannelByte(Q_CHAN, 11) == (crc & 0xff)) return 1; else return 0; } // sets P channel bit void PWSubChannel96::pChannel(int f) { int i; if (f != 0) { for (i = 0; i < 96; i++) data_[i] |= 0x80; } else { for (i = 0; i < 96; i++) data_[i] &= 0x7f; } } // returns Q type SubChannel::Type PWSubChannel96::type() const { return type_; } // set Q type void PWSubChannel96::type(unsigned char type) { switch (type & 0x0f) { case 1: type_ = QMODE1DATA; break; case 2: type_ = QMODE2; break; case 3: type_ = QMODE3; break; case 5: type_ = QMODE5TOC; break; default: type_ = QMODE_ILLEGAL; break; } unsigned char val = getChannelByte(Q_CHAN, 0); val &= 0xf0; val |= type & 0x0f; setChannelByte(Q_CHAN, 0, val); } // function for setting various Q sub channel fields void PWSubChannel96::ctl(int c) { assert((c & 0x0f) == 0); unsigned char val = getChannelByte(Q_CHAN, 0); val &= 0x0f; val |= c & 0xf0; setChannelByte(Q_CHAN, 0, val); } unsigned char PWSubChannel96::ctl() const { unsigned char val = getChannelByte(Q_CHAN, 0); return val >> 4; } void PWSubChannel96::trackNr(int t) { assert(type_ == QMODE1DATA); setChannelByte(Q_CHAN, 1, bcd(t)); } int PWSubChannel96::trackNr() const { assert(type_ == QMODE1DATA); return bcd2int(getChannelByte(Q_CHAN, 1)); } void PWSubChannel96::indexNr(int i) { assert(type_ == QMODE1DATA); setChannelByte(Q_CHAN, 2, bcd(i)); } int PWSubChannel96::indexNr() const { assert(type_ == QMODE1DATA); return bcd2int(getChannelByte(Q_CHAN, 2)); } void PWSubChannel96::point(int p) { assert(type_ == QMODE1TOC || type_ == QMODE5TOC); setChannelByte(Q_CHAN, 2, bcd(p)); } void PWSubChannel96::min(int m) { assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC); setChannelByte(Q_CHAN, 3, bcd(m)); } int PWSubChannel96::min() const { assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC); return bcd2int(getChannelByte(Q_CHAN, 3)); } void PWSubChannel96::sec(int s) { assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC); setChannelByte(Q_CHAN, 4, bcd(s)); } int PWSubChannel96::sec() const { assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC); return bcd2int(getChannelByte(Q_CHAN, 4)); } void PWSubChannel96::frame(int f) { assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC); setChannelByte(Q_CHAN, 5, bcd(f)); } int PWSubChannel96::frame() const { assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC); return bcd2int(getChannelByte(Q_CHAN, 5)); } void PWSubChannel96::zero(int z) { assert(type_ == QMODE5TOC); setChannelByte(Q_CHAN, 6, bcd(z)); } void PWSubChannel96::amin(int am) { assert(type_ == QMODE1DATA); setChannelByte(Q_CHAN, 7, bcd(am)); } int PWSubChannel96::amin() const { assert(type_ == QMODE1DATA); return bcd2int(getChannelByte(Q_CHAN, 7)); } void PWSubChannel96::asec(int as) { assert(type_ == QMODE1DATA); setChannelByte(Q_CHAN, 8, bcd(as)); } int PWSubChannel96::asec() const { assert(type_ == QMODE1DATA); return bcd2int(getChannelByte(Q_CHAN, 8)); } void PWSubChannel96::aframe(int af) { assert(type_ == QMODE1DATA || type_ == QMODE2 || type_ == QMODE3); setChannelByte(Q_CHAN, 9, bcd(af)); } int PWSubChannel96::aframe() const { assert(type_ == QMODE1DATA || type_ == QMODE2 || type_ == QMODE3); return bcd2int(getChannelByte(Q_CHAN, 9)); } void PWSubChannel96::pmin(int pm) { assert(type_ == QMODE1TOC || type_ == QMODE5TOC); setChannelByte(Q_CHAN, 7, bcd(pm)); } void PWSubChannel96::psec(int ps) { assert(type_ == QMODE1TOC || type_ == QMODE5TOC); setChannelByte(Q_CHAN, 8, bcd(ps)); } void PWSubChannel96::pframe(int pf) { assert(type_ == QMODE1TOC || type_ == QMODE5TOC); setChannelByte(Q_CHAN, 9, bcd(pf)); } void PWSubChannel96::catalog(char n1, char n2, char n3, char n4, char n5, char n6, char n7, char n8, char n9, char n10, char n11, char n12, char n13) { assert(type_ == QMODE2); unsigned char buf[8]; int i; encodeCatalogNumber(buf, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13); buf[7] = 0; for (i = 0; i < 8; i++) setChannelByte(Q_CHAN, i + 1, buf[i]); } const char *PWSubChannel96::catalog() const { static char buf[14]; unsigned char in[7]; int i; for (i = 0; i < 7; i++) in[i] = getChannelByte(Q_CHAN, i + 1); decodeCatalogNumber(in, &buf[0], &buf[1], &buf[2], &buf[3], &buf[4], &buf[5], &buf[6], &buf[7], &buf[8], &buf[9], &buf[10], &buf[11], &buf[12]); buf[13] = 0; return buf; } void PWSubChannel96::isrc(char c1, char c2, char o1, char o2, char o3, char y1, char y2, char s1, char s2, char s3, char s4, char s5) { assert(type_ == QMODE3); unsigned char buf[8]; int i; encodeIsrcCode(buf, c1, c2, o1, o2, o3, y1, y2, s1, s2, s3, s4, s5); for (i = 0; i < 8; i++) setChannelByte(Q_CHAN, i + 1, buf[i]); } const char *PWSubChannel96::isrc() const { static char buf[13]; unsigned char in[8]; int i; assert(type_ == QMODE3); for (i = 0; i < 8; i++) in[i] = getChannelByte(Q_CHAN, i + 1); decodeIsrcCode(in, &buf[0], &buf[1], &buf[2], &buf[3], &buf[4], &buf[5], &buf[6], &buf[7], &buf[8], &buf[9], &buf[10], &buf[11]); buf[12] = 0; return buf; } void PWSubChannel96::print() const { if (type_ != QMODE_ILLEGAL) log_message(0, "P:%02x ", getChannelByte(P_CHAN, 0)); switch (type_) { case QMODE1TOC: case QMODE1DATA: case QMODE5TOC: log_message(0, "Q: (%02x) %02x,%02x %02x:%02x:%02x %02x %02x:%02x:%02x ", getChannelByte(Q_CHAN, 0), getChannelByte(Q_CHAN, 1), getChannelByte(Q_CHAN, 2), getChannelByte(Q_CHAN, 3), getChannelByte(Q_CHAN, 4), getChannelByte(Q_CHAN, 5), getChannelByte(Q_CHAN, 6), getChannelByte(Q_CHAN, 7), getChannelByte(Q_CHAN, 8), getChannelByte(Q_CHAN, 9)); break; case QMODE2: log_message(0, "Q: (%02x) MCN: %s %02x ", getChannelByte(Q_CHAN, 0), catalog(), getChannelByte(Q_CHAN, 9)); break; case QMODE3: log_message(0, "Q: (%02x) ISRC: %s %02x ", getChannelByte(Q_CHAN, 0), isrc(), getChannelByte(Q_CHAN, 9)); break; case QMODE_ILLEGAL: log_message(0, "INVALID QMODE: %02x", getChannelByte(Q_CHAN, 0)); break; } if (type_ != QMODE_ILLEGAL) log_message(0, "%04x %d", (getChannelByte(Q_CHAN, 10) << 8) | getChannelByte(Q_CHAN, 11), checkCrc()); } // sets R-W channel bits from 72 byte data buffer, used for CD-TEXT void PWSubChannel96::setRawRWdata(const unsigned char *data) { int i; for (i = 0; i < 96; i += 4) { data_[i] |= (data[0] >> 2) & 0x3f; data_[i + 1] |= ((data[0] << 4) & 0x30) | ((data[1] >> 4) & 0x0f); data_[i + 2] |= ((data[1] << 2) & 0x3c) | ((data[2] >> 6) & 0x03); data_[i + 3] |= data[2] & 0x3f; data += 3; } } // concatenates the R-W channel bits and writes them to provided 72 byte buffer void PWSubChannel96::getRawRWdata(unsigned char *data) const { int i; for (i = 0; i < 96; i += 4) { data[0] = ((data_[i] << 2) & 0xfc) | ((data_[i + 1] >> 4) & 0x03); data[1] = ((data_[i + 1] << 4) & 0xf0) | ((data_[i + 2] >> 2) & 0x0f); data[2] = ((data_[i + 2] << 6) & 0xc0) | (data_[i + 3] & 0x3f); data += 3; } } ���������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/PWSubChannel96.h����������������������������������������������������������0000664�0000000�0000000�00000010540�15114537466�0020262�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998 Andreas Mueller <mueller@daneb.ping.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 * (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. */ /* * $Log: PWSubChannel96.h,v $ * Revision 1.2 2000/12/17 10:51:22 andreasm * Default verbose level is now 2. Adaopted message levels to have finer * grained control about the amount of messages printed by cdrdao. * Added CD-TEXT writing support to the GenericMMCraw driver. * Fixed CD-TEXT cue sheet creating for the GenericMMC driver. * * Revision 1.1.1.1 2000/02/05 01:35:05 llanero * Uploaded cdrdao 1.1.3 with pre10 patch applied. * * Revision 1.5 1999/04/05 11:04:48 mueller * Added decoding of media catalog number and ISRC code. * * Revision 1.4 1999/03/27 20:58:55 mueller * Added various access functions. * * Revision 1.3 1998/09/27 19:19:39 mueller * Added retrieval of control nibbles for track with 'analyzeTrack()'. * * Revision 1.2 1998/08/30 19:10:32 mueller * Added handling of Catalog Number and ISRC codes. * * Revision 1.1 1998/08/29 21:32:27 mueller * Initial revision * * */ #ifndef __PW_SUB_CHANNEL_96_H__ #define __PW_SUB_CHANNEL_96_H__ #include "SubChannel.h" class PWSubChannel96 : public SubChannel { public: enum Channel { P_CHAN = 7, Q_CHAN = 6 }; PWSubChannel96(); PWSubChannel96(unsigned char *buf); ~PWSubChannel96(); // virtual constructors: // create sub channel with specified q-mode SubChannel *makeSubChannel(Type); // create sub channel with reading sub channel data from given buffer SubChannel *makeSubChannel(unsigned char *); // initialize sub-channel from given buffer (96 bytes) void init(unsigned char *); void type(unsigned char); // set Q type Type type() const; // returns Q mode type long dataLength() const; // returns number of sub channel bytes void pChannel(int); // sets P channel bit void ctl(int); // sets control flags unsigned char ctl() const; // return control nibbles in bits 0-3 void trackNr(int); // sets track number (QMODE1DATA) int trackNr() const; // returns track number (QMODE1DATA) void indexNr(int); // sets index number (QMODE1DATA) int indexNr() const; // returns index number (QMODE1DATA) void point(int); // sets point filed (QMODE1TOC) void min(int); // track relative time (QMODE1TOC, QMODE1DATA) int min() const; void sec(int); // track relative time (QMODE1TOC, QMODE1DATA) int sec() const; void frame(int); // track relative time (QMODE1TOC, QMODE1DATA) int frame() const; void amin(int); // absolute time (QMODE1DATA) int amin() const; void asec(int); // absolute time (QMODE1DATA) int asec() const; void aframe(int); // absolute time (QMODE1DATA) int aframe() const; void pmin(int); // track start time (QMODE1TOC) void psec(int); // track start time (QMODE1TOC) void pframe(int); // track start time (QMODE1TOC) void zero(int); // zero field (QMODE5TOC) // sets raw R-W channels from 72 byte buffer void setRawRWdata(const unsigned char *); // gets raw R-W channels to 72 byte buffer void getRawRWdata(unsigned char *) const; void print() const; void calcCrc(); // calculates crc and stores it in crc fields int checkCrc() const; void catalog(char, char, char, char, char, char, char, char, char, char, char, char, char); const char *catalog() const; void isrc(char, char, char, char, char, char, char, char, char, char, char, char); const char *isrc() const; const unsigned char *data() const; protected: unsigned char data_[96]; // P - W sub channel data private: void setChannelByte(Channel, int byteNr, unsigned char value); unsigned char getChannelByte(Channel, int byteNr) const; }; #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/PlextorReader.cc����������������������������������������������������������0000664�0000000�0000000�00000077252�15114537466�0020545�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #include <config.h> #include <unistd.h> #include <string.h> #include <assert.h> #include <errno.h> #include "PlextorReader.h" #include "Toc.h" #include "util.h" #include "log.h" #include "PWSubChannel96.h" PlextorReader::PlextorReader(ScsiIf *scsiIf, unsigned long options) : CdrDriver(scsiIf, options) { driverName_ = "Plextor CD-ROM Reader - Version 1.3"; speed_ = 0; simulate_ = false; audioDataByteOrder_ = 0; slow_down_on_read_errors = -1; transfer_data_before_max_speed = -1; slow_down_on_vibrations = -1; memset(&diskInfo_, 0, sizeof(DiskInfo)); diskInfo_.valid.empty = 1; { struct { int number; const char *productid; // as obtained through INQUIRY } models[] = { { 1,"CD-ROM PX-4XCH" }, { 2,"CD-ROM PX-4XCS" }, { 3,"CD-ROM PX-4XCE" }, { 4,"CD-ROM PX-6X" }, { 5,"CD-ROM PX-8X" }, { 6,"CD-ROM PX-12" }, { 7,"CD-ROM PX-20" }, { 8,"CD-ROM PX-32" }, { 9,"CD-ROM PX-40" }, { 0,NULL } }; int m = 0; while (models[m].number) { if (strncmp(scsiIf_->product(), models[m].productid, strlen(models[m].productid)) == 0) break; else m++; } model_ = models[m].number; // zero if not found if (model_ > 0) { /* Plextor special features initialization */ unsigned char buf[32]; unsigned char header[8]; unsigned char blockdesc[8]; struct plex_msg { int value; const char *msg; }; struct plex_msg slowdown_msg[] = { { -1, "Unsupported"}, { 0, "Enabled, unit will slow down"}, { 1, "Disabled, unit won't slow down"} }; struct plex_msg trbefmax_msg[] = { { -1, "Unsupported"}, { 0, "Disabled, unit will wait for max speed"}, { 1, "Enabled, unit will transfer as soon as possible"} }; /* Read error slowdown seems available for all drives, while vibration and transfer control only for PX-20 and later Data is taken from Mode page 0x31 byte 3 [ x x x x x sl td re ] re=read errors , if 0 slow down on read errors, 0 default td=transfer data, if 0 wait for max speed before transfer data, 0 default sl=if 0 slowdown to avoid vibrations, 0 default */ slow_down_on_read_errors = -1; transfer_data_before_max_speed = -1; slow_down_on_vibrations = -1; orig_byte3 = 0; if (getModePage6 (0x31, buf, 32, header, blockdesc, 1) == 0) { orig_byte3 = buf[3]; slow_down_on_read_errors = buf[3] & 0x01; if (model_ >= 7) { transfer_data_before_max_speed = (buf[3] & 0x02) >> 1; slow_down_on_vibrations = (buf[3] & 0x04) >> 2; } } if (options & OPT_PLEX_NOSLOW_ON_ERR) ReadErrorsSlowDown (0); if (options & OPT_PLEX_TRANSF_BEF_MAX) WaitMaxSpeed (0); if (options & OPT_PLEX_NOSLOW_ON_VIB) VibrationsSlowDown (0); log_message(4, "Plextor features status:"); log_message(4, " Slowdown on read errors: %s", slowdown_msg[slow_down_on_read_errors+1].msg); log_message(4, " Slowdown to avoid vibrations: %s", slowdown_msg[slow_down_on_vibrations+1].msg); log_message(4, " Transfer data before max speed: %s", trbefmax_msg[transfer_data_before_max_speed+1].msg); } log_message(4, "model number %d\n",model_); log_message(4, "PRODUCT ID: '%s'\n", scsiIf_->product()); } } PlextorReader::~PlextorReader () { /* Only for Plextor units */ if (model_ > 0) { unsigned char buf[32]; unsigned char header[8]; unsigned char blockdesc[8]; if (getModePage6 (0x31, buf, 32, header, blockdesc, 1) != 0) return; buf[3] = orig_byte3; setModePage6 (buf, header, blockdesc, 1); } } int PlextorReader::ReadErrorsSlowDown (int slowdown) { /* Not supported */ if (slow_down_on_read_errors == -1 ) return -1; slowdown ? slowdown = 0 : slowdown = 1; unsigned char buf[32]; unsigned char header[8]; unsigned char blockdesc[8]; if (getModePage6 (0x31, buf, 32, header, blockdesc, 1) != 0) return -1; if (slowdown) buf[3] |= 0x01; if (setModePage6 (buf, header, blockdesc, 1) != 0) return -1; slow_down_on_read_errors = slowdown; return 1; } int PlextorReader::VibrationsSlowDown (int slowdown) { if (slow_down_on_vibrations == -1) return -1; slowdown ? slowdown = 0 : slowdown = 1; unsigned char buf[32]; unsigned char header[8]; unsigned char blockdesc[8]; if (getModePage6 (0x31, buf, 32, header, blockdesc, 1) != 0) return -1; if (slowdown) buf[3] |= 0x04; if (setModePage6 (buf, header, blockdesc, 1) != 0) return -1; slow_down_on_vibrations = slowdown; return 1; } int PlextorReader::WaitMaxSpeed (int wait) { if (transfer_data_before_max_speed == -1) return -1; wait ? wait = 0 : wait = 1; unsigned char buf[32]; unsigned char header[8]; unsigned char blockdesc[8]; if (getModePage6 (0x31, buf, 32, header, blockdesc, 1) != 0) return -1; if (wait) buf[3] |= 0x02; if (setModePage6 (buf, header, blockdesc, 1) != 0) return -1; transfer_data_before_max_speed = wait; return 1; } // static constructor CdrDriver *PlextorReader::instance(ScsiIf *scsiIf, unsigned long options) { return new PlextorReader(scsiIf, options); } // sets speed // return: 0: OK // 1: illegal speed (n/a; the strategy is to map to a valid speed) int PlextorReader::speed(int speed) { unsigned short dataLen = 56; unsigned char data[56]; char speedvalue=0; if (model_ == 0) // not a Plextor device return 0; switch (model_) { case 4: speedvalue = (speed-1)/2; break; default: speedvalue = speed/2; break; } getModePage6((long)0x31,data,dataLen,NULL,NULL,1); //log_message(0,"page code %0x\n",data[0]); //log_message(0,"speed value was %d\n",data[2]); data[2]=speedvalue; //log_message(0,"new speedvalue %d\n",speedvalue); setModePage6(data,NULL,NULL,1); return 0; } DiskInfo *PlextorReader::diskInfo() { return &diskInfo_; } int PlextorReader::initDao(const Toc *toc) { log_message(-2, "Writing is not supported by this driver."); return 1; } int PlextorReader::startDao() { return 1; } int PlextorReader::finishDao() { return 1; } void PlextorReader::abortDao() { } // tries to read catalog number from disk and adds it to 'toc' // return: 1 if valid catalog number was found, else 0 int PlextorReader::readCatalog(Toc *toc, long startLba, long endLba) { unsigned char cmd[10]; unsigned short dataLen = 0x30; unsigned char data[0x30]; char catalog[14]; int i; // read sub channel information memset(cmd, 0, 10); cmd[0] = 0x42; // READ SUB CHANNEL cmd[2] = 0x40; // get sub channel data cmd[3] = 0x02; // get media catalog number cmd[7] = dataLen >> 8; cmd[8] = dataLen; if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) { log_message(-2, "Cannot read sub channel data."); return 0; } if (data[0x08] & 0x80) { for (i = 0; i < 13; i++) { catalog[i] = data[0x09 + i]; } catalog[13] = 0; if (toc->catalog(catalog) == 0) { return 1; } } return 0; } // plays one audio block starting from given position void PlextorReader::playAudioBlock(long start, long len) { unsigned char cmd[10]; // play one audio block memset(cmd, 0, 10); cmd[0] = 0x45; // PLAY AUDIO cmd[2] = start >> 24; cmd[3] = start >> 16; cmd[4] = start >> 8; cmd[5] = start; cmd[7] = len >> 8; cmd[8] = len; if (sendCmd(cmd, 10, NULL, 0, NULL, 0) != 0) { log_message(-2, "Cannot play audio block."); return; } } int PlextorReader::analyzeTrack(TrackData::Mode mode, int trackNr, long startLba, long endLba, Msf *index, int *indexCnt, long *pregap, char *isrcCode, unsigned char *ctl) { int ret = analyzeTrackSearch(mode, trackNr, startLba, endLba, index, indexCnt, pregap, isrcCode, ctl); if (mode == TrackData::AUDIO) readIsrc(trackNr, isrcCode); else *isrcCode = 0; return ret; } // tries to read ISRC code of given track number and stores it in // given buffer. // return: 1 if valid ISRC code was found, else 0 int PlextorReader::readIsrc(int trackNr, char *buf) { unsigned char cmd[10]; unsigned short dataLen = 0x30; unsigned char data[0x30]; int i; // time to finish the last audio play operation sleep(1); buf[0] = 0; // read sub channel information memset(cmd, 0, 10); cmd[0] = 0x42; // READ SUB CHANNEL cmd[2] = 0x40; // get sub channel data cmd[3] = 0x03; // get ISRC code cmd[6] = trackNr; cmd[7] = dataLen >> 8; cmd[8] = dataLen; if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) { log_message(-1, "Cannot read ISRC code."); return 0; } if (data[0x08] & 0x80) { for (i = 0; i < 12; i++) { buf[i] = data[0x09 + i]; } buf[12] = 0; } return 0; } // Reads actual track number, index and relative position from sub channel. // return: 0 OK, 1: SCSI command failed int PlextorReader::readSubChannelData(int *trackNr, int *indexNr, long *relPos, unsigned char *ctl) { unsigned char cmd[10]; unsigned short dataLen = 0x30; unsigned char data[0x30]; // read sub channel information memset(cmd, 0, 10); cmd[0] = 0x42; // READ SUB CHANNEL cmd[2] = 0x40; // get sub channel data cmd[3] = 0x01; // get sub Q channel data cmd[6] = 0; cmd[7] = dataLen >> 8; cmd[8] = dataLen; if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) { log_message(-2, "Cannot read sub Q channel data."); } *trackNr = data[6]; *indexNr = data[7]; *relPos = 0; *relPos |= data[0x0c] << 24; *relPos |= data[0x0d] << 16; *relPos |= data[0x0e] << 8; *relPos |= data[0x0f]; if (ctl != NULL) { *ctl = data[5] & 0x0f; } return 0; } // Retrieves track and index at given block address 'lba'. // Return: 0: OK, 1: SCSI command failed int PlextorReader::getTrackIndex(long lba, int *trackNr, int *indexNr, unsigned char *ctl) { long relPos; playAudioBlock(lba, 1); return readSubChannelData(trackNr, indexNr, &relPos, ctl); } CdRawToc *PlextorReader::getRawToc(int sessionNr, int *len) { unsigned char cmd[10]; unsigned short dataLen; unsigned char *data = NULL;; unsigned char reqData[4]; // buffer for requestion the actual length unsigned char *p = NULL; int i, entries; CdRawToc *rawToc; assert(sessionNr >= 1); // read disk toc length memset(cmd, 0, 10); cmd[0] = 0x43; // READ TOC cmd[6] = sessionNr; cmd[8] = 4; cmd[9] |= 2 << 6; // get Q subcodes if (sendCmd(cmd, 10, NULL, 0, reqData, 4) != 0) { log_message(-2, "Cannot read raw disk toc."); return NULL; } dataLen = ((reqData[0] << 8) | reqData[1]) + 2; log_message(4, "Raw toc data len: %d", dataLen); data = new unsigned char[dataLen]; // read disk toc cmd[7] = dataLen >> 8; cmd[8] = dataLen; if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) { log_message(-2, "Cannot read raw disk toc."); delete[] data; return NULL; } entries = (((data[0] << 8) | data[1]) - 2) / 11; rawToc = new CdRawToc[entries]; for (i = 0, p = data + 4; i < entries; i++, p += 11 ) { #if 0 log_message(0, "%d %02x %02d %2x %02x:%02x:%02x %02x %02x:%02x:%02x", p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10]); #endif rawToc[i].sessionNr = p[0]; rawToc[i].adrCtl = p[1]; rawToc[i].point = p[3]; rawToc[i].pmin = p[8]; rawToc[i].psec = p[9]; rawToc[i].pframe = p[10]; } delete[] data; *len = entries; return rawToc; } long PlextorReader::readTrackData(TrackData::Mode mode, TrackData::SubChannelMode, long lba, long len, unsigned char *buf) { unsigned char cmd[10]; long blockLen = 2340; long i; TrackData::Mode actMode; int ok = 0; const unsigned char *sense; int senseLen; int softError; if (setBlockSize(blockLen) != 0) return 0; memset(cmd, 0, 10); cmd[0] = 0x28; // READ10 cmd[2] = lba >> 24; cmd[3] = lba >> 16; cmd[4] = lba >> 8; cmd[5] = lba; while (len > 0 && !ok) { cmd[7] = len >> 8; cmd[8] = len; memset(transferBuffer_, 0, len * blockLen); switch (sendCmd(cmd, 10, NULL, 0, transferBuffer_, len * blockLen, 0)) { case 0: ok = 1; break; case 2: softError = 0; sense = scsiIf_->getSense(senseLen); if (senseLen > 0x0c) { if ((sense[2] &0x0f) == 5) { // Illegal request switch (sense[12]) { case 0x63: // End of user area encountered on this track case 0x64: // Illegal mode for this track softError = 1; break; } } else if ((sense[2] & 0x0f) == 3) { // Medium error switch (sense[12]) { case 0x02: // No seek complete, sector not found case 0x11: // L-EC error return -2; break; } } } if (!softError) { scsiIf_->printError(); return -1; } break; default: log_message(-2, "Read error at LBA %ld, len %ld", lba, len); return -1; break; } if (!ok) { len--; } } unsigned char *sector = transferBuffer_; for (i = 0; i < len; i++) { actMode = determineSectorMode(sector); if (!(actMode == mode || (mode == TrackData::MODE2_FORM_MIX && (actMode == TrackData::MODE2_FORM1 || actMode == TrackData::MODE2_FORM2)) || (mode == TrackData::MODE1_RAW && actMode == TrackData::MODE1) || (mode == TrackData::MODE2_RAW && (actMode == TrackData::MODE2 || actMode == TrackData::MODE2_FORM1 || actMode == TrackData::MODE2_FORM2)))) { log_message(4, "Stopped because sector with not matching mode %s found.", TrackData::mode2String(actMode)); log_message(4, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", sector[0], sector[1], sector[2], sector[3], sector[4], sector[5], sector[6], sector[7], sector[8], sector[9], sector[10], sector[11]); return i; } if (buf != NULL) { switch (mode) { case TrackData::MODE1: memcpy(buf, sector + 4, MODE1_BLOCK_LEN); buf += MODE1_BLOCK_LEN; break; case TrackData::MODE2: case TrackData::MODE2_FORM_MIX: memcpy(buf, sector + 4, MODE2_BLOCK_LEN); buf += MODE2_BLOCK_LEN; break; case TrackData::MODE2_FORM1: memcpy(buf, sector + 12, MODE2_FORM1_DATA_LEN); buf += MODE2_FORM1_DATA_LEN; break; case TrackData::MODE2_FORM2: memcpy(buf, sector + 12, MODE2_FORM2_DATA_LEN); buf += MODE2_FORM2_DATA_LEN; break; case TrackData::MODE1_RAW: case TrackData::MODE2_RAW: memcpy(buf, syncPattern, 12); memcpy(buf + 12, sector, 2340); buf += AUDIO_BLOCK_LEN; break; case TrackData::MODE0: case TrackData::AUDIO: log_message(-3, "PlextorReader::readTrackData: Illegal mode."); return 0; break; } } sector += blockLen; } return len; } Toc *PlextorReader::readDiskToc(int session, const char *audioFilename) { Toc *toc = CdrDriver::readDiskToc(session, audioFilename); setBlockSize(MODE1_BLOCK_LEN); return toc; } Toc *PlextorReader::readDisk(int session, const char *dataFilename) { Toc *toc = CdrDriver::readDisk(session, dataFilename); setBlockSize(MODE1_BLOCK_LEN); return toc; } // Creates 'Toc' object for inserted CD. // audioFilename: name of audio file that is placed into TOC // Return: newly allocated 'Toc' object or 'NULL' on error int PlextorReader::readAudioRangePlextor(ReadDiskInfo *rinfo, int fd, long startLba, long endLba, int startTrack, int endTrack, TrackInfo *info) { int i; int ret; //unsigned char trackCtl; // control nibbles of track //int ctlCheckOk; int blockLength = AUDIO_BLOCK_LEN + 1 + 294 + 96; long blocksPerRead = scsiIf_->maxDataLen() / blockLength; long stampLba; // first, last, current and number of recorded tracks int fat=-1,lat=-1,cat,nat=0; // first, last, number, current, remaining and read (audio blocks) long fab,lab,nab,cab,rab,n; // SCSI command unsigned char cmd[12]; unsigned char *data; // number of byte errors in current audio block (cab) int cabFaulty; // number of retries and goods of current audio block (cab) unsigned long cabRetries=0,cabGoods=0,scsiRetries=0; // audio repair block unsigned char repairBlock[AUDIO_BLOCK_LEN + 1 + 294 + 96]; //unsigned char referBlock[AUDIO_BLOCK_LEN + 1 + 294 + 96]; int repairErrors=-1; int overspeed,cai=-1; data = new unsigned char[blocksPerRead * blockLength]; fat = startTrack; lat = endTrack; nat = endTrack - startTrack + 1; info[lat].bytesWritten = 0; // set first, last and number of audio blocks fab = startLba; lab = endLba; nab=lab-fab; log_message(1, "Reading CDDA tracks in range [%lu,%lu].", fat+1,lat+1); cat = fat + 1; log_message(2, "Reading CDDA blocks in range [%lu,%lu>" " (%lu blocks=%lu bytes).",fab,lab,nab,nab*2352); memset(cmd,0,12); cmd[0]=0xd8; cmd[10]=0x09; #if 0 // for testing purposes I set the position/length of a scratch here fab+=3000; nab=921; #endif // set current audio block cab=fab; // set remaining audio blocks rab=nab; stampLba = cab; // start optimistic speed(overspeed=20); // while still audio blocks left to read while (rab != 0) { // the maximum number of blocks to read, or just those which are left n=(rab > blocksPerRead ? blocksPerRead : rab); // set starting audio block cmd[2] = cab >> 24; cmd[3] = cab >> 16; cmd[4] = cab >> 8; cmd[5] = cab; // set number of blocks cmd[6] = n >> 24; cmd[7] = n >> 16; cmd[8] = n >> 8; cmd[9] = n; log_message(1, "block %6ld\r",cab); if (remote_) { if (cab > stampLba + 75) { long totalLen = info[cat + 1].start - info[cat].start; long progress = cab - info[cat].start; long totalProgress; if (progress > 0) { progress *= 1000; progress /= totalLen; } else { progress = 0; } totalProgress = cab - rinfo->startLba; if (totalProgress > 0) { totalProgress *= 1000; totalProgress /= rinfo->endLba - rinfo->startLba; } else { totalProgress = 0; } sendReadCdProgressMsg(RCD_EXTRACTING, rinfo->tracks, cat + 1, progress, totalProgress); stampLba = cab; } } // SCSI command failed? while (sendCmd(cmd,12,NULL,0,data,n*blockLength)) { scsiRetries++; if (cabRetries==0) { if (scsiRetries==10) { delete[] data; return 1; } } else { scsiRetries=0; //cabRetries++; break; } } // iterate through the read audio blocks for (i=0;i<n;i++) { // create subchannel object PWSubChannel96 chan(data + i*blockLength + AUDIO_BLOCK_LEN + 1 + 294); // q subchannel error? if (!chan.checkCrc()) { // TODO: Implement heuristic subchannel error correction here } // q subchannel ok? if (chan.checkCrc() && chan.checkConsistency()) { // q subchannel contains mode 1 data? if(chan.type() == SubChannel::QMODE1DATA) { // track relative time as it occurs in subchannel Msf qRelTime(chan.min(),chan.sec(),chan.frame()); // disc absolute time as it occurs in subchannel Msf qAbsTime(chan.amin(),chan.asec(),chan.aframe()); if ((chan.indexNr()!=cai) || (chan.trackNr()!=cat)) { log_message(2, "(track,index,absolute)=(%2d,%2d,%s)", chan.trackNr(),chan.indexNr(),qAbsTime.str()); // first track start? if ((chan.trackNr()==1) && (chan.indexNr()==1)) { log_message(1, "Found track number %02d at %s (block %d).", chan.trackNr(),qAbsTime.str(),cab); if ((qAbsTime.lba()-150)!=info[0].start) { log_message(2, "TOC SAYS TRACK STARTS AT %s!", Msf(info[0].start).str()); } } // next track start? else if ((chan.trackNr()==(cat+1)) && (chan.indexNr()==1)) { log_message(1, "Found track number %02d at %s.", chan.trackNr(),qAbsTime.str()); if ((qAbsTime.lba()-150)!=info[cat].start) { log_message(2, "TOC SAYS TRACK STARTS AT %s!", Msf(info[cat].start).str()); } } // pregap of next track? else if ((chan.trackNr()==(cat+1)) && (chan.indexNr()==0)) { log_message(2, "Found pregap of track %02d with size %s at ", chan.trackNr(), qRelTime.str()); log_message(2, "%s", qAbsTime.str()); if (cat <= lat) { info[cat].pregap = qRelTime.lba(); } } // index increment? else if ((chan.trackNr()==cat) && (chan.indexNr()==(cai+1))) { if (chan.indexNr() > 1) { log_message(2, "Found index number %02d at %s.", chan.indexNr(),qAbsTime.str()); int indexCnt = info[cat - 1].indexCnt; if (cat - 1 <= lat && indexCnt < 98) { info[cat - 1].index[indexCnt] = qRelTime.lba(); info[cat - 1].indexCnt += 1; } } } else if (chan.trackNr()==0xAA) { log_message(2, "LEAD OUT TRACK ENCOUNTERED!"); n=0; i=0; rab=0; cab-=1; lab=cab; break; } else if ((chan.trackNr()==cat) && (chan.indexNr()==cai)) { } else { log_message(1, "UNEXPECTED!"); } cat=chan.trackNr(); cai=chan.indexNr(); } } else if (chan.type() == SubChannel::QMODE3) { // subchannel contains ISRC code if (info[cat - 1].isrcCode[0] == 0) { memcpy(info[cat - 1].isrcCode, chan.isrc(), 13); log_message(2, "Found ISRC code of track %02d.", cat); } } } // erronous subchannel data else { } // read CIRC error indicator cabFaulty=data[i*blockLength+AUDIO_BLOCK_LEN]; // only errorless blocks or often retried blocks are accepted if ((cabFaulty==0) || (repairErrors==0) || (cabRetries>80)) { unsigned char *block; // the current audio block in the data buffer is perfect if (cabFaulty==0) { block=data + i*blockLength; // write this block's audio data //fwrite(data + i*blockLength,1,AUDIO_BLOCK_LEN,fd); // increment number of consecutive good blocks cabGoods++; if (cabRetries) { log_message(1,"block %6ld read and written without errors now. \n", cab); } } // we have a fully repaired block else if (repairErrors==0) { // write this block's audio data block=repairBlock; //fwrite(repairBlock,1,AUDIO_BLOCK_LEN,fd); log_message(1,"block %6ld written after fully being repaired...", cab); } // we have a partially repaired block else if (cabRetries>=0) { // write this block's audio data block=repairBlock; //fwrite(repairBlock,1,AUDIO_BLOCK_LEN,fd); log_message(1,"block %6ld written with %4ld erroneous bytes in it!", cab, repairErrors); } else { log_message(1,"PROGRAM BUG!!!! BUG #1! ENTERED ILLEGAL STATE\n"); } #if 1 // not if we test please if (options_ & OPT_DRV_SWAP_READ_SAMPLES) swapSamples((Sample*)block, SAMPLES_PER_BLOCK); if ((ret = fullWrite(fd, block, AUDIO_BLOCK_LEN)) != AUDIO_BLOCK_LEN) { if (ret < 0) log_message(-2, "Writing of data failed: %s", strerror(errno)); else log_message(-2, "Writing of data failed: Disk full"); delete[] data; return 1; } info[lat].bytesWritten += AUDIO_BLOCK_LEN; #endif repairErrors=-1; cabRetries=0; // proceed to next audio block //log_message(0,"PROCEEDING TO NEXT BLOCK"); cab++; rab--; if (cabGoods == 1000) { if (overspeed<20) { overspeed=((overspeed*2)>=20?20:overspeed*2); // crank up the speed again // log_message(0,"Speeding up to %ld overspeed...\r",overspeed); speed(overspeed); cabGoods=0; } } } else // the current block contains errors { int j; // first time error on this block? if (cabRetries==0) { // copy faulty block into our repair buffer memcpy(repairBlock,data+i*blockLength,AUDIO_BLOCK_LEN+1+294+96); // slow down to lower error rate (we hope so!?) if (overspeed>1) overspeed/=2; // log_message(0,"Slowing down to %ld...\r",overspeed); speed(overspeed); } // iterate through all audio samples, merge all good samples into // a repair audio block // Implementor's note: The following info is NOT mentioned in the // official Plextor documentation I have, but IS confirmed by // Plextor. -- Leon Woestenberg <leon@stack.nl>. // NOTE: Any two bytes of a sample (or both) can be damaged. // Although the error bit flag can be set for just one byte, the // other byte can be changed due to the fact that DSP interpolation // is applied to the whole (two-byte) sample. // THEREFORE, any of the two bits relating to a two-byte sample // indicate the WHOLE sample is incorrect, and we will try to // repair the whole sample, not just the one byte. // THIS will ensure we have a 100% bit-wise accurate copy of // the audio data. repairErrors=0; for (j=0;j<AUDIO_BLOCK_LEN;j+=2) // iterate by steps of 1 sample { // sample erronous in repair block? (bits 7-j and/or 6-j set?) if (repairBlock[AUDIO_BLOCK_LEN+1+(j/8)] & (192>>(j%8))) { // sample good in fresh data block? if (!(data[i*blockLength+AUDIO_BLOCK_LEN+1+(j/8)] & (192>>(j%8)))) { #if 0 printf("\nerrenous sample %d (bytes %d/%d) being repaired with %04x", j/2,j,j+1,data[i*blockLength+j]*256+data[i*blockLength+j+1]); #endif // then copy it into the repairBlock; repairBlock[j]=data[i*blockLength+j]; repairBlock[j+1]=data[i*blockLength+j+1]; // clear error bit in repair block repairBlock[AUDIO_BLOCK_LEN+1+(j/8)] &= (~(192>>(j%8))); } // erronous sample could not be replaced by the good one else { #if 0 printf("%d, ",j/2); #endif // increment number of repair block erronous samples repairErrors++; } #if 0 log_message(0,"bits %ld/%ld (bits %ld/%ld of byte %ld) was 1", j,j+1,7-(j%8),6-(j%8),j/8); #endif } #if 0 else { log_message(0,"bits %ld/%ld (bits %ld/%ld of byte %ld) were 0", j,j+1,7-(j%8),6-(j%8),j/8); } #endif } if (cabRetries==0) { log_message(1,"\nblock %6ld has %3ld error samples\r", cab,repairErrors); } else { log_message(1,"block %6ld has %3ld error samples left after %3ld retries\r", cab,repairErrors,cabRetries); } // increase number of retries cabRetries++; cabGoods=0; // break out of for-loop (into while-loop) to re-read current block break; } } } delete[] data; return 0; } int PlextorReader::readSubChannels(TrackData::SubChannelMode, long lba, long len, SubChannel ***chans, Sample *audioData) { unsigned char cmd[12]; int cmdLen; int tries = 5; int ret; memset(cmd, 0, 12); if (options_ & OPT_PLEX_DAE_READ10) { if (setBlockSize(AUDIO_BLOCK_LEN) != 0) return 1; cmd[0] = 0x28; // READ10 cmd[2] = lba >> 24; cmd[3] = lba >> 16; cmd[4] = lba >> 8; cmd[5] = lba; cmd[7] = len >> 8; cmd[8] = len; cmdLen = 10; } else if (options_ & OPT_PLEX_DAE_D4_12) { cmd[0] = 0xd4; cmd[2] = lba >> 24; cmd[3] = lba >> 16; cmd[4] = lba >> 8; cmd[5] = lba; cmd[8] = len >> 8; cmd[9] = len; cmdLen = 12; } else { cmd[0]=0xd8; // READ CDDA cmd[2] = lba >> 24; cmd[3] = lba >> 16; cmd[4] = lba >> 8; cmd[5] = lba; cmd[6] = len >> 24; cmd[7] = len >> 16; cmd[8] = len >> 8; cmd[9] = len; cmdLen = 12; } do { ret = sendCmd(cmd, cmdLen, NULL, 0, (unsigned char*)audioData, len * AUDIO_BLOCK_LEN, (tries == 1) ? 1 : 0); if (ret != 0 && tries == 1) { log_message(-2, "Reading of audio data failed at sector %ld.", lba); return 1; } tries--; } while (ret != 0 && tries > 0); *chans = NULL; return 0; } int PlextorReader::readAudioRange(ReadDiskInfo *rinfo, int fd, long start, long end, int startTrack, int endTrack, TrackInfo *info) { if (model_ != 0 && (options_ & OPT_PLEX_USE_PARANOIA) == 0) { // we have a plextor drive -> use the special plextor method which // will also detect pre-gaps, index marks and ISRC codes return readAudioRangePlextor(rinfo, fd, start, end, startTrack, endTrack, info); } if (!onTheFly_) { int t, i; long pregap = 0; int indexCnt = 0; Msf index[98]; unsigned char ctl; long slba, elba; log_message(1, "Analyzing..."); for (t = startTrack; t <= endTrack; t++) { long totalProgress; log_message(1, "Track %d...", t + 1); totalProgress = t * 1000; totalProgress /= rinfo->tracks; sendReadCdProgressMsg(RCD_ANALYZING, rinfo->tracks, t + 1, 0, totalProgress); if (!fastTocReading_) { if (pregap != 0) log_message(2, "Found pre-gap: %s", Msf(pregap).str()); slba = info[t].start; if (info[t].mode == info[t + 1].mode) elba = info[t + 1].start; else elba = info[t + 1].start - 150; pregap = 0; if (analyzeTrackSearch(TrackData::AUDIO, t + 1, slba, elba, index, &indexCnt, &pregap, info[t].isrcCode, &ctl) != 0) return 1; for (i = 0; i < indexCnt; i++) info[t].index[i] = index[i].lba(); info[t].indexCnt = indexCnt; if (t < endTrack) info[t + 1].pregap = pregap; } else { info[t].indexCnt = 0; info[t + 1].pregap = 0; } info[t].isrcCode[0] = 0; readIsrc(t + 1, info[t].isrcCode); if (info[t].isrcCode[0] != 0) log_message(2, "Found ISRC code."); totalProgress = (t + 1) * 1000; totalProgress /= rinfo->tracks; sendReadCdProgressMsg(RCD_ANALYZING, rinfo->tracks, t + 1, 1000, totalProgress); } log_message(1, "Reading..."); } return CdrDriver::readAudioRangeParanoia(rinfo, fd, start, end, startTrack, endTrack, info); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/PlextorReader.h�����������������������������������������������������������0000664�0000000�0000000�00000013247�15114537466�0020401�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __PLEXTOR_READER_H__ #define __PLEXTOR_READER_H__ #include "CdrDriver.h" #define OPT_PLEX_USE_PARANOIA 0x0001 // always use paranoia method for DAE #define OPT_PLEX_DAE_READ10 0x0002 // use READ10 for DAE #define OPT_PLEX_DAE_D4_12 0x0004 // use 12 byte command 0xD4 for DAE /*! \def OPT_PLEX_NOSLOW_ON_ERR \brief Don't slow down read speed if any read error encountered By default is activated, so the unit slows down. Passing this option will disable it; unit won't slow down. Driver checks previous status and restores it. Mode page 0x31 byte 3 [ x x x x x x x re ] 1 means don't slow down, 0 default */ #define OPT_PLEX_NOSLOW_ON_ERR 0x0010 /*! \def OPT_PLEX_TRANSF_BEF_MAX \brief Start to transfer data before max speed reached By default is disabled, so unit reaches max speed before beginning transfer. Passing this options will enable it; unit will transfer data before reaching max speed. Driver checks previous status and restores it. Mode page 0x31 byte 3 [ x x x x x x td x ] 1 means don't wait for max speed, 0 default */ #define OPT_PLEX_TRANSF_BEF_MAX 0x0020 /*! \def OPT_PLEX_NOSLOW_ON_VIB \brief Don't slowdown to avoid vibrations By default is activated, so unit slows down. Passing this option will disable it; unit won't slow down. Driver checks previous status and restores it. Mode page 0x31 byte 3 [ x x x x x sl x x ] 1 means don't slow down, 0 default */ #define OPT_PLEX_NOSLOW_ON_VIB 0x0040 class Toc; class Track; class PlextorReader : public CdrDriver { public: PlextorReader(ScsiIf *scsiIf, unsigned long options); /*! * Its only purpose is to reset Plextor special features to their value * before cdrdao initialization. */ virtual ~PlextorReader(); static CdrDriver *instance(ScsiIf *scsiIf, unsigned long options); unsigned long getReadCapabilities(const CdToc *, int) const { return 0; } // not used for readers int bigEndianSamples() const { return 0;} int speed(int); int loadUnload(int) const { return 0; } int initDao(const Toc *); int startDao(); int finishDao(); void abortDao(); inline int ReadErrorsSlowDown () {return slow_down_on_read_errors;} inline int VibrationsSlowDown () {return slow_down_on_vibrations;} inline int WaitMaxSpeed () {return transfer_data_before_max_speed;} /*! \brief Controls wheter drive slows down when a read error occurs Special plextor feature; \param slowdown 0 to disable slowdown, 1 to enable (default) \return 1 on success, -1 on error */ int ReadErrorsSlowDown (int slowdown); /*! \brief Controls wheter drive slows down when paused to avoid vibrations Special plextor feature, available on PX-20 and later \param slowdown 0 to disable slowdown, 1 to enable (default) \return 1 on success, -1 on error */ int VibrationsSlowDown (int slowdown); /*! \brief Controls wheter drive waits for max speed before transferring data Special plextor feature, available on PX-20 and later \param wait 0 to transfer before maximum speed, 1 to wait (default) \return 1 on success, -1 on error */ int WaitMaxSpeed (int wait); DiskInfo *diskInfo(); Toc *readDiskToc(int, const char *); Toc *readDisk(int, const char *); protected: DiskInfo diskInfo_; /*! \brief Drive model, as index of following { 1,"CD-ROM PX-4XCH" }, { 2,"CD-ROM PX-4XCS" }, { 3,"CD-ROM PX-4XCE" }, { 4,"CD-ROM PX-6X" }, { 5,"CD-ROM PX-8X" }, { 6,"CD-ROM PX-12" }, { 7,"CD-ROM PX-20" }, { 8,"CD-ROM PX-32" }, { 9,"CD-ROM PX-40" } */ int model_; CdRawToc *getRawToc(int sessionNr, int *len); int getTrackIndex(long lba, int *trackNr, int *indexNr, unsigned char *ctl); int readCatalog(Toc *, long startLba, long endLba); int analyzeTrack(TrackData::Mode, int trackNr, long startLba, long endLba, Msf *index, int *indexCnt, long *pregap, char *isrcCode, unsigned char *ctl); int readIsrc(int trackNr, char *); long readTrackData(TrackData::Mode mode, TrackData::SubChannelMode, long lba, long len, unsigned char *buf); int readSubChannels(TrackData::SubChannelMode, long lba, long len, SubChannel ***, Sample *); int readAudioRange(ReadDiskInfo *, int fd, long start, long end, int startTrack, int endTrack, TrackInfo *trackInfo); private: void playAudioBlock(long start, long len); int readSubChannelData(int *trackNr, int *indexNr, long *, unsigned char *ctl); int readAudioRangePlextor(ReadDiskInfo *, int fd, long start, long end, int startTrack, int endTrack, TrackInfo *); /* These can be -1 if not available, 0 or 1 */ int slow_down_on_read_errors; int transfer_data_before_max_speed; int slow_down_on_vibrations; /* Original status of plextor special features */ unsigned char orig_byte3; }; #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/PlextorReaderScan.cc������������������������������������������������������0000664�0000000�0000000�00000013652�15114537466�0021344�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #include <config.h> #include <string.h> #include <assert.h> #include "PlextorReaderScan.h" #include "PWSubChannel96.h" #include "PQSubChannel16.h" #include "Toc.h" #include "log.h" PlextorReaderScan::PlextorReaderScan(ScsiIf *scsiIf, unsigned long options) : PlextorReader(scsiIf, options) { int i; driverName_ = "Plextor CD-ROM Reader (scanning) - Version 1.0"; for (i = 0; i < maxScannedSubChannels_; i++) { if (options_ & OPT_PLEX_USE_PQ) scannedSubChannels_[i] = new PQSubChannel16; else scannedSubChannels_[i] = new PWSubChannel96; } } PlextorReaderScan::~PlextorReaderScan() { int i; for (i = 0; i < maxScannedSubChannels_; i++) { delete scannedSubChannels_[i]; scannedSubChannels_[i] = NULL; } } // static constructor CdrDriver *PlextorReaderScan::instance(ScsiIf *scsiIf, unsigned long options) { return new PlextorReaderScan(scsiIf, options); } Toc *PlextorReaderScan::readDisk(int session, const char *fname) { Toc *toc = CdrDriver::readDisk(session, fname); setBlockSize(MODE1_BLOCK_LEN); return toc; } int PlextorReaderScan::analyzeTrack(TrackData::Mode mode, int trackNr, long startLba, long endLba, Msf *indexIncrements, int *indexIncrementCnt, long *pregap, char *isrcCode, unsigned char *ctl) { int ret = analyzeTrackScan(mode, trackNr, startLba, endLba, indexIncrements, indexIncrementCnt, pregap, isrcCode, ctl); if ((options_ & OPT_PLEX_READ_ISRC) || ((options_ & OPT_PLEX_USE_PQ) && !(options_ & OPT_PLEX_PQ_BCD))) { // The ISRC code is usually not usable if the PQ channel data is // converted to hex numbers by the drive. Read them with the // appropriate command in this case *isrcCode = 0; if (mode == TrackData::AUDIO) readIsrc(trackNr, isrcCode); } return ret; } int PlextorReaderScan::readSubChannels(TrackData::SubChannelMode sm, long lba, long len, SubChannel ***chans, Sample *audioData) { unsigned char cmd[12]; int i; int retries = 5; long blockLen; if (options_ & OPT_PLEX_USE_PQ) blockLen = AUDIO_BLOCK_LEN + 16; else blockLen = AUDIO_BLOCK_LEN + 96; cmd[0] = 0xd8; // READ CDDA cmd[1] = 0; cmd[2] = lba >> 24; cmd[3] = lba >> 16; cmd[4] = lba >> 8; cmd[5] = lba; cmd[6] = 0; cmd[7] = len >> 16; cmd[8] = len >> 8; cmd[9] = len; if (options_ & OPT_PLEX_USE_PQ) cmd[10] = 0x01; else cmd[10] = 0x02; cmd[11] = 0; while (1) { if (sendCmd(cmd, 12, NULL, 0, transferBuffer_, len * blockLen, retries == 0 ? 1 : 0) != 0) { if (retries == 0) return 1; } else { break; } retries--; } #if 0 if (lba > 5000) { char fname[200]; sprintf(fname, "testout_%ld", lba); FILE *fp = fopen(fname, "w"); fwrite(transferBuffer_, blockLen, len, fp); fclose(fp); } #endif unsigned char *p = transferBuffer_ + AUDIO_BLOCK_LEN; for (i = 0; i < len; i++) { if (options_ & OPT_PLEX_USE_PQ) { if (!(options_ & OPT_PLEX_PQ_BCD)) { // Numbers in sub-channel data are hex instead of BCD. // We have to convert them back to BCD for the 'SubChannel' class. p[1] = SubChannel::bcd(p[1]); p[2] = SubChannel::bcd(p[2]); p[3] = SubChannel::bcd(p[3]); p[4] = SubChannel::bcd(p[4]); p[5] = SubChannel::bcd(p[5]); p[6] = SubChannel::bcd(p[6]); p[7] = SubChannel::bcd(p[7]); p[8] = SubChannel::bcd(p[8]); p[9] = SubChannel::bcd(p[9]); } ((PQSubChannel16*)scannedSubChannels_[i])->init(p); if (scannedSubChannels_[i]->type() != SubChannel::QMODE_ILLEGAL) { // the CRC of the sub-channel data is usually invalid -> mark the // sub-channel object that it should not try to verify the CRC scannedSubChannels_[i]->crcInvalid(); } } else { ((PWSubChannel96*)scannedSubChannels_[i])->init(p); } p += blockLen; } if (audioData != NULL) { p = transferBuffer_; for (i = 0; i < len; i++) { memcpy(audioData, p, AUDIO_BLOCK_LEN); p += blockLen; audioData += SAMPLES_PER_BLOCK; } } *chans = scannedSubChannels_; return 0; } int PlextorReaderScan::readAudioRange(ReadDiskInfo *info, int fd, long start, long end, int startTrack, int endTrack, TrackInfo *trackInfo) { if (!onTheFly_) { if ((options_ & OPT_PLEX_READ_ISRC) || ((options_ & OPT_PLEX_USE_PQ) && !(options_ & OPT_PLEX_PQ_BCD))) { int t; log_message(1, "Analyzing..."); for (t = startTrack; t <= endTrack; t++) { long totalProgress; log_message(1, "Track %d...", t + 1); totalProgress = t * 1000; totalProgress /= info->tracks; sendReadCdProgressMsg(RCD_ANALYZING, info->tracks, t + 1, 0, totalProgress); trackInfo[t].isrcCode[0] = 0; readIsrc(t + 1, trackInfo[t].isrcCode); if (trackInfo[t].isrcCode[0] != 0) log_message(2, "Found ISRC code."); totalProgress = (t + 1) * 1000; totalProgress /= info->tracks; sendReadCdProgressMsg(RCD_ANALYZING, info->tracks, t + 1, 1000, totalProgress); } log_message(1, "Reading..."); } } return CdrDriver::readAudioRangeParanoia(info, fd, start, end, startTrack, endTrack, trackInfo); } ��������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/PlextorReaderScan.h�������������������������������������������������������0000664�0000000�0000000�00000004007�15114537466�0021200�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __PLEXTOR_READER_SCAN_H__ #define __PLEXTOR_READER_SCAN_H__ #include "PlextorReader.h" #define OPT_PLEX_USE_PQ 0x0001 // use PQ sub-channel data for scanning #define OPT_PLEX_PQ_BCD 0x0002 // PQ sub-channel contains BCD numbers #define OPT_PLEX_READ_ISRC 0x0004 // force reading of ISRC code with // READ SUB CHANNEL instead taking it from // the sub-channel data class PlextorReaderScan : public PlextorReader { public: PlextorReaderScan(ScsiIf *scsiIf, unsigned long options); ~PlextorReaderScan(); static CdrDriver *instance(ScsiIf *scsiIf, unsigned long options); Toc *readDisk(int session, const char *); unsigned long getReadCapabilites(const CdToc *, int) const { return 0; } protected: int analyzeTrack(TrackData::Mode, int trackNr, long startLba, long endLba, Msf *index, int *indexCnt, long *pregap, char *isrcCode, unsigned char *ctl); int readSubChannels(TrackData::SubChannelMode, long lba, long len, SubChannel ***, Sample *); int readAudioRange(ReadDiskInfo *, int fd, long start, long end, int startTrack, int endTrack, TrackInfo *); }; #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/RicohMP6200.cc������������������������������������������������������������0000664�0000000�0000000�00000012700�15114537466�0017561�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <andreas@daneb.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 * (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. */ /* Driver for the Ricoh MP6200 drive. It's mainly SCSI-3/mmc compatible but * disk-at-once writing is done with the Philips CDD2x00 commands. */ #include <config.h> #include <string.h> #include <assert.h> #include "RicohMP6200.h" #include "SubChannel.h" #include "Toc.h" #include "log.h" RicohMP6200::RicohMP6200(ScsiIf *scsiIf, unsigned long options) : GenericMMC(scsiIf, options), CDD2600Base(this) { driverName_ = "Ricoh MP6200 - Version 0.1(alpha)"; simulate_ = true; encodingMode_ = 0; } RicohMP6200::~RicohMP6200() { } // static constructor CdrDriver *RicohMP6200::instance(ScsiIf *scsiIf, unsigned long options) { return new RicohMP6200(scsiIf, options); } // Sets write parameters via mode page 0x05. // return: 0: OK // 1: scsi command failed int RicohMP6200::setWriteParameters() { int i; unsigned char mp[0x38]; if (getModePage(5/*write parameters mode page*/, mp, 0x38, NULL, NULL, 1) != 0) { log_message(-2, "Cannot retrieve write parameters mode page."); return 1; } mp[0] &= 0x7f; // clear PS flag mp[2] &= 0xef; if (simulate_) { mp[2] |= 1 << 4; // test write } mp[3] &= 0x3f; // Multi-session: No B0 pointer, next session not allowed if (multiSession_ != 0) mp[3] |= 0x03 << 6; // open next session if (toc_->catalogValid()) { mp[16] = 0x80; for (i = 0; i < 13; i++) mp[17 + i] = toc_->catalog(i) + '0'; mp[30] = 0; mp[31] = 0; } else { mp[16] = 0; } if (setModePage(mp, NULL, NULL, 1) != 0) { log_message(-2, "Cannot set write parameters mode page."); return 1; } return 0; } int RicohMP6200::initDao(const Toc *toc) { long n; blockLength_ = AUDIO_BLOCK_LEN; blocksPerWrite_ = scsiIf_->maxDataLen() / blockLength_; assert(blocksPerWrite_ > 0); toc_ = toc; // the ATAPI version does not like the following command so a failure // is non fatal modeSelectBlockSize(blockLength_, 0); if (readSessionInfo(&leadInLen_, &leadOutLen_, 1) != 0 || setWriteParameters() != 0) return 1; // allocate buffer for write zeros n = blocksPerWrite_ * blockLength_; delete[] zeroBuffer_; zeroBuffer_ = new char[n]; memset(zeroBuffer_, 0, n); return 0; } int RicohMP6200::startDao() { long lba = 0; if (writeSession(toc_, multiSession_, 0) != 0) { return 1; } log_message(2, "Writing lead-in and gap..."); // write lead-in if (writeZeros(toc_->leadInMode(), TrackData::SUBCHAN_NONE, lba, 0, leadInLen_) != 0) { flushCache(); return 1; } // write gap (2 seconds) if (writeZeros(toc_->leadInMode(), TrackData::SUBCHAN_NONE, lba, 0, 150) != 0) { flushCache(); return 1; } log_message(2, ""); return 0; } int RicohMP6200::finishDao() { long lba = toc_->length().lba(); log_message(2, "Writing lead-out..."); // write lead-out if (writeZeros(toc_->leadOutMode(), TrackData::SUBCHAN_NONE, lba, lba + 150, leadOutLen_) != 0) { flushCache(); return 1; } log_message(2, "\nFlushing cache..."); if (flushCache() != 0) { return 1; } log_message(2, ""); delete[] zeroBuffer_, zeroBuffer_ = NULL; return 0; } void RicohMP6200::abortDao() { flushCache(); } // Writes data to target, the block length depends on the actual writing mode // and is stored internally. 'len' is number of blocks to write. // 'lba' specifies the next logical block address for writing and is updated // by this function but not used for writing // return: 0: OK // 1: scsi command failed int RicohMP6200::writeData(TrackData::Mode mode, TrackData::SubChannelMode sm, long &lba, const char *buf, long len) { assert(blocksPerWrite_ > 0); assert(blockLength_ > 0); assert(mode == TrackData::AUDIO); int nwritten = 0; int writeLen = 0; unsigned char cmd[10]; memset(cmd, 0, 10); cmd[0] = 0x2a; // WRITE1 while (len > 0) { writeLen = (len > blocksPerWrite_ ? blocksPerWrite_ : len); cmd[7] = writeLen >> 8; cmd[8] = writeLen & 0xff; if (sendCmd(cmd, 10, (unsigned char *)(buf + (nwritten * blockLength_)), writeLen * blockLength_, NULL, 0) != 0) { log_message(-2, "Write data failed."); return 1; } lba += writeLen; len -= writeLen; nwritten += writeLen; } return 0; } // loads ('unload' == 0) or ejects ('unload' == 1) tray // return: 0: OK // 1: scsi command failed int RicohMP6200::loadUnload(int unload) const { unsigned char cmd[10]; memset(cmd, 0, 10); cmd[0] = 0xe7; // MEDIUM LOAD/UNLOAD if (unload) { cmd[8] |= 0x01; } if (sendCmd(cmd, 10, NULL, 0, NULL, 0) != 0) { log_message(-2, "Cannot load/unload medium."); return 1; } return 0; } ����������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/RicohMP6200.h�������������������������������������������������������������0000664�0000000�0000000�00000003045�15114537466�0017425�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <andreas@daneb.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 * (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. */ /* Driver for the Ricoh MP6200 drive. It's mainly SCSI-3/mmc compatible but * disk-at-once writing is done with the Philips CDD2x00 commands. */ #ifndef __RICOH_MP6200_H__ #define __RICOH_MP6200_H__ #include "GenericMMC.h" #include "CDD2600Base.h" class RicohMP6200 : public GenericMMC, private CDD2600Base { public: RicohMP6200(ScsiIf *scsiIf, unsigned long options); ~RicohMP6200(); static CdrDriver *instance(ScsiIf *scsiIf, unsigned long options); int initDao(const Toc *); int startDao(); int finishDao(); void abortDao(); int writeData(TrackData::Mode, TrackData::SubChannelMode, long &lba, const char *buf, long len); int loadUnload(int unload) const; protected: int setWriteParameters(); }; #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/ScsiIf-common.cc����������������������������������������������������������0000664�0000000�0000000�00000005504�15114537466�0020422�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1999 Andreas Mueller <mueller@daneb.ping.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 * (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. */ // checks if unit is ready // return: 0: OK, ready // 1: not ready (busy) // 2: not ready, no disk in drive // 3: scsi command failed int ScsiIf::testUnitReady() { unsigned char cmd[6]; const unsigned char *senseData; int senseLen; int ret = 0; memset(cmd, 0, 6); switch (sendCmd(cmd, 6, NULL, 0, NULL, 0, 0)) { case 1: ret = 3; break; case 2: senseData = getSense(senseLen); switch (senseData[2] & 0x0f) { case 0x02: // Not ready switch (senseData[12]) { case 0x3a: // medium not present ret = 2; break; default: ret = 1; break; } break; case 0x06: // Unit attention ret = 0; break; default: ret = 3; break; } } return ret; } cd_page_2a* ScsiIf::checkMmc() { static const int MODE_SENSE_G1_CMD = 0x5a; static const int MODE_MAX_SIZE = 256; static const int MODE_PAGE_HEADER_SIZE = 8; static const int MODE_CD_CAP_PAGE = 0x2a; static unsigned char mode[MODE_MAX_SIZE]; memset(mode, 0, sizeof(mode)); // First, read header of mode page 0x2A, to figure out its exact // length. For this, we issue a MODE_SENSE (10) command with a // data length of 8, just the size of the mode header. unsigned char cmd[10]; memset(&cmd, 0, sizeof(cmd)); cmd[0] = MODE_SENSE_G1_CMD; // MODE SENSE(10) cmd[2] = MODE_CD_CAP_PAGE; cmd[8] = MODE_PAGE_HEADER_SIZE; if (sendCmd((unsigned char*)&cmd, 10, NULL, 0, mode, MODE_PAGE_HEADER_SIZE) != 0) { return NULL; } int len = ((mode[0] << 8) + mode[1]) + 2; // +2 is for address field if (len > MODE_MAX_SIZE) len = MODE_MAX_SIZE; // Now we have the length of page 0x2a, read the whole page. memset(mode, 0, MODE_PAGE_HEADER_SIZE); memset(&cmd, 0, sizeof(cmd)); cmd[0] = MODE_SENSE_G1_CMD; // MODE SENSE(10) cmd[2] = MODE_CD_CAP_PAGE; cmd[8] = len; if (sendCmd((unsigned char*)&cmd, 10, NULL, 0, mode, len) != 0) { return NULL; } return (cd_page_2a*)(mode + 9); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/ScsiIf-freebsd-cam.cc�����������������������������������������������������0000664�0000000�0000000�00000012105�15114537466�0021275�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <andreas@daneb.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 * (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. */ /* SCSI interface implemenation for FreeBSD. * Written by Max Khon <fjoe@iclub.nsu.ru> */ #include <config.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <camlib.h> #include <cam/scsi/scsi_message.h> #include "ScsiIf.h" #include "log.h" #define DEF_RETRY_COUNT 1 #include "decodeSense.cc" class ScsiIfImpl { public: char * devname; struct cam_device * dev; union ccb * ccb; int timeout; /* timeout in ms */ }; ScsiIf::ScsiIf(const char *devname) { impl_ = new ScsiIfImpl; impl_->devname = strdupCC(devname); impl_->dev = NULL; impl_->ccb = NULL; impl_->timeout = 5000; maxDataLen_ = 32 * 1024; vendor_[0] = 0; product_[0] = 0; revision_[0] = 0; } ScsiIf::~ScsiIf() { if (impl_->ccb) cam_freeccb(impl_->ccb); if (impl_->dev) cam_close_device(impl_->dev); delete[] impl_->devname; delete impl_; } // opens scsi device // return: 0: OK // 1: device could not be opened // 2: inquiry failed int ScsiIf::init() { if ((impl_->dev = cam_open_device(impl_->devname, O_RDWR)) == NULL) { log_message(-2, "%s", cam_errbuf); return 1; } impl_->ccb = cam_getccb(impl_->dev); if (impl_->ccb == NULL) { log_message(-2, "init: error allocating ccb"); return 1; } if (inquiry()) return 2; return 0; } // Sets given timeout value in seconds and returns old timeout. // return: old timeout int ScsiIf::timeout(int t) { int old = impl_->timeout; impl_->timeout = t*1000; return old/1000; } // sends a scsi command and receives data // return 0: OK // 1: scsi command failed (os level, no sense data available) // 2: scsi command failed (sense data available) int ScsiIf::sendCmd(const unsigned char *cmd, int cmdLen, const unsigned char *dataOut, int dataOutLen, unsigned char *dataIn, int dataInLen, int showMessage) { int retval; int flags = CAM_DIR_NONE; u_int8_t * data_ptr = NULL; size_t data_len = 0; bzero(impl_->ccb, sizeof(union ccb)); bcopy(cmd, &impl_->ccb->csio.cdb_io.cdb_bytes, cmdLen); if (dataOut && dataOutLen > 0) { data_ptr = (u_int8_t*) dataOut; data_len = dataOutLen; flags = CAM_DIR_OUT; } else if (dataIn && dataInLen > 0) { data_ptr = dataIn; data_len = dataInLen; flags = CAM_DIR_IN; } cam_fill_csio(&impl_->ccb->csio, DEF_RETRY_COUNT, NULL, flags | CAM_DEV_QFRZDIS, MSG_SIMPLE_Q_TAG, data_ptr, data_len, SSD_FULL_SIZE, cmdLen, impl_->timeout); if ((retval = cam_send_ccb(impl_->dev, impl_->ccb)) < 0 || (impl_->ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { if (retval < 0) { log_message(-2, "sendCmd: error sending command"); return 1; } if ((impl_->ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR) { if (showMessage) printError(); return 2; } return 1; } return 0; } const unsigned char *ScsiIf::getSense(int &len) const { len = impl_->ccb->csio.sense_len; return (const unsigned char*) &impl_->ccb->csio.sense_data; } void ScsiIf::printError() { decodeSense((const unsigned char*) &impl_->ccb->csio.sense_data, impl_->ccb->csio.sense_len); } int ScsiIf::inquiry() { int i; struct scsi_inquiry_data inq_data; bzero(impl_->ccb, sizeof(union ccb)); bzero(&inq_data, sizeof(inq_data)); scsi_inquiry(&impl_->ccb->csio, DEF_RETRY_COUNT, NULL, MSG_SIMPLE_Q_TAG, (u_int8_t*) &inq_data, sizeof(inq_data), 0, 0, SSD_FULL_SIZE, impl_->timeout); impl_->ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; if (cam_send_ccb(impl_->dev, impl_->ccb) < 0) { if ((impl_->ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_SCSI_STATUS_ERROR) { log_message(-2, "%s", cam_errbuf); return 1; } printError(); return 1; } strncpy(vendor_, inq_data.vendor, 8); vendor_[8] = 0; strncpy(product_, inq_data.product, 16); product_[16] = 0; strncpy(revision_, inq_data.revision, 4); revision_[4] = 0; for (i = 7; i >= 0 && vendor_[i] == ' '; i--) vendor_[i] = 0; for (i = 15; i >= 0 && product_[i] == ' '; i--) product_[i] = 0; for (i = 3; i >= 0 && revision_[i] == ' '; i--) revision_[i] = 0; return 0; } ScsiIf::ScanData *ScsiIf::scan(int *len, char* scsi_dev_path) { *len = 0; return NULL; } #include "ScsiIf-common.cc" �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/ScsiIf-irix.cc������������������������������������������������������������0000664�0000000�0000000�00000023354�15114537466�0020110�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Native implementation of cdrdao's SCSI interface for Irix 6. * Copyright (C) by Edgar Fuß, Bonn, May 2003, July 2007. * Do with this whatever you like, as long as you are either me or you keep * this message intact and both * - acknowledge that I wrote it for cdrdao in the first place, and * - don't blame me if it doesn't do what you like or expect. * These routines do exactly what they do. If that's not what you expect them * or would like them to do, don't complain with me, the cdrdao project, my * neighbour's brother-in-law or anybody else, but rewrite them to your taste. */ #include <stdio.h> #include <ctype.h> #include <string.h> #include <errno.h> #include <sys/dsreq.h> #include <fcntl.h> #include <sys/types.h> #include <dirent.h> #include <unistd.h> #include "ScsiIf.h" extern void message(int level, const char *fmt, ...); #include "decodeSense.cc" #define MAX_SCAN 32 #define SENSE_MAX 256 class ScsiIfImpl { public: char *name_; int fd_; long timeout_; /* in ms */ struct dsreq dsreq_; char *error_; unsigned char sensebuf_[SENSE_MAX]; }; ScsiIf::ScsiIf(const char *name) { #define PREFIX "/dev/scsi/" #define PREFIX_SC "/dev/scsi/sc" int len; int bus, targ, lun, count; impl_ = new ScsiIfImpl; len = strlen(name); if (len == 0) { impl_->name_ = NULL; } else if (sscanf(name, "%i,%i,%i%n", &bus, &targ, &lun, &count) == 3 && count == len) { if ((bus < 0) || (targ < 0) || (lun < 0)) impl_->name_ = NULL; else { impl_->name_ = new char[strlen(PREFIX_SC) + len + 1]; sprintf(impl_->name_, "%s%dd%dl%d", PREFIX_SC, bus, targ, lun); } } else if (strncmp(name, "/", 1) == 0 || strncmp(name, "./", 2) == 0 || strncmp(name, "../", 3) == 0) { impl_->name_ = new char[len + 1]; strcpy(impl_->name_, name); } else { impl_->name_ = new char[strlen(PREFIX) + len + 1]; strcpy(impl_->name_, PREFIX); strcat(impl_->name_, name); } impl_->fd_ = -1; impl_->timeout_ = 10*1000; impl_->error_ = NULL; maxDataLen_ = 64 * 1024; vendor_[0] = 0; product_[0] = 0; revision_[0] = 0; #undef PREFIX } ScsiIf::~ScsiIf() { if (impl_->fd_ >= 0) (void)close(impl_->fd_); if (impl_->name_ != NULL) delete[] impl_->name_; if (impl_->error_ != NULL) delete[] impl_->error_; delete impl_; } int ScsiIf::init() { if (impl_->name_ == NULL) return 1; if ((impl_->fd_ = open(impl_->name_, O_RDWR, 0)) < 0) { message(-2, "init: %s", strerror(errno)); return 1; } if (inquiry()) return 2; return 0; } int ScsiIf::timeout(int t) { int ret = impl_->timeout_/1000; impl_->timeout_ = t*1000; return ret; } int ScsiIf::sendCmd(const unsigned char *cmd, int cmdLen, const unsigned char *dataOut, int dataOutLen, unsigned char *dataIn, int dataInLen, int showMessage) { #define ERROR(msg) {\ impl_->error_ = new char[9 + strlen(msg) + 1];\ strcpy(impl_->error_, "sendCmd: ");\ strcat(impl_->error_, msg);\ if (showMessage) printError();\ return 1;\ } if (impl_->error_ != NULL) { delete[] impl_->error_; impl_->error_ = NULL; } /* for printError: */ impl_->dsreq_.ds_cmdbuf = NULL; impl_->dsreq_.ds_cmdlen = 0; impl_->dsreq_.ds_databuf = NULL; impl_->dsreq_.ds_datalen = 0; impl_->dsreq_.ds_flags = 0; impl_->dsreq_.ds_time = impl_->timeout_; if (cmdLen == 0) ERROR("cmdLen == 0"); if (cmdLen > 255) ERROR("cmdLen > 255"); impl_->dsreq_.ds_cmdbuf = (caddr_t)cmd; impl_->dsreq_.ds_cmdlen = cmdLen; if (dataOut != NULL && dataIn != NULL) { ERROR("Out and In"); } else if (dataOut != NULL) { if (dataOutLen == 0) ERROR("dataOutLen == 0"); if (dataInLen != 0) ERROR("dataInLen != 0"); impl_->dsreq_.ds_flags |= DSRQ_WRITE; impl_->dsreq_.ds_databuf = (caddr_t)dataOut; impl_->dsreq_.ds_datalen = dataOutLen; } else if (dataIn != NULL) { if (dataInLen == 0) ERROR("dataInLen == 0"); if (dataOutLen !=0) ERROR("dataOutLen != 0"); impl_->dsreq_.ds_flags |= DSRQ_READ; impl_->dsreq_.ds_databuf = (caddr_t)dataIn; impl_->dsreq_.ds_datalen = dataInLen; } else { if (dataOutLen !=0 || dataInLen != 0) ERROR("dataLen != 0"); impl_->dsreq_.ds_databuf = NULL; impl_->dsreq_.ds_datalen = 0; } impl_->dsreq_.ds_senselen = SENSE_MAX; impl_->dsreq_.ds_sensebuf = (caddr_t)impl_->sensebuf_; impl_->dsreq_.ds_flags |= DSRQ_SENSE; if (ioctl(impl_->fd_, DS_ENTER, &impl_->dsreq_) < 0) { char str[80]; strcpy(str, "DS_ENTER: "); strcat(str, strerror(errno)); ERROR(str); } if (impl_->dsreq_.ds_ret == 0 || impl_->dsreq_.ds_ret == DSRT_OK || impl_->dsreq_.ds_ret == DSRT_SHORT) return 0; else if (impl_->dsreq_.ds_ret == DSRT_SENSE) { if (showMessage) printError(); return 1; } else { if (showMessage) printError(); return 2; } #undef ERROR } const unsigned char *ScsiIf::getSense(int &len) const { len = impl_->dsreq_.ds_sensesent; return impl_->sensebuf_; } void ScsiIf::printError() { if (impl_->dsreq_.ds_cmdbuf != NULL) { char s[80]; char *p = s; int i; p += snprintf(p, s + sizeof(s) - p, "CDB="); for (i = 0; i < impl_->dsreq_.ds_cmdlen; i++) { p += snprintf(p, s + sizeof(s) - p, "%.2X ", impl_->dsreq_.ds_cmdbuf[i]); } p[-1] = ','; switch (impl_->dsreq_.ds_flags & (DSRQ_READ | DSRQ_WRITE)) { case DSRQ_READ: p += snprintf(p, s + sizeof(s) - p, " RD"); break; case DSRQ_WRITE: p += snprintf(p, s + sizeof(s) - p, " WR"); break; case DSRQ_READ | DSRQ_WRITE: p += snprintf(p, s + sizeof(s) - p, " RW"); break; } p += snprintf(p, s + sizeof(s) - p, ", BUF=%p", impl_->dsreq_.ds_databuf); p += snprintf(p, s + sizeof(s) - p, ", LEN=%lu", impl_->dsreq_.ds_datalen); p += snprintf(p, s + sizeof(s) - p, ", TO=%lu", impl_->dsreq_.ds_time); message(-2, s); } if (impl_->error_ != NULL) { message(-2, impl_->error_); } else { switch (impl_->dsreq_.ds_ret) { case DSRT_DEVSCSI: message(-2,"devscsi failure"); break; case DSRT_MULT: message(-2,"request rejected"); break; case DSRT_CANCEL: message(-2,"request cancelled"); break; case DSRT_REVCODE: message(-2,"obsolete"); break; case DSRT_AGAIN: message(-2,"try again"); break; case DSRT_HOST: message(-2,"host failure"); break; case DSRT_NOSEL: message(-2,"no select"); break; case DSRT_SHORT: message(-2,"short transfer"); break; case DSRT_OK: message(-2,"complete transfer"); break; case DSRT_SENSE: /* message(-2,"sense"); */ decodeSense(impl_->sensebuf_, impl_->dsreq_.ds_sensesent); break; case DSRT_NOSENSE: message(-2,"sense error"); break; case DSRT_TIMEOUT: message(-2,"timeout"); break; case DSRT_LONG: message(-2,"overrun"); break; case DSRT_PROTO: message(-2,"protocol failure"); break; case DSRT_EBSY: message(-2,"busy lost"); break; case DSRT_REJECT: message(-2,"message reject"); break; case DSRT_PARITY: message(-2,"parity error"); break; case DSRT_MEMORY: message(-2,"memory error"); break; case DSRT_CMDO: message(-2,"command error"); break; case DSRT_STAI: message(-2,"status error"); break; case DSRT_UNIMPL: message(-2,"not implemented"); break; default: message(-2, "undefined ds_ret"); break; } switch (impl_->dsreq_.ds_status) { case 0x00: message(-2, "GOOD"); break; case 0x02: message(-2, "CHECK CONDITION"); break; case 0x04: message(-2, "CONDITION MET"); break; case 0x08: message(-2, "BUSY"); break; case 0x10: message(-2, "INTERMEDIATE"); break; case 0x14: message(-2, "INTERMEDIATE, CONDITION MET"); break; case 0x18: message(-2, "RESERVATION CONFLICT"); break; case 0x22: message(-2, "COMMAND TERMINATED"); break; case 0x28: message(-2, "QUEUE FULL"); break; case 0xff: break; default: message(-2, "undefined status"); } } } int inq(int fd, void *sensebuf, int senselen, char *vend, char *prod, char *rev) { char buf[44]; char cmd[] = {0x12, 0, 0, 0, sizeof(buf), 0}; struct dsreq dsreq = { /* flags */ DSRQ_READ, /* time */ 1000, /* private */ 0, /* cmdbuf */ (caddr_t)cmd, /* cmdlen */ sizeof(cmd), /* databuf */ (caddr_t)buf, /* datalen */ sizeof(buf), /* sensebuf */ (caddr_t)sensebuf, /* senselen */ senselen, /* iovbuf */ NULL, /* iovlen */ 0, /* link */ NULL, /* sync */ 0, /* revcode */ 0, /* ret */ 0, /* status */ 0, /* msg */ 0, /* cmdsent */ 0, /* datasent */ 0, /* sensesent */ 0 }; char *p, *q; if (sensebuf != NULL && senselen > 0) dsreq.ds_flags |= DSRQ_SENSE; if (ioctl(fd, DS_ENTER, &dsreq) < 0 || (dsreq.ds_ret != 0 && dsreq.ds_ret != DSRT_OK && dsreq.ds_ret != DSRT_SHORT)) { vend[0] = prod[0] = rev[0] = '\0'; return 1; } p = buf + 8; q = buf + 16; while (q > p && q[-1] == ' ') q--; memcpy(vend, p, q - p); vend[q - p] = '\0'; p = buf + 16; q = buf + 32; while (q > p && q[-1] == ' ') q--; memcpy(prod, p, q - p); prod[q - p] = '\0'; p = buf + 32; q = buf + 36; while (q > p && q[-1] == ' ') q--; memcpy(rev, p, q - p); rev[q - p] = '\0'; return 0; } int ScsiIf::inquiry() { return inq(impl_->fd_, impl_->sensebuf_, SENSE_MAX, vendor_, product_, revision_); } ScsiIf::ScanData *ScsiIf::scan(int *len) { DIR *dirp; struct dirent *dp; int l; int fd; ScanData *scanData; char s[35]; int bus, targ, lun, count; scanData = new ScanData[MAX_SCAN]; *len = 0; if ((dirp = opendir("/dev/scsi")) == 0) { *len = 0; return NULL; } while ((dp = readdir(dirp)) != NULL) { l = strlen(dp->d_name); if (*len < MAX_SCAN && l > 2 && sscanf(dp->d_name, "sc%dd%dl%d%n", &bus, &targ, &lun, &count) == 3 && count == l) { scanData[*len].bus = bus; scanData[*len].id = targ; scanData[*len].lun = lun; strcpy(s, "/dev/scsi/"); strcat(s, dp->d_name); if ((fd = open(s, O_RDWR, 0)) >= 0) { if (inq(fd, NULL, 0, scanData[*len].vendor, scanData[*len].product, scanData[*len].revision) == 0) (*len)++; } (void)close(fd); } } closedir(dirp); return scanData; } #include "ScsiIf-common.cc" ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/ScsiIf-linux.cc�����������������������������������������������������������0000664�0000000�0000000�00000023006�15114537466�0020266�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 2007 Denis Leroy <denis@poolshark.org> * * 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. */ #include <config.h> #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <assert.h> #include <sys/ioctl.h> #include <glob.h> #include <asm/param.h> #include <scsi/scsi.h> #include <scsi/sg.h> #include "ScsiIf.h" #include "sg_err.h" #include "log.h" #include "util.h" // // SG_IO Linux SCSI interface /// #ifndef SG_GET_RESERVED_SIZE #define SG_GET_RESERVED_SIZE 0x2272 #endif #ifndef SG_SET_RESERVED_SIZE #define SG_SET_RESERVED_SIZE 0x2275 #endif #ifndef SG_GET_VERSION_NUM #define SG_GET_VERSION_NUM 0x2282 #endif #ifndef SG_MAX_SENSE #define SG_MAX_SENSE 16 #endif #define CDRDAO_DEFAULT_TIMEOUT 30000 #define SYSFS_SCSI_DEVICES "/sys/bus/scsi/devices" typedef unsigned char uchar; class ScsiIfImpl { public: char* filename_; // user provided device name int fd_; bool readOnlyMode; int openScsiDevAsSg(const char* devname); int adjustReservedBuffer(int requestedSize); uchar sense_buffer[SG_MAX_SENSE]; uchar sense_buffer_length; uchar last_sense_buffer_length; uchar last_command_status; int timeout_ms; }; ScsiIf::ScsiIf(const char *dev) { impl_ = new ScsiIfImpl; memset(impl_, 0, sizeof(ScsiIfImpl)); impl_->filename_ = strdupCC(dev); impl_->fd_ = -1; impl_->sense_buffer_length = SG_MAX_SENSE; impl_->timeout_ms = CDRDAO_DEFAULT_TIMEOUT; } ScsiIf::~ScsiIf() { if (impl_->fd_ >= 0) close(impl_->fd_); delete[] impl_->filename_; delete impl_; } // Opens and flushes scsi device. int ScsiIf::init() { int flags; int sg_version = 0; impl_->fd_ = open(impl_->filename_, O_RDWR | O_NONBLOCK | O_EXCL); if (impl_->fd_ < 0) { if (errno == EACCES) { impl_->fd_ = open(impl_->filename_, O_RDONLY | O_NONBLOCK); if (impl_->fd_ < 0) { goto failed; } impl_->readOnlyMode = true; log_message(-1, "No permission to write to SCSI device." "Only read commands are supported."); } else { goto failed; } } if (ioctl(impl_->fd_, SG_GET_VERSION_NUM, &sg_version) == 0) { log_message(3, "Detected SG driver version: %d.%d.%d", sg_version / 10000, (sg_version / 100) % 100, sg_version % 100); if (sg_version < 30000) { log_message(-2, "SG interface under 3.0 not supported."); return 1; } } maxDataLen_ = impl_->adjustReservedBuffer(64 * 1024); if (inquiry() != 0) { return 2; } return 0; failed: log_message(-2, "Unable to open SCSI device %s: %s.", impl_->filename_, strerror(errno)); return 1; } // Sets given timeout value in seconds and returns old timeout. Return // the previous timeout value. int ScsiIf::timeout(int t) { int old = impl_->timeout_ms / 1000; impl_->timeout_ms = t * 1000; return old; } // Sens a scsi command and send/receive data. int ScsiIf::sendCmd(const uchar *cmd, int cmdLen, const uchar *dataOut, int dataOutLen, uchar *dataIn, int dataInLen, int showMsg) { int status; sg_io_hdr_t io_hdr; memset(&io_hdr, 0, sizeof(io_hdr)); // Check SCSI cdb length. assert(cmdLen >= 0 && cmdLen <= 16); // Can't both input and output data. assert(!(dataOut && dataIn)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = cmdLen; io_hdr.cmdp = (unsigned char*)cmd; io_hdr.timeout = impl_->timeout_ms; io_hdr.sbp = impl_->sense_buffer; io_hdr.mx_sb_len = impl_->sense_buffer_length; io_hdr.flags = 1; if (dataOut) { io_hdr.dxferp = (void*)dataOut; io_hdr.dxfer_len = dataOutLen; io_hdr.dxfer_direction = SG_DXFER_TO_DEV; } else if (dataIn) { io_hdr.dxferp = dataIn; io_hdr.dxfer_len = dataInLen; io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; } log_message(5, "%s: Initiating SCSI command %s%s", impl_->filename_, sg_strcommand(cmd[0]), sg_strcmdopts(cmd)); if (ioctl(impl_->fd_, SG_IO, &io_hdr) < 0) { int errnosave = errno; log_message((showMsg ? -2 : 3), "[SCSI] %s (0x%02x) " "failed: %s.", sg_strcommand(cmd[0]), cmd[0], strerror(errnosave)); return 1; } log_message(4, "[SCSI] %s (0x%02x) executed in %u ms, status=%d", sg_strcommand(cmd[0]), cmd[0], io_hdr.duration, io_hdr.status); impl_->last_sense_buffer_length = io_hdr.sb_len_wr; impl_->last_command_status = io_hdr.status; if (io_hdr.status) { if (io_hdr.sb_len_wr > 0) return 2; else return 1; } return 0; } const uchar *ScsiIf::getSense(int &len) const { len = impl_->last_sense_buffer_length; return impl_->sense_buffer; } void ScsiIf::printError() { sg_print_sense("\nSCSI command failed", impl_->sense_buffer); } int ScsiIf::inquiry() { unsigned char cmd[6] = { INQUIRY, 0, 0, 0, 0x2c, 0 }; unsigned char result[0x2c]; int i; memset(result, 0, sizeof(result)); if (sendCmd(cmd, 6, NULL, 0, result, 0x2c, 1) != 0) { log_message(-2, "Inquiry command failed on \"%s\"", impl_->filename_); return 1; } strncpy(vendor_, (char *)(result + 0x08), 8); vendor_[8] = 0; strncpy(product_, (char *)(result + 0x10), 16); product_[16] = 0; strncpy(revision_, (char *)(result + 0x20), 4); revision_[4] = 0; // Remove all trailing spaces. for (i = 7; i >= 0 && vendor_[i] == ' '; i--) { vendor_[i] = 0; } for (i = 15; i >= 0 && product_[i] == ' '; i--) { product_[i] = 0; } for (i = 3; i >= 0 && revision_[i] == ' '; i--) { revision_[i] = 0; } return 0; } // Scan implementation uses sysfs to ScsiIf::ScanData *ScsiIf::scan(int *len, char* scsi_dev_path) { struct stat st; int matches = 0; unsigned i; ScanData* sdata = NULL; char* path = NULL; glob_t pglob; if (stat(SYSFS_SCSI_DEVICES, &st) != 0) { log_message(-2, "Unable to access sysfs filesystem at %s", SYSFS_SCSI_DEVICES); goto fail; } path = (char*)alloca(strlen(SYSFS_SCSI_DEVICES) + 64); sprintf(path, "%s/*", SYSFS_SCSI_DEVICES); if (glob(path, 0, NULL, &pglob) != 0) { log_message(-2, "No devices found"); goto fail; } sdata = new ScanData[pglob.gl_pathc]; for (i = 0; i < pglob.gl_pathc; i++) { int type; char rbuf[16]; FILE* f; sprintf(path, "%s/type", pglob.gl_pathv[i]); f = fopen(path, "r"); if (!f) continue; int ret = fscanf(f, "%d", &type); fclose(f); if (ret != 1 || type != TYPE_ROM) continue; // Now we have a CD-ROM device. memset(&sdata[matches].vendor, 0, sizeof(sdata[matches].vendor)); memset(&sdata[matches].product, 0, sizeof(sdata[matches].product)); memset(&sdata[matches].revision, 0, sizeof(sdata[matches].revision)); // Copy vendor data sprintf(path, "%s/vendor", pglob.gl_pathv[i]); f = fopen(path, "r"); if (!f) continue; if (fread(sdata[matches].vendor, 8, 1, f) != 1) { fclose(f); continue; } fclose(f); // Copy product data sprintf(path, "%s/model", pglob.gl_pathv[i]); f = fopen(path, "r"); if (!f) continue; if (fread(sdata[matches].product, 16, 1, f) != 1) { fclose(f); continue; } fclose(f); // Copy revision data sprintf(path, "%s/rev", pglob.gl_pathv[i]); f = fopen(path, "r"); if (!f) continue; if (fread(sdata[matches].revision, 4, 1, f) != 1) { fclose(f); continue; } fclose(f); // figure out the block device glob_t bglob; char* devname = NULL; sprintf(path, "%s/block:*", pglob.gl_pathv[i]); if (glob(path, 0, NULL, &bglob) == 0) { if (bglob.gl_pathc != 1) { globfree(&bglob); continue; } char* match = strrchr(bglob.gl_pathv[0], ':'); if (!match) { globfree(&bglob); continue; } devname = (char*)alloca(strlen(match)); strcpy(devname, match+1); } else { sprintf(path, "%s/block/*", pglob.gl_pathv[i]); if (glob(path, 0, NULL, &bglob) == 0) { if (bglob.gl_pathc != 1) { globfree(&bglob); continue; } char* match = strrchr(bglob.gl_pathv[0], '/'); devname = (char*)alloca(strlen(match)); strcpy(devname, match + 1); } } if (devname) { sdata[matches].dev = "/dev/"; sdata[matches].dev += devname; globfree(&bglob); } else { continue; } matches++; } globfree(&pglob); if (matches) { *len = matches; return sdata; } delete[] sdata; fail: *len = 0; return NULL; } #include "ScsiIf-common.cc" int ScsiIfImpl::adjustReservedBuffer(int requestedSize) { int maxTransferLength; if (ioctl(fd_, SG_SET_RESERVED_SIZE, &requestedSize) < 0) { log_message(-2, "SG_SET_RESERVED_SIZE ioctl failed: %s", strerror(errno)); return 0; } if (ioctl(fd_, SG_GET_RESERVED_SIZE, &maxTransferLength) < 0) { log_message(-2, "SG_GET_RESERVED_SIZE ioctl failed: %s", strerror(errno)); return 0; } log_message(4, "SG: Maximum transfer length: %ld", maxTransferLength); return maxTransferLength; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/ScsiIf-netbsd.cc����������������������������������������������������������0000664�0000000�0000000�00000021660�15114537466�0020412�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Native implementation of cdrdao's SCSI interface for NetBSD. * Copyright (C) by Edgar Fuß, Bonn, May 2003, July 2007. * Do with this whatever you like, as long as you are either me or you keep * this message intact and both * - acknowledge that I wrote it for cdrdao and NetBSD in the first place, and * - don't blame me if it doesn't do what you like or expect. * These routines do exactly what they do. If that's not what you expect them * or would like them to do, don't complain with me, the cdrdao project, my * neighbour's brother-in-law or anybody else, but rewrite them to your taste. */ #include <ctype.h> #include <string.h> #include <errno.h> #include <sys/scsiio.h> #include <fcntl.h> #include <sys/types.h> #include <dirent.h> /* avoid ../trackdb/util.h */ #include "/usr/include/util.h" #include <unistd.h> #include "ScsiIf.h" #include "log.h" /* can't include trackdb/util.h */ #include "decodeSense.cc" #define MAX_SCAN 32 class ScsiIfImpl { public: char *name_; int fd_; long timeout_; /* in ms */ struct scsireq screq_; char *error_; }; ScsiIf::ScsiIf(const char *name) { #define PREFIX "/dev/" int len; impl_ = new ScsiIfImpl; len = strlen(name); if (len == 0) { impl_->name_ = NULL; } else if (strncmp(name, "/", 1) == 0 || strncmp(name, "./", 2) == 0 || strncmp(name, "../", 3) == 0) { impl_->name_ = new char[len + 1]; strcpy(impl_->name_, name); } else if (isdigit(name[len-1]) && (strncmp(name, "sd", 2) == 0 || strncmp(name, "rsd", 3) == 0 || strncmp(name, "cd", 2) == 0 || strncmp(name, "rcd", 3) == 0)) { impl_->name_ = new char[strlen(PREFIX) + len + 1 + 1]; strcpy(impl_->name_, PREFIX); strcat(impl_->name_, name); impl_->name_[strlen(PREFIX) + len] = 'a' + getrawpartition(); impl_->name_[strlen(PREFIX) + len + 1] = '\0'; } else { impl_->name_ = new char[strlen(PREFIX) + len + 1]; strcpy(impl_->name_, PREFIX); strcat(impl_->name_, name); } impl_->fd_ = -1; impl_->timeout_ = 5*1000; impl_->error_ = NULL; maxDataLen_ = 64 * 1024; vendor_[0] = 0; product_[0] = 0; revision_[0] = 0; #undef PREFIX } ScsiIf::~ScsiIf() { if (impl_->fd_ >= 0) (void)close(impl_->fd_); if (impl_->name_ != NULL) delete[] impl_->name_; if (impl_->error_ != NULL) delete[] impl_->error_; delete impl_; } int ScsiIf::init() { if (impl_->name_ == NULL) return 1; if ((impl_->fd_ = open(impl_->name_, O_RDWR, 0)) < 0) { log_message(-2, "init: %s", strerror(errno)); return 1; } if (inquiry()) return 2; return 0; } int ScsiIf::timeout(int t) { int ret = impl_->timeout_/1000; impl_->timeout_ = t*1000; return ret; } // sends a scsi command and receives data // return 0: OK // 1: scsi command failed (os level, no sense data available) // 2: scsi command failed (sense data available) int ScsiIf::sendCmd(const unsigned char *cmd, int cmdLen, const unsigned char *dataOut, int dataOutLen, unsigned char *dataIn, int dataInLen, int showMessage) { #define ERROR(msg) {\ impl_->error_ = new char[9 + strlen(msg) + 1];\ strcpy(impl_->error_, "sendCmd: ");\ strcat(impl_->error_, msg);\ if (showMessage) printError();\ return 1;\ } if (impl_->error_ != NULL) { delete[] impl_->error_; impl_->error_ = NULL; } /* for printError: */ impl_->screq_.cmdlen = 0; impl_->screq_.databuf = NULL; impl_->screq_.datalen = 0; impl_->screq_.flags = 0; impl_->screq_.timeout = impl_->timeout_; if (cmdLen > 16) ERROR("cmdLen > 16"); if (cmdLen == 0) ERROR("cmdLen == 0"); memcpy(impl_->screq_.cmd, cmd, cmdLen); impl_->screq_.cmdlen = cmdLen; if (dataOut != NULL && dataIn != NULL) { ERROR("Out and In"); } else if (dataOut != NULL) { if (dataOutLen == 0) ERROR("dataOutLen == 0"); if (dataInLen != 0) ERROR("dataInLen != 0"); impl_->screq_.flags |= SCCMD_WRITE; impl_->screq_.databuf = (caddr_t)dataOut; impl_->screq_.datalen = dataOutLen; } else if (dataIn != NULL) { if (dataInLen == 0) ERROR("dataInLen == 0"); if (dataOutLen !=0) ERROR("dataOutLen != 0"); impl_->screq_.flags |= SCCMD_READ; impl_->screq_.databuf = (caddr_t)dataIn; impl_->screq_.datalen = dataInLen; } else { if (dataOutLen !=0 || dataInLen != 0) ERROR("dataLen != 0"); impl_->screq_.databuf = NULL; impl_->screq_.datalen = 0; } impl_->screq_.senselen = SENSEBUFLEN; if (ioctl(impl_->fd_, SCIOCCOMMAND, &impl_->screq_) < 0) { char str[80]; strcpy(str, "SCIOCOMMAND: "); strcat(str, strerror(errno)); ERROR(str); } if (impl_->screq_.retsts == SCCMD_OK && impl_->screq_.status == 0) return 0; else if (impl_->screq_.retsts == SCCMD_SENSE && impl_->screq_.status == 0) { if (showMessage) printError(); return 1; } else { if (showMessage) printError(); return 2; } #undef ERROR } const unsigned char *ScsiIf::getSense(int &len) const { len = impl_->screq_.senselen_used; return impl_->screq_.sense; } void ScsiIf::printError() { if (impl_->screq_.cmdlen > 0) { char s[80]; char *p = s; int i; p += snprintf(p, s + sizeof(s) - p, "CDB="); for (i = 0; i < impl_->screq_.cmdlen; i++) { p += snprintf(p, s + sizeof(s) - p, "%.2X ", impl_->screq_.cmd[i]); } p[-1] = ','; switch (impl_->screq_.flags & (SCCMD_READ | SCCMD_WRITE)) { case SCCMD_READ: p += snprintf(p, s + sizeof(s) - p, " RD"); break; case SCCMD_WRITE: p += snprintf(p, s + sizeof(s) - p, " WR"); break; case SCCMD_READ | SCCMD_WRITE: p += snprintf(p, s + sizeof(s) - p, " RW"); break; } p += snprintf(p, s + sizeof(s) - p, ", BUF=%p", impl_->screq_.databuf); p += snprintf(p, s + sizeof(s) - p, ", LEN=%lu", impl_->screq_.datalen); p += snprintf(p, s + sizeof(s) - p, ", TO=%lu", impl_->screq_.timeout); log_message(-2, s); } if (impl_->error_ != NULL) { log_message(-2, impl_->error_); } else switch (impl_->screq_.retsts) { case SCCMD_OK: switch (impl_->screq_.status) { case 0x00: log_message(-2, "GOOD"); break; case 0x02: log_message(-2, "CHECK CONDITION"); break; case 0x04: log_message(-2, "CONDITION MET"); break; case 0x08: log_message(-2, "BUSY"); break; case 0x10: log_message(-2, "INTERMEDIATE"); break; case 0x14: log_message(-2, "INTERMEDIATE, CONDITION MET"); break; case 0x18: log_message(-2, "RESERVATION CONFLICT"); break; case 0x22: log_message(-2, "COMMAND TERMINATED"); break; case 0x28: log_message(-2, "QUEUE FULL"); break; default: log_message(-2, "undefined status"); } break; case SCCMD_TIMEOUT: log_message(-2, "timeout"); break; case SCCMD_BUSY: log_message(-2, "busy"); break; case SCCMD_SENSE: decodeSense(impl_->screq_.sense, impl_->screq_.senselen_used); break; case SCCMD_UNKNOWN: log_message(-2, "unknown error"); break; default: log_message(-2, "undefined retsts"); break; } } int inq(int fd, char *vend, char *prod, char *rev) { char buf[44]; struct scsireq screq = { /* flags */ SCCMD_READ, /* timeout */ 1000, /* cmd */ {0x12, 0, 0, 0, sizeof(buf), 0}, /* cmdlen */ 6, /* databuf */ (caddr_t)&buf, /* datalen */ sizeof(buf), /* datalen_used */ 0, /* sense */ {}, /* senselen */ SENSEBUFLEN, /* senselen_used */ 0, /* status */ 0, /* retsts */ 0, /* error */ 0 }; char *p, *q; if (ioctl(fd, SCIOCCOMMAND, &screq) < 0 || screq.status != 0 || screq.retsts != SCCMD_OK) { vend[0] = prod[0] = rev[0] = '\0'; return 1; } p = buf + 8; q = buf + 16; while (q > p && q[-1] == ' ') q--; memcpy(vend, p, q - p); vend[q - p] = '\0'; p = buf + 16; q = buf + 32; while (q > p && q[-1] == ' ') q--; memcpy(prod, p, q - p); prod[q - p] = '\0'; p = buf + 32; q = buf + 36; while (q > p && q[-1] == ' ') q--; memcpy(rev, p, q - p); rev[q - p] = '\0'; return 0; } int ScsiIf::inquiry() { return inq(impl_->fd_, vendor_, product_, revision_); } ScsiIf::ScanData *ScsiIf::scan(int *len, char* scsi_dev_path) { DIR *dirp; struct dirent *dp; char c; int l; int fd; struct scsi_addr saddr; ScanData *scanData; char *s; scanData = new ScanData[MAX_SCAN]; *len = 0; c = 'a' + getrawpartition(); if ((dirp = opendir("/dev")) == 0) { *len = 0; return NULL; } while ((dp = readdir(dirp)) != NULL) { l = strlen(dp->d_name); if (*len < MAX_SCAN && l > 2 && (((strncmp(dp->d_name, "rsd", 3) == 0 || strncmp(dp->d_name, "rcd", 3) == 0) && isdigit(dp->d_name[l-2]) && dp->d_name[l-1] == c) || ((strncmp(dp->d_name, "enrst", 5) == 0 || strncmp(dp->d_name, "ch", 2) == 0 || strncmp(dp->d_name, "enss", 4) == 0 || strncmp(dp->d_name, "uk", 2) == 0) && isdigit(dp->d_name[l-1])))) { s = new char[5 + l + 1]; strcpy(s, "/dev/"); strcat(s, dp->d_name); if ((fd = open(s, O_RDWR, 0)) >= 0) { if (ioctl(fd, SCIOCIDENTIFY, &saddr) >= 0) { scanData[*len].dev = s; if (inq(fd, scanData[*len].vendor, scanData[*len].product, scanData[*len].revision) == 0) (*len)++; } (void)close(fd); } delete[] s; } } closedir(dirp); return scanData; } #include "ScsiIf-common.cc" ��������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/ScsiIf-nt.cc��������������������������������������������������������������0000664�0000000�0000000�00000015730�15114537466�0017555�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <andreas@daneb.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 * (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. */ #include "config.h" #include <windows.h> #include <ntddscsi.h> #include <stdio.h> #include <fcntl.h> #include <errno.h> #include <stddef.h> #include <string.h> #include <assert.h> #include <string> #include "ScsiIf.h" #include "log.h" #include "decodeSense.cc" typedef struct { SCSI_PASS_THROUGH_DIRECT sptd; ULONG Filler; // realign buffer to double word boundary UCHAR ucSenseBuf[32]; } SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER; typedef struct _SCSI_INQUIRY_DEVICE { UCHAR Type; UCHAR TypeModifier; UCHAR Version; UCHAR Format; UCHAR AddLength; // n-4 UCHAR Reserved[2]; UCHAR Flags; char VendorId[8]; char ProductId[16]; char ProductRevLevel[4]; char ProductRevDate[8]; } SCSI_INQUIRY_DEVICE; // // SCSI CDB operation codes // #define SCSIOP_INQUIRY 0x12 #define SCSIOP_MODE_SELECT 0x15 #define SCSIOP_MODE_SENSE 0x1A class ScsiIfImpl { public: std::string dev_; HANDLE hCD; SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb; unsigned char senseBuffer_[32]; int timeout_; }; ScsiIf::ScsiIf(const char *dev) { impl_ = new ScsiIfImpl; impl_->dev_ = "\\\\.\\"; impl_->dev_.append({dev[0]}); impl_->dev_.append(":"); impl_->timeout_ = 30; impl_->hCD = INVALID_HANDLE_VALUE; vendor_[0] = 0; product_[0] = 0; revision_[0] = 0; } ScsiIf::~ScsiIf() { if (impl_->hCD != INVALID_HANDLE_VALUE) CloseHandle (impl_->hCD); delete impl_; } // opens scsi device // return: 0: OK // 1: device could not be opened // 2: inquiry failed int ScsiIf::init() { int i = 0; DWORD ol; SCSI_ADDRESS sa; IO_SCSI_CAPABILITIES ca; while (i++ < 3 && (impl_->hCD == INVALID_HANDLE_VALUE)) { impl_->hCD = CreateFile (impl_->dev_.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); } if (impl_->hCD == INVALID_HANDLE_VALUE) { return 1; } if (DeviceIoControl (impl_->hCD, IOCTL_SCSI_GET_CAPABILITIES, NULL, 0, &ca, sizeof(IO_SCSI_CAPABILITIES), &ol, NULL)) { maxDataLen_ = ca.MaximumTransferLength; } else { // Pick sensible default, most drives won't honor the GET_CAP maxDataLen_ = 64 * 1024; } if (inquiry() != 0) return 2; return 0; } // Sets given timeout value in seconds and returns old timeout. // return: old timeout int ScsiIf::timeout (int t) { int old = impl_->timeout_; impl_->timeout_ = t; return old; } // sends a scsi command and receives data // return 0: OK // 1: scsi command failed (os level, no sense data available) // 2: scsi command failed (sense data available) int ScsiIf::sendCmd (const u8* cmd, int cmdLen, const u8 *dataOut, int dataOutLen, u8 *dataIn, int dataInLen, int showMessage) { int i = 10; DWORD er, il, ol; ZeroMemory (&impl_->sb, sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER)); impl_->sb.sptd.Length = sizeof(SCSI_PASS_THROUGH_DIRECT); impl_->sb.sptd.PathId = 0; impl_->sb.sptd.TargetId = 0; //impl_->scsi_id_; impl_->sb.sptd.Lun = 0; //impl_->lun_; impl_->sb.sptd.CdbLength = cmdLen; impl_->sb.sptd.SenseInfoLength = 32; impl_->sb.sptd.TimeOutValue = impl_->timeout_; impl_->sb.sptd.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf); memcpy (impl_->sb.sptd.Cdb, cmd, cmdLen); if (dataOut && dataOutLen) { impl_->sb.sptd.DataIn = SCSI_IOCTL_DATA_OUT; impl_->sb.sptd.DataBuffer = (void*)dataOut; impl_->sb.sptd.DataTransferLength = dataOutLen; } else { impl_->sb.sptd.DataIn = SCSI_IOCTL_DATA_IN; impl_->sb.sptd.DataBuffer = dataIn; impl_->sb.sptd.DataTransferLength = dataInLen; } il = sizeof (SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER); auto result = DeviceIoControl(impl_->hCD, IOCTL_SCSI_PASS_THROUGH_DIRECT, &impl_->sb, il, &impl_->sb, il, &ol, NULL); if (!result) { log_message(-2, "DeviceIoControl failed: %lu\n", GetLastError()); return 1; } if (impl_->sb.sptd.ScsiStatus != 0) return 2; return 0; } const unsigned char *ScsiIf::getSense(int &len) const { len = 32; return impl_->sb.ucSenseBuf; } void ScsiIf::printError() { decodeSense(impl_->sb.ucSenseBuf, 32); } int ScsiIf::inquiry() { unsigned char cmd[6]; int i; SCSI_INQUIRY_DEVICE NTinqbuf; ZeroMemory (&NTinqbuf, sizeof(SCSI_INQUIRY_DEVICE)); cmd[0] = 0x12; // INQUIRY cmd[1] = cmd[2] = cmd[3] = 0; cmd[4] = sizeof (NTinqbuf); cmd[5] = 0; if (sendCmd (cmd, 6, NULL, 0, (unsigned char *) &NTinqbuf, sizeof (NTinqbuf), 1) != 0) { log_message(-2, "Inquiry command failed on '%s'", impl_->dev_.c_str()); return 1; } strncpy(vendor_, (char *)(NTinqbuf.VendorId), 8); vendor_[8] = 0; strncpy(product_, (char *)(NTinqbuf.ProductId), 16); product_[16] = 0; strncpy(revision_, (char *)(NTinqbuf.ProductRevLevel), 4); revision_[4] = 0; for (i = 7; i >= 0 && vendor_[i] == ' '; i--) { vendor_[i] = 0; } for (i = 15; i >= 0 && product_[i] == ' '; i--) { product_[i] = 0; } for (i = 3; i >= 0 && revision_[i] == ' '; i--) { revision_[i] = 0; } return 0; } #include "ScsiIf-common.cc" ScsiIf::ScanData *ScsiIf::scan(int* len, char* scsi_dev_path) { ScanData* sdata = NULL; DWORD drive_mask = GetLogicalDrives(); std::vector<std::string> matches; if (drive_mask == 0) { log_message(0, "Error: Could not retrieve logical drives"); return NULL; } for (int i = 0; i < 26; i++) { if (drive_mask & (1 << i)) { std::string path; path.append({(char)('A' + i)}); path.append(":\\"); UINT drive_type = GetDriveType(path.c_str()); if (drive_type == DRIVE_CDROM) { matches.push_back(path); } } } if (matches.size() > 0) { *len = matches.size(); sdata = new ScanData[matches.size()]; for (int i = 0; i < matches.size(); i++) { ScsiIf sif(matches[i].c_str()); sif.init(); sdata[i].dev = matches[i]; strcpy(sdata[i].vendor, sif.vendor()); strcpy(sdata[i].product, sif.product()); strcpy(sdata[i].revision, sif.revision()); } } return sdata; } ����������������������������������������cdrdao-cdrdao-f00afb2/dao/ScsiIf-osx.cc�������������������������������������������������������������0000664�0000000�0000000�00000037222�15114537466�0017745�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Native implementation of cdrdao's SCSI interface for Mac OS X. * Copyright (C) by Edgar Fuß, Bonn, July 2007. * Do with this whatever you like, as long as you are either me or you keep * this message intact and both * - acknowledge that I wrote it for cdrdao in the first place, and * - don't blame me if it doesn't do what you like or expect. * These routines do exactly what they do. If that's not what you expect them * or would like them to do, don't complain with me, the cdrdao project, my * neighbour's brother-in-law or anybody else, but rewrite them to your taste. */ /* standard includes */ #include <stdio.h> #include <ctype.h> #include <string.h> /* cdrdao specific includes and prototype */ #include "ScsiIf.h" #include "trackdb/util.h" #include "log.h" #include "decodeSense.cc" /* Mac OS X specific includes */ #include <CoreFoundation/CFPlugInCOM.h> #include <IOKit/IOKitLib.h> #include <IOKit/scsi/SCSITaskLib.h> #include <IOKit/scsi/SCSICommandOperationCodes.h> #include <IOKit/scsi/SCSICmds_INQUIRY_Definitions.h> class ScsiIfImpl { public: int num_; /* number of device for compatibility mode */ char *path_; /* native (IO registry) pathname of device */ io_object_t object_; IOCFPlugInInterface **plugin_; MMCDeviceInterface **mmc_; SCSITaskDeviceInterface **scsi_; int exclusive_; long timeout_; /* in ms */ char *error_; /* sendCmd() internal error string */ SCSIServiceResponse response_; SCSITaskStatus status_; struct SCSI_Sense_Data sense_; }; ScsiIf::ScsiIf(const char *name) { int len; int bus, targ, lun, count; impl_ = new ScsiIfImpl; impl_->num_ = 0; impl_->path_ = NULL; len = strlen(name); if (len) { if (isdigit(name[0])) { /* Compatibility mode. Just add bus+targ+lun */ if (sscanf(name, "%i,%i,%i%n", &bus, &targ, &lun, &count) == 3 && count == len) { if ((bus >= 0) && (targ >= 0) && (lun >= 0)) impl_->num_ = 1 + bus + targ + lun; } } else { /* Native mode. Take name as IOreg path */ impl_->path_ = strdupCC(name); } } impl_->object_ = 0; impl_->plugin_ = NULL; impl_->mmc_ = NULL; impl_->scsi_ = NULL; impl_->exclusive_ = 0; impl_->timeout_ = 10*1000; impl_->error_ = NULL; vendor_[0] = 0; product_[0] = 0; revision_[0] = 0; maxDataLen_ = 64*1024; /* XXX */ } ScsiIf::~ScsiIf() { if (impl_->scsi_) { if (impl_->exclusive_) (*impl_->scsi_)->ReleaseExclusiveAccess(impl_->scsi_); (*impl_->scsi_)->Release(impl_->scsi_); } if (impl_->mmc_) (*impl_->mmc_)->Release(impl_->mmc_); if (impl_->plugin_) IODestroyPlugInInterface(impl_->plugin_); if (impl_->object_) IOObjectRelease(impl_->object_); if (impl_->path_ != NULL) delete[] impl_->path_; if (impl_->error_ != NULL) delete[] impl_->error_; delete impl_; } int ScsiIf::init() { CFMutableDictionaryRef dict = NULL; CFMutableDictionaryRef sub = NULL; io_iterator_t iterator = 0; kern_return_t err; SInt32 score; HRESULT herr; int i; if (impl_->num_) { /* * Compatibility mode. * Build dictionaries to search for num_'th device having the * authoring property using an IO iterator. */ dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, NULL); sub = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, NULL); CFDictionarySetValue(sub, CFSTR(kIOPropertySCSITaskDeviceCategory), CFSTR(kIOPropertySCSITaskAuthoringDevice)); CFDictionarySetValue(dict, CFSTR(kIOPropertyMatchKey), sub); IOServiceGetMatchingServices(kIOMainPortDefault, dict, &iterator); if (!iterator) log_message(3, "init: no iterator"); if (iterator) { i = impl_->num_; do { impl_->object_ = IOIteratorNext(iterator); i--; } while (i && impl_->object_); IOObjectRelease(iterator); } } else if (impl_->path_) { /* Native mode. Just use the IO Registry pathname */ impl_->object_ = IORegistryEntryFromPath(kIOMainPortDefault, impl_->path_); } /* Strange if (!x) ... if (x) style so you can #ifdef out the !x part */ if (!impl_->object_) log_message(-2, "init: no object"); if (impl_->object_) { /* Get intermediate (IOCFPlugIn) plug-in for MMC device */ err = IOCreatePlugInInterfaceForService(impl_->object_, kIOMMCDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &impl_->plugin_, &score); if (err != noErr) log_message(-2, "init: IOCreatePlugInInterfaceForService failed: %d", err); } if (!impl_->plugin_) log_message(-2, "init: no plugin"); if (impl_->plugin_) { /* Get the MMC interface (MMCDeviceInterface) */ herr = (*impl_->plugin_)->QueryInterface(impl_->plugin_, CFUUIDGetUUIDBytes(kIOMMCDeviceInterfaceID), /* * Most of Apple's examples erroneously cast to LPVOID, * not LPVOID *. */ (LPVOID *)&impl_->mmc_); if (herr != S_OK) log_message(-2, "init: QueryInterface failed: %d", herr); } if (!impl_->mmc_) log_message(-2, "init: no mmc"); if (impl_->mmc_) { /* Get the SCSI interface */ impl_->scsi_ = (*impl_->mmc_)->GetSCSITaskDeviceInterface(impl_->mmc_); } if (!impl_->scsi_) log_message(-2, "init: no scsi"); if (impl_->scsi_) { /* Obtain exclusive access to device */ err = (*impl_->scsi_)->ObtainExclusiveAccess(impl_->scsi_); if (err != noErr) log_message(-2, "Device already in use, please use diskutil to unmount the disc first"); if (err == noErr) { impl_->exclusive_ = 1; /* Send SCSI inquiry command */ i = inquiry(); if (i != 0) log_message(-2, "init: inquiry failed: %d", i); return (i == 0) ? 0 : 2; } } log_message(-2, "init: failed"); return 1; } int ScsiIf::timeout(int t) { int ret = impl_->timeout_/1000; impl_->timeout_ = t*1000; return ret; } int ScsiIf::sendCmd(const unsigned char *cmd, int cmdLen, const unsigned char *dataOut, int dataOutLen, unsigned char *dataIn, int dataInLen, int showMessage) { SCSITaskInterface **task; IOVirtualRange range; IOReturn ret; UInt64 len; if (impl_->error_ != NULL) { delete[] impl_->error_; impl_->error_ = NULL; } #define ERROR(msg) do {\ impl_->error_ = new char[9 + strlen(msg) + 1];\ strcpy(impl_->error_, "sendCmd: ");\ strcat(impl_->error_, msg);\ if (showMessage) printError();\ if (task) (*task)->Release(task);\ return 1;\ } while(0) task = (*impl_->scsi_)->CreateSCSITask(impl_->scsi_); if (!task) ERROR("no task"); ret = (*task)->SetCommandDescriptorBlock(task, (UInt8 *)cmd, cmdLen); if (ret != kIOReturnSuccess) ERROR("SetCommandDescriptorBlock failed"); /* The OSX SCSI interface can't deal with two data phases */ if (dataIn && dataOut) ERROR("dataIn && dataOut"); if (dataIn) { range.address = (IOVirtualAddress)dataIn; range.length = dataInLen; ret = (*task)->SetScatterGatherEntries(task, &range, 1, dataInLen, kSCSIDataTransfer_FromTargetToInitiator); } else if (dataOut) { range.address = (IOVirtualAddress)dataOut; range.length = dataOutLen; ret = (*task)->SetScatterGatherEntries(task, &range, 1, dataOutLen, kSCSIDataTransfer_FromInitiatorToTarget); } else { /* Just to make sure. We pass in zero ranges anyway */ range.address = (IOVirtualAddress)NULL; range.length = 0; ret = (*task)->SetScatterGatherEntries(task, &range, 0, 0, kSCSIDataTransfer_NoDataTransfer); } if (ret != kIOReturnSuccess) ERROR("SetScatterGatherEntries failed"); ret = (*task)->SetTimeoutDuration(task, impl_->timeout_); if (ret != kIOReturnSuccess) ERROR("SetTimeoutDuration failed"); ret = (*task)->ExecuteTaskSync(task, &impl_->sense_, &impl_->status_, &len); if (ret != kIOReturnSuccess) ERROR("ExecuteTaskSync failed"); ret = (*task)->GetSCSIServiceResponse(task, &impl_->response_); if (ret != kIOReturnSuccess) ERROR("GetSCSIServiceResponse failed"); (*task)->Release(task); if (impl_->response_ == kSCSIServiceResponse_TASK_COMPLETE) { if (impl_->status_ == kSCSITaskStatus_GOOD) return 0; if (impl_->status_ == kSCSITaskStatus_CHECK_CONDITION) return 2; } if (impl_->response_ == kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE) return 1; return 1 /* XXX This shouldn't happen */; #undef ERROR } const unsigned char *ScsiIf::getSense(int &len) const { len = kSenseDefaultSize; return (unsigned char *)&impl_->sense_; } void ScsiIf::printError() { const char *s; if (impl_->error_) /* Internal error in sendCmd(). We saved a message string. */ s = impl_->error_; else switch (impl_->response_) { case kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE: /* The SCSI command didn't complete */ switch (impl_->status_) { case kSCSITaskStatus_TaskTimeoutOccurred: s = "task timeout"; break; case kSCSITaskStatus_ProtocolTimeoutOccurred: s = "protocol timeout"; break; case kSCSITaskStatus_DeviceNotResponding: s = "device not responding"; break; case kSCSITaskStatus_DeviceNotPresent: s = "device not present"; break; case kSCSITaskStatus_DeliveryFailure: s = "delivery failure"; break; case kSCSITaskStatus_No_Status: s = "no status"; break; default: s = "failure, unknown status"; break; } break; case kSCSIServiceResponse_TASK_COMPLETE: /* The SCSI command did complete */ switch (impl_->status_) { case kSCSITaskStatus_GOOD: s = "good"; break; case kSCSITaskStatus_CHECK_CONDITION: decodeSense((unsigned char *)&impl_->sense_, sizeof(impl_->sense_)); s = NULL; break; case kSCSITaskStatus_CONDITION_MET: s = "condition met"; break; case kSCSITaskStatus_BUSY: s = "busy"; break; case kSCSITaskStatus_INTERMEDIATE: s = "intermediate"; break; case kSCSITaskStatus_INTERMEDIATE_CONDITION_MET: s = "intermediate, condition met"; break; case kSCSITaskStatus_RESERVATION_CONFLICT: s = "reservation conflict"; break; case kSCSITaskStatus_TASK_SET_FULL: s = "task set full"; break; case kSCSITaskStatus_ACA_ACTIVE: s = "aca active"; break; default: s = "complete, unknown status"; break; } break; default: s = "unknown response"; break; } if (s) log_message(-2, s); } /* * Internal form or inquiry command. * Used by both inquiry() and scanData(), but with different data. */ int inq(SCSITaskDeviceInterface **scsi, SCSIServiceResponse *response, SCSITaskStatus *status, struct SCSI_Sense_Data *sense, char *vend, char *prod, char *rev) { SCSICmd_INQUIRY_StandardData inq_data; SCSICommandDescriptorBlock cdb; SCSITaskInterface **task; IOVirtualRange range; IOReturn ret; UInt64 len; int i; task = (*scsi)->CreateSCSITask(scsi); if (!task) { log_message(-2, "inq: no task"); return 1; } bzero(cdb, sizeof(cdb)); cdb[0] = kSCSICmd_INQUIRY; cdb[4] = sizeof(inq_data); ret = (*task)->SetCommandDescriptorBlock(task, cdb, kSCSICDBSize_6Byte); if (ret != kIOReturnSuccess) { log_message(-2, "inq: SetCommandDescriptorBlock failed: %d", ret); (*task)->Release(task); return 1; } range.address = (IOVirtualAddress)&inq_data; range.length = sizeof(inq_data); ret = (*task)->SetScatterGatherEntries(task, &range, 1, sizeof(inq_data), kSCSIDataTransfer_FromTargetToInitiator); if (ret != kIOReturnSuccess) { log_message(-2, "inq: SetScatterGatherEntries failed: %d", ret); (*task)->Release(task); return 1; } ret = (*task)->SetTimeoutDuration(task, 1000); if (ret != kIOReturnSuccess) { log_message(-2, "inq: SetTimeoutDuration failed: %d", ret); (*task)->Release(task); return 1; } ret = (*task)->ExecuteTaskSync(task, sense, status, &len); if (ret != kIOReturnSuccess) { log_message(-2, "inq: ExecuteTaskSync failed: %d", ret); (*task)->Release(task); return 1; } ret = (*task)->GetSCSIServiceResponse(task, response); if (ret != kIOReturnSuccess) { log_message(-2, "inq: GetSCSIServiceResponse failed: %d", ret); (*task)->Release(task); return 1; } if (*response != kSCSIServiceResponse_TASK_COMPLETE) { log_message(-2, "inq: response=%d", *response); (*task)->Release(task); return 1; } if (*status != kSCSITaskStatus_GOOD) { log_message(-2, "inq: status=%d", *status); (*task)->Release(task); return 1; } (*task)->Release(task); /* Copy vendor/product/revision stripping traiiling spaces */ i = kINQUIRY_VENDOR_IDENTIFICATION_Length; while (i > 0 && inq_data.VENDOR_IDENTIFICATION[i - 1] == ' ') i--; memcpy(vend, inq_data.VENDOR_IDENTIFICATION, i); vend[i] = '\0'; i = kINQUIRY_PRODUCT_IDENTIFICATION_Length; while (i > 0 && inq_data.PRODUCT_IDENTIFICATION[i - 1] == ' ') i--; memcpy(prod, inq_data.PRODUCT_IDENTIFICATION, i); prod[i] = '\0'; i = kINQUIRY_PRODUCT_REVISION_LEVEL_Length; while (i > 0 && inq_data.PRODUCT_REVISION_LEVEL[i - 1] == ' ') i--; memcpy(rev, inq_data.PRODUCT_REVISION_LEVEL, i); rev[i] = '\0'; return 0; } int ScsiIf::inquiry() { return inq(impl_->scsi_, &impl_->response_, &impl_->status_, &impl_->sense_, vendor_, product_, revision_); } #define MAX_SCAN 10 ScsiIf::ScanData *ScsiIf::scan(int *len, char *dev) { ScanData *scanData; CFMutableDictionaryRef dict = NULL; CFMutableDictionaryRef sub = NULL; io_iterator_t iterator = 0; io_object_t object = 0; IOCFPlugInInterface **plugin = NULL; MMCDeviceInterface **mmc = NULL; SCSITaskDeviceInterface **scsi = NULL; SCSIServiceResponse response; SCSITaskStatus status; int exclusive = 0; io_string_t path; kern_return_t err; SInt32 score; HRESULT herr; int ret; int i; /* Ignore dev. We don't support different kinds of busses that way. */ /* Build matching dictionaries to find authoring decices. See init(). */ dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, NULL); sub = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, NULL); CFDictionarySetValue(sub, CFSTR(kIOPropertySCSITaskDeviceCategory), CFSTR(kIOPropertySCSITaskAuthoringDevice)); CFDictionarySetValue(dict, CFSTR(kIOPropertyMatchKey), sub); IOServiceGetMatchingServices(kIOMainPortDefault, dict, &iterator); if (!iterator) { log_message(3, "scan: no iterator"); *len = 0; return NULL; } scanData = new ScanData[MAX_SCAN]; *len = 0; for (i = 0; ; i++) { object = IOIteratorNext(iterator); if (!object) break; if (*len == MAX_SCAN) break; /* Get native (IO Registry) pathname of this device. */ err = IORegistryEntryGetPath(object, kIOServicePlane, path); if (err == noErr) { scanData[*len].dev = strdupCC(path); } /* See init() for a description of the plugin/interface tour. */ err = IOCreatePlugInInterfaceForService(object, kIOMMCDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugin, &score); if (err != noErr) { log_message(-2, "scan: IOCreatePlugInInterfaceForService failed: %d", err); goto clean; } if (!plugin) { log_message(-2, "scan: no plugin"); goto clean; } herr = (*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOMMCDeviceInterfaceID), (LPVOID *)&mmc); if (herr != S_OK) { log_message(-2, "scan: QueryInterface failed: %d", herr); goto clean; } if (!mmc) { log_message(-2, "scan: no mmc"); goto clean; } scsi = (*mmc)->GetSCSITaskDeviceInterface(mmc); if (!scsi) { log_message(-2, "scan: no scsi"); goto clean; } err = (*scsi)->ObtainExclusiveAccess(scsi); if (err != noErr) { log_message(-2, "Device already in use, please use diskutil to unmount the disc first"); goto clean; } ret = inq(scsi, &response, &status, NULL, scanData[*len].vendor, scanData[*len].product, scanData[*len].revision); if (ret != 0) { log_message(-2, "scan: inq failed: %d", ret); goto clean; } (*len)++; clean: if (exclusive) (*scsi)->ReleaseExclusiveAccess(scsi); if (scsi) (*scsi)->Release(scsi); if (mmc) (*mmc)->Release(mmc); if (plugin) IODestroyPlugInInterface(plugin); if (object) IOObjectRelease(object); } IOObjectRelease(iterator); return scanData; } #include "ScsiIf-common.cc" ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/ScsiIf.h������������������������������������������������������������������0000664�0000000�0000000�00000012645�15114537466�0017002�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998, 1999 Andreas Mueller <mueller@daneb.ping.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 * (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. */ // \file ScsiIf.h // \brief Low level SCSI interface. #ifndef __SCSIIF_H__ #define __SCSIIF_H__ #include <stdlib.h> #include <string> #include "util.h" typedef struct { unsigned char p_len; unsigned cd_r_read : 1; unsigned cd_rw_read : 1; unsigned method2 : 1; unsigned dvd_rom_read : 1; unsigned dvd_r_read : 1; unsigned dvd_ram_read : 1; unsigned res_2_67 : 2; unsigned cd_r_write : 1; unsigned cd_rw_write : 1; unsigned test_write : 1; unsigned res_3_3 : 1; unsigned dvd_r_write : 1; unsigned dvd_ram_write : 1; unsigned res_3_67 : 2; } cd_page_2a; class ScsiIfImpl; //! \brief Base class to communicate with SCSI device class ScsiIf { public: //! \brief Constructor. Does not do SCSI initialization. // // Sets up some internal data and gets page size. ScsiIf(const char *dev); ~ScsiIf(); //! \brief Accessor method: vendor string of the device. const char *vendor() const { return vendor_; } //! \brief Accessor method: product string of the device. const char *product() const { return product_; } //! \brief Accessor method: revision string of the device. const char *revision() const { return revision_; } //! \brief Accessor method: SCSI bus this device is connected to. const int bus (); //! \brief Accessor method: SCSI ID of the device. const int id (); /*! \brief Accessor method: SCSI LUN of the device. */ const int lun (); //! \brief Opens the scsi device. Issues an inquiry to test the // communication. Gets max DMA transfer length. // // \return int // - 0 OK // - 1 device could not be opened // - 2 inquiry failed int init(); // \brief Accessor method: returns max DMA transfer length. int maxDataLen() const { return maxDataLen_; } //! \brief Sends a SCSI command and receives data // \param cmd Buffer with CDB // \param cmdLen Length of CDB // \param dataOut Output buffer from the command, preallocated, // will be overwritten // \param dataOutLen Length of preallocated output // buffer. dataOutLen or dataInLen must be 0. // \param dataIn Input buffer to the command, containing // parameters to the command // \param dataInLen Length of input buffer. dataOutLen or // dataInLen must be 0. // \param showMessage If 0 makes it silent. If 1 verbose // command execution. // \return int // - 0 OK // - 1 scsi command failed (os level, no sense data available) // - 2 scsi command failed (sense data available) int sendCmd(const u8 *cmd, int cmdLen, const u8 *dataOut, int dataOutLen, u8 *dataIn, int dataInLen, int showMessage = 1); //! \brief Return the actual sense buffer // \param len will be overwritten and contain // the length of returned buffer. // \return buffer contains last sense data available. The // buffer is owned and must not be freed. const u8 *getSense(int &len) const; //! \brief Prints extended status information of the last SCSI command. // Prints the following SCSI codes: // - command transport status // - CDB // - SCSI status byte // - Sense Bytes // - Decoded Sense data // - DMA status // - SCSI timing // void printError(); //! \brief Sets new timeout (seconds) and returns old timeout. int timeout(int); //! \brief Issues TEST UNIT READY command // \return int // - 0 OK, ready // - 1 not ready (busy, default case when TUR command fails, // except when there's no disk in drive, see below) // - 2 not ready, no disk in drive // - 3 scsi command failed at OS level, no sense available int testUnitReady(); //! \brief Check for mmc capability. Return whether the //driver/drive can read and write CD-R and CD-RW disks. cd_page_2a* checkMmc(); struct ScanData { std::string dev; // This is crazy, but the schily header #define vendor, product // and revision. Talk about namespace pollution... char vendor[9]; char product[17]; char revision[5]; }; //! Scans for all SCSI devices and returns a newly allocated // 'ScanData' array. static ScanData *scan(int *len, char* scsi_dev_path = NULL); private: char vendor_[9]; char product_[17]; char revision_[5]; int maxDataLen_; // \brief Standard INQUIRY command used to fill ScsiIf::vendor_ , // ScsiIf::product_ , ScsiIf::revision_ // \return int // - 0 if all right // - 1 if INQUIRY command failed int inquiry(); ScsiIfImpl *impl_; }; #endif �������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/Settings.cc���������������������������������������������������������������0000664�0000000�0000000�00000016611�15114537466�0017555�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <andreas@daneb.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 * (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. */ #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <assert.h> #include <sstream> #include "Settings.h" #include "util.h" #include "log.h" using namespace std; #ifdef UNIXWARE extern "C" { extern int strcasecmp(const char *, const char *); } #endif enum SettingType { SET_INTEGER, SET_STRING }; const char* Settings::setWriteSpeed = "write_speed"; const char* Settings::setWriteDriver = "write_driver"; const char* Settings::setWriteDevice = "write_device"; const char* Settings::setWriteBuffers = "write_buffers"; const char* Settings::setUserCapacity = "user_capacity"; const char* Settings::setFullBurn = "full_burn"; const char* Settings::setReadSpeed = "read_speed"; const char* Settings::setReadDriver = "read_driver"; const char* Settings::setReadDevice = "read_device"; const char* Settings::setReadParanoiaMode = "read_paranoia_mode"; const char* Settings::setCddbServerList = "cddb_server_list"; const char* Settings::setCddbTimeout = "cddb_timeout"; const char* Settings::setCddbDbDir = "cddb_directory"; const char* Settings::setTmpFileDir = "tmp_file_dir"; class SettingEntry { public: SettingEntry(const char *, int); SettingEntry(const char *, const char *); ~SettingEntry(); SettingType type_; char *name_; union { int integerValue_; char *stringValue_; } val_; SettingEntry *next_; }; class SettingsImpl { public: SettingsImpl(); ~SettingsImpl(); void addSetting(SettingEntry *); SettingEntry *findSetting(const char *, SettingType); void set(const char *, int); void set(const char *, const char *); int read(FILE *); void parseAndSetValue(char *name, char *valStr); SettingEntry *settings_; }; SettingEntry::SettingEntry(const char *name, int val) { type_ = SET_INTEGER; name_ = strdupCC(name); val_.integerValue_ = val; } SettingEntry::SettingEntry(const char *name, const char *val) { type_ = SET_STRING; name_ = strdupCC(name); val_.stringValue_ = strdupCC(val); } SettingEntry::~SettingEntry() { delete[] name_; name_ = NULL; if (type_ == SET_STRING) { delete[] val_.stringValue_; val_.stringValue_ = NULL; } } SettingsImpl::SettingsImpl() { settings_ = NULL; } SettingsImpl::~SettingsImpl() { SettingEntry *next; while (settings_ != NULL) { next = settings_->next_; delete settings_; settings_ = next; } } void SettingsImpl::addSetting(SettingEntry *s) { s->next_ = settings_; settings_ = s; } SettingEntry *SettingsImpl::findSetting(const char *name, SettingType type) { SettingEntry *run; for (run = settings_; run != NULL; run = run->next_) { if (run->type_ == type && strcasecmp(run->name_, name) == 0) return run; } return NULL; } void SettingsImpl::set(const char *name, int val) { SettingEntry *s = findSetting(name, SET_INTEGER); if (s == NULL) { addSetting(new SettingEntry(name, val)); } else { s->val_.integerValue_ = val; } } void SettingsImpl::set(const char *name, const char *val) { SettingEntry *s = findSetting(name, SET_STRING); if (s == NULL) { addSetting(new SettingEntry(name, val)); } else { delete[] s->val_.stringValue_; s->val_.stringValue_ = strdupCC(val); } } #define MAX_LINE_LENGTH 1024 int SettingsImpl::read(FILE *fp) { char buf[MAX_LINE_LENGTH]; char *p, *p1; char *name; long n; while (fgets(buf, MAX_LINE_LENGTH, fp) != NULL) { // handle comment if ((p = strchr(buf, '#')) != NULL) continue; if ((p = strchr(buf, ':')) != NULL) { *p++ = 0; p1 = buf; while (*p1 != 0 && isspace(*p1)) p1++; name = p1; while (*p1 != 0 && !isspace(*p1)) p1++; *p1 = 0; while (*p != 0 && isspace(*p)) p++; // strip off trailing white space if ((n = strlen(p)) > 0) { for (p1 = p + n - 1; p1 >= p; p1--) { if (isspace(*p1)) { *p1 = 0; } } } parseAndSetValue(name, p); } } return 0; } void SettingsImpl::parseAndSetValue(char *name, char *valStr) { char *p; char *val; int intValue; if (name == NULL || *name == 0 || valStr == NULL || *valStr == 0) return; if (*valStr == '"') { val = valStr + 1; p = val + strlen(val)-1; if (*p != '"') { fprintf(stderr,"Error in string constant '%s'\n", valStr); } else { *p=0; set(name, val); } } else { /* valSTR is numeric? */ char * end = NULL; errno=0; intValue = strtol(valStr, &end, 0); if(errno != 0 || !end || *end) { fprintf(stderr,"Error parsing numeric option '%s' (missing quotes?)\n", valStr); } else set(name, intValue); } } Settings::Settings() { impl_ = new SettingsImpl; } Settings::~Settings() { delete impl_; impl_ = NULL; } int Settings::read(const char *fname) { FILE *fp; if ((fp = fopen(fname, "r")) == NULL) return 1; impl_->read(fp); fclose(fp); return 0; } int Settings::write(const char *fname) const { SettingEntry *run; FILE *fp; if ((fp = fopen(fname, "w")) == NULL) { log_message(-2, "Cannot open \"%s\" for writing: %s", fname, strerror(errno)); return 1; } for (run = impl_->settings_; run != NULL; run = run->next_) { switch (run->type_) { case SET_INTEGER: fprintf(fp, "%s: %d\n", run->name_, run->val_.integerValue_); break; case SET_STRING: fprintf(fp, "%s: \"%s\"\n", run->name_, run->val_.stringValue_); break; } } fclose(fp); return 0; } const int *Settings::getInteger(const char *name) const { SettingEntry *s = impl_->findSetting(name, SET_INTEGER); if (s != NULL) return &(s->val_.integerValue_); else return NULL; } const char *Settings::getString(const char *name) const { SettingEntry *s = impl_->findSetting(name, SET_STRING); if (s != NULL) return s->val_.stringValue_; else return NULL; } bool Settings::getStrings(const char* name, vector<string>& strings) const { const char* entry = getString(name); if (!entry) return false; string parsed; stringstream iss(entry); while (getline(iss, parsed, ';')) strings.push_back(parsed); return true; } void Settings::set(const char *name, int val) { impl_->set(name, val); } void Settings::set(const char *name, const char *val) { impl_->set(name, val); } void Settings::set(const char* name, const vector<string>& strings) { string accu; for (const auto& s : strings) { if (accu.size()) accu += ";"; accu += s; } set(name, accu.c_str()); } �����������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/Settings.h����������������������������������������������������������������0000664�0000000�0000000�00000003614�15114537466�0017416�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <andreas@daneb.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 * (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. */ #ifndef __SETTINGS_H__ #define __SETTINGS_H__ #include <string> #include <vector> class Settings { public: Settings(); ~Settings(); int read(const char *); int write(const char *) const; const int *getInteger(const char *) const; const char *getString(const char *) const; bool getStrings(const char *, std::vector<std::string>& strings) const; void set(const char *, int); void set(const char *, const char *); void set(const char *, const std::vector<std::string>& strings); // Key name definitions static const char* setWriteSpeed; static const char* setWriteDriver; static const char* setWriteDevice; static const char* setWriteBuffers; static const char* setUserCapacity; static const char* setFullBurn; static const char* setReadSpeed; static const char* setReadDriver; static const char* setReadDevice; static const char* setReadParanoiaMode; static const char* setCddbServerList; static const char* setCddbTimeout; static const char* setCddbDbDir; static const char* setTmpFileDir; private: class SettingsImpl *impl_; }; #endif ��������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/SonyCDU920.cc�������������������������������������������������������������0000664�0000000�0000000�00000054110�15114537466�0017470�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <andreas@daneb.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 * (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. */ #include <config.h> #include <string.h> #include <assert.h> #include <unistd.h> #include "SonyCDU920.h" #include "port.h" #include "Toc.h" #include "log.h" #include "PQSubChannel16.h" SonyCDU920::SonyCDU920(ScsiIf *scsiIf, unsigned long options) : CdrDriver(scsiIf, options) { int i; driverName_ = "Sony CDU920 - Version 0.1 (data) (alpha)"; speed_ = 2; simulate_ = true; encodingMode_ = 1; scsiTimeout_ = 0; leadInLen_ = 0; for (i = 0; i < maxScannedSubChannels_; i++) { scannedSubChannels_[i] = new PQSubChannel16; } // reads little endian samples audioDataByteOrder_ = 0; } SonyCDU920::~SonyCDU920() { int i; for (i = 0; i < maxScannedSubChannels_; i++) { delete scannedSubChannels_[i]; scannedSubChannels_[i] = NULL; } } // static constructor CdrDriver *SonyCDU920::instance(ScsiIf *scsiIf, unsigned long options) { return new SonyCDU920(scsiIf, options); } int SonyCDU920::bigEndianSamples() const { return 0; // drive takes little endian samples } int SonyCDU920::multiSession(int m) { return 1; // not supported in DAO mode } // sets speed // return: 0: OK // 1: illegal speed int SonyCDU920::speed(int s) { if (s >= 0 && s <= 2) speed_ = s; else if (s > 2) speed_ = 2; else return 1; return 0; } // loads ('unload' == 0) or ejects ('unload' == 1) tray // return: 0: OK // 1: scsi command failed int SonyCDU920::loadUnload(int unload) const { unsigned char cmd[6]; memset(cmd, 0, 6); cmd[0] = 0x1b; // START/STOP UNIT if (unload) { cmd[4] = 0x02; // LoUnlo=1, Start=0 } else { cmd[4] = 0x01; // LoUnlo=0, Start=1 } if (sendCmd(cmd, 6, NULL, 0, NULL, 0) != 0) { log_message(-2, "Cannot load/unload medium."); return 1; } return 0; } // sets read/write speed and simulation mode // return: 0: OK // 1: scsi command failed int SonyCDU920::selectSpeed() { unsigned char mp[4]; mp[0] = 0x31; mp[1] = 2; mp[2] = 0; mp[3] = 0; switch (speed_) { case 0: mp[2] = 0xff; case 1: mp[2] = 0; break; case 2: mp[2] = 1; break; } if (setModePage6(mp, NULL, NULL, 1) != 0) { log_message(-2, "Cannot set speed mode page."); return 1; } return 0; } // Determins start and length of lead-in. // return: 0: OK // 1: SCSI command failed int SonyCDU920::getSessionInfo() { unsigned char mp[32]; if (getModePage6(0x22, mp, 32, NULL, NULL, 1) != 0) { log_message(-2, "Cannot retrieve CD-R disc information mode page."); return 1; } leadInStart_ = Msf(mp[25], mp[26], mp[27]); if (leadInStart_.lba() != 0) leadInLen_ = 450000 - leadInStart_.lba(); else leadInLen_ = 0; log_message(4, "Lead-in start: %s length: %ld", leadInStart_.str(), leadInLen_); return 0; } // Sets write parameters. // return: 0: OK // 1: scsi command failed int SonyCDU920::setWriteParameters() { unsigned char mp[32]; memset(mp, 0, 8); mp[0] = 0x20; mp[1] = 6; mp[3] = (simulate_ != 0) ? 2 : 0; if (setModePage6(mp, NULL, NULL, 1) != 0) { log_message(-2, "Cannot set CD-R mastering information page."); return 1; } memset(mp, 0, 32); if (getModePage6(0x22, mp, 32, NULL, NULL, 1) != 0) { log_message(-2, "Cannot retrieve CD-R disc information page."); return 1; } mp[0] &= 0x7f; // clear PS flag mp[2] = 0; // Disc Style: uninterrupted mp[3] = sessionFormat(); // Disc Type: from 'toc_' object mp[19] = 0; // no automatic post-gap; required? if (setModePage6(mp, NULL, NULL, 1) != 0) { log_message(-2, "Cannot set CD-R disc information page."); return 1; } return 0; } // Creates cue sheet for current 'toc_' object. // cueSheetLen: filled with length of cue sheet in bytes // return: newly allocated cue sheet buffer or 'NULL' on error unsigned char *SonyCDU920::createCueSheet(unsigned char leadInDataForm, long *cueSheetLen) { const Track *t; int trackNr; Msf start, end, index; unsigned char *cueSheet; long len; long n; // index into cue sheet unsigned char ctl; // control nibbles of cue sheet entry CTL/ADR long i; unsigned char dataMode; int firstTrack; TrackIterator itr(toc_); if (itr.first(start, end) == NULL) { return NULL; } // determine length of cue sheet len = 3; // entries for lead-in, 1st pre-gap, lead-out for (t = itr.first(start, end), trackNr = 1; t != NULL; t = itr.next(start, end), trackNr++) { len += 1; // entry for track if (t->start().lba() != 0 && trackNr > 1) { len += 1; // entry for pre-gap } len += t->nofIndices(); // entry for each index increment } cueSheet = new unsigned char[len * 8]; n = 0; // entry for lead-in ctl = (toc_->leadInMode() == TrackData::AUDIO) ? 0 : 0x40; cueSheet[n*8] = 0x01 | ctl; // CTL/ADR cueSheet[n*8+1] = 0; // Track number cueSheet[n*8+2] = 0; // Index cueSheet[n*8+3] = leadInDataForm; cueSheet[n*8+4] = 0; // Serial Copy Management System cueSheet[n*8+5] = 0; // MIN cueSheet[n*8+6] = sessionFormat(); // disc type cueSheet[n*8+7] = 0; // FRAME n++; firstTrack = 1; for (t = itr.first(start, end), trackNr = 1; t != NULL; t = itr.next(start, end), trackNr++) { switch (t->type()) { case TrackData::AUDIO: dataMode = 0x01; break; case TrackData::MODE1: case TrackData::MODE1_RAW: dataMode = 0x11; break; case TrackData::MODE2: dataMode = 0x19; break; case TrackData::MODE2_RAW: case TrackData::MODE2_FORM1: case TrackData::MODE2_FORM2: case TrackData::MODE2_FORM_MIX: dataMode = 0x23; break; default: dataMode = 0; break; } ctl = 0; if (t->copyPermitted()) { ctl |= 0x20; } if (t->type() == TrackData::AUDIO) { // audio track if (t->preEmphasis()) { ctl |= 0x10; } if (t->audioType() == 1) { ctl |= 0x80; } } else { // data track ctl |= 0x40; } Msf tstart(start.lba() + 150); // start of index 1 of current track if (firstTrack) { // entry for pre-gap before first track cueSheet[n*8] = ctl | 0x01; cueSheet[n*8+1] = SubChannel::bcd(trackNr); cueSheet[n*8+2] = 0; // Index 0 cueSheet[n*8+3] = dataMode; // Data Form cueSheet[n*8+4] = 0; // Serial Copy Management System cueSheet[n*8+5] = 0; // MIN 0 cueSheet[n*8+6] = 0; // SEC 0 cueSheet[n*8+7] = 0; // FRAME 0 n++; } else if (t->start().lba() != 0) { // entry for pre-gap Msf pstart(tstart.lba() - t->start().lba()); cueSheet[n*8] = ctl | 0x01; cueSheet[n*8+1] = SubChannel::bcd(trackNr); cueSheet[n*8+2] = 0; // Index 0: pre-gap cueSheet[n*8+3] = dataMode; // Data Form cueSheet[n*8+4] = 0; // no alternate copy bit cueSheet[n*8+5] = SubChannel::bcd(pstart.min()); cueSheet[n*8+6] = SubChannel::bcd(pstart.sec()); cueSheet[n*8+7] = SubChannel::bcd(pstart.frac()); n++; } cueSheet[n*8] = ctl | 0x01; cueSheet[n*8+1] = SubChannel::bcd(trackNr); cueSheet[n*8+2] = 1; // Index 1 cueSheet[n*8+3] = dataMode; // Data Form cueSheet[n*8+4] = 0; // no alternate copy bit cueSheet[n*8+5] = SubChannel::bcd(tstart.min()); cueSheet[n*8+6] = SubChannel::bcd(tstart.sec()); cueSheet[n*8+7] = SubChannel::bcd(tstart.frac()); n++; for (i = 0; i < t->nofIndices(); i++) { index = tstart + t->getIndex(i); cueSheet[n*8] = ctl | 0x01; cueSheet[n*8+1] = SubChannel::bcd(trackNr); cueSheet[n*8+2] = SubChannel::bcd(i + 2); // Index cueSheet[n*8+3] = dataMode; // Data Form cueSheet[n*8+4] = 0; // no alternate copy bit cueSheet[n*8+5] = SubChannel::bcd(index.min()); cueSheet[n*8+6] = SubChannel::bcd(index.sec()); cueSheet[n*8+7] = SubChannel::bcd(index.frac()); n++; } firstTrack = 0; } assert(n == len - 1); // entry for lead out Msf lostart(toc_->length().lba() + 150); ctl = (toc_->leadOutMode() == TrackData::AUDIO) ? 0 : 0x40; cueSheet[n*8] = ctl | 0x01; cueSheet[n*8+1] = 0xaa; cueSheet[n*8+2] = 1; // Index 1 cueSheet[n*8+3] = 0x00; // CD-DA data, data generated by device cueSheet[n*8+4] = 0; // no alternate copy bit cueSheet[n*8+5] = SubChannel::bcd(lostart.min()); cueSheet[n*8+6] = SubChannel::bcd(lostart.sec()); cueSheet[n*8+7] = SubChannel::bcd(lostart.frac()); log_message(4, "\nCue Sheet:"); log_message(4, "CTL/ TNO INDEX DATA SCMS MIN SEC FRAME"); log_message(4, "ADR FORM BCD BCD BCD"); for (n = 0; n < len; n++) { log_message(4, "%02x %02x %02x %02x %02x %02x %02x %02x", cueSheet[n*8], cueSheet[n*8+1], cueSheet[n*8+2], cueSheet[n*8+3], cueSheet[n*8+4], cueSheet[n*8+5], cueSheet[n*8+6], cueSheet[n*8+7]); } *cueSheetLen = len * 8; return cueSheet; } int SonyCDU920::sendCueSheet(unsigned char leadInDataForm) { unsigned char cmd[10]; long cueSheetLen; unsigned char *cueSheet = createCueSheet(leadInDataForm, &cueSheetLen); if (cueSheet == NULL) { return 1; } if (cueSheetLen > 3600) { log_message(-2, "Cue sheet too big. Please remove index marks."); delete[] cueSheet; return 1; } memset(cmd, 0, 10); cmd[0] = 0xe0; // WRITE START cmd[1] = (cueSheetLen >> 16) & 0x0f; cmd[2] = cueSheetLen >> 8; cmd[3] = cueSheetLen; if (sendCmd(cmd, 10, cueSheet, cueSheetLen, NULL, 0) != 0) { log_message(-2, "Cannot send cue sheet."); delete[] cueSheet; return 1; } delete[] cueSheet; return 0; } int SonyCDU920::readBufferCapacity(long *capacity) { unsigned char cmd[10]; unsigned char data[8]; memset(cmd, 0, 10); memset(data, 0, 8); cmd[0] = 0xec; // READ BUFFER CAPACITY if (sendCmd(cmd, 10, NULL, 0, data, 8) != 0) { log_message(-2, "Read buffer capacity failed."); return 1; } *capacity = (data[5] << 16) | (data[6] << 8) | data[7]; return 0; } int SonyCDU920::initDao(const Toc *toc) { long n; toc_ = toc; blockLength_ = AUDIO_BLOCK_LEN; blocksPerWrite_ = scsiIf_->maxDataLen() / blockLength_; assert(blocksPerWrite_ > 0); if (selectSpeed() != 0 || getSessionInfo() != 0) { return 1; } // allocate buffer for writing zeros n = blocksPerWrite_ * blockLength_; delete[] zeroBuffer_; zeroBuffer_ = new char[n]; memset(zeroBuffer_, 0, n); return 0; } int SonyCDU920::startDao() { scsiTimeout_ = scsiIf_->timeout(3 * 60); if (setWriteParameters() != 0 || sendCueSheet(0x00/* Data Form: CD-DA, generate data by device */) != 0) return 1; long lba = -150; // write mandatory pre-gap after lead-in if (writeZeros(toc_->leadInMode(), TrackData::SUBCHAN_NONE, lba, 0, 150) != 0) { return 1; } return 0; } int SonyCDU920::finishDao() { scsiIf_->timeout(scsiTimeout_); delete[] zeroBuffer_, zeroBuffer_ = NULL; return 0; } void SonyCDU920::abortDao() { unsigned char cmd[10]; memset(cmd, 0, 10); cmd[0] = 0xe2; // DISCONTINUE sendCmd(cmd, 10, NULL, 0, NULL, 0, 1); } // Writes data to target, the block length depends on the actual track 'mode'. // 'len' is number of blocks to write. // 'lba' specifies the next logical block address for writing and is updated // by this function. // return: 0: OK // 1: scsi command failed int SonyCDU920::writeData(TrackData::Mode mode, TrackData::SubChannelMode sm, long &lba, const char *buf, long len) { assert(blocksPerWrite_ > 0); unsigned char cmd[10]; int writeLen = 0; long blockLength = blockSize(mode, TrackData::SUBCHAN_NONE); long byteLen; int ret; #if 0 long sum, i; sum = 0; for (i = 0; i < len * blockLength; i++) { sum += buf[i]; } log_message(0, "W: %ld: %ld, %ld, %ld", lba, blockLength, len, sum); #endif memset(cmd, 0, 10); cmd[0] = 0xe1; // WRITE CONTINUE while (len > 0) { writeLen = (len > blocksPerWrite_ ? blocksPerWrite_ : len); byteLen = writeLen * blockLength; cmd[1] = (byteLen >> 16) & 0x1f; cmd[2] = byteLen >> 8; cmd[3] = byteLen; if ((ret = sendCmd(cmd, 10, (unsigned char *)buf, byteLen, NULL, 0, 0)) != 0) { if(ret == 2) { const unsigned char *sense; int senseLen; sense = scsiIf_->getSense(senseLen); // The drive logs in the CD-R after write simulation again and // reports this by Unit Attention. Ceck for this error and ignore it. if(senseLen >= 14 && (sense[2] & 0x0f) == 0x6 && sense[7] >= 6 && (sense[12] == 0x80 /*this really happened*/ || sense[12] == 0xd4 /*EXIT FROM PSEUDO TRACK AT ONCE RECORDING*/)) { sleep(10); // wait until drive becomes ready again } else { scsiIf_->printError(); log_message(-2, "Write data failed."); return 1; } } else { log_message(-2, "Write data failed."); return 1; } } buf += byteLen; lba += writeLen; len -= writeLen; } return 0; } DiskInfo *SonyCDU920::diskInfo() { unsigned char mp[32]; memset(&diskInfo_, 0, sizeof(DiskInfo)); memset(mp, 0, 32); if (getModePage6(0x22, mp, 32, NULL, NULL, 1) != 0) { log_message(-2, "Cannot retrieve CD-R disc information mode page."); return &diskInfo_; } diskInfo_.empty = ((mp[16] >> 6) == 0 ? 1 : 0); diskInfo_.valid.empty = 1; diskInfo_.cdrw = 0; diskInfo_.valid.cdrw = 1; if (diskInfo_.empty) { diskInfo_.manufacturerId = Msf(mp[25], mp[26], mp[27]); diskInfo_.valid.manufacturerId = 1; diskInfo_.capacity = Msf(mp[13], mp[14], mp[15]).lba(); diskInfo_.valid.capacity = 1; } return &diskInfo_; } Toc *SonyCDU920::readDiskToc(int session, const char *audioFilename) { Toc *toc = CdrDriver::readDiskToc(session, audioFilename); setBlockSize(MODE1_BLOCK_LEN); return toc; } // tries to read catalog number from disk and adds it to 'toc' // return: 1 if valid catalog number was found, else 0 int SonyCDU920::readCatalog(Toc *toc, long startLba, long endLba) { unsigned char cmd[10]; unsigned char data[24]; char catalog[14]; int i; memset(cmd, 0, 10); memset(data, 0, 24); cmd[0] = 0x42; // READ SUB-CHANNEL cmd[2] = 1 << 6; cmd[3] = 0x02; // get media catalog number cmd[8] = 24; // transfer length if (sendCmd(cmd, 10, NULL, 0, data, 24) != 0) { log_message(-2, "Cannot get catalog number."); return 0; } if (data[8] & 0x80) { for (i = 0; i < 13; i++) { catalog[i] = data[0x09 + i]; } catalog[13] = 0; if (toc->catalog(catalog) == 0) { return 1; } } return 0; } int SonyCDU920::readIsrc(int trackNr, char *buf) { unsigned char cmd[10]; unsigned char data[24]; int i; buf[0] = 0; memset(cmd, 0, 10); memset(data, 0, 24); cmd[0] = 0x42; // READ SUB-CHANNEL cmd[2] = 1 << 6; cmd[3] = 0x03; // get media catalog number cmd[6] = trackNr; cmd[8] = 24; // transfer length if (sendCmd(cmd, 10, NULL, 0, data, 24) != 0) { log_message(-2, "Cannot get ISRC code."); return 0; } if (data[8] & 0x80) { for (i = 0; i < 12; i++) { buf[i] = data[0x09 + i]; } buf[12] = 0; } return 0; } int SonyCDU920::analyzeTrack(TrackData::Mode mode, int trackNr, long startLba, long endLba, Msf *indexIncrements, int *indexIncrementCnt, long *pregap, char *isrcCode, unsigned char *ctl) { selectSpeed(); int ret = analyzeTrackScan(mode, trackNr, startLba, endLba, indexIncrements, indexIncrementCnt, pregap, isrcCode, ctl); return ret; } int SonyCDU920::readSubChannels(TrackData::SubChannelMode, long lba, long len, SubChannel ***chans, Sample *audioData) { unsigned char cmd[12]; int i; int retries = 5; long blockLen = AUDIO_BLOCK_LEN + 16; cmd[0] = 0xd8; // READ CDDA cmd[1] = 0; cmd[2] = lba >> 24; cmd[3] = lba >> 16; cmd[4] = lba >> 8; cmd[5] = lba; cmd[6] = len >> 24; cmd[7] = len >> 16; cmd[8] = len >> 8; cmd[9] = len; cmd[10] = 0x01; cmd[11] = 0; while (1) { if (sendCmd(cmd, 12, NULL, 0, transferBuffer_, len * blockLen, retries == 0 ? 1 : 0) != 0) { if (retries == 0) return 1; } else { break; } retries--; } unsigned char *p = transferBuffer_ + AUDIO_BLOCK_LEN; for (i = 0; i < len; i++) { ((PQSubChannel16*)scannedSubChannels_[i])->init(p); if (scannedSubChannels_[i]->type() != SubChannel::QMODE_ILLEGAL) { // the CRC of the sub-channel data is set to zero -> mark the // sub-channel object that it should not try to verify the CRC scannedSubChannels_[i]->crcInvalid(); } p += blockLen; } if (audioData != NULL) { p = transferBuffer_; for (i = 0; i < len; i++) { memcpy(audioData, p, AUDIO_BLOCK_LEN); p += blockLen; audioData += SAMPLES_PER_BLOCK; } } *chans = scannedSubChannels_; return 0; } CdRawToc *SonyCDU920::getRawToc(int sessionNr, int *len) { unsigned char cmd[10]; unsigned short dataLen; unsigned char *data = NULL;; unsigned char reqData[4]; // buffer for requestion the actual length unsigned char *p; int i, entries; CdRawToc *rawToc; assert(sessionNr >= 1); // read disk toc length memset(cmd, 0, 10); cmd[0] = 0x43; // READ TOC cmd[6] = sessionNr; cmd[8] = 4; cmd[9] = (2 << 6); if (sendCmd(cmd, 10, NULL, 0, reqData, 4) != 0) { log_message(-2, "Cannot read disk toc."); return NULL; } dataLen = ((reqData[0] << 8) | reqData[1]) + 2; log_message(4, "Raw toc data len: %d", dataLen); data = new unsigned char[dataLen]; // read disk toc cmd[7] = dataLen >> 8; cmd[8] = dataLen; if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) { log_message(-2, "Cannot read disk toc."); delete[] data; return NULL; } entries = (((data[0] << 8) | data[1]) - 2) / 11; rawToc = new CdRawToc[entries]; for (i = 0, p = data + 4; i < entries; i++, p += 11 ) { #if 0 log_message(0, "%d %02x %02d %2x %02d:%02d:%02d %02d %02d:%02d:%02d", p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10]); #endif rawToc[i].sessionNr = p[0]; rawToc[i].adrCtl = p[1]; rawToc[i].point = p[3]; rawToc[i].pmin = p[8]; rawToc[i].psec = p[9]; rawToc[i].pframe = p[10]; } delete[] data; *len = entries; return rawToc; } long SonyCDU920::readTrackData(TrackData::Mode mode, TrackData::SubChannelMode, long lba, long len, unsigned char *buf) { unsigned char cmd[10]; long blockLen = 2340; long i; TrackData::Mode actMode; int ok = 0; const unsigned char *sense; int senseLen; int softError; if (setBlockSize(blockLen) != 0) return 0; memset(cmd, 0, 10); cmd[0] = 0x28; // READ10 cmd[2] = lba >> 24; cmd[3] = lba >> 16; cmd[4] = lba >> 8; cmd[5] = lba; while (len > 0 && !ok) { cmd[7] = len >> 8; cmd[8] = len; memset(transferBuffer_, 0, len * blockLen); switch (sendCmd(cmd, 10, NULL, 0, transferBuffer_, len * blockLen, 0)) { case 0: ok = 1; break; case 2: softError = 0; sense = scsiIf_->getSense(senseLen); if (senseLen > 0x0c) { if ((sense[2] &0x0f) == 5) { switch (sense[12]) { case 0x63: // end of user area encountered on this track case 0x64: // Illegal mode for this track softError = 1; break; } } else if ((sense[2] & 0x0f) == 3) { // Medium error switch (sense[12]) { case 0x02: // No seek complete, sector not found case 0x11: // L-EC error return -2; break; } } } if (!softError) { scsiIf_->printError(); return -1; } break; default: log_message(-2, "Read error at LBA %ld, len %ld", lba, len); return -1; break; } if (!ok) { len--; } } unsigned char *sector = transferBuffer_; for (i = 0; i < len; i++) { actMode = determineSectorMode(sector); if (!(actMode == mode || (mode == TrackData::MODE2_FORM_MIX && (actMode == TrackData::MODE2_FORM1 || actMode == TrackData::MODE2_FORM2)) || (mode == TrackData::MODE1_RAW && actMode == TrackData::MODE1) || (mode == TrackData::MODE2_RAW && (actMode == TrackData::MODE2 || actMode == TrackData::MODE2_FORM1 || actMode == TrackData::MODE2_FORM2)))) { log_message(4, "Stopped because sector with not matching mode %s found.", TrackData::mode2String(actMode)); return i; } if (buf != NULL) { switch (mode) { case TrackData::MODE1: memcpy(buf, sector + 4, MODE1_BLOCK_LEN); buf += MODE1_BLOCK_LEN; break; case TrackData::MODE2: case TrackData::MODE2_FORM_MIX: memcpy(buf, sector + 4, MODE2_BLOCK_LEN); buf += MODE2_BLOCK_LEN; break; case TrackData::MODE2_FORM1: memcpy(buf, sector + 12, MODE2_FORM1_DATA_LEN); buf += MODE2_FORM1_DATA_LEN; break; case TrackData::MODE2_FORM2: memcpy(buf, sector + 12, MODE2_FORM2_DATA_LEN); buf += MODE2_FORM2_DATA_LEN; break; case TrackData::MODE1_RAW: case TrackData::MODE2_RAW: memcpy(buf, syncPattern, 12); memcpy(buf + 12, sector, 2340); buf += AUDIO_BLOCK_LEN; break; case TrackData::MODE0: case TrackData::AUDIO: log_message(-3, "PlextorReader::readTrackData: Illegal mode."); return 0; break; } } sector += blockLen; } return len; } int SonyCDU920::readAudioRange(ReadDiskInfo *rinfo, int fd, long start, long end, int startTrack, int endTrack, TrackInfo *info) { return CdrDriver::readAudioRangeParanoia(rinfo, fd, start, end, startTrack, endTrack, info); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/SonyCDU920.h��������������������������������������������������������������0000664�0000000�0000000�00000005226�15114537466�0017336�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1999-2001 Andreas Mueller <andreas@daneb.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 * (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. */ #ifndef __SONY_CDU920_H__ #define __SONY_CDU920_H__ #include "CdrDriver.h" class Toc; class Track; class SonyCDU920 : public CdrDriver { public: SonyCDU920(ScsiIf *scsiIf, unsigned long options); ~SonyCDU920(); static CdrDriver *instance(ScsiIf *scsiIf, unsigned long options); unsigned long getReadCapabilities(const CdToc *, int) const { return 0; } int bigEndianSamples() const; int multiSession(int); int speed(int); int loadUnload(int) const; int initDao(const Toc *); int startDao(); int finishDao(); void abortDao(); int writeData(TrackData::Mode, TrackData::SubChannelMode, long &lba, const char *buf, long len); DiskInfo *diskInfo(); Toc *readDiskToc(int session, const char *audioFilename); protected: int scsiTimeout_; Msf leadInStart_; // start of lead-in long leadInLen_; // length of lead-in DiskInfo diskInfo_; int getSessionInfo(); int readCatalog(Toc *, long startLba, long endLba); int readIsrc(int, char *); virtual int selectSpeed(); // overloaded by 'SonyCDU948' virtual int setWriteParameters(); // overloaded by 'SonyCDU948' unsigned char *createCueSheet(unsigned char leadInDataForm, long *cueSheetLen); int sendCueSheet(unsigned char leadInDataForm); int readBufferCapacity(long *capacity); int analyzeTrack(TrackData::Mode, int trackNr, long startLba, long endLba, Msf *index, int *indexCnt, long *pregap, char *isrcCode, unsigned char *ctl); int readSubChannels(TrackData::SubChannelMode, long lba, long len, SubChannel ***, Sample *); CdRawToc *getRawToc(int sessionNr, int *len); long readTrackData(TrackData::Mode, TrackData::SubChannelMode, long lba, long len, unsigned char *buf); int readAudioRange(ReadDiskInfo *, int fd, long start, long end, int startTrack, int endTrack, TrackInfo *); }; #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/SonyCDU948.cc�������������������������������������������������������������0000664�0000000�0000000�00000012316�15114537466�0017504�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <andreas@daneb.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 * (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. */ #include <config.h> #include <string.h> #include <assert.h> #include "SonyCDU948.h" #include "PWSubChannel96.h" #include "log.h" #include "Toc.h" #include "CdTextEncoder.h" SonyCDU948::SonyCDU948(ScsiIf *scsiIf, unsigned long options) : SonyCDU920(scsiIf, options) { driverName_ = "Sony CDU948 - Version 0.1 (data) (alpha)"; speed_ = 4; cdTextEncoder_ = NULL; } SonyCDU948::~SonyCDU948() { delete cdTextEncoder_; cdTextEncoder_ = NULL; } // static constructor CdrDriver *SonyCDU948::instance(ScsiIf *scsiIf, unsigned long options) { return new SonyCDU948(scsiIf, options); } int SonyCDU948::checkToc(const Toc *toc) { int err = SonyCDU920::checkToc(toc); int e; if ((e = toc->checkCdTextData()) > err) err = e; return err; } int SonyCDU948::multiSession(int m) { multiSession_ = m != 0 ? 1 : 0; return 0; } // sets speed // return: 0: OK // 1: illegal speed int SonyCDU948::speed(int s) { if (s == 0 || s == 1 || s == 2 || s == 4) speed_ = s; else if (s == 3) speed_ = 2; else if (s > 4) speed_ = 4; else return 1; return 0; } // sets read/write speed and simulation mode // return: 0: OK // 1: scsi command failed int SonyCDU948::selectSpeed() { unsigned char mp[4]; mp[0] = 0x31; mp[1] = 2; mp[2] = 0; mp[3] = 0; switch (speed_) { case 0: mp[2] = 0xff; case 1: mp[2] = 0; break; case 2: mp[2] = 1; break; case 4: mp[2] = 3; break; } if (setModePage6(mp, NULL, NULL, 1) != 0) { log_message(-2, "Cannot set speed mode page."); return 1; } return 0; } // Sets write parameters. // return: 0: OK // 1: scsi command failed int SonyCDU948::setWriteParameters() { unsigned char cmd[10]; unsigned char data[52]; if (SonyCDU920::setWriteParameters() != 0) return 1; memset(cmd, 0, 10); memset(data, 0, 52); cmd[0] = 0xf8; // SET WRITE PARAMETERS cmd[7] = 0; cmd[8] = 52; data[1] = 50; data[3] = (multiSession_ != 0 ? (3 << 6) : 0); if (sendCmd(cmd, 10, data, 52, NULL, 0, 1) != 0) { log_message(-1, "Cannot set write parameters."); return 1; } return 0; } int SonyCDU948::initDao(const Toc *toc) { long n; delete cdTextEncoder_; cdTextEncoder_ = new CdTextEncoder(toc); if (cdTextEncoder_->encode() != 0) { log_message(-2, "CD-TEXT encoding failed."); return 1; } if (cdTextEncoder_->getSubChannels(&n) == NULL || n == 0) { // there is no CD-TEXT data to write delete cdTextEncoder_; cdTextEncoder_ = NULL; } return SonyCDU920::initDao(toc); } int SonyCDU948::startDao() { unsigned char leadInDataForm = 0x00; // CD-DA, generate data by device scsiTimeout_ = scsiIf_->timeout(3 * 60); if (cdTextEncoder_ != NULL) leadInDataForm = 0xc0; // CD-DA with P-W sub-channel data if (setWriteParameters() != 0 || sendCueSheet(leadInDataForm) != 0) return 1; if (writeCdTextLeadIn() != 0) { return 1; } long lba = -150; // write mandatory pre-gap after lead-in if (writeZeros(toc_->leadInMode(), TrackData::SUBCHAN_NONE, lba, 0, 150) != 0) { return 1; } return 0; } int SonyCDU948::writeCdTextLeadIn() { unsigned char cmd[10]; const PWSubChannel96 **cdTextSubChannels; long cdTextSubChannelCount; long channelsPerCmd = scsiIf_->maxDataLen() / 96; long scp = 0; long byteLen; long len = leadInLen_; long n; long i; unsigned char *p; if (cdTextEncoder_ == NULL) return 0; if (leadInLen_ == 0) { log_message(-2, "Cannot write CD-TEXT lead-in because lead-in length is not known."); return 1; } cdTextSubChannels = cdTextEncoder_->getSubChannels(&cdTextSubChannelCount); assert(channelsPerCmd > 0); assert(cdTextSubChannels != NULL); assert(cdTextSubChannelCount > 0); log_message(2, "Writing CD-TEXT lead-in..."); memset(cmd, 0, 10); cmd[0] = 0xe1; // WRITE CONTINUE while (len > 0) { n = (len > channelsPerCmd) ? channelsPerCmd : len; byteLen = n * 96; cmd[1] = (byteLen >> 16) & 0x1f; cmd[2] = byteLen >> 8; cmd[3] = byteLen; p = transferBuffer_; for (i = 0; i < n; i++) { memcpy(p, cdTextSubChannels[scp]->data(), 96); p += 96; scp++; if (scp >= cdTextSubChannelCount) scp = 0; } if (sendCmd(cmd, 10, transferBuffer_, byteLen, NULL, 0) != 0) { log_message(-2, "Writing of CD-TEXT data failed."); return 1; } len -= n; } return 0; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/SonyCDU948.h��������������������������������������������������������������0000664�0000000�0000000�00000002572�15114537466�0017351�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1999-2001 Andreas Mueller <andreas@daneb.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 * (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. */ #ifndef __SONY_CDU948_H__ #define __SONY_CDU948_H__ #include "SonyCDU920.h" class Toc; class Track; class CdTextEncoder; class SonyCDU948 : public SonyCDU920 { public: SonyCDU948(ScsiIf *scsiIf, unsigned long options); ~SonyCDU948(); static CdrDriver *instance(ScsiIf *scsiIf, unsigned long options); int checkToc(const Toc *); int multiSession(int); int speed(int); int initDao(const Toc *); int startDao(); protected: CdTextEncoder *cdTextEncoder_; int selectSpeed(); int setWriteParameters(); int writeCdTextLeadIn(); }; #endif ��������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/SubChannel.cc�������������������������������������������������������������0000664�0000000�0000000�00000021544�15114537466�0020000�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998 Andreas Mueller <mueller@daneb.ping.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 * (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. */ /* * $Log: SubChannel.cc,v $ * Revision 1.2 2000/12/17 10:51:23 andreasm * Default verbose level is now 2. Adaopted message levels to have finer * grained control about the amount of messages printed by cdrdao. * Added CD-TEXT writing support to the GenericMMCraw driver. * Fixed CD-TEXT cue sheet creating for the GenericMMC driver. * * Revision 1.1.1.1 2000/02/05 01:37:27 llanero * Uploaded cdrdao 1.1.3 with pre10 patch applied. * * Revision 1.4 1999/04/05 11:04:48 mueller * Added decoding of media catalog number and ISRC code. * * Revision 1.3 1999/03/27 20:58:55 mueller * Added various access functions. * * Revision 1.2 1998/08/30 19:10:32 mueller * Added handling of Catalog Number and ISRC codes. * * Revision 1.1 1998/08/29 21:31:00 mueller * Initial revision * * */ #include "SubChannel.h" #include <ctype.h> // lookup table for crc calculation unsigned short SubChannel::crctab[256] = { 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 }; SubChannel::SubChannel() { crcValid_ = 1; // CRC is usually valid } SubChannel::~SubChannel() { } void SubChannel::crcInvalid() { crcValid_ = 0; } SubChannel::Type SubChannel::type() const { return type_; } // returns bcd value for given binary value if it is >= 0 and <= 99, otherwise // the given value is returned unsigned char SubChannel::bcd(int d) { if (d >= 0 && d <= 99) return ((d / 10) << 4) | (d % 10); else return d; } int SubChannel::bcd2int(unsigned char d) { unsigned char d1 = d & 0x0f; unsigned char d2 = d >> 4; if (d1 <= 9 && d2 <= 9) { return d2 * 10 + d1; } else { return d; } } int SubChannel::isBcd(unsigned char d) { if ((d & 0x0f) <= 9 && (d >> 4) <= 9) return 1; return 0; } // Encodes the given catalog number digits 'n1' - 'n13' (ascii) into // provided buffer 'buf' of 7 bytes length void SubChannel::encodeCatalogNumber(unsigned char *buf, char n1, char n2, char n3, char n4, char n5, char n6, char n7, char n8, char n9, char n10, char n11, char n12, char n13) { buf[0] = ((n1 - '0') << 4) | ((n2 - '0') & 0x0f); buf[1] = ((n3 - '0') << 4) | ((n4 - '0') & 0x0f); buf[2] = ((n5 - '0') << 4) | ((n6 - '0') & 0x0f); buf[3] = ((n7 - '0') << 4) | ((n8 - '0') & 0x0f); buf[4] = ((n9 - '0') << 4) | ((n10 - '0') & 0x0f); buf[5] = ((n11 - '0') << 4) | ((n12 - '0') & 0x0f); buf[6] = ((n13 - '0') << 4); } // Decodes given 7 byte buffer to ascii media catalog numbers. void SubChannel::decodeCatalogNumber(const unsigned char *in, char *n1, char *n2, char *n3, char *n4, char *n5, char *n6, char *n7, char *n8, char *n9, char *n10, char *n11, char *n12, char *n13) { *n1 = ((in[0] >> 4) & 0x0f) + '0'; *n2 = (in[0] & 0x0f) + '0'; *n3 = ((in[1] >> 4) & 0x0f) + '0'; *n4 = (in[1] & 0x0f) + '0'; *n5 = ((in[2] >> 4) & 0x0f) + '0'; *n6 = (in[2] & 0x0f) + '0'; *n7 = ((in[3] >> 4) & 0x0f) + '0'; *n8 = (in[3] & 0x0f) + '0'; *n9 = ((in[4] >> 4) & 0x0f) + '0'; *n10 = (in[4] & 0x0f) + '0'; *n11 = ((in[5] >> 4) & 0x0f) + '0'; *n12 = (in[5] & 0x0f) + '0'; *n13 = ((in[6] >> 4) & 0x0f) + '0'; } // Encodes given ISRC code into provided buffer of 8 bytes length. // c1 - c2: country code (ascii digits or letters) // o1 - o3: country code (ascii digits or letters) // y1 - y2: year of recording (ascii digits) // s1 - s2: serial number (ascii digits) void SubChannel::encodeIsrcCode(unsigned char *buf, char c1, char c2, char o1, char o2, char o3, char y1, char y2, char s1, char s2, char s3, char s4, char s5) { unsigned char d; buf[0] = ascii2Isrc(c1) << 2; d = ascii2Isrc(c2); buf[0] |= d >> 4; buf[1] = d << 4; d = ascii2Isrc(o1); buf[1] |= d >> 2; buf[2] = d << 6; buf[2] |= ascii2Isrc(o2); buf[3] = ascii2Isrc(o3) << 2; buf[4] = ((y1 - '0') << 4) | ((y2 - '0') & 0x0f); buf[5] = ((s1 - '0') << 4) | ((s2 - '0') & 0x0f); buf[6] = ((s3 - '0') << 4) | ((s4 - '0') & 0x0f); buf[7] = ((s5 - '0') << 4); } // Decodes ISRC code from given 8 byte length buffer to ascii characters. void SubChannel::decodeIsrcCode(const unsigned char *in, char *c1, char *c2, char *o1, char *o2, char *o3, char *y1, char *y2, char *s1, char *s2, char *s3, char *s4, char *s5) { unsigned char d; d = (in[0] >> 2) & 0x3f; *c1 = isrc2Ascii(d); d = ((in[0] & 0x03) << 4) | ((in[1] >> 4) & 0x0f); *c2 = isrc2Ascii(d); d = ((in[1] & 0x0f) << 2) | ((in[2] >> 6) & 0x03); *o1 = isrc2Ascii(d); d = in[2] & 0x3f; *o2 = isrc2Ascii(d); d = (in[3] >> 2) & 0x3f; *o3 = isrc2Ascii(d); *y1 = ((in[4] >> 4) & 0x0f) + '0'; *y2 = (in[4] & 0x0f) + '0'; *s1 = ((in[5] >> 4) & 0x0f) + '0'; *s2 = (in[5] & 0x0f) + '0'; *s3 = ((in[6] >> 4) & 0x0f) + '0'; *s4 = (in[6] & 0x0f) + '0'; *s5 = ((in[7] >> 4) & 0x0f) + '0'; } unsigned char SubChannel::ascii2Isrc(char c) { if (isdigit(c)) return (c - '0') & 0x3f; if (isupper(c)) return (c - 'A' + 17) & 0x3f; if (islower(c)) return (c - 'a' + 17) & 0x3f; return 0; } char SubChannel::isrc2Ascii(unsigned char c) { if (c <= 9) return '0' + c; if (c >= 17 && c <= 42) return 'A' + (c - 17); return 0; } int SubChannel::checkConsistency() { const char *buf; int i; switch (type()) { case QMODE1TOC: // Not complete, yet. if (min() > 99 || sec() > 59 || frame() > 74) return 0; break; case QMODE5TOC: // not required right now break; case QMODE1DATA: if (trackNr() < 1 || trackNr() > 99) return 0; if (indexNr() > 99) return 0; if (min() > 99 || sec() > 59 || frame() > 74) return 0; if (amin() > 99 || asec() > 59 || aframe() > 74) return 0; break; case QMODE2: buf = catalog(); for (i = 0; i < 13; i++) { if (!isdigit(buf[i])) return 0; } break; case QMODE3: buf = isrc(); for (i = 0; i < 5; i++) { if (!isdigit(buf[i]) && !isupper(buf[i])) return 0; } for (i = 5; i < 12; i++) { if (!isdigit(buf[i])) return 0; } break; case QMODE_ILLEGAL: return 0; break; } return 1; } ������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/SubChannel.h��������������������������������������������������������������0000664�0000000�0000000�00000011603�15114537466�0017635�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #ifndef __SUB_CHANNEL_H__ #define __SUB_CHANNEL_H__ class SubChannel { public: enum Type { QMODE1TOC, // toc data QMODE1DATA, // current position in data QMODE2, // Catalog number QMODE3, // ISRC code QMODE5TOC, // toc data QMODE_ILLEGAL // indicates illegal adr field }; SubChannel(); virtual ~SubChannel(); // marks the CRC of this sub-channel as invalid, 'checkCrc()' will always // return true for such sub-channels void crcInvalid(); // virtual constructors: // create sub channel with specified q-mode virtual SubChannel *makeSubChannel(Type) = 0; // create sub channel with reading sub channel data from given buffer virtual SubChannel *makeSubChannel(unsigned char *) = 0; virtual void type(unsigned char) = 0; // sets Q mode type virtual Type type() const; // return Q mode type virtual long dataLength() const = 0; // returns number of sub channel bytes virtual void pChannel(int) = 0; // sets P channel bit virtual void ctl(int) = 0; // sets control flags virtual unsigned char ctl() const = 0; // return control nibbles in bits 0-3 virtual void trackNr(int) = 0; // sets track number (QMODE1DATA) virtual int trackNr() const = 0; // returns track number (QMODE1DATA) virtual void indexNr(int) = 0; // sets index number (QMODE1DATA) virtual int indexNr() const = 0; // returns index number (QMODE1DATA) virtual void point(int) = 0; // sets point filed (QMODE1TOC, QMODE5TOC) virtual void min(int) = 0; // track relative time (QMODE1TOC, QMODE1DATA, QMODE5TOC) virtual int min() const = 0; virtual void sec(int) = 0; // track relative time (QMODE1TOC, QMODE1DATA, QMODE5TOC) virtual int sec() const = 0; virtual void frame(int) = 0; // track relative time (QMODE1TOC, QMODE1DATA, QMODE5TOC) virtual int frame() const = 0; virtual void amin(int) = 0; // absolute time (QMODE1DATA) virtual int amin() const = 0; virtual void asec(int) = 0; // absolute time (QMODE1DATA) virtual int asec() const = 0; virtual void aframe(int) = 0; // absolute time (QMODE1DATA, QMODE2, QMODE3) virtual int aframe() const = 0; virtual void pmin(int) = 0; // track start time (QMODE1TOC, QMODE5TOC) virtual void psec(int) = 0; // track start time (QMODE1TOC, QMODE5TOC) virtual void pframe(int) = 0; // track start time (QMODE1TOC, QMODE5TOC) virtual void zero(int) = 0; // zero field (QMODE5TOC) // set catalog number (QMODE2) virtual void catalog(char, char, char, char, char, char, char, char, char, char, char, char, char) = 0; // return catalog number virtual const char *catalog() const = 0; // set ISRC code (QMODE3) virtual void isrc(char, char, char, char, char, char, char, char, char, char, char, char) = 0; // returns ISRC code virtual const char *isrc() const = 0; virtual void print() const = 0; virtual void calcCrc() = 0; // calculates crc and stores it in crc fields virtual int checkCrc() const = 0; virtual int checkConsistency(); virtual const unsigned char *data() const = 0; static unsigned char ascii2Isrc(char); static char isrc2Ascii(unsigned char); static unsigned char bcd(int); static int bcd2int(unsigned char d); static int isBcd(unsigned char); protected: Type type_; int crcValid_; // 0 if sub channel has no valid CRC that can be checked, // 1 if CRC is valid and can be checked static unsigned short crctab[256]; static void encodeCatalogNumber(unsigned char *, char, char, char, char, char, char, char, char, char, char, char, char, char); static void decodeCatalogNumber(const unsigned char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, char *); static void encodeIsrcCode(unsigned char *, char, char, char, char, char, char, char, char, char, char, char, char); static void decodeIsrcCode(const unsigned char *in, char *c1, char *c2, char *o1, char *o2, char *o3, char *y1, char *y2, char *s1, char *s2, char *s3, char *s4, char *s5); }; #endif �����������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/TaiyoYuden.cc�������������������������������������������������������������0000664�0000000�0000000�00000015725�15114537466�0020054�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <andreas@daneb.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 * (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. */ /* Driver for the TaiyoYuden drive created by Henk-Jan Slotboom. * Very similar to the Philips CDD2x00 drives. */ #include <config.h> #include <string.h> #include <assert.h> #include "TaiyoYuden.h" #include "SubChannel.h" #include "Toc.h" #include "log.h" TaiyoYuden::TaiyoYuden(ScsiIf *scsiIf, unsigned long options) : PlextorReader(scsiIf, options), CDD2600Base(this) { driverName_ = "Taiyo-Yuden - Version 0.1(alpha)"; leadInLength_ = leadOutLength_ = 0; speed_ = 2; simulate_ = true; encodingMode_ = 0; audioDataByteOrder_ = 0; // little endian memset(&diskInfo_, 0, sizeof(DiskInfo)); } TaiyoYuden::~TaiyoYuden() { } // static constructor CdrDriver *TaiyoYuden::instance(ScsiIf *scsiIf, unsigned long options) { return new TaiyoYuden(scsiIf, options); } // sets speed // return: 0: OK // 1: illegal speed int TaiyoYuden::speed(int s) { if (s >= 0 && s <= 2) { speed_ = s; return 0; } else if (s > 2) { speed_ = 2; return 0; } else { return 1; } } // loads ('unload' == 0) or ejects ('unload' == 1) tray // return: 0: OK // 1: scsi command failed int TaiyoYuden::loadUnload(int unload) const { unsigned char cmd[10]; memset(cmd, 0, 10); cmd[0] = 0xe7; // MEDIUM LOAD/UNLOAD if (unload) { cmd[8] |= 0x01; } if (sendCmd(cmd, 10, NULL, 0, NULL, 0) != 0) { log_message(-2, "Cannot load/unload medium."); return 1; } return 0; }; int TaiyoYuden::initDao(const Toc *toc) { long n; toc_ = toc; blockLength_ = AUDIO_BLOCK_LEN; blocksPerWrite_ = scsiIf_->maxDataLen() / blockLength_; assert(blocksPerWrite_ > 0); if (modeSelectBlockSize(blockLength_, 1) != 0 || modeSelectSpeed(-1, speed_, simulate_, 1) != 0 || modeSelectCatalog(toc_) != 0 || readSessionInfo(&leadInLength_, &leadOutLength_, 1) != 0) { return 1; } // allocate buffer for write zeros n = blocksPerWrite_ * blockLength_; delete[] zeroBuffer_; zeroBuffer_ = new char[n]; memset(zeroBuffer_, 0, n); return 0; } int TaiyoYuden::startDao() { long lba = -leadInLength_ - 150; // Value is not really important since the // LBA is not used by 'writeData'. if (writeSession(toc_, multiSession_, 0) != 0) { return 1; } log_message(2, "Writing lead-in and gap..."); // write lead-in if (writeZeros(toc_->leadInMode(), TrackData::SUBCHAN_NONE, lba, 0, leadInLength_) != 0) { flushCache(); return 1; } // write gap (2 seconds) if (writeZeros(toc_->leadInMode(), TrackData::SUBCHAN_NONE, lba, 0, 150) != 0) { flushCache(); return 1; } log_message(2, ""); return 0; } int TaiyoYuden::finishDao() { long lba = toc_->length().lba(); log_message(2, "Writing lead-out..."); // write lead-out if (writeZeros(toc_->leadOutMode(), TrackData::SUBCHAN_NONE, lba, lba + 150, leadOutLength_) != 0) { flushCache(); return 1; } log_message(2, "\nFlushing cache..."); if (flushCache() != 0) { return 1; } log_message(2, ""); delete[] zeroBuffer_, zeroBuffer_ = NULL; return 0; } void TaiyoYuden::abortDao() { flushCache(); } // Writes data to target, the block length depends on the actual writing mode // and is stored internally. 'len' is number of blocks to write. // 'lba' specifies the next logical block address for writing and is updated // by this function but not used for writing // return: 0: OK // 1: scsi command failed int TaiyoYuden::writeData(TrackData::Mode mode, TrackData::SubChannelMode sm, long &lba, const char *buf, long len) { assert(blocksPerWrite_ > 0); assert(blockLength_ > 0); assert(mode == TrackData::AUDIO); int nwritten = 0; int writeLen = 0; unsigned char cmd[10]; memset(cmd, 0, 10); cmd[0] = 0x2a; // WRITE1 while (len > 0) { writeLen = (len > blocksPerWrite_ ? blocksPerWrite_ : len); cmd[7] = writeLen >> 8; cmd[8] = writeLen & 0xff; if (sendCmd(cmd, 10, (unsigned char *)(buf + (nwritten * blockLength_)), writeLen * blockLength_, NULL, 0) != 0) { log_message(-2, "Write data failed."); return 1; } lba += writeLen; len -= writeLen; nwritten += writeLen; } return 0; } // Retrieve disk information. // return: DiskInfo structure or 'NULL' on error DiskInfo *TaiyoYuden::diskInfo() { unsigned char cmd[10]; unsigned long dataLen = 34; unsigned char data[34]; memset(&diskInfo_, 0, sizeof(DiskInfo)); if (readCapacity(&(diskInfo_.capacity), 0) == 0) { diskInfo_.valid.capacity = 1; } if (readSessionInfo(&leadInLength_, &leadOutLength_, 0) == 0) { diskInfo_.valid.manufacturerId = 1; // start time of lead-in diskInfo_.manufacturerId = Msf(450150 - leadInLength_ - 150 ); diskInfo_.empty = 1; } else { diskInfo_.empty = 0; } diskInfo_.valid.empty = 0; // does not work for this drive memset(cmd, 0, 10); memset(data, 0, dataLen); cmd[0] = 0x51; // READ DISK INFORMATION cmd[7] = dataLen >> 8; cmd[8] = dataLen; if (sendCmd(cmd, 10, NULL, 0, data, dataLen, 0) == 0) { diskInfo_.empty = (data[2] & 0x03) == 0 ? 1 : 0; diskInfo_.cdrw = (data[2] & 0x10) != 0 ? 1 : 0; diskInfo_.valid.cdrw = 1; } return &diskInfo_; } // Special toc check for Taiyo-Yuden drives. Every track must have a pre-gap // to create a correct disk. The pre-gap length may be only 1 block. // Only warnings are created. // Return: 0: OK // 1: at least one warning was given // 2: at least on error was given int TaiyoYuden::checkToc(const Toc *toc) { int err = PlextorReader::checkToc(toc); int trackNr; Msf start, end; const Track *t; int warningGiven = 0; TrackIterator itr(toc); for (t = itr.first(start, end), trackNr = 1; t != NULL; t = itr.next(start, end), trackNr++) { if (t->start().lba() == 0 && trackNr > 1) { if (!warningGiven) { warningGiven = 1; log_message(-1, "Each track must have a minimal pre-gap to create a useful disk."); log_message(-1, "This is not fulfilled for following track(s):"); } log_message(-1, "Track %d", trackNr); } } if (warningGiven) { log_message(0,""); if (err < 1) err = 1; } return err; } �������������������������������������������cdrdao-cdrdao-f00afb2/dao/TaiyoYuden.h��������������������������������������������������������������0000664�0000000�0000000�00000003341�15114537466�0017705�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <andreas@daneb.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 * (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. */ /* Driver for the TaiyoYuden drive created by Henk-Jan Slotboom. * Very similar to the Philips CDD2x00 drives. */ #ifndef __TAIYO_YUDEN_H__ #define __TAIYO_YUDEN_H__ #include "CdrDriver.h" #include "PlextorReader.h" #include "CDD2600Base.h" class TaiyoYuden : public PlextorReader, private CDD2600Base { public: TaiyoYuden(ScsiIf *scsiIf, unsigned long options); ~TaiyoYuden(); static CdrDriver *instance(ScsiIf *scsiIf, unsigned long options); // takes little endian samples int bigEndianSamples() const { return 0; } int speed(int); DiskInfo *diskInfo(); int loadUnload(int) const; int checkToc(const Toc *); int initDao(const Toc *); int startDao(); int finishDao(); void abortDao(); int writeData(TrackData::Mode, TrackData::SubChannelMode, long &lba, const char *buf, long len); protected: DiskInfo diskInfo_; private: long leadInLength_; long leadOutLength_; }; #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/TeacCdr55.cc��������������������������������������������������������������0000664�0000000�0000000�00000101054�15114537466�0017430�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <andreas@daneb.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 * (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. */ #include <config.h> #include <string.h> #include <assert.h> #include "TeacCdr55.h" #include "Toc.h" #include "PQSubChannel16.h" #include "log.h" TeacCdr55::TeacCdr55(ScsiIf *scsiIf, unsigned long options) : CdrDriver(scsiIf, options) { int i; driverName_ = "Teac CD-R50/55 - Version 0.1 (data)"; speed_ = 0; simulate_ = true; encodingMode_ = 1; scsiTimeout_ = 0; actMode_ = TrackData::AUDIO; writeEndLba_ = 0; memset(modeSelectData_, 0, 12); memset(&diskInfo_, 0, sizeof(DiskInfo)); for (i = 0; i < maxScannedSubChannels_; i++) scannedSubChannels_[i] = new PQSubChannel16; // reads little endian samples audioDataByteOrder_ = 0; } TeacCdr55::~TeacCdr55() { int i; for (i = 0; i < maxScannedSubChannels_; i++) { delete scannedSubChannels_[i]; scannedSubChannels_[i] = NULL; } } // static constructor CdrDriver *TeacCdr55::instance(ScsiIf *scsiIf, unsigned long options) { return new TeacCdr55(scsiIf, options); } // sets speed // return: 0: OK // 1: illegal speed int TeacCdr55::speed(int s) { if (s >= 0 && s <= 4 && s != 3) { speed_ = s; } else if (s == 3) { speed_ = 2; } else if (s > 4) { speed_ = 4; } else { return 1; } return 0; } // loads ('unload' == 0) or ejects ('unload' == 1) tray // return: 0: OK // 1: scsi command failed int TeacCdr55::loadUnload(int unload) const { unsigned char cmd[6]; memset(cmd, 0, 6); cmd[0] = 0x1b; // START/STOP UNIT cmd[4] = unload ? 0x02 : 0x03; if (sendCmd(cmd, 6, NULL, 0, NULL, 0) != 0) { log_message(-2, "Cannot load/unload medium."); return 1; } return 0; } // Retrieves mode select header and block descriptor and stores it in // class member 'modeSelectData_' for later usage with various mode select // commands. // Return: 0: OK, 1: SCSI error int TeacCdr55::getModeSelectData() { unsigned char cmd[6]; memset(cmd, 0, 6); memset(modeSelectData_, 0, 12); cmd[0] = 0x1a; // MODE SENSE cmd[4] = 12; if (sendCmd(cmd, 6, NULL, 0, modeSelectData_, 12, 1) != 0) { log_message(-2, "Mode Sense failed."); return 1; } return 0; } // sets read/write speed and simulation mode // return: 0: OK // 1: scsi command failed int TeacCdr55::setWriteSpeed() { unsigned char mp[4]; mp[0] = 0x31; mp[1] = 2; mp[2] = 0; mp[3] = 0; switch (speed_) { case 1: mp[2] = 0; break; case 2: mp[2] = 1; break; case 0: case 4: mp[2] = 2; break; } if (setModePage6(mp, modeSelectData_, NULL, 1) != 0) { log_message(-2, "Cannot set speed mode page."); return 1; } return 0; } // Sets write parameters via mode page 0x22. // return: 0: OK // 1: scsi command failed int TeacCdr55::setWriteParameters() { unsigned char mp[9]; memset(mp, 0, 9); mp[0] = 0x22; mp[1] = 7; if (multiSession()) { mp[4] = 4; // session at once, keep session open } else { if (diskInfo_.sessionCnt > 0) mp[4] = 0x84; // session at once and close disk else mp[4] = 2; // disk at once } if (setModePage6(mp, modeSelectData_, NULL, 1) != 0) { log_message(-2, "Cannot set write method mode page."); return 1; } return 0; } int TeacCdr55::setSimulationMode() { unsigned char mp[3]; mp[0] = 0x21; mp[1] = 1; if (simulate()) mp[2] = 3; else mp[2] = 0; if (setModePage6(mp, modeSelectData_, NULL, 1) != 0) { log_message(-2, "Cannot set preview write mode page."); return 1; } return 0; } int TeacCdr55::setWriteDensity(TrackData::Mode mode) { long blockLength = blockSize(mode, TrackData::SUBCHAN_NONE); unsigned char cmd[6]; unsigned char data[12]; memset(cmd, 0, 6); cmd[0] = 0x15; // MODE SELECT cmd[1] = 0x10; cmd[4] = 12; memcpy(data, modeSelectData_, 12); data[0] = 0; data[3] = 8; data[9] = 0; switch (mode) { case TrackData::AUDIO: data[4] = 0x04; break; case TrackData::MODE1: case TrackData::MODE1_RAW: data[4] = 0x01; break; case TrackData::MODE2: data[4] = 0xc1; break; case TrackData::MODE2_FORM1: data[4] = 0x81; break; case TrackData::MODE2_FORM2: data[4] = 0x82; break; case TrackData::MODE2_RAW: case TrackData::MODE2_FORM_MIX: data[4] = 0x83; // I'm not sure if this really allows writing of mixed // form 1 and form 2 sectors. break; case TrackData::MODE0: log_message(-3, "Illegal mode in 'TeacCdr55::setWriteDensity()'."); return 0; break; } data[10] = blockLength >> 8; data[11] = blockLength; log_message(3, "Changing write density to 0x%02x/0x%02x%02x.", data[4], data[10], data[11]); if (sendCmd(cmd, 6, data, 12, NULL, 0, 1) != 0) { log_message(-2, "Cannot set density/block size."); return 1; } return 0; } // Judges disc and performs power calibration if possible. // judge: 1: judge disc, 0: don't judge disc // Return 0: OK // 1: judge disc rejected inserted medium // 2: SCSI error occured int TeacCdr55::executeOPC(int judge) { unsigned char cmd[12]; const unsigned char *senseCode; int senseLen; memset(cmd, 0, 12); cmd[0] = 0xec; // OPC EXECUTION if (judge) { cmd[1] = 1; // judge current disc log_message(2, "Judging disk..."); switch (sendCmd(cmd, 12, NULL, 0, NULL, 0, 0)) { case 0: // OK, disc can be written at selected speed break; case 1: log_message(-2, "Judge disk command failed."); return 2; break; case 2: // Check sense code senseCode = scsiIf_->getSense(senseLen); if (senseLen > 12 && (senseCode[2] & 0x0f) == 5 && senseCode[7] != 0) { switch (senseCode[12]) { case 0xcd: log_message(-2, "Cannot ensure reliable writing with inserted disk."); return 1; break; case 0xce: log_message(-2, "Cannot ensure reliable writing at selected speed."); return 1; break; case 0xcf: log_message(-2, "Cannot ensure reliable writing - disk has no ID code."); return 1; break; } } scsiIf_->printError(); return 2; break; } } if (simulate()) { log_message(2, "Skipping optimum power calibration in simulation mode."); return 0; } cmd[1] = 0; log_message(2, "Performing optimum power calibration..."); if (sendCmd(cmd, 12, NULL, 0, NULL, 0, 1) != 0) { log_message(-2, "Optimum power calibration failed."); return 2; } return 0; } // Clears the drive's subcode data. // Return: 0: OK, 1: SCSI error int TeacCdr55::clearSubcode() { unsigned char cmd[12]; memset(cmd, 0, 12); cmd[0] = 0xe4; // CLEAR SUBCODE cmd[5] = 0x80; if (sendCmd(cmd, 12, NULL, 0, NULL, 0, 1) != 0) { log_message(-2, "Clear subcode failed."); return 1; } return 0; } // Sets subcode data. // start: start LBA // end: end LBA, one greater than last block with specfied subcode data // ctl: track mode flags in bits 4-7 // trackNr: track number // indexNr: index number // pflag: P-channel flag // return: 0: OK, 1: SCSI error int TeacCdr55::setSubcode(long start, long end, unsigned char ctl, int trackNr, int indexNr, int pflag) { assert(start < end); unsigned char cmd[12]; unsigned char data[4]; long len = end - start; log_message(4, "Setting subcode: start: %6ld, end: %6ld, len: %6ld, CTL: %02x P: %d, T: %2d I: %2d", start, end, len, ctl, pflag, trackNr, indexNr); memset(cmd, 0, 12); cmd[0] = 0xb3; // SET LIMITS cmd[2] = start >> 24; cmd[3] = start >> 16; cmd[4] = start >> 8; cmd[5] = start; cmd[6] = len >> 24; cmd[7] = len >> 16; cmd[8] = len >> 8; cmd[9] = len; if (sendCmd(cmd, 12, NULL, 0, NULL, 0, 1) != 0) { log_message(-2, "Cannot set limits."); return 1; } memset(cmd, 0, 10); cmd[0] = 0xc2; // SET SUBCODE cmd[8] = 4; // parameter list length data[0] = pflag != 0 ? 1 : 0; data[1] = (ctl & 0xf0) | 0x01; data[2] = SubChannel::bcd(trackNr); data[3] = SubChannel::bcd(indexNr); if (sendCmd(cmd, 10, data, 4, NULL, 0, 1) != 0) { log_message(-2, "Cannot set subcode."); return 1; } return 0; } // Sets the subcodes for given track. // track: actual track // trackNr: number of current track // start: LBA of track start (index 1), pre-gap length is taken from 'track' // end: LBA of track end, same as 'nstart' if next track has no pre-gap // nstart: LBA of next track start (index 1) // Return: 0: OK // 1: SCSI command failed struct SubCodeData { long start; // start LBA int index; // index int pflag; // P channel flag }; int TeacCdr55::setSubcodes(const Track *track, int trackNr, long start, long end, long nstart) { assert(start < end); assert(end <= nstart); unsigned char ctl = trackCtl(track); SubCodeData subCodes[102]; // index 0-99 + P-channel entry + end-entry int n = 0; int i; if (track->start().lba() != 0) { // pre-gap subCodes[n].start = start - track->start().lba(); subCodes[n].index = 0; subCodes[n].pflag = 1; n++; } // track start (index 1) subCodes[n].start = start; subCodes[n].index = 1; subCodes[n].pflag = 0; n++; // create index marks // We have to check if we have to add an entry for the P-channel flag if the // pre-gap of the following track is shorter than 2 seconds // calculate LBA where P-channel must be set for next track, if // it is behind 'end' it'll be ignored long pChangeLba = nstart - 150; int pChangeEntry = 0; // set to 1 if a P-channel entry was created long indexStart; for (i = 0; i < track->nofIndices(); i++) { indexStart = track->getIndex(i).lba() + start; if (indexStart > pChangeLba && pChangeEntry == 0) { subCodes[n].start = pChangeLba; subCodes[n].index = i + 1; subCodes[n].pflag = 1; n++; pChangeEntry = 1; } else if (indexStart == pChangeLba) { // index increment coincides with p channel change position // -> no entry required pChangeEntry = 1; } subCodes[n].start = indexStart; subCodes[n].index = i + 2; subCodes[n].pflag = indexStart >= pChangeLba ? 1 : 0; n++; } if (pChangeEntry == 0 && pChangeLba < end) { subCodes[n].start = pChangeLba; subCodes[n].index = i + 1; subCodes[n].pflag = 1; n++; } // add end of track as last entry subCodes[n].start = end; subCodes[n].index = 0; // not used subCodes[n].pflag = 0; // not used assert(n <= 101); // now issue the subcode commands for (i = 0; i < n; i++) { if (setSubcode(subCodes[i].start, subCodes[i+1].start, ctl, trackNr, subCodes[i].index, subCodes[i].pflag) != 0) { return 1; } } return 0; } // Sets sub codes for all tracks. // Return: 0: OK // 1: toc contains no track // 2: SCSI error int TeacCdr55::setSubcodes() { const Track *t, *nt; int trackNr; Msf start, end; Msf nstart, nend; long offset = diskInfo_.thisSessionLba; int first = 1; TrackIterator itr(toc_); trackNr = diskInfo_.lastTrackNr; if ((nt = itr.first(nstart, nend)) == NULL) { return 1; } if (clearSubcode() != 0) return 2; do { trackNr += 1; t = nt; start = nstart; end = nend; if ((nt = itr.next(nstart, nend)) == NULL) nstart = Msf(toc_->length()); // start of lead-out if (first) { // set sub code for pre-gap of first track first = 0; if (setSubcode(offset - 150, offset, trackCtl(t), trackNr, 0, 1) != 0) return 2; } if (setSubcodes(t, trackNr, start.lba() + offset, end.lba() + offset, nstart.lba() + offset) != 0) { return 2; } } while (nt != NULL); return 0; } // Sets toc data. // Return: 0: OK // 1: toc contains no track // 2: SCSI command failed int TeacCdr55::setToc() { const Track *t; int trackNr; Msf start, end; long offset = diskInfo_.thisSessionLba + 150; // LBA offset int trackOffset = diskInfo_.lastTrackNr + 1; unsigned char firstTrackCtl = 0; unsigned char lastTrackCtl = 0; unsigned char ctl; int lastTrackNr = 0; int sessFormat; unsigned char cmd[10]; unsigned char data[3 + 102 * 5]; // max. 99 tracks + 3 POINT entries unsigned char *p = data + 3; data[0] = 0; data[1] = 0; data[2] = 0; TrackIterator itr(toc_); for (t = itr.first(start, end), trackNr = trackOffset; t != NULL && trackNr <= 99; t = itr.next(start, end), trackNr++) { Msf s(start.lba() + offset); ctl = trackCtl(t); if (trackNr == trackOffset) firstTrackCtl = ctl; p[0] = ctl | 0x01; p[1] = SubChannel::bcd(trackNr); p[2] = SubChannel::bcd(s.min()); p[3] = SubChannel::bcd(s.sec()); p[4] = SubChannel::bcd(s.frac()); p += 5; lastTrackNr = trackNr; lastTrackCtl = ctl; } if (lastTrackNr == 0) return 1; // Point A0 entry (first track nr and session format) if (diskInfo_.empty) { // disk is empty -> take toc type from toc-file sessFormat = sessionFormat(); } else { // Disk has already a recorded session -> take toc type from // previous session if it is well defined. switch (diskInfo_.diskTocType) { case 0x00: case 0x10: case 0x20: sessFormat = diskInfo_.diskTocType; break; default: sessFormat = sessionFormat(); break; } } p[0] = firstTrackCtl | 0x01; p[1] = 0xa0; p[2] = SubChannel::bcd(trackOffset); p[3] = SubChannel::bcd(sessFormat); p[4] = 0; p += 5; // Point A1 entry (last track nr) p[0] = lastTrackCtl | 0x01; p[1] = 0xa1; p[2] = SubChannel::bcd(lastTrackNr); p[3] = 0; p[4] = 0; p += 5; // Point A2 entry (start of lead-out) Msf los(toc_->length().lba() + offset); p[0] = lastTrackCtl | 0x01; p[1] = 0xa2; p[2] = SubChannel::bcd(los.min()); p[3] = SubChannel::bcd(los.sec()); p[4] = SubChannel::bcd(los.frac()); p += 5; long dataLen = p - data; #if 1 log_message(4, "TOC data:"); long i; for (i = 3; i < dataLen; i += 5) { log_message(4, "%02x %02x %02x:%02x:%02x", data[i], data[i+1], data[i+2], data[i+3], data[i+4]); } #endif memset(cmd, 0, 10); cmd[0] = 0xc2; // SET SUBCODE cmd[7] = dataLen >> 8; cmd[8] = dataLen; if (sendCmd(cmd, 10, data, dataLen, NULL, 0, 1) != 0) { log_message(-2, "Cannot set TOC data."); return 2; } return 0; } // Sets catalog number. // Return: 0: OK // 1: SCSI command failed int TeacCdr55::setCatalog() { unsigned char cmd[10]; unsigned char data[15]; int i; if (!toc_->catalogValid()) return 0; data[0] = 0; if (toc_->leadInMode() == TrackData::AUDIO) data[1] = 0x02; else data[1] = 0x42; for (i = 0; i < 13; i++) data[2 + i] = toc_->catalog(i); memset(cmd, 0, 10); cmd[0] = 0xc2; // SET SUBCODE cmd[8] = 15; if (sendCmd(cmd, 10, data, 15, NULL, 0, 1) != 0) { log_message(-2, "Cannot set catalog number data."); return 2; } return 0; } // Sets ISRC codes for all tracks int TeacCdr55::setIsrc() { const Track *t; int trackNr; Msf start, end; int trackOffset = diskInfo_.lastTrackNr + 1; unsigned char cmd[10]; unsigned char data[15]; data[0] = 0; memset(cmd, 0, 10); cmd[0] = 0xc2; // SET SUBCODE cmd[8] = 15; TrackIterator itr(toc_); for (t = itr.first(start, end), trackNr = trackOffset; t != NULL && trackNr <= 99; t = itr.next(start, end), trackNr++) { if (t->isrcValid()) { data[1] = trackCtl(t) | 0x03; data[2] = t->isrcCountry(0); data[3] = t->isrcCountry(1); data[4] = t->isrcOwner(0); data[5] = t->isrcOwner(1); data[6] = t->isrcOwner(2); data[7] = t->isrcYear(0) + '0'; data[8] = t->isrcYear(1) + '0'; data[9] = t->isrcSerial(0) + '0'; data[10] = t->isrcSerial(1) + '0'; data[11] = t->isrcSerial(2) + '0'; data[12] = t->isrcSerial(3) + '0'; data[13] = t->isrcSerial(4) + '0'; data[14] = 0; cmd[6] = trackNr; if (sendCmd(cmd, 10, data, 15, NULL, 0, 1) != 0) { log_message(-2, "Cannot set ISRC code."); return 2; } } } return 0; } // Need to overload this function to set the WriteExtension flag. It'll // also change the write density if the actual mode changes. int TeacCdr55::writeData(TrackData::Mode mode, TrackData::SubChannelMode sm, long &lba, const char *buf, long len) { assert(blocksPerWrite_ > 0); int writeLen = 0; unsigned char cmd[10]; long blockLength = blockSize(mode, TrackData::SUBCHAN_NONE); #if 0 long sum, i; sum = 0; for (i = 0; i < len * blockLength; i++) { sum += buf[i]; } log_message(0, "W: %ld: %ld, %ld, %ld", lba, blockLength, len, sum); #endif if (mode != actMode_) { actMode_ = mode; log_message(3, "Changed write density at LBA %ld.", lba); if (setWriteDensity(actMode_) != 0) { return 1; } } memset(cmd, 0, 10); cmd[0] = 0x2a; // WRITE10 while (len > 0) { writeLen = (len > blocksPerWrite_ ? blocksPerWrite_ : len); cmd[2] = lba >> 24; cmd[3] = lba >> 16; cmd[4] = lba >> 8; cmd[5] = lba; cmd[7] = writeLen >> 8; cmd[8] = writeLen & 0xff; if (lba + writeLen >= writeEndLba_) { // last write command log_message(4, "Last write command at LBA: %ld", lba); cmd[9] = 0; } else { cmd[9] = 0x80; // extended write } if (sendCmd(cmd, 10, (unsigned char *)buf, writeLen * blockLength, NULL, 0) != 0) { log_message(-2, "Write data failed."); return 1; } buf += writeLen * blockLength; lba += writeLen; len -= writeLen; } return 0; } int TeacCdr55::initDao(const Toc *toc) { long offset; // LBA offset for this session long n; toc_ = toc; blockLength_ = AUDIO_BLOCK_LEN; blocksPerWrite_ = scsiIf_->maxDataLen() / blockLength_; assert(blocksPerWrite_ > 0); diskInfo(); if (!diskInfo_.valid.empty || !diskInfo_.valid.append) { log_message(-2, "Cannot determine status of inserted medium."); return 1; } if (!diskInfo_.append) { log_message(-2, "Inserted medium is not appendable."); return 1; } offset = diskInfo_.thisSessionLba; // allocate buffer for writing zeros n = blocksPerWrite_ * blockLength_; delete[] zeroBuffer_; zeroBuffer_ = new char[n]; memset(zeroBuffer_, 0, n); writeEndLba_ = toc_->length().lba() + offset; actMode_ = toc_->leadInMode(); if (getModeSelectData() != 0 || setWriteDensity(actMode_) != 0 || setSimulationMode() != 0 || setWriteParameters() != 0 || setWriteSpeed() != 0) { return 1; } return 0; } int TeacCdr55::startDao() { scsiTimeout_ = scsiIf_->timeout(3 * 60); if (executeOPC(1) != 0 || setSubcodes() != 0 || setCatalog() != 0 || setToc() != 0 || setIsrc() != 0) { return 1; } long lba = diskInfo_.thisSessionLba - 150; if (writeZeros(actMode_, TrackData::SUBCHAN_NONE, lba, lba + 150, 150) != 0) { return 1; } return 0; } int TeacCdr55::finishDao() { //log_message(0, "Writing lead-out..."); // wait until writing of lead-out is finished ??? scsiIf_->timeout(scsiTimeout_); delete[] zeroBuffer_, zeroBuffer_ = NULL; return 0; } void TeacCdr55::abortDao() { unsigned char cmd[10]; // Send a zero length write command with cleared extendened write bit. // I don't know if it has the expected effect. memset(cmd, 0, 10); cmd[0] = 0x2a; // WRITE10 sendCmd(cmd, 10, NULL, 0, NULL, 0, 0); } DiskInfo *TeacCdr55::diskInfo() { int i; unsigned char cmd[12]; unsigned char data[12]; memset(&diskInfo_, 0, sizeof(DiskInfo)); diskInfo_.cdrw = 0; diskInfo_.valid.cdrw = 1; memset(cmd, 0, 10); memset(data, 0, 8); cmd[0] = 0x25; // READ CAPACITY cmd[9] = 0x80; if (sendCmd(cmd, 10, NULL, 0, data, 8, 1) != 0) { log_message(-1, "Cannot read CD-R capacity."); } else { diskInfo_.capacity = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; diskInfo_.valid.capacity = 1; } memset(cmd, 0, 12); memset(data, 0, 4); cmd[0] = 0xe6; // NEXT WRITABLE ADDRESS cmd[2] = 0xff; cmd[3] = 0xff; cmd[4] = 0xff; cmd[5] = 0xff; cmd[6] = 0xff; cmd[7] = 0xff; cmd[8] = 0xff; cmd[9] = 0xff; long nwa = 0; switch (sendCmd(cmd, 12, NULL, 0, data, 4, 0)) { case 0: // command succeed -> writable area exists diskInfo_.empty = 1; diskInfo_.valid.empty = 1; nwa = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; log_message(4, "Next writable address: %ld", nwa); break; case 1: // SCSI command failed, no sense data -> cannot tell anything log_message(-1, "Get next writable address failed."); break; case 2: // SCSI command failed, sense data available // assume that disk is not writable log_message(4, "Cannot get next writable address."); diskInfo_.empty = 0; diskInfo_.valid.empty = 1; break; } // SCSI command failed -> stop further processing if (diskInfo_.valid.empty == 0) return &diskInfo_; memset(cmd, 0, 10); memset(data, 0, 4); cmd[0] = 0x43; // READ TOC cmd[6] = 1; cmd[8] = 4; if (sendCmd(cmd, 10, NULL, 0, data, 4, 0) == 0) { log_message(4, "First track %u, last track %u", data[2], data[3]); diskInfo_.lastTrackNr = data[3]; } else { log_message(4, "READ TOC (format 0) failed."); } if (diskInfo_.lastTrackNr > 0) { diskInfo_.empty = 0; diskInfo_.diskTocType = 0xff; // undefined memset(cmd, 0, 10); memset(data, 0, 12); cmd[0] = 0x43; // READ TOC cmd[6] = 0; cmd[8] = 12; cmd[9] = 1 << 6; if (sendCmd(cmd, 10, NULL, 0, data, 12) == 0) { diskInfo_.sessionCnt = data[3]; diskInfo_.lastSessionLba = (data[8] << 24) | (data[9] << 16) | (data[10] << 8) | data[11]; log_message(4, "First session %u, last session %u, last session start %ld", data[2], data[3], diskInfo_.lastSessionLba); } else { log_message(4, "READ TOC (format 1) failed."); } if (diskInfo_.sessionCnt > 0) { int len; CdRawToc *toc = getRawToc(diskInfo_.sessionCnt, &len); if (toc != NULL) { for (i = 0; i < len; i++) { if (toc[i].sessionNr == diskInfo_.sessionCnt) { if (toc[i].point == 0xb0 && toc[i].min != 0xff && toc[i].sec != 0xff && toc[i].frame != 0xff) { int m = SubChannel::bcd2int(toc[i].min); int s = SubChannel::bcd2int(toc[i].sec); int f = SubChannel::bcd2int(toc[i].frame); if (m < 90 && s < 60 && f < 75) diskInfo_.thisSessionLba = Msf(m, s, f).lba(); // + 150 - 150 } if (toc[i].point == 0xa0) { diskInfo_.diskTocType = SubChannel::bcd2int(toc[i].psec); } } } if (diskInfo_.thisSessionLba > 0) { if (diskInfo_.lastTrackNr < 99) diskInfo_.append = 1; } else { log_message(4, "Did not find BO pointer in session %d.", diskInfo_.sessionCnt); } delete[] toc; } else { log_message(4, "getRawToc failed."); } } } else { // disk is empty and appendable diskInfo_.empty = 1; diskInfo_.append = 1; } diskInfo_.valid.append = 1; return &diskInfo_; } // tries to read catalog number from disk and adds it to 'toc' // return: 1 if valid catalog number was found, else 0 int TeacCdr55::readCatalog(Toc *toc, long startLba, long endLba) { unsigned char cmd[10]; unsigned char data[24]; char catalog[14]; int i; memset(cmd, 0, 10); memset(data, 0, 24); cmd[0] = 0x42; // READ SUB-CHANNEL cmd[2] = 1 << 6; cmd[3] = 0x02; // get media catalog number cmd[8] = 24; // transfer length if (sendCmd(cmd, 10, NULL, 0, data, 24) != 0) { log_message(-2, "Cannot get catalog number."); return 0; } if (data[8] & 0x80) { for (i = 0; i < 13; i++) { catalog[i] = data[0x09 + i]; } catalog[13] = 0; if (toc->catalog(catalog) == 0) { return 1; } } return 0; } int TeacCdr55::readIsrc(int trackNr, char *buf) { unsigned char cmd[10]; unsigned char data[24]; int i; buf[0] = 0; memset(cmd, 0, 10); memset(data, 0, 24); cmd[0] = 0x42; // READ SUB-CHANNEL cmd[2] = 1 << 6; cmd[3] = 0x03; // get media catalog number cmd[6] = trackNr; cmd[8] = 24; // transfer length if (sendCmd(cmd, 10, NULL, 0, data, 24) != 0) { log_message(-2, "Cannot get ISRC code."); return 0; } if (data[8] & 0x80) { for (i = 0; i < 12; i++) { buf[i] = data[0x09 + i]; } buf[12] = 0; } return 0; } int TeacCdr55::analyzeTrack(TrackData::Mode mode, int trackNr, long startLba, long endLba, Msf *indexIncrements, int *indexIncrementCnt, long *pregap, char *isrcCode, unsigned char *ctl) { int ret = analyzeTrackScan(mode, trackNr, startLba, endLba, indexIncrements, indexIncrementCnt, pregap, isrcCode, ctl); if (mode == TrackData::AUDIO) readIsrc(trackNr, isrcCode); else *isrcCode = 0; return ret; } int TeacCdr55::readSubChannels(TrackData::SubChannelMode, long lba, long len, SubChannel ***chans, Sample *audioData) { int retries = 5; unsigned char cmd[12]; int i; cmd[0] = 0xd8; // READ CD_DA cmd[1] = 0; cmd[2] = lba >> 24; cmd[3] = lba >> 16; cmd[4] = lba >> 8; cmd[5] = lba; cmd[6] = len >> 24; cmd[7] = len >> 16; cmd[8] = len >> 8; cmd[9] = len; cmd[10] = 0x01; // Q sub-channel data cmd[11] = 0; while (1) { if (sendCmd(cmd, 12, NULL, 0, transferBuffer_, len * (AUDIO_BLOCK_LEN + 16), retries == 0 ? 1 : 0) != 0) { if (retries == 0) return 1; } else { break; } retries--; } for (i = 0; i < len; i++) { PQSubChannel16 *chan = (PQSubChannel16*)scannedSubChannels_[i]; unsigned char *p = transferBuffer_ + i * (AUDIO_BLOCK_LEN + 16) + AUDIO_BLOCK_LEN; // slightly reorder the sub-channel so it is suitable for 'PQSubChannel16' p[0] <<= 4; // ctl/adr p[0] |= p[1]; p[1] = p[2]; // track nr p[2] = p[3]; // index nr p[3] = p[4]; // min p[4] = p[5]; // sec p[5] = p[6]; // frame p[6] = 0; // zero // p[7] is amin // p[8] is asec // p[9] is aframe chan->init(p); if (chan->checkConsistency()) chan->calcCrc(); } if (audioData != NULL) { unsigned char *p = transferBuffer_; for (i = 0; i < len; i++) { memcpy(audioData, p, AUDIO_BLOCK_LEN); p += AUDIO_BLOCK_LEN + 16; audioData += SAMPLES_PER_BLOCK; } } *chans = scannedSubChannels_; return 0; } CdRawToc *TeacCdr55::getRawToc(int sessionNr, int *len) { unsigned char cmd[10]; unsigned short dataLen; unsigned char *data = NULL;; unsigned char reqData[4]; // buffer for requestion the actual length unsigned char *p = NULL; int i, entries; CdRawToc *rawToc; assert(sessionNr >= 1); // read disk toc length memset(cmd, 0, 10); cmd[0] = 0x43; // READ TOC cmd[6] = sessionNr; cmd[8] = 4; cmd[9] |= 2 << 6; // get Q subcodes if (sendCmd(cmd, 10, NULL, 0, reqData, 4) != 0) { log_message(-2, "Cannot read raw disk toc."); return NULL; } dataLen = ((reqData[0] << 8) | reqData[1]) + 2; log_message(4, "Raw toc data len: %d", dataLen); if (dataLen == 4) return NULL; data = new unsigned char[dataLen]; // read disk toc cmd[7] = dataLen >> 8; cmd[8] = dataLen; if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) { log_message(-2, "Cannot read raw disk toc."); delete[] data; return NULL; } entries = (((data[0] << 8) | data[1]) - 2) / 11; rawToc = new CdRawToc[entries]; for (i = 0, p = data + 4; i < entries; i++, p += 11 ) { #if 0 log_message(0, "%d %02x %02d %2x %02x:%02x:%02x %02x %02x:%02x:%02x", p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10]); #endif rawToc[i].sessionNr = p[0]; rawToc[i].adrCtl = p[1]; rawToc[i].point = p[3]; rawToc[i].min = p[4]; rawToc[i].sec = p[5]; rawToc[i].frame = p[6]; rawToc[i].pmin = p[8]; rawToc[i].psec = p[9]; rawToc[i].pframe = p[10]; } delete[] data; *len = entries; return rawToc; } long TeacCdr55::readTrackData(TrackData::Mode mode, TrackData::SubChannelMode, long lba, long len, unsigned char *buf) { unsigned char cmd[10]; long blockLen = 2340; long i; TrackData::Mode actMode; int ok = 0; int softError; const unsigned char *sense; int senseLen; if (setBlockSize(blockLen) != 0) return 0; memset(cmd, 0, 10); cmd[0] = 0x28; // READ10 cmd[2] = lba >> 24; cmd[3] = lba >> 16; cmd[4] = lba >> 8; cmd[5] = lba; while (len > 0 && !ok) { cmd[7] = len >> 8; cmd[8] = len; memset(transferBuffer_, 0, len * blockLen); switch (sendCmd(cmd, 10, NULL, 0, transferBuffer_, len * blockLen, 0)) { case 0: ok = 1; break; case 2: softError = 0; sense = scsiIf_->getSense(senseLen); if (senseLen > 0x0c) { if ((sense[2] &0x0f) == 5) { switch (sense[12]) { case 0x63: // end of user area encountered on this track case 0x64: // Illegal mode for this track softError = 1; break; } } else if ((sense[2] & 0x0f) == 3) { // Medium error switch (sense[12]) { case 0x02: // No seek complete, sector not found case 0x11: // L-EC error return -2; break; } } } if (!softError) { scsiIf_->printError(); return -1; } break; default: log_message(-2, "Read error at LBA %ld, len %ld", lba, len); return -1; break; } if (!ok) { len--; } } unsigned char *sector = transferBuffer_; for (i = 0; i < len; i++) { actMode = determineSectorMode(sector); if (!(actMode == mode || (mode == TrackData::MODE2_FORM_MIX && (actMode == TrackData::MODE2_FORM1 || actMode == TrackData::MODE2_FORM2)) || (mode == TrackData::MODE1_RAW && actMode == TrackData::MODE1) || (mode == TrackData::MODE2_RAW && (actMode == TrackData::MODE2 || actMode == TrackData::MODE2_FORM1 || actMode == TrackData::MODE2_FORM2)))) { return i; } if (buf != NULL) { switch (mode) { case TrackData::MODE1: memcpy(buf, sector + 4, MODE1_BLOCK_LEN); buf += MODE1_BLOCK_LEN; break; case TrackData::MODE2: case TrackData::MODE2_FORM_MIX: memcpy(buf, sector + 4, MODE2_BLOCK_LEN); buf += MODE2_BLOCK_LEN; break; case TrackData::MODE2_FORM1: memcpy(buf, sector + 12, MODE2_FORM1_DATA_LEN); buf += MODE2_FORM1_DATA_LEN; break; case TrackData::MODE2_FORM2: memcpy(buf, sector + 12, MODE2_FORM2_DATA_LEN); buf += MODE2_FORM2_DATA_LEN; break; case TrackData::MODE1_RAW: case TrackData::MODE2_RAW: memcpy(buf, syncPattern, 12); memcpy(buf + 12, sector, 2340); buf += AUDIO_BLOCK_LEN; break; case TrackData::MODE0: case TrackData::AUDIO: log_message(-3, "TeacCdr55::readTrackData: Illegal mode."); return 0; break; } } sector += blockLen; } return len; } Toc *TeacCdr55::readDiskToc(int session, const char *audioFilename) { Toc *toc = CdrDriver::readDiskToc(session, audioFilename); setBlockSize(MODE1_BLOCK_LEN); return toc; } Toc *TeacCdr55::readDisk(int session, const char *fname) { Toc *toc = CdrDriver::readDisk(session, fname); setBlockSize(MODE1_BLOCK_LEN); return toc; } int TeacCdr55::readAudioRange(ReadDiskInfo *rinfo, int fd, long start, long end, int startTrack, int endTrack, TrackInfo *info) { if (!onTheFly_) { int t; log_message(1, "Analyzing..."); for (t = startTrack; t <= endTrack; t++) { long totalProgress; totalProgress = t * 1000; totalProgress /= rinfo->tracks; sendReadCdProgressMsg(RCD_ANALYZING, rinfo->tracks, t + 1, 0, totalProgress); log_message(1, "Track %d...", t + 1); info[t].isrcCode[0] = 0; readIsrc(t + 1, info[t].isrcCode); if (info[t].isrcCode[0] != 0) log_message(2, "Found ISRC code."); totalProgress = (t + 1) * 1000; totalProgress /= rinfo->tracks; sendReadCdProgressMsg(RCD_ANALYZING, rinfo->tracks, t + 1, 1000, totalProgress); } log_message(1, "Reading..."); } return CdrDriver::readAudioRangeParanoia(rinfo, fd, start, end, startTrack, endTrack, info); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/TeacCdr55.h���������������������������������������������������������������0000664�0000000�0000000�00000006107�15114537466�0017275�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <andreas@daneb.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 * (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. */ #ifndef __TEAC_CDR55_H__ #define __TEAC_CDR55_H__ #include "CdrDriver.h" class Toc; class Track; class TeacCdr55 : public CdrDriver { public: TeacCdr55(ScsiIf *scsiIf, unsigned long options); ~TeacCdr55(); static CdrDriver *instance(ScsiIf *scsiIf, unsigned long options); unsigned long getReadCapabilities(const CdToc *, int) const { return 0; } // MMC compatible drives take little endian samples int bigEndianSamples() const { return 0; } int speed(int); DiskInfo *diskInfo(); int driveInfo(DriveInfo *, bool showErrorMsg); Toc *readDiskToc(int, const char *audioFilename); Toc *readDisk(int, const char *audioFilename); int initDao(const Toc *); int startDao(); int finishDao(); void abortDao(); int writeData(TrackData::Mode, TrackData::SubChannelMode, long &lba, const char *buf, long len); int loadUnload(int) const; protected: DiskInfo diskInfo_; unsigned char modeSelectData_[12]; TrackData::Mode actMode_; // actual writing mode, used to switch modes // in 'writeData()' long writeEndLba_; // LBA at which writing ends, used in 'writeData()' int scsiTimeout_; int getModeSelectData(); int setWriteSpeed(); int setWriteParameters(); int setSimulationMode(); int setWriteDensity(TrackData::Mode); int executeOPC(int judge); int clearSubcode(); int setSubcode(long start, long end, unsigned char ctl, int trackNr, int indexNr, int pflag); int setSubcodes(const Track *track, int trackNr, long start, long end, long nstart); int setSubcodes(); int setToc(); int setCatalog(); int setIsrc(); CdRawToc *getRawToc(int sessionNr, int *len); int analyzeTrack(TrackData::Mode mode, int trackNr, long startLba, long endLba, Msf *indexIncrements, int *indexIncrementCnt, long *pregap, char *isrcCode, unsigned char *ctl); int readSubChannels(TrackData::SubChannelMode, long lba, long len, SubChannel ***, Sample *); long readTrackData(TrackData::Mode, TrackData::SubChannelMode, long lba, long len, unsigned char *buf); int readIsrc(int trackNr, char *buf); int readCatalog(class Toc *, long startLba, long endLba); int readAudioRange(ReadDiskInfo *, int fd, long start, long end, int startTrack, int endTrack, TrackInfo *); }; #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/ToshibaReader.cc����������������������������������������������������������0000664�0000000�0000000�00000004152�15114537466�0020466�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1999-2001 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #include <config.h> #include <unistd.h> #include <assert.h> #include "ToshibaReader.h" #include "Toc.h" #include "log.h" ToshibaReader::ToshibaReader(ScsiIf *scsiIf, unsigned long options) : PlextorReader(scsiIf, options | OPT_DRV_GET_TOC_GENERIC) { driverName_ = "Toshiba CD-ROM Reader - Version 0.1"; audioDataByteOrder_ = 0; model_ = 0; } // static constructor CdrDriver *ToshibaReader::instance(ScsiIf *scsiIf, unsigned long options) { return new ToshibaReader(scsiIf, options); } int ToshibaReader::readSubChannels(TrackData::SubChannelMode, long lba, long len, SubChannel ***chans, Sample *audioData) { unsigned char cmd[10]; int tries = 5; int ret; if (setBlockSize(AUDIO_BLOCK_LEN, 0x82) != 0) return 1; cmd[0] = 0x28; // READ10 cmd[1] = 0x08; // force unit access cmd[2] = lba >> 24; cmd[3] = lba >> 16; cmd[4] = lba >> 8; cmd[5] = lba; cmd[6] = 0; cmd[7] = len >> 8; cmd[8] = len; cmd[9] = 0; do { ret = sendCmd(cmd, 10, NULL, 0, (unsigned char*)audioData, len * AUDIO_BLOCK_LEN, (tries == 1) ? 1 : 0); if (ret != 0 && tries == 1) { log_message(-2, "Reading of audio data failed at sector %ld.", lba); return 1; } tries--; } while (ret != 0 && tries > 0); *chans = NULL; return 0; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/ToshibaReader.h�����������������������������������������������������������0000664�0000000�0000000�00000002467�15114537466�0020337�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1999-2001 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __TOSHIBA_READER_H__ #define __TOSHIBA_READER_H__ #include "PlextorReader.h" class Toc; class Track; class ToshibaReader : public PlextorReader { public: ToshibaReader(ScsiIf *scsiIf, unsigned long options); static CdrDriver *instance(ScsiIf *scsiIf, unsigned long options); unsigned long getReadCapabilites(const CdToc *, int) const { return 0; } protected: int readSubChannels(TrackData::SubChannelMode, long lba, long len, SubChannel ***, Sample *); }; #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/YamahaCDR10x.cc�����������������������������������������������������������0000664�0000000�0000000�00000062421�15114537466�0020037�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1999-2001 Cameron G. MacKinnon <C_MacKinnon@yahoo.com> * Andreas Mueller <andreas@daneb.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 * (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. */ /* Driver for Yamaha CDR10X drives. * Written by Cameron G. MacKinnon <C_MacKinnon@yahoo.com>. */ #include <config.h> #include <unistd.h> #include <string.h> #include <assert.h> #include "YamahaCDR10x.h" #include "Toc.h" #include "PQSubChannel16.h" #include "log.h" #include "port.h" YamahaCDR10x::YamahaCDR10x(ScsiIf *scsiIf, unsigned long options) : CdrDriver(scsiIf, options) { int i; driverName_ = "Yamaha CDR10x - Version 0.5 (data)"; encodingMode_ = 1; speed_ = 0; simulate_ = true; scsiTimeout_ = 0; for (i = 0; i < maxScannedSubChannels_; i++) scannedSubChannels_[i] = new PQSubChannel16; // reads little endian samples audioDataByteOrder_ = 0; } // static constructor CdrDriver *YamahaCDR10x::instance(ScsiIf *scsiIf, unsigned long options) { return new YamahaCDR10x(scsiIf, options); } YamahaCDR10x::~YamahaCDR10x() { int i; for (i = 0; i < maxScannedSubChannels_; i++) { delete scannedSubChannels_[i]; scannedSubChannels_[i] = NULL; } } int YamahaCDR10x::multiSession(int m) { if (m != 0) { return 1; // multi session mode is not supported } return 0; } // sets speed // return: 0: OK // 1: illegal speed int YamahaCDR10x::speed(int s) { if (s == 0 || s == 1 || s == 2 || s == 4) speed_ = s; else if (s == 3) speed_ = 2; else if (s > 4) speed_ = 4; else return 1; if (selectSpeed() != 0) return 1; return 0; } int YamahaCDR10x::speed() { DriveInfo di; if (driveInfo(&di, 1) != 0) { return 0; } return speed2Mult(di.currentWriteSpeed); } // loads ('unload' == 0) or ejects ('unload' == 1) tray // return: 0: OK // 1: scsi command failed int YamahaCDR10x::loadUnload(int unload) const { unsigned char cmd[6]; memset(cmd, 0, 6); cmd[0] = 0x1b; // START/STOP UNIT if (unload) { cmd[4] = 0x02; // LoUnlo=1, Start=0 } else { cmd[4] = 0x01; // LoUnlo=0, Start=1: This is a caddy, and load is reserved } if (sendCmd(cmd, 6, NULL, 0, NULL, 0) != 0) { log_message(-2, "Cannot %s medium.", (unload ? "stop & unload" : "start")); return 1; } return 0; } // sets read/write speed // return: 0: OK // 1: scsi command failed int YamahaCDR10x::selectSpeed() { unsigned char mp[4]; if (getModePage6(0x31/*drive configuration mode page*/, mp, 4, NULL, NULL, 1) != 0) { log_message(-2, "Cannot retrieve drive configuration mode page (0x31)."); return 1; } mp[3] &= 0x0f; if(speed_ == 0 || speed_ == 4) { mp[3] |= 0x20; // read at 4x, write at 2x (CDR102) or 4x (CDR100) } else if(speed_ == 2) { mp[3] |= 0x10; // read at 2x, write at 2x } else if(speed_ == 1) { ; // read at 1x, write at 1x } else { log_message(-2, "Invalid write speed argument %d. 0, 1, 2 or 4 expected.", speed_); return 1; } if (setModePage6(mp, NULL, NULL, 1) != 0) { log_message(-2, "Cannot set drive configuration mode page for cd speed."); return 1; } return 0; } // Sets write parameters via mode pages 0x31 and 0x32. // return: 0: OK // 1: scsi command failed int YamahaCDR10x::setWriteParameters() { unsigned char mp[8]; // the larger of 4 and 8, gets used twice if (getModePage6(0x31/*drive configuration mode page*/, mp, 4, NULL, NULL, 1) != 0) { log_message(-2, "Cannot retrieve drive configuration mode page (0x31)."); return 1; } mp[3] &= 0xf0; // save speed settings in high nibble mp[3] |= (simulate_ ? 1 : 0); if (setModePage6(mp, NULL, NULL, 1) != 0) { log_message(-2, "Cannot set drive configuration mode page (0x31)."); return 1; } memset(mp, 0, 8); if (getModePage6(0x32/*write format mode page*/, mp, 8, NULL, NULL, 1) != 0) { log_message(-2, "Cannot retrieve write format mode page (0x32)."); return 1; } mp[2] &= 0xf0; // RW subcode internally zero supplied mp[3] &= 0xf0; mp[3] |= 0x04; // disc at once (single session) if (setModePage6(mp, NULL, NULL, 1) != 0) { log_message(-2, "Cannot set write format mode page (0x32)."); return 1; } return 0; } void YamahaCDR10x::cueSheetDataType(TrackData::Mode mode, unsigned char *dataType, unsigned char *dataForm) { switch (mode) { case TrackData::AUDIO: *dataType = 0; *dataForm = 0; break; case TrackData::MODE1: case TrackData::MODE1_RAW: *dataType = 2; *dataForm = 3; break; case TrackData::MODE2: *dataType = 3; *dataForm = 3; break; case TrackData::MODE2_RAW: case TrackData::MODE2_FORM1: case TrackData::MODE2_FORM2: case TrackData::MODE2_FORM_MIX: if (toc_->tocType() == Toc::Type::CD_I) *dataType = 4; else *dataType = 5; *dataForm = 3; break; case TrackData::MODE0: log_message(-3, "Illegal mode in 'YamahaCDR10x::cueSheetDataType()'."); *dataType = 0; *dataForm = 0; break; } } // Creates cue sheet for current toc. // cueSheetLen: filled with length of cue sheet in bytes // return: newly allocated cue sheet buffer or 'NULL' on error // CHECKS OUT WITH DOS-DAO AND MANUAL unsigned char *YamahaCDR10x::createCueSheet(long *cueSheetLen) { const Track *t; int trackNr; Msf start, end, index; unsigned char *cueSheet; long len = 2; // entries for lead-in, lead-out long n; // index into cue sheet unsigned char ctl; // control nibbles of cue sheet entry CTL/ADR long i; unsigned char dataForm; unsigned char dataType; TrackIterator itr(toc_); if (itr.first(start, end) == NULL) { return NULL; } if (toc_->catalogValid()) { len += 2; } for (t = itr.first(start, end), trackNr = 1; t != NULL; t = itr.next(start, end), trackNr++) { len += 2; // entry for track and mandatory pre-gap if (t->type() == TrackData::AUDIO && t->isrcValid()) { len += 2; // entries for ISRC code } len += t->nofIndices(); // entry for each index increment } cueSheet = new unsigned char[len * 8]; n = 0; if (toc_->leadInMode() == TrackData::AUDIO) ctl = 0; else ctl = 0x40; if (toc_->catalogValid()) { // fill catalog number entry cueSheet[n*8] = 0x02 | ctl; cueSheet[(n+1)*8] = 0x02 | ctl; for (i = 1; i <= 13; i++) { if (i < 8) { cueSheet[n*8 + i] = toc_->catalog(i-1) + '0'; } else { cueSheet[(n+1)*8 + i - 7] = toc_->catalog(i-1) + '0'; } } cueSheet[(n+1)*8+7] = 0; n += 2; } cueSheetDataType(toc_->leadInMode(), &dataType, &dataForm); // entry for lead-in cueSheet[n*8] = 0x01 | ctl; // CTL/ADR cueSheet[n*8+1] = 0; // Track number cueSheet[n*8+2] = 0; // Index cueSheet[n*8+3] = dataType; // Data Type cueSheet[n*8+4] = 0; // Data Form: always 0 for lead-in cueSheet[n*8+5] = 0; // MIN cueSheet[n*8+6] = 0; // SEC cueSheet[n*8+7] = 0; // FRAME n++; for (t = itr.first(start, end), trackNr = 1; t != NULL; t = itr.next(start, end), trackNr++) { cueSheetDataType(t->type(), &dataType, &dataForm); ctl = trackCtl(t); if (t->type() == TrackData::AUDIO) { // set ISRC code for audio track if (t->isrcValid()) { cueSheet[n*8] = ctl | 0x03; cueSheet[n*8+1] = SubChannel::bcd(trackNr); cueSheet[n*8+2] = t->isrcCountry(0); cueSheet[n*8+3] = t->isrcCountry(1); cueSheet[n*8+4] = t->isrcOwner(0); cueSheet[n*8+5] = t->isrcOwner(1); cueSheet[n*8+6] = t->isrcOwner(2); cueSheet[n*8+7] = t->isrcYear(0) + '0'; n++; cueSheet[n*8] = ctl | 0x03; cueSheet[n*8+1] = SubChannel::bcd(trackNr); cueSheet[n*8+2] = t->isrcYear(1) + '0'; cueSheet[n*8+3] = t->isrcSerial(0) + '0'; cueSheet[n*8+4] = t->isrcSerial(1) + '0'; cueSheet[n*8+5] = t->isrcSerial(2) + '0'; cueSheet[n*8+6] = t->isrcSerial(3) + '0'; cueSheet[n*8+7] = t->isrcSerial(4) + '0'; n++; } } Msf tstart(start.lba() + 150); // start of index 1 // start of pre-gap, atime equals index 1 if no pre-gap is defined Msf pstart(trackNr == 1 ? 0 : tstart.lba() - t->start().lba()); // entry for pre-gap cueSheet[n*8] = ctl | 0x01; cueSheet[n*8+1] = SubChannel::bcd(trackNr); cueSheet[n*8+2] = 0; // Index 0 indicates pre-gap cueSheet[n*8+3] = dataType; // Data Type cueSheet[n*8+4] = dataForm; // Data Form cueSheet[n*8+5] = SubChannel::bcd(pstart.min()); cueSheet[n*8+6] = SubChannel::bcd(pstart.sec()); cueSheet[n*8+7] = SubChannel::bcd(pstart.frac()); n++; cueSheet[n*8] = ctl | 0x01; cueSheet[n*8+1] = SubChannel::bcd(trackNr); cueSheet[n*8+2] = 1; // Index 1 cueSheet[n*8+3] = dataType; // Data Type cueSheet[n*8+4] = dataForm; // Data Form cueSheet[n*8+5] = SubChannel::bcd(tstart.min()); cueSheet[n*8+6] = SubChannel::bcd(tstart.sec()); cueSheet[n*8+7] = SubChannel::bcd(tstart.frac()); n++; for (i = 0; i < t->nofIndices(); i++) { index = tstart + t->getIndex(i); cueSheet[n*8] = ctl | 0x01; cueSheet[n*8+1] = SubChannel::bcd(trackNr); cueSheet[n*8+2] = SubChannel::bcd(i+2); // Index cueSheet[n*8+3] = dataType; // DataType cueSheet[n*8+4] = dataForm; // Data Form cueSheet[n*8+5] = SubChannel::bcd(index.min()); cueSheet[n*8+6] = SubChannel::bcd(index.sec()); cueSheet[n*8+7] = SubChannel::bcd(index.frac()); n++; } } assert(n == len - 1); // entry for lead out Msf lostart(toc_->length().lba() + 150); cueSheetDataType(toc_->leadOutMode(), &dataType, &dataForm); ctl = toc_->leadOutMode() == TrackData::AUDIO ? 0 : 0x40; cueSheet[n*8] = ctl | 0x01; cueSheet[n*8+1] = 0xaa; // This IS BCD cueSheet[n*8+2] = 1; // Index 1 cueSheet[n*8+3] = dataType; // Data for lead-out cueSheet[n*8+4] = 0; // Data Form, always 0 for lead-out cueSheet[n*8+5] = SubChannel::bcd(lostart.min()); cueSheet[n*8+6] = SubChannel::bcd(lostart.sec()); cueSheet[n*8+7] = SubChannel::bcd(lostart.frac()); log_message(4, "\nCue Sheet:"); log_message(4, "CTL/ TNO INDEX DATA DATA MIN SEC FRAME"); log_message(4, "ADR BCD BCD TYPE Form BCD BCD BCD <- Note"); for (n = 0; n < len; n++) { log_message(4, "%02x %02x %02x %02x %02x %02x %02x %02x", cueSheet[n*8], cueSheet[n*8+1], cueSheet[n*8+2], cueSheet[n*8+3], cueSheet[n*8+4], cueSheet[n*8+5], cueSheet[n*8+6], cueSheet[n*8+7]); } *cueSheetLen = len * 8; return cueSheet; } // LOOKS GOOD int YamahaCDR10x::sendCueSheet() { unsigned char cmd[10]; long cueSheetLen; unsigned char *cueSheet = createCueSheet(&cueSheetLen); if (cueSheet == NULL) { return 1; } if(cueSheetLen > 32768) { // Limit imposed by drive. log_message(-2, "Cue sheet too long for this device: Limit is 32k bytes."); delete[] cueSheet; return 1; } memset(cmd, 0, 10); cmd[0] = 0xea; // Yamaha Vendor Specific WRITE TOC cmd[7] = cueSheetLen >> 8; cmd[8] = cueSheetLen; if (sendCmd(cmd, 10, cueSheet, cueSheetLen, NULL, 0) != 0) { log_message(-2, "Cannot send cue sheet."); delete[] cueSheet; return 1; } delete[] cueSheet; return 0; } // DOES NOT TALK TO DRIVE: JUST HOUSEKEEPING int YamahaCDR10x::initDao(const Toc *toc) { long n; toc_ = toc; blockLength_ = AUDIO_BLOCK_LEN; blocksPerWrite_ = scsiIf_->maxDataLen() / blockLength_; assert(blocksPerWrite_ > 0); if (selectSpeed() != 0) { return 1; } // allocate buffer for writing zeros n = blocksPerWrite_ * blockLength_; delete[] zeroBuffer_; zeroBuffer_ = new char[n]; memset(zeroBuffer_, 0, n); return 0; } // LOOKS OK - dodgy WRITE TRACK parameters, but apparently how DAO16 does it int YamahaCDR10x::startDao() { unsigned char cmd[10]; scsiTimeout_ = scsiIf_->timeout(3 * 60); if (setWriteParameters() != 0 || sendCueSheet() != 0) { return 1; } memset(cmd, 0, 10); cmd[0] = 0xe6; // Yamaha WRITE TRACK(10) cmd[5] = 0; // Track Number cmd[6] &= 0xdf; // R Parity = 0; cmd[6] &= 0xef; // Byte Swap = 0 = little endian cmd[6] &= 0xf7; // Copy = 0 cmd[6] &= 0xfb; // Audio = 0 (false) cmd[6] &= 0xfc; // Mode=0 NB This combination of mode/audio is reserved // so we end up sending a bare e6 command with nine bytes of nulls if (sendCmd(cmd, 10, NULL, 0, NULL, 0) != 0) { log_message(-2, "Could not send command 0xE6: WRITE TRACK(10)"); return 1; } //log_message(2, "Writing lead-in and gap..."); long lba = -150; if (writeZeros(toc_->leadInMode(), TrackData::SUBCHAN_NONE, lba, 0, 150) != 0) { return 1; } return 0; } int YamahaCDR10x::finishDao() { unsigned char cmd[6]; const unsigned char *sense; int senseLen; log_message(2, "Flushing cache..."); if (flushCache() != 0) { return 1; } memset(cmd, 0, 6); // wait until lead-out is written while(sendCmd(cmd, 6, NULL, 0, NULL, 0, 0) == 2 && (sense = scsiIf_->getSense(senseLen)) && senseLen && sense[2] == 0x0b && sense[0xc] == 0x50) { sleep(1); } scsiIf_->timeout(scsiTimeout_); delete[] zeroBuffer_, zeroBuffer_ = NULL; return 0; } void YamahaCDR10x::abortDao() { flushCache(); } ///////////////////////// FIXME THE TOP BAR ////////////////////////////// // NEEDS WORK DiskInfo *YamahaCDR10x::diskInfo() { unsigned char cmd[10]; unsigned long dataLen = 8; unsigned char data[8]; static DiskInfo di; //char spd; memset(&di, 0, sizeof(DiskInfo)); di.valid.cdrw = 0; // by definition, for this device memset(cmd, 0, 10); memset(data, 0, dataLen); // This looks like CdrDevice::readCapacity, but with a difference: we // get data for a ROM, and we need to check that our disc is writable cmd[0] = 0x25; // READ CD-ROM CAPACITY if (sendCmd(cmd, 10, NULL, 0, data, dataLen) != 0) { log_message(-1, "Cannot read CD-ROM capacity."); return &di; } if(data[4] | data[5] | data[6] | data[7]) { // block length field, 0=writable di.capacity = 0; } else { // disk is writable di.capacity = data[0]<<24 | data[1]<<16 | data[2]<<8 | data[3]; } di.valid.capacity = 1; // FIXME: need to come up with empty, manufacturerID, recSpeed // maybe use READ DISC INFO (0x43) here? se p. 62 ///////////////////////////////////////// return &di; } // tries to read catalog number from disk and adds it to 'toc' // return: 1 if valid catalog number was found, else 0 int YamahaCDR10x::readCatalog(Toc *toc, long startLba, long endLba) { unsigned char cmd[10]; unsigned char data[24]; char catalog[14]; int i; memset(cmd, 0, 10); memset(data, 0, 24); cmd[0] = 0x42; // READ SUB-CHANNEL cmd[2] = 1 << 6; cmd[3] = 0x02; // get media catalog number cmd[8] = 24; // transfer length if (sendCmd(cmd, 10, NULL, 0, data, 24) != 0) { log_message(-2, "Cannot get catalog number."); return 0; } if (data[8] & 0x80) { for (i = 0; i < 13; i++) { catalog[i] = data[0x09 + i]; } catalog[13] = 0; if (toc->catalog(catalog) == 0) { return 1; } } return 0; } int YamahaCDR10x::readIsrc(int trackNr, char *buf) { unsigned char cmd[10]; unsigned char data[24]; int i; buf[0] = 0; memset(cmd, 0, 10); memset(data, 0, 24); cmd[0] = 0x42; // READ SUB-CHANNEL cmd[2] = 1 << 6; cmd[3] = 0x03; // get ISRC cmd[6] = trackNr; cmd[8] = 24; // transfer length if (sendCmd(cmd, 10, NULL, 0, data, 24) != 0) { log_message(-2, "Cannot get ISRC code."); return 0; } // FIXME this looks right, but the offsets could be wrong if (data[8] & 0x80) { for (i = 0; i < 12; i++) { buf[i] = data[0x09 + i]; } buf[12] = 0; } return 0; } int YamahaCDR10x::analyzeTrack(TrackData::Mode mode, int trackNr, long startLba, long endLba, Msf *indexIncrements, int *indexIncrementCnt, long *pregap, char *isrcCode, unsigned char *ctl) { int ret = analyzeTrackScan(mode, trackNr, startLba, endLba, indexIncrements, indexIncrementCnt, pregap, isrcCode, ctl); if (mode == TrackData::AUDIO) readIsrc(trackNr, isrcCode); else *isrcCode = 0; return ret; } int YamahaCDR10x::readSubChannels(TrackData::SubChannelMode, long lba, long len, SubChannel ***chans, Sample *audioData) { int retries = 5; int i; unsigned char cmd[12]; cmd[0] = 0xd8; // Yamaha READ CD-DA cmd[1] = 0; cmd[2] = lba >> 24; cmd[3] = lba >> 16; cmd[4] = lba >> 8; cmd[5] = lba; cmd[6] = len >> 24; cmd[7] = len >> 16; cmd[8] = len >> 8; cmd[9] = len; cmd[10] = 0x01; // 2352 + 10 Q (no CRC) + 6 NULL cmd[11] = 0; while (1) { if (sendCmd(cmd, 12, NULL, 0, transferBuffer_, len * (AUDIO_BLOCK_LEN + 16), retries == 0 ? 1 : 0) != 0) { if (retries == 0) return 1; } else { break; } retries--; } for (i = 0; i < len; i++) { PQSubChannel16 *chan = (PQSubChannel16*)scannedSubChannels_[i]; unsigned char *p = transferBuffer_ + i * (AUDIO_BLOCK_LEN + 16) + AUDIO_BLOCK_LEN; // slightly reorder the sub-channel so it is suitable for 'PQSubChannel16' p[0] <<= 4; // ctl/adr p[0] |= p[1]; p[1] = p[2]; // track nr p[2] = p[3]; // index nr p[3] = p[4]; // min p[4] = p[5]; // sec p[5] = p[6]; // frame p[6] = 0; // zero // p[7] is amin // p[8] is asec // p[9] is aframe chan->init(p); if (chan->checkConsistency()) chan->calcCrc(); } if (audioData != NULL) { unsigned char *p = transferBuffer_; for (i = 0; i < len; i++) { memcpy(audioData, p, AUDIO_BLOCK_LEN); p += AUDIO_BLOCK_LEN + 16; audioData += SAMPLES_PER_BLOCK; } } *chans = scannedSubChannels_; return 0; } // LOOKSGOOD, except for accurate audio stream bit int YamahaCDR10x::driveInfo(DriveInfo *info, bool showErrorMsg) { unsigned char mp[4]; if (getModePage6(0x31, mp, 4, NULL, NULL, showErrorMsg) != 0) { if (showErrorMsg) { log_message(-2, "Cannot retrieve drive configuration mode page (0x31)."); } return 1; } // FIXME // info->accurateAudioStream = mp[5] & 0x02 ? 1 : 0; info->accurateAudioStream = 0; info->maxReadSpeed = mult2Speed(4); if(!strncmp(scsiIf_->product(), "CDR100", 6)) { info->maxWriteSpeed = mult2Speed(4); info->currentWriteSpeed = info->currentReadSpeed = mult2Speed(1 << (mp[3] >> 4)); } else { // CDR102, crippled to 2x write info->maxWriteSpeed = mult2Speed(2); info->currentReadSpeed = mult2Speed(1 << (mp[3] >> 4)); info->currentWriteSpeed = mult2Speed((mp[3] >> 4) ? 2 : 1); } return 0; } // writeData is overridden here because the CDR10x, while writing the disc // lead-in with the buffer full, will return CHECK CONDITION with sense // DRIVE BUSY and additional sense 0xb8 = WRITE LEAD-IN IN PROGRESS. // This is normal operation and the write should be retried until successful. // Writes data to target, the block length depends on the actual writing mode // 'len' is number of blocks to write. // 'lba' specifies the next logical block address for writing and is updated // by this function. // return: 0: OK // 1: scsi command failed int YamahaCDR10x::writeData(TrackData::Mode mode, TrackData::SubChannelMode sm, long &lba, const char *buf, long len) { assert(blocksPerWrite_ > 0); int writeLen = 0; unsigned char cmd[10]; int retry; int retval; long blockLength = blockSize(mode, TrackData::SUBCHAN_NONE); #if 0 long sum, i; sum = 0; for (i = 0; i < len * blockLength; i++) { sum += buf[i]; } log_message(0, "W: %ld: %ld, %ld, %ld", lba, blockLength, len, sum); #endif memset(cmd, 0, 10); cmd[0] = 0x2a; // WRITE1 while (len > 0) { writeLen = (len > blocksPerWrite_ ? blocksPerWrite_ : len); cmd[2] = lba >> 24; cmd[3] = lba >> 16; cmd[4] = lba >> 8; cmd[5] = lba; cmd[7] = writeLen >> 8; cmd[8] = writeLen & 0xff; do { retry = 0; retval = sendCmd(cmd, 10, (unsigned char *)buf, writeLen * blockLength, NULL, 0, 0); if(retval == 2) { const unsigned char *sense; int senseLen; sense = scsiIf_->getSense(senseLen); // we spin on the write here, waiting a reasonable time in between // we should really use READ BLOCK LIMIT (0x05) if(senseLen && sense[2] == 9 && sense[0xc] == 0xb8) { mSleep(40); retry = 1; } else { scsiIf_->printError(); } } } while(retry == 1); if(retval) { log_message(-2, "Write data failed."); return 1; } buf += writeLen * blockLength; lba += writeLen; len -= writeLen; } return 0; } CdRawToc *YamahaCDR10x::getRawToc(int sessionNr, int *len) { // not supported by drive return NULL; } long YamahaCDR10x::readTrackData(TrackData::Mode mode, TrackData::SubChannelMode, long lba, long len, unsigned char *buf) { unsigned char cmd[10]; long blockLen = 2340; long i; TrackData::Mode actMode; int ok = 0; int softError; const unsigned char *sense; int senseLen; if (setBlockSize(blockLen) != 0) return 0; memset(cmd, 0, 10); cmd[0] = 0x28; // READ10 cmd[2] = lba >> 24; cmd[3] = lba >> 16; cmd[4] = lba >> 8; cmd[5] = lba; while (len > 0 && !ok) { cmd[7] = len >> 8; cmd[8] = len; memset(transferBuffer_, 0, len * blockLen); switch (sendCmd(cmd, 10, NULL, 0, transferBuffer_, len * blockLen, 0)) { case 0: ok = 1; break; case 2: softError = 0; sense = scsiIf_->getSense(senseLen); if (senseLen > 0x0c) { if ((sense[2] &0x0f) == 5) { switch (sense[12]) { case 0x63: // end of user area encountered on this track case 0x64: // Illegal mode for this track softError = 1; break; } } else if ((sense[2] & 0x0f) == 3) { // Medium error switch (sense[12]) { case 0x02: // No seek complete, sector not found case 0x11: // L-EC error return -2; break; } } } if (!softError) { scsiIf_->printError(); return -1; } break; default: log_message(-2, "Read error at LBA %ld, len %ld", lba, len); return -1; break; } if (!ok) { len--; } } unsigned char *sector = transferBuffer_; for (i = 0; i < len; i++) { actMode = determineSectorMode(sector); if (!(actMode == mode || (mode == TrackData::MODE2_FORM_MIX && (actMode == TrackData::MODE2_FORM1 || actMode == TrackData::MODE2_FORM2)) || (mode == TrackData::MODE1_RAW && actMode == TrackData::MODE1) || (mode == TrackData::MODE2_RAW && (actMode == TrackData::MODE2 || actMode == TrackData::MODE2_FORM1 || actMode == TrackData::MODE2_FORM2)))) { return i; } if (buf != NULL) { switch (mode) { case TrackData::MODE1: memcpy(buf, sector + 4, MODE1_BLOCK_LEN); buf += MODE1_BLOCK_LEN; break; case TrackData::MODE2: case TrackData::MODE2_FORM_MIX: memcpy(buf, sector + 4, MODE2_BLOCK_LEN); buf += MODE2_BLOCK_LEN; break; case TrackData::MODE2_FORM1: memcpy(buf, sector + 12, MODE2_FORM1_DATA_LEN); buf += MODE2_FORM1_DATA_LEN; break; case TrackData::MODE2_FORM2: memcpy(buf, sector + 12, MODE2_FORM2_DATA_LEN); buf += MODE2_FORM2_DATA_LEN; break; case TrackData::MODE1_RAW: case TrackData::MODE2_RAW: memcpy(buf, syncPattern, 12); memcpy(buf + 12, sector, 2340); buf += AUDIO_BLOCK_LEN; break; case TrackData::MODE0: case TrackData::AUDIO: log_message(-3, "YamahaCDR10x::readTrackData: Illegal mode."); return 0; break; } } sector += blockLen; } return len; } Toc *YamahaCDR10x::readDiskToc(int session, const char *audioFilename) { Toc *toc = CdrDriver::readDiskToc(session, audioFilename); setBlockSize(MODE1_BLOCK_LEN); return toc; } Toc *YamahaCDR10x::readDisk(int session, const char *fname) { Toc *toc = CdrDriver::readDisk(session, fname); setBlockSize(MODE1_BLOCK_LEN); return toc; } int YamahaCDR10x::readAudioRange(ReadDiskInfo *rinfo, int fd, long start, long end, int startTrack, int endTrack, TrackInfo *info) { if (!onTheFly_) { int t; log_message(1, "Analyzing..."); for (t = startTrack; t <= endTrack; t++) { long totalProgress; totalProgress = t * 1000; totalProgress /= rinfo->tracks; sendReadCdProgressMsg(RCD_ANALYZING, rinfo->tracks, t + 1, 0, totalProgress); log_message(1, "Track %d...", t + 1); info[t].isrcCode[0] = 0; readIsrc(t + 1, info[t].isrcCode); if (info[t].isrcCode[0] != 0) log_message(2, "Found ISRC code."); totalProgress = (t + 1) * 1000; totalProgress /= rinfo->tracks; sendReadCdProgressMsg(RCD_ANALYZING, rinfo->tracks, t + 1, 1000, totalProgress); } log_message(1, "Reading..."); } return CdrDriver::readAudioRangeParanoia(rinfo, fd, start, end, startTrack, endTrack, info); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/YamahaCDR10x.h������������������������������������������������������������0000664�0000000�0000000�00000006103�15114537466�0017674�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1999 Cameron G. MacKinnon <C_MacKinnon@yahoo.com> * Copyright (C) 1998-2001 Andreas Mueller <andreas@daneb.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 * (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. */ /* Driver for Yamaha CDR10X drives. * Written by Cameron G. MacKinnon <C_MacKinnon@yahoo.com>. */ #ifndef __YAMAHACDR10X_H__ #define __YAMAHACDR10X_H__ #include "CdrDriver.h" #include "TrackData.h" class Toc; class Track; class YamahaCDR10x : public CdrDriver { public: YamahaCDR10x(ScsiIf *scsiIf, unsigned long options); ~YamahaCDR10x(); static CdrDriver *instance(ScsiIf *scsiIf, unsigned long options); unsigned long getReadCapabilities(const CdToc *, int) const { return 0; } // FIXME: We say we're little endian, incurring work for the host // The drive has endian flags, but I don't want to experiment int bigEndianSamples() const { return 0; } int multiSession(int); int speed(int); int speed(); DiskInfo *diskInfo(); Toc *readDiskToc(int, const char *audioFilename); Toc *readDisk(int, const char *audioFilename); int loadUnload(int) const; int initDao(const Toc *); int startDao(); int finishDao(); void abortDao(); int driveInfo(DriveInfo *, bool showErrorMsg); int writeData(TrackData::Mode, TrackData::SubChannelMode, long &lba, const char *buf, long len); protected: int scsiTimeout_; unsigned char audioModePage_[16]; // saved audio mode page Msf leadInStart_; // start of lead-in long leadInLen_; // length of lead-in long leadOutLen_; // length if lead-out CdRawToc *getRawToc(int sessionNr, int *len); int readCatalog(Toc *, long startLba, long endLba); int readIsrc(int, char *); int readSubChannels(TrackData::SubChannelMode, long lba, long len, SubChannel ***, Sample *); virtual int selectSpeed(); virtual int setWriteParameters(); void cueSheetDataType(TrackData::Mode mode, unsigned char *dataType, unsigned char *dataForm); unsigned char *createCueSheet(long *cueSheetLen); int sendCueSheet(); int analyzeTrack(TrackData::Mode, int trackNr, long startLba, long endLba, Msf *index, int *indexCnt, long *pregap, char *isrcCode, unsigned char *ctl); long readTrackData(TrackData::Mode, TrackData::SubChannelMode, long lba, long len, unsigned char *buf); int readAudioRange(ReadDiskInfo *, int fd, long start, long end, int startTrack, int endTrack, TrackInfo *); }; #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/cdda_interface.h����������������������������������������������������������0000664�0000000�0000000�00000001624�15114537466�0020530�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/****************************************************************** * CopyPolicy: GNU Public License 2 applies * Copyright (C) 1998 Monty xiphmont@mit.edu * and Heiko Eissfeldt heiko@escape.colossus.de * * Toplevel interface header; applications include this * ******************************************************************/ #ifndef _cdda_interface_h_ #define _cdda_interface_h_ #ifndef CD_FRAMESIZE #define CD_FRAMESIZE 2048 #endif #ifndef CD_FRAMESIZE_RAW #define CD_FRAMESIZE_RAW 2352 #endif #define CD_FRAMESAMPLES (CD_FRAMESIZE_RAW / 4) #include <sys/types.h> typedef struct cdrom_drive{ long nsectors; /* number of sectors that can be read at once */ void *cdr; /* pointer to a CdrDriver object */ } cdrom_drive; #ifdef __cplusplus extern "C" { #endif extern long cdda_read(cdrom_drive *d, void *buffer, long beginsector, long sectors); #ifdef __cplusplus } #endif #endif ������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/cdrdao.drivers������������������������������������������������������������0000664�0000000�0000000�00000030175�15114537466�0020303�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Driver table for cdrdao-1.1.7 # Generated Sun Sep 22 18:06:35 2002 by mueller # Drivers for read operations R|ASUS|CD-S340|generic-mmc R|ASUS|CD-S400|generic-mmc R|ASUS|CD-S500/A|generic-mmc|OPT_MMC_NO_SUBCHAN R|ASUS|DVD-ROM E608|generic-mmc R|E-IDE|CD-950E/TKU|generic-mmc R|E-IDE|CD-ROM 36X/AKU|generic-mmc R|E-IDE|CD-ROM 52X/AKH|generic-mmc R|FUNAI|E295X|generic-mmc R|Goldstar|CD-RW CED-8042B|generic-mmc R|HITACHI|CDR-7730|generic-mmc R|HITACHI|CDR-8435|generic-mmc|OPT_MMC_NO_SUBCHAN R|LG|CD-ROM CRD-8480C|generic-mmc|OPT_MMC_NO_SUBCHAN R|LG|CD-ROM CRD-8482B|generic-mmc|OPT_MMC_NO_SUBCHAN R|LG|CD-ROM CRD-8521B|generic-mmc R|LG|DVD-ROM DRN8080B|generic-mmc|OPT_DRV_GET_TOC_GENERIC R|LITE-ON|CD-ROM|generic-mmc|OPT_DRV_GET_TOC_GENERIC R|LITE-ON|LTD-163|generic-mmc R|LITEON|DVD-ROM LTD163D|generic-mmc R|MATSHITA|CD-ROM CR-588|generic-mmc R|MATSHITA|CD-ROM CR-589|generic-mmc|OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD R|MATSHITA|DVD-ROM SR-8585|generic-mmc|OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD R|MEMOREX|CD-233E|generic-mmc R|MITSUMI|CD-ROM FX4820|generic-mmc|OPT_MMC_NO_SUBCHAN R|OPTICS_S|8622|generic-mmc R|PHILIPS|36X/AKU|generic-mmc R|PHILIPS|CD-ROM PCCD052|generic-mmc R|PHILIPS|E-IDE CD-ROM 36X|generic-mmc R|PIONEER|CD-ROM DR-U32|generic-mmc|OPT_DRV_GET_TOC_GENERIC|OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD R|PIONEER|DVD-103|generic-mmc|OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD R|PIONEER|DVD-104|generic-mmc|OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD R|PIONEER|DVD-105|generic-mmc|OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD R|PIONEER|DVR-106D|generic-mmc|OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD R|PIONEER|DVR-107D|generic-mmc|OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD R|SONY|CD-ROM CDU31A-02|generic-mmc R|SONY|CD-ROM CDU4821|generic-mmc R|SONY|CDU5211|generic-mmc R|TEAC|CD-524E|generic-mmc|OPT_DRV_GET_TOC_GENERIC|OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD R|TEAC|CD-532E|generic-mmc|OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD R|TEAC|CD-540E|generic-mmc R|TOSHIBA|CD-ROM XM-3206B|generic-mmc R|TOSHIBA|CD-ROM XM-6102B|generic-mmc R|TOSHIBA|CD-ROM XM-6302B|generic-mmc R|TOSHIBA|CD-ROM XM-6402B|generic-mmc R|TOSHIBA|DVD-ROM SD-C2202|generic-mmc R|TOSHIBA|DVD-ROM SD-C2302|generic-mmc R|TOSHIBA|DVD-ROM SD-C2402|generic-mmc R|TOSHIBA|DVD-ROM SD-M1102|generic-mmc R|TOSHIBA|DVD-ROM SD-M1401|generic-mmc R|TOSHIBA|DVD-ROM SD-M1402|generic-mmc R|HITACHI|DVD-ROM GD-2500|plextor R|MATSHITA|CD-ROM CR-506|plextor|OPT_PLEX_DAE_D4_12 R|MATSHITA|CR-8008|plextor R|NAKAMICH|MJ-5.16S|plextor R|PIONEER|CD-ROM DR-U03|plextor|OPT_DRV_GET_TOC_GENERIC R|PIONEER|CD-ROM DR-U06|plextor|OPT_DRV_GET_TOC_GENERIC R|PIONEER|CD-ROM DR-U10|plextor|OPT_DRV_GET_TOC_GENERIC R|PIONEER|CD-ROM DR-U12|plextor|OPT_DRV_GET_TOC_GENERIC R|PIONEER|CD-ROM DR-U16|plextor|OPT_DRV_GET_TOC_GENERIC R|PIONEER|DVD-303|plextor R|PIONEER|DVD-305|plextor R|SAF|CD-R2006PLUS|plextor R|SONY|CD-ROM|plextor R|SONY|CD-ROM CDU-76|plextor R|TOSHIBA|XM-5401|plextor R|PLEXTOR|CD-ROM|plextor-scan R|PLEXTOR|PX-40TS|plextor-scan R|PLEXTOR|PX-40TW|plextor-scan R|PLEXTOR|PX-63|plextor-scan R|TEAC|CD-ROM CD-532S|plextor-scan|OPT_PLEX_USE_PQ|OPT_PLEX_PQ_BCD R|TEAC|CD-532S|teac-cdr55 R|TOSHIBA|1504|toshiba R|TOSHIBA|CD-ROM XM-3601B|toshiba R|TOSHIBA|CD-ROM XM-5302TA|toshiba R|TOSHIBA|CD-ROM XM-5701TA|toshiba R|TOSHIBA|CD-ROM XM-6201TA|toshiba R|TOSHIBA|CD-ROM XM-6401TA|toshiba R|TOSHIBA|DVD-ROM SD-2102|toshiba # Drivers for write operations W|CDWRITER|IDE5224|generic-mmc|OPT_MMC_CD_TEXT W|GRUNDIG|CDR100IPW|cdd2600 W|HP|CD-Writer 4020|cdd2600 W|HP|CD-Writer 6020|cdd2600 W|IMS|522|cdd2600 W|IMS|CDD2000|cdd2600 W|KODAK|PCD-225|cdd2600 W|PHILIPS|CDD2000|cdd2600 W|PHILIPS|CDD2600|cdd2600 W|PHILIPS|CDD522|cdd2600 W|AOPEN|CD-RW CRW1632|generic-mmc W|AOPEN|CD-RW CRW2040|generic-mmc W|AOPEN|CD-RW-241040|generic-mmc W|AOPEN|CRW9624|generic-mmc W|CD-RW|CDR-2440MB|generic-mmc|OPT_MMC_CD_TEXT W|CREATIVE|CD-RW RW1210E|generic-mmc W|CREATIVE|CD-RW RW4424|generic-mmc W|CREATIVE|CD-RW RW8433E|generic-mmc|OPT_MMC_CD_TEXT W|CREATIVE|CD5233E|generic-mmc W|DELTA|OME-W141|generic-mmc W|GENERIC|CRD-BP1600P|generic-mmc W|GENERIC|CRD-R800S|generic-mmc W|GENERIC|CRD-RW2|generic-mmc W|HL-DT-ST|RW/DVD GCC-4120B|generic-mmc|OPT_MMC_CD_TEXT W|HP|9510i|generic-mmc|OPT_MMC_CD_TEXT W|HP|CD-Writer+ 7570|generic-mmc|OPT_MMC_CD_TEXT W|HP|CD-Writer+ 8100|generic-mmc|OPT_MMC_CD_TEXT W|HP|CD-Writer+ 8200|generic-mmc|OPT_MMC_CD_TEXT W|HP|CD-Writer+ 8290|generic-mmc|OPT_MMC_CD_TEXT W|HP|CD-Writer+ 9100|generic-mmc|OPT_MMC_CD_TEXT W|HP|CD-Writer+ 9110|generic-mmc|OPT_MMC_CD_TEXT W|HP|CD-Writer+ 9200|generic-mmc|OPT_MMC_CD_TEXT W|HP|CD-Writer+ 9300|generic-mmc|OPT_MMC_CD_TEXT W|HP|CD-Writer+ 9600|generic-mmc|OPT_MMC_CD_TEXT W|HP|CD-Writer+ 9700|generic-mmc|OPT_MMC_CD_TEXT W|HP|DVD Writer 100j|generic-mmc W|IDE-CD|R/RW 16x10A|generic-mmc W|IMATION|IMW121032IAB|generic-mmc W|LG|8088B|generic-mmc W|LG|8120B|generic-mmc|OPT_MMC_CD_TEXT W|LG|CD-ROM CDR-8428B|generic-mmc W|LG|CD-RW CED-8080B|generic-mmc|OPT_MMC_CD_TEXT W|LG|CD-RW CED-8081B|generic-mmc|OPT_MMC_CD_TEXT W|LG|CD-RW CED-8083B|generic-mmc|OPT_MMC_CD_TEXT W|LG|CD-RW GCE-8240B|generic-mmc|OPT_MMC_CD_TEXT W|LG|COMBO|generic-mmc W|LG|HL-DT-ST RW/DVD GCC-4080N|generic-mmc|OPT_MMC_CD_TEXT W|LITE-ON|LTR-0841|generic-mmc|OPT_MMC_CD_TEXT|OPT_MMC_NO_SUBCHAN W|LITE-ON|LTR-24102B|generic-mmc W|LITE-ON|LTR-32125W|generic-mmc|OPT_MMC_CD_TEXT W|MATSHITA|CD-R CW-7502|generic-mmc W|MATSHITA|CD-R CW-7503|generic-mmc W|MATSHITA|CD-R CW-7582|generic-mmc W|MATSHITA|CD-R CW-7585|generic-mmc W|MATSHITA|CD-R CW-7586|generic-mmc W|MATSHITA|CDRRW01|generic-mmc W|MATSHITA|UJDA360|generic-mmc W|MATSHITA|UJDA710|generic-mmc|OPT_MMC_CD_TEXT W|MATSHITA|UJDA720|generic-mmc|OPT_MMC_CD_TEXT W|MEMOREX|24MAX 1040|generic-mmc W|MEMOREX|40MAXX 1248AJ|generic-mmc W|MEMOREX|CD-RW4224|generic-mmc W|MICROSOLUTIONS|BACKPACK CD REWRITER|generic-mmc W|MITSUMI|CR-4801|generic-mmc W|MITSUMI|CR-48X5|generic-mmc W|MITSUMI|CR-48X5TE|generic-mmc|OPT_MMC_CD_TEXT W|MITSUMI|CR-48X8TE|generic-mmc W|MITSUMI|CR-48XATE|generic-mmc W|OLYMPIC|RWD RW4224|generic-mmc|OPT_DRV_GET_TOC_GENERIC|OPT_MMC_USE_PQ W|PANASONIC|CD-R CW-7582|generic-mmc W|PHILIPS|CDRW1610A|generic-mmc|OPT_MMC_CD_TEXT W|PHILIPS|CDRW2412A|generic-mmc W|PHILIPS|PCA460RW|generic-mmc W|PIONEER|DVD-ROM DVD-114|generic-mmc|OPT_MMC_CD_TEXT W|PLEXTOR|CD-R PX-R412|generic-mmc|OPT_MMC_USE_PQ|OPT_MMC_READ_ISRC W|PLEXTOR|CD-R PX-R820|generic-mmc W|PLEXTOR|CD-R PX-W1210|generic-mmc|OPT_MMC_CD_TEXT W|PLEXTOR|CD-R PX-W124|generic-mmc|OPT_MMC_CD_TEXT W|PLEXTOR|CD-R PX-W1610|generic-mmc|OPT_MMC_CD_TEXT W|PLEXTOR|CD-R PX-W2410|generic-mmc|OPT_MMC_CD_TEXT W|PLEXTOR|CD-R PX-W4220|generic-mmc|OPT_MMC_CD_TEXT W|PLEXTOR|CD-R PX-W8220|generic-mmc|OPT_MMC_CD_TEXT W|PLEXTOR|CD-R PX-W8432|generic-mmc|OPT_MMC_CD_TEXT W|PLEXTOR|CD-R PX-W241040|generic-mmc|OPT_MMC_CD_TEXT W|PLEXTOR|CD-R PX-W2410a|generic-mmc|OPT_MMC_CD_TEXT W|PLEXTOR|CD-R PX-W4012A|generic-mmc|OPT_MMC_CD_TEXT W|RICOH|CD-R/RW MP7040|generic-mmc|OPT_MMC_CD_TEXT W|RICOH|CD-R/RW MP7060|generic-mmc|OPT_MMC_CD_TEXT W|RICOH|CD-R/RW MP7063A|generic-mmc|OPT_MMC_CD_TEXT W|RICOH|CD-R/RW MP7080|generic-mmc|OPT_MMC_CD_TEXT W|RICOH|CD-R/RW MP7083A|generic-mmc|OPT_MMC_CD_TEXT W|RICOH|DVD/CDRW MP9060|generic-mmc|OPT_MMC_CD_TEXT W|SAF|CD-R8020|generic-mmc W|SAF|CD-RW4224A|generic-mmc W|SAF|CD-RW6424|generic-mmc W|SAMSUNG|CD-R/RW SW-206|generic-mmc W|SAMSUNG|CD-R/RW SW-408B|generic-mmc|OPT_MMC_CD_TEXT W|SAMSUNG|CDRW/DVD SM-308B|generic-mmc|OPT_MMC_CD_TEXT W|SANYO|CRD-BP3|generic-mmc W|SONY|CD-RW CRX700E|generic-mmc W|SONY|CRX-815|generic-mmc|OPT_MMC_CD_TEXT W|SONY|CRX100|generic-mmc|OPT_MMC_CD_TEXT W|SONY|CRX120|generic-mmc|OPT_MMC_CD_TEXT W|SONY|CRX140|generic-mmc|OPT_MMC_CD_TEXT W|SONY|CRX145|generic-mmc|OPT_MMC_CD_TEXT W|SONY|CRX160E|generic-mmc|OPT_MMC_CD_TEXT W|SONY|CRX175A1|generic-mmc W|SONY|CRX175E|generic-mmc|OPT_MMC_CD_TEXT W|SONY|CRX185E1|generic-mmc|OPT_MMC_CD_TEXT W|TDK|4800|generic-mmc|OPT_MMC_CD_TEXT W|TDK|CDRW121032|generic-mmc|OPT_MMC_CD_TEXT W|TDK|CDRW321040B|generic-mmc W|TDK|CDRW8432|generic-mmc|OPT_MMC_CD_TEXT W|TEAC|CD-R56|generic-mmc|OPT_MMC_USE_PQ|OPT_MMC_CD_TEXT W|TEAC|CD-R58|generic-mmc|OPT_MMC_USE_PQ|OPT_MMC_CD_TEXT W|TEAC|CD-W216E|generic-mmc|OPT_MMC_CD_TEXT W|TEAC|CD-W512EB|generic-mmc|OPT_MMC_CD_TEXT W|TEAC|CD-W512SB|generic-mmc|OPT_MMC_CD_TEXT W|TEAC|CD-W516EB|generic-mmc|OPT_MMC_CD_TEXT W|TEAC|CD-W516EC|generic-mmc|OPT_MMC_CD_TEXT W|TEAC|CD-W524E|generic-mmc|OPT_MMC_CD_TEXT W|TEAC|CD-W54E|generic-mmc W|TORiSAN|CDW-U4424|generic-mmc W|TOSHIBA|DVD-ROM SD-M1612|generic-mmc W|TOSHIBA|DVD-ROM SD-R1002|generic-mmc W|TOSHIBA|DVD-ROM SD-R1202|generic-mmc W|TRAXDATA|241040|generic-mmc W|TRAXDATA|CDRW4260|generic-mmc W|WAITEC|WT624|generic-mmc|OPT_MMC_NO_SUBCHAN W|YAMAHA|CDR200|generic-mmc W|YAMAHA|CDR400|generic-mmc W|YAMAHA|CRW2100|generic-mmc|OPT_MMC_CD_TEXT W|YAMAHA|CRW2200|generic-mmc|OPT_MMC_CD_TEXT W|YAMAHA|CRW2260|generic-mmc W|YAMAHA|CRW3200|generic-mmc|OPT_MMC_CD_TEXT W|YAMAHA|CRW4001|generic-mmc W|YAMAHA|CRW4260|generic-mmc W|YAMAHA|CRW4416|generic-mmc W|YAMAHA|CRW6416|generic-mmc W|YAMAHA|CRW8424|generic-mmc W|YAMAHA|CRW8824|generic-mmc W|_NEC|NR-7700A|generic-mmc W|ACER|10x8x32|generic-mmc-raw W|ACER|2010A|generic-mmc-raw W|ACER|20x10x40|generic-mmc-raw W|ACER|4406EU|generic-mmc-raw W|ACER|4x4x6|generic-mmc-raw W|ACER|8X4X32|generic-mmc-raw W|ACER|CD-R/RW 4X4X32|generic-mmc-raw|OPT_MMC_NO_SUBCHAN W|AOPEN|CD-RW CRW3248|generic-mmc-raw W|AOPEN|CRW1232|generic-mmc-raw W|ARTEC|RW241040|generic-mmc-raw W|ARTEC|WRA-WA48|generic-mmc-raw W|ARTEC|WRR-4048|generic-mmc-raw W|ASUS|CRW-1610A|generic-mmc-raw W|ASUS|CRW-3212A|generic-mmc-raw W|ATAPI|CD-R/RW 12X8X32|generic-mmc-raw W|ATAPI|CD-R/RW 4X4X32|generic-mmc-raw W|ATAPI|CD-R/RW CRW6206A|generic-mmc-raw W|BENQ|CRW2410A|generic-mmc-raw W|BTC|BCE1610IM|generic-mmc-raw W|BTC|BCE2410IM|generic-mmc-raw W|BTC|BCE621E|generic-mmc-raw W|CyberDrv|CW018D|generic-mmc-raw W|CyberDrv|CW038D|generic-mmc-raw W|CyberDrv|CW058D|generic-mmc-raw W|Goldstar|8120B|generic-mmc-raw W|HL-DT-ST|CD-RW GCE-8160B|generic-mmc-raw W|HL-DT-ST|CD-RW GCE-8320B|generic-mmc-raw W|HP|CD-Writer+ 7100|generic-mmc-raw W|HP|CD-Writer+ 7200|generic-mmc-raw W|HP|DVD Writer 200j|generic-mmc-raw W|IDE-CD|R/RW 2x2x24|generic-mmc-raw W|IDE-CD|R/RW 4x4x24|generic-mmc-raw W|IDE-CD|R/RW 4x4x32|generic-mmc-raw W|IDE-CD|R/RW 8x4x32|generic-mmc-raw W|IDE-CD|ReWritable-2x2x6|generic-mmc-raw W|IOMEGA|ZIPCD 4x650|generic-mmc-raw W|LITE-ON|LTR-12101B|generic-mmc-raw W|LITE-ON|LTR-16101B|generic-mmc-raw W|LITE-ON|LTR-16102C|generic-mmc-raw W|LITE-ON|LTR-32123S|generic-mmc-raw W|LITE-ON|LTR-40125S|generic-mmc-raw W|LITE-ON|LTR-48125W|generic-mmc-raw W|MEMOREX|CDRW-2216|generic-mmc-raw W|MEMOREX|CR-622|generic-mmc-raw W|MEMOREX|CRW-1662|generic-mmc-raw W|MITSUMI|2801|generic-mmc-raw W|MITSUMI|CR-4802|generic-mmc-raw W|MITSUMI|CR-4804|generic-mmc-raw W|OTI|-975 SOCRATES|generic-mmc-raw W|PHILIPS|CDD 3801/31|generic-mmc-raw W|PHILIPS|CDD3600|generic-mmc-raw W|PHILIPS|CDD3610|generic-mmc-raw W|PHILIPS|CDD4201|generic-mmc-raw|OPT_MMC_NO_SUBCHAN W|PHILIPS|CDD4801|generic-mmc-raw W|PHILIPS|CDRW400|generic-mmc-raw W|PHILIPS|PCRW1208|generic-mmc-raw W|PHILIPS|PCRW120899|generic-mmc-raw W|PHILIPS|PCRW404|generic-mmc-raw W|PHILIPS|PCRW804|generic-mmc-raw W|QPS|CRD-BP 1500P|generic-mmc-raw W|SAMSUNG|CD-R/RW SW-204B|generic-mmc-raw W|SAMSUNG|CD-R/RW SW-208|generic-mmc-raw W|SAMSUNG|CD-R/RW SW-212B|generic-mmc-raw W|SAMSUNG|CD-R/RW SW-224|generic-mmc-raw W|SAMSUNG|SW-232|generic-mmc-raw W|SONY|CRX195E1|generic-mmc-raw W|TEAC|CD-W512E|generic-mmc|OPT_MMC_CD_TEXT W|TEAC|CD-W58E|generic-mmc-raw|OPT_MMC_USE_PQ|OPT_MMC_PQ_BCD W|TOSHIBA|R/RW 4x4x24|generic-mmc-raw W|TRAXDATA|2832|generic-mmc-raw W|TRAXDATA|CDRW2260+|generic-mmc-raw W|TRAXDATA|CRW2260 PRO|generic-mmc-raw W|WAITEC|WT2444EI|generic-mmc-raw W|WAITEC|WT4424|generic-mmc-raw W|_NEC|7900|generic-mmc-raw W|_NEC|NR-7800A|generic-mmc-raw W|AOPEN|CRW620|ricoh-mp6200 W|MEMOREX|CRW620|ricoh-mp6200 W|PHILIPS|OMNIWRITER26|ricoh-mp6200 W|RICOH|MP6200|ricoh-mp6200 W|RICOH|MP6201|ricoh-mp6200 W|SONY|CD-R CDU920|sony-cdu920 W|SONY|CD-R CDU924|sony-cdu920 W|SONY|CD-R CDU948|sony-cdu948 W|T.YUDEN|CD-WO EW-50|taiyo-yuden W|JVC|R2626|teac-cdr55 W|JVC|XR-W2010|teac-cdr55 W|SAF|CD-R2006PLUS|teac-cdr55 W|SAF|CD-R4012|teac-cdr55 W|SAF|CD-RW 226|teac-cdr55 W|TEAC|CD-R50|teac-cdr55 W|TEAC|CD-R55|teac-cdr55 W|TRAXDATA|CDR4120|teac-cdr55 W|TOSHIBA|DVD-ROM SD-R2002|toshiba W|TOSHIBA|DVD-ROM SD-R2102|toshiba W|YAMAHA|CDR100|yamaha-cdr10x W|YAMAHA|CDR102|yamaha-cdr10x ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/cdrdao.man����������������������������������������������������������������0000664�0000000�0000000�00000064732�15114537466�0017406�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������.TH CDRDAO 1 "Jan 18, 2006" .SH NAME cdrdao \- reads and writes CDs in disc-at-once mode .SH SYNOPSIS .B cdrdao .RB { show-toc|toc-info|toc-size|read-toc|read-cd|read-cddb|show-data|read-test|disk-info|discid|msinfo|drive-info|unlock|scanbus|simulate|write|copy|blank } .RB [ --device .IR device ] .RB [ --source-device .IR device ] .RB [ --driver .IR driver-id ] .RB [ --source-driver .IR driver-id ] .RB [ --simulate ] .RB [ --speed .IR writing-speed ] .RB [ --blank-mode .IR mode] .RB [ --datafile .IR file ] .RB [ --read-raw ] .RB [ --read-subchan .RB [ --no-mode2-mixed ] .IR mode ] .RB [ --tao-source ] .RB [ --tao-source-adjust .IR link-blocks ] .RB [ --fast-toc ] .RB [ --buffers .IR buffer-count ] .RB [ --multi ] .RB [ --overburn ] .RB [ --eject ] .RB [ --swap ] .RB [ --session ] .RB [ --force ] .RB [ --reload ] .RB [ --keepimage ] .RB [ --on-the-fly ] .RB [ --paranoia-mode .IR mode ] .RB [ --with-cddb ] .RB [ --cddb-servers .IR server-list ] .RB [ --cddb-timeout .IR timeout ] .RB [ --cddb-directory .IR directory ] .RB [ --tmpdir .IR directory ] .RB [ --keep ] .RB [ --save ] .RB [ -n ] .RB [ -v .IR verbose-level ] .RI toc-file .SH DESCRIPTION .I cdrdao creates audio and data CD-Rs in disk-at-once (DAO) mode driven by a description file called .I toc-file. In DAO mode it is possible to create non standard track pre-gaps that have other lengths than 2 seconds and contain nonzero audio data. This is for example useful to divide live recordings into tracks where 2 second gaps would be kind of irritating. Instead of a .I toc-file a cue file (used by a famous DOS/Windows mastering tool) may be used. See the CUE FILES section for more details. .SH COMMANDS .TP The first argument must be one of the following commands: .TP .BI show-toc Print out a summary about what will be written to the CD-R. .TP .BI toc-info Prints out short toc-file summary. .TP .BI toc-size Prints total number of blocks for toc. .TP .BI read-toc Analyze each track of the inserted CD and create a .I toc-file that can be used to make a more or less exact copy of the CD. This command does not read out the audio or data tracks, use .BI read-cd for this purpose. You can specify a filename for the data file via the .BI \--datafile option. .TP .BI read-cd Copies all tracks of the inserted CD to an image file and creates a corresponding .I toc-file. The name of the image file defaults to "data.bin" if no .BI --datafile option is given. .TP .BI read-cddb Tries to retrieve title and artist data from a CDDB server for the CD represented by the given toc-file. The retrieved data is added as CD-TEXT data for language 0 to the toc-file. Existing CD-TEXT data for language 0 will be overwritten. .TP .BI show-data Print out all samples that would be written to the CD-R. Each line contains the sample number (starting at 0) and the decimal sample value for the left and right channel. Useful to check if the byte order of audio files is correct. .TP .BI read-test Check if all data can be read from the audio files that are defined in the .I toc-file. This will also check the communication with the slave process that is responsible for writing the audio data to the CD-recorder. Mainly used for testing. .TP .BI disk-info Shows information about the inserted CD-R. If the CD-R has an open session it will also print the start of the last and current session which is used by mkisofs to create an image for a second or higher session. .TP .BI discid Prints out CDDB information. .TP .BI msinfo Shows information required for creating multi session disks with mkisofs. The output is meant for processing by scripts. .TP .BI drive-info Shows drive information. .TP .BI unlock Tries to unlock the recorder device after a failed write or simulation run. If you cannot eject the CD after a cdrdao run try this command. .TP .BI blank Blanks a CD-RW. The CD-RW is minimally blanked by default. Use option .BI --blank-mode to select another blanking mode. Sometimes the blanking speed must be manually reduced for a successful blanking operation. Use option .BI --speed to select another blanking speed. .TP .BI scanbus Scan for devices. .TP .BI simulate Like .BI write but laser stays cold. It is a shortcut for .BI "write --simulate." .TP .BI write Write the CD-R according to the specifications in the .I toc-file. .TP .BI copy Performs all steps to copy a CD. The device containing the source CD must be specified with option .BI --source-device and the recorder device with option .BI --device. If only a single device is available the option .BI --source-device must be omitted and cdrdao will prompt to insert the CD-R after an image of the source CD was created. The image file with name "cddata<pid>.bin" will be created in the current working directory if no .BI --datafile option is given. The created image will be removed after it has been written. If option .BI --on-the-fly is given no image file is created and the data will be directly piped from the reading device to the CD recorder. .SH OPTIONS .TP .BI \--device " [prot:]bus,id,lun" Sets the SCSI address of the CD-recorder in form of a bus/id/lun triple, e.g. '0,2,0' for the logical unit 0 of SCSI device with ID 2 on bus 0. ATAPI devices can be specified by using the prefix 'ATAPI:', e.g. 'ATAPI:0,0,0'. On some systems a device node may be specified directly, e.g. '/dev/sg0' on Linux systems. Linux 2.6 users may also try the newer ATAPI interface with the 'ATA:' prefix. .TP .BI \--source-device " [prot:]bus,id,lun" Like above but used for the .BI copy command to specify the source device. .TP .BI \--driver " driver-id:option-flags" Force usage of specified driver instead of the automatically determined driver. Available driver IDs: .br cdd2600, plextor, plextor-scan, generic-mmc, generic-mmc-raw, ricoh-mp6200, yamaha-cdr10x, teac-cdr55, sony-cdu920, sony-cdu948, taiyo-yuden, toshiba. .br Specifying an illegal driver ID will give a list of available drivers. Option flags may be used to modify the behavior of some drivers. See .BI README for details. .TP .BI \--source-driver " driver-id:option-flags" Like above but used for the device specified with option .BI --source-device. .TP .BI \--speed " value" Set the writing speed to .I value. Default is the highest possible speed. .TP .BI \--blank-mode " mode" Sets the blanking mode. Available modes are .BI full and .BI minimal. Please consider that the data of minimally blanked disks may be easily recovered. Use the .BI full blanking mode for completely erasing all data. The default blanking mode is .BI minimal. .TP .BI \--datafile " file" Used for .BI "read-toc, read-cd" and .BI copy. Set the default data file placed in the toc-file by .BI read-toc. Use "-" to indicate STDIN. For commands .BI read-cd and .BI copy it specifies the name of the created image file. .TP .BI \--read-raw Only used for commands .BI read-cd and .BI read-toc. All data sectors will be written as 2352 byte blocks including the sector header and L-EC data to the image file. The track mode will be set to MODE1_RAW or MODE2_RAW in the created .I toc-file. .TP .BI \--read-subchan " mode" Used by commands .BI read-cd, .BI read-toc and .BI copy. Specifies the type of sub-channel data that is extracted from the source CD and written to the track image or copied to the destination CD. Mode may be .BI rw for reading packed R-W sub-channel data (de-interleaved and error corrected) and .BI rw_raw for reading raw R-W sub-channel data (not de-interleaved, not error corrected, L-EC data included in the track image). If this option is not specified no sub-channel data will be extracted. .TP .BI \--no-mode2-mixed Only used for commands .BI read-cd and .BI read-toc. If we have MODE2_FORM1 or MODE2_FORM2, don't extract it as MODE2_FORM_MIX. .I toc-file. .TP .BI \--tao-source This option indicates to the commands .I read-toc and .I read-cd that the source CD was written in TAO mode. It will be assumed that the pre-gap length between all tracks (except between two audio tracks) is the standard 150 blocks plus the number of link blocks (usually 2). The number of link blocks can be controlled with option .I --tao-source-adjust. Use this option only if .I read-toc or .I read-cd give error messages in the transition areas between two tracks. If you use this option with pressed CDs or CDs written in DAO mode you will get wrong results. .TP .BI \--tao-source-adjust " link-blocks" Specifies the number of link blocks for tracks written in TAO mode. This option has only an effect if option .I --tao-source is given. .TP .BI \--fast-toc Only used for command .BI read-toc. This option suppresses the pre-gap length and index mark extraction which speeds up the read-toc process. Standard 2 second pre-gaps (but no silence!) will be placed into the toc-file. The resulting CD will sound like the source CD. Only the CD player's display will behave slightly different in the transition area between two tracks. This option might help, too, if read-toc fails with your drive otherwise. .TP .BI \--buffers " buffer-count" Specifies the number of buffers that are allocated to avoid buffer under runs. The minimal buffer count is fixed to 10, default is 32 except on FreeBSD systems, on which default is 20. Each buffer holds 1 second of audio data so that dividing .I buffer-count by the writing speed gives the maximum time for which reading of audio data may be stalled. .TP .BI \--multi If this option is given the session will not be closed after the audio data is successfully written. It is possible to append another session on such disks, e.g. to create a CD-EXTRA. .TP .BI \--overburn By default cdrdao will not allow one to write more data on a medium than specified by the current medium. This option allows one to ignore this condition. .TP .BI \--eject Eject the CD-R after writing or write simulation. .TP .BI \--swap Swap the byte order of all samples that are send to the CD-recorder. .TP .BI \--session " session-nr" Used for .BI read-toc and .BI read-cd to specify the session which should be processed on multi session CDs. .TP .BI \--reload Indicates that the tray may be opened before writing without prompting the user to reset the disk status after a simulation run. .TP .BI \--force Forces the execution of an operation that otherwise would not be performed. .TP .BI \--paranoia-mode " mode" Sets the correction mode for digital audio extraction. 0: No checking, data is copied directly from the drive. 1: Perform overlapped reading to avoid jitter. 2: Like 1 but with additional checks of the read audio data. 3: Like 2 but with additional scratch detection and repair. The extraction speed reduces from 0 to 3. Default is the full paranoia mode (3). .TP .BI \--keepimage If a CD is copied with command .I copy this option will cause that the created image is not removed after the copy process has finished. .TP .BI \--on-the-fly Perform CD copy on the fly without creating an image file. .TP .BI \--with-cddb Enables the automatic fetching of CDDB data for use as CD-TEXT data for commands .I copy, .I read-toc and .I read-cd. .TP .BI \--cddb-servers " server-list" Sets space or ',' separated list of CDDB servers used for command .I read-cddb or for commands where the .I --with-cddb option is active. A server entry may have the following forms: .IP <server> Connect to <server>, default cddbp port (888), use cddbp protocol. .IP <server>:<port> Connect to <server>, port <port>, use cddbp protocol. .IP <server>:<cgi-bin-path> Connect to <server>, default http port (80), use http protocol, url: <cgi-bin-path>. .IP <server>:<port>:<cgi-bin-path> Connect to <server>, port <port>, use http protocol, url: <cgi-bin-path>. .IP <server>:<port>:<cgi-bin-path>:<proxy-server> Connect to <proxy-server>, default http port (80), use http protocol, url: http://<server>:<port>/<cgi-bin-path>. .IP <server>:<port>:<cgi-bin-path>:<proxy-server>:<proxy-port> Connect to <proxy-server>, port <proxy-port>, use http protocol, url: http://<server>:<port>/<cgi-bin-path>. The <cgi-bin-path> is usually "/~cddb/cddb.cgi". All servers of the server list will be tried in the given order until a successful connection can be established. For http proxy servers the first successful connected http proxy server will be used independent of the ability to connect to the target http server. Example: freedb.freedb.org:/~cddb/cddb.cgi .TP .BI \--cddb-timeout " timeout" Sets the timeout in seconds used for connections to CDDB servers. .TP .BI \--cddb-directory " directory" Specifies the local CDDB database directory where fetched CDDB records will be stored. If this option is not given a fetched CDDB record will not be stored locally. .TP .BI \--tmpdir " directory" Specifies the directory in which to store temporary data files created from decoding MP3 and Ogg Vorbis files. By default, "/tmp" is used. .TP .BI \--keep Upon exit from cdrdao, do not delete temporary WAV files created from MP3 and Ogg Vorbis files. .TP .BI \--save Saves some of the current options to the settings file "$HOME/.cdrdao" and exits. See section \'SETTINGS\' for more details. .TP .BI \-n Suppresses the 10 second pause before writing or simulating. .TP .BI \-v " verbose-level Sets verbose level. Levels > 2 are debug levels which produce a lot of output. .SH "TOC FILES" The .I toc-file describes what data is written to the CD-R and allows control over track/index positions, pre-gaps and sub-channel information. It is a simple text file, use your favorite text editor to create it. A .I toc-file contains an optional header and a sequence of track specifications. Comments starting with '//' reaching until end of line can be placed anywhere. .SS Header .IP CATALOG\ "ddddddddddddd" Specifies the optional catalog number of the CD. The string must contain exactly 13 digits. .LP The following flags specify the type of session that will be created. It is used to create the correct CD-TOC format and to check the consistency of the track modes for the desired session type. If multiple flags are given the last one will take effect. .IP CD_DA The disc contains only audio tracks. .IP CD_ROM The disc contains just mode 1 tracks or mode 1 and audio tracks (mixed mode CD). .IP CD_ROM_XA The disc contains mode 2 form 1 or mode 2 form 2 tracks. Audio tracks are allowed, too. This type must be used if multi session disks are created (option --multi). .IP CD_TEXT\ {\ ...\ } Defines global CD-TEXT data like the album title and the used languages. See the CD-TEXT section below for the syntax of the CD-TEXT block contents. .SS Track\ Specification .IP TRACK\ <track-mode>\ [<sub-channel-mode>] Starts a new track, the track number is incremented by 1. The length of a track must be at least 4 seconds. The block length of the input data depends on the <track-mode>: AUDIO: 2352 bytes (588 samples), MODE1: 2048 bytes, MODE1_RAW: 2352 bytes, MODE2: 2336 bytes, MODE2_FORM1: 2048 bytes, MODE2_FORM2: 2324 bytes, MODE2_FORM_MIX: 2336 bytes including the sub-header, MODE2_RAW: 2352 bytes. The <sub-channel-mode> is optional. If given it specifies the type of sub-channel data for each sector. RW: packed R-W sub-channel data (96 bytes, L-EC data will be generated if required), RW_RAW: raw R-W sub-channel data (interleaved and L-EC data already calculated, 96 bytes). The block length is increased by the sub-channel data length if a <sub-channel-mode> is specified. If the input data length is not a multiple of the block length it will be padded with zeros. .LP The following flags may follow the track start statement. They are used to set sub-channel information for the current track. Each flag is optional. If not given the following defaults are used: copy not permitted, no pre emphasis, two channel audio, no ISRC code. .IP "[ NO ] COPY" Sets or clears the copy permitted flag. .IP "[ NO ] PRE_EMPHASIS" Sets or clears the pre emphasis flag (only for audio tracks). .IP TWO_CHANNEL_AUDIO Indicates that track contains two channel audio data (only for audio tracks). .IP FOUR_CHANNEL_AUDIO Indicates that track contains four channel audio data (only for audio tracks). .IP ISRC\ "CCOOOYYSSSSS" Sets ISRC code of track (only for audio tracks). .br C: country code (upper case letters or digits) .br O: owner code (upper case letters or digits) .br Y: year (digits) .br S: serial number (digits) .LP An optional CD-TEXT block that defines the CD-TEXT data for this track may follow. See the CD-TEXT section below for the syntax of the CD-TEXT block contents. .IP "CD_TEXT { ... }" .LP At least one of the following statements must appear to specify the data for the current track. Lengths and start positions may be expressed in samples (1/44100 seconds) for audio tracks or in bytes for data tracks. It is also possible to give the length in blocks with the MSF format 'MM:SS:FF' specifying minutes, seconds and frames (0 <= 'FF' < 75) . A frame equals one block. If more than one statement is used the track will be composed by concatenating the data in the specified order. .IP "SILENCE <length>" Adds zero audio data of specified length to the current audio track. Useful to create silent pre-gaps. .IP "ZERO <length>" Adds zero data to data tracks. Must be used to define pre- or post-gaps between tracks of different mode. .IP [\ FILE\ |\ AUDIOFILE\ ]\ "<filename>"\ <start>\ [\ <length>\ ] Adds the audio data of specified file to the current audio track. It is possible to select a portion of an audio file with <start> and <length> which allows non destructive cutting. The first sample of an audio file is addressed with <start> = 0. If <length> is omitted or set to 0 all audio data from <start> until the end of file is used. Audio files may have raw or WAVE format with 16 bits per sample, 44.1 kHz sampling rate, stereo. Raw files must have the layout 'MSBLeft LSBLeft MSBRight LSBRight ...' (big endian byte order). WAVE files are expected to have little endian byte order. The option --swap reverses the expected byte order for all raw and WAVE files. Only filenames with a ".wav" ending are treated as WAVE files, all other names are assumed to be raw audio files. Use tools like sox(1) to convert other file formats to supported formats. Specifying a "-" as filename causes data to be read from STDIN. Currently only raw files are supported from STDIN. If you are unsure about the byte order of your audio files try the command 'show-data'. If the byte order is correct you will see a sequence of increasing or decreasing numbers for both channels. Otherwise numbers are jumping between very high and low values - high volume static. .IP DATAFILE\ "<filename>"\ [\ <length>\ ] Adds data from given file to the current data track. If <length> is omitted the actual file length will be used. .IP FIFO\ "<fifo\ path>"\ <length> Adds data from specified FIFO path to the current audio or data track. <length> must specify the amount of data that will be read from the FIFO. The value is always in terms of bytes (scalar value) or in terms of the block length (MSF value). .IP "START [ MM:SS:FF ]" Defines the length of the pre-gap (position where index switches from 0 to 1). If the MSF value is omitted the current track length is used. If the current track length is not a multiple of the block length the pre-gap length will be rounded up to next block boundary. If no START statement is given the track will not have a pre-gap. .IP "PREGAP MM:SS:FF" This is an alternate way to specify a pre-gap with zero audio data. It may appear before the first SILENCE, ZERO or FILE statement. Either PREGAP or START can be used within a track specification. It is equivalent to the sequence .br SILENCE MM:SS:FF .br START .br for audio tracks or .br ZERO MM:SS:FF .br START .br for data tracks. .LP Nothing prevents mixing 'DATAFILE'/'ZERO' and 'AUDIOFILE'/'SILENCE' statements within the same track. The results, however, are undefined. The end of a track specification may contain zero or more index increment statements: .IP "INDEX MM:SS:FF" Increments the index number at given position within the track. The first statement will increment from 1 to 2. The position is relative to the real track start, not counting an existing pre-gap. .SS CD-TEXT Blocks A CD-TEXT block may be placed in the global section to define data valid for the whole CD and in each track specification of a .I toc-file. The global section must define a language map that is used to map a .I language-number to country codes. Up to 8 different languages can be defined: .IP "LANGUAGE_MAP { 0 : c1 1 : c2 ... 7 : c7 }" The country code may be an integer value in the range 0..255 or one of the following countries (the corresponding integer value is placed in braces behind the token): EN(9, English) .br It is just necessary to define a mapping for the used languages. .LP If no mapping exists for a .I language-number the data for this language will be ignored. For each language a language block must exist that defines the actual data for a certain language. .IP "LANGUAGE language-number { cd-text-item cd-text-data cd-text-item cd-text-data ... }" Defines the CD-TEXT items for given .I language-number which must be defined in the language map. .LP The .I cd-text-data may be either a string enclosed by " or binary data like .nf .in +.5i { 0, 10, 255, ... } .in -.5i .fi where each integer number must be in the range 0..255. .br The .I cd-text-item may be one of the following: .IP TITLE String data: Title of CD or track. .IP PERFORMER String data. .IP SONGWRITER String data. .IP COMPOSER String data. .IP ARRANGER String data. .IP MESSAGE String data. Message to the user. .IP DISC_ID String data: Should only appear in the global CD-TEXT block. The format is usually: XY12345 .IP GENRE Mixture of binary data (genre code) and string data. Should only appear in the global CD-TEXT block. Useful entries will be created by .I gcdmaster. .IP TOC_INFO1 Binary data: Optional table of contents 1. Should only appear in the global CD-TEXT block. .IP TOC_INFO2 Binary data: Optional table of contents 2. Should only appear in the global CD-TEXT block. .IP UPC_EAN String data: This item should only appear in the global CD-TEXT block. Was always an empty string on the CD-TEXT CDs I had access to. .IP ISRC String data: ISRC code of track. The format is usually: CC-OOO-YY-SSSSS .IP SIZE_INFO Binary data: Contains summary about all CD-TEXT data and should only appear in the global CD-TEXT block. The data will be automatically (re)created when the CD-TEXT data is written. If one of the CD-TEXT items TITLE, PERFORMER, SONGWRITER, COMPOSER, ARRANGER, ISRC is defined for at least on track or in the global section it must be defined for all tracks and in the global section. If a DISC_ID item is defined in the global section, an ISRC entry must be defined for each track. .SS Examples Simple track without pre-gap with all audio data from WAVE file "data.wav": .nf .in +.5i CD_DA TRACK AUDIO FILE "data.wav" 0 .in -.5i .fi Standard track with two second pre-gap, ISRC code and CD-TEXT: .nf .in +.5i CD_DA CD_TEXT { LANGUAGE_MAP { 0 : EN } LANGUAGE 0 { TITLE "CD Title" PERFORMER "Performer" DISC_ID "XY12345" UPC_EAN "" } } TRACK AUDIO ISRC "DEXXX9800001" CD_TEXT { LANGUAGE 0 { TITLE "Track Title" PERFORMER "Performer" ISRC "DE-XXX-98-00001" } } PREGAP 0:2:0 FILE "data.wav" 0 .in -.5i .fi Track with 10 second pre-gap containing audio data from raw file "data.cdr": .nf .in +.5i CD_DA TRACK AUDIO FILE "data.cdr" 0 START 0:10:0 .in -.5i .fi Composed track with data from different files. Pre-gap data and length is taken from "pregapdata.wav". The first minute of "track.cdr" is omitted and two seconds silence are inserted at \&'2:0:0'. Index will be incremented after 2 and 4 minutes past track start: .nf .in +.5i CD_DA TRACK AUDIO FILE "pregapdata.wav" 0 START FILE "track.cdr" 1:0:0 1:0:0 SILENCE 0:2:0 FILE "track.cdr" 2:0:0 INDEX 2:0:0 INDEX 4:0:0 .in -.5i .fi Mixed mode CD with a data track as first track followed by two audio tracks. .nf .in +.5i CD_ROM TRACK MODE1 DATAFILE "data_1" ZERO 00:02:00 // post-gap TRACK AUDIO SILENCE 00:02:00 // pre-gap START FILE "data_2.wav" 0 TRACK AUDIO FILE "data_3.wav" 0 .in -.5i .fi .SH CUE FILES Cue files may be used wherever a .I toc-file is expected. The corresponding bin file is not taken from the FILE statement of a cue file but constructed from the cue file name by replacing ".cue" by ".bin". The cue file must have exactly one FILE statement. Currently, following track modes are supported: MODE1/2048, MODE1/2352, MODE2/2336, MODE2/2352. The CATALOG, ISRC and POSTGAP statements are parsed but not evaluated, yet. .SH SETTINGS Some of the command line options can be stored as settings at following locations. The files will be read on startup of .I cdrdao in that order: 1. /etc/cdrdao.conf 2. /etc/defaults/cdrdao 3. /etc/default/cdrdao 4. $HOME/.cdrdao Command line options will overwrite the loaded settings. The settings file contains name - value pairs separated by a colon. String values must be enclosed by ". The file is automatically written if the command line option .I \--save is used but it is also possible to modify it manually. Following values are defined: .IP write_device Device used for operations .I simulate, write, copy, blank, disk-info and .I unlock. Corresponding option: .I --device .IP write_driver Driver (including driver options) that is used for operations .I simulate, write, copy, blank, disk-info and .I unlock. Corresponding option: .I --driver .IP write_speed Specifies writing speed. Corresponding option: --speed .IP write_buffers Specifies fifo buffers used for recording. Corresponding option: --buffers .IP read_device Device used for operations .I read-toc, read-cd and .I copy. Corresponding option: .I --device or .I --source-device .IP read_driver Driver (including driver options) used for operations .I read-toc, read-cd and .I copy. Corresponding option: .I --driver or .I --source-driver .IP read_paranoia_mode Paranoia mode used for operations .I read-cd and copy. Corresponding option: .I --paranoia-mode .IP cddb_server_list CDDB server list for .I read-cddb. Corresponding option: .I --cddb-servers .IP cddb_timeout CDDB connection timeout in seconds used by .I read-cddb. Corresponding option: .I --cddb-timeout .IP cddb_directory Local directory where fetched CDDB records will be stored, used by .I read-cddb. Corresponding option: .I --cddb-directory .IP tmp_file_dir Directory where temporary WAV files will be created from decoding MP3 and Ogg Vorbis files. Corresponding option: .I --tmpdir .LP .SH BUGS If the program is terminated during the write/simulation process used IPC resources may not be released. Use ipcs(8) and ipcrm(8) to delete them. .SH AUTHOR .ft CW .nf \&Andreas Mueller mueller@daneb.ping.de [DEFUNCT] \&Denis Leroy <denis@poolshark.org> \&Manuel Clos <llanero@users.sourceforge.net> .ft R .fi .SH SEE ALSO .BR gcdmaster "(1), "cdrecord "(1), "cdda2wav "(1), "cdparanoia "(1), " sox "(1), "ipcs "(8), " ipcrm (8) ��������������������������������������cdrdao-cdrdao-f00afb2/dao/dao-win32.cc��������������������������������������������������������������0000664�0000000�0000000�00000010761�15114537466�0017460�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <andreas@daneb.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 * (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. */ #include "config.h" #include <stdio.h> #include <malloc.h> #include <errno.h> #include <string.h> #include <signal.h> #include <sys/types.h> #include "dao.h" #include "log.h" #define BUFSIZE 150 // buffer size in blocks int BUFFER_SIZE = BUFSIZE; static int TERMINATE = 0; unsigned char rbuf1[BUFSIZE * AUDIO_BLOCK_LEN]; // unsigned char rbuf2[BUFSIZE * AUDIO_BLOCK_LEN]; /* typedef struct uebergabe_write { CdrDriver *cdr; int testmode; DWORD total; } UWRITE; */ int writeDiskAtOnce (const Toc *toc, CdrDriver *cdr, int nofBuffers, int swap, int testMode) { long length = toc->length().lba(); long total = length * AUDIO_BLOCK_LEN; long n, rn; int err = 0; long cnt = 0; long blkCount = 0; long lba = 0; // LBA for writing long encodeLba = 150; // LBA for encoding data blocks long cntMb; long lastMb = 0; const Track *track = NULL; int trackNr = 1; Msf tstart, tend; TrackData::Mode dataMode; int encodingMode = 0; /* DWORD thread; UWRITE uw; */ TERMINATE = 0; if (cdr != NULL && cdr->bigEndianSamples() == 0) { // swap samples for little endian recorders swap = !swap; encodingMode = cdr->encodingMode(); } if (!testMode) { if (cdr->initDao() != 0) { err = 1; goto fail; } } TrackIterator itr(toc_); TrackReader reader; track = itr.first(tstart, tend); reader.init(track); if (reader.openData() != 0) { log_message(-2, "Opening of track data failed."); err = 1; goto fail; } dataMode = encodingMode == 0 ? TrackData::AUDIO : track->type(); if (!testMode) { if (cdr->startDao() != 0) { err = 2; goto fail; } log_message(0, "Writing tracks..."); } log_message(0, "Writing track %02d (mode %s/%s)...", trackNr, TrackData::mode2String(track->type()), TrackData::mode2String(dataMode)); while (length > 0 && !TERMINATE) { n = (length > BUFFER_SIZE ? BUFFER_SIZE : length); do { rn = reader.readData(encodingMode, encodeLba, (char*)rbuf1, n); if (rn < 0) { log_message(-2, "Reading of track data failed."); err = 1; goto fail; } if (rn == 0) { track = itr.next(tstart, tend); reader.init(track); if (reader.openData() != 0) { log_message(-2, "Opening of track data failed."); err = 1; goto fail; } trackNr++; if (encodingMode != 0) dataMode = track->type(); log_message(0, "Writing track %02d (mode %s/%s)...", trackNr, TrackData::mode2String(track->type()), TrackData::mode2String(dataMode)); } } while (rn == 0); encodeLba += rn; if (track->type() == TrackData::AUDIO && swap) swapSamples ((Sample *)rbuf1, rn * SAMPLES_PER_BLOCK); if (!testMode) { if (cdr->writeData(dataMode, lba, (char *) rbuf1, rn) != 0) { log_message(-2, "Write of audio data failed."); cdr->flushCache(); err = 1; goto fail; } else { cntMb = cnt >> 20; if (cntMb > lastMb) { log_message(0, "Wrote %ld of %ld MB.\r", cnt >> 20, total >> 20); lastMb = cntMb; } } } else { log_message(0, "Read %ld of %ld MB.\r", cnt >> 20, total >> 20); } length -= rn; cnt += rn * AUDIO_BLOCK_LEN; blkCount += rn; /* uw.cdr = cdr; uw.testmode = testMode; uw.total = total; if ((thread = _beginthread (writeSlave, 4096, &uw)) != -1) { } */ } if (testMode) log_message(0, "Read %ld blocks.", blkCount); else log_message(0, "Wrote %ld blocks.", blkCount); if (!testMode && daoStarted) { if (cdr->finishDao() != 0) err = 3; } fail: return err; } ���������������cdrdao-cdrdao-f00afb2/dao/dao.cc��������������������������������������������������������������������0000664�0000000�0000000�00000056372�15114537466�0016530�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <andreas@daneb.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 * (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. */ #include <config.h> #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <string.h> #include <signal.h> #include <sys/types.h> #include <sys/wait.h> #include <assert.h> #ifdef linux #include <linux/unistd.h> #include <linux/types.h> #endif #ifdef HAVE_SYS_MMAN_H #include <sys/mman.h> #endif #ifdef USE_POSIX_THREADS #include <pthread.h> #else #include <sys/ipc.h> #include <sys/shm.h> #endif #include "dao.h" #include "util.h" #include "log.h" #include "port.h" #include "log.h" #define DEBUG_WRITE 0 #if defined(__FreeBSD__) #define IPC_ARG_T void #else #define IPC_ARG_T msgbuf #endif struct ShmSegment { int id; char *buffer; }; struct Buffer { long bufLen; // number of blocks in buffer that should be written TrackData::Mode mode; // data mode for writing TrackData::Mode trackMode; // mode of track may differ from 'mode' if data // blocks must be encoded in audio blocks, // only used for message printing TrackData::SubChannelMode subChanMode; // sub-channel data mode int trackNr; // if != 0 a new track with given number has started int trackProgress; // reading progress of current track 0..1000 char *buffer; // address of buffer that should be written }; struct BufferHeader { long buffersRead; // number of blocks that are read and put to the buffer long buffersWritten; // number of blocks that were taken from the buffer int buffersFilled; // set to 1 by reader process when buffer is filled the // first time int readerFinished; int readerTerminated; int terminateReader; long nofBuffers; // number of available buffers Buffer *buffers; }; // buffer size in blocks int BUFFER_SIZE = 75; static int TERMINATE = 0; static int getSharedMemory(long nofBuffers, BufferHeader **header, long *nofSegments, ShmSegment **shmSegments); static void releaseSharedMemory(long nofSegments, ShmSegment *shmSegments); static RETSIGTYPE terminationRequest(int sig) { if (sig == SIGQUIT || sig == SIGTERM) TERMINATE = 1; #if 0 if (sig == SIGCHLD) { log_message(0, "SIGCHLD received."); } #endif } #ifndef USE_POSIX_THREADS // Waits or polls for termination of a child process. // noHang: 0: wait until child terminates, 1: just poll if child terminated // status: filled with status information, only valid if 0 is returned // return: 0: child exited // 1: no child exited, can only happen if 'noHang' is 1 // 2: wait failed, 'errno' contains cause static int waitForChild(int noHang, int *status) { int ret; do { if (noHang) ret = wait3(status, WNOHANG, NULL); else ret = wait(status); if (ret > 0) return 0; if (ret < 0 && errno != EINTR #ifdef ERESTARTSYS && errno != ERESTARTSYS #endif ) { return 2; } } while (ret < 0); return 1; } #endif // Blocks all signals that are handled by this module. static void blockSignals() { sigset_t set; sigemptyset(&set); sigaddset(&set, SIGCHLD); sigaddset(&set, SIGQUIT); sigaddset(&set, SIGTERM); #ifdef USE_POSIX_THREADS #ifdef HAVE_PTHREAD_SIGMASK pthread_sigmask(SIG_BLOCK, &set, NULL); #endif #else sigprocmask(SIG_BLOCK, &set, NULL); #endif } // Blocks all signals that are handled by this module. static void unblockSignals() { sigset_t set; sigemptyset(&set); sigaddset(&set, SIGCHLD); sigaddset(&set, SIGQUIT); sigaddset(&set, SIGTERM); #ifdef USE_POSIX_THREADS #ifdef HAVE_PTHREAD_SIGMASK pthread_sigmask(SIG_UNBLOCK, &set, NULL); #endif #else sigprocmask(SIG_UNBLOCK, &set, NULL); #endif } // return: 0: OK // 1: child process terminated and has been collected with 'wait()' // 2: error -> child process must be terminated static int writer(const Toc *toc, CdrDriver *cdr, BufferHeader *header, long lba, int speed) { long total = toc->length().lba() * AUDIO_BLOCK_LEN; long totalTracks = toc->nofTracks(); long cnt = 0; long blkCount = 0; long len = 0; long cntMb; long lastMb = 0; long buffered; int buffFill; int writerFill = 0; int minFill = 100; int maxFill = 0; int actTrackNr = 0; long actProgress; TrackData::Mode dataMode; TrackData::SubChannelMode subChanMode; #ifndef USE_POSIX_THREADS int status; #endif log_message(3, "Waiting for reader process"); while (header->buffersFilled == 0) { sleep(1); if (header->readerTerminated) { log_message(-2, "Reader process terminated abnormally."); return 1; } #ifndef USE_POSIX_THREADS // Check if child has terminated switch (waitForChild(1, &status)) { case 0: // Child exited log_message(-2, "Reader process terminated abnormally."); return 1; case 2: log_message(-2, "wait failed: %s", strerror(errno)); return 2; } #endif } #if DEBUG_WRITE FILE *fp = fopen("test.out", "w"); #endif log_message(3, "Awaken, will start writing"); if (cdr != NULL) { cdr->sendWriteCdProgressMsg(CdrDriver::WCD_LEADIN, totalTracks, 0, 0, 0, 100); blockSignals(); if (cdr->startDao() != 0) { unblockSignals(); return 2; } unblockSignals(); } do { //log_message(4, "Slave: waiting for master."); while (header->buffersWritten == header->buffersRead) { if (header->readerTerminated) { log_message(-2, "Reader process terminated abnormally."); return 1; } #ifndef USE_POSIX_THREADS // Check if child has terminated switch (waitForChild(1, &status)) { case 0: // Child exited log_message(-2, "Reader process terminated abnormally."); return 1; case 2: log_message(-2, "wait failed: %s", strerror(errno)); return 2; } #endif mSleep(10); } Buffer &buf = header->buffers[header->buffersWritten % header->nofBuffers]; len = buf.bufLen; dataMode = buf.mode; subChanMode = buf.subChanMode; if (header->readerFinished) { buffFill = 100; if (maxFill == 0) maxFill = 100; } else { buffered = header->buffersRead - header->buffersWritten; if (buffered == header->nofBuffers || buffered == header->nofBuffers - 1) { buffFill = 100; } else { buffFill = 100 * buffered; buffFill /= header->nofBuffers; } if (buffFill > maxFill) maxFill = buffFill; } if (buffFill < minFill) minFill = buffFill; if (len == 0) { // all data is written log_message(1, ""); if (cdr == NULL) log_message(1, "Read %ld blocks.", blkCount); else log_message(1, "Wrote %ld blocks. Buffer fill min %d%%/max %d%%.", blkCount, minFill, maxFill); #if DEBUG_WRITE if (fp != NULL) fclose(fp); #endif if (cdr != NULL) { cdr->sendWriteCdProgressMsg(CdrDriver::WCD_LEADOUT, totalTracks, 0xaa, 1000, 1000, 100); blockSignals(); if (cdr->finishDao() != 0) { unblockSignals(); return 2; } unblockSignals(); } return 0; } cnt += len * AUDIO_BLOCK_LEN; blkCount += len; if (buf.trackNr > 0) { log_message(1, "Writing track %02d (mode %s/%s %s)...", buf.trackNr, TrackData::mode2String(buf.trackMode), TrackData::mode2String(dataMode), TrackData::subChannelMode2String(subChanMode)); actTrackNr = buf.trackNr; } //log_message(4, "Slave: writing buffer %p (%ld).", buf, len); #if DEBUG_WRITE if (fp != NULL) { if (cdr != NULL) { log_message(0, "dao: blockSize: %ld", cdr->blockSize(dataMode, subChanMode)); fwrite(buf.buffer, cdr->blockSize(dataMode, subChanMode), len, fp); } else { fwrite(buf.buffer, 2352, len, fp); } } #endif // Write track data. if (cdr != NULL) { blockSignals(); if (cdr->writeData(dataMode, subChanMode, lba, buf.buffer, len) != 0) { log_message(-2, "Writing failed - buffer under run?"); unblockSignals(); return 2; } // Print stat line update every megabyte. cntMb = cnt >> 20; if (cntMb > lastMb) { long totalcap, availcap; if (cdr->readBufferCapacity(&totalcap, &availcap)) { writerFill = (int)((1.0 - ((double)availcap / (double)totalcap)) * 100.0); log_message(1, "Wrote %ld of %ld MB (Buffers %3d%% %3d%%).\r", cnt >> 20, total >> 20, buffFill, writerFill); } else { log_message(1, "Wrote %ld of %ld MB (Buffer %3d%%).\r", cnt >> 20, total >> 20, buffFill); } lastMb = cntMb; } unblockSignals(); actProgress = cnt; actProgress /= total / 1000; cdr->sendWriteCdProgressMsg(CdrDriver::WCD_DATA, totalTracks, actTrackNr, buf.trackProgress, actProgress, buffFill, writerFill); } else { if (speed > 0) { log_message(1, "Read %ld of %ld MB (Buffer %3d%%).\r", cnt >> 20, total >> 20, buffFill); mSleep(1000 / speed); } else { log_message(1, "Read %ld of %ld MB.\r", cnt >> 20, total >> 20); } } header->buffersWritten += 1; } while (!TERMINATE); log_message(-1, "Writing/simulation/read-test aborted on user request."); return 2; } struct ReaderArgs { const Toc *toc; CdrDriver *cdr; int swap; BufferHeader *header; long startLba; }; static void *reader(void *args) { const Toc *toc = ((ReaderArgs*)args)->toc; CdrDriver *cdr = ((ReaderArgs*)args)->cdr; int swap = ((ReaderArgs*)args)->swap; BufferHeader *header = ((ReaderArgs*)args)->header; long lba = ((ReaderArgs*)args)->startLba + 150; // used to encode the sector // header (MSF) long length = toc->length().lba(); long n, rn; int first = header->nofBuffers; const Track *track; int trackNr = toc->firstTrackNo() == 0 ? 1 : toc->firstTrackNo(); TrackData::Mode dataMode; TrackData::SubChannelMode subChanMode; int encodingMode = 0; int subChanEncodingMode = 1; int newTrack; long tact; // number of blocks already read from current track long tprogress; setRealTimeScheduling(4); giveUpRootPrivileges(); if (cdr != NULL) { if (cdr->bigEndianSamples() == 0) { // swap samples for little endian recorders swap = !swap; } encodingMode = cdr->encodingMode(); } log_message(4, "Swap: %d", swap); TrackIterator itr(toc); TrackReader reader; track = itr.first(); reader.init(track); if (reader.openData() != 0) { log_message(-2, "Opening of track data failed."); goto fail; } newTrack = 1; tact = 0; dataMode = (encodingMode == 0) ? TrackData::AUDIO : track->type(); subChanMode = track->subChannelType(); if (cdr != NULL) subChanEncodingMode = cdr->subChannelEncodingMode(subChanMode); do { n = (length > BUFFER_SIZE ? BUFFER_SIZE : length); Buffer &buf = header->buffers[header->buffersRead % header->nofBuffers]; do { rn = reader.readData(encodingMode, subChanEncodingMode, lba, buf.buffer, n); if (rn < 0) { log_message(-2, "Reading of track data failed."); goto fail; } if (rn == 0) { track = itr.next(); reader.init(track); if (reader.openData() != 0) { log_message(-2, "Opening of track data failed."); goto fail; } trackNr++; if (encodingMode != 0) dataMode = track->type(); subChanMode = track->subChannelType(); if (cdr != NULL) subChanEncodingMode = cdr->subChannelEncodingMode(subChanMode); newTrack = 1; tact = 0; } } while (rn == 0); lba += rn; tact += rn; if (cdr != NULL && ((track->type() == TrackData::AUDIO && swap) || (encodingMode == 0 && cdr->bigEndianSamples() == 0 && (track->type() != TrackData::AUDIO)))) { // swap audio data long blockLen = cdr->blockSize(dataMode, subChanMode); char *brun = buf.buffer; int i; for (i = 0; i < rn; i++, brun += blockLen) swapSamples((Sample *)brun, SAMPLES_PER_BLOCK); } buf.bufLen = rn; buf.mode = dataMode; buf.trackMode = track->type(); buf.subChanMode = subChanMode; tprogress = tact * 1000; tprogress /= track->length().lba(); buf.trackProgress = tprogress; if (newTrack) { // inform write process that it should print message about new track buf.trackNr = trackNr; } else { buf.trackNr = 0; } header->buffersRead += 1; length -= rn; if (first > 0) { first--; if (first == 0 || length == 0) { log_message(3, "Buffer filled"); header->buffersFilled = 1; } } // wait for writing process to finish writing of previous buffer //log_message(4, "Reader: waiting for Writer."); while (header->buffersRead - header->buffersWritten == header->nofBuffers && header->terminateReader == 0) { mSleep(10); } newTrack = 0; } while (length > 0 && header->terminateReader == 0); header->readerFinished = 1; if (header->terminateReader == 0) { Buffer &buf1 = header->buffers[header->buffersRead % header->nofBuffers]; buf1.bufLen = 0; buf1.trackNr = 0; header->buffersRead += 1; } #ifndef USE_POSIX_THREADS // wait until we get killed while (1) sleep(1000); exit(0); #endif return NULL; fail: header->readerTerminated = 1; #ifndef USE_POSIX_THREADS exit(1); #endif return NULL; } int writeDiskAtOnce(const Toc *toc, CdrDriver *cdr, int nofBuffers, int swap, int testMode, int speed) { int err = 0; BufferHeader *header = NULL; long nofShmSegments = 0; ShmSegment *shmSegments = NULL; long startLba = 0; #ifdef USE_POSIX_THREADS pthread_t readerThread; pthread_attr_t readerThreadAttr; int threadStarted = 0; #else int pid = 0; int status; #endif #if 1 if (nofBuffers < 10) { nofBuffers = 10; log_message(-1, "Adjusted number of FIFO buffers to 10."); } #endif if (getSharedMemory(nofBuffers, &header, &nofShmSegments, &shmSegments) != 0) { releaseSharedMemory(nofShmSegments, shmSegments); return 1; } header->buffersRead = 0; header->buffersWritten = 0; header->buffersFilled = 0; header->readerFinished = 0; header->readerTerminated = 0; header->terminateReader = 0; TERMINATE = 0; installSignalHandler(SIGINT, SIG_IGN); installSignalHandler(SIGPIPE, SIG_IGN); installSignalHandler(SIGALRM, SIG_IGN); installSignalHandler(SIGCHLD, terminationRequest); installSignalHandler(SIGQUIT, terminationRequest); installSignalHandler(SIGTERM, terminationRequest); if (!testMode) { const DiskInfo *di; if (cdr->initDao(toc) != 0) { err = 1; goto fail; } if ((di = cdr->diskInfo()) != NULL) { startLba = di->thisSessionLba; } } // start reader process #ifdef USE_POSIX_THREADS if (pthread_attr_init(&readerThreadAttr) != 0) { log_message(-2, "pthread_attr_init failed: %s", strerror(errno)); err = 1; goto fail; } ReaderArgs rargs; rargs.toc = toc; rargs.cdr = cdr; rargs.swap = swap; rargs.header = header; rargs.startLba = startLba; if (pthread_create(&readerThread, &readerThreadAttr, reader, &rargs) != 0) { log_message(-2, "Cannot create thread: %s", strerror(errno)); pthread_attr_destroy(&readerThreadAttr); err = 1; goto fail; } else { threadStarted = 1; } #else /* USE_POSIX_THREADS */ if ((pid = fork()) == 0) { // we are the new process setsid(); // detach from controlling terminal #ifdef HAVE_MLOCKALL if (geteuid() == 0) { if (mlockall(MCL_CURRENT|MCL_FUTURE) != 0) { log_message(-1, "Cannot lock memory pages: %s", strerror(errno)); } log_message(4, "Reader process memory locked"); } #endif ReaderArgs rargs; rargs.toc = toc; rargs.cdr = cdr; rargs.swap = swap; rargs.header = header; rargs.startLba = startLba; reader(&rargs); } else if (pid < 0) { log_message(-2, "fork failed: %s", strerror(errno)); err = 1; goto fail; } #endif /* USE_POSIX_THREADS */ switch (setRealTimeScheduling(5)) { case 1: log_message(-1, "No super user permission to setup real time scheduling."); break; case 2: log_message(2, "Real time scheduling not available."); break; } #ifdef HAVE_MLOCKALL if (geteuid() == 0) { if (mlockall(MCL_CURRENT|MCL_FUTURE) != 0) { log_message(-1, "Cannot lock memory pages: %s", strerror(errno)); } log_message(4, "Memory locked"); } #endif giveUpRootPrivileges(); switch (writer(toc, cdr, header, startLba, speed)) { case 1: // error, reader process terminated abnormally #ifndef USE_POSIX_THREADS pid = 0; #endif err = 1; break; case 2: // error, reader process must be terminated err = 1; break; } if (err != 0 && cdr != NULL) cdr->abortDao(); // abort writing process fail: #ifdef HAVE_MUNLOCKALL munlockall(); #endif #ifdef USE_POSIX_THREADS if (threadStarted) { header->terminateReader = 1; if (pthread_join(readerThread, NULL) != 0) { log_message(-2, "pthread_join failed: %s", strerror(errno)); err = 1; } pthread_attr_destroy(&readerThreadAttr); } #else if (pid != 0) { if (kill(pid, SIGKILL) == 0) { waitForChild(0, &status); } } #endif releaseSharedMemory(nofShmSegments, shmSegments); installSignalHandler(SIGINT, SIG_DFL); installSignalHandler(SIGPIPE, SIG_DFL); installSignalHandler(SIGALRM, SIG_DFL); installSignalHandler(SIGCHLD, SIG_DFL); installSignalHandler(SIGQUIT, SIG_DFL); installSignalHandler(SIGTERM, SIG_DFL); return err; } #ifdef USE_POSIX_THREADS static int getSharedMemory(long nofBuffers, BufferHeader **header, long *nofSegments, ShmSegment **shmSegment) { long b; long bufferSize = BUFFER_SIZE * (AUDIO_BLOCK_LEN + PW_SUBCHANNEL_LEN); *header = NULL; *nofSegments = 0; *shmSegment = NULL; if (nofBuffers <= 0) { return 1; } *shmSegment = new ShmSegment; *nofSegments = 1; (*shmSegment)->id = -1; (*shmSegment)->buffer = new char[sizeof(BufferHeader) + nofBuffers * sizeof(Buffer) + nofBuffers * bufferSize]; if ( (*shmSegment)->buffer == NULL) { log_message(-2, "Cannot allocated memory for ring buffer."); return 1; } *header = (BufferHeader*)((*shmSegment)->buffer); (*header)->nofBuffers = nofBuffers; (*header)->buffers = (Buffer*)((*shmSegment)->buffer + sizeof(BufferHeader)); char *bufferBase = (*shmSegment)->buffer + sizeof(BufferHeader) + nofBuffers * sizeof(Buffer); for (b = 0; b < nofBuffers; b++) (*header)->buffers[b].buffer = bufferBase + b * bufferSize; return 0; } static void releaseSharedMemory(long nofSegments, ShmSegment *shmSegment) { if (shmSegment == NULL || nofSegments == 0) return; if (shmSegment->buffer != NULL) { delete[] shmSegment->buffer; shmSegment->buffer = NULL; } delete shmSegment; } #else /* USE_POSIX_THREADS */ static int getSharedMemory(long nofBuffers, BufferHeader **header, long *nofSegments, ShmSegment **shmSegments) { long i, b; long bufferSize = BUFFER_SIZE * (AUDIO_BLOCK_LEN + PW_SUBCHANNEL_LEN); long maxSegmentSize = 0; long bcnt = 0; *header = NULL; *nofSegments = 0; *shmSegments = NULL; if (nofBuffers <= 0) { return 1; } #if defined(linux) && defined(IPC_INFO) struct shminfo info; if (shmctl(0, IPC_INFO, (struct shmid_ds*)&info) < 0) { log_message(-1, "Cannot get IPC info: %s", strerror(errno)); maxSegmentSize = 4 * 1024 * 1024; log_message(-1, "Assuming %ld MB shared memory segment size.", maxSegmentSize >> 20); } else { maxSegmentSize = info.shmmax; } #elif defined(__FreeBSD__) maxSegmentSize = 4 * 1024 * 1024; // 4 MB #else maxSegmentSize = 1 * 1024 * 1024; // 1 MB #endif log_message(4, "Shm max segment size: %ld (%ld MB)", maxSegmentSize, maxSegmentSize >> 20); if (maxSegmentSize < sizeof(BufferHeader) + nofBuffers * sizeof(Buffer)) { log_message(-2, "Shared memory segment cannot hold a single buffer."); return 1; } maxSegmentSize -= sizeof(BufferHeader) + nofBuffers * sizeof(Buffer); long buffersPerSegment = maxSegmentSize / bufferSize; if (buffersPerSegment == 0) { log_message(-2, "Shared memory segment cannot hold a single buffer."); return 1; } *nofSegments = nofBuffers / buffersPerSegment; if (nofBuffers % buffersPerSegment != 0) *nofSegments += 1; *shmSegments = new ShmSegment[*nofSegments]; log_message(4, "Using %ld shared memory segments.", *nofSegments); for (i = 0; i < *nofSegments; i++) { (*shmSegments)[i].id = -1; (*shmSegments)[i].buffer = NULL; } long bufCnt = nofBuffers; long n; long segmentLength; char *bufferBase; for (i = 0; i < *nofSegments; i++) { n = (bufCnt > buffersPerSegment ? buffersPerSegment : bufCnt); segmentLength = n * bufferSize; if (*header == NULL) { // first segment contains the buffer header segmentLength += sizeof(BufferHeader) + nofBuffers * sizeof(Buffer); } (*shmSegments)[i].id = shmget(IPC_PRIVATE, segmentLength, 0600|IPC_CREAT); if ((*shmSegments)[i].id < 0) { log_message(-2, "Cannot create shared memory segment: %s", strerror(errno)); log_message(-2, "Try to reduce the buffer count (option --buffers)."); return 1; } (*shmSegments)[i].buffer = (char *)shmat((*shmSegments)[i].id, 0, 0); if (((*shmSegments)[i].buffer) == NULL || ((*shmSegments)[i].buffer) == (char *)-1) { (*shmSegments)[i].buffer = NULL; log_message(-2, "Cannot get shared memory: %s", strerror(errno)); log_message(-2, "Try to reduce the buffer count (option --buffers)."); return 1; } if (*header == NULL) { bufferBase = (*shmSegments)[i].buffer + sizeof(BufferHeader) + nofBuffers * sizeof(Buffer); *header = (BufferHeader*)(*shmSegments)[i].buffer; (*header)->nofBuffers = nofBuffers; (*header)->buffers = (Buffer*)((*shmSegments)[i].buffer + sizeof(BufferHeader)); } else { bufferBase = (*shmSegments)[i].buffer; } for (b = 0; b < n; b++) (*header)->buffers[bcnt++].buffer = bufferBase + b * bufferSize; bufCnt -= n; } assert(bcnt == nofBuffers); return 0; } static void releaseSharedMemory(long nofSegments, ShmSegment *shmSegments) { long i; if (shmSegments == NULL || nofSegments == 0) return; for (i = 0; i < nofSegments; i++) { if (shmSegments[i].id >= 0) { if (shmSegments[i].buffer != NULL) { if (shmdt(shmSegments[i].buffer) != 0) { log_message(-2, "shmdt: %s", strerror(errno)); } } if (shmctl(shmSegments[i].id, IPC_RMID, NULL) != 0) { log_message(-2, "Cannot remove shared memory: %s", strerror(errno)); } } } delete[] shmSegments; } #endif /* USE_POSIX_THREADS */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/dao.h���������������������������������������������������������������������0000664�0000000�0000000�00000002001�15114537466�0016346�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #ifndef __DAO_H__ #define __DAO_H__ #include "Toc.h" #include "CdrDriver.h" int writeDiskAtOnce(const Toc *, CdrDriver *, int nofBuffers, int swap, int testMode, int speed); #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/data.cc�������������������������������������������������������������������0000664�0000000�0000000�00000032013�15114537466�0016660�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ /* Data for creating an sector with L-EC errors */ unsigned char SECTOR_ERROR_DATA[2448] = { 0x95,0xd1,0x90,0x52,0x73,0xeb,0xf3,0xda,0xef,0x6e,0xd1,0x4b,0x03,0xab,0xd9,0xe5, 0x71,0x86,0x4e,0xb4,0x4a,0x39,0x2c,0xa2,0x10,0x75,0xfb,0x70,0xbf,0x33,0xc6,0x55, 0x05,0x56,0xa7,0x78,0x41,0x9b,0x52,0x30,0x09,0x24,0x7b,0x0d,0xcf,0x55,0xf2,0x40, 0xdb,0x40,0xf4,0x26,0x7a,0x21,0xc8,0x8a,0x96,0xc3,0xfa,0x55,0xf7,0xc0,0xaa,0xfc, 0x17,0x52,0x74,0x58,0xed,0xc7,0x89,0xf6,0xeb,0x04,0x03,0xba,0x59,0xf5,0xfb,0x35, 0x36,0xef,0x5b,0xb0,0x10,0x23,0x3a,0xa6,0xe7,0x34,0xfc,0xde,0xf4,0xa6,0xda,0x0b, 0xf8,0x4e,0x64,0xe5,0x15,0xed,0xdc,0x00,0xf1,0xdf,0xbb,0x4b,0xd5,0xb6,0x80,0x0b, 0xa5,0xdb,0xbb,0xb6,0xfe,0xf5,0x5c,0xe5,0x29,0x58,0xc3,0x1d,0xff,0x9d,0x29,0xf7, 0xec,0x8d,0xdd,0x01,0x7a,0xb9,0x02,0x6b,0x98,0xbd,0xb6,0x6d,0x73,0x36,0x78,0x18, 0x11,0x33,0xce,0x10,0x28,0x2b,0xf5,0x51,0x83,0xb9,0x6f,0x82,0x56,0x98,0x7a,0x42, 0x25,0x57,0x44,0x9f,0x10,0x46,0x0a,0xa8,0x03,0xc1,0x16,0x76,0xf7,0x8e,0x8e,0x09, 0xc2,0x5d,0x19,0xea,0x88,0x0e,0x3c,0x0b,0xc7,0xab,0x8e,0x1e,0x43,0x08,0x60,0x68, 0x5f,0xa4,0x07,0x6f,0xea,0x11,0x17,0xed,0xd2,0x2d,0x63,0xca,0xbc,0xf2,0xd3,0x7e, 0x4f,0xec,0x68,0xd7,0xfa,0xa4,0xe2,0xc2,0x4f,0x70,0xe0,0x92,0x78,0x40,0xfa,0xd7, 0xe5,0x01,0x46,0xcf,0x13,0x5e,0xbd,0xe5,0x8b,0x20,0xaf,0x47,0x12,0x82,0xc5,0x61, 0x6e,0x2e,0x38,0x69,0xd2,0x1b,0x2b,0x22,0x8b,0x0b,0xb4,0x04,0x4b,0xaf,0xdb,0x30, 0xb0,0x22,0x00,0xc3,0x80,0xbd,0xa9,0x0b,0xdd,0x58,0x53,0xf0,0xdb,0x18,0x51,0x49, 0x46,0x8a,0xb2,0x19,0xa5,0xdd,0x3b,0x30,0xe8,0xef,0x34,0x34,0x9e,0x10,0x64,0x4f, 0x32,0x64,0x12,0xb2,0x21,0xbb,0xbd,0xff,0x14,0x10,0xef,0xef,0x29,0x40,0x38,0x6f, 0xca,0xeb,0x88,0x6f,0xc8,0xc3,0xa0,0xb1,0xb3,0xd4,0xe5,0x51,0xe4,0x49,0xa0,0x16, 0xae,0xb3,0xc8,0xcf,0x6e,0x86,0xce,0x82,0x96,0xbd,0x71,0xbf,0xfe,0xaa,0x2f,0xc8, 0x95,0xb7,0x38,0x5d,0x7b,0xd8,0x0e,0x2e,0xac,0xf3,0x7f,0x91,0x3d,0x20,0xa7,0xeb, 0xd3,0x70,0xba,0x41,0xf6,0x89,0xc4,0x8c,0x46,0x35,0x4c,0x44,0xdf,0x7b,0x0d,0x74, 0x32,0x45,0xd2,0xad,0x1d,0xe0,0xdb,0xc9,0xd4,0x5b,0x5a,0x11,0x7b,0x02,0xfc,0x4e, 0x72,0xb6,0x8f,0x68,0x3f,0x53,0xf4,0x86,0x89,0x40,0xca,0x68,0xbb,0xd7,0xdd,0xee, 0x1c,0xaf,0x9b,0x39,0x8f,0x77,0x03,0x63,0xd2,0x5d,0x74,0x4d,0x5f,0x70,0x9b,0xd1, 0x27,0x2a,0x39,0x66,0x7e,0x2e,0xec,0x07,0x6e,0xb7,0x6f,0x2a,0x8e,0x4c,0x18,0xab, 0xfb,0xb3,0xe4,0x8b,0x2a,0xe7,0xee,0xfc,0x45,0x63,0x49,0xa4,0xd3,0xe4,0x76,0xfa, 0x0f,0xaf,0x61,0x8d,0xdd,0x4d,0x94,0x4c,0x04,0x03,0x76,0x93,0x50,0x8e,0x3e,0x4b, 0x41,0x22,0xd6,0x6c,0x0a,0xc5,0x68,0x4f,0x28,0xb2,0xf3,0xfb,0x96,0x69,0xf6,0xa5, 0x19,0x57,0x32,0xf6,0xa4,0xc6,0x42,0xa9,0xca,0xb8,0x3c,0x1a,0x46,0x7a,0x65,0x88, 0x9c,0x3c,0xf4,0xa6,0x01,0x5c,0xf5,0x29,0x0e,0xe9,0x24,0xa5,0x52,0x1a,0x4a,0x6b, 0x71,0x7d,0x62,0x16,0x43,0xa4,0xbf,0x0d,0x5d,0xfb,0x27,0xa3,0x75,0x8d,0x2b,0x11, 0xc9,0x1f,0xb8,0xca,0x7c,0xad,0xf3,0x8a,0x96,0x17,0x2f,0xe9,0x32,0x7a,0x54,0xa3, 0xf7,0xb6,0xb9,0x3a,0x5b,0x78,0x48,0xb8,0x73,0x6f,0x5b,0xe8,0xfc,0x87,0xfa,0xc5, 0xa6,0xb2,0x8f,0x22,0x5f,0x82,0xad,0xf6,0x9a,0xdc,0xdf,0xcc,0x56,0x33,0x6f,0x4d, 0xea,0x29,0x88,0x45,0xa1,0xd0,0xfd,0x15,0x3f,0x58,0xfd,0x3c,0xdf,0xf7,0x01,0x86, 0xa9,0x91,0xa8,0x09,0x13,0x55,0xff,0xad,0x32,0xde,0x79,0x88,0x11,0xe9,0xd6,0xfb, 0x12,0x5e,0x40,0xb3,0x2e,0x3d,0xc8,0x6d,0x96,0xc6,0xa9,0x75,0xbd,0xab,0xfb,0x67, 0x3c,0xa4,0x70,0x4f,0xf9,0x6f,0xfd,0x2b,0x4d,0x76,0xb4,0x5e,0x5f,0x8a,0x5a,0x71, 0xe8,0x9a,0x25,0x16,0xd8,0xed,0x83,0x6e,0xb3,0x2d,0xe3,0x71,0xd8,0xdf,0xd8,0x14, 0x83,0x48,0x63,0x7c,0xb7,0x60,0xa8,0x04,0xd7,0x5c,0x62,0x36,0xe6,0xbc,0xa8,0xce, 0x57,0xcd,0xe4,0x2f,0xba,0x67,0x9d,0x6e,0x94,0x80,0xdf,0x6c,0x5f,0xb7,0x80,0xe2, 0xff,0xe4,0x5f,0xb6,0x44,0x07,0xba,0x1b,0x63,0x1c,0x52,0x49,0xd9,0xfa,0x17,0x30, 0xc7,0xfb,0x5f,0x81,0x62,0xfc,0xef,0xf7,0x7c,0xce,0x63,0xdc,0x85,0xe4,0xbe,0x84, 0xc8,0x1d,0x3a,0x0c,0x24,0xf4,0x28,0x87,0x11,0x7a,0xd0,0xea,0x74,0xe7,0x1a,0x3b, 0xe2,0x79,0xbc,0x45,0x75,0xac,0x3c,0xf1,0x7a,0x9f,0xcd,0x00,0x83,0x8c,0x84,0x4b, 0xa9,0xbf,0x58,0xce,0xb3,0x80,0x55,0xc4,0xfa,0x26,0xae,0x6e,0x0d,0xc8,0xa9,0xf0, 0x41,0x65,0x35,0xb6,0x11,0x71,0xa8,0x8c,0x10,0x75,0x8c,0x94,0x01,0x10,0xdf,0xab, 0xcf,0x37,0x79,0x83,0xb7,0xce,0x47,0xb1,0xf4,0xf6,0x1f,0x02,0xbe,0xc8,0xf2,0x00, 0x2e,0x27,0xb6,0x3f,0x98,0x5e,0xcb,0xa8,0xd4,0x57,0x3c,0xd5,0x68,0x1c,0x80,0x37, 0x53,0xf9,0xba,0x0b,0xc8,0x02,0xbc,0xbc,0xf8,0xdc,0xbe,0xb6,0xa4,0xb0,0xb6,0xd2, 0xd7,0x6d,0x12,0x6f,0xcb,0xdd,0x18,0x9f,0x35,0x54,0x75,0x9d,0x70,0xf5,0xd4,0xc4, 0xef,0x8f,0xcf,0xb7,0x91,0x8b,0x73,0x89,0x67,0x32,0x3f,0x0c,0xe2,0xf6,0xde,0xba, 0x63,0xf0,0x29,0x2e,0xce,0x41,0xce,0x03,0x96,0x43,0xa0,0x06,0x38,0x74,0xca,0x27, 0x03,0x99,0xde,0x94,0x25,0x52,0x1d,0x8c,0x84,0x5d,0x98,0x66,0x53,0x77,0x20,0xb6, 0x67,0x4a,0xe4,0x35,0x8b,0xb2,0x38,0x21,0xf5,0xd8,0x28,0x2e,0x4d,0xf2,0x55,0x50, 0x8c,0x34,0xe5,0xb1,0x86,0x02,0x3d,0x0a,0x5f,0xd6,0x70,0xb2,0x4d,0x91,0x68,0xb4, 0xdb,0x4d,0xea,0x66,0xff,0x22,0x88,0xf5,0xfb,0xb0,0x23,0x48,0xa2,0x78,0x98,0x2e, 0xac,0x7d,0xdf,0x32,0x80,0x1d,0x3c,0xdf,0xf3,0xad,0x92,0x40,0x3e,0xfa,0xf4,0x19, 0x47,0xde,0x7f,0x47,0x01,0x07,0x3c,0xfc,0xb7,0x5f,0x44,0x5a,0xd7,0xdc,0x88,0x84, 0x5a,0x68,0xb6,0xda,0x85,0xf3,0xb9,0x78,0xa0,0x4b,0xb8,0xde,0x46,0xac,0xf7,0x8d, 0x8b,0x76,0xd4,0x8c,0x7e,0x10,0x88,0x35,0x6f,0xcc,0x8f,0x47,0xa8,0x18,0xcb,0x02, 0x80,0x81,0xdc,0x05,0x74,0x96,0x7d,0x14,0xe1,0x35,0xf2,0x27,0xe1,0xe9,0xb5,0x6c, 0x60,0x89,0xf8,0xde,0x9a,0x80,0x13,0x09,0x4c,0xa3,0x50,0xf5,0xbb,0x1b,0xf7,0x3b, 0x9d,0xd4,0x40,0x11,0x6a,0xbd,0x26,0x4b,0xf2,0x18,0x73,0xd3,0x02,0x28,0x40,0x62, 0xb1,0x38,0x40,0x4b,0xb9,0x53,0x55,0x05,0xf6,0xa5,0xfa,0xb1,0xc1,0xf2,0xec,0x5e, 0xc6,0x2c,0x6f,0x30,0xe9,0x95,0x7b,0xdb,0xae,0xee,0xaf,0xb0,0x16,0xef,0x12,0xc8, 0x27,0x52,0x13,0xe0,0xa5,0x68,0xe6,0x9c,0x0e,0xe0,0x4d,0xcf,0xd2,0x3a,0x2d,0x98, 0x66,0x9c,0xc8,0x50,0x32,0x44,0x2b,0xe0,0x32,0xda,0x90,0x49,0xc9,0xa2,0x11,0xf1, 0xf4,0x24,0xd1,0x99,0x8d,0xb7,0x35,0x9b,0x98,0x83,0x6a,0x6a,0xbd,0x97,0x03,0x23, 0x33,0xcb,0x73,0x65,0x0f,0x9f,0x45,0x42,0x79,0xd5,0x8b,0x43,0x77,0x9c,0x34,0x6b, 0xc0,0x05,0x05,0x4d,0xbd,0x3a,0xe8,0x55,0xbd,0x52,0xbf,0x7a,0xe9,0xc2,0x9e,0x1d, 0x8e,0x11,0x82,0x9d,0xb0,0xc8,0xdf,0x2a,0x9d,0x6a,0x6d,0x15,0x06,0xa1,0x80,0xc7, 0xa6,0x85,0x14,0x63,0xc0,0xfd,0xb8,0x7d,0x4f,0x78,0xf8,0x39,0x3a,0x96,0x56,0xc8, 0xa7,0xd8,0x66,0x58,0xa0,0x45,0x82,0x3e,0xb0,0xef,0x53,0xb6,0x90,0xd3,0x7d,0x36, 0x59,0x92,0x9a,0x19,0x8f,0x52,0x96,0xde,0xca,0x8e,0x17,0x05,0x24,0x6d,0xcd,0xcc, 0x46,0x33,0x24,0xe6,0x79,0xa6,0x24,0x29,0x95,0x77,0xdf,0x25,0x4b,0x5d,0x5b,0xa4, 0xef,0xf5,0xbd,0x7e,0x48,0x53,0x5c,0x12,0xe2,0x74,0x17,0x06,0xe1,0xe5,0xd2,0x27, 0x18,0xf6,0x0e,0x91,0x9c,0x32,0xba,0x31,0xaa,0x9a,0x56,0xf5,0xf7,0xb2,0x99,0xe6, 0xa7,0x56,0x64,0xef,0xa9,0xc0,0x02,0x8b,0x34,0x19,0x92,0x16,0xfe,0x64,0x3d,0x17, 0x5b,0x4b,0xa8,0xf7,0x7e,0x63,0x29,0x28,0xfd,0x7f,0x1d,0xf4,0x31,0xb6,0xda,0xd9, 0x0c,0x3e,0xc8,0xb5,0xfe,0xca,0x41,0x33,0xe4,0xd3,0x49,0xe2,0x37,0x86,0xf9,0x92, 0xd2,0xa2,0x8a,0x50,0x05,0xb3,0x78,0x02,0x32,0x95,0xf6,0x64,0x4b,0xd0,0x3d,0x57, 0x0e,0x05,0x0c,0x0c,0xd0,0x4d,0x3f,0xb4,0x20,0x88,0x96,0x58,0x0f,0x90,0xea,0xe1, 0x32,0x74,0x31,0x37,0x27,0xa9,0x39,0x5a,0x3e,0x2f,0xbe,0x89,0xff,0xfb,0xe0,0x0d, 0x00,0xec,0x19,0xd0,0x3a,0x59,0x84,0x5a,0xe1,0x1b,0xb2,0xf0,0xab,0x9d,0xd1,0xdd, 0x11,0x02,0x14,0x39,0xab,0x4d,0x93,0xe9,0x7c,0x51,0x72,0x7b,0x4c,0x52,0x88,0x4c, 0x3f,0xa1,0x1d,0x79,0xfa,0xa1,0xd3,0xdc,0xbc,0x86,0xcc,0x67,0x23,0x9e,0x44,0x34, 0xa0,0x58,0x6d,0x4c,0xa5,0x00,0x35,0x21,0x51,0xa8,0x9c,0x9d,0xfa,0x24,0xea,0x39, 0xc6,0x07,0xb2,0xc0,0xa8,0x86,0x9c,0x65,0x0c,0x69,0xcc,0x2f,0x07,0x11,0x63,0xa7, 0x69,0xd1,0xf3,0x0f,0xd1,0x29,0x30,0x23,0xd1,0xcd,0xc0,0xcb,0xf1,0xaa,0x05,0xb7, 0xb1,0xb7,0x78,0x5a,0x3d,0x14,0xbf,0x49,0x7d,0x8b,0x78,0x84,0x9c,0xdc,0x2c,0x06, 0xad,0x1f,0x15,0x7e,0x48,0x45,0xa1,0x19,0x12,0x62,0xe5,0x04,0x0c,0xea,0xbb,0xbe, 0xa1,0x33,0x18,0xdf,0x48,0xd7,0x28,0xc5,0x62,0xa1,0x4a,0xff,0x7d,0x76,0x05,0x2a, 0x95,0x1a,0xa8,0xde,0x5f,0x4a,0xf7,0x72,0xac,0xdc,0x76,0xb8,0xc6,0x31,0x76,0x68, 0x65,0x8e,0x47,0xad,0x65,0x6f,0x72,0xc8,0x10,0xbc,0xc7,0x8d,0x32,0xcc,0xb7,0xc8, 0xe6,0x60,0xa6,0x45,0xaa,0x9d,0xb7,0x56,0x7a,0x2d,0x0e,0x40,0x5f,0x85,0xa8,0xc4, 0x13,0xef,0x71,0x79,0x5f,0xe3,0x41,0x6f,0xa0,0x08,0xfd,0xd2,0xd4,0xb4,0x9a,0xba, 0x14,0x40,0xff,0xbe,0xde,0xb7,0x14,0x58,0xe4,0x23,0x98,0x43,0xa8,0x41,0x07,0xbb, 0x30,0x78,0x34,0x8f,0x5c,0x75,0xff,0xfc,0x7d,0xfc,0xce,0x51,0xb0,0x69,0x0b,0xc5, 0xa9,0x0b,0x83,0x87,0xc2,0x98,0xdf,0xa6,0xbb,0x78,0xea,0x63,0xb9,0xf1,0x1e,0xe9, 0x6a,0x53,0x79,0xc6,0xc8,0x78,0xc2,0x46,0x74,0x90,0x97,0x24,0xf9,0xa3,0xe9,0xa3, 0xae,0x6d,0x2a,0x70,0x05,0x0a,0x16,0xc0,0x82,0x00,0x23,0x3b,0xf2,0x41,0x24,0x5c, 0x94,0x9d,0x22,0x5d,0x15,0xe4,0xa3,0x89,0x74,0x3a,0xae,0x6e,0xdd,0x97,0x11,0x8b, 0x04,0x3b,0xfb,0x09,0x45,0x12,0xc9,0xc7,0x12,0xec,0x02,0x04,0x2e,0x27,0x60,0xc2, 0xc4,0x82,0x1f,0xda,0x66,0xc2,0x63,0xdb,0xfd,0x11,0x49,0xda,0xa9,0x5a,0x66,0xad, 0x95,0x61,0xb7,0xdb,0x73,0x80,0xa2,0x86,0x6d,0xa5,0x8a,0x9b,0xcc,0xeb,0x5d,0x90, 0x6d,0x7d,0x6a,0xd4,0x3f,0xce,0xaf,0x3c,0xdf,0xf8,0x17,0x88,0x52,0x7d,0x36,0xe7, 0xde,0xed,0xc2,0x52,0x6d,0x65,0xd8,0xda,0x0a,0x62,0x75,0xd6,0x4d,0xd3,0x66,0xbb, 0x50,0xd1,0x8f,0x8f,0x9f,0x3e,0xcc,0x7e,0x36,0xe3,0x07,0x88,0x60,0x3d,0x6f,0x3e, 0x2a,0x32,0x90,0x97,0x97,0x68,0x72,0xa1,0xcb,0xe7,0x77,0x18,0xba,0xdd,0xd3,0x0a, 0xae,0x62,0x9a,0x4d,0xa0,0x66,0xcc,0xd6,0x49,0xd3,0x5e,0xa9,0x10,0xce,0xe7,0x3a, 0x00,0x78,0xd1,0x97,0xe0,0x43,0x38,0xab,0x2b,0xaf,0xc4,0xe5,0x8c,0x97,0xf0,0x3b, 0xfa,0x8a,0x88,0x9a,0xf0,0x54,0x71,0x39,0x27,0xcf,0xe2,0x37,0x9d,0xc9,0x71,0x9d, 0x41,0x43,0x34,0x22,0x86,0x6c,0xcd,0xb1,0x1b,0x91,0x97,0xa8,0x29,0x87,0xe3,0x23, 0x11,0x6b,0xbd,0x01,0xc0,0x2e,0x3a,0xe7,0xfe,0x1c,0x1f,0x9b,0xe5,0x90,0x39,0x27, 0xd3,0x6d,0x49,0x5a,0xda,0x16,0x0b,0xf5,0xa8,0xa2,0x9d,0xd1,0x29,0x80,0xf4,0x3a, 0xec,0xb1,0x3b,0xac,0xe0,0x75,0x93,0xde,0x91,0xb2,0x79,0x77,0x43,0xb2,0x9e,0x16, 0x20,0xe7,0x70,0xfa,0xfd,0x7c,0xef,0xa5,0x1e,0x8d,0x76,0x48,0x0d,0x6a,0x82,0xf9, 0x1c,0xbe,0xa5,0xfc,0x33,0x39,0xda,0xc5,0xeb,0x53,0x3c,0x2e,0x06,0xda,0x45,0x26, 0xc1,0xb5,0x20,0xbe,0x31,0x0f,0x64,0x50,0x9c,0xda,0x98,0xaa,0x45,0x1a,0xa3,0x61, 0xd8,0x49,0x5d,0x0c,0x82,0x37,0xd1,0x6d,0x8a,0x0d,0x9c,0x90,0xe7,0xe1,0xb6,0xa8, 0x96,0xd6,0x66,0xc8,0xe6,0xca,0x18,0x82,0xa5,0xb0,0x2c,0xea,0xca,0xd0,0x4b,0xa3, 0x19,0xa8,0xaf,0x9b,0xdf,0x80,0x08,0x69,0x8d,0xa4,0xfa,0x74,0x85,0xb0,0x1c,0x1c, 0x87,0x82,0xe4,0x6d,0x4d,0xfc,0xef,0xf2,0xac,0x1c,0xdc,0x76,0xec,0x27,0x19,0x05, 0xcf,0xc8,0xa0,0xae,0x48,0xa8,0x17,0xd5,0x4d,0x11,0x49,0xd2,0xc2,0x65,0xee,0x49, 0xe8,0xd2,0xb6,0x35,0xce,0xa5,0x27,0x7a,0xc1,0x03,0xf1,0xad,0x2a,0x0a,0xb2,0xf9, 0xd3,0x52,0xa7,0x1b,0xfb,0xbe,0xf1,0x48,0xd0,0x3a,0x1a,0x92,0xa0,0x09,0xdb,0x88, 0xdb,0x91,0xbd,0xaa,0x36,0xe4,0x24,0xf8,0xe7,0x15,0xa5,0x11,0x20,0x58,0x0a,0xf3, 0xaa,0xb1,0x0e,0xa5,0x6f,0xff,0xed,0x3f,0x3a,0x08,0xd1,0xda,0x11,0xac,0x62,0xec, 0x3d,0x1f,0x96,0x74,0x03,0xbb,0x6c,0xea,0xd0,0x11,0xfb,0xf0,0x69,0x05,0xe3,0x14, 0xb6,0xf2,0xb9,0x25,0xf1,0xa7,0x65,0x2b,0xaf,0x36,0x05,0xc0,0xe3,0x67,0xac,0x20, 0x86,0x43,0x94,0x89,0xfe,0x00,0x73,0xce,0x12,0x6e,0xbf,0x7b,0x73,0xa2,0x8f,0x29, 0x94,0x49,0x4f,0x86,0xf0,0xb4,0xb1,0x9f,0xea,0xb7,0x5f,0xcd,0x1e,0x0b,0xee,0xa5, 0x4e,0x82,0x2e,0x4c,0x83,0xa2,0x1b,0x95,0x10,0xda,0x10,0x84,0x7c,0xa0,0xad,0x11, 0xe9,0xfc,0x97,0xd9,0xb0,0x48,0x78,0x9b,0xff,0xd7,0x68,0x1e,0xe2,0x56,0xc3,0x31, 0xd9,0xf1,0x7d,0x5c,0x93,0x98,0xf1,0xa4,0x72,0x01,0x28,0xef,0xa1,0xd5,0x00,0x8a, 0xd2,0x97,0x63,0x82,0xdf,0xdb,0x1d,0xdf,0xb2,0x86,0xfd,0x95,0xdc,0xc0,0xc6,0xb5, 0xb1,0x43,0x11,0x45,0xdc,0x02,0xe9,0x4e,0x04,0x11,0x3d,0xa5,0xe6,0x3d,0x30,0xb8, 0xd4,0x93,0x3b,0xb4,0x6f,0x58,0x93,0x21,0xde,0x90,0xb6,0xbb,0x50,0x7c,0x70,0x01, 0xc0,0x82,0x46,0x9c,0x84,0x2f,0xea,0x88,0x40,0x28,0x2e,0x27,0x65,0x5e,0xdf,0x3a, 0xf1,0x1a,0xee,0x60,0x73,0x81,0x82,0x51,0x11,0x38,0x0c,0x61,0xb5,0x7d,0x62,0x75, 0xff,0xa9,0x11,0x83,0xd8,0xfb,0x0c,0x19,0x23,0x3a,0x40,0x89,0x98,0x1f,0xc3,0x89, 0x3a,0xb1,0xea,0xad,0x32,0x6c,0xfe,0x43,0xa4,0x0b,0xa4,0x59,0x88,0x06,0xce,0x87, 0xaf,0xdf,0x0a,0x88,0xdb,0x16,0xa1,0xfe,0x50,0xe1,0x87,0xe8,0x00,0x4a,0x72,0x3a, 0xfb,0x5c,0xe7,0x2d,0xc8,0xe6,0x70,0x6c,0xf1,0x14,0xc6,0x79,0x1b,0x94,0x00,0xca, 0x74,0x0a,0x52,0x4f,0x21,0xf3,0x4d,0x71,0xd4,0xd5,0x5a,0xd5,0x1f,0xcc,0x0f,0x1b, 0x28,0xf7,0x48,0xf0,0xdd,0xb9,0x5c,0xce,0xcd,0x22,0x47,0xe8,0xb7,0x47,0xb3,0x2b, 0x51,0x05,0x7a,0x72,0xf9,0xc7,0xe4,0xcd,0x9c,0x3e,0xa2,0xbc,0x0a,0xb2,0xd7,0x32, 0xa9,0x1f,0x22,0x86,0xd8,0x7e,0x54,0xa6,0xa1,0x9b,0x8e,0x58,0xe2,0x41,0x83,0x33, 0x47,0xfd,0xa6,0x40,0xc4,0x8a,0x0d,0x61,0xc8,0xb0,0x1d,0xd2,0x62,0xf4,0x04,0x0b, 0x13,0x26,0x91,0xec,0xa4,0xe5,0x92,0x45,0x80,0x20,0x9d,0x62,0x62,0x20,0x95,0xa9 }; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/data.h��������������������������������������������������������������������0000664�0000000�0000000�00000001637�15114537466�0016532�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #ifndef __DATA_H__ #define __DATA_H__ extern unsigned char SECTOR_ERROR_DATA[2448]; #endif �������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/decodeSense.cc������������������������������������������������������������0000664�0000000�0000000�00000005220�15114537466�0020170�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998, 1999 Andreas Mueller <mueller@daneb.ping.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 * (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. */ /* * $Log: decodeSense.cc,v $ * Revision 1.2 2007/12/29 12:26:34 poolshark * Complete rewrite of native Linux SG driver for SG 3.0 using SG_IO ioctl. Code cleanup * * Revision 1.1.1.1 2000/02/05 01:38:06 llanero * Uploaded cdrdao 1.1.3 with pre10 patch applied. * * Revision 1.1 1999/03/14 15:34:03 mueller * Initial revision * */ /* Sense code printing for direct SCSI implementations */ struct StringTable { int code; const char *message; }; static StringTable SENSE_KEYS[] = { { 0x00, "NO SENSE" }, { 0x01, "RECOVERED ERROR" }, { 0x02, "NOT READY" }, { 0x03, "MEDIUM ERROR" }, { 0x04, "HARDWARE ERROR" }, { 0x05, "ILLEGAL REQUEST" }, { 0x06, "UNIT ATTENTION" }, { 0x08, "BLANK CHECK" }, { 0x09, "VENDOR SPECIFIC" }, { 0x0b, "ABORTED COMMAND" }, { 0x0d, "VOLUME OVERFLOW" }, { 0x0e, "MISCOMPARE" }, { 0x00, (char *)0 } }; static const char *getFromStringTable(const StringTable *t, int code) { while (t->message != NULL) { if (t->code == code) { return t->message; } t += 1; } return NULL; } // Prints decoded sense message, if 'ignoreUnitAttention' is != 0 and sense // code indicates unit attention nothing will be printed and 0 will be // returned. // return: 0: OK, no error // 1: sense key indicates error static int decodeSense(const unsigned char *buf, int len) { int code = buf[2] & 0x0f; const char *msg; if (code == 0) { return 0; } msg = getFromStringTable(SENSE_KEYS, code); log_message(-2, "SCSI command failed:"); log_message(-2, " sense key 0x%x: %s.", code, msg != NULL ? msg : "unknown code"); if (len > 0x0c && buf[7] != 0) { log_message(-2, " additional sense code: 0x%x", buf[0x0c]); } if (len > 0x0d && buf[7] != 0) { log_message(-2, " additional sense code qualifier: 0x%x", buf[0x0d]); } return 1; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/main.cc�������������������������������������������������������������������0000664�0000000�0000000�00000243647�15114537466�0016714�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #include <config.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/utsname.h> #include <pwd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <iostream> #include <fstream> #include <stdarg.h> #include <signal.h> #include <ctype.h> #include <list> #include <string> #include <vector> #include <assert.h> #include <sstream> #include <algorithm> #include <memory> #include "log.h" #include "util.h" #include "Toc.h" #include "ScsiIf.h" #include "CdrDriver.h" #include "dao.h" #include "port.h" #include "Settings.h" #include "Cddb.h" #include "TempFileManager.h" #include "FormatConverter.h" #ifdef __CYGWIN__ #define NOMINMAX #include <windows.h> #include <winioctl.h> #define IOCTL_SCSI_BASE FILE_DEVICE_CONTROLLER #define IOCTL_SCSI_GET_CAPABILITIES CTL_CODE(IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define IOCTL_SCSI_GET_ADDRESS CTL_CODE(IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS) #endif using namespace std; namespace { #ifdef UNIXWARE extern "C" { extern int seteuid(uid_t); extern int setegid(uid_t); }; #endif PrintParams errPrintParams, filePrintParams; typedef enum { UNKNOWN = -1, SHOW_TOC, SHOW_DATA, READ_TEST, SIMULATE, WRITE, READ_TOC, DISK_INFO, READ_CD, TOC_INFO, TOC_SIZE, BLANK, SCAN_BUS, UNLOCK, COPY_CD, READ_CDDB, MSINFO, DRIVE_INFO, DISCID, SHOW_VERSION, CDTEXT, LAST_CMD, } DaoCommand; typedef enum { NO_DEVICE, NEED_CDR_R, NEED_CDR_W, NEED_CDRW_W, } DaoDeviceType; // The cmdInfo[] array provides information about each of cdrdao's // main commands, including some of the basic processing steps // required, almost as a simplified state machine. struct { // The command code, which is also the index into the array DaoCommand cmd; // The command-line string for this command const char* str; // What type of device does the command require, for device // auto-detection. DaoDeviceType requiredDevice; // Does the command require a toc file bool needTocFile; // Does the command require to parse an existing toc file bool tocParse; // Does the command require to check the parsed toc file bool tocCheck; } cmdInfo[LAST_CMD] = { { SHOW_TOC, "show-toc", NO_DEVICE, 1, 1, 0 }, { SHOW_DATA, "show-data", NO_DEVICE, 1, 1, 1 }, { READ_TEST, "read-test", NO_DEVICE, 1, 1, 1 }, { SIMULATE, "simulate", NEED_CDR_W, 1, 1, 1 }, { WRITE, "write", NEED_CDR_W, 1, 1, 1 }, { READ_TOC, "read-toc", NEED_CDR_R, 1, 0, 1 }, { DISK_INFO, "disk-info", NEED_CDR_R, 0, 0, 1 }, { READ_CD, "read-cd", NEED_CDR_R, 1, 0, 1 }, { TOC_INFO, "toc-info", NO_DEVICE, 1, 1, 1 }, { TOC_SIZE, "toc-size", NO_DEVICE, 1, 1, 1 }, { BLANK, "blank", NEED_CDRW_W, 0, 0, 1 }, { SCAN_BUS, "scanbus", NO_DEVICE, 0, 0, 1 }, { UNLOCK, "unlock", NEED_CDR_R, 0, 0, 1 }, { COPY_CD, "copy", NEED_CDR_W, 0, 0, 1 }, { READ_CDDB, "read-cddb", NO_DEVICE, 1, 1, 0 }, { MSINFO, "msinfo", NEED_CDR_R, 0, 0, 1 }, { DRIVE_INFO, "drive-info", NEED_CDR_R, 0, 0, 1 }, { DISCID, "discid", NEED_CDR_R, 0, 0, 1 }, { SHOW_VERSION, "version", NO_DEVICE, 0, 0, 0 }, { CDTEXT, "cdtext", NEED_CDR_R, 0, 0, 0 }, }; struct DaoCommandLine { DaoCommand command; const char* progName; string tocFile; string driverId; string sourceDriverId; string scsiDevice; const char* sourceScsiDevice; const char* dataFilename; string cddbLocalDbDir; string tmpFileDir; vector<string> cddbServerList; int readingSpeed; int writingSpeed; bool eject; bool swap; bool multiSession; int verbose; int session; int fifoBuffers; bool fastToc; bool pause; bool readRaw; bool mode2Mixed; bool remoteMode; int remoteFd; bool reload; bool force; int paranoiaMode; bool onTheFly; bool writeSimulate; bool saveSettings; int userCapacity; bool fullBurn; int cddbTimeout; bool withCddb; bool taoSource; int taoSourceAdjust; bool keepImage; bool overburn; int bufferUnderrunProtection; bool writeSpeedControl; bool keep; bool printQuery; bool no_utf8; CdrDriver::BlankingMode blankingMode; TrackData::SubChannelMode readSubchanMode; DaoCommandLine(); void printUsage(); void importSettings(Settings* settings); void exportSettings(Settings* settings); void commitSettings(Settings* settings, const char* settingsPath); int parseCmdLine(int argc, char** argv, Settings* settings); }; DaoCommandLine::DaoCommandLine() : eject(false), swap(false), multiSession(false), fastToc(false), pause(false), readRaw(false), mode2Mixed(false), remoteMode(false), reload(false), force(false), onTheFly(false), writeSimulate(false), saveSettings(false), fullBurn(false), withCddb(false), taoSource(false), keepImage(false), overburn(false), writeSpeedControl(false), keep(false), printQuery(false), no_utf8(false) { dataFilename = NULL; sourceScsiDevice = NULL; readingSpeed = -1; writingSpeed = -1; command = UNKNOWN; verbose = 2; session = 1; pause = true; mode2Mixed = true; remoteFd = -1; paranoiaMode = 3; cddbTimeout = 60; userCapacity = 0; taoSourceAdjust = -1; bufferUnderrunProtection = 1; writeSpeedControl = true; scsiDevice.clear(); #if defined(__FreeBSD__) fifoBuffers = 20; #else fifoBuffers = 32; #endif cddbServerList = { "gnudb.gnudb.org", "http://gnudb.gnudb.org:80/~cddb/cddb.cgi" }; blankingMode = CdrDriver::BLANK_MINIMAL; readSubchanMode = TrackData::SUBCHAN_NONE; } bool isNT = false; #ifdef __CYGWIN__ /*! \brief OS handle to the device As obtained from CreateFile, used to apply OS level locking. */ HANDLE fh = NULL; /*! \brief Device string Like "\\\\.\\E:", used in CreateFile to obtain handle to device. */ char devstr[10]; #endif void printVersion() { log_message(2, "Cdrdao version %s - (C) Andreas Mueller <andreas@daneb.de>", VERSION); list<string> elist; int num = formatConverter.supportedExtensions(elist); if (num) { string msg = "Format converter enabled for extensions:"; for (const auto& i : elist) { msg += " "; msg += i; } log_message(3, msg.c_str()); } } void DaoCommandLine::printUsage() { switch (command) { case UNKNOWN: log_message(0, "\nUsage: %s <command> [options] [toc-file]", progName); log_message(0, "command:\n" " show-toc - prints out toc and exits\n" " toc-info - prints out short toc-file summary\n" " toc-size - prints total number of blocks for toc\n" " read-toc - create toc file from audio CD\n" " read-cd - create toc and rip audio data from CD\n" " read-cddb - contact CDDB server and add data as CD-TEXT to toc-file\n" " show-data - prints out audio data and exits\n" " read-test - reads all audio files and exits\n" " disk-info - shows information about inserted medium\n" " discid - prints out CDDB information\n" " msinfo - shows multi session info, output is suited for scripts\n" " drive-info - shows drive information\n" " cdtext - shows CD CD-TEXT content\n" " unlock - unlock drive after failed writing\n" " blank - blank a CD-RW\n" " scanbus - scan for devices\n" " simulate - shortcut for 'write --simulate'\n" " write - writes CD\n" " copy - copies CD\n"); log_message(0, "\n Try '%s <command> -h' to get a list of available " "options\n", progName); break; case SHOW_TOC: log_message(0, "\nUsage: %s show-toc [options] toc-file", progName); log_message(0, "options:\n" " -v # - sets verbose level\n" " --no-utf8 - don't show CD-TEXT as UTF-8\n"); break; case SHOW_DATA: log_message(0, "\nUsage: %s show-data [--swap] [-v #] toc-file\n", progName); break; case READ_TEST: log_message(0, "\nUsage: %s read-test [-v #] toc-file\n", progName); break; case CDTEXT: log_message(0, "\nUsage: %s cdtext [options]\n", progName); log_message(0, "options:\n" " -v # - sets verbose level\n" " --no-utf8 - don't show CD-TEXT as UTF-8\n" " --device [proto:]{<x,y,z>|device} - sets SCSI device of CD-ROM reader\n" " --driver <id> - force usage of specified driver for source device\n"); break; case SIMULATE: log_message(0, "\nUsage: %s simulate [options] toc-file", progName); log_message(0, "options:\n" " --device [proto:]{<x,y,z>|device} - sets SCSI device of CD-writer\n" " --driver <id> - force usage of specified driver\n" " --speed <writing-speed> - selects writing speed\n" " --multi - session will not be closed\n" " --overburn - allow one to overburn a medium\n" " --full-burn - force burning to the outer disk edge\n" " with '--driver generic-mmc-raw'\n" " --capacity <minutes> - sets disk capacity for '--full-burn'\n" " you must specify this when using blanks bigger\n" " than 80 min. (90,99,etc.)\n" " because they seems like 80 min. blanks\n" " --eject - ejects cd after simulation\n" " --swap - swap byte order of audio files\n" " --buffers # - sets fifo buffer size (min. 10)\n" " --reload - reload the disk if necessary for writing\n" " --force - force execution of operation\n" " --tmpdir <path> - sets directory for temporary wav files\n" " --keep - keep generated temp wav files after exit\n" " -v # - sets verbose level\n" " -n - no pause before writing\n"); break; case WRITE: log_message(0, "\nUsage: %s write [options] toc-file", progName); log_message(0, "options:\n" " --device [proto:]{<x,y,z>|device} - sets SCSI device of CD-writer\n" " --driver <id> - force usage of specified driver\n" " --simulate - just perform a write simulation\n" " --speed <writing-speed> - selects writing speed\n" " --multi - session will not be closed\n" " --buffer-under-run-protection #\n" " - 0: disable buffer under run protection\n" " 1: enable buffer under run protection (default)\n" " --write-speed-control # - 0: disable writing speed control by the drive\n" " 1: enable writing speed control (default)\n" " --overburn - allow one to overburn a medium\n" " --full-burn - force burning to the outer disk edge\n" " with '--driver generic-mmc-raw'\n" " --capacity <minutes> - sets disk capacity for '--full-burn'\n" " you must specify this when using blanks bigger\n" " than 80 min. (90,99,etc.)\n" " because they seems like 80 min. blanks\n" " --eject - ejects cd after writing or simulation\n" " --swap - swap byte order of audio files\n" " --buffers # - sets fifo buffer size (min. 10)\n" " --reload - reload the disk if necessary for writing\n" " --force - force execution of operation\n" " --tmpdir <path> - sets directory for temporary wav files\n" " --keep - keep generated temp wav files after exit\n" " -v # - sets verbose level\n" " -n - no pause before writing\n"); break; case READ_TOC: log_message(0, "\nUsage: %s read-toc [options] toc-file", progName); log_message(0, "options:\n" " --device [proto:]{<x,y,z>|device} - sets SCSI device of CD-ROM reader\n" " --driver <id> - force usage of specified driver for source device\n" " --datafile <filename> - name of data file placed in toc-file\n" " --session # - select session\n" " --fast-toc - do not extract pre-gaps and index marks\n" " --read-raw - select raw sectors modes for data tracks\n" " --no-mode2-mixed - don't switch to mode2_mixed\n" " --rspeed <read-speed> - selects reading speed\n" " --read-subchan <mode> - defines sub-channel reading mode\n" " <mode> = rw | rw_raw\n" " --tao-source - indicate that source CD was written in TAO mode\n" " --tao-source-adjust # - # of link blocks for TAO source CDs (def. 2)\n" " --with-cddb - retrieve CDDB CD-TEXT data while copying\n" " --cddb-servers <list> - sets space separated list of CDDB servers\n" " --cddb-timeout # - timeout in seconds for CDDB server communication\n" " --cddb-directory <path> - path to local CDDB directory where fetched\n" " CDDB records will be stored\n" " --force - force execution of operation\n" " --no-utf8 - don't show CD-TEXT as UTF-8\n" " -v # - sets verbose level\n"); break; case DISK_INFO: log_message(0, "\nUsage: %s disk-info [options]", progName); log_message(0, "options:\n" " --device [proto:]{<x,y,z>|device} - sets SCSI device of CD-writer\n" " --driver <id> - force usage of specified driver\n" " -v # - sets verbose level\n"); break; case DISCID: log_message(0, "\nUsage: %s discid [options]", progName); log_message(0, "options:\n" " --device [proto:]{<x,y,z>|device} - sets SCSI device of CD-writer\n" " --driver <id> - force usage of specified driver\n" " --cddb-servers <list> - sets space separated list of CDDB servers\n" " --cddb-timeout # - timeout in seconds for CDDB server communication\n" " --cddb-directory <path> - path to local CDDB directory where fetched\n" " CDDB records will be stored\n" " --query-string - prints out CDDB query only\n" " -v # - sets verbose level\n"); break; case READ_CD: log_message(0, "\nUsage: %s read-cd [options] toc-file", progName); log_message(0, "options:\n" " --datafile <filename> - name of data file placed in toc-file\n" " --session # - select session\n" " --fast-toc - do not extract pre-gaps and index marks\n" " --read-raw - read raw data sectors (including L-EC data)\n" " --no-mode2-mixed - don't switch to mode2_mixed\n" " --rspeed <read-speed> - selects reading speed\n" " --read-subchan <mode> - defines sub-channel reading mode\n" " <mode> = rw | rw_raw\n" " --tao-source - indicate that source CD was written in TAO mode\n" " --tao-source-adjust # - # of link blocks for TAO source CDs (def. 2)\n" " --paranoia-mode # - DAE paranoia mode (0..3)\n" " --with-cddb - retrieve CDDB CD-TEXT data while copying\n" " --cddb-servers <list> - sets space separated list of CDDB servers\n" " --cddb-timeout # - timeout in seconds for CDDB server communication\n" " --cddb-directory <path> - path to local CDDB directory where fetched\n" " CDDB records will be stored\n" " --no-utf8 - don't show CD-TEXT as UTF-8\n" " --force - force execution of operation\n" " -v # - sets verbose level\n"); break; case TOC_INFO: log_message(0, "\nUsage: %s toc-info [options] toc-file", progName); log_message(0, "options:\n" " -v # - sets verbose level\n"); break; case TOC_SIZE: log_message(0, "\nUsage: %s toc-size [options] toc-file", progName); log_message(0, "options:\n" " -v # - sets verbose level\n"); break; case BLANK: log_message(0, "\nUsage: %s blank [options]", progName); log_message(0, "options:\n" " --device [proto:]{<x,y,z>|device} - sets SCSI device of CD-writer\n" " --driver <id> - force usage of specified driver\n" " --speed <writing-speed> - selects writing speed\n" " --blank-mode <mode> - blank mode ('full', 'minimal')\n" " --eject - ejects cd after writing or simulation\n" " -v # - sets verbose level\n"); break; case SCAN_BUS: log_message(0, "\nUsage: %s scan-bus [-v #]\n", progName); break; case UNLOCK: log_message(0, "\nUsage: %s unlock [options]", progName); log_message(0, "options:\n" " --device [proto:]{<x,y,z>|device} - sets SCSI device of CD-writer\n" " --driver <id> - force usage of specified driver\n" " --reload - reload the disk if necessary for writing\n" " --eject - ejects cd after unlocking\n" " -v # - sets verbose level\n"); break; case DRIVE_INFO: log_message(0, "\nUsage: %s drive-info [options]", progName); log_message(0, "options:\n" " --device [proto:]{<x,y,z>|device} - sets SCSI device of CD-writer\n" " --driver <id> - force usage of specified driver\n" " -v # - sets verbose level\n"); break; case COPY_CD: log_message(0, "\nUsage: %s copy [options]", progName); log_message(0, "options:\n" " --device [proto:]{<x,y,z>|device} - sets SCSI device of CD-writer\n" " --source-device {<x,y,z>|device} - sets SCSI device of CD-ROM reader\n" " --driver <id> - force usage of specified driver\n" " --source-driver <id> - force usage of specified driver for source device\n" " --simulate - just perform a copy simulation\n" " --speed <writing-speed> - selects writing speed\n" " --rspeed <read-speed> - selects reading speed\n" " --multi - session will not be closed\n" " --buffer-under-run-protection #\n" " - 0: disable buffer under run protection\n" " 1: enable buffer under run protection (default)\n" " --write-speed-control # - 0: disable writing speed control by the drive\n" " 1: enable writing speed control (default)\n" " --overburn - allow one to overburn a medium\n" " --full-burn - force burning to the outer disk edge\n" " with '--driver generic-mmc-raw'\n" " --capacity <minutes> - sets disk capacity for '--full-burn'\n" " you must specify this when using blanks bigger\n" " than 80 min. (90,99,etc.)\n" " because they seems like 80 min. blanks\n" " --eject - ejects cd after writing or simulation\n" " --swap - swap byte order of audio files\n" " --on-the-fly - perform on-the-fly copy, no image file is created\n" " --datafile <filename> - name of temporary data file\n" " --buffers # - sets fifo buffer size (min. 10)\n" " --session # - select session\n" " --fast-toc - do not extract pre-gaps and index marks\n" " --read-subchan <mode> - defines sub-channel reading mode\n" " <mode> = rw | rw_raw\n" " --keepimage - the image will not be deleted after copy\n" " --tao-source - indicate that source CD was written in TAO mode\n" " --tao-source-adjust # - # of link blocks for TAO source CDs (def. 2)\n" " --paranoia-mode # - DAE paranoia mode (0..3)\n" " --reload - reload the disk if necessary for writing\n" " --force - force execution of operation\n" " --with-cddb - retrieve CDDB CD-TEXT data while copying\n" " --cddb-servers <list> - sets space separated list of CDDB servers\n" " --cddb-timeout # - timeout in seconds for CDDB server communication\n" " --cddb-directory <path> - path to local CDDB directory where fetched\n" " CDDB records will be stored\n" " -v # - sets verbose level\n" " -n - no pause before writing\n"); break; case READ_CDDB: log_message(0, "\nUsage: %s read-cddb [options] toc-file", progName); log_message(0, "options:\n" " --cddb-servers <list> - sets space separated list of CDDB servers\n" " --cddb-timeout # - timeout in seconds for CDDB server communication\n" " --cddb-directory <path> - path to local CDDB directory where fetched\n" " CDDB records will be stored\n" " -v # - sets verbose level\n"); break; case MSINFO: log_message(0, "\nUsage: %s msinfo [options]", progName); log_message(0, "options:\n" " --device [proto:]{<x,y,z>|device} - sets SCSI device of CD-writer\n" " --driver <id> - force usage of specified driver\n" " --reload - reload the disk if necessary for writing\n" " --no-utf8 - don't show CD-TEXT as UTF-8\n" " -v # - sets verbose level\n"); break; default: log_message(0, "Sorry, no help available for command %d :-(\n", command); break; } } void DaoCommandLine::importSettings(Settings* settings) { const char *sval; const int *ival; DaoCommand cmd = command; if (cmd == SIMULATE || cmd == WRITE || cmd == COPY_CD) { if ((sval = settings->getString(Settings::setWriteDriver)) != NULL) { driverId = sval; } if ((sval = settings->getString(Settings::setWriteDevice)) != NULL) { scsiDevice = sval; } if ((ival = settings->getInteger(Settings::setWriteSpeed)) != NULL && *ival >= 0) { writingSpeed = *ival; } if ((ival = settings->getInteger(Settings::setWriteBuffers)) != NULL && *ival >= 10) { fifoBuffers = *ival; } if ((ival = settings->getInteger(Settings::setUserCapacity)) != NULL && *ival >= 0) { userCapacity = *ival; } if ((ival = settings->getInteger(Settings::setFullBurn)) != NULL && *ival >= 0) { fullBurn = *ival; } } if (cmd == READ_CD || cmd == READ_TOC) { if ((sval = settings->getString(Settings::setReadDriver)) != NULL) { driverId = sval; } if ((sval = settings->getString(Settings::setReadDevice)) != NULL) { scsiDevice = sval; } if ((ival = settings->getInteger(Settings::setReadParanoiaMode)) != NULL && *ival >= 0) { paranoiaMode = *ival; } } if (cmd == COPY_CD) { if ((sval = settings->getString(Settings::setReadDriver)) != NULL) { sourceDriverId = sval; } if ((sval = settings->getString(Settings::setReadDevice)) != NULL) { sourceScsiDevice = strdupCC(sval); } if ((ival = settings->getInteger(Settings::setReadParanoiaMode)) != NULL && *ival >= 0) { paranoiaMode = *ival; } } if (cmd == BLANK || cmd == DISK_INFO || cmd == MSINFO || cmd == UNLOCK || cmd == DISCID || cmd == DRIVE_INFO) { if ((sval = settings->getString(Settings::setWriteDriver)) != NULL) { driverId = sval; } if ((sval = settings->getString(Settings::setWriteDevice)) != NULL) { scsiDevice = sval; } } if (cmd == READ_CDDB || cmd == COPY_CD || cmd == READ_TOC || cmd == READ_CD || cmd == DISCID) { vector<string> sl; settings->getStrings(Settings::setCddbServerList, sl); if (sl.size()) cddbServerList = sl; if ((sval = settings->getString(Settings::setCddbDbDir)) != NULL) { cddbLocalDbDir = sval; } if ((ival = settings->getInteger(Settings::setCddbTimeout)) != NULL && *ival > 0) { cddbTimeout = *ival; } if ((sval = settings->getString(Settings::setTmpFileDir)) != NULL) { tmpFileDir = sval; } } if ((ival = settings->getInteger(Settings::setReadSpeed)) != NULL && *ival >= 0) { readingSpeed = *ival; } } void DaoCommandLine::exportSettings(Settings* settings) { DaoCommand cmd = command; if (cmd == SIMULATE || cmd == WRITE || cmd == COPY_CD) { if (!driverId.empty()) settings->set(Settings::setWriteDriver, driverId.c_str()); if (!scsiDevice.empty()) settings->set(Settings::setWriteDevice, scsiDevice.c_str()); if (writingSpeed >= 0) { settings->set(Settings::setWriteSpeed, writingSpeed); } if (fifoBuffers > 0) { settings->set(Settings::setWriteBuffers, fifoBuffers); } if (fullBurn > 0) { settings->set(Settings::setFullBurn, fullBurn); } if (userCapacity > 0) { settings->set(Settings::setUserCapacity, userCapacity); } } if (cmd == READ_CD) { if (!driverId.empty()) settings->set(Settings::setReadDriver, driverId.c_str()); if (!scsiDevice.empty()) settings->set(Settings::setReadDevice, scsiDevice.c_str()); settings->set(Settings::setReadParanoiaMode, paranoiaMode); } if (cmd == COPY_CD) { if (!sourceDriverId.empty()) settings->set(Settings::setReadDriver, sourceDriverId.c_str()); if (sourceScsiDevice != NULL) settings->set(Settings::setReadDevice, sourceScsiDevice); settings->set(Settings::setReadParanoiaMode, paranoiaMode); } if (cmd == BLANK || cmd == DISK_INFO || cmd == MSINFO || cmd == UNLOCK || cmd == DISCID || cmd == DRIVE_INFO) { if (!driverId.empty()) settings->set(Settings::setWriteDriver, driverId.c_str()); if (!scsiDevice.empty()) settings->set(Settings::setWriteDevice, scsiDevice.c_str()); } if (cmd == READ_CDDB || (withCddb && (cmd == COPY_CD || cmd == READ_TOC || cmd == READ_CD || cmd == DISCID))) { if (cddbServerList.size()) { settings->set(Settings::setCddbServerList, cddbServerList); } if (!cddbLocalDbDir.empty()) { settings->set(Settings::setCddbDbDir, cddbLocalDbDir.c_str()); } if (cddbTimeout > 0) { settings->set(Settings::setCddbTimeout, cddbTimeout); } } if (readingSpeed >= 0) { settings->set(Settings::setReadSpeed, readingSpeed); } if (cmd == SHOW_TOC || cmd == SIMULATE || cmd == WRITE || cmd == TOC_INFO || cmd == TOC_SIZE) { if (tmpFileDir.size()) settings->set(Settings::setTmpFileDir, tmpFileDir.c_str()); } } int DaoCommandLine::parseCmdLine(int argc, char **argv, Settings* settings) { int i; bool clear_default_servers = true; if (argc < 1) { return 1; } for (i = 0; i < LAST_CMD; i++) { if (strcmp(*argv, cmdInfo[i].str) == 0) { command = cmdInfo[i].cmd; break; } } if (command == UNKNOWN) { log_message(-2, "Illegal command: %s", *argv); return 1; } // retrieve settings from $HOME/.cdrdao for given command importSettings(settings); argc--, argv++; while (argc > 0 && (*argv)[0] == '-') { if ((*argv)[1] != '-') { switch ((*argv)[1]) { case 'h': return 1; case 'v': if ((*argv)[2] != 0) { verbose = atoi((*argv) + 2); } else { if (argc < 2) { log_message(-2, "Missing argument after: %s", *argv); return 1; } else { verbose = atoi(argv[1]); argc--, argv++; } } break; case 'n': pause = false; break; default: log_message(-2, "Illegal option: %s", *argv); return 1; break; } } else { if (strcmp((*argv) + 2, "help") == 0) { return 1; } if (strcmp((*argv) + 2, "device") == 0) { if (argc < 2) { log_message(-2, "Missing argument after: %s", *argv); return 1; } else { scsiDevice = argv[1]; argc--, argv++; } } else if (strcmp((*argv) + 2, "source-device") == 0) { if (argc < 2) { log_message(-2, "Missing argument after: %s", *argv); return 1; } else { sourceScsiDevice = argv[1]; argc--, argv++; } } else if (strcmp((*argv) + 2, "rspeed") == 0) { if (argc < 2) { log_message(-2, "Missing argument after: %s", *argv); return 1; } else { readingSpeed = atol(argv[1]); if (readingSpeed < 0) { log_message(-2, "Illegal reading speed: %s", argv[1]); return 1; } argc--, argv++; } } else if (strcmp((*argv) + 2, "speed") == 0) { if (argc < 2) { log_message(-2, "Missing argument after: %s", *argv); return 1; } else { writingSpeed = atol(argv[1]); if (writingSpeed < 0) { log_message(-2, "Illegal writing speed: %s", argv[1]); return 1; } argc--, argv++; } } else if (strcmp((*argv) + 2, "capacity") == 0) { if (argc < 2) { log_message(-2, "Missing argument after: %s", *argv); return 1; } else { userCapacity = atol(argv[1]); if (userCapacity < 0) { log_message(-2, "Illegal disk capacity: %s minutes", argv[1]); return 1; } argc--, argv++; } } else if (strcmp((*argv) + 2, "blank-mode") == 0) { if (argc < 2) { log_message(-2, "Missing argument after: %s", *argv); return 1; } else { if (strcmp(argv[1], "full") == 0) { blankingMode = CdrDriver::BLANK_FULL; } else if (strcmp(argv[1], "minimal") == 0) { blankingMode = CdrDriver::BLANK_MINIMAL; } else { log_message(-2, "Illegal blank mode. Valid values: full minimal"); return 1; } argc--, argv++; } } else if (strcmp((*argv) + 2, "paranoia-mode") == 0) { if (argc < 2) { log_message(-2, "Missing argument after: %s", *argv); return 1; } else { paranoiaMode= atol(argv[1]); if (paranoiaMode < 0) { log_message(-2, "Illegal paranoia mode: %s", argv[1]); return 1; } argc--, argv++; } } else if (strcmp((*argv) + 2, "remote") == 0) { if (argc < 2) { log_message(-2, "Missing argument after: %s", *argv); return 1; } else { remoteFd = atol(argv[1]); if (remoteFd < 0) { log_message(-2, "Invalid remote message file descriptor: %s", argv[1]); return 1; } remoteMode = true; argc--, argv++; } } else if (strcmp((*argv) + 2, "eject") == 0) { eject = true; } else if (strcmp((*argv) + 2, "swap") == 0) { swap = true; } else if (strcmp((*argv) + 2, "query-string") == 0) { printQuery = true; } else if (strcmp((*argv) + 2, "multi") == 0) { multiSession = true; } else if (strcmp((*argv) + 2, "simulate") == 0) { writeSimulate = true; } else if (strcmp((*argv) + 2, "fast-toc") == 0) { fastToc = true; } else if (strcmp((*argv) + 2, "read-raw") == 0) { readRaw = true; } else if (strcmp((*argv) + 2, "no-mode2-mixed") == 0) { mode2Mixed = false; } else if (strcmp((*argv) + 2, "reload") == 0) { reload = true; } else if (strcmp((*argv) + 2, "no-utf8") == 0) { no_utf8 = true; } else if (strcmp((*argv) + 2, "force") == 0) { force = true; } else if (strcmp((*argv) + 2, "keep") == 0) { keep = true; } else if (strcmp((*argv) + 2, "on-the-fly") == 0) { onTheFly = true; } else if (strcmp((*argv) + 2, "save") == 0) { saveSettings = true; } else if (strcmp((*argv) + 2, "tao-source") == 0) { taoSource = true; } else if (strcmp((*argv) + 2, "keepimage") == 0) { keepImage = true; } else if (strcmp((*argv) + 2, "overburn") == 0) { overburn = true; } else if (strcmp((*argv) + 2, "full-burn") == 0) { fullBurn = true; } else if (strcmp((*argv) + 2, "with-cddb") == 0) { withCddb = true; } else if (strcmp((*argv) + 2, "driver") == 0) { if (argc < 2) { log_message(-2, "Missing argument after: %s", *argv); return 1; } else { driverId = argv[1]; argc--, argv++; } } else if (strcmp((*argv) + 2, "source-driver") == 0) { if (argc < 2) { log_message(-2, "Missing argument after: %s", *argv); return 1; } else { sourceDriverId = argv[1]; argc--, argv++; } } else if (strcmp((*argv) + 2, "datafile") == 0) { if (argc < 2) { log_message(-2, "Missing argument after: %s", *argv); return 1; } else { dataFilename = argv[1]; argc--, argv++; } } else if (strcmp((*argv) + 2, "buffers") == 0) { if (argc < 2) { log_message(-2, "Missing argument after: %s", *argv); return 1; } else { fifoBuffers = atoi(argv[1]); argc--, argv++; } } else if (strcmp((*argv) + 2, "session") == 0) { if (argc < 2) { log_message(-2, "Missing argument after: %s", *argv); return 1; } else { session = atoi(argv[1]); argc--, argv++; if (session < 1) { log_message(-2, "Illegal session number: %d", session); return 1; } } } else if (strcmp((*argv) + 2, "cddb-servers") == 0) { if (argc < 2) { log_message(-2, "Missing argument after: %s", *argv); return 1; } else { if (clear_default_servers) { clear_default_servers = false; cddbServerList.clear(); } { string parsed; stringstream iss(argv[1]); while (getline(iss, parsed, ' ')) cddbServerList.push_back(parsed); } argc--, argv++; } } else if (strcmp((*argv) + 2, "cddb-directory") == 0) { if (argc < 2) { log_message(-2, "Missing argument after: %s", *argv); return 1; } else { cddbLocalDbDir = argv[1]; argc--, argv++; } } else if (strcmp((*argv) + 2, "tmpdir") == 0) { if (argc < 2) { log_message(-2, "Missing argument after: %s", *argv); return 1; } else { tmpFileDir = argv[1]; argc--, argv++; } } else if (strcmp((*argv) + 2, "cddb-timeout") == 0) { if (argc < 2) { log_message(-2, "Missing argument after: %s", *argv); return 1; } else { cddbTimeout = atoi(argv[1]); argc--, argv++; if (cddbTimeout < 1) { log_message(-2, "Illegal CDDB timeout: %d", cddbTimeout); return 1; } } } else if (strcmp((*argv) + 2, "tao-source-adjust") == 0) { if (argc < 2) { log_message(-2, "Missing argument after: %s", *argv); return 1; } else { taoSourceAdjust = atoi(argv[1]); argc--, argv++; if (taoSourceAdjust < 0 || taoSourceAdjust >= 100) { log_message(-2, "Illegal number of TAO link blocks: %d", taoSourceAdjust); return 1; } } } else if (strcmp((*argv) + 2, "buffer-under-run-protection") == 0) { if (argc < 2) { log_message(-2, "Missing argument after: %s", *argv); return 1; } else { int val = atoi(argv[1]); argc--, argv++; if (val < 0 || val > 1) { log_message(-2, "Illegal value for option --buffer-under-run-protection: %d", val); return 1; } bufferUnderrunProtection = val; } } else if (strcmp((*argv) + 2, "write-speed-control") == 0) { if (argc < 2) { log_message(-2, "Missing argument after: %s", *argv); return 1; } else { int val = atoi(argv[1]); argc--, argv++; if (val < 0 || val > 1) { log_message(-2, "Illegal value for option --write-speed-control: %d", val); return 1; } writeSpeedControl = val; } } else if (strcmp((*argv) + 2, "read-subchan") == 0) { if (argc < 2) { log_message(-2, "Missing argument after: %s", *argv); return 1; } else { if (strcmp(argv[1], "rw") == 0) { readSubchanMode = TrackData::SUBCHAN_RW; } else if (strcmp(argv[1], "rw_raw") == 0) { readSubchanMode = TrackData::SUBCHAN_RW_RAW; } else { log_message(-2, "Invalid argument after %s: %s", argv[0], argv[1]); return 1; } argc--, argv++; } } else { log_message(-2, "Illegal option: %s", *argv); return 1; } } argc--, argv++; } if (cmdInfo[command].needTocFile) { if (argc < 1) { log_message(-2, "Missing toc-file."); return 1; } else if (argc > 1) { log_message(-2, "Expecting only one toc-file."); return 1; } tocFile = *argv; } return 0; } // Commit settings to overall system. Export them. void DaoCommandLine::commitSettings(Settings* settings, const char* settingsPath) { if (tmpFileDir.size()) tempFileManager.setTempDirectory(tmpFileDir.c_str()); tempFileManager.setKeepTemps(keep); if (saveSettings && settingsPath != NULL) { // If we're saving our settings, give up root privileges and // exit. The --save option is only compiled in if setreuid() is // available (because it could be used for a local root exploit). if (giveUpRootPrivileges()) { exportSettings(settings); settings->write(settingsPath); } exit(0); } } // Selects driver for device of 'scsiIf'. CdrDriver *selectDriver(DaoCommand cmd, ScsiIf *scsiIf, const string& driverId) { unsigned long options = 0; CdrDriver *ret = NULL; if (!driverId.empty()) { char *s = strdupCC(driverId.c_str()); char *p = strchr(s, ':'); if (p != NULL) { *p = 0; options = strtoul(p + 1, NULL, 0); } ret = CdrDriver::createDriver(s, options, scsiIf); if (ret == NULL) { log_message(-2, "%s: Illegal driver ID, available drivers:", s); CdrDriver::printDriverIds(); } delete[] s; } else { const char *id = NULL; // for reading commands try to select a special read driver first: if (cmd == READ_TOC || cmd == READ_CD) id = CdrDriver::selectDriver(0, scsiIf->vendor(), scsiIf->product(), &options); // try to select a write driver if (id == NULL) id = CdrDriver::selectDriver(1, scsiIf->vendor(), scsiIf->product(), &options); // if no driver is selected, yet, try to select a read driver for // disk-info if (id == NULL && (cmd == DISK_INFO || cmd == MSINFO || cmd == DISCID)) id = CdrDriver::selectDriver(0, scsiIf->vendor(), scsiIf->product(), &options); // Still no driver, try to autodetect one if (id == NULL) id = CdrDriver::detectDriver(scsiIf, &options); if (id != NULL) { ret = CdrDriver::createDriver(id, options, scsiIf); } else { log_message(0, ""); log_message(-2, "No driver found for '%s %s', available drivers:\n", scsiIf->vendor(), scsiIf->product()); CdrDriver::printDriverIds(); log_message(0, "\nFor all recent recorder models either the 'generic-mmc' or"); log_message(0, "the 'generic-mmc-raw' driver should work."); log_message(0, "Use option '--driver' to force usage of a driver, e.g.: --driver generic-mmc"); } } return ret; } string getDefaultDevice(DaoDeviceType req) { int i, len; string buf; // This function should not be called if the command issues // doesn't actually require a device. assert(req != NO_DEVICE); ScsiIf::ScanData* sdata = ScsiIf::scan(&len); if (sdata) { for (i = 0; i < len; i++) { ScsiIf testif(sdata[i].dev.c_str()); if (testif.init() != 0) { continue; } cd_page_2a* p2a; if (!(p2a = testif.checkMmc())) continue; if (req == NEED_CDR_R && !p2a->cd_r_read) continue; if (req == NEED_CDR_W && !p2a->cd_r_write) continue; if (req == NEED_CDRW_W && !p2a->cd_rw_write) continue; buf = sdata[i].dev; delete[] sdata; return buf; } delete[] sdata; } return buf; } #define MAX_RETRY 10 CdrDriver *setupDevice(DaoCommand cmd, const string& scsiDevice, const string& driverId, int initDevice, int checkReady, int checkEmpty, int readingSpeed, bool remote, bool reload) { ScsiIf *scsiIf = NULL; CdrDriver *cdr = NULL; DiskInfo *di = NULL; int inquiryFailed = 0; int retry = 0; int initTries = 2; int ret = 0; scsiIf = new ScsiIf(scsiDevice.c_str()); switch (scsiIf->init()) { case 1: log_message(-2, "Please use option '--device device'" ", e.g. --device /dev/cdrom"); delete scsiIf; return NULL; break; case 2: inquiryFailed = 1; break; } log_message(2, "%s: %s %s\tRev: %s", scsiDevice.c_str(), scsiIf->vendor(), scsiIf->product(), scsiIf->revision()); if (inquiryFailed && driverId.empty()) { log_message(-2, "Inquiry failed and no driver id is specified."); log_message(-2, "Please use option --driver to specify a driver id."); delete scsiIf; return NULL; } if ((cdr = selectDriver(cmd, scsiIf, driverId)) == NULL) { delete scsiIf; return NULL; } log_message(2, "Using driver: %s (options 0x%04lx)\n", cdr->driverName(), cdr->options()); if (!initDevice) return cdr; while (initTries > 0) { // clear unit attention cdr->rezeroUnit(0); if (readingSpeed >= 0) { if (!cdr->rspeed(readingSpeed)) { log_message(-2, "Reading speed %d is not supported by device.", readingSpeed); exit(1); } } if (checkReady) { retry = 0; while (retry < MAX_RETRY) { if (retry++) sleep(3); if (!(ret = cdr->testUnitReady(1))) break; if (ret == 1) { delete cdr; delete scsiIf; return NULL; } log_message(-1, "Unit not ready, still trying..."); } if (ret != 0) { log_message(-2, "Unit not ready, giving up."); delete cdr; delete scsiIf; return NULL; } cdr->rezeroUnit(0); if (readingSpeed >= 0) { log_message(0, "Setting reading speed %d.", readingSpeed); if (!cdr->rspeed(readingSpeed)) { log_message(-2, "Reading speed %d is not supported by device.", readingSpeed); exit(1); } } if ((di = cdr->diskInfo()) == NULL) { log_message(-2, "Cannot get disk information."); delete cdr; delete scsiIf; return NULL; } if (checkEmpty && initTries == 2 && di->valid.empty && !di->empty && (!di->valid.append || !di->append) && (!remote || reload)) { if (!reload) { log_message(0, "Disk seems to be written - hit return to reload disk."); fgetc(stdin); } log_message(1, "Reloading disk..."); if (cdr->loadUnload(1) != 0) { delete cdr; delete scsiIf; return NULL; } sleep(1); cdr->rezeroUnit(0); // clear unit attention if (cdr->loadUnload(0) != 0) { log_message(-2, "Cannot load tray."); delete cdr; delete scsiIf; return NULL; } initTries = 1; } else { initTries = 0; } } else { initTries = 0; } } if (readingSpeed >= 0) { if (!cdr->rspeed(readingSpeed)) { log_message(-2, "Reading speed %d is not supported by device.", readingSpeed); exit(1); } } return cdr; } void showDriveInfo(const DriveInfo *i) { if (i == NULL) { log_message(0, "No drive information available."); return; } printf("Maximum reading speed: %d kB/s\n", i->maxReadSpeed); printf("Current reading speed: %d kB/s\n", i->currentReadSpeed); printf("Maximum writing speed: %d kB/s\n", i->maxWriteSpeed); printf("Current writing speed: %d kB/s\n", i->currentWriteSpeed); printf("BurnProof supported: %s\n", i->burnProof ? "yes" : "no"); printf("JustLink supported: %s\n", i->ricohJustLink ? "yes" : "no"); printf("JustSpeed supported: %s\n", i->ricohJustSpeed ? "yes" : "no"); } void showTocInfo(const Toc *toc, const string& tocFile) { long len = toc->length().lba() * AUDIO_BLOCK_LEN; len >>= 20; printf("%s: %d tracks, length %s, %ld blocks, %ld MB\n", tocFile.c_str(), toc->nofTracks(), toc->length().str(), toc->length().lba(), len); } void showTocSize(const Toc *toc, const string& tocFile) { printf("%ld\n", toc->length().lba()); } void showToc(Toc *toc, DaoCommandLine& options) { const Track *t; Msf start, end, index; int i; int n; int tcount = 1; char buf[14]; printf("TOC TYPE: %s\n", Toc::tocType2String(toc->tocType())); if (toc->catalogValid()) { for (i = 0; i < 13; i++) buf[i] = toc->catalog(i) + '0'; buf[13] = 0; printf("CATALOG NUMBER: %s\n", buf); } if (options.verbose > 2) { for (const auto& item : toc->globalCdTextItems()) { PrintParams params; params.no_utf8 = options.no_utf8; cout << " "; item.print(cout, params); cout << "\n"; } } TrackIterator itr(toc); for (t = itr.first(start, end); t != NULL; t = itr.next(start, end)) { if (tcount > 1) printf("\n"); printf("TRACK %2d Mode %s", tcount, TrackData::mode2String(t->type())); if (t->subChannelType() != TrackData::SUBCHAN_NONE) printf(" %s", TrackData::subChannelMode2String(t->subChannelType())); printf(":\n"); if (t->type() == TrackData::AUDIO) { if (t->isrcValid()) { printf(" ISRC %c%c %c%c%c %c%c %c%c%c%c%c\n", t->isrcCountry(0), t->isrcCountry(1), t->isrcOwner(0), t->isrcOwner(1), t->isrcOwner(2), t->isrcYear(0) + '0', t->isrcYear(1) + '0', t->isrcSerial(0) + '0', t->isrcSerial(1) + '0', t->isrcSerial(2) + '0', t->isrcSerial(3) + '0', t->isrcSerial(4) + '0'); } } printf(" COPY%sPERMITTED\n", t->copyPermitted() ? " " : " NOT "); if (t->type() == TrackData::AUDIO) { printf(" %sPRE-EMPHASIS\n", t->preEmphasis() ? "" : "NO "); printf(" %s CHANNEL AUDIO\n", t->audioType() == 0 ? "TWO" : "FOUR"); } if (t->start().lba() != 0) { printf(" PREGAP %s(%6ld)\n", t->start().str(), t->start().lba()); } printf(" START %s(%6ld)\n", start.str(), start.lba()); n = t->nofIndices(); for (i = 0; i < n; i++) { index = start + t->getIndex(i); printf(" INDEX %2d %s(%6ld)\n", i + 2, index.str(), index.lba()); } printf(" END%c %s(%6ld)\n", t->isPadded() ? '*' : ' ', end.str(), end.lba()); if (options.verbose > 2) { for (const auto& item : t->getCdTextItems()) { PrintParams params; params.no_utf8 = options.no_utf8; cout << " "; item.print(cout, params); cout << "\n"; } } tcount++; } } void showData(const Toc *toc, bool swap) { long length = toc->length().lba(); Sample buf[SAMPLES_PER_BLOCK]; int i; unsigned long sampleNr = 0; long lba = 150; TocReader reader(toc); if (reader.openData() != 0) { log_message(-2, "Cannot open audio data."); return; } while (length > 0) { if (reader.readSamples(buf, SAMPLES_PER_BLOCK) != SAMPLES_PER_BLOCK) { log_message(-2, "Read of audio data failed."); return; } lba++; if (swap) { swapSamples(buf, SAMPLES_PER_BLOCK); } for (i = 0; i < SAMPLES_PER_BLOCK; i++) { printf("%7lu:%6d %6d\n", sampleNr, buf[i].left(), buf[i].right()); sampleNr++; } length -= 1; } } void showCDText(CdrDriver* cdr, DaoCommandLine& options) { int nofTracks = 0; auto cdt = cdr->getTocGeneric(&nofTracks); if (!cdt || nofTracks <= 1) return; nofTracks--; // remove leadout // Create a fake Toc placeholder. auto toc = new Toc(); for (int i = 0; i < nofTracks; i++) toc->append(new Track(TrackData::AUDIO, TrackData::SUBCHAN_RW)); if (cdr->readCdTextData(toc) != 0) { log_message(-2, "Cannot read CD-TEXT data."); return; } for (const auto& item : toc->globalCdTextItems()) { PrintParams params; params.no_utf8 = options.no_utf8; item.print(cout, params); cout << "\n"; } // for (const auto i : items) { // if (i->packType() == CdTextItem::PackType::SIZE_INFO) // continue; // if (i->blockNr() != n_block) { // n_block = i->blockNr(); // if (n_block > 0) cout << "\n"; // cout << "Block " << n_block << ":\n"; // if (languages && n_block < 8 && languages[n_block] != 0) { // cout << " LANGUAGE \"" // << CdTextContainer::languageName(languages[n_block]) // << "\"\n"; // } // } // if (i->trackNr() >= 1 && i->trackNr() != n_track) { // n_track = i->trackNr(); // cout << " Track " << n_track << ":\n"; // } // cout << " "; // if (i->dataType() == CdTextItem::DataType::SBCC) { // cout << CdTextItem::packType2String(i->trackNr() > 0, i->packType()) // << " \"" << Util::to_utf8((u8*)i->data(), (size_t)i->dataLen(), // encodings[i->blockNr()]) << "\""; // } else { // PrintParams p; // p.to_utf8 = true; // i->print(cout, p); // } // cout << "\n"; // } } void showDiskInfo(DiskInfo *di) { const char *s1, *s2; log_message(2, "That data below may not reflect the real status of the inserted medium"); log_message(2, "if a simulation run was performed before. Reload the medium in this case."); log_message(2, ""); printf("CD-RW : "); if (di->valid.cdrw) printf(di->cdrw ? "yes" : "no"); else printf("n/a"); printf("\n"); printf("Total Capacity : "); if (di->valid.capacity) printf("%s (%ld blocks, %ld/%ld MB)", Msf(di->capacity).str(), di->capacity, (di->capacity * 2) >> 10, (di->capacity * AUDIO_BLOCK_LEN) >> 20); else printf("n/a"); printf("\n"); printf("CD-R medium : "); if (di->valid.manufacturerId) { if (CdrDriver::cdrVendor(di->manufacturerId, &s1, &s2)) { printf("%s\n", s1); printf(" %s\n", s2); } else { printf("%s: unknown vendor ID\n", di->manufacturerId.str()); } } else { printf("n/a\n"); } printf("Recording Speed : "); if (di->valid.recSpeed) printf("%dX - %dX", di->recSpeedLow, di->recSpeedHigh); else printf("n/a"); printf("\n"); printf("CD-R empty : "); if (di->valid.empty) printf(di->empty ? "yes" : "no"); else printf("n/a"); printf("\n"); if (di->valid.empty && !di->empty && di->valid.append) { printf("Toc Type : "); switch (di->diskTocType) { case 0x00: printf("CD-DA or CD-ROM"); break; case 0x10: printf("CD-I"); break; case 0x20: printf("CD-ROM XA"); break; case 0xff: printf("Undefined"); break; default: printf("invalid: %d", di->diskTocType); break; } printf("\n"); printf("Sessions : %d\n", di->sessionCnt); printf("Last Track : %d\n", di->lastTrackNr); printf("Appendable : %s\n", di->append ? "yes" : "no"); if (di->append) { printf("Start of last session: %ld (%s)\n", di->lastSessionLba, Msf(di->lastSessionLba + 150).str()); printf("Start of new session : %ld (%s)\n", di->thisSessionLba, Msf(di->thisSessionLba + 150).str()); if (di->valid.capacity && di->capacity > di->thisSessionLba) { long r = di->capacity - di->thisSessionLba; printf("Remaining Capacity : %s (%ld blocks, %ld/%ld MB)\n", Msf(r).str(), r, (r * 2) >> 10, (r * AUDIO_BLOCK_LEN) >> 20); } } } } /* * Show multi session info in a format that is easy to parse with scritps. * Return: 0: OK * 1: disk is not empty and not appendable * 2: could not determine the requested information */ int showMultiSessionInfo(DiskInfo *di) { if (di->valid.empty) { if (di->empty) { // print nothing to indicate empty disk return 0; } else if (di->valid.append) { if (di->append) { printf("%ld,%ld\n", di->lastSessionLba, di->thisSessionLba); return 0; } else { return 1; } } } return 2; } void printCddbQuery(Toc *toc) { Cddb cddb(toc); cddb.printDbQuery(); } int readCddb(const DaoCommandLine& opts, Toc *toc, bool showEntry = false) { int err = 0; char *p; const char *sep = " ,"; char *user = NULL; char *host = NULL; struct passwd *pwent; Cddb::QueryResults *qres, *qrun, *qsel; Cddb::CddbEntry *dbEntry; Cddb cddb(toc); cddb.timeout(opts.cddbTimeout); if (!opts.cddbLocalDbDir.empty()) cddb.localCddbDirectory(opts.cddbLocalDbDir); for (const auto& p : opts.cddbServerList) cddb.appendServer(p.c_str()); if ((pwent = getpwuid(getuid())) != NULL && pwent->pw_name != NULL) { user = strdupCC(pwent->pw_name); } else { user = strdupCC("unknown"); } { struct utsname sinfo; if (uname(&sinfo) == 0) { host = strdupCC(sinfo.nodename); } else { host = strdupCC("unknown"); } } if (cddb.connectDb(user, host, "cdrdao", VERSION) != 0) { log_message(-2, "Cannot connect to any CDDB server."); err = 2; goto fail; } if (cddb.queryDb(&qres) != 0) { log_message(-2, "Querying of CDDB server failed."); err = 2; goto fail; } if (qres == NULL) { log_message(1, "No CDDB record found for this toc-file."); err = 1; goto fail; } if (qres->next != NULL || !(qres->exactMatch)) { int qcount; if (qres->next == NULL) log_message(0, "Found following inexact match:"); else log_message(0, "Found following inexact matches:"); log_message(0, "\n DISKID CATEGORY TITLE\n"); for (qrun = qres, qcount = 0; qrun != NULL; qrun = qrun->next, qcount++) { log_message(0, "%2d. %-8s %-12s %s", qcount + 1, qrun->diskId, qrun->category, qrun->title); } log_message(0, "\n"); qsel = NULL; while (1) { char buf[20]; int sel; log_message(0, "Select match, 0 for none [0-%d]?", qcount); if (fgets(buf, 20, stdin) == NULL) break; for (p = buf; *p != 0 && isspace(*p); p++) ; if (*p != 0 && isdigit(*p)) { sel = atoi(p); if (sel == 0) { break; } else if (sel > 0 && sel <= qcount) { sel--; for (qsel = qres, qcount = 0; qsel != NULL && qcount != sel; qsel = qsel->next, qcount++) ; break; } } } if (qsel == NULL) { log_message(0, "No match selected."); err = 1; goto fail; } } else { qsel = qres; } log_message(1, "Reading CDDB record for: %s-%s-%s", qsel->diskId, qsel->category, qsel->title); if (cddb.readDb(qsel->category, qsel->diskId, &dbEntry) != 0) { log_message(-2, "Reading of CDDB record failed."); err = 2; goto fail; } if (showEntry) cddb.printDbEntry(); if (!cddb.addAsCdText(toc)) err = 1; fail: delete[] user; delete[] host; return err; } void scanBus() { int i, len; ScsiIf::ScanData *sdata = ScsiIf::scan(&len); if (sdata) { for (i = 0; i < len; i++) { log_message(0, "%s : %s, %s, %s", sdata[i].dev.c_str(), sdata[i].vendor, sdata[i].product, sdata[i].revision); } delete[] sdata; } #ifdef SCSI_ATAPI sdata = ScsiIf::scan(&len, "ATA"); if (sdata) { for (i = 0; i < len; i++) { log_message(0, "%-20s %s, %s, %s", sdata[i].dev.c_str(), sdata[i].vendor, sdata[i].product, sdata[i].revision); } delete[] sdata; } else { sdata = ScsiIf::scan(&len, "ATAPI"); if (sdata) { for (i = 0; i < len; i++) { log_message(0, "%-20s %s, %s, %s", sdata[i].dev.c_str(), sdata[i].vendor, sdata[i].product, sdata[i].revision); } delete[] sdata; } } #endif } int checkToc(const Toc *toc, bool force) { int ret = toc->check(); if (ret == 0 || (ret == 1 && force)) return 0; log_message(-2, "The toc check function detected at least one warning."); log_message(-2, "If you record this toc the resulting CD might be unusable"); log_message(-2, "or the recording process might abort with error."); log_message(-2, "Use option --force to ignore the warnings."); return ret; } int copyCd(DaoCommandLine& opts, CdrDriver *src, CdrDriver *dst) { char dataFilenameBuf[50]; long pid = getpid(); Toc *toc; int ret = 0; DiskInfo *di = NULL; int isAppendable = 0; if (opts.dataFilename == NULL) { // create a unique temporary data file name in current directory snprintf(dataFilenameBuf, sizeof(dataFilenameBuf), "cddata%ld.bin", pid); opts.dataFilename = dataFilenameBuf; } src->rawDataReading(true); src->taoSource(opts.taoSource); if (opts.taoSourceAdjust >= 0) src->taoSourceAdjust(opts.taoSourceAdjust); if ((toc = src->readDisk(opts.session, opts.dataFilename)) == NULL) { unlink(opts.dataFilename); log_message(-2, "Creation of source CD image failed."); return 1; } if (opts.withCddb) { if (readCddb(opts, toc) == 0) log_message(2, "CD-TEXT data was added to toc-file."); else log_message(2, "Reading of CD-TEXT data failed - " "continuing without CD-TEXT data."); } if (opts.keepImage) { string tocFilename; tocFilename = "cd"; tocFilename += to_string(pid); tocFilename += ".toc"; log_message(2, "Keeping created image file \"%s\".", opts.dataFilename); log_message(2, "Corresponding toc-file is written to \"%s\".", tocFilename.c_str()); toc->write(tocFilename); } if (checkToc(toc, opts.force)) { log_message(-3, "Toc created from source CD image is inconsistent."); toc->print(cout, errPrintParams); delete toc; return 1; } switch (dst->checkToc(toc)) { case 0: // OK break; case 1: // warning if (!opts.force) { log_message(-2, "The toc extracted from the source CD is not suitable for"); log_message(-2, "the recorder device and may produce undefined results."); log_message(-2, "Use option --force to use it anyway."); delete toc; return 1; } break; default: // error log_message(-2, "The toc extracted from the source CD is not suitable for this drive."); delete toc; return 1; break; } if (src == dst) { // Unlock src to make swaping possible src->preventMediumRemoval(0); src->loadUnload(1); log_message(0, "Please insert a recordable medium and hit enter."); getc(stdin); } do { if ((di = dst->diskInfo()) == NULL) { log_message(-2, "Cannot get disk information from recorder device."); delete toc; return 1; } if (!di->valid.empty) { log_message(-2, "Cannot determine disk status - hit enter to try again."); getc(stdin); isAppendable = 0; } else if (!di->empty && (!di->valid.append || !di->append)) { log_message(0, "Medium in recorder device is not empty and not appendable."); log_message(0, "Please insert a recordable medium and hit enter."); getc(stdin); isAppendable = 0; } else { isAppendable = 1; } } while (!isAppendable); if (dst->preventMediumRemoval(1) != 0) { if (!opts.keepImage) { if (unlink(opts.dataFilename) != 0) log_message(-2, "Cannot remove CD image file \"%s\": %s", opts.dataFilename, strerror(errno)); } delete toc; return 1; } if (writeDiskAtOnce(toc, dst, opts.fifoBuffers, opts.swap, 0, 0) != 0) { if (dst->simulate()) log_message(-2, "Simulation failed."); else log_message(-2, "Writing failed."); ret = 1; } else { if (dst->simulate()) log_message(1, "Simulation finished successfully."); else log_message(1, "Writing finished successfully."); } if (dst->preventMediumRemoval(0) != 0) ret = 1; dst->rezeroUnit(0); if (ret == 0 && opts.eject) { dst->loadUnload(1); } if (!opts.keepImage) { if (unlink(opts.dataFilename) != 0) log_message(-2, "Cannot remove CD image file \"%s\": %s", opts.dataFilename, strerror(errno)); } delete toc; return ret; } int copyCdOnTheFly(DaoCommandLine& opts,CdrDriver *src, CdrDriver *dst) { Toc *toc = NULL; int pipeFds[2]; pid_t pid = -1; int ret = 0; int oldStdin = -1; if (src == dst) return 1; if (pipe(pipeFds) != 0) { log_message(-2, "Cannot create pipe: %s", strerror(errno)); return 1; } src->rawDataReading(true); src->taoSource(opts.taoSource); if (opts.taoSourceAdjust >= 0) src->taoSourceAdjust(opts.taoSourceAdjust); src->onTheFly(1); // the fd is not used by 'readDiskToc', just need to // indicate that on-the-fly copying is active for // automatical selection if the first track's pre-gap // is padded with zeros in the created Toc. if ((toc = src->readDiskToc(opts.session, "-")) == NULL) { log_message(-2, "Creation of source CD toc failed."); ret = 1; goto fail; } if (opts.withCddb) { if (readCddb(opts, toc) != 0) { ret = 1; goto fail; } else { log_message(2, "CD-TEXT data was added to toc."); } } if (checkToc(toc, opts.force) != 0) { log_message(-3, "Toc created from source CD image is inconsistent" "- please report."); toc->print(cout, errPrintParams); ret = 1; goto fail; } switch (dst->checkToc(toc)) { case 0: // OK break; case 1: // warning if (!opts.force) { log_message(-2, "The toc extracted from the source CD is not suitable for"); log_message(-2, "the recorder device and may produce undefined results."); log_message(-2, "Use option --force to use it anyway."); ret = 1; goto fail; } break; default: // error log_message(-2, "The toc extracted from the source CD is not suitable for this drive."); ret = 1; goto fail; break; } if ((pid = fork()) < 0) { log_message(-2, "Cannot fork reader process: %s", strerror(errno)); ret = 1; goto fail; } if (pid == 0) { // we are the reader process setsid(); close(pipeFds[0]); src->onTheFly(pipeFds[1]); opts.verbose = 0; #ifdef __CYGWIN__ /* Close the SCSI interface and open it again. This will re-init the * ASPI layer which is required for the child process */ delete src->scsiIf(); src->scsiIf(new ScsiIf(opts.sourceScsiDevice)); if (src->scsiIf()->init() != 0) { log_message(-2, "Re-init of SCSI interace failed."); // indicate end of data close(pipeFds[1]); while (1) sleep(10); } #endif if (src->readDisk(opts.session, "-") != NULL) log_message(1, "CD image reading finished successfully."); else log_message(-2, "CD image reading failed."); // indicate end of data close(pipeFds[1]); while (1) sleep(10); } close(pipeFds[1]); pipeFds[1] = -1; if ((oldStdin = dup(fileno(stdin))) < 0) { log_message(-2, "Cannot duplicate stdin: %s", strerror(errno)); ret = 1; goto fail; } if (dup2(pipeFds[0], fileno(stdin)) != 0) { log_message(-2, "Cannot connect pipe to stdin: %s", strerror(errno)); close(oldStdin); oldStdin = -1; ret = 1; goto fail; } dst->onTheFly(fileno(stdin)); if (dst->preventMediumRemoval(1) != 0) { ret = 1; goto fail; } if (writeDiskAtOnce(toc, dst, opts.fifoBuffers, opts.swap, 0, 0) != 0) { if (dst->simulate()) log_message(-2, "Simulation failed."); else log_message(-2, "Writing failed."); ret = 1; } else { if (dst->simulate()) log_message(1, "Simulation finished successfully."); else log_message(1, "Writing finished successfully."); } dst->rezeroUnit(0); if (dst->preventMediumRemoval(0) != 0) ret = 1; if (ret == 0 && opts.eject) { dst->loadUnload(1); } fail: if (pid > 0) { int status; kill(pid, SIGKILL); wait(&status); } if (oldStdin >= 0) { dup2(oldStdin, fileno(stdin)); close(oldStdin); } delete toc; close(pipeFds[0]); if (pipeFds[1] >= 0) close(pipeFds[1]); return ret; } } // End of anonymous namespace int main(int argc, char **argv) { int exitCode = 0; Toc *toc = NULL; ScsiIf *cdrScsi = NULL; ScsiIf *srcCdrScsi = NULL; CdrDriver *cdr = NULL; CdrDriver *srcCdr = NULL; int delSrcDevice = 0; DiskInfo *di = NULL; DiskInfo *srcDi = NULL; const char *homeDir; const char *settingsPath = NULL; #if defined(HAVE_SETEUID) && defined(HAVE_SETEGID) if (geteuid() == 0 && getuid() != 0) { uid_t uid = getuid(); if (setuid(uid) == -1) { log_message(-2, "Failed to drop privileges; exiting."); exit(1); } } #endif log_init(); // Initialize command line options to default values DaoCommandLine options; options.progName = argv[0]; Settings* settings = new Settings; settingsPath = "/etc/cdrdao.conf"; if (settings->read(settingsPath) == 0) log_message(3, "Read settings from \"%s\".", settingsPath); settingsPath = "/etc/defaults/cdrdao"; if (settings->read(settingsPath) == 0) log_message(3, "Read settings from \"%s\".", settingsPath); settingsPath = "/etc/default/cdrdao"; if (settings->read(settingsPath) == 0) log_message(3, "Read settings from \"%s\".", settingsPath); settingsPath = NULL; if ((homeDir = getenv("HOME")) != NULL) { settingsPath = strdup3CC(homeDir, "/.cdrdao", NULL); if (settings->read(settingsPath) == 0) log_message(3, "Read settings from \"%s\".", settingsPath); } else { log_message(-1, "Environment variable 'HOME' not defined" "- cannot read .cdrdao."); } #ifdef UNIXWARE if (getuid() != 0) { log_message(-2, "You must be root to use cdrdao."); exit(1); } #endif // Parse command line command and options. if (options.parseCmdLine(argc - 1, argv + 1, settings) != 0) { log_set_verbose(2); printVersion(); options.printUsage(); exit(1); } log_set_verbose(options.verbose); options.commitSettings(settings, settingsPath); // Just show version ? We're done. if (options.command == SHOW_VERSION) { printVersion(); goto fail; } errPrintParams.no_utf8 = options.no_utf8; filePrintParams.no_utf8 = options.no_utf8; // --------------------------------------------------------------------- // Parse and check the toc file // --------------------------------------------------------------------- if (cmdInfo[options.command].tocParse) { // Parse TOC file toc = Toc::read(options.tocFile); if (options.remoteMode) { unlink(options.tocFile.c_str()); } // Check and resolve input files paths if (!toc || !toc->resolveFilenames(options.tocFile.c_str())) { exitCode = 1; goto fail; } if (!toc->convertFilesToWav()) { log_message(-2, "Could not decode audio files from toc file \"%s\".", options.tocFile.c_str()); exitCode = 1; goto fail; } toc->recomputeLength(); if (cmdInfo[options.command].tocCheck) { if (checkToc(toc, options.force) != 0) { log_message(-2, "Toc file \"%s\" is inconsistent.", options.tocFile.c_str()); exitCode = 1; goto fail; } } } // --------------------------------------------------------------------- // Setup the CD device, obtain disk media information. // --------------------------------------------------------------------- if (cmdInfo[options.command].requiredDevice != NO_DEVICE) { if (options.scsiDevice.empty()) { options.scsiDevice = getDefaultDevice(cmdInfo[options.command].requiredDevice); } if (options.scsiDevice.empty()) { log_message(-2, "No device specified, no default device found."); exitCode = 1; goto fail; } cdr = setupDevice(options.command, options.scsiDevice, options.driverId, /* init device? */ (options.command == UNLOCK) ? 0 : 1, /* check for ready status? */ (options.command == DRIVE_INFO) ? 0 : 1, /* reset status of medium if not empty? */ (options.command == SIMULATE || options.command == WRITE) ? 1 : 0, options.readingSpeed, options.remoteMode, options.reload); if (cdr == NULL) { log_message(-2, "Cannot setup device %s.", options.scsiDevice.c_str()); exitCode = 1; goto fail; } cdrScsi = cdr->scsiIf(); if ((di = cdr->diskInfo()) == NULL) { log_message(-2, "Cannot get disk information."); exitCode = 1; goto fail; } } // --------------------------------------------------------------------- // Process fullburn option for writing commands. // --------------------------------------------------------------------- if (options.command == SIMULATE || options.command == WRITE || options.command == COPY_CD) { if (options.fullBurn) { if (!options.driverId.empty() && options.driverId != "generic-mmc-raw") { log_message(-2, "You must use the generic-mmc-raw driver to use the " "full-burn option."); exitCode = 1; goto fail; } else { int mins = options.userCapacity ? options.userCapacity : Msf(cdr->diskInfo()->capacity).min(); log_message(2, "Burning entire %d mins disc.", mins); } } cdr->fullBurn(options.fullBurn); cdr->userCapacity(options.userCapacity); } // --------------------------------------------------------------------- // Setup secondary device for copy command. // --------------------------------------------------------------------- if (options.command == COPY_CD) { if (options.sourceScsiDevice != NULL && options.scsiDevice != options.sourceScsiDevice) { delSrcDevice = 1; srcCdr = setupDevice(READ_CD, options.sourceScsiDevice, options.sourceDriverId, 1, 1, 0, options.readingSpeed, false, false); if (srcCdr == NULL) { log_message(-2, "Cannot setup source device %s.", options.sourceScsiDevice); exitCode = 1; goto fail; } srcCdrScsi = srcCdr->scsiIf(); if ((srcDi = srcCdr->diskInfo()) == NULL) { log_message(-2, "Cannot get disk information from source device."); exitCode = 1; goto fail; } } else { srcCdr = cdr; srcDi = di; } } if (options.remoteMode) options.pause = false; // --------------------------------------------------------------------- // Main command dispatch. // --------------------------------------------------------------------- switch (options.command) { case READ_CDDB: if ((exitCode = readCddb(options, toc)) == 0) { log_message(1, "Writing CD-TEXT populated toc-file \"%s\".", options.tocFile.c_str()); if (toc->write(options.tocFile) != 0) exitCode = 2; } break; case SCAN_BUS: scanBus(); break; case DRIVE_INFO: showDriveInfo(cdr->driveInfo(true)); break; case SHOW_TOC: showToc(toc, options); if (toc->check() > 1) { log_message(-2, "Toc file \"%s\" is inconsistent.", options.tocFile.c_str()); } break; case TOC_INFO: showTocInfo(toc, options.tocFile); if (toc->check() > 1) { log_message(-2, "Toc file \"%s\" is inconsistent.", options.tocFile.c_str()); } break; case TOC_SIZE: showTocSize(toc, options.tocFile); if (toc->check() > 1) { log_message(-2, "Toc file \"%s\" is inconsistent.", options.tocFile.c_str()); } break; case SHOW_DATA: showData(toc, options.swap); break; case READ_TEST: log_message(1, "Starting read test..."); log_message(2, "Process can be aborted with QUIT signal " "(usually CTRL-\\)."); if (writeDiskAtOnce(toc, NULL, options.fifoBuffers, options.swap, 1, options.writingSpeed) != 0) { log_message(-2, "Read test failed."); exitCode = 1; goto fail; } break; case DISK_INFO: showDiskInfo(di); break; case CDTEXT: showCDText(cdr, options); break; case DISCID: if (di->valid.empty && di->empty) { log_message(-2, "Inserted disk is empty."); exitCode = 1; goto fail; } cdr->subChanReadMode(options.readSubchanMode); cdr->rawDataReading(options.readRaw); cdr->mode2Mixed(options.mode2Mixed); cdr->fastTocReading(true); cdr->taoSource(options.taoSource); if (options.taoSourceAdjust >= 0) cdr->taoSourceAdjust(options.taoSourceAdjust); cdr->force(options.force); if ((toc = cdr->readDiskToc(options.session, (options.dataFilename == NULL) ? "data.wav" : options.dataFilename)) == NULL) { cdr->rezeroUnit(0); exitCode = 1; goto fail; } else { cdr->rezeroUnit(0); if (options.printQuery) printCddbQuery(toc); else readCddb(options, toc, true); } break; case MSINFO: switch (showMultiSessionInfo(di)) { case 0: log_message(2, "msinfo: Session is appendable"); exitCode = 0; break; case 1: // CD-R is not empty and not appendable log_message(2, "msinfo: CD-R is not empty and not appendable"); exitCode = 2; break; case 2: // cannot determine state log_message(2, "msinfo: cannot determine state"); exitCode = 3; break; default: // everthing else is an error log_message(2, "msinfo: command error"); exitCode = 1; break; } break; case READ_TOC: if (di->valid.empty && di->empty) { log_message(-2, "Inserted disk is empty."); exitCode = 1; goto fail; } log_message(1, "Reading toc data..."); if (access(options.tocFile.c_str(), R_OK) == 0) { log_message(-2, "File \"%s\" exists, will not overwrite.", options.tocFile.c_str()); exitCode = 1; goto fail; } cdr->subChanReadMode(options.readSubchanMode); cdr->rawDataReading(options.readRaw); cdr->mode2Mixed(options.mode2Mixed); cdr->fastTocReading(options.fastToc); cdr->taoSource(options.taoSource); if (options.taoSourceAdjust >= 0) cdr->taoSourceAdjust(options.taoSourceAdjust); cdr->force(options.force); if ((toc = cdr->readDiskToc(options.session, (options.dataFilename == NULL) ? "data.wav" : options.dataFilename)) == NULL) { cdr->rezeroUnit(0); exitCode = 1; goto fail; } else { cdr->rezeroUnit(0); if (options.withCddb) { if (readCddb(options, toc) == 0) { log_message(2, "CD-TEXT data was added to toc-file."); } } { ofstream out(options.tocFile); if (!out) { log_message(-2, "Cannot open \"%s\" for writing: %s", options.tocFile.c_str(), strerror(errno)); exitCode = 1; goto fail; } toc->print(out, filePrintParams); } log_message(1, "Reading of toc data finished successfully."); } break; case READ_CD: if (di->valid.empty && di->empty) { log_message(-2, "Inserted disk is empty."); exitCode = 1; goto fail; } log_message(1, "Reading toc and track data..."); if (access(options.tocFile.c_str(), R_OK) == 0) { log_message(-2, "File \"%s\" exists, will not overwrite.", options.tocFile.c_str()); exitCode = 1; goto fail; } cdr->subChanReadMode(options.readSubchanMode); cdr->rawDataReading(options.readRaw); cdr->mode2Mixed(options.mode2Mixed); cdr->taoSource(options.taoSource); if (options.taoSourceAdjust >= 0) cdr->taoSourceAdjust(options.taoSourceAdjust); cdr->paranoiaMode(options.paranoiaMode); cdr->fastTocReading(options.fastToc); cdr->remote(options.remoteMode, options.remoteFd); cdr->force(options.force); toc = cdr->readDisk(options.session, (options.dataFilename == NULL) ? "data.bin" : options.dataFilename); if (toc == NULL) { cdr->rezeroUnit(0); exitCode = 1; goto fail; } cdr->rezeroUnit(0); if (options.withCddb) { if (readCddb(options, toc) == 0) { log_message(2, "CD-TEXT data was added to toc-file."); } } { ofstream out(options.tocFile); if (!out) { log_message(-2, "Cannot open \"%s\" for writing: %s", options.tocFile.c_str(), strerror(errno)); exitCode = 1; goto fail; } toc->print(out, filePrintParams); } log_message(1, "Reading of toc and track data finished successfully."); break; case WRITE: if (!options.writeSimulate) cdr->simulate(false); // fall through case SIMULATE: if (di->valid.empty && !di->empty && (!di->valid.append || !di->append)) { log_message(-2, "Inserted disk is not empty and not appendable."); exitCode = 1; goto fail; } if (toc->length().lba() > di->capacity) { log_message((options.overburn ? -1 : -2), "Length of toc (%s, %ld blocks) exceeds capacity ", toc->length().str(), toc->length().lba()); log_message(0, "of CD-R (%s, %ld blocks).", Msf(di->capacity).str(), di->capacity); if (options.overburn) { log_message(-1, "Ignored because of option '--overburn'."); log_message(-1, "Some drives may fail to record this toc."); } else { log_message(-2, "Please use option '--overburn' to start" "recording anyway."); exitCode = 1; goto fail; } } if (options.multiSession) { if (cdr->multiSession(1) != 0) { log_message(-2, "This driver does not support " "multi session discs."); exitCode = 1; goto fail; } } if (options.writingSpeed >= 0) { if (cdr->speed(options.writingSpeed) != 0) { log_message(-2, "Writing speed %d not supported by device.", options.writingSpeed); exitCode = 1; goto fail; } } cdr->bufferUnderRunProtection(options.bufferUnderrunProtection); cdr->writeSpeedControl(options.writeSpeedControl); cdr->force(options.force); cdr->remote(options.remoteMode, options.remoteFd); switch (cdr->checkToc(toc)) { case 0: // OK break; case 1: // warning if (!options.force && !options.remoteMode) { log_message(-2, "Toc-file \"%s\" may create undefined " "results.", options.tocFile.c_str()); log_message(-2, "Use option --force to use it anyway."); exitCode = 1; goto fail; } break; default: // error log_message(-2, "Toc-file \"%s\" is not suitable for this drive.", options.tocFile.c_str()); exitCode = 1; goto fail; break; } log_message(1, "Starting write "); if (cdr->simulate()) { log_message(1, "simulation "); } log_message(1, "at speed %d...", cdr->speed()); if (cdr->multiSession() != 0) { log_message(1, "Using multi session mode."); } if (options.pause) { log_message(1, "Pausing 10 seconds - hit CTRL-C to abort."); sleep(10); } log_message(2, "Process can be aborted with QUIT signal " "(usually CTRL-\\)."); if (cdr->preventMediumRemoval(1) != 0) { exitCode = 1; goto fail; } if (writeDiskAtOnce(toc, cdr, options.fifoBuffers, options.swap, 0, 0) != 0) { if (cdr->simulate()) { log_message(-2, "Simulation failed."); } else { log_message(-2, "Writing failed."); } cdr->preventMediumRemoval(0); cdr->rezeroUnit(0); exitCode = 1; goto fail; } if (cdr->simulate()) { log_message(1, "Simulation finished successfully."); } else { log_message(1, "Writing finished successfully."); } cdr->rezeroUnit(0); if (cdr->preventMediumRemoval(0) != 0) { exitCode = 1; goto fail; } if (options.eject) { cdr->loadUnload(1); } break; case COPY_CD: if (cdr != srcCdr) { if (di->valid.empty && !di->empty && (!di->valid.append || !di->append)) { log_message(-2, "Medium in recorder device is not empty" "and not appendable."); exitCode = 1; goto fail; } } if (srcDi->valid.empty && srcDi->empty) { log_message(-2, "Medium in source device is empty."); exitCode = 1; goto fail; } cdr->simulate(options.writeSimulate); cdr->force(options.force); cdr->remote(options.remoteMode, options.remoteFd); cdr->bufferUnderRunProtection(options.bufferUnderrunProtection); cdr->writeSpeedControl(options.writeSpeedControl); if (options.multiSession) { if (cdr->multiSession(1) != 0) { log_message(-2, "This driver does not support multi" "session discs."); exitCode = 1; goto fail; } } if (options.writingSpeed >= 0) { if (cdr->speed(options.writingSpeed) != 0) { log_message(-2, "Writing speed %d not supported by device.", options.writingSpeed); exitCode = 1; goto fail; } } srcCdr->paranoiaMode(options.paranoiaMode); srcCdr->subChanReadMode(options.readSubchanMode); srcCdr->fastTocReading(options.fastToc); srcCdr->force(options.force); if (options.onTheFly) log_message(1, "Starting on-the-fly CD copy "); else log_message(1, "Starting CD copy "); if (cdr->simulate()) { log_message(1, "simulation "); } log_message(1, "at speed %d...", cdr->speed()); if (cdr->multiSession() != 0) { log_message(1, "Using multi session mode."); } if (options.onTheFly) { if (srcCdr == cdr) { log_message(-2, "Two different device are required " "for on-the-fly copying."); log_message(-2, "Please use option '--source-device x,y,z'."); exitCode = 1; goto fail; } if (copyCdOnTheFly(options, srcCdr, cdr) == 0) { log_message(1, "On-the-fly CD copying finished successfully."); } else { log_message(-2, "On-the-fly CD copying failed."); exitCode = 1; goto fail; } } else { if (srcCdr != cdr) srcCdr->remote(options.remoteMode, options.remoteFd); if (copyCd(options, srcCdr, cdr) == 0) { log_message(1, "CD copying finished successfully."); } else { log_message(-2, "CD copying failed."); exitCode = 1; goto fail; } } break; case BLANK: if (options.writingSpeed >= 0) { if (cdr->speed(options.writingSpeed) != 0) { log_message(-2, "Blanking speed %d not supported by device.", options.writingSpeed); exitCode = 1; goto fail; } } cdr->remote(options.remoteMode, options.remoteFd); cdr->simulate(options.writeSimulate); log_message(1, "Blanking disk..."); if (cdr->blankDisk(options.blankingMode) != 0) { log_message(-2, "Blanking failed."); exitCode = 1; goto fail; } if (options.eject) cdr->loadUnload(1); break; case UNLOCK: log_message(1, "Trying to unlock drive..."); cdr->abortDao(); if (cdr->preventMediumRemoval(0) != 0) { exitCode = 1; goto fail; } if (options.eject) cdr->loadUnload(1); break; case UNKNOWN: assert(0); break; case SHOW_VERSION: case LAST_CMD: /* To avoid warning */ break; } fail: delete cdr; if (delSrcDevice) delete srcCdr; delete cdrScsi; if (delSrcDevice) delete srcCdrScsi; delete toc; #ifdef __CYGWIN__ if (isNT) { DWORD bytes; if (fh) { if (!DeviceIoControl (fh, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &bytes, NULL)) log_message(-2, "Couldn't unlock device %s!", devstr); else log_message(2, "Device %s unlocked.", devstr); CloseHandle (fh); } } #endif exit(exitCode); } �����������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/port.cc�������������������������������������������������������������������0000664�0000000�0000000�00000016607�15114537466�0016746�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <andreas@daneb.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 * (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. */ #include <config.h> #include <unistd.h> #include <signal.h> #include <errno.h> #include <string.h> #ifdef USE_POSIX_THREADS #include <pthread.h> #endif #if defined(HAVE_USLEEP) #else #include <sys/time.h> #include <sys/types.h> #endif #ifdef __CYGWIN__ #include <windows.h> #endif #ifdef UNIXWARE #include <sys/priocntl.h> #include <sys/fppriocntl.h> extern uid_t geteuid(); #endif #include "log.h" /* Select POSIX scheduler interface for real time scheduling if possible */ #ifdef USE_POSIX_THREADS #undef LINUX_QNX_SCHEDULING #if (defined HAVE_PTHREAD_GETSCHEDPARAM) && (defined HAVE_SCHED_GET_PRIORITY_MAX) && (defined HAVE_PTHREAD_ATTR_SETSCHEDPOLICY) && (defined HAVE_PTHREAD_ATTR_SETSCHEDPARAM) && (defined HAVE_PTHREAD_SETSCHEDPARAM) && (!defined LINUX_QNX_SCHEDULING) #define POSIX_SCHEDULING #endif #else #if (defined HAVE_SCHED_GETPARAM) && (defined HAVE_SCHED_GET_PRIORITY_MAX) && (defined HAVE_SCHED_SETSCHEDULER) && (!defined LINUX_QNX_SCHEDULING) #define POSIX_SCHEDULING #endif #endif #if defined LINUX_QNX_SCHEDULING #include <sys/types.h> #define SCHED_OTHER 0 #define SCHED_FIFO 1 #define SCHED_RR 2 struct sched_param { unsigned int priority; int fork_penalty_threshold; unsigned int starvation_threshold; unsigned int ts_max; unsigned int run_q, run_q_min, run_q_max; }; extern "C" int sched_setparam __P((pid_t __pid, const struct sched_param *__param)); extern "C" int sched_getparam __P((pid_t __pid, struct sched_param *__param)); extern "C" int sched_setscheduler __P((pid_t __pid, int __policy, const struct sched_param *__param)); extern "C" int sched_getscheduler __P((pid_t __pid)); #elif defined POSIX_SCHEDULING #ifdef HAVE_SCHED_H #include <sched.h> #endif #endif #include "port.h" #include "log.h" void mSleep(long milliSeconds) { #if defined(HAVE_USLEEP) usleep(milliSeconds * 1000); #else struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 1000 * milliSeconds; select(0, NULL, NULL, NULL, &tv); #endif } // Installs signal handler for signal 'sig' that will stay installed after // it is called. void installSignalHandler(int sig, SignalHandler handler) { struct sigaction action; memset(&action, 0, sizeof(action)); #ifdef UNIXWARE action.sa_handler = (void(*)()) handler; #else action.sa_handler = handler; #endif sigemptyset(&(action.sa_mask)); if (sigaction(sig, &action, NULL) != 0) log_message(-2, "Cannot install signal handler: %s", strerror(errno)); } // Blocks specified signal. void blockSignal(int sig) { sigset_t set; sigemptyset(&set); sigaddset(&set, sig); #ifdef USE_POSIX_THREADS #ifdef HAVE_PTHREAD_SIGMASK pthread_sigmask(SIG_BLOCK, &set, NULL); #endif #else sigprocmask(SIG_BLOCK, &set, NULL); #endif } // Unblocks specified signal. void unblockSignal(int sig) { sigset_t set; sigemptyset(&set); sigaddset(&set, sig); #ifdef USE_POSIX_THREADS #ifdef HAVE_PTHREAD_SIGMASK pthread_sigmask(SIG_UNBLOCK, &set, NULL); #endif #else sigprocmask(SIG_UNBLOCK, &set, NULL); #endif } /* Sets real time scheduling. * int priority: priority which is subtracted from the maximum priority * Return: 0: OK * 1: no permissions * 2: real time scheduling not available * 3: error occured */ int setRealTimeScheduling(int priority) { #if defined(__CYGWIN__) if (!SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS)) { log_message(-1, "Cannot set real time priority class."); return 3; } if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL)) { log_message(-1, "Cannot set real time priority."); return 3; } log_message(5, "Using WIN32 real time scheduling."); #elif defined(USE_POSIX_THREADS) && defined(POSIX_SCHEDULING) struct sched_param schedp; int schedPolicy; if (geteuid() != 0) { return 1; } pthread_getschedparam(pthread_self(), &schedPolicy, &schedp); schedp.sched_priority = sched_get_priority_max(SCHED_RR) - priority; if (pthread_setschedparam(pthread_self(), SCHED_RR, &schedp) < 0) { log_message(-1, "Cannot setup real time scheduling: %s", strerror(errno)); return 3; } else { log_message(5, "Using pthread POSIX real time scheduling."); } #elif defined(LINUX_QNX_SCHEDULING) struct sched_param schedp; if (geteuid() != 0) { return 1; } sched_getparam (0, &schedp); schedp.run_q_min = schedp.run_q_max = 2; if (sched_setscheduler (0, SCHED_RR, &schedp) < 0) { log_message(-1, "Cannot setup real time scheduling: %s", strerror(errno)); return 3; } else { log_message(5, "Using Linux QNX real time scheduling."); } #elif defined POSIX_SCHEDULING struct sched_param schedp; if (geteuid() != 0) { return 1; } sched_getparam (0, &schedp); schedp.sched_priority = sched_get_priority_max (SCHED_RR) - priority; if (sched_setscheduler (0, SCHED_RR, &schedp) < 0) { log_message(-1, "Cannot setup real time scheduling: %s", strerror(errno)); return 3; } else { log_message(5, "Using POSIX real time scheduling."); } #elif defined UNIXWARE /* Switch to fixed priority scheduling for this process */ pcinfo_t pci; pcparms_t pcp; fpparms_t *fp; if (geteuid() != 0) { return 1; } /* set fixed priority class */ strcpy(pci.pc_clname, "FP"); fp = (fpparms_t *) &pcp.pc_clparms; fp->fp_pri = FP_NOCHANGE; fp->fp_tqsecs = (ulong_t) FP_TQDEF; fp->fp_tqnsecs = FP_TQDEF; if (priocntl(P_PID, 0, PC_GETCID, (void *) &pci) < 0) { log_message(-1, "priocntl PC_GETCID failed"); return 3; } pcp.pc_cid = pci.pc_cid; if (priocntl(P_PID, getpid(), PC_SETPARMS, (void *) &pcp) < 0) { log_message(-1, "priocntl PC_SETPARMS failed"); return 3; } log_message(5, "Now running in fixed-priority scheduling mode."); #else return 2; #endif return 0; } // Give up root privileges. Returns true if succeeded or no action was // taken. bool giveUpRootPrivileges() { if (geteuid() != getuid()) { #if defined(HAVE_SETREUID) if (setreuid((uid_t)-1, getuid()) != 0) return false; #elif defined(HAVE_SETEUID) if (seteuid(getuid()) != 0) return false; #elif defined(HAVE_SETUID) if (setuid(getuid()) != 0) return false; #else return false; #endif } if (getegid() != getgid()) { #if defined(HAVE_SETREGID) if (setregid((gid_t)-1, getgid()) != 0) return false; #elif defined(HAVE_SETEGID) if (setegid(getgid()) != 0) return false; #elif defined(HAVE_SETGID) if (setgid(getgid()) != 0) return false; #else return false; #endif } return true; } �������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/port.h��������������������������������������������������������������������0000664�0000000�0000000�00000002204�15114537466�0016574�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <andreas@daneb.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 * (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. */ #ifndef __PORT_H__ #define __PORT_H__ #include "config.h" typedef RETSIGTYPE (*SignalHandler)(int); void mSleep(long milliSeconds); void installSignalHandler(int sig, SignalHandler); void blockSignal(int sig); void unblockSignal(int sig); int setRealTimeScheduling(int priority); bool giveUpRootPrivileges(); #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/remote.h������������������������������������������������������������������0000664�0000000�0000000�00000004663�15114537466�0017116�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2000 Andreas Mueller <mueller@daneb.ping.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 * (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. */ /* * $Log: remote.h,v $ * Revision 1.6 2004/02/12 01:13:31 poolshark * Merge from gnome2 branch * * Revision 1.5.4.1 2004/01/12 20:53:33 poolshark * Added writer buffer fill in Progress Message structure * * Revision 1.5 2001/10/01 18:08:41 andreasm * Enabled remote progress messages for blanking. * * Revision 1.4 2000/11/05 19:20:59 andreasm * Unified progress messages sent from cdrdao to gcdmaster. * * Revision 1.3 2000/10/08 16:39:41 andreasm * Remote progress message now always contain the track relative and total * progress and the total number of processed tracks. * * Revision 1.2 2000/04/23 16:29:50 andreasm * Updated to state of my private development environment. * * Revision 1.2 1999/12/15 20:31:46 mueller * Added remote messages for 'read-cd' progress used by a GUI. * * Revision 1.1 1999/11/07 09:17:08 mueller * Initial revision * */ #ifndef __REMOTE_H__ #define __REMOTE_H__ #define PGSMSG_MIN PGSMSG_RCD_ANALYZING #define PGSMSG_RCD_ANALYZING 1 #define PGSMSG_RCD_EXTRACTING 2 #define PGSMSG_WCD_LEADIN 3 #define PGSMSG_WCD_DATA 4 #define PGSMSG_WCD_LEADOUT 5 #define PGSMSG_BLK 6 #define PGSMSG_MAX PGSMSG_BLK #define PSGMSG_MINSIZE 24 struct ProgressMsg { int status; // see PGSMSG_* constants int totalTracks; // total number of tracks int track; // actually written track int trackProgress; // progress for current track 0..1000 int totalProgress; // total writing progress 0..1000 int bufferFillRate; // buffer fill rate 0..100 int writerFillRate; // device write buffer fill rate 0..100 }; #endif �����������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/dao/sg_err.cc�����������������������������������������������������������������0000664�0000000�0000000�00000064742�15114537466�0017246�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdio.h> #include <stdlib.h> #include "sg_err.h" #include "log.h" /* This file is a huge cut, paste and hack from linux/drivers/scsi/constant.c * which I guess was written by: * Copyright (C) 1993, 1994, 1995 Eric Youngdale * The rest of this is: * Copyright (C) 1999 D. Gilbert * * 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, or (at your option) * any later version. * * ASCII values for a number of symbolic constants, printing functions, etc. * * Some of the tables have been updated for SCSI 2. * * Version 0.61 (990519) */ static const unsigned char scsi_command_size[8] = { 6, 10, 10, 12, 12, 12, 10, 10 }; #define COMMAND_SIZE(opcode) scsi_command_size[((opcode) >> 5) & 7] static const char unknown[] = "UNKNOWN"; static const char * group_0_commands[] = { /* 00-03 */ "Test Unit Ready", "Rezero Unit", unknown, "Request Sense", /* 04-07 */ "Format Unit", "Read Block Limits", unknown, "Reasssign Blocks", /* 08-0d */ "Read (6)", unknown, "Write (6)", "Seek (6)", unknown, unknown, /* 0e-12 */ unknown, "Read Reverse", "Write Filemarks", "Space", "Inquiry", /* 13-16 */ "Verify", "Recover Buffered Data", "Mode Select", "Reserve", /* 17-1b */ "Release", "Copy", "Erase", "Mode Sense", "Start/Stop Unit", /* 1c-1d */ "Receive Diagnostic", "Send Diagnostic", /* 1e-1f */ "Prevent/Allow Medium Removal", unknown, }; static const char *group_1_commands[] = { /* 20-22 */ unknown, unknown, unknown, /* 23-28 */ unknown, "Define window parameters", "Read Capacity", unknown, unknown, "Read (10)", /* 29-2d */ "Read Generation", "Write (10)", "Seek (10)", "Erase", "Read updated block", /* 2e-31 */ "Write Verify","Verify", "Search High", "Search Equal", /* 32-34 */ "Search Low", "Set Limits", "Prefetch or Read Position", /* 35-37 */ "Synchronize Cache","Lock/Unlock Cache", "Read Defect Data", /* 38-3c */ "Medium Scan", "Compare", "Copy Verify", "Write Buffer", "Read Buffer", /* 3d-3f */ "Update Block", "Read Long", "Write Long", }; static const char *group_2_commands[] = { /* 40-41 */ "Change Definition", "Write Same", /* 42-44 */ "Read sub-channel", "Read TOC", "Read header", /* 45-47 */ "Play audio (10)", "Get configuration", "Play audio msf", /* 48 */ "Play audio track/index", /* 49-4a */ "Play track relative (10)", "Get event/status notification", /* 4b */ "Pause/resume", /* 4c-4f */ "Log Select", "Log Sense", "Stop play/scan", unknown, /* 50-55 */ unknown, "Read disc information", "Read track information", "Reserve track", "Send OPC information", "Mode Select (10)", /* 56-5b */ unknown, unknown, "Repair track", unknown, "Mode Sense (10)", "Close track/session", /* 5c-5f */ "Read buffer capacity", "Send cue sheet", unknown, }; /* The following are 12 byte commands in group 5 */ static const char *group_5_commands[] = { /* a0-a5 */ unknown, "Blank", unknown, "Send key", "Report key", "Move medium/play audio(12)", /* a6-a9 */ "Exchange medium", "Set read ahead", "Read(12)", "Play track relative(12)", /* aa-ae */ "Write(12)", "Read media s/n", "Erase(12)", "Read disc structure", "Write and verify(12)", /* af-b1 */ "Verify(12)", "Search data high(12)", "Search data equal(12)", /* b2-b4 */ "Search data low(12)", "Set limits(12)", unknown, /* b5-b6 */ "Request volume element address", "Send volume tag", /* b7-b9 */ "Read defect data(12)", "Read element status", "Read CD MSF", /* ba-bf */ unknown, "Set CD speed", unknown, "Mechanism status", "Read CD", "Send disc structure", }; #define group(opcode) (((opcode) >> 5) & 7) #define RESERVED_GROUP 0 #define VENDOR_GROUP 1 static const char **commands[] = { group_0_commands, group_1_commands, group_2_commands, (const char **) RESERVED_GROUP, (const char **) RESERVED_GROUP, group_5_commands, (const char **) VENDOR_GROUP, (const char **) VENDOR_GROUP }; static const char reserved[] = "RESERVED"; static const char vendor[] = "VENDOR SPECIFIC"; static void print_opcode(int opcode) { const char **table = commands[ group(opcode) ]; switch ((unsigned long) table) { case RESERVED_GROUP: log_message(0, "%s(0x%02x) ", reserved, opcode); break; case VENDOR_GROUP: log_message(0, "%s(0x%02x) ", vendor, opcode); break; default: if (table[opcode & 0x1f] != unknown) log_message(0, "%s ",table[opcode & 0x1f]); else log_message(0, "%s(0x%02x) ", unknown, opcode); break; } } void sg_print_command (const unsigned char * command) { int i,s; print_opcode(command[0]); for ( i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) log_message(0, "%02x ", command[i]); log_message(0, ""); } const char* sg_strcommand(unsigned char opcode) { static char buf[8]; const char** table = commands[group(opcode)]; switch ((unsigned long)table) { case RESERVED_GROUP: case VENDOR_GROUP: break; default: if (table[opcode & 0x1f] != unknown) return table[opcode & 0x1f]; break; } sprintf(buf, "0x%02x", opcode); return buf; } const char* sg_strcmdopts(const unsigned char* cdb) { static char buf[32]; switch (cdb[0]) { case 0x1a: case 0x5a: snprintf(buf, sizeof(buf), " (page %02x.%02x len %d)", cdb[2] & 0x3f, cdb[3], cdb[8]); return buf; case 0x43: snprintf(buf, sizeof(buf), " (fmt %d num %d)", cdb[2] & 0x0f, cdb[6]); return buf; default: return ""; } } static const char * statuses[] = { /* 0-4 */ "Good", "Check Condition", "Condition Met", unknown, "Busy", /* 5-9 */ unknown, unknown, unknown, "Intermediate", unknown, /* a-c */ "Intermediate-Condition Met", unknown, "Reservation Conflict", /* d-10 */ unknown, unknown, unknown, unknown, /* 11-14 */ "Command Terminated", unknown, unknown, "Queue Full", /* 15-1a */ unknown, unknown, unknown, unknown, unknown, unknown, /* 1b-1f */ unknown, unknown, unknown, unknown, unknown, }; void sg_print_target_status (int target_status) { /* status = (status >> 1) & 0xf; */ /* already done */ log_message(0, "%s ",statuses[target_status]); } #define D 0x001 /* DIRECT ACCESS DEVICE (disk) */ #define T 0x002 /* SEQUENTIAL ACCESS DEVICE (tape) */ #define L 0x004 /* PRINTER DEVICE */ #define P 0x008 /* PROCESSOR DEVICE */ #define W 0x010 /* WRITE ONCE READ MULTIPLE DEVICE */ #define R 0x020 /* READ ONLY (CD-ROM) DEVICE */ #define S 0x040 /* SCANNER DEVICE */ #define O 0x080 /* OPTICAL MEMORY DEVICE */ #define M 0x100 /* MEDIA CHANGER DEVICE */ #define C 0x200 /* COMMUNICATION DEVICE */ struct error_info{ unsigned char code1, code2; unsigned short int devices; const char * text; }; struct error_info2{ unsigned char code1, code2_min, code2_max; unsigned short int devices; const char * text; }; static struct error_info2 additional2[] = { {0x40,0x00,0x7f,D,"Ram failure (%x)"}, {0x40,0x80,0xff,D|T|L|P|W|R|S|O|M|C,"Diagnostic failure on component (%x)"}, {0x41,0x00,0xff,D,"Data path failure (%x)"}, {0x42,0x00,0xff,D,"Power-on or self-test failure (%x)"}, {0, 0, 0, 0, NULL} }; static struct error_info additional[] = { {0x00,0x01,T,"Filemark detected"}, {0x00,0x02,T|S,"End-of-partition/medium detected"}, {0x00,0x03,T,"Setmark detected"}, {0x00,0x04,T|S,"Beginning-of-partition/medium detected"}, {0x00,0x05,T|S,"End-of-data detected"}, {0x00,0x06,D|T|L|P|W|R|S|O|M|C,"I/O process terminated"}, {0x00,0x11,R,"Audio play operation in progress"}, {0x00,0x12,R,"Audio play operation paused"}, {0x00,0x13,R,"Audio play operation successfully completed"}, {0x00,0x14,R,"Audio play operation stopped due to error"}, {0x00,0x15,R,"No current audio status to return"}, {0x01,0x00,D|W|O,"No index/sector signal"}, {0x02,0x00,D|W|R|O|M,"No seek complete"}, {0x03,0x00,D|T|L|W|S|O,"Peripheral device write fault"}, {0x03,0x01,T,"No write current"}, {0x03,0x02,T,"Excessive write errors"}, {0x04,0x00,D|T|L|P|W|R|S|O|M|C, "Logical unit not ready, cause not reportable"}, {0x04,0x01,D|T|L|P|W|R|S|O|M|C, "Logical unit is in process of becoming ready"}, {0x04,0x02,D|T|L|P|W|R|S|O|M|C, "Logical unit not ready, initializing command required"}, {0x04,0x03,D|T|L|P|W|R|S|O|M|C, "Logical unit not ready, manual intervention required"}, {0x04,0x04,D|T|L|O,"Logical unit not ready, format in progress"}, {0x05,0x00,D|T|L|W|R|S|O|M|C,"Logical unit does not respond to selection"}, {0x06,0x00,D|W|R|O|M,"No reference position found"}, {0x07,0x00,D|T|L|W|R|S|O|M,"Multiple peripheral devices selected"}, {0x08,0x00,D|T|L|W|R|S|O|M|C,"Logical unit communication failure"}, {0x08,0x01,D|T|L|W|R|S|O|M|C,"Logical unit communication time-out"}, {0x08,0x02,D|T|L|W|R|S|O|M|C,"Logical unit communication parity error"}, {0x09,0x00,D|T|W|R|O,"Track following error"}, {0x09,0x01,W|R|O,"Tracking servo failure"}, {0x09,0x02,W|R|O,"Focus servo failure"}, {0x09,0x03,W|R|O,"Spindle servo failure"}, {0x0A,0x00,D|T|L|P|W|R|S|O|M|C,"Error log overflow"}, {0x0C,0x00,T|S,"Write error"}, {0x0C,0x01,D|W|O,"Write error recovered with auto reallocation"}, {0x0C,0x02,D|W|O,"Write error - auto reallocation failed"}, {0x10,0x00,D|W|O,"Id crc or ecc error"}, {0x11,0x00,D|T|W|R|S|O,"Unrecovered read error"}, {0x11,0x01,D|T|W|S|O,"Read retries exhausted"}, {0x11,0x02,D|T|W|S|O,"Error too long to correct"}, {0x11,0x03,D|T|W|S|O,"Multiple read errors"}, {0x11,0x04,D|W|O,"Unrecovered read error - auto reallocate failed"}, {0x11,0x05,W|R|O,"L-ec uncorrectable error"}, {0x11,0x06,W|R|O,"Circ unrecovered error"}, {0x11,0x07,W|O,"Data resynchronization error"}, {0x11,0x08,T,"Incomplete block read"}, {0x11,0x09,T,"No gap found"}, {0x11,0x0A,D|T|O,"Miscorrected error"}, {0x11,0x0B,D|W|O,"Unrecovered read error - recommend reassignment"}, {0x11,0x0C,D|W|O,"Unrecovered read error - recommend rewrite the data"}, {0x12,0x00,D|W|O,"Address mark not found for id field"}, {0x13,0x00,D|W|O,"Address mark not found for data field"}, {0x14,0x00,D|T|L|W|R|S|O,"Recorded entity not found"}, {0x14,0x01,D|T|W|R|O,"Record not found"}, {0x14,0x02,T,"Filemark or setmark not found"}, {0x14,0x03,T,"End-of-data not found"}, {0x14,0x04,T,"Block sequence error"}, {0x15,0x00,D|T|L|W|R|S|O|M,"Random positioning error"}, {0x15,0x01,D|T|L|W|R|S|O|M,"Mechanical positioning error"}, {0x15,0x02,D|T|W|R|O,"Positioning error detected by read of medium"}, {0x16,0x00,D|W|O,"Data synchronization mark error"}, {0x17,0x00,D|T|W|R|S|O,"Recovered data with no error correction applied"}, {0x17,0x01,D|T|W|R|S|O,"Recovered data with retries"}, {0x17,0x02,D|T|W|R|O,"Recovered data with positive head offset"}, {0x17,0x03,D|T|W|R|O,"Recovered data with negative head offset"}, {0x17,0x04,W|R|O,"Recovered data with retries and/or circ applied"}, {0x17,0x05,D|W|R|O,"Recovered data using previous sector id"}, {0x17,0x06,D|W|O,"Recovered data without ecc - data auto-reallocated"}, {0x17,0x07,D|W|O,"Recovered data without ecc - recommend reassignment"}, {0x18,0x00,D|T|W|R|O,"Recovered data with error correction applied"}, {0x18,0x01,D|W|R|O,"Recovered data with error correction and retries applied"}, {0x18,0x02,D|W|R|O,"Recovered data - data auto-reallocated"}, {0x18,0x03,R,"Recovered data with circ"}, {0x18,0x04,R,"Recovered data with lec"}, {0x18,0x05,D|W|R|O,"Recovered data - recommend reassignment"}, {0x19,0x00,D|O,"Defect list error"}, {0x19,0x01,D|O,"Defect list not available"}, {0x19,0x02,D|O,"Defect list error in primary list"}, {0x19,0x03,D|O,"Defect list error in grown list"}, {0x1A,0x00,D|T|L|P|W|R|S|O|M|C,"Parameter list length error"}, {0x1B,0x00,D|T|L|P|W|R|S|O|M|C,"Synchronous data transfer error"}, {0x1C,0x00,D|O,"Defect list not found"}, {0x1C,0x01,D|O,"Primary defect list not found"}, {0x1C,0x02,D|O,"Grown defect list not found"}, {0x1D,0x00,D|W|O,"Miscompare during verify operation"}, {0x1E,0x00,D|W|O,"Recovered id with ecc correction"}, {0x20,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid command operation code"}, {0x21,0x00,D|T|W|R|O|M,"Logical block address out of range"}, {0x21,0x01,M,"Invalid element address"}, {0x22,0x00,D,"Illegal function (should use 20 00, 24 00, or 26 00)"}, {0x24,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid field in cdb"}, {0x25,0x00,D|T|L|P|W|R|S|O|M|C,"Logical unit not supported"}, {0x26,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid field in parameter list"}, {0x26,0x01,D|T|L|P|W|R|S|O|M|C,"Parameter not supported"}, {0x26,0x02,D|T|L|P|W|R|S|O|M|C,"Parameter value invalid"}, {0x26,0x03,D|T|L|P|W|R|S|O|M|C,"Threshold parameters not supported"}, {0x27,0x00,D|T|W|O,"Write protected"}, {0x28,0x00,D|T|L|P|W|R|S|O|M|C,"Not ready to ready transition (medium may have changed)"}, {0x28,0x01,M,"Import or export element accessed"}, {0x29,0x00,D|T|L|P|W|R|S|O|M|C,"Power on, reset, or bus device reset occurred"}, {0x2A,0x00,D|T|L|W|R|S|O|M|C,"Parameters changed"}, {0x2A,0x01,D|T|L|W|R|S|O|M|C,"Mode parameters changed"}, {0x2A,0x02,D|T|L|W|R|S|O|M|C,"Log parameters changed"}, {0x2B,0x00,D|T|L|P|W|R|S|O|C,"Copy cannot execute since host cannot disconnect"}, {0x2C,0x00,D|T|L|P|W|R|S|O|M|C,"Command sequence error"}, {0x2C,0x01,S,"Too many windows specified"}, {0x2C,0x02,S,"Invalid combination of windows specified"}, {0x2D,0x00,T,"Overwrite error on update in place"}, {0x2F,0x00,D|T|L|P|W|R|S|O|M|C,"Commands cleared by another initiator"}, {0x30,0x00,D|T|W|R|O|M,"Incompatible medium installed"}, {0x30,0x01,D|T|W|R|O,"Cannot read medium - unknown format"}, {0x30,0x02,D|T|W|R|O,"Cannot read medium - incompatible format"}, {0x30,0x03,D|T,"Cleaning cartridge installed"}, {0x31,0x00,D|T|W|O,"Medium format corrupted"}, {0x31,0x01,D|L|O,"Format command failed"}, {0x32,0x00,D|W|O,"No defect spare location available"}, {0x32,0x01,D|W|O,"Defect list update failure"}, {0x33,0x00,T,"Tape length error"}, {0x36,0x00,L,"Ribbon, ink, or toner failure"}, {0x37,0x00,D|T|L|W|R|S|O|M|C,"Rounded parameter"}, {0x39,0x00,D|T|L|W|R|S|O|M|C,"Saving parameters not supported"}, {0x3A,0x00,D|T|L|W|R|S|O|M,"Medium not present"}, {0x3B,0x00,T|L,"Sequential positioning error"}, {0x3B,0x01,T,"Tape position error at beginning-of-medium"}, {0x3B,0x02,T,"Tape position error at end-of-medium"}, {0x3B,0x03,L,"Tape or electronic vertical forms unit not ready"}, {0x3B,0x04,L,"Slew failure"}, {0x3B,0x05,L,"Paper jam"}, {0x3B,0x06,L,"Failed to sense top-of-form"}, {0x3B,0x07,L,"Failed to sense bottom-of-form"}, {0x3B,0x08,T,"Reposition error"}, {0x3B,0x09,S,"Read past end of medium"}, {0x3B,0x0A,S,"Read past beginning of medium"}, {0x3B,0x0B,S,"Position past end of medium"}, {0x3B,0x0C,S,"Position past beginning of medium"}, {0x3B,0x0D,M,"Medium destination element full"}, {0x3B,0x0E,M,"Medium source element empty"}, {0x3D,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid bits in identify message"}, {0x3E,0x00,D|T|L|P|W|R|S|O|M|C,"Logical unit has not self-configured yet"}, {0x3F,0x00,D|T|L|P|W|R|S|O|M|C,"Target operating conditions have changed"}, {0x3F,0x01,D|T|L|P|W|R|S|O|M|C,"Microcode has been changed"}, {0x3F,0x02,D|T|L|P|W|R|S|O|M|C,"Changed operating definition"}, {0x3F,0x03,D|T|L|P|W|R|S|O|M|C,"Inquiry data has changed"}, {0x43,0x00,D|T|L|P|W|R|S|O|M|C,"Message error"}, {0x44,0x00,D|T|L|P|W|R|S|O|M|C,"Internal target failure"}, {0x45,0x00,D|T|L|P|W|R|S|O|M|C,"Select or reselect failure"}, {0x46,0x00,D|T|L|P|W|R|S|O|M|C,"Unsuccessful soft reset"}, {0x47,0x00,D|T|L|P|W|R|S|O|M|C,"Scsi parity error"}, {0x48,0x00,D|T|L|P|W|R|S|O|M|C,"Initiator detected error message received"}, {0x49,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid message error"}, {0x4A,0x00,D|T|L|P|W|R|S|O|M|C,"Command phase error"}, {0x4B,0x00,D|T|L|P|W|R|S|O|M|C,"Data phase error"}, {0x4C,0x00,D|T|L|P|W|R|S|O|M|C,"Logical unit failed self-configuration"}, {0x4E,0x00,D|T|L|P|W|R|S|O|M|C,"Overlapped commands attempted"}, {0x50,0x00,T,"Write append error"}, {0x50,0x01,T,"Write append position error"}, {0x50,0x02,T,"Position error related to timing"}, {0x51,0x00,T|O,"Erase failure"}, {0x52,0x00,T,"Cartridge fault"}, {0x53,0x00,D|T|L|W|R|S|O|M,"Media load or eject failed"}, {0x53,0x01,T,"Unload tape failure"}, {0x53,0x02,D|T|W|R|O|M,"Medium removal prevented"}, {0x54,0x00,P,"Scsi to host system interface failure"}, {0x55,0x00,P,"System resource failure"}, {0x57,0x00,R,"Unable to recover table-of-contents"}, {0x58,0x00,O,"Generation does not exist"}, {0x59,0x00,O,"Updated block read"}, {0x5A,0x00,D|T|L|P|W|R|S|O|M,"Operator request or state change input (unspecified)"}, {0x5A,0x01,D|T|W|R|O|M,"Operator medium removal request"}, {0x5A,0x02,D|T|W|O,"Operator selected write protect"}, {0x5A,0x03,D|T|W|O,"Operator selected write permit"}, {0x5B,0x00,D|T|L|P|W|R|S|O|M,"Log exception"}, {0x5B,0x01,D|T|L|P|W|R|S|O|M,"Threshold condition met"}, {0x5B,0x02,D|T|L|P|W|R|S|O|M,"Log counter at maximum"}, {0x5B,0x03,D|T|L|P|W|R|S|O|M,"Log list codes exhausted"}, {0x5C,0x00,D|O,"Rpl status change"}, {0x5C,0x01,D|O,"Spindles synchronized"}, {0x5C,0x02,D|O,"Spindles not synchronized"}, {0x60,0x00,S,"Lamp failure"}, {0x61,0x00,S,"Video acquisition error"}, {0x61,0x01,S,"Unable to acquire video"}, {0x61,0x02,S,"Out of focus"}, {0x62,0x00,S,"Scan head positioning error"}, {0x63,0x00,R,"End of user area encountered on this track"}, {0x64,0x00,R,"Illegal mode for this track"}, {0, 0, 0, NULL} }; static const char *snstext[] = { "None", /* There is no sense information */ "Recovered Error", /* The last command completed successfully but used error correction */ "Not Ready", /* The addressed target is not ready */ "Medium Error", /* Data error detected on the medium */ "Hardware Error", /* Controller or device failure */ "Illegal Request", "Unit Attention", /* Removable medium was changed, or the target has been reset */ "Data Protect", /* Access to the data is blocked */ "Blank Check", /* Reached unexpected written or unwritten region of the medium */ "Key=9", /* Vendor specific */ "Copy Aborted", /* COPY or COMPARE was aborted */ "Aborted Command", /* The target aborted the command */ "Equal", /* A SEARCH DATA command found data equal */ "Volume Overflow", /* Medium full with still data to be written */ "Miscompare", /* Source data and data on the medium do not agree */ "Key=15" /* Reserved */ }; /* Print sense information */ void sg_print_sense(const char * leadin, const unsigned char * sense_buffer) { int i, s; int sense_class, valid, code; const char * error = NULL; sense_class = (sense_buffer[0] >> 4) & 0x07; code = sense_buffer[0] & 0xf; valid = sense_buffer[0] & 0x80; if (sense_class == 7) { /* extended sense data */ s = sense_buffer[7] + 8; if(s > SG_ERR_MAX_SENSE_LEN) s = SG_ERR_MAX_SENSE_LEN; if (!valid) log_message(0, "[valid=0] "); log_message(0, "Info fld=%d, ", (int)((sense_buffer[3] << 24) | (sense_buffer[4] << 16) | (sense_buffer[5] << 8) | sense_buffer[6])); if (sense_buffer[2] & 0x80) log_message(0, "FMK "); /* current command has read a filemark */ if (sense_buffer[2] & 0x40) log_message(0, "EOM "); /* end-of-medium condition exists */ if (sense_buffer[2] & 0x20) log_message(0, "ILI "); /* incorrect block length requested */ switch (code) { case 0x0: error = "Current"; /* error concerns current command */ break; case 0x1: error = "Deferred"; /* error concerns some earlier command */ /* e.g., an earlier write to disk cache succeeded, but now the disk discovers that it cannot write the data */ break; default: error = "Invalid"; } log_message(0, "%s ", error); if (leadin) log_message(0, "%s: ", leadin); log_message(0, "sense key: 0x%02x: %s", sense_buffer[2] & 0x0f, snstext[sense_buffer[2] & 0x0f]); /* Check to see if additional sense information is available */ if(sense_buffer[7] + 7 < 13 || (sense_buffer[12] == 0 && sense_buffer[13] == 0)) goto done; for(i=0; additional[i].text; i++) if(additional[i].code1 == sense_buffer[12] && additional[i].code2 == sense_buffer[13]) log_message(0, "Additional sense indicates: %s", additional[i].text); for(i=0; additional2[i].text; i++) if(additional2[i].code1 == sense_buffer[12] && additional2[i].code2_min >= sense_buffer[13] && additional2[i].code2_max <= sense_buffer[13]) { log_message(0, "Additional sense indicates: "); log_message(0, additional2[i].text, sense_buffer[13]); log_message(0, ""); }; } else { /* non-extended sense data */ /* * Standard says: * sense_buffer[0] & 0200 : address valid * sense_buffer[0] & 0177 : vendor-specific error code * sense_buffer[1] & 0340 : vendor-specific * sense_buffer[1..3] : 21-bit logical block address */ if (leadin) log_message(0, "%s: ", leadin); if (sense_buffer[0] < 15) log_message(0, "old sense: key %s", snstext[sense_buffer[0] & 0x0f]); else log_message(0, "sns = %2x %2x", sense_buffer[0], sense_buffer[2]); log_message(0, "Non-extended sense class %d code 0x%0x", sense_class, code); s = 4; } done: log_message(0, "Raw sense data: "); for (i = 0; i < s; ++i) { if ((i > 0) && (0 == (i % 10))) log_message(0, ""); log_message(0, "0x%02x ", sense_buffer[i]); } log_message(0, ""); return; } static const char * hostbyte_table[]={ "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", "DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR", "DID_PASSTHROUGH", "DID_SOFT_ERROR", NULL}; void sg_print_host_status(int host_status) { static int maxcode=0; int i; if(! maxcode) { for(i = 0; hostbyte_table[i]; i++) ; maxcode = i-1; } log_message(0, "Host_status=0x%02x ", host_status); if(host_status > maxcode) { log_message(0, "is invalid "); return; } log_message(0, "(%s) ",hostbyte_table[host_status]); } static const char * driverbyte_table[]={ "DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA", "DRIVER_ERROR", "DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD", "DRIVER_SENSE", NULL}; static const char * driversuggest_table[]={"SUGGEST_OK", "SUGGEST_RETRY", "SUGGEST_ABORT", "SUGGEST_REMAP", "SUGGEST_DIE", unknown,unknown,unknown, "SUGGEST_SENSE",NULL}; void sg_print_driver_status(int driver_status) { static int driver_max =0 , suggest_max=0; int i; int dr = driver_status & DRIVER_MASK; int su = (driver_status & SUGGEST_MASK) >> 4; if(! driver_max) { for(i = 0; driverbyte_table[i]; i++) ; driver_max = i; for(i = 0; driversuggest_table[i]; i++) ; suggest_max = i; } log_message(0, "Driver_status=0x%02x ",driver_status); log_message(0, "(%s,%s) ", dr < driver_max ? driverbyte_table[dr]:"invalid", su < suggest_max ? driversuggest_table[su]:"invalid"); } int sg_chk_n_print(const char * leadin, int target_status, int host_status, int driver_status, const unsigned char * sense_buffer) { int done_leadin = 0; int done_sense = 0; if ((0 == target_status) && (0 == host_status) && (0 == driver_status)) return 1; /* No problems */ if (0 != target_status) { if (leadin) log_message(0, "%s: ", leadin); done_leadin = 1; sg_print_target_status(target_status); log_message(0, ""); if (sense_buffer && ((target_status == CHECK_CONDITION) || (target_status == COMMAND_TERMINATED))) { sg_print_sense(0, sense_buffer); done_sense = 1; } } if (0 != host_status) { if (leadin && (! done_leadin)) log_message(0, "%s: ", leadin); if (done_leadin) log_message(0, "plus...: "); else done_leadin = 1; sg_print_host_status(host_status); log_message(0, ""); } if (0 != driver_status) { if (leadin && (! done_leadin)) log_message(0, "%s: ", leadin); if (done_leadin) log_message(0, "plus...: "); else done_leadin = 1; sg_print_driver_status(driver_status); log_message(0, ""); if (sense_buffer && (! done_sense) && (DRIVER_SENSE & driver_status)) sg_print_sense(0, sense_buffer); } return 0; } int sg_err_category(int target_status, int host_status, int driver_status, const unsigned char * sense_buffer) { if ((0 == target_status) && (0 == host_status) && (0 == driver_status)) return SG_ERR_CAT_CLEAN; if ((CHECK_CONDITION == target_status) || (COMMAND_TERMINATED == target_status) || (DRIVER_SENSE & driver_status)) { if (sense_buffer) { if(RECOVERED_ERROR == sense_buffer[2]) return SG_ERR_CAT_RECOVERED; else if (UNIT_ATTENTION == (0x0f & sense_buffer[2])) { if (0x28 == sense_buffer[12]) return SG_ERR_CAT_MEDIA_CHANGED; if (0x29 == sense_buffer[12]) return SG_ERR_CAT_RESET; } } return SG_ERR_CAT_SENSE; } if (0 != host_status) { if ((DID_NO_CONNECT == host_status) || (DID_BUS_BUSY == host_status) || (DID_TIME_OUT == host_status)) return SG_ERR_CAT_TIMEOUT; } if (0 != driver_status) { if (DRIVER_TIMEOUT == driver_status) return SG_ERR_CAT_TIMEOUT; } return SG_ERR_CAT_OTHER; } int sg_get_command_size(unsigned char opcode) { return COMMAND_SIZE(opcode); } ������������������������������cdrdao-cdrdao-f00afb2/dao/sg_err.h������������������������������������������������������������������0000664�0000000�0000000�00000007167�15114537466�0017106�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef SG_ERR_H #define SG_ERR_H #include <scsi/scsi.h> /* cope with silly includes */ /* Feel free to copy and modify this GPL-ed code into your applications. */ /* Version 0.61 (990519) */ /* Some of the following error/status codes are exchanged between the various layers of the SCSI sub-system in Linux and should never reach the user. They are placed here for completeness. What appears here is copied from drivers/scsi/scsi.h which is not visible in the user space. */ /* The following are 'host_status' codes */ #ifndef DID_OK #define DID_OK 0x00 #endif #ifndef DID_NO_CONNECT #define DID_NO_CONNECT 0x01 /* Unable to connect before timeout */ #define DID_BUS_BUSY 0x02 /* Bus remain busy until timeout */ #define DID_TIME_OUT 0x03 /* Timed out for some other reason */ #define DID_BAD_TARGET 0x04 /* Bad target (id?) */ #define DID_ABORT 0x05 /* Told to abort for some other reason */ #define DID_PARITY 0x06 /* Parity error (on SCSI bus) */ #define DID_ERROR 0x07 /* Internal error */ #define DID_RESET 0x08 /* Reset by somebody */ #define DID_BAD_INTR 0x09 /* Received an unexpected interrupt */ #define DID_PASSTHROUGH 0x0a /* Force command past mid-level */ #define DID_SOFT_ERROR 0x0b /* The low-level driver wants a retry */ #endif /* The following are 'driver_status' codes */ #ifndef DRIVER_OK #define DRIVER_OK 0x00 #endif #ifndef DRIVER_BUSY #define DRIVER_BUSY 0x01 #define DRIVER_SOFT 0x02 #define DRIVER_MEDIA 0x03 #define DRIVER_ERROR 0x04 #define DRIVER_INVALID 0x05 #define DRIVER_TIMEOUT 0x06 #define DRIVER_HARD 0x07 #define DRIVER_SENSE 0x08 /* Sense_buffer has been set */ /* Following "suggests" are "or-ed" with one of previous 8 entries */ #define SUGGEST_RETRY 0x10 #define SUGGEST_ABORT 0x20 #define SUGGEST_REMAP 0x30 #define SUGGEST_DIE 0x40 #define SUGGEST_SENSE 0x80 #define SUGGEST_IS_OK 0xff #endif #ifndef DRIVER_MASK #define DRIVER_MASK 0x0f #endif #ifndef SUGGEST_MASK #define SUGGEST_MASK 0xf0 #endif #define SG_ERR_MAX_SENSE_LEN 16 /* The following "print" functions send ACSII to stdout */ extern void sg_print_command(const unsigned char * command); extern const char* sg_strcommand(unsigned char opcode); extern const char* sg_strcmdopts(const unsigned char* command); extern void sg_print_sense(const char * leadin, const unsigned char * sense_buffer); extern void sg_print_target_status(int target_status); extern void sg_print_host_status(int host_status); extern void sg_print_driver_status(int driver_status); /* sg_chk_n_print() returns 1 quietly if there are no errors/warnings else it prints to standard output and returns 0. */ extern int sg_chk_n_print(const char * leadin, int target_status, int host_status, int driver_status, const unsigned char * sense_buffer); /* The following "category" function returns one of the following */ #define SG_ERR_CAT_CLEAN 0 /* No errors or other information */ #define SG_ERR_CAT_MEDIA_CHANGED 1 /* interpreted from sense buffer */ #define SG_ERR_CAT_RESET 2 /* interpreted from sense buffer */ #define SG_ERR_CAT_TIMEOUT 3 #define SG_ERR_CAT_RECOVERED 4 /* Successful command after recovered err */ #define SG_ERR_CAT_SENSE 98 /* Something else is in the sense buffer */ #define SG_ERR_CAT_OTHER 99 /* Some other error/warning has occurred */ extern int sg_err_category(int target_status, int host_status, int driver_status, const unsigned char * sense_buffer); /* Returns length of SCSI command given the opcode (first byte) */ int sg_get_command_size(unsigned char opcode); #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/debian/�����������������������������������������������������������������������0000775�0000000�0000000�00000000000�15114537466�0016120�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/debian/gcdmaster.docs���������������������������������������������������������0000664�0000000�0000000�00000000036�15114537466�0020742�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������CREDITS README README.PlexDAE ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/debian/gcdmaster.install������������������������������������������������������0000664�0000000�0000000�00000000640�15114537466�0021461�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/usr/bin/gcdmaster /usr/share/application-registry/gcdmaster.applications /usr/share/applications/gcdmaster.desktop /usr/share/gcdmaster/glade /usr/share/glib-2.0/schemas/org.gnome.gcdmaster.gschema.xml /usr/share/man/man1/gcdmaster.1 /usr/share/mime/packages/gcdmaster.xml /usr/share/mime-info/gcdmaster.keys /usr/share/mime-info/gcdmaster.mime /usr/share/pixmaps/gcdmaster.png /usr/share/pixmaps/gcdmaster-doc.png ������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/depcomp�����������������������������������������������������������������������0000775�0000000�0000000�00000056217�15114537466�0016266�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2024-06-19.01; # UTC # Copyright (C) 1999-2024 Free Software Foundation, Inc. # 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, 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, see <https://www.gnu.org/licenses/>. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>. case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to <bug-automake@gnu.org>. GNU Automake home page: <https://www.gnu.org/software/automake/>. General help using GNU software: <https://www.gnu.org/gethelp/>. EOF exit $? ;; -v | --v*) echo "depcomp (GNU Automake) $scriptversion" exit $? ;; esac # Get the directory component of the given path, and save it in the # global variables '$dir'. Note that this directory component will # be either empty or ending with a '/' character. This is deliberate. set_dir_from () { case $1 in */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; *) dir=;; esac } # Get the suffix-stripped basename of the given path, and save it the # global variable '$base'. set_base_from () { base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` } # If no dependency file was actually created by the compiler invocation, # we still have to create a dummy depfile, to avoid errors with the # Makefile "include basename.Plo" scheme. make_dummy_depfile () { echo "#dummy" > "$depfile" } # Factor out some common post-processing of the generated depfile. # Requires the auxiliary global variable '$tmpdepfile' to be set. aix_post_process_depfile () { # If the compiler actually managed to produce a dependency file, # post-process it. if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependency.h'. # Do two passes, one to just change these to # $object: dependency.h # and one to simply output # dependency.h: # which is needed to avoid the deleted-header problem. { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" } > "$depfile" rm -f "$tmpdepfile" else make_dummy_depfile fi } # A tabulation character. tab=' ' # A newline character. nl=' ' # Character ranges might be problematic outside the C locale. # These definitions help. upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ lower=abcdefghijklmnopqrstuvwxyz alpha=${upper}${lower} if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Avoid interference from the environment. gccflag= dashmflag= # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. gccflag=-qmakedep=gcc,-MF depmode=gcc fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## Note that this doesn't just cater to obsolete pre-3.x GCC compilers. ## but also to in-use compilers like IBM xlc/xlC and the HP C compiler. ## (see the conditional assignment to $gccflag above). ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). Also, it might not be ## supported by the other compilers which use the 'gcc' depmode. ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The second -e expression handles DOS-style file names with drive # letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ | tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" ;; xlc) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts '$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done aix_post_process_depfile ;; tcc) # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 # FIXME: That version still under development at the moment of writing. # Make that this statement remains true also for stable, released # versions. # It will wrap lines (doesn't matter whether long or short) with a # trailing '\', as in: # # foo.o : \ # foo.c \ # foo.h \ # # It will put a trailing '\' even on the last line, and will use leading # spaces rather than leading tabs (at least since its commit 0394caf7 # "Emit spaces for -MD"). "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. # We have to change lines of the first kind to '$object: \'. sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" # And for each line of the second kind, we have to emit a 'dep.h:' # dummy dependency, to avoid the deleted-header problem. sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; ## The order of this option in the case statement is important, since the ## shell code in configure will try each of these formats in the order ## listed in this file. A plain '-MD' option would be understood by many ## compilers, so we must ensure this comes after the gcc and icc options. pgcc) # Portland's C compiler understands '-MD'. # Will always output deps to 'file.d' where file is the root name of the # source file under compilation, even if file resides in a subdirectory. # The object file name does not affect the name of the '.d' file. # pgcc 10.2 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\' : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... set_dir_from "$object" # Use the source, not the object, to determine the base name, since # that's sadly what pgcc will do too. set_base_from "$source" tmpdepfile=$base.d # For projects that build the same source file twice into different object # files, the pgcc approach of using the *source* file root name can cause # problems in parallel builds. Use a locking strategy to avoid stomping on # the same $tmpdepfile. lockdir=$base.d-lock trap " echo '$0: caught signal, cleaning up...' >&2 rmdir '$lockdir' exit 1 " 1 2 13 15 numtries=100 i=$numtries while test $i -gt 0; do # mkdir is a portable test-and-set. if mkdir "$lockdir" 2>/dev/null; then # This process acquired the lock. "$@" -MD stat=$? # Release the lock. rmdir "$lockdir" break else # If the lock is being held by a different process, wait # until the winning process is done or we timeout. while test -d "$lockdir" && test $i -gt 0; do sleep 1 i=`expr $i - 1` done fi i=`expr $i - 1` done trap - 1 2 13 15 if test $i -le 0; then echo "$0: failed to acquire lock after $numtries attempts" >&2 echo "$0: check lockdir '$lockdir'" >&2 exit 1 fi if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in 'foo.d' instead, so we check for that too. # Subdirectories are respected. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then # Libtool generates 2 separate objects for the 2 libraries. These # two compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir$base.o.d # libtool 1.5 tmpdepfile2=$dir.libs/$base.o.d # Likewise. tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d "$@" -MD fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done # Same post-processing that is required for AIX mode. aix_post_process_depfile ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" echo >> "$depfile" # make sure the fragment doesn't end with a backslash rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this sed invocation # correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process the last invocation # correctly. Breaking it into two sed invocations is a workaround. sed '1,2d' "$tmpdepfile" \ | tr ' ' "$nl" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E \ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/��������������������������������������������������������������������0000775�0000000�0000000�00000000000�15114537466�0016647�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/.cvsignore����������������������������������������������������������0000664�0000000�0000000�00000000045�15114537466�0020646�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������Makefile Makefile.in .deps gcdmaster �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/.gitignore����������������������������������������������������������0000664�0000000�0000000�00000000074�15114537466�0020640�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gcdmaster org.gnome.gcdmaster.gschema.valid stock/pixbufs.h ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/AddFileDialog.cc����������������������������������������������������0000664�0000000�0000000�00000007361�15114537466�0021575�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #include "config.h" #include <stdio.h> #include <limits.h> #include <math.h> #include <assert.h> #include <gtkmm.h> #include <glibmm/i18n.h> #include "config.h" #include "AddFileDialog.h" #include "guiUpdate.h" #include "TocEdit.h" #include "Sample.h" #include "util.h" #include "AudioCDProject.h" #include "xcdrdao.h" AddFileDialog::AddFileDialog(AudioCDProject *project) : Gtk::FileChooserDialog("") { active_ = false; project_ = project; set_select_multiple(true); set_transient_for(*project->getParentWindow ()); mode(M_APPEND_TRACK); Glib::RefPtr<Gtk::FileFilter> filter_tocs = Gtk::FileFilter::create(); std::string fname = "Audio Files (wav"; #ifdef HAVE_MP3_SUPPORT fname = fname + ", mp3, m3u"; #endif #ifdef HAVE_OGG_SUPPORT fname = fname + ", ogg"; #endif fname = fname + ")"; filter_tocs->set_name(fname); filter_tocs->add_pattern("*.wav"); #ifdef HAVE_OGG_SUPPORT filter_tocs->add_pattern("*.ogg"); #endif #ifdef HAVE_MP3_SUPPORT filter_tocs->add_pattern("*.mp3"); filter_tocs->add_pattern("*.m3u"); #endif add_filter(filter_tocs); Glib::RefPtr<Gtk::FileFilter> filter_all = Gtk::FileFilter::create(); filter_all->set_name("Any files"); filter_all->add_pattern("*"); add_filter(filter_all); add_button(Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL); add_button(Gtk::Stock::ADD, Gtk::RESPONSE_OK); } void AddFileDialog::mode(Mode m) { mode_ = m; switch (mode_) { case M_APPEND_TRACK: set_title(_("Append Track")); break; case M_APPEND_FILE: set_title(_("Append File")); break; case M_INSERT_FILE: set_title(_("Insert File")); break; } } void AddFileDialog::start() { if (active_) { get_window()->raise(); return; } active_ = true; show(); bool contFlag = true; while (contFlag) { int result = run(); switch (result) { case Gtk::RESPONSE_CANCEL: contFlag = false; break; case Gtk::RESPONSE_OK: contFlag = applyAction(); break; } } stop(); } void AddFileDialog::stop() { if (active_) { hide(); active_ = false; } } bool AddFileDialog::on_delete_event(GdkEventAny*) { stop(); return 1; } bool AddFileDialog::applyAction() { std::vector<std::string> sfiles = get_filenames(); std::list<std::string> files; for (std::vector<std::string>::const_iterator i = sfiles.begin(); i != sfiles.end(); i++) { const char *s = stripCwd((*i).c_str()); if (s && *s != 0 && s[strlen(s) - 1] != '/') { if (Util::fileExtension(s) == Util::FileExtension::M3U) parseM3u(s, files); else files.push_back(s); } } if (files.size() > 0) { switch (mode_) { case M_APPEND_TRACK: project_->appendTracks(files); break; case M_APPEND_FILE: project_->appendFiles(files); break; case M_INSERT_FILE: project_->insertFiles(files); break; } if (files.size() > 1) return false; } return true; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/AddFileDialog.h�����������������������������������������������������0000664�0000000�0000000�00000002467�15114537466�0021441�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __ADD_FILE_DIALOG_H__ #define __ADD_FILE_DIALOG_H__ #include <gtkmm.h> class AudioCDProject; class AddFileDialog : public Gtk::FileChooserDialog { public: enum Mode { M_APPEND_TRACK, M_APPEND_FILE, M_INSERT_FILE }; AddFileDialog(AudioCDProject *); void start(); void stop(); void mode(Mode); void update(unsigned long level) {} bool on_delete_event(GdkEventAny*); private: AudioCDProject *project_; bool active_; Mode mode_; bool applyAction(); }; #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/AddSilenceDialog.cc�������������������������������������������������0000664�0000000�0000000�00000013464�15114537466�0022301�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2000 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #include "config.h" #include <stdio.h> #include <limits.h> #include <math.h> #include <assert.h> #include <gtkmm.h> #include <glibmm/i18n.h> #include "AddSilenceDialog.h" #include "TocEdit.h" #include "TocEditView.h" #include "guiUpdate.h" #include "Sample.h" AddSilenceDialog::AddSilenceDialog() { Gtk::Button *button; Gtk::VBox *vbox; Gtk::HBox *hbox; tocEditView_ = NULL; active_ = false; mode_ = M_APPEND; Gtk::Frame *frame = new Gtk::Frame(_(" Length of Silence ")); Gtk::Table *table = new Gtk::Table(4, 2, false); table->set_row_spacings(5); table->set_col_spacings(5); hbox = new Gtk::HBox; hbox->pack_start(*table, true, true, 5); vbox = new Gtk::VBox; vbox->pack_start(*hbox, false, false, 5); frame->add(*vbox); Gtk::Label *label = new Gtk::Label(_("Minutes:")); table->attach(*label, 0, 1, 0, 1, Gtk::SHRINK); table->attach(minutes_, 1, 2, 0, 1); label = new Gtk::Label(_("Seconds:")); table->attach(*label, 0, 1, 1, 2, Gtk::SHRINK); table->attach(seconds_, 1, 2, 1, 2); label = new Gtk::Label(_("Frames:")); table->attach(*label, 0, 1, 2, 3, Gtk::SHRINK); table->attach(frames_, 1, 2, 2, 3); label = new Gtk::Label(_("Samples:")); table->attach(*label, 0, 1, 3, 4, Gtk::SHRINK); table->attach(samples_, 1, 2, 3, 4); hbox = new Gtk::HBox; hbox->pack_start(*frame, true, true, 10); get_vbox()->pack_start(*hbox, false, false, 10); Gtk::HButtonBox *bbox = new Gtk::HButtonBox(Gtk::BUTTONBOX_SPREAD); applyButton_ = new Gtk::Button(Gtk::StockID(Gtk::Stock::APPLY)); bbox->pack_start(*applyButton_); applyButton_->signal_clicked().connect(mem_fun(*this, &AddSilenceDialog::applyAction)); button = new Gtk::Button(Gtk::StockID(Gtk::Stock::CLEAR)); bbox->pack_start(*button); button->signal_clicked().connect(mem_fun(*this, &AddSilenceDialog::clearAction)); button = new Gtk::Button(Gtk::StockID(Gtk::Stock::CLOSE)); bbox->pack_start(*button); button->signal_clicked().connect(mem_fun(*this, &AddSilenceDialog::closeAction)); get_action_area()->pack_start(*bbox); show_all_children(); } AddSilenceDialog::~AddSilenceDialog() { } void AddSilenceDialog::mode(Mode m) { mode_ = m; switch (mode_) { case M_APPEND: set_title(_("Append Silence")); break; case M_INSERT: set_title(_("Insert Silence")); break; } } void AddSilenceDialog::start(TocEditView *view) { active_ = true; update(UPD_ALL, view); present(); tocEditView_ = view; } void AddSilenceDialog::stop() { hide(); active_ = false; } void AddSilenceDialog::update(unsigned long level, TocEditView *view) { if (!active_) return; if (view == NULL) { applyButton_->set_sensitive(false); tocEditView_ = NULL; return; } std::string s(view->tocEdit()->filename()); s += " - "; s += APP_NAME; if (view->tocEdit()->tocDirty()) s += "(*)"; set_title(s); if ((level & UPD_EDITABLE_STATE) || tocEditView_ == NULL) { applyButton_->set_sensitive(view->tocEdit()->editable() ? true : false); } tocEditView_ = view; } bool AddSilenceDialog::on_delete_event(GdkEventAny*) { stop(); return 1; } void AddSilenceDialog::closeAction() { stop(); } void AddSilenceDialog::clearAction() { minutes_.set_text(""); seconds_.set_text(""); frames_.set_text(""); samples_.set_text(""); } void AddSilenceDialog::applyAction() { unsigned long length = 0; char buf[20]; long val; TocEdit *tocEdit; if (tocEditView_ == NULL) return; tocEdit = tocEditView_->tocEdit(); if (!tocEdit->editable()) return; const char *s = minutes_.get_text().c_str(); if (s != NULL && *s != 0) { val = atol(s); length += val * 60 * 75 * SAMPLES_PER_BLOCK; snprintf(buf, sizeof(buf),"%ld", val); minutes_.set_text(buf); } s = seconds_.get_text().c_str(); if (s != NULL && *s != 0) { val = atol(s); length += val * 75 * SAMPLES_PER_BLOCK; snprintf(buf, sizeof(buf),"%ld", val); seconds_.set_text(buf); } s = frames_.get_text().c_str(); if (s != NULL && *s != 0) { val = atol(s); length += val * SAMPLES_PER_BLOCK; snprintf(buf, sizeof(buf),"%ld", val); frames_.set_text(buf); } s = samples_.get_text().c_str(); if (s != NULL && *s != 0) { val = atol(s); length += val; snprintf(buf, sizeof(buf),"%ld", val); samples_.set_text(buf); } if (length > 0) { unsigned long pos; switch (mode_) { case M_APPEND: tocEdit->appendSilence(length); update (UPD_TOC_DATA | UPD_TRACK_DATA | UPD_SAMPLE_SEL, tocEditView_); signal_tocModified (UPD_TOC_DATA | UPD_TRACK_DATA | UPD_SAMPLE_SEL); signal_fullView(); signal_tocModified(UPD_SAMPLES); break; case M_INSERT: if (tocEditView_->sampleMarker(&pos)) { if (tocEdit->insertSilence(length, pos) == 0) { tocEditView_->sampleSelect(pos, pos + length - 1); update (UPD_TOC_DATA | UPD_TRACK_DATA, tocEditView_); signal_tocModified (UPD_TOC_DATA | UPD_TRACK_DATA); } } break; } guiUpdate(); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/AddSilenceDialog.h��������������������������������������������������0000664�0000000�0000000�00000003130�15114537466�0022130�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2000 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __ADD_SILENCE_DIALOG_H__ #define __ADD_SILENCE_DIALOG_H__ #include <gtkmm.h> #include <gtk/gtk.h> class TocEditView; class AddSilenceDialog : public Gtk::Dialog { public: enum Mode { M_APPEND, M_INSERT }; AddSilenceDialog(); ~AddSilenceDialog(); void start(TocEditView *); void stop(); void mode(Mode); void update(unsigned long level, TocEditView *); sigc::signal1<void, unsigned long> signal_tocModified; sigc::signal0<void> signal_fullView; bool on_delete_event(GdkEventAny*); private: TocEditView *tocEditView_; bool active_; Mode mode_; Gtk::Button *applyButton_; Gtk::Entry minutes_; Gtk::Entry seconds_; Gtk::Entry frames_; Gtk::Entry samples_; void clearAction(); void closeAction(); void applyAction(); }; #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/AudioCDProject.cc���������������������������������������������������0000664�0000000�0000000�00000044541�15114537466�0021765�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2000 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #include "config.h" #include <assert.h> #include <cstring> #include <gtkmm.h> #include <glibmm/i18n.h> #include "Toc.h" #include "SoundIF.h" #include "AudioCDProject.h" #include "AudioCDView.h" #include "TocEdit.h" #include "TocEditView.h" #include "TocInfoDialog.h" #include "CdTextDialog.h" #include "guiUpdate.h" #include "util.h" #include "gcdmaster.h" #include "xcdrdao.h" #include "RecordTocDialog.h" #include "Icons.h" #include "MessageBox.h" AudioCDProject::AudioCDProject(int number, const char *name, TocEdit *tocEdit, Gtk::Window *parent) : Project(parent) { tocInfoDialog_ = NULL; cdTextDialog_ = NULL; soundInterface_ = NULL; buttonPlay_ = NULL; buttonStop_ = NULL; buttonPause_ = NULL; audioCDView_ = NULL; parent_ = parent; pack_start(hbox_); projectNumber_ = number; playStatus_ = STOPPED; playBurst_ = 588 * 10; playBuffer_ = new Sample[playBurst_]; if (tocEdit == NULL) tocEdit_ = new TocEdit(NULL, NULL); else tocEdit_ = tocEdit; // Connect TocEdit signals to us. tocEdit_->signalStatusMessage. connect(sigc::mem_fun(*this, &AudioCDProject::status)); tocEdit_->signalProgressFraction. connect(sigc::mem_fun(*this, &AudioCDProject::progress)); tocEdit_->signalFullView. connect(sigc::mem_fun(*this, &AudioCDProject::fullView)); tocEdit_->signalSampleSelection. connect(sigc::mem_fun(*this, &AudioCDProject::sampleSelect)); tocEdit_->signalCancelEnable. connect(sigc::mem_fun(*this, &AudioCDProject::cancelEnable)); tocEdit_->signalError. connect(sigc::mem_fun(*this, &AudioCDProject::errorDialog)); if (tocEdit_->isQueueActive()) cancelEnable(true); if (!name || strlen(name) == 0) { char buf[20]; snprintf(buf, sizeof(buf),"unnamed-%i.toc", projectNumber_); tocEdit_->filename(buf); new_ = true; } else { new_ = false; // The project file already exists } audioCDView_ = new AudioCDView(this); hbox_.pack_start(*audioCDView_, TRUE, TRUE); audioCDView_->tocEditView()->sampleViewFull(); updateWindowTitle(); guiUpdate(UPD_ALL); show_all(); } void AudioCDProject::add_menus(Glib::RefPtr<Gtk::UIManager> m_refUIManager) { m_refActionGroup = Gtk::ActionGroup::create("AudioCDProject"); m_refActionGroup->add( Gtk::Action::create("Save", Gtk::Stock::SAVE), sigc::mem_fun(*this, &Project::saveProject) ); m_refActionGroup->add( Gtk::Action::create("SaveAs", Gtk::Stock::SAVE_AS), sigc::mem_fun(*this, &Project::saveAsProject) ); m_refActionGroup->add( Gtk::Action::create("ProjectInfo", Gtk::Stock::PROPERTIES, _("Project Info..."), _("Edit global project data")), sigc::mem_fun(*this, &AudioCDProject::projectInfo) ); m_refActionGroup->add( Gtk::Action::create("CDTEXT", Gtk::Stock::PROPERTIES, _("CD-TEXT..."), _("Edit CD-TEXT data")), sigc::mem_fun(*this, &AudioCDProject::cdTextDialog) ); m_refActionGroup->add( Gtk::Action::create("Record", Icons::RECORD, _("_Record"), _("Record")), sigc::mem_fun(*this, &AudioCDProject::recordToc2CD) ); m_refActionGroup->add( Gtk::Action::create("Play", Icons::PLAY, _("Play"), _("Play")), sigc::mem_fun(*this, &AudioCDProject::on_play_clicked) ); m_refActionGroup->add( Gtk::Action::create("Stop", Icons::STOP, _("Stop"), _("Stop")), sigc::mem_fun(*this, &AudioCDProject::on_stop_clicked) ); m_refActionGroup->add( Gtk::Action::create("Pause", Icons::PAUSE, _("Pause"), _("Pause")), sigc::mem_fun(*this, &AudioCDProject::on_pause_clicked) ); //Add Toggle Actions: Gtk::RadioAction::Group group_colors; m_refActionGroup->add( Gtk::RadioAction::create(group_colors, "Select", Gtk::Stock::JUMP_TO, _("Select"), _("Select Mode")), sigc::mem_fun(*this, &AudioCDProject::on_select_clicked)); m_refActionGroup->add( Gtk::RadioAction::create(group_colors, "Zoom", Gtk::Stock::ZOOM_FIT, _("Zoom"), _("Zoom Mode")), sigc::mem_fun(*this, &AudioCDProject::on_zoom_clicked)); m_refActionGroup->add( Gtk::Action::create("ZoomIn", Gtk::Stock::ZOOM_IN, _("Zoom In"), _("Zoom In")), sigc::mem_fun(*this, &AudioCDProject::on_zoom_in_clicked) ); m_refActionGroup->add( Gtk::Action::create("ZoomOut", Gtk::Stock::ZOOM_OUT, _("Zoom Out"), _("Zoom Out")), sigc::mem_fun(*this, &AudioCDProject::on_zoom_out_clicked) ); m_refActionGroup->add( Gtk::Action::create("ZoomFit", Gtk::Stock::ZOOM_FIT, _("Zoom Fit"), _("Zoom Fit")), sigc::mem_fun(*this, &AudioCDProject::on_zoom_fit_clicked) ); m_refUIManager->insert_action_group(m_refActionGroup); // Merge menuitems try { Glib::ustring ui_info = "<ui>" " <menubar name='MenuBar'>" " <menu action='FileMenu'>" " <placeholder name='FileSaveHolder'>" " <menuitem action='Save'/>" " <menuitem action='SaveAs'/>" " </placeholder>" " </menu>" " <menu action='EditMenu'>" " <menuitem action='ProjectInfo'/>" " <menuitem action='CDTEXT'/>" " </menu>" " <menu action='ActionsMenu'>" " <placeholder name='ActionsRecordHolder'>" " <menuitem action='Record'/>" " </placeholder>" " <menuitem action='Play'/>" " <menuitem action='Stop'/>" " <menuitem action='Pause'/>" " <separator/>" " <menuitem action='Select'/>" " <menuitem action='Zoom'/>" " <separator/>" " <menuitem action='ZoomIn'/>" " <menuitem action='ZoomOut'/>" " <menuitem action='ZoomFit'/>" " </menu>" " </menubar>" " <toolbar name='ToolBar'>" " <toolitem action='Save'/>" " <toolitem action='Record'/>" " <separator/>" " <toolitem action='Play'/>" " <toolitem action='Stop'/>" " <toolitem action='Pause'/>" " <separator/>" " <toolitem action='Select'/>" " <toolitem action='Zoom'/>" " <separator/>" " <toolitem action='ZoomIn'/>" " <toolitem action='ZoomOut'/>" " <toolitem action='ZoomFit'/>" " <separator/>" " </toolbar>" "</ui>"; m_refUIManager->add_ui_from_string(ui_info); } catch(const Glib::Error& ex) { std::cerr << "merging menus failed: " << ex.what(); } Glib::RefPtr<Gtk::Action> action; action = m_refActionGroup->get_action ("Play"); action->set_sensitive(true); action = m_refActionGroup->get_action ("Pause"); action->set_sensitive(false); action = m_refActionGroup->get_action ("Stop"); action->set_sensitive(false); audioCDView_->add_menus (m_refUIManager); audioCDView_->signal_tocModified. connect(sigc::mem_fun(*this, &AudioCDProject::update)); } void AudioCDProject::configureAppBar(Gtk::Statusbar *s, Gtk::ProgressBar* p, Gtk::Button *b) { statusbar_ = s; progressbar_ = p; progressButton_ = b; if (tocEdit_) { tocEdit_->signalProgressPulse. connect(sigc::mem_fun(*progressbar_, &Gtk::ProgressBar::pulse)); signalCancelClicked.connect(sigc::mem_fun(*tocEdit_, &TocEdit::queueAbort)); if (tocEdit_->isQueueActive()) progressButton_->set_sensitive(true); } progressButton_->signal_clicked(). connect(sigc::mem_fun(*this, &AudioCDProject::on_cancel_clicked)); progressbar_->set_pulse_step(0.01); } void AudioCDProject::status(const char* msg) { statusMessage(msg); } void AudioCDProject::errorDialog(const char* msg) { Gtk::MessageDialog md(*(getParentWindow()), msg, false, Gtk::MESSAGE_ERROR); md.run(); } void AudioCDProject::progress(double val) { progressbar_->set_fraction(val); } void AudioCDProject::fullView() { if (audioCDView_) audioCDView_->fullView(); } void AudioCDProject::sampleSelect(unsigned long start, unsigned long len) { audioCDView_->tocEditView()->sampleSelect(start, len); } void AudioCDProject::cancelEnable(bool enable) { if (progressButton_) progressButton_->set_sensitive(enable); } bool AudioCDProject::closeProject() { if (tocEdit_->tocDirty()) { // Project window might be iconified and user might have forgotten // about it (Quit can be called on another project window). getParentWindow()->present(); Glib::ustring message = "Project "; message += tocEdit_->filename(); message += " not saved. Are you sure you want to close it ?"; Gtk::MessageDialog d(*getParentWindow(), message, false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO, true); int ret = d.run(); d.hide(); if (ret == Gtk::RESPONSE_NO || ret == Gtk::RESPONSE_DELETE_EVENT) return false; } if (tocEdit_ && tocEdit_->isQueueActive()) { tocEdit_->queueAbort(); } if (playStatus_ == PLAYING || playStatus_ == PAUSED) { playStop(); } if (audioCDView_) { delete audioCDView_; audioCDView_ = NULL; } if (tocInfoDialog_) delete tocInfoDialog_; if (cdTextDialog_) delete cdTextDialog_; if (recordTocDialog_) delete recordTocDialog_; return true; } void AudioCDProject::recordToc2CD() { if (recordTocDialog_ == NULL) recordTocDialog_ = new RecordTocDialog(tocEdit_); recordTocDialog_->start (parent_); } void AudioCDProject::projectInfo() { if (!tocInfoDialog_) tocInfoDialog_ = new TocInfoDialog(parent_); tocInfoDialog_->start(tocEdit_); } void AudioCDProject::cdTextDialog() { if (cdTextDialog_ == 0) cdTextDialog_ = new CdTextDialog(); cdTextDialog_->start(tocEdit_); } void AudioCDProject::update(unsigned long level) { //FIXME: Here we should update the menus and the icons // this is, enabled/disabled. level |= tocEdit_->updateLevel(); if (level & (UPD_TOC_DIRTY | UPD_TOC_DATA)) updateWindowTitle(); audioCDView_->update(level); if (tocInfoDialog_) tocInfoDialog_->update(level, tocEdit_); if (cdTextDialog_ != 0) cdTextDialog_->update(level, tocEdit_); if (recordTocDialog_ != 0) recordTocDialog_->update(level); if (level & UPD_PLAY_STATUS) { bool sensitivity[3][3] = { //PLAY PAUSE STOP { false, true, true }, // Playing { true, true, true }, // Paused { true, false, false } // Stopped }; Glib::RefPtr<Gtk::Action> action; action = m_refActionGroup->get_action ("Play"); action->set_sensitive(sensitivity[playStatus_][0]); action = m_refActionGroup->get_action ("Pause"); action->set_sensitive(sensitivity[playStatus_][1]); action = m_refActionGroup->get_action ("Stop"); action->set_sensitive(sensitivity[playStatus_][2]); } if (level & UPD_EDITABLE_STATE) { bool editable = tocEdit_->editable(); Glib::RefPtr<Gtk::Action> action; action = m_refActionGroup->get_action ("Play"); action->set_sensitive(editable); } } void AudioCDProject::playStart() { unsigned long start, end; // If we're in paused mode, resume playing. if (playStatus_ == PAUSED) { playStatus_ = PLAYING; Glib::signal_idle().connect(sigc::mem_fun(*this, &AudioCDProject::playCallback)); return; } else if (playStatus_ == PLAYING) { return; } if (audioCDView_ && audioCDView_->tocEditView()) { if (!audioCDView_->tocEditView()->sampleSelection(&start, &end)) audioCDView_->tocEditView()->sampleView(&start, &end); playStart(start, end); } } void AudioCDProject::playStart(unsigned long start, unsigned long end) { unsigned long level = 0; if (playStatus_ == PLAYING) return; if (tocEdit_->lengthSample() == 0) { guiUpdate(UPD_PLAY_STATUS); return; } if (soundInterface_ == NULL) { soundInterface_ = new SoundIF; if (soundInterface_->init() != 0) { delete soundInterface_; soundInterface_ = NULL; guiUpdate(UPD_PLAY_STATUS); statusMessage(_("WARNING: Cannot open \"/dev/dsp\"")); return; } } if (soundInterface_->start() != 0) { statusMessage(_("WARNING: Cannot open sound device")); guiUpdate(UPD_PLAY_STATUS); return; } tocReader.init(tocEdit_->toc()); if (tocReader.openData() != 0) { tocReader.init(NULL); soundInterface_->end(); guiUpdate(UPD_PLAY_STATUS); return; } if (tocReader.seekSample(start) != 0) { tocReader.init(NULL); soundInterface_->end(); guiUpdate(UPD_PLAY_STATUS); return; } playLength_ = end - start + 1; playPosition_ = start; playStatus_ = PLAYING; playAbort_ = false; level |= UPD_PLAY_STATUS; //FIXME: Selection / Zooming does not depend // on the Child, but the View. // we should have different blocks! tocEdit_->blockEdit(); guiUpdate(level); Glib::signal_idle().connect(sigc::mem_fun(*this, &AudioCDProject::playCallback)); } void AudioCDProject::playPause() { if (playStatus_ == PAUSED) { playStatus_ = PLAYING; Glib::signal_idle().connect(sigc::mem_fun(*this, &AudioCDProject::playCallback)); } else if (playStatus_ == PLAYING) { playStatus_ = PAUSED; } } void AudioCDProject::playStop() { if (playStatus() == PAUSED) { soundInterface_->end(); tocReader.init(NULL); playStatus_ = STOPPED; tocEdit_->unblockEdit(); playStatus_ = STOPPED; guiUpdate(UPD_PLAY_STATUS|UPD_EDITABLE_STATE); } else { playAbort_ = true; } } bool AudioCDProject::playCallback() { unsigned long level = 0; long len = playLength_ > playBurst_ ? playBurst_ : playLength_; if (playStatus_ == PAUSED) { level |= UPD_PLAY_STATUS; guiUpdate(level); return false; // remove idle handler } if (tocReader.readSamples(playBuffer_, len) != len || soundInterface_->play(playBuffer_, len) != 0) { soundInterface_->end(); tocReader.init(NULL); playStatus_ = STOPPED; level |= UPD_PLAY_STATUS; tocEdit_->unblockEdit(); guiUpdate(level); return false; // remove idle handler } playLength_ -= len; playPosition_ += len; unsigned long delay = soundInterface_->getDelay(); if (delay <= playPosition_) level |= UPD_PLAY_STATUS; if (len == 0 || playAbort_) { soundInterface_->end(); tocReader.init(NULL); playStatus_ = STOPPED; level |= UPD_PLAY_STATUS | UPD_EDITABLE_STATE; tocEdit_->unblockEdit(); guiUpdate(level); return false; // remove idle handler } else { guiUpdate(level); return true; // keep idle handler } } unsigned long AudioCDProject::playPosition() { return playPosition_; } unsigned long AudioCDProject::getDelay() { return soundInterface_->getDelay(); } void AudioCDProject::on_play_clicked() { playStart(); } void AudioCDProject::on_stop_clicked() { playStop(); } void AudioCDProject::on_pause_clicked() { playPause(); } void AudioCDProject::on_zoom_in_clicked() { if (audioCDView_) audioCDView_->zoomx2(); } void AudioCDProject::on_zoom_out_clicked() { if (audioCDView_) audioCDView_->zoomOut(); } void AudioCDProject::on_zoom_fit_clicked() { if (audioCDView_) audioCDView_->fullView(); } void AudioCDProject::on_zoom_clicked() { if (audioCDView_) audioCDView_->setMode(AudioCDView::ZOOM); } void AudioCDProject::on_select_clicked() { if (audioCDView_) audioCDView_->setMode(AudioCDView::SELECT); } void AudioCDProject::on_cancel_clicked() { signalCancelClicked(); } bool AudioCDProject::appendTrack(const char* file) { auto type = Util::fileExtension(file); switch (type) { case Util::FileExtension::M3U: { std::list<std::string> list; if (parseM3u(file, list)) { std::list<std::string>::iterator i = list.begin(); for (; i != list.end(); i++) { tocEdit()->queueAppendTrack((*i).c_str()); } } else { std::string msg = "Could not read M3U file \""; msg += file; msg += "\""; errorDialog(msg.c_str()); return false; } break; } default: tocEdit()->queueAppendTrack(file); } return true; } bool AudioCDProject::appendTracks(std::list<std::string>& files) { std::list<std::string>::iterator i = files.begin(); for (; i != files.end(); i++) { tocEdit()->queueAppendTrack((*i).c_str()); } return true; } bool AudioCDProject::appendFiles(std::list<std::string>& files) { std::list<std::string>::iterator i = files.begin(); for (; i != files.end(); i++) { tocEdit()->queueAppendFile((*i).c_str()); } return true; } bool AudioCDProject::insertFiles(std::list<std::string>& files) { unsigned long pos; TocEditView* view = audioCDView_->tocEditView(); if (!view) return false; if (!view->sampleMarker(&pos)) pos = 0; std::list<std::string>::iterator i = files.end(); do { i--; tocEdit()->queueInsertFile((*i).c_str(), pos); } while (i != files.begin()); return true; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/AudioCDProject.h����������������������������������������������������0000664�0000000�0000000�00000006416�15114537466�0021626�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 2000 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __AUDIOCDPROJECT_H__ #define __AUDIOCDPROJECT_H__ #include <gtkmm.h> #include <gtk/gtk.h> class Toc; class Track; class Sample; class SoundIF; class AudioCDView; class TocInfoDialog; class CdTextDialog; class TocEdit; #include "Project.h" class AudioCDProject : public Project { public: enum PlayStatus {PLAYING, PAUSED, STOPPED}; AudioCDProject(int number, const char *name, TocEdit *tocEdit, Gtk::Window *parent); void add_menus (Glib::RefPtr<Gtk::UIManager> m_refUIManager); void configureAppBar (Gtk::Statusbar *s, Gtk::ProgressBar* p, Gtk::Button *b); bool closeProject(); unsigned long playPosition(); unsigned long getDelay(); bool appendTrack(const char* file); bool appendTracks(std::list<std::string>&); bool appendFiles(std::list<std::string>&); bool insertFiles(std::list<std::string>&); PlayStatus playStatus() { return playStatus_; } // Controls for app bar void cancelEnable(bool); sigc::signal0<void> signalCancelClicked; protected: Gtk::Button* buttonPlay_; Gtk::Button* buttonStop_; Gtk::Button* buttonPause_; virtual void on_play_clicked(); virtual void on_stop_clicked(); virtual void on_pause_clicked(); virtual void on_select_clicked(); virtual void on_zoom_clicked(); virtual void on_zoom_in_clicked(); virtual void on_zoom_out_clicked(); virtual void on_zoom_fit_clicked(); virtual void on_cancel_clicked(); virtual void status(const char* msg); virtual void errorDialog(const char* msg); virtual void progress(double val); virtual void fullView(); virtual void sampleSelect(unsigned long, unsigned long); void playStart(); void playStart(unsigned long start, unsigned long end); void playPause(); void playStop(); private: TocReader tocReader; SoundIF *soundInterface_; unsigned long playLength_; // remaining play length unsigned long playBurst_; unsigned long playPosition_; Sample *playBuffer_; bool playAbort_; bool playCallback(); Gtk::HBox hbox_; AudioCDView* audioCDView_; TocInfoDialog* tocInfoDialog_; CdTextDialog* cdTextDialog_; Glib::RefPtr<Gtk::ActionGroup> m_refActionGroup; Glib::RefPtr<Gtk::ToggleAction> selectToggle_; Glib::RefPtr<Gtk::ToggleAction> zoomToggle_; void recordToc2CD(); void projectInfo(); void cdTextDialog(); void update(unsigned long level); enum PlayStatus playStatus_; }; #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/AudioCDView.cc������������������������������������������������������0000664�0000000�0000000�00000061267�15114537466�0021275�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2000 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #include <gtkmm.h> #include <glibmm/convert.h> #include <glibmm/i18n.h> #include <iostream> #include "config.h" #include "xcdrdao.h" #include "guiUpdate.h" #include "MessageBox.h" #include "SampleDisplay.h" #include "TocEdit.h" #include "TocEditView.h" #include "util.h" #include "AudioCDProject.h" #include "AudioCDView.h" #include "Project.h" #include "TrackInfoDialog.h" #include "AddFileDialog.h" #include "AddSilenceDialog.h" AudioCDView::AudioCDView(AudioCDProject *project) : addFileDialog_(project) { project_ = project; tocEditView_ = new TocEditView(project->tocEdit()); // These are not created until first needed, for faster startup // and less memory usage. trackInfoDialog_ = 0; addSilenceDialog_ = 0; std::vector<Gtk::TargetEntry> drop_types; drop_types.push_back(Gtk::TargetEntry("text/uri-list", Gtk::TargetFlags(0), TARGET_URI_LIST)); drag_dest_set(drop_types); signal_drag_data_received(). connect(sigc::mem_fun(*this, &AudioCDView::drag_data_received_cb)); sampleDisplay_ = new SampleDisplay; sampleDisplay_->setTocEdit(project->tocEdit()); sampleDisplay_->set_size_request(200,200); pack_start(*sampleDisplay_, TRUE, TRUE); sampleDisplay_->override_font(Pango::FontDescription("Monospace 8")); sampleDisplay_->show(); Gtk::HScrollbar *scrollBar = new Gtk::HScrollbar(sampleDisplay_->getAdjustment()); pack_start(*scrollBar, FALSE, FALSE); scrollBar->show(); Gtk::Label *label; Gtk::HBox *selectionInfoBox = new Gtk::HBox; //FIXME: Calculate entry width for the current font. gint entry_width = 90; markerPos_ = new Gtk::Entry; markerPos_->set_editable(true); markerPos_->set_size_request(entry_width, -1); markerPos_->signal_activate(). connect(sigc::mem_fun(*this, &AudioCDView::markerSet)); cursorPos_ = new Gtk::Label; cursorPos_->set_size_request(entry_width, -1); selectionStartPos_ = new Gtk::Entry; selectionStartPos_->set_editable(true); selectionStartPos_->set_size_request(entry_width, -1); selectionStartPos_->signal_activate(). connect(sigc::mem_fun(*this, &AudioCDView::selectionSet)); selectionEndPos_ = new Gtk::Entry; selectionEndPos_->set_editable(true); selectionEndPos_->set_size_request(entry_width, -1); selectionEndPos_->signal_activate(). connect(sigc::mem_fun(*this, &AudioCDView::selectionSet)); label = new Gtk::Label(_("Cursor: ")); selectionInfoBox->pack_start(*label, FALSE, FALSE); selectionInfoBox->pack_start(*cursorPos_); label->show(); cursorPos_->show(); label = new Gtk::Label(_("Marker: ")); selectionInfoBox->pack_start(*label, FALSE, FALSE); selectionInfoBox->pack_start(*markerPos_); label->show(); markerPos_->show(); label = new Gtk::Label(_("Selection: ")); selectionInfoBox->pack_start(*label, FALSE, FALSE); selectionInfoBox->pack_start(*selectionStartPos_); label->show(); selectionStartPos_->show(); label = new Gtk::Label(" - "); selectionInfoBox->pack_start(*label, FALSE, FALSE); selectionInfoBox->pack_start(*selectionEndPos_); label->show(); selectionEndPos_->show(); selectionInfoBox->set_border_width(2); pack_start(*selectionInfoBox, FALSE, FALSE); selectionInfoBox->show(); setMode(SELECT); sampleDisplay_->markerSet.connect( sigc::mem_fun(*this, &AudioCDView::markerSetCallback)); sampleDisplay_->selectionSet.connect( sigc::mem_fun(*this, &AudioCDView::selectionSetCallback)); sampleDisplay_->selectionCleared.connect( sigc::mem_fun(*this, &AudioCDView::selectionClearedCallback)); sampleDisplay_->cursorMoved.connect( sigc::mem_fun(*this, &AudioCDView::cursorMovedCallback)); sampleDisplay_->trackMarkSelected.connect( sigc::mem_fun(*this, &AudioCDView::trackMarkSelectedCallback)); sampleDisplay_->trackMarkMoved.connect( sigc::mem_fun(*this, &AudioCDView::trackMarkMovedCallback)); sampleDisplay_->viewModified.connect( sigc::mem_fun(*this, &AudioCDView::viewModifiedCallback)); tocEditView_->sampleViewFull(); } AudioCDView::~AudioCDView() { if (trackInfoDialog_) delete trackInfoDialog_; if (addSilenceDialog_) delete addSilenceDialog_; } void AudioCDView::add_menus(Glib::RefPtr<Gtk::UIManager> m_refUIManager) { m_refActionGroup = Gtk::ActionGroup::create("AudioCDView"); m_refActionGroup->add( Gtk::Action::create("TrackInfo", Gtk::Stock::PROPERTIES, _("Track Info..."), _("Edit track data")), sigc::mem_fun(*this, &AudioCDView::trackInfo) ); m_refActionGroup->add( Gtk::Action::create("Cut", Gtk::Stock::CUT, _("Cut"), _("Cut out selected samples")), Gtk::AccelKey("<control>x"), sigc::mem_fun(*this, &AudioCDView::cutTrackData) ); m_refActionGroup->add( Gtk::Action::create("Paste", Gtk::Stock::PASTE, _("Paste"), _("Paste previously cut samples")), Gtk::AccelKey("<control>v"), sigc::mem_fun(*this, &AudioCDView::pasteTrackData) ); m_refActionGroup->add( Gtk::Action::create("SelectAll", _("Select All"), _("Select entire sample")), Gtk::AccelKey("<control>a"), sigc::mem_fun(*this, &AudioCDView::selectAll) ); m_refActionGroup->add( Gtk::Action::create("AddTrackMark", _("Add Track Mark"), _("Add track marker at current marker position")), Gtk::AccelKey("<control>m"), sigc::mem_fun(*this, &AudioCDView::addTrackMark) ); m_refActionGroup->add( Gtk::Action::create("AddIndexMark", _("Add Index Mark"), _("Add index marker at current marker position")), sigc::mem_fun(*this, &AudioCDView::addIndexMark) ); m_refActionGroup->add( Gtk::Action::create("AddPreGap", _("Add Pre-Gap"), _("Add pre-gap at current marker position")), sigc::mem_fun(*this, &AudioCDView::addPregap) ); m_refActionGroup->add( Gtk::Action::create("RemoveTrackMark", _("Remove Track Mark"), _("Remove selected track/index marker or pre-gap")), Gtk::AccelKey("<control>D"), sigc::mem_fun(*this, &AudioCDView::removeTrackMark) ); m_refActionGroup->add( Gtk::Action::create("AppendTrack", _("Append Track"), _("Append track with data from audio file")), Gtk::AccelKey("<control>T"), sigc::mem_fun(*this, &AudioCDView::appendTrack) ); m_refActionGroup->add( Gtk::Action::create("AppendFile", _("Append File"), _("Append data from audio file to last track")), Gtk::AccelKey("<control>F"), sigc::mem_fun(*this, &AudioCDView::appendFile) ); m_refActionGroup->add( Gtk::Action::create("InsertFile", _("Insert File"), _("Insert data from audio file at current marker position")), Gtk::AccelKey("<control>I"), sigc::mem_fun(*this, &AudioCDView::insertFile) ); m_refActionGroup->add( Gtk::Action::create("AppendSilence", _("Append Silence"), _("Append silence to last track")), sigc::mem_fun(*this, &AudioCDView::appendSilence) ); m_refActionGroup->add( Gtk::Action::create("InsertSilence", _("Insert Silence"), _("Insert silence at current marker position")), sigc::mem_fun(*this, &AudioCDView::insertSilence) ); m_refUIManager->insert_action_group(m_refActionGroup); // Merge menuitems try { Glib::ustring ui_info = "<ui>" " <menubar name='MenuBar'>" " <menu action='EditMenu'>" " <menuitem action='TrackInfo'/>" " <separator/>" " <menuitem action='Cut'/>" " <menuitem action='Paste'/>" " <separator/>" " <menuitem action='SelectAll'/>" " <separator/>" " <menuitem action='AddTrackMark'/>" " <menuitem action='AddIndexMark'/>" " <menuitem action='AddPreGap'/>" " <menuitem action='RemoveTrackMark'/>" " <separator/>" " <menuitem action='AppendTrack'/>" " <menuitem action='AppendFile'/>" " <menuitem action='InsertFile'/>" " <separator/>" " <menuitem action='AppendSilence'/>" " <menuitem action='InsertSilence'/>" " </menu>" " </menubar>" "</ui>"; m_refUIManager->add_ui_from_string(ui_info); } catch(const Glib::Error& ex) { std::cerr << "merging menus failed: " << ex.what(); } } void AudioCDView::update(unsigned long level) { if (level & (UPD_TOC_DIRTY | UPD_TOC_DATA)) { cursorPos_->set_text(""); } if (level & UPD_TRACK_MARK_SEL) { int trackNr, indexNr; if (tocEditView_->trackSelection(&trackNr) && tocEditView_->indexSelection(&indexNr)) { sampleDisplay_->setSelectedTrackMarker(trackNr, indexNr); } else { sampleDisplay_->setSelectedTrackMarker(0, 0); } } if (level & UPD_SAMPLES) { unsigned long smin, smax; tocEditView_->sampleView(&smin, &smax); sampleDisplay_->updateToc(smin, smax); } else if (level & (UPD_TRACK_DATA | UPD_TRACK_MARK_SEL)) { sampleDisplay_->updateTrackMarks(); } if (level & UPD_SAMPLE_MARKER) { unsigned long marker; if (tocEditView_->sampleMarker(&marker)) { markerPos_->set_text(sample2string(marker)); sampleDisplay_->setMarker(marker); } else { markerPos_->set_text(""); sampleDisplay_->clearMarker(); } } if (level & UPD_SAMPLE_SEL) { unsigned long start, end; if (tocEditView_->sampleSelection(&start, &end)) { selectionStartPos_->set_text(sample2string(start)); selectionEndPos_->set_text(sample2string(end)); sampleDisplay_->setRegion(start, end); } else { selectionStartPos_->set_text(""); selectionEndPos_->set_text(""); sampleDisplay_->clearRegion(); } } if (level & UPD_PLAY_STATUS) { switch (project_->playStatus()) { case AudioCDProject::PLAYING: sampleDisplay_->setCursor(1, project_->playPosition() - project_->getDelay()); // FIXME: What about using a separate cursor for playing? cursorPos_->set_text(sample2string(project_->playPosition() - project_->getDelay())); break; case AudioCDProject::PAUSED: sampleDisplay_->setCursor(1, project_->playPosition() - project_->getDelay()); // FIXME: What about using a separate cursor for playing? cursorPos_->set_text(sample2string(project_->playPosition() - project_->getDelay())); break; case AudioCDProject::STOPPED: sampleDisplay_->setCursor(0, 0); break; default: std::cerr << "invalid play status" << std::endl; } } if (trackInfoDialog_ != 0) trackInfoDialog_->update(level, tocEditView_); addFileDialog_.update(level); if (addSilenceDialog_ != 0) addSilenceDialog_->update(level, tocEditView_); } void AudioCDView::zoomIn() { unsigned long start, end; if (tocEditView_->sampleSelection(&start, &end)) { if (tocEditView_->sampleView(start, end)) { update(UPD_SAMPLES); } } } void AudioCDView::zoomx2() { unsigned long start, end, len, center; tocEditView_->sampleView(&start, &end); len = end - start + 1; center = start + len / 2; start = center - len / 4; end = center + len / 4; if (tocEditView_->sampleView(start, end)) { update(UPD_SAMPLES); } } void AudioCDView::zoomOut() { unsigned long start, end, len, center; tocEditView_->sampleView(&start, &end); len = end - start + 1; center = start + len / 2; if (center > len) start = center - len; else start = 0; end = center + len; if (end >= tocEditView_->tocEdit()->toc()->length().samples()) end = tocEditView_->tocEdit()->toc()->length().samples() - 1; if (tocEditView_->sampleView(start, end)) { update(UPD_SAMPLES); } } void AudioCDView::fullView() { tocEditView_->sampleViewFull(); update(UPD_SAMPLES); } int AudioCDView::getMarker(unsigned long *sample) { if (tocEditView_->tocEdit()->lengthSample() == 0) return 0; if (sampleDisplay_->getMarker(sample) == 0) { project_->statusMessage(_("Please set marker.")); return 0; } return 1; } void AudioCDView::trackMarkSelectedCallback(const Track *, int trackNr, int indexNr) { tocEditView_->trackSelection(trackNr); tocEditView_->indexSelection(indexNr); update(UPD_TRACK_MARK_SEL); } // Called when the user clicks on the SampleDisplay void AudioCDView::markerSetCallback(unsigned long sample) { tocEditView_->sampleMarker(sample); update(UPD_SAMPLE_MARKER); } // Called when the user makes a selection on the SampleDisplay void AudioCDView::selectionSetCallback(unsigned long start, unsigned long end) { if (mode_ == ZOOM ) { if (tocEditView_->sampleView(start, end)) { update(UPD_SAMPLES); } } else { tocEditView_->sampleSelect(start, end); update(UPD_SAMPLE_SEL); } } void AudioCDView::selectAll() { tocEditView_->sampleSelectAll(); update(UPD_SAMPLE_SEL); } void AudioCDView::selectionClearedCallback() { if (mode_ != ZOOM) { if (tocEditView_->sampleSelectionClear()) { update(UPD_SAMPLE_SEL); } } } void AudioCDView::cursorMovedCallback(unsigned long pos) { cursorPos_->set_text(sample2string(pos)); } void AudioCDView::viewModifiedCallback(unsigned long start, unsigned long end) { if (tocEditView_->sampleView(start, end)) { update(UPD_SAMPLES); } } void AudioCDView::setMode(Mode m) { mode_ = m; } // Called when the user enters a value in the marker entry void AudioCDView::markerSet() { unsigned long s = string2sample(markerPos_->get_text().c_str()); tocEditView_->sampleMarker(s); update(UPD_SAMPLE_MARKER); } // Called when the user enters a value in one of the two selection entries void AudioCDView::selectionSet() { unsigned long s1 = string2sample(selectionStartPos_->get_text().c_str()); unsigned long s2 = string2sample(selectionEndPos_->get_text().c_str()); tocEditView_->sampleSelect(s1, s2); update(UPD_SAMPLE_SEL); } void AudioCDView::drag_data_received_cb(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, const Gtk::SelectionData& selection_data, guint info, guint time) { switch (info) { case TARGET_URI_LIST: if (project_->playStatus() != AudioCDProject::STOPPED) return; std::string list = selection_data.get_data_as_string(); int idx = 0, n; while ((n = list.find("\r\n", idx)) >= 0) { std::string sub = list.substr(idx, n - idx); idx = n + 2; std::string fn; try { fn = Glib::filename_from_uri(sub); } catch (std::exception& e) { fn.clear(); } if (fn.empty()) continue; // Process m3u file. auto type = Util::fileExtension(fn.c_str()); if (type == Util::FileExtension::WAV || type == Util::FileExtension::M3U #ifdef HAVE_MP3_SUPPORT || type == Util::FileExtension::MP3 #endif #ifdef HAVE_OGG_SUPPORT || type == Util::FileExtension::OGG #endif ) { project_->appendTrack(fn.c_str()); } } break; } } void AudioCDView::trackInfo() { int track; if (tocEditView_->trackSelection(&track)) { if (trackInfoDialog_ == 0) trackInfoDialog_ = new TrackInfoDialog(); trackInfoDialog_->start(tocEditView_); } else { Gtk::MessageDialog md(*project_->getParentWindow (), _("Please select a track first"), Gtk::MESSAGE_INFO); md.run(); } } void AudioCDView::cutTrackData() { if (!project_->tocEdit()->editable()) { project_->tocBlockedMsg("Cut"); return; } switch (project_->tocEdit()->removeTrackData(tocEditView_)) { case 0: project_->statusMessage(_("Removed selected samples.")); signal_tocModified(UPD_TOC_DATA | UPD_TRACK_DATA | UPD_SAMPLE_SEL | UPD_SAMPLE_MARKER | UPD_SAMPLES); break; case 1: project_->statusMessage(_("Please select samples.")); break; case 2: project_->statusMessage(_("Selected sample range crosses track " "boundaries.")); break; } } void AudioCDView::pasteTrackData() { if (!project_->tocEdit()->editable()) { project_->tocBlockedMsg("Paste"); return; } switch (project_->tocEdit()->insertTrackData(tocEditView_)) { case 0: project_->statusMessage(_("Pasted samples.")); signal_tocModified(UPD_TOC_DATA | UPD_TRACK_DATA | UPD_SAMPLE_SEL); break; case 1: project_->statusMessage(_("No samples in scrap.")); break; } } void AudioCDView::addTrackMark() { unsigned long sample; if (!project_->tocEdit()->editable()) { project_->tocBlockedMsg(_("Add Track Mark")); return; } if (getMarker(&sample)) { long lba; int snapped = snapSampleToBlock(sample, &lba); switch (project_->tocEdit()->addTrackMarker(lba)) { case 0: project_->statusMessage(_("Added track mark at %s%s."), Msf(lba).str(), snapped ? _(" (snapped to next block)") : ""); signal_tocModified(UPD_TOC_DATA | UPD_TRACK_DATA | UPD_SAMPLE_MARKER); break; case 2: project_->statusMessage(_("Cannot add track at this point.")); break; case 3: case 4: project_->statusMessage(_("Resulting track would be shorter than " "4 seconds.")); break; case 5: project_->statusMessage(_("Cannot modify a data track.")); break; default: project_->statusMessage(_("Internal error in addTrackMark(), please " "report.")); break; } } } void AudioCDView::addIndexMark() { unsigned long sample; if (!project_->tocEdit()->editable()) { project_->tocBlockedMsg(_("Add Index Mark")); return; } if (getMarker(&sample)) { long lba; int snapped = snapSampleToBlock(sample, &lba); switch (project_->tocEdit()->addIndexMarker(lba)) { case 0: project_->statusMessage(_("Added index mark at %s%s."), Msf(lba).str(), snapped ? _(" (snapped to next block)") : ""); signal_tocModified(UPD_TRACK_DATA | UPD_SAMPLE_MARKER); break; case 2: project_->statusMessage(_("Cannot add index at this point.")); break; case 3: project_->statusMessage(_("Track has already 98 index marks.")); break; default: project_->statusMessage(_("Internal error in addIndexMark(), " "please report.")); break; } } } void AudioCDView::addPregap() { unsigned long sample; if (!project_->tocEdit()->editable()) { project_->tocBlockedMsg(_("Add Pre-Gap")); return; } if (getMarker(&sample)) { long lba; int snapped = snapSampleToBlock(sample, &lba); switch (project_->tocEdit()->addPregap(lba)) { case 0: project_->statusMessage(_("Added pre-gap mark at %s%s."), Msf(lba).str(), snapped ? _(" (snapped to next block)") : ""); signal_tocModified(UPD_TRACK_DATA | UPD_SAMPLE_MARKER); break; case 2: project_->statusMessage(_("Cannot add pre-gap at this point.")); break; case 3: project_->statusMessage(_("Track would be shorter than 4 seconds.")); break; case 4: project_->statusMessage(_("Cannot modify a data track.")); break; default: project_->statusMessage(_("Internal error in addPregap(), " "please report.")); break; } } } void AudioCDView::removeTrackMark() { int trackNr; int indexNr; if (!project_->tocEdit()->editable()) { project_->tocBlockedMsg(_("Remove Track Mark")); return; } if (tocEditView_->trackSelection(&trackNr) && tocEditView_->indexSelection(&indexNr)) { switch (project_->tocEdit()->removeTrackMarker(trackNr, indexNr)) { case 0: project_->statusMessage(_("Removed track/index marker.")); signal_tocModified(UPD_TOC_DATA | UPD_TRACK_DATA | UPD_SAMPLE_MARKER); break; case 1: project_->statusMessage(_("Cannot remove first track.")); break; case 3: project_->statusMessage(_("Cannot modify a data track.")); break; default: project_->statusMessage(_("Internal error in removeTrackMark(), " "please report.")); break; } } else { project_->statusMessage(_("Please select a track/index mark.")); } } int AudioCDView::snapSampleToBlock(unsigned long sample, long *block) { unsigned long rest = sample % SAMPLES_PER_BLOCK; *block = sample / SAMPLES_PER_BLOCK; if (rest == 0) return 0; if (rest > SAMPLES_PER_BLOCK / 2) *block += 1; return 1; } void AudioCDView::trackMarkMovedCallback(const Track *, int trackNr, int indexNr, unsigned long sample) { if (!project_->tocEdit()->editable()) { project_->tocBlockedMsg(_("Move Track Marker")); return; } long lba; int snapped = snapSampleToBlock(sample, &lba); switch (project_->tocEdit()->moveTrackMarker(trackNr, indexNr, lba)) { case 0: project_->statusMessage(_("Moved track marker to %s%s."), Msf(lba).str(), snapped ? _(" (snapped to next block)") : ""); break; case 6: project_->statusMessage(_("Cannot modify a data track.")); break; default: project_->statusMessage(_("Illegal track marker position.")); break; } tocEditView_->trackSelection(trackNr); tocEditView_->indexSelection(indexNr); update(UPD_TRACK_MARK_SEL); } void AudioCDView::appendTrack() { addFileDialog_.mode(AddFileDialog::M_APPEND_TRACK); addFileDialog_.start(); } void AudioCDView::appendFile() { addFileDialog_.mode(AddFileDialog::M_APPEND_FILE); addFileDialog_.start(); } void AudioCDView::insertFile() { addFileDialog_.mode(AddFileDialog::M_INSERT_FILE); addFileDialog_.start(); } void AudioCDView::appendSilence() { if (addSilenceDialog_ == 0) { addSilenceDialog_ = new AddSilenceDialog(); addSilenceDialog_->set_transient_for(*project_->getParentWindow ()); addSilenceDialog_->signal_tocModified. connect(sigc::mem_fun(*this, &AudioCDView::update)); addSilenceDialog_->signal_fullView. connect(sigc::mem_fun(*this, &AudioCDView::fullView)); } addSilenceDialog_->mode(AddSilenceDialog::M_APPEND); addSilenceDialog_->start(tocEditView_); } void AudioCDView::insertSilence() { if (addSilenceDialog_ == 0) addSilenceDialog_ = new AddSilenceDialog(); addSilenceDialog_->mode(AddSilenceDialog::M_INSERT); addSilenceDialog_->start(tocEditView_); } const char *AudioCDView::sample2string(unsigned long sample) { static char buf[50]; unsigned long min = sample / (60 * 44100); sample %= 60 * 44100; unsigned long sec = sample / 44100; sample %= 44100; unsigned long frame = sample / 588; sample %= 588; snprintf(buf, sizeof(buf),"%2lu:%02lu:%02lu.%03lu", min, sec, frame, sample); return buf; } unsigned long AudioCDView::string2sample(const char *str) { int m = 0; int s = 0; int f = 0; int n = 0; sscanf(str, "%d:%d:%d.%d", &m, &s, &f, &n); if (m < 0) m = 0; if (s < 0 || s > 59) s = 0; if (f < 0 || f > 74) f = 0; if (n < 0 || n > 587) n = 0; return Msf(m, s, f).samples() + n; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/AudioCDView.h�������������������������������������������������������0000664�0000000�0000000�00000006067�15114537466�0021134�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 2000 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __AUDIO_CD_VIEW_H__ #define __AUDIO_CD_VIEW_H__ #include <gtkmm.h> #include <gtk/gtk.h> #include "AddFileDialog.h" #include "GenericView.h" #include <list> class SampleDisplay; class Project; class TrackInfoDialog; class AddFileDialog; class AddSilenceDialog; class Track; enum { TARGET_URI_LIST, }; class AudioCDView : public GenericView { public: AudioCDView(AudioCDProject *project); ~AudioCDView(); void add_menus(Glib::RefPtr<Gtk::UIManager> m_refUIManager); sigc::signal0<void> add_view; void update(unsigned long level = 0); enum Mode { ZOOM, SELECT }; void setMode(Mode); void zoomIn(); void zoomx2(); void zoomOut(); void fullView(); sigc::signal1<void, unsigned long> signal_tocModified; protected: static const char* sample2string(unsigned long sample); static unsigned long string2sample(const char* s); private: AudioCDProject *project_; Glib::RefPtr<Gtk::ActionGroup> m_refActionGroup; TrackInfoDialog* trackInfoDialog_; AddFileDialog addFileDialog_; AddSilenceDialog* addSilenceDialog_; Mode mode_; SampleDisplay *sampleDisplay_; Gtk::Entry* markerPos_; Gtk::Label* cursorPos_; Gtk::Entry* selectionStartPos_; Gtk::Entry* selectionEndPos_; void markerSetCallback(unsigned long); void cursorMovedCallback(unsigned long); void selectionSetCallback(unsigned long, unsigned long); void selectAll(); void selectionClearedCallback(); void trackMarkSelectedCallback(const Track *, int trackNr, int indexNr); void trackMarkMovedCallback(const Track *, int trackNr, int indexNr, unsigned long sample); void viewModifiedCallback(unsigned long, unsigned long); int snapSampleToBlock(unsigned long sample, long *block); void trackInfo(); void cutTrackData(); void pasteTrackData(); void addTrackMark(); void addIndexMark(); void addPregap(); void removeTrackMark(); void appendSilence(); void insertSilence(); void appendTrack(); void appendFile(); void insertFile(); int getMarker(unsigned long *sample); void markerSet(); void selectionSet(); void drag_data_received_cb(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, const Gtk::SelectionData& selection_data, guint info, guint time); }; #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/BUGS����������������������������������������������������������������0000664�0000000�0000000�00000002176�15114537466�0017340�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������Status Who Description ====== ====== ============================================================== - - Infinite messages from cdrdao if you close xcdrdao while extracting: xcdrdao should not exit!! and if xcdrdao crashes cdrdao should get a SIGPIPE, continue recording and send messages to stdout if appropiate, but don't try to send messages to xcdrdao again. - - In the Extract process xcdrdao is getting: 31 32 33 32 33 34 !! of trackProgress this makes the progressbar decrease and increase. It looks ugly :) - - Using a big number with buffers when recording won't work! 'new' throwing an exception? (try ... else ... ???) - - I can press the eject button on my cdrom and the CD will eject, the problem is that I'm extracting! xcdrdao/cdrdao should block the CD! until the operation is done. - - When writing (simulated!) I was not able to eject the CD, good :), but if I try (in gmc) right click->eject device, this command will block, and make cdrdao "hang" without any error messages until you abort the recording, then the CD will eject ;). The device should not receive any other command when writing!!! ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/BlankCDDialog.cc����������������������������������������������������0000664�0000000�0000000�00000023201�15114537466�0021532�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #include <gtkmm.h> #include <glibmm/i18n.h> #include "config.h" #include "guiUpdate.h" #include "xcdrdao.h" #include "ConfigManager.h" #include "DeviceList.h" #include "MessageBox.h" #include "BlankCDDialog.h" #include "Icons.h" BlankCDDialog::BlankCDDialog() { Gtk::VBox *vbox = new Gtk::VBox; vbox->set_border_width(10); vbox->set_spacing(10); add(*vbox); active_ = false; moreOptionsDialog_ = 0; speed_ = 1; Devices = new DeviceList(CdDevice::CD_RW); vbox->pack_start(*Devices, true, true); // device settings Gtk::Frame *blankOptionsFrame = new Gtk::Frame(_(" Blank Options ")); Gtk::VBox *frameBox = new Gtk::VBox; frameBox->set_border_width(5); frameBox->set_spacing(5); blankOptionsFrame->add(*frameBox); fastBlank_rb = new Gtk::RadioButton(_("Fast Blank - does not erase contents"), 0); fullBlank_rb = new Gtk::RadioButton(_("Full Blank - erases contents, slower"), 0); Gtk::RadioButton::Group rb_group = fastBlank_rb->get_group(); fullBlank_rb->set_group(rb_group); frameBox->pack_start(*fastBlank_rb); frameBox->pack_start(*fullBlank_rb); Gtk::Image *moreOptionsPixmap = manage(new Gtk::Image(Gtk::StockID(Gtk::Stock::PROPERTIES), Gtk::ICON_SIZE_SMALL_TOOLBAR)); Gtk::Label *moreOptionsLabel = manage(new Gtk::Label(_("More Options"))); Gtk::HBox *moreOptionsBox = manage(new Gtk::HBox); moreOptionsBox->set_border_width(2); Gtk::Button *moreOptionsButton = manage(new Gtk::Button()); moreOptionsBox->pack_start(*moreOptionsPixmap, false, false, 3); moreOptionsBox->pack_start(*moreOptionsLabel, false, false, 4); moreOptionsButton->add(*moreOptionsBox); moreOptionsButton->signal_clicked(). connect(mem_fun(*this, &BlankCDDialog::moreOptions)); moreOptionsBox = manage(new Gtk::HBox); frameBox->pack_start(*moreOptionsBox); moreOptionsBox->pack_end(*moreOptionsButton, false, false); vbox->pack_start(*blankOptionsFrame, false, false); Gtk::Image *pixmap = manage(new Gtk::Image(Icons::GCDMASTER, Gtk::ICON_SIZE_DIALOG)); Gtk::Label *startLabel = manage(new Gtk::Label(_("Start"))); Gtk::VBox *startBox = manage(new Gtk::VBox); Gtk::Button *button = manage(new Gtk::Button()); startBox->pack_start(*pixmap, false, false); startBox->pack_start(*startLabel, false, false); button->add(*startBox); button->signal_clicked().connect(mem_fun(*this, &BlankCDDialog::startAction)); Gtk::HBox *hbox2 = manage(new Gtk::HBox); hbox2->set_spacing(20); hbox2->set_border_width(10); hbox2->pack_start(*button); Gtk::Button* cancel_but = manage(new Gtk::Button(Gtk::StockID(Gtk::Stock::CANCEL))); cancel_but->signal_clicked().connect(mem_fun(*this, &BlankCDDialog::stop)); hbox2->pack_start(*cancel_but); vbox->pack_start(*hbox2, Gtk::PACK_SHRINK); show_all_children(); } void BlankCDDialog::moreOptions() { if (!moreOptionsDialog_) { moreOptionsDialog_ = new Gtk::MessageDialog(*this, _("Blank options"), false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_CLOSE, true); Gtk::Box *box = moreOptionsDialog_->get_vbox(); Gtk::Frame *frame = new Gtk::Frame(_(" More Blank Options ")); box->pack_start(*frame); Gtk::VBox* vbox = new Gtk::VBox; vbox->set_border_width(10); vbox->set_spacing(5); frame->add(*vbox); ejectButton_ = new Gtk::CheckButton(_("Eject the CD after blanking"), 0); ejectButton_->set_active(false); vbox->pack_start(*ejectButton_); reloadButton_ = new Gtk::CheckButton(_("Reload the CD after writing, if necessary"), 0); reloadButton_->set_active(false); vbox->pack_start(*reloadButton_); Gtk::HBox *hbox = new Gtk::HBox; Gtk::Label *label = new Gtk::Label(_("Speed: "), 0); hbox->pack_start(*label, false, false); Glib::RefPtr<Gtk::Adjustment> adjustment = Gtk::Adjustment::create(1, 1, 20); speedSpinButton_ = new Gtk::SpinButton(adjustment); speedSpinButton_->set_digits(0); speedSpinButton_->set_sensitive(false); adjustment->signal_value_changed(). connect(mem_fun(*this, &BlankCDDialog::speedChanged)); hbox->pack_start(*speedSpinButton_, false, false, 10); speedButton_ = new Gtk::CheckButton(_("Use max."), 0); speedButton_->set_active(true); speedButton_->signal_toggled(). connect(mem_fun(*this, &BlankCDDialog::speedButtonChanged)); hbox->pack_start(*speedButton_, true, true); vbox->pack_start(*hbox); moreOptionsDialog_->show_all_children(); } moreOptionsDialog_->show(); moreOptionsDialog_->run(); moreOptionsDialog_->hide(); } void BlankCDDialog::start(Gtk::Window& parent) { present(); active_ = true; parent_ = &parent; update(UPD_CD_DEVICES); } void BlankCDDialog::stop() { hide(); if (moreOptionsDialog_) moreOptionsDialog_->hide(); active_ = false; } void BlankCDDialog::update(unsigned long level) { if (!active_) return; set_title(_("Blank CD Rewritable")); if (level & UPD_CD_DEVICES) Devices->import(); else if (level & UPD_CD_DEVICE_STATUS) { Devices->importStatus(); Devices->selectOne(); } } bool BlankCDDialog::on_delete_event(GdkEventAny*) { stop(); return 1; } void BlankCDDialog::startAction() { if (Devices->selection().empty()) { Gtk::MessageDialog d(*this, _("Please select at least one recorder device"), Gtk::MESSAGE_WARNING); d.run(); return; } int fast; if (fastBlank_rb->get_active()) fast = 1; else fast = 0; int eject = checkEjectWarning(this); int reload = checkReloadWarning(this); int burnSpeed = getSpeed(); std::string targetData = Devices->selection(); CdDevice *writeDevice = CdDevice::find(targetData.c_str()); if (writeDevice) { if (writeDevice->blank(parent_, fast, burnSpeed, eject, reload) != 0) { Gtk::MessageDialog d(*this, _("Cannot start blanking"), Gtk::MESSAGE_ERROR); d.run(); } else guiUpdate(UPD_CD_DEVICE_STATUS); } stop(); } void BlankCDDialog::speedButtonChanged() { if (speedButton_->get_active()) { speedSpinButton_->set_sensitive(false); } else { speedSpinButton_->set_sensitive(true); } } void BlankCDDialog::speedChanged() { //FIXME: get max burn speed from selected burner(s) int new_speed = speedSpinButton_->get_value_as_int(); if ((new_speed % 2) == 1) { if (new_speed > 2) { if (new_speed > speed_) { new_speed = new_speed + 1; } else { new_speed = new_speed - 1; } } speedSpinButton_->set_value(new_speed); } speed_ = new_speed; } bool BlankCDDialog::getEject() { if (moreOptionsDialog_) return ejectButton_->get_active() ? 1 : 0; else return 0; } int BlankCDDialog::checkEjectWarning(Gtk::Window *parent) { // If ejecting the CD after recording is requested issue a warning message // because buffer under runs may occur for other devices that are recording. if (getEject()) { if (configManager->getEjectWarning()) { Ask3Box msg(parent, _("Request"), 1, 2, _("Ejecting a CD may block the SCSI bus and"), _("cause buffer under runs when other devices"), _("are still recording."), "", _("Keep the eject setting anyway?"), NULL); switch (msg.run()) { case 1: // keep eject setting if (msg.dontShowAgain()) { configManager->setEjectWarning(false); } return 1; break; case 2: // don't keep eject setting ejectButton_->set_active(false); return 0; break; default: // cancel return -1; break; } } return 1; } return 0; } bool BlankCDDialog::getReload() { if (moreOptionsDialog_) return reloadButton_->get_active() ? 1 : 0; else return 0; } int BlankCDDialog::checkReloadWarning(Gtk::Window *parent) { // The same is true for reloading the disk. if (getReload()) { if (configManager->getReloadWarning()) { Ask3Box msg(parent, _("Request"), 1, 2, _("Reloading a CD may block the SCSI bus and"), _("cause buffer under runs when other devices"), _("are still recording."), "", _("Keep the reload setting anyway?"), NULL); switch (msg.run()) { case 1: // keep reload setting if (msg.dontShowAgain()) { configManager->setReloadWarning(false); } return 1; break; case 2: // don't keep reload setting reloadButton_->set_active(false); return 0; break; default: // cancel return -1; break; } } return 1; } return 0; } int BlankCDDialog::getSpeed() { if (moreOptionsDialog_) { if (speedButton_->get_active()) return 0; else return speed_; } return 0; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/BlankCDDialog.h�����������������������������������������������������0000664�0000000�0000000�00000003263�15114537466�0021402�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998, 1999 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __BLANK_CD_DIALOG_H #define __BLANK_CD_DIALOG_H class Project; class DeviceList; class BlankCDDialog : public Gtk::Window { public: BlankCDDialog(); void start(Gtk::Window& parent); void update(unsigned long level); private: DeviceList *Devices; Gtk::Window* parent_; bool active_; int speed_; Gtk::RadioButton *fastBlank_rb; Gtk::RadioButton *fullBlank_rb; Gtk::MessageDialog *moreOptionsDialog_; Gtk::CheckButton *ejectButton_; Gtk::CheckButton *reloadButton_; Gtk::SpinButton *speedSpinButton_; Gtk::CheckButton *speedButton_; void stop(); void startAction(); void moreOptions(); void speedButtonChanged(); void speedChanged(); bool getEject(); int checkEjectWarning(Gtk::Window *); bool getReload(); int checkReloadWarning(Gtk::Window *); int getSpeed(); bool on_delete_event(GdkEventAny*); }; #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/CdDevice.cc���������������������������������������������������������0000664�0000000�0000000�00000062705�15114537466�0020636�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #include <sys/time.h> #include <sys/types.h> #include <stddef.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <errno.h> #include <ctype.h> #include <assert.h> #include <gtkmm.h> #include <glibmm/i18n.h> #include "TocEdit.h" #include "CdDevice.h" #include "ProcessMonitor.h" #include "xcdrdao.h" #include "guiUpdate.h" #include "ProgressDialog.h" #include "ConfigManager.h" #include "config.h" #include "remote.h" #include "ScsiIf.h" #include "CdrDriver.h" #include "util.h" #include "log.h" #include "Toc.h" #define DRIVER_IDS 13 #define DRIVER_ID_DEFAULT 2 CdDevice *CdDevice::DEVICE_LIST_ = NULL; const char *CdDevice::DRIVER_NAMES_[DRIVER_IDS] = { "Undefined", "cdd2600", "generic-mmc", "generic-mmc-raw", "plextor", "plextor-scan", "ricoh-mp6200", "sony-cdu920", "sony-cdu948", "taiyo-yuden", "teac-cdr55", "toshiba", "yamaha-cdr10x" }; CdDevice::CdDevice(const char* dev, const char *vendor, const char *product) { dev_ = dev; vendor_ = vendor; product_ = product; driverId_ = 0; driverOptions_ = 0; deviceType_ = CD_R; manuallyConfigured_ = false; status_ = DEV_UNKNOWN; exitStatus_ = 0; progressStatusChanged_ = 0; progressStatus_ = 0; progressTotalTracks_ = 0; progressTrack_ = 0; progressTotal_ = 0; progressTrackRelative_ = 0; progressBufferFill_ = 0; progressWriterFill_ = 0; process_ = NULL; scsiIf_ = NULL; scsiIfInitFailed_ = 0; next_ = NULL; slaveDevice_ = NULL; autoSelectDriver(); } CdDevice::~CdDevice() { delete scsiIf_; scsiIf_ = NULL; } Glib::ustring CdDevice::settingString() const { char buf[100]; Glib::ustring s; s = "'" + dev_ + "','"; s += vendor_; s += "','"; s += product_; s += "',"; switch (deviceType_) { case CD_R: s += "CD_R"; break; case CD_RW: s += "CD_RW"; break; case CD_ROM: s+= "CD_ROM"; break; } s += ","; s += driverName(driverId_); s += ","; snprintf(buf, sizeof(buf),"0x%lx", driverOptions_); s += buf; return s; } void CdDevice::driverId(int id) { if (id >= 0 && id < DRIVER_IDS) driverId_ = id; } void CdDevice::status(Status s) { status_ = s; } int CdDevice::exitStatus() const { return exitStatus_; } int CdDevice::autoSelectDriver() { unsigned long options = 0; const char *driverName; driverName = CdrDriver::selectDriver(1, vendor_.c_str(), product_.c_str(), &options); if (driverName) { driverId_ = driverName2Id(driverName); driverOptions_ = options; } else { cd_page_2a* p2a; ScsiIf* sif = new ScsiIf(dev_.c_str()); if (sif && sif->init() == 0 && (p2a = sif->checkMmc())) { driverId_ = driverName2Id("generic-mmc"); if (p2a->cd_r_read) deviceType_ = CD_ROM; if (p2a->cd_r_write) deviceType_ = CD_R; if (p2a->cd_rw_write) deviceType_ = CD_RW; } else { driverId_ = DRIVER_ID_DEFAULT; driverOptions_ = 0; } if (sif) delete sif; } return 1; } int CdDevice::updateStatus() { Status newStatus = status_; if (process_ != NULL) { if (process_->exited()) { newStatus = DEV_UNKNOWN; exitStatus_ = process_->exitStatus(); progressStatusChanged_ = 1; PROCESS_MONITOR->remove(process_); process_ = NULL; if (slaveDevice_ != NULL) { slaveDevice_->status(DEV_UNKNOWN); slaveDevice_ = NULL; } } } if (status_ == DEV_READY || status_ == DEV_BUSY || status_ == DEV_NO_DISK || status_ == DEV_UNKNOWN) { if (scsiIf_ == NULL) createScsiIf(); if (scsiIf_ != NULL) { switch (scsiIf_->testUnitReady()) { case 0: newStatus = DEV_READY; break; case 1: newStatus = DEV_BUSY; break; case 2: newStatus = DEV_NO_DISK; break; case 3: // Most likely a timeout error. newStatus = DEV_BUSY; break; } } else { newStatus = DEV_FAULT; } } if (newStatus != status_) { status_ = newStatus; return 1; } return 0; } bool CdDevice::updateProgress(Glib::IOCondition cond, int fd) { static unsigned char msgSync[4] = { 0xff, 0x00, 0xff, 0x00 }; fd_set fds; int state = 0; unsigned char buf[10]; struct timeval timeout = { 0, 0 }; if (process_ == NULL) return false; if (!(cond & Glib::IO_IN)) return false; FD_ZERO(&fds); FD_SET(fd, &fds); while (select(fd + 1, &fds, NULL, NULL, &timeout) > 0 && FD_ISSET(fd, &fds)) { FD_ZERO(&fds); FD_SET(fd, &fds); state = 0; while (state < 4) { if (read(fd, buf, 1) != 1) { //message(-2, "Reading of msg sync failed."); return false; } if (buf[0] == msgSync[state]) { state++; } else { state = 0; if (buf[0] == msgSync[state]) { state++; } } } ProgressMsg msg; int msgsize = read(fd, (char *)&msg, sizeof(msg)); if (msgsize >= PSGMSG_MINSIZE) { if (msg.status >= PGSMSG_MIN && msg.status <= PGSMSG_MAX && msg.track >= 0 && msg.totalProgress >= 0 && msg.totalProgress <= 1000 && msg.bufferFillRate >= 0 && msg.bufferFillRate <= 100) { progressStatus_ = msg.status; progressTotalTracks_ = msg.totalTracks; progressTrack_ = msg.track; progressTrackRelative_ = msg.trackProgress; progressTotal_ = msg.totalProgress; progressBufferFill_ = msg.bufferFillRate; if (msgsize == sizeof(msg)) progressWriterFill_ = msg.writerFillRate; else progressWriterFill_ = 0; progressStatusChanged_ = 1; } } else { log_message(-1, _("Reading of progress message failed.")); } } if (progressStatusChanged_) guiUpdate(UPD_PROGRESS_STATUS); return true; } CdDevice::DeviceType CdDevice::deviceType() const { return deviceType_; } void CdDevice::deviceType(DeviceType t) { deviceType_ = t; } unsigned long CdDevice::driverOptions() const { return driverOptions_; } void CdDevice::driverOptions(unsigned long o) { driverOptions_ = o; } bool CdDevice::ejectCd(bool load) { bool success = false; if (!scsiIf_) createScsiIf(); if (scsiIf_) { CdrDriver* driver = CdrDriver::createDriver(driverName(driverId_), driverOptions_, scsiIf_); int ret = driver->loadUnload((load ? 0 : 1)); success = (ret == 0); delete(driver); } return success; } // Starts a 'cdrdao' for recording given toc. Returns false if an // error occured and the process was not successfully launched. bool CdDevice::recordDao(Gtk::Window& parent, TocEdit *tocEdit, int simulate, int multiSession, int speed, int eject, int reload, int buffer, int overburn) { std::string tocFileName; const char *args[30]; int n = 0; char devname[30]; char drivername[50]; char speedbuf[20]; const char *s; char bufferbuf[20]; int remoteFdArgNum = 0; if ((status_ != DEV_READY && status_ != DEV_FAULT && status_ != DEV_UNKNOWN) || process_ != NULL) return false; // Not ideal, but NO alternatives with C++14. tocFileName = std::tmpnam(nullptr); tocFileName += ".gcdm.toc"; // Write out temporary toc file containing all the converted wav // files (don't want to rely on cdrdao doing the mp3->wav // translation, besides it's already been done). if (tocEdit->toc()->write(tocFileName, true != 0)) { log_message(-2, _("Cannot write temporary toc-file.")); return false; } Glib::ustring execName = configManager->getCdrdaoPath(); args[n++] = execName.c_str(); if (simulate) args[n++] = "simulate"; else args[n++] = "write"; args[n++] = "--remote"; remoteFdArgNum = n; args[n++] = NULL; args[n++] = "-v0"; if (multiSession) args[n++] = "--multi"; if (speed > 0) { snprintf(speedbuf, sizeof(speedbuf), "%d", speed); args[n++] = "--speed"; args[n++] = speedbuf; } if (eject) args[n++] = "--eject"; if (reload) args[n++] = "--reload"; if (overburn) args[n++] = "--overburn"; args[n++] = "--device"; args[n++] = (char*)dev_.c_str(); if (driverId_ > 0) { snprintf(drivername, sizeof(drivername), "%s:0x%lx", driverName(driverId_), driverOptions_); args[n++] = "--driver"; args[n++] = drivername; } if (buffer >= 10) { snprintf(bufferbuf, sizeof(bufferbuf), "%i", buffer); args[n++] = "--buffers"; args[n++] = bufferbuf; } args[n++] = tocFileName.c_str(); args[n++] = NULL; assert(n <= 20); PROGRESS_POOL->start(parent, this, tocEdit->filename()); // Remove the SCSI interface of this device to avoid problems with double // usage of device nodes. delete scsiIf_; scsiIf_ = NULL; process_ = PROCESS_MONITOR->start(execName.c_str(), args, remoteFdArgNum); if (process_ != NULL) { status_ = DEV_RECORDING; action_ = A_RECORD; if (process_->commFd() >= 0) { Glib::signal_io().connect(bind(mem_fun(*this, &CdDevice::updateProgress), process_->commFd()), process_->commFd(), Glib::IO_IN | Glib::IO_HUP); } return true; } else { unlink(tocFileName.c_str()); return false; } } void CdDevice::abortDaoRecording() { if (process_ != NULL && !process_->exited()) { PROCESS_MONITOR->stop(process_); } } int CdDevice::progressStatusChanged() { if (progressStatusChanged_) { progressStatusChanged_ = 0; return 1; } return 0; } void CdDevice::progress(int *status, int *totalTracks, int *track, int *trackProgress, int *totalProgress, int *bufferFill, int *writerFill) const { *status = progressStatus_; *totalTracks = progressTotalTracks_; *track = progressTrack_; *trackProgress = progressTrackRelative_; *totalProgress = progressTotal_; *bufferFill = progressBufferFill_; *writerFill = progressWriterFill_; } // Starts a 'cdrdao' for reading whole cd. // Return: 0: OK, process succesfully launched // 1: error occured int CdDevice::extractDao(Gtk::Window& parent, const char *tocFileName, int correction, int readSubChanMode) { const char *args[30]; int n = 0; char devname[30]; char drivername[50]; const char *s; char correctionbuf[20]; int remoteFdArgNum = 0; if ((status_ != DEV_READY && status_ != DEV_FAULT && status_ != DEV_UNKNOWN) || process_ != NULL) return 1; Glib::ustring execName = configManager->getCdrdaoPath(); args[n++] = execName.c_str(); args[n++] = "read-cd"; args[n++] = "--remote"; remoteFdArgNum = n; args[n++] = NULL; args[n++] = "-v0"; args[n++] = "--read-raw"; switch (readSubChanMode) { case 1: args[n++] = "--read-subchan"; args[n++] = "rw"; break; case 2: args[n++] = "--read-subchan"; args[n++] = "rw_raw"; break; } args[n++] = "--device"; args[n++] = (char*)dev_.c_str(); if (driverId_ > 0) { snprintf(drivername, sizeof(drivername), "%s:0x%lx", driverName(driverId_), driverOptions_); args[n++] = "--driver"; args[n++] = drivername; } snprintf(correctionbuf, sizeof(correctionbuf), "%d", correction); args[n++] = "--paranoia-mode"; args[n++] = correctionbuf; args[n++] = "--datafile"; args[n++] = g_strdup_printf("%s.bin", tocFileName); args[n++] = g_strdup_printf("%s.toc", tocFileName); args[n++] = NULL; assert(n <= 20); PROGRESS_POOL->start(parent, this, tocFileName, false, false); // Remove the SCSI interface of this device to avoid problems with double // usage of device nodes. delete scsiIf_; scsiIf_ = NULL; process_ = PROCESS_MONITOR->start(execName.c_str(), args, remoteFdArgNum); if (process_ != NULL) { status_ = DEV_READING; action_ = A_READ; if (process_->commFd() >= 0) { Glib::signal_io().connect(bind(mem_fun(*this, &CdDevice::updateProgress), process_->commFd()), process_->commFd(), Glib::IO_IN | Glib::IO_PRI | Glib::IO_ERR | Glib::IO_HUP); } return 0; } else { return 1; } } void CdDevice::abortDaoReading() { if (process_ != NULL && !process_->exited()) { PROCESS_MONITOR->stop(process_); } } // Starts a 'cdrdao' for duplicating a CD. // Return: 0: OK, process succesfully launched // 1: error occured int CdDevice::duplicateDao(Gtk::Window& parent, int simulate, int multiSession, int speed, int eject, int reload, int buffer, int onthefly, int correction, int readSubChanMode, CdDevice *readdev) { const char *args[30]; int n = 0; char devname[30]; char drivername[50]; char r_drivername[50]; char speedbuf[20]; char correctionbuf[20]; const char *s; char bufferbuf[20]; int remoteFdArgNum = 0; int rdstat = readdev->status(); if ((rdstat != DEV_READY && rdstat != DEV_UNKNOWN && rdstat != DEV_FAULT) || readdev->process() != NULL) return 1; if ((status_ != DEV_READY && status_ != DEV_FAULT && status_ != DEV_UNKNOWN) || process_ != NULL) return 1; Glib::ustring execName = configManager->getCdrdaoPath(); args[n++] = execName.c_str(); args[n++] = "copy"; if (simulate) args[n++] = "--simulate"; args[n++] = "--remote"; remoteFdArgNum = n; args[n++] = NULL; args[n++] = "-v0"; if (multiSession) args[n++] = "--multi"; snprintf(correctionbuf, sizeof(correctionbuf), "%d", correction); args[n++] = "--paranoia-mode"; args[n++] = correctionbuf; if (speed > 0) { snprintf(speedbuf, sizeof(speedbuf), "%d", speed); args[n++] = "--speed"; args[n++] = speedbuf; } if (eject) args[n++] = "--eject"; if (reload) args[n++] = "--reload"; if (onthefly) args[n++] = "--on-the-fly"; switch (readSubChanMode) { case 1: args[n++] = "--read-subchan"; args[n++] = "rw"; break; case 2: args[n++] = "--read-subchan"; args[n++] = "rw_raw"; break; } args[n++] = "--device"; args[n++] = (char*)dev_.c_str(); if (driverId_ > 0) { snprintf(drivername, sizeof(drivername), "%s:0x%lx", driverName(driverId_), driverOptions_); args[n++] = "--driver"; args[n++] = drivername; } if (readdev != this) { // reader and write the same, skip source device args[n++] = "--source-device"; args[n++] = (char*)readdev->dev(); if (readdev->driverId() > 0) { snprintf(r_drivername, sizeof(r_drivername), "%s:0x%lx", driverName(readdev->driverId()), readdev->driverOptions()); args[n++] = "--source-driver"; args[n++] = r_drivername; } } if (buffer >= 10) { snprintf(bufferbuf, sizeof(bufferbuf), "%i", buffer); args[n++] = "--buffers"; args[n++] = bufferbuf; } args[n++] = NULL; assert(n <= 25); PROGRESS_POOL->start(parent, this, _("CD to CD copy")); // Remove the SCSI interface of this device to avoid problems with double // usage of device nodes. delete scsiIf_; scsiIf_ = NULL; process_ = PROCESS_MONITOR->start(execName.c_str(), args, remoteFdArgNum); if (process_ != NULL) { slaveDevice_ = readdev; slaveDevice_->status(DEV_READING); status_ = DEV_RECORDING; action_ = A_DUPLICATE; if (process_->commFd() >= 0) { Glib::signal_io().connect(bind(mem_fun(*this, &CdDevice::updateProgress), process_->commFd()), process_->commFd(), Glib::IO_IN | Glib::IO_HUP); } return 0; } else { return 1; } } void CdDevice::abortDaoDuplication() { if (process_ != NULL && !process_->exited()) { PROCESS_MONITOR->stop(process_); } } // Starts a 'cdrdao' for blanking a CD. // Return: 0: OK, process succesfully launched // 1: error occured int CdDevice::blank(Gtk::Window* parent, int fast, int speed, int eject, int reload) { const char *args[20]; int n = 0; char devname[30]; char drivername[50]; char speedbuf[20]; const char *s; int remoteFdArgNum = 0; if ((status_ != DEV_READY && status_ != DEV_FAULT && status_ != DEV_UNKNOWN) || process_ != NULL) return 1; Glib::ustring execName = configManager->getCdrdaoPath(); args[n++] = execName.c_str(); args[n++] = "blank"; args[n++] = "--remote"; remoteFdArgNum = n; args[n++] = NULL; args[n++] = "-v0"; args[n++] = "--blank-mode"; if (fast) args[n++] = "minimal"; else args[n++] = "full"; if (speed > 0) { snprintf(speedbuf, sizeof(speedbuf), "%d", speed); args[n++] = "--speed"; args[n++] = speedbuf; } if (eject) args[n++] = "--eject"; if (reload) args[n++] = "--reload"; args[n++] = "--device"; args[n++] = (char*)dev_.c_str(); if (driverId_ > 0) { snprintf(drivername, sizeof(drivername), "%s:0x%lx", driverName(driverId_), driverOptions_); args[n++] = "--driver"; args[n++] = drivername; } args[n++] = NULL; assert(n <= 20); if (parent) PROGRESS_POOL->start(*parent, this, _("Blanking CDRW"), false, false); else PROGRESS_POOL->start(this, _("Blanking CDRW"), false, false); // Remove the SCSI interface of this device to avoid problems with double // usage of device nodes. delete scsiIf_; scsiIf_ = NULL; process_ = PROCESS_MONITOR->start(execName.c_str(), args, remoteFdArgNum); if (process_ != NULL) { status_ = DEV_BLANKING; action_ = A_BLANK; if (process_->commFd() >= 0) { Glib::signal_io().connect(bind(mem_fun(*this, &CdDevice::updateProgress), process_->commFd()), process_->commFd(), Glib::IO_IN | Glib::IO_HUP); } return 0; } else { return 1; } } void CdDevice::abortBlank() { if (process_ != NULL && !process_->exited()) { PROCESS_MONITOR->stop(process_); } } void CdDevice::createScsiIf() { char buf[100]; if (scsiIfInitFailed_) return; delete scsiIf_; scsiIf_ = new ScsiIf(dev_.c_str()); if (scsiIf_->init() != 0) { delete scsiIf_; scsiIf_ = NULL; scsiIfInitFailed_ = 1; } } int CdDevice::driverName2Id(const char *driverName) { int i; for (i = 1; i < DRIVER_IDS; i++) { if (strcmp(DRIVER_NAMES_[i], driverName) == 0) return i; } return 0; } int CdDevice::maxDriverId() { return DRIVER_IDS - 1; } const char *CdDevice::driverName(int id) { if (id >= 0 && id < DRIVER_IDS) { return DRIVER_NAMES_[id]; } else { return "Undefined"; } } const char *CdDevice::status2string(Status s) { const char *ret = NULL; switch (s) { case DEV_READY: ret = "Ready"; break; case DEV_RECORDING: ret = "Recording"; break; case DEV_READING: ret = "Reading"; break; case DEV_WAITING: ret = "Waiting"; break; case DEV_BLANKING: ret = "Blanking"; break; case DEV_BUSY: ret = "Busy"; break; case DEV_NO_DISK: ret = "No disk"; break; case DEV_FAULT: ret = "Not available"; break; case DEV_UNKNOWN: ret = "Unknown"; break; } return ret; } const char *CdDevice::deviceType2string(DeviceType t) { const char *ret = NULL; switch (t) { case CD_R: ret = "CD-R"; break; case CD_RW: ret = "CD-RW"; break; case CD_ROM: ret = "CD-ROM"; break; } return ret; } /* reads configured devices from gnome settings */ void CdDevice::importSettings() { CdDevice *dev; std::vector<Glib::ustring> settingsStrings = configManager->getConfiguredDevices(); std::vector<Glib::ustring>::iterator i; for (i = settingsStrings.begin(); i != settingsStrings.end(); ++i) { if (!i->empty()) { if ((dev = CdDevice::add(i->c_str())) != NULL) dev->manuallyConfigured(true); } } } /* saves manually configured devices as gnome settings */ void CdDevice::exportSettings() { CdDevice* drun; int n; std::vector<Glib::ustring> settingStrings; for (drun = first(), n = 0; drun != NULL; drun = next(drun)) { if (drun->manuallyConfigured()) { settingStrings.push_back(drun->settingString()); n++; } } try { configManager->setConfiguredDevices(settingStrings); } catch (const Glib::Error& e) { std::cerr << e.what() << std::endl; } } CdDevice *CdDevice::add(const char* dev, const char *vendor, const char *product) { CdDevice *run, *pred, *ent; for (pred = NULL, run = DEVICE_LIST_; run != NULL; pred = run, run = run->next_) { if (strcmp(run->dev(), dev) == 0) return run; } ent = new CdDevice(dev, vendor, product); if (pred != NULL) { ent->next_ = pred->next_; pred->next_ = ent; } else { ent->next_ = DEVICE_LIST_; DEVICE_LIST_ = ent; } return ent; } static char *nextToken(char *&p) { char *val = NULL; if (p == NULL || *p == 0) return NULL; while (*p != 0 && isspace(*p)) p++; if (*p == 0) return NULL; if (*p == '\'') { p++; val = p; while (*p != 0 && *p != '\'') p++; if (*p == 0) { // error, no matching ' found return NULL; } else { *p++ = 0; // skip over , while (*p != 0 && *p != ',') p++; if (*p == ',') p++; } } else { val = p; while (*p != 0 && *p != ',') p++; if (*p == ',') *p++ = 0; } return val; } static CdDevice *addImpl(char *s) { char *p; int driverId; std::string dev; std::string vendor; std::string model; std::string device; unsigned long options; char *val; CdDevice::DeviceType type; CdDevice *cddev; if (s[0] != '\'') return NULL; p = s; if ((val = nextToken(p)) == NULL) return NULL; dev = val; if ((val = nextToken(p)) == NULL) return NULL; vendor = val; if ((val = nextToken(p)) == NULL) return NULL; model = val; if ((val = nextToken(p)) == NULL) return NULL; if (strcasecmp(val, "CD_R") == 0) type = CdDevice::CD_R; else if (strcasecmp(val, "CD_RW") == 0) type = CdDevice::CD_RW; else if (strcasecmp(val, "CD_ROM") == 0) type = CdDevice::CD_ROM; else type = CdDevice::CD_R; if ((val = nextToken(p)) == NULL) return NULL; driverId = CdDevice::driverName2Id(val); if ((val = nextToken(p)) == NULL) return NULL; options = strtoul(val, NULL, 0); cddev = CdDevice::add(dev.c_str(), vendor.c_str(), model.c_str()); cddev->driverId(driverId); cddev->deviceType(type); cddev->driverOptions(options); return cddev; } CdDevice *CdDevice::add(const char *setting) { char *s = strdupCC(setting); CdDevice *dev = addImpl(s); delete[] s; return dev; } CdDevice *CdDevice::find(const char* dev) { CdDevice *run; for (run = DEVICE_LIST_; run != NULL; run = run->next_) { if (strcmp(run->dev(), dev) == 0) return run; } return NULL; } void CdDevice::scan() { int i, len; ScsiIf::ScanData *sdata = ScsiIf::scan(&len); if (sdata) { for (i = 0; i < len; i++) CdDevice::add(sdata[i].dev.c_str(), sdata[i].vendor, sdata[i].product); delete[] sdata; } #ifdef SCSI_ATAPI sdata = ScsiIf::scan(&len, "ATA"); if (sdata) { for (i = 0; i < len; i++) CdDevice::add(sdata[i].dev.c_str(), sdata[i].vendor, sdata[i].product); delete[] sdata; } else { // Only scan for ATAPI devices if we got nothing on the ATA // interface, otherwise every device would show up twice on the // list. sdata = ScsiIf::scan(&len, "ATAPI"); if (sdata) { for (i = 0; i < len; i++) CdDevice::add(sdata[i].dev.c_str(), sdata[i].vendor, sdata[i].product); delete[] sdata; } } #endif } void CdDevice::remove(const char* dev) { CdDevice *run, *pred; for (pred = NULL, run = DEVICE_LIST_; run != NULL; pred = run, run = run->next_) { if (strcmp(run->dev(), dev) == 0) { if (run->status() == DEV_RECORDING || run->status() == DEV_BLANKING || run->status() == DEV_READING || run->status() == DEV_WAITING) return; if (pred != NULL) pred->next_ = run->next_; else DEVICE_LIST_ = run->next_; delete run; return; } } } void CdDevice::clear() { CdDevice *next; while (DEVICE_LIST_ != NULL) { next = DEVICE_LIST_->next_; delete DEVICE_LIST_; DEVICE_LIST_ = next; } } CdDevice *CdDevice::first() { return DEVICE_LIST_; } CdDevice *CdDevice::next(const CdDevice *run) { if (run != NULL) return run->next_; else return NULL; } int CdDevice::count() { CdDevice *run; int cnt = 0; for (run = DEVICE_LIST_; run != NULL; run = run->next_) cnt++; return cnt; } int CdDevice::updateDeviceStatus() { int newStatus = 0; CdDevice *run; blockProcessMonitorSignals(); for (run = DEVICE_LIST_; run != NULL; run = run->next_) { if (run->updateStatus()) newStatus = 1; } unblockProcessMonitorSignals(); return newStatus; } �����������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/CdDevice.h����������������������������������������������������������0000664�0000000�0000000�00000011463�15114537466�0020473�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __CD_DEVICE_H__ #define __CD_DEVICE_H__ #include <sigc++/trackable.h> #include <gdk/gdk.h> #include <string> #include "Project.h" class TocEdit; class Process; class ScsiIf; class CdDevice : public sigc::trackable { public: enum Status { DEV_READY, DEV_RECORDING, DEV_READING, DEV_WAITING, DEV_BUSY, DEV_NO_DISK, DEV_BLANKING, DEV_FAULT, DEV_UNKNOWN }; enum DeviceType { CD_R, CD_RW, CD_ROM }; enum Action { A_RECORD, A_READ, A_DUPLICATE, A_BLANK, A_NONE }; CdDevice(const char* dev, const char *vendor, const char *product); ~CdDevice(); Glib::ustring settingString() const; const char *dev() const { return dev_.c_str(); } const char *vendor() const { return vendor_.c_str(); } const char *product() const { return product_.c_str(); } Status status() const { return status_; } Process *process() const { return process_; } int exitStatus() const; void status(Status); int updateStatus(); Action action() const { return action_; } bool updateProgress(Glib::IOCondition, int fd); int autoSelectDriver(); int driverId() const { return driverId_; } void driverId(int); DeviceType deviceType() const; void deviceType(DeviceType); unsigned long driverOptions() const; void driverOptions(unsigned long); bool manuallyConfigured() const { return manuallyConfigured_; } void manuallyConfigured(bool b) { manuallyConfigured_ = b; } bool ejectCd(bool load=false); bool loadCd() { return ejectCd(true); } bool recordDao(Gtk::Window& parent, TocEdit *, int simulate, int multiSession, int speed, int eject, int reload, int buffer, int overburn); void abortDaoRecording(); int extractDao(Gtk::Window& parent, const char *tocFileName, int correction, int readSubChanMode); void abortDaoReading(); int duplicateDao(Gtk::Window& parent, int simulate, int multiSession, int speed, int eject, int reload, int buffer, int onthefly, int correction, int readSubChanMode, CdDevice *readdev); void abortDaoDuplication(); int blank(Gtk::Window* parent, int fast, int speed, int eject, int reload); void abortBlank(); int progressStatusChanged(); void progress(int *status, int *totalTracks, int *track, int *trackProgress, int *totalProgress, int *bufferFill, int *writerFill) const; static int maxDriverId(); static const char *driverName(int id); static int driverName2Id(const char *); static const char *status2string(Status); static const char *deviceType2string(DeviceType); static void importSettings(); static void exportSettings(); static CdDevice *add(const char* scsidev, const char *vendor, const char *product); static CdDevice *add(const char *setting); static CdDevice *find(const char* dev); static void scan(); static void remove(const char* dev); static void clear(); static CdDevice *first(); static CdDevice *next(const CdDevice *); static int updateDeviceStatus(); /* not used anymore since Gtk::Main::input signal will call * CdDevice::updateProgress directly. static int updateDeviceProgress(); */ static int count(); private: std::string dev_; // SCSI device std::string vendor_; std::string product_; DeviceType deviceType_; int driverId_; unsigned long driverOptions_; bool manuallyConfigured_; ScsiIf *scsiIf_; int scsiIfInitFailed_; Status status_; enum Action action_; int exitStatus_; int progressStatusChanged_; int progressStatus_; int progressTotalTracks_; int progressTrack_; int progressTotal_; int progressTrackRelative_; int progressBufferFill_; int progressWriterFill_; Process *process_; CdDevice *next_; CdDevice *slaveDevice_; // slave device (used when copying etc.) void createScsiIf(); static const char *DRIVER_NAMES_[]; static CdDevice *DEVICE_LIST_; }; #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/CdTextDialog.cc�����������������������������������������������������0000664�0000000�0000000�00000023614�15114537466�0021477�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #include "config.h" #include "CdTextDialog.h" #include <gtkmm.h> #include <glibmm/i18n.h> #include <stddef.h> #include <string.h> #include "TocEdit.h" #include "Toc.h" #include "util.h" #include "guiUpdate.h" CdTextDialog::CdTextDialog() { int i; Gtk::VBox *contents = manage(new Gtk::VBox); char buf[20]; active_ = false; tocEdit_ = NULL; trackEntries_ = 0; set_hexpand(true); set_vexpand(true); languages_ = manage(new Gtk::Notebook); for (i = 0; i < 8; i++) { page_[i].table = new Gtk::Grid(); page_[i].table->set_row_homogeneous(false); page_[i].table->set_row_spacing(5); page_[i].table->set_column_spacing(5); page_[i].performer = manage(new Gtk::Entry); page_[i].title = manage(new Gtk::Entry); page_[i].tabLabel = new Gtk::Label(""); page_[i].performerButton = new Gtk::CheckButton(_("Enable Performer Entries")); page_[i].performerButton->set_active(false); page_[i].performerButton->signal_toggled(). connect(bind(mem_fun(*this, &CdTextDialog::activatePerformerAction), i)); page_[i].tracks = NULL; page_[i].table->attach(*(new Gtk::Label(_("Performer"))), 1, 0); page_[i].table->attach(*(new Gtk::Label(_("Title"))), 2, 0); { Gtk::HBox *hbox = manage(new Gtk::HBox); hbox->pack_end(*(new Gtk::Label(_("Album")))); page_[i].table->attach(*hbox, 0, 1); page_[i].title->set_hexpand(true); page_[i].table->attach(*(page_[i].title), 2, 1); page_[i].table->attach(*(page_[i].performer), 1, 1); } { Gtk::HBox *hbox = manage(new Gtk::HBox); hbox->pack_start(*(page_[i].performerButton)); page_[i].table->attach(*hbox, 1, 2); } { Gtk::HBox *hbox1 = manage(new Gtk::HBox); Gtk::VBox *vbox1 = manage(new Gtk::VBox); hbox1->pack_start(*(page_[i].table), true, true, 5); vbox1->pack_start(*hbox1, false, false, 5); Gtk::ScrolledWindow *swin = manage(new Gtk::ScrolledWindow); swin->set_propagate_natural_height(); swin->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); swin->show_all(); swin->add(*vbox1); snprintf(buf, sizeof(buf)," %d ", i); languages_->append_page(*swin, *(page_[i].tabLabel)); } } contents->pack_start(*languages_); { Gtk::HBox *hbox = manage(new Gtk::HBox); hbox->pack_start(*contents, true, true, 10); get_vbox()->pack_start(*hbox, true, true, 10); } Gtk::HButtonBox *bbox = new Gtk::HButtonBox(Gtk::BUTTONBOX_SPREAD); applyButton_ = new Gtk::Button(Gtk::StockID(Gtk::Stock::APPLY)); bbox->pack_start(*applyButton_); applyButton_->signal_clicked().connect(mem_fun(*this, &CdTextDialog::applyAction)); Gtk::Button *fillButton = new Gtk::Button(_(" Fill Performer ")); fillButton->signal_clicked().connect(mem_fun(*this, &CdTextDialog::fillPerformerAction)); Gtk::Button *cancelButton = new Gtk::Button(Gtk::StockID(Gtk::Stock::CLOSE)); bbox->pack_start(*cancelButton); cancelButton->signal_clicked().connect(mem_fun(*this, &CdTextDialog::stop)); get_action_area()->pack_start(*bbox); show_all_children(); set_title(_("CD-TEXT Entry")); } CdTextDialog::~CdTextDialog() { } bool CdTextDialog::on_delete_event(GdkEventAny*) { stop(); return 1; } void CdTextDialog::updateTabLabels() { const Toc *toc = tocEdit_->toc(); int l; for (l = 0; l < 8; l++) { const char *s = CdTextContainer::languageName(toc->cdTextLanguage(l)); if (page_[l].tabLabel->get_label() != s) page_[l].tabLabel->set_label(s); } } void CdTextDialog::adjustTableEntries(int n) { int i, l; char buf[20]; if (trackEntries_ == n) return; for (l = 0; l < 8; l++) { if (n < trackEntries_) { for (i = n; i < trackEntries_; i++) { delete page_[l].tracks[i].performer; delete page_[l].tracks[i].title; delete page_[l].tracks[i].hbox; delete page_[l].tracks[i].label; } } else { int performerActive = page_[l].performerButton->get_active(); TableEntry *newTracks = new TableEntry[n]; for (i = 0; i < trackEntries_; i++) newTracks[i] = page_[l].tracks[i]; delete[] page_[l].tracks; page_[l].tracks = newTracks; for (i = trackEntries_; i < n; i++) { snprintf(buf, sizeof(buf),_("Track %02d"), i + 1); page_[l].tracks[i].performer = manage(new Gtk::Entry); page_[l].tracks[i].performer->set_sensitive(performerActive); page_[l].tracks[i].title = manage(new Gtk::Entry); page_[l].tracks[i].label = new Gtk::Label(buf); page_[l].tracks[i].hbox = manage(new Gtk::HBox); page_[l].tracks[i].hbox->pack_end(*(page_[l].tracks[i].label), Gtk::PACK_SHRINK); page_[l].table->attach(*(page_[l].tracks[i].hbox), 0, i + 3); page_[l].table->attach(*(page_[l].tracks[i].title), 2, i + 3); page_[l].table->attach(*(page_[l].tracks[i].performer), 1, i + 3); } page_[l].table->show_all(); } } trackEntries_ = n; } void CdTextDialog::update(unsigned long level, TocEdit *view) { if (view != tocEdit_) { tocEdit_ = view; level = UPD_ALL; } std::string s(view->filename()); s += " - "; s += APP_NAME; if (view->tocDirty()) s += "(*)"; set_title(s); if (level & UPD_TOC_DATA) { updateTabLabels(); } if ((level & UPD_TOC_DATA) || (level & UPD_TRACK_DATA)) { importData(); } if (level & UPD_EDITABLE_STATE) { applyButton_->set_sensitive(tocEdit_->editable() ? true : false); } } void CdTextDialog::start(TocEdit *view) { update(UPD_ALL, view); present(); active_ = true; } void CdTextDialog::stop() { hide(); active_ = false; } void CdTextDialog::applyAction() { if (tocEdit_ == NULL || !tocEdit_->editable()) return; exportData(); guiUpdate(); } void CdTextDialog::fillPerformerAction() { int l = languages_->get_current_page(); if (l >= 0 && l <= 7) { int i; const char *s = checkString(page_[l].performer->get_text()); if (s == NULL) return; char *performer = strdupCC(s); for (i = 0; i < trackEntries_; i++) { if (checkString(page_[l].tracks[i].performer->get_text()) == NULL) page_[l].tracks[i].performer->set_text(performer); } delete[] performer; } } void CdTextDialog::activatePerformerAction(int l) { int i; int val = page_[l].performerButton->get_active(); for (i = 0; i < trackEntries_; i++) { page_[l].tracks[i].performer->set_sensitive(val); } } void CdTextDialog::importData() { const CdTextItem *item; const Toc *toc = tocEdit_->toc(); int i, l; int n = toc->nofTracks(); adjustTableEntries(n); for (l = 0; l < 8; l++) { if ((item = toc->getCdTextItem(0, l, CdTextItem::PackType::TITLE)) != NULL) page_[l].title->set_text(item->getText()); else page_[l].title->set_text(""); if ((item = toc->getCdTextItem(0, l, CdTextItem::PackType::PERFORMER)) != NULL) page_[l].performer->set_text(item->getText()); else page_[l].performer->set_text(""); for (i = 0; i < n; i++) { if ((item = toc->getCdTextItem(i + 1, l, CdTextItem::PackType::TITLE)) != NULL) page_[l].tracks[i].title->set_text(item->getText()); else page_[l].tracks[i].title->set_text(""); if ((item = toc->getCdTextItem(i + 1, l, CdTextItem::PackType::PERFORMER)) != NULL) page_[l].tracks[i].performer->set_text(item->getText()); else page_[l].tracks[i].performer->set_text(""); } } } void CdTextDialog::exportData() { int i, l; for (l = 0; l < 8; l++) { setCdTextItem(CdTextItem::PackType::TITLE, 0, l, checkString(page_[l].title->get_text())); setCdTextItem(CdTextItem::PackType::PERFORMER, 0, l, checkString(page_[l].performer->get_text())); for (i = 0; i < trackEntries_; i++) { setCdTextItem(CdTextItem::PackType::TITLE, i + 1, l, checkString(page_[l].tracks[i].title->get_text())); setCdTextItem(CdTextItem::PackType::PERFORMER, i + 1, l, checkString(page_[l].tracks[i].performer->get_text())); } } } void CdTextDialog::setCdTextItem(CdTextItem::PackType type, int trackNr, int l, const char *s) { const CdTextItem *item; TocEdit *tocEdit = tocEdit_; const Toc *toc = tocEdit->toc(); CdTextItem *newItem; if (s != NULL) { newItem = new CdTextItem(type, l); newItem->setText(s); } else newItem = NULL; if ((item = toc->getCdTextItem(trackNr, l, type)) != NULL) { if (newItem == NULL) tocEdit->setCdTextItem(trackNr, type, l, NULL); else if (*newItem != *item) tocEdit->setCdTextItem(trackNr, type, l, s); } else if (newItem != NULL) { tocEdit->setCdTextItem(trackNr, type, l, s); } delete newItem; } const char *CdTextDialog::checkString(const std::string &str) { static char *buf = NULL; static long bufLen = 0; char *p, *s; long len = strlen(str.c_str()); if (len == 0) return NULL; if (buf == NULL || len + 1 > bufLen) { delete[] buf; bufLen = len + 1; buf = new char[bufLen]; } strcpy(buf, str.c_str()); s = buf; p = buf + len - 1; while (*s != 0 && isspace(*s)) s++; if (*s == 0) return NULL; while (p > s && isspace(*p)) { *p = 0; p--; } return s; } ��������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/CdTextDialog.h������������������������������������������������������0000664�0000000�0000000�00000003723�15114537466�0021340�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __CD_TEXT_DIALOG_H__ #define __CD_TEXT_DIALOG_H__ #include <gtkmm.h> #include <gtk/gtk.h> //#include "Toc.h" #include "CdTextItem.h" class TocEdit; class CdTextDialog : public Gtk::Dialog { public: CdTextDialog(); ~CdTextDialog(); bool on_delete_event(GdkEventAny*); void update(unsigned long, TocEdit *); void start(TocEdit *); void stop(); private: bool active_; TocEdit *tocEdit_; int trackEntries_; Gtk::Button *applyButton_; Gtk::Notebook *languages_; struct TableEntry { Gtk::Entry *performer; Gtk::Entry *title; Gtk::Label *label; Gtk::HBox *hbox; }; struct Language { Gtk::Grid *table; Gtk::Entry *performer; Gtk::Entry *title; Gtk::Label *tabLabel; Gtk::CheckButton *performerButton; TableEntry *tracks; }; Language page_[8]; void adjustTableEntries(int); void updateTabLabels(); void applyAction(); void fillPerformerAction(); void activatePerformerAction(int); void importData(); void exportData(); void setCdTextItem(CdTextItem::PackType, int trackNr, int l, const char *); const char *checkString(const std::string &); }; #endif ���������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/ConfigManager.cc����������������������������������������������������0000664�0000000�0000000�00000005522�15114537466�0021662�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 2007 Denis Leroy * * 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. */ #include "ConfigManager.h" static const char* NAME_SCHEMA = "org.gnome.gcdmaster"; static const char* KEY_CDRDAO_PATH = "cdrdao-path"; static const char* KEY_TEMP_DIR = "temp-dir"; static const char* KEY_RECORD_EJECT_WARNING = "record-eject-warning"; static const char* KEY_RELOAD_EJECT_WARNING = "record-reload-warning"; static const char* KEY_DUPLICATE_ON_THE_FLY_WARNING = "duplicate-on-the-fly-warning"; static const char* KEY_CONFIGURED_DEVICES = "configured-devices"; ConfigManager::ConfigManager() { settings_ = Gio::Settings::create(NAME_SCHEMA); } ConfigManager::~ConfigManager() { if (settings_->get_has_unapplied()) { settings_->apply(); } } Glib::ustring ConfigManager::getCdrdaoPath() const { return settings_->get_string(KEY_CDRDAO_PATH); } void ConfigManager::setTempDir(const Glib::ustring& dir) const { settings_->set_string(KEY_TEMP_DIR, dir); settings_->apply(); } Glib::ustring ConfigManager::getTempDir() const { return settings_->get_string(KEY_TEMP_DIR); } bool ConfigManager::getEjectWarning() const { return settings_->get_boolean(KEY_RECORD_EJECT_WARNING); } void ConfigManager::setEjectWarning(bool value) { settings_->set_boolean(KEY_RECORD_EJECT_WARNING, value); settings_->apply(); } bool ConfigManager::getReloadWarning() const { return settings_->get_boolean(KEY_RELOAD_EJECT_WARNING); } void ConfigManager::setReloadWarning(bool value) { settings_->set_boolean(KEY_RELOAD_EJECT_WARNING, value); settings_->apply(); } bool ConfigManager::getDuplicateOnTheFlyWarning() const { return settings_->get_boolean(KEY_DUPLICATE_ON_THE_FLY_WARNING); } void ConfigManager::setDuplicateOnTheFlyWarning(bool value) { settings_->set_boolean(KEY_DUPLICATE_ON_THE_FLY_WARNING, value); settings_->apply(); } void ConfigManager::setConfiguredDevices(const std::vector<Glib::ustring>& strings) { settings_->set_string_array(KEY_CONFIGURED_DEVICES, strings); settings_->apply(); } std::vector<Glib::ustring> ConfigManager::getConfiguredDevices(void) const { return settings_->get_string_array(KEY_CONFIGURED_DEVICES); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/ConfigManager.h�����������������������������������������������������0000664�0000000�0000000�00000003052�15114537466�0021520�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 2007 Denis Leroy * * 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. */ #ifndef __CONFIG_MANAGER_H #define __CONFIG_MANAGER_H #include <giomm/settings.h> #include <string> class ConfigManager { public: ConfigManager(); virtual ~ConfigManager(); Glib::ustring getCdrdaoPath() const; Glib::ustring getTempDir() const; void setTempDir(const Glib::ustring& dir) const; bool getEjectWarning() const; void setEjectWarning(bool value); bool getDuplicateOnTheFlyWarning() const; void setDuplicateOnTheFlyWarning(bool value); bool getReloadWarning() const; void setReloadWarning(bool value); void setConfiguredDevices(const std::vector<Glib::ustring>& strings); std::vector<Glib::ustring> getConfiguredDevices(void) const; protected: Glib::RefPtr<Gio::Settings> settings_; }; #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/DeviceConfDialog.cc�������������������������������������������������0000664�0000000�0000000�00000032542�15114537466�0022311�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #include "config.h" #include <stdio.h> #include <limits.h> #include <math.h> #include <assert.h> #include <ctype.h> #include <gtkmm.h> #include <glibmm/i18n.h> #include "DeviceConfDialog.h" #include "CdDevice.h" #include "guiUpdate.h" #include "util.h" #define MAX_DEVICE_TYPE_ID 2 static CdDevice::DeviceType ID2DEVICE_TYPE[MAX_DEVICE_TYPE_ID + 1] = { CdDevice::CD_ROM, CdDevice::CD_R, CdDevice::CD_RW }; DeviceConfDialog::DeviceConfDialog() { int i; Gtk::Label *label; Gtk::Table *table; Gtk::HBox *hbox; Gtk::VBox *vbox; Gtk::Button *button; active_ = false; set_title(_("Configure Devices")); // TreeView initialization listModel_ = Gtk::ListStore::create(listColumns_); list_.set_model(listModel_); list_.append_column(_("Dev"), listColumns_.dev); list_.append_column(_("Vendor"), listColumns_.vendor); list_.append_column(_("Model"), listColumns_.model); list_.append_column(_("Status"), listColumns_.status); if (list_.get_selection()) { selectedRow_ = list_.get_selection()->get_selected(); list_.get_selection()->signal_changed(). connect(mem_fun(*this, &DeviceConfDialog::selectionChanged)); } for (i = 0; i <= CdDevice::maxDriverId(); i++) { driverMenu_.append(CdDevice::driverName(i)); } driverMenu_.signal_changed().connect( sigc::mem_fun(*this, &DeviceConfDialog::setDriverId)); for (i = 0; i <= MAX_DEVICE_TYPE_ID; i++) { devtypeMenu_.append(CdDevice::deviceType2string(ID2DEVICE_TYPE[i])); } devtypeMenu_.signal_changed().connect( sigc::mem_fun(*this, &DeviceConfDialog::setDeviceType)); devEntry_.set_max_length(32); vendorEntry_.set_max_length(8); productEntry_.set_max_length(16); Gtk::VBox *contents = manage(new Gtk::VBox); contents->set_spacing(5); contents->set_border_width(7); // ---------------------------- Device list Gtk::VBox *listBox = manage(new Gtk::VBox); listBox->set_spacing(5); listBox->set_border_width(5); hbox = manage(new Gtk::HBox); hbox->pack_start(list_, Gtk::PACK_EXPAND_WIDGET); Glib::RefPtr<Gtk::Adjustment> adjust = Gtk::Adjustment::create(0.0, 0.0, 0.0); Gtk::VScrollbar *scrollBar = manage(new Gtk::VScrollbar(adjust)); hbox->pack_start(*scrollBar, Gtk::PACK_SHRINK); list_.set_vadjustment(adjust); listBox->pack_start(*hbox, Gtk::PACK_EXPAND_WIDGET); Gtk::ButtonBox *bbox = manage(new Gtk::HButtonBox(Gtk::BUTTONBOX_SPREAD)); button = manage(new Gtk::Button(_("Rescan"))); bbox->pack_start(*button); button->signal_clicked(). connect(sigc::mem_fun(*this,&DeviceConfDialog::rescanAction)); button = manage(new Gtk::Button(Gtk::StockID(Gtk::Stock::DELETE))); bbox->pack_start(*button); button->signal_clicked(). connect(sigc::mem_fun(*this,&DeviceConfDialog::deleteDeviceAction)); listBox->pack_start(*bbox, Gtk::PACK_SHRINK); listFrame_.set_label(_(" Device List ")); listFrame_.add(*listBox); contents->pack_start(listFrame_, Gtk::PACK_EXPAND_WIDGET); // ---------------------------- Device settings settingFrame_.set_label(_(" Device Settings ")); table = manage(new Gtk::Table(2, 4, FALSE)); table->set_row_spacings(5); table->set_col_spacings(5); table->set_border_width(10); settingFrame_.add(*table); label = manage(new Gtk::Label(_("Device Type:"))); table->attach(*label, 0, 1, 0, 1); table->attach(devtypeMenu_, 1, 2, 0, 1); label = manage(new Gtk::Label(_("Driver:"))); table->attach(*label, 0, 1, 1, 2); table->attach(driverMenu_, 1, 2, 1, 2); label = manage(new Gtk::Label(_("Driver Options:"))); table->attach(*label, 0, 1, 2, 3); table->attach(driverOptionsEntry_, 1, 2, 2, 3); contents->pack_start(settingFrame_, Gtk::PACK_SHRINK); // -------------- Add device addDeviceFrame_.set_label(_(" Add Device ")); Gtk::VBox *addDeviceBox = manage(new Gtk::VBox); addDeviceBox->set_spacing(5); addDeviceBox->set_border_width(5); table = manage(new Gtk::Table(3, 2, FALSE)); table->set_row_spacings(5); table->set_col_spacings(5); addDeviceBox->pack_start(*table, Gtk::PACK_EXPAND_WIDGET); label = manage(new Gtk::Label(_("Device:"))); table->attach(*label, 0, 1, 0, 1); table->attach(devEntry_, 1, 2, 0, 1); label = manage(new Gtk::Label(_("Vendor:"))); table->attach(*label, 0, 1, 1, 2); table->attach(vendorEntry_, 1, 2, 1, 2); label = manage(new Gtk::Label(_("Product:"))); table->attach(*label, 0, 1, 2, 3); table->attach(productEntry_, 1, 2, 2, 3); bbox = manage(new Gtk::HButtonBox(Gtk::BUTTONBOX_SPREAD)); bbox->set_spacing(5); Gtk::Button* addButton = manage(new Gtk::Button(Gtk::StockID(Gtk::Stock::ADD))); bbox->pack_start(*addButton); addButton->signal_clicked(). connect(mem_fun(*this, &DeviceConfDialog::addDeviceAction)); addDeviceBox->pack_start(*bbox); addDeviceFrame_.add(*addDeviceBox); contents->pack_start(addDeviceFrame_, Gtk::PACK_SHRINK); // 3 buttons at bottom of window. bbox = manage(new Gtk::HButtonBox(Gtk::BUTTONBOX_SPREAD)); bbox->set_spacing(5); hbox->set_border_width(10); Gtk::Button* applyButton = manage(new Gtk::Button(Gtk::StockID(Gtk::Stock::APPLY))); bbox->pack_start(*applyButton); applyButton->signal_clicked().connect(mem_fun(*this, &DeviceConfDialog::applyAction)); Gtk::Button *resetButton = manage(new Gtk::Button(_("Reset"))); bbox->pack_start(*resetButton); resetButton->signal_clicked().connect(mem_fun(*this, &DeviceConfDialog::resetAction)); Gtk::Button *cancelButton = manage(new Gtk::Button(Gtk::StockID(Gtk::Stock::CLOSE))); bbox->pack_start(*cancelButton); cancelButton->signal_clicked().connect(mem_fun(*this, &DeviceConfDialog::closeAction)); contents->pack_start(*bbox, Gtk::PACK_SHRINK); add(*contents); } DeviceConfDialog::~DeviceConfDialog() { } void DeviceConfDialog::start() { if (active_) { present(); return; } active_ = true; update(UPD_CD_DEVICES); show_all(); } void DeviceConfDialog::stop() { hide(); active_ = false; } void DeviceConfDialog::update(unsigned long level) { if (!active_) return; if (level & UPD_CD_DEVICES) import(); else if (level & UPD_CD_DEVICE_STATUS) importStatus(); } void DeviceConfDialog::closeAction() { stop(); } void DeviceConfDialog::resetAction() { import(); } void DeviceConfDialog::applyAction() { if (selectedRow_) exportConfiguration(selectedRow_); exportData(); guiUpdate(UPD_CD_DEVICES); } void DeviceConfDialog::addDeviceAction() { const char *s; std::string dev; std::string vendor; std::string product; CdDevice *cddev; if ((s = checkString(devEntry_.get_text())) == NULL) return; dev = s; if ((s = checkString(vendorEntry_.get_text())) == NULL) return; vendor = s; if ((s = checkString(productEntry_.get_text())) == NULL) return; product = s; if (CdDevice::find(dev.c_str()) != NULL) return; cddev = CdDevice::add(dev.c_str(), vendor.c_str(), product.c_str()); if (cddev) { cddev->manuallyConfigured(true); Gtk::TreeIter new_entry = appendTableEntry(cddev); list_.get_selection()->select(new_entry); } guiUpdate(UPD_CD_DEVICES); } void DeviceConfDialog::deleteDeviceAction() { DeviceData *data; CdDevice *dev; if (selectedRow_) { data = (*selectedRow_)[listColumns_.data]; dev = CdDevice::find(data->dev.c_str()); if (dev == NULL || dev->status() == CdDevice::DEV_RECORDING || dev->status() == CdDevice::DEV_BLANKING) { // don't remove device that is currently busy return; } CdDevice::remove(data->dev.c_str()); listModel_->erase(selectedRow_); list_.get_selection()->unselect_all(); selectedRow_ = list_.get_selection()->get_selected(); delete data; guiUpdate(UPD_CD_DEVICES); } } void DeviceConfDialog::rescanAction() { CdDevice::scan(); guiUpdate(UPD_CD_DEVICES); } Gtk::TreeIter DeviceConfDialog::appendTableEntry(CdDevice *dev) { DeviceData *data; const gchar *rowStr[6]; data = new DeviceData; data->dev = dev->dev(); data->driverId = dev->driverId(); data->options = dev->driverOptions(); switch (dev->deviceType()) { case CdDevice::CD_ROM: data->deviceType = 0; break; case CdDevice::CD_R: data->deviceType = 1; break; case CdDevice::CD_RW: data->deviceType = 2; break; } Gtk::TreeIter newiter = listModel_->append(); Gtk::TreeModel::Row row = *newiter; row[listColumns_.dev] = data->dev; row[listColumns_.vendor] = dev->vendor(); row[listColumns_.model] = dev->product(); row[listColumns_.status] = CdDevice::status2string(dev->status()); row[listColumns_.data] = data; return newiter; } void DeviceConfDialog::import() { CdDevice *drun; DeviceData *data; list_.get_selection()->unselect_all(); selectedRow_ = list_.get_selection()->get_selected(); listModel_->clear(); for (drun = CdDevice::first(); drun != NULL; drun = CdDevice::next(drun)) { appendTableEntry(drun); } if (listModel_->children().size() > 0) { list_.columns_autosize(); list_.get_selection()->select(Gtk::TreeModel::Path((unsigned)1)); } } void DeviceConfDialog::importConfiguration(Gtk::TreeIter row) { char buf[50]; DeviceData *data; if (selectedRow_) { data = (*selectedRow_)[listColumns_.data]; driverMenu_.set_sensitive(true); driverMenu_.set_active(data->driverId); devtypeMenu_.set_sensitive(true); devtypeMenu_.set_active(data->deviceType); driverOptionsEntry_.set_sensitive(true); snprintf(buf, sizeof(buf),"0x%lx", data->options); driverOptionsEntry_.set_text(buf); } else { driverMenu_.set_active(0); driverMenu_.set_sensitive(false); devtypeMenu_.set_active(0); devtypeMenu_.set_sensitive(false); driverOptionsEntry_.set_text(""); driverOptionsEntry_.set_sensitive(false); } } void DeviceConfDialog::importStatus() { DeviceData *data; CdDevice *dev; Gtk::TreeNodeChildren ch = listModel_->children(); for (unsigned i = 0; i < ch.size(); i++) { Gtk::TreeRow row = ch[i]; data = row[listColumns_.data]; if (data && (dev = CdDevice::find(data->dev.c_str()))) { row[listColumns_.status] = CdDevice::status2string(dev->status()); } } list_.columns_autosize(); } void DeviceConfDialog::exportConfiguration(Gtk::TreeIter row) { DeviceData *data; if (row) { data = (*row)[listColumns_.data]; if (data) { data->options = strtoul(driverOptionsEntry_.get_text().c_str(), NULL, 0); } } } void DeviceConfDialog::exportData() { DeviceData *data; CdDevice *dev; std::string s; Gtk::TreeNodeChildren ch = listModel_->children(); for (unsigned i = 0; i < ch.size(); i++) { Gtk::TreeRow row = ch[i]; data = row[listColumns_.data]; if (data && (dev = CdDevice::find(data->dev.c_str()))) { if (dev->driverId() != data->driverId) { dev->driverId(data->driverId); dev->manuallyConfigured(true); } if (dev->deviceType() != ID2DEVICE_TYPE[data->deviceType]) { dev->deviceType(ID2DEVICE_TYPE[data->deviceType]); dev->manuallyConfigured(true); } if (dev->driverOptions() != data->options) { dev->driverOptions(data->options); dev->manuallyConfigured(true); } } } } void DeviceConfDialog::setDriverId(void) { int id = driverMenu_.get_active_row_number(); if (selectedRow_ && id >= 0 && id <= CdDevice::maxDriverId()) { DeviceData *data = (*selectedRow_)[listColumns_.data]; if (data) data->driverId = id; } } void DeviceConfDialog::setDeviceType(void) { int id = devtypeMenu_.get_active_row_number(); if (selectedRow_ && id >= 0 && id <= MAX_DEVICE_TYPE_ID) { DeviceData *data = (*selectedRow_)[listColumns_.data]; if (data) data->deviceType = id; } } void DeviceConfDialog::selectionChanged() { Gtk::TreeIter new_sel = list_.get_selection()->get_selected(); if ((bool)selectedRow_ != (bool)new_sel || selectedRow_ != new_sel) { if (selectedRow_) exportConfiguration(selectedRow_); selectedRow_ = new_sel; importConfiguration(selectedRow_); } } const char *DeviceConfDialog::checkString(const std::string &str) { static char *buf = NULL; static long bufLen = 0; char *p, *s; long len = strlen(str.c_str()); if (len == 0) return NULL; if (buf == NULL || len + 1 > bufLen) { delete[] buf; bufLen = len + 1; buf = new char[bufLen]; } strcpy(buf, str.c_str()); s = buf; p = buf + len - 1; while (*s != 0 && isspace(*s)) s++; if (*s == 0) return NULL; while (p > s && isspace(*p)) { *p = 0; p--; } return s; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/DeviceConfDialog.h��������������������������������������������������0000664�0000000�0000000�00000005032�15114537466�0022145�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998, 1999 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __DEVICE_CONF_DIALOG_H #define __DEVICE_CONF_DIALOG_H #include <gtkmm.h> class TocEdit; class CdDevice; class DeviceConfDialog : public Gtk::Window { public: DeviceConfDialog(); ~DeviceConfDialog(); void start(); void stop(); void update(unsigned long level); private: bool active_; Gtk::TreeIter selectedRow_; struct DeviceData { std::string dev; int driverId; int deviceType; unsigned long options; }; // ------------------------------------- Device TreeView class ListColumns : public Gtk::TreeModel::ColumnRecord { public: ListColumns() { add(dev); add(vendor); add(model); add(status); add(data); }; Gtk::TreeModelColumn<std::string> dev; Gtk::TreeModelColumn<std::string> vendor; Gtk::TreeModelColumn<std::string> model; Gtk::TreeModelColumn<std::string> status; Gtk::TreeModelColumn<DeviceData*> data; }; Gtk::TreeView list_; Glib::RefPtr<Gtk::ListStore> listModel_; ListColumns listColumns_; Gtk::Frame listFrame_; Gtk::Frame settingFrame_; Gtk::Frame addDeviceFrame_; Gtk::ComboBoxText driverMenu_; Gtk::ComboBoxText devtypeMenu_; Gtk::Entry devEntry_; Gtk::Entry vendorEntry_; Gtk::Entry productEntry_; Gtk::Entry driverOptionsEntry_; const char *checkString(const std::string &str); void setDriverId(); void setDeviceType(); void selectionChanged(); void closeAction(); void resetAction(); void applyAction(); void addDeviceAction(); void deleteDeviceAction(); void rescanAction(); Gtk::TreeIter appendTableEntry(CdDevice *); void import(); void importConfiguration(Gtk::TreeIter); void importStatus(); void exportData(); void exportConfiguration(Gtk::TreeIter); }; #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/DeviceList.cc�������������������������������������������������������0000664�0000000�0000000�00000012436�15114537466�0021217�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #include "config.h" #include <stdio.h> #include <limits.h> #include <math.h> #include <assert.h> #include <string> #include <gtkmm.h> #include <glibmm/i18n.h> #include "DeviceList.h" #include "MessageBox.h" #include "xcdrdao.h" #include "CdDevice.h" #include "guiUpdate.h" #include "TocEdit.h" #include "util.h" DeviceList::DeviceList(CdDevice::DeviceType filterType) { filterType_ = filterType; listModel_ = Gtk::ListStore::create(listColumns_); list_.set_model(listModel_); list_.append_column(_("Vendor"), listColumns_.vendor); list_.append_column(_("Model"), listColumns_.model); list_.append_column(_("Status"), listColumns_.status); Gtk::VBox *contents = new Gtk::VBox; contents->set_spacing(10); // available device list Gtk::HBox *listHBox = new Gtk::HBox; Gtk::VBox *listVBox = new Gtk::VBox; Gtk::HBox *hbox = new Gtk::HBox; hbox->pack_start(list_, TRUE, TRUE); Glib::RefPtr<Gtk::Adjustment> adjust = Gtk::Adjustment::create(0.0, 0.0, 0.0); Gtk::VScrollbar *scrollBar = new Gtk::VScrollbar(adjust); hbox->pack_start(*scrollBar, FALSE, FALSE); list_.set_vadjustment(adjust); listHBox->pack_start(*hbox, TRUE, TRUE, 5); listVBox->pack_start(*listHBox, TRUE, TRUE, 5); switch (filterType_) { case CdDevice::CD_ROM: set_label(_(" Available Reader Devices ")); break; case CdDevice::CD_R: set_label(_(" Available Recorder Devices ")); break; case CdDevice::CD_RW: set_label(_(" Available Recorder (RW) Devices ")); break; } add(*listVBox); } std::string DeviceList::selection() { Gtk::TreeIter i = list_.get_selection()->get_selected(); if (i) { return ((std::string)((*i)[listColumns_.dev])).c_str(); } else return std::string(); } void DeviceList::appendTableEntry(CdDevice *dev) { Gtk::TreeIter newiter = listModel_->append(); Gtk::TreeModel::Row row = *newiter; row[listColumns_.dev] = dev->dev(); row[listColumns_.vendor] = dev->vendor(); row[listColumns_.model] = dev->product(); row[listColumns_.status] = CdDevice::status2string(dev->status()); if (dev->status() == CdDevice::DEV_READY) list_.get_selection()->select(newiter); } void DeviceList::import() { CdDevice *drun; unsigned int i; listModel_->clear(); for (drun = CdDevice::first(); drun != NULL; drun = CdDevice::next(drun)) { switch (filterType_) { case CdDevice::CD_ROM: if (drun->driverId() > 0 && (drun->deviceType() == CdDevice::CD_ROM || drun->deviceType() == CdDevice::CD_R || drun->deviceType() == CdDevice::CD_RW)) { appendTableEntry(drun); } break; case CdDevice::CD_R: if (drun->driverId() > 0 && (drun->deviceType() == CdDevice::CD_R || drun->deviceType() == CdDevice::CD_RW)) { appendTableEntry(drun); } break; case CdDevice::CD_RW: if (drun->driverId() > 0 && (drun->deviceType() == CdDevice::CD_RW)) { appendTableEntry(drun); } break; } } if (listModel_->children().size() > 0) { list_.columns_autosize(); list_.get_selection()->select(Gtk::TreeModel::Path((unsigned)1)); } } void DeviceList::importStatus() { std::string data; CdDevice *cddev; Gtk::TreeNodeChildren ch = listModel_->children(); for (unsigned i = 0; i < ch.size(); i++) { Gtk::TreeRow row = ch[i]; data = row[listColumns_.dev]; if ((cddev = CdDevice::find(data.c_str()))) { if (cddev->status() == CdDevice::DEV_READY) list_.get_column(i)->set_clickable(true); else list_.get_column(i)->set_clickable(false); row[listColumns_.status] = CdDevice::status2string(cddev->status()); } } list_.columns_autosize(); } void DeviceList::selectOne() { if (list_.get_selection()->count_selected_rows() > 0) return; for (unsigned i = 0; i < listModel_->children().size(); i++) { list_.get_selection()->select(Gtk::TreePath(1, i)); if (list_.get_selection()->count_selected_rows() > 0) break; } } void DeviceList::selectOneBut(const char *targetData) { if (!targetData) return selectOne(); if (list_.get_selection()->count_selected_rows() == 0) { Gtk::TreeNodeChildren ch = listModel_->children(); for (unsigned i = 0; i < ch.size(); i++) { std::string sourceData = (ch[i])[listColumns_.dev]; if (sourceData != targetData) { list_.get_selection()->select(ch[i]); break; } } if (list_.get_selection()->count_selected_rows() == 0) { selectOne(); } } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/DeviceList.h��������������������������������������������������������0000664�0000000�0000000�00000003344�15114537466�0021057�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998, 1999 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __DEVICE_LIST_H #define __DEVICE_LIST_H #include <gtkmm.h> #include <gtk/gtk.h> #include <string> class TocEdit; #include "CdDevice.h" class DeviceList : public Gtk::Frame { public: DeviceList(CdDevice::DeviceType filterType); ~DeviceList() {}; std::string selection(); void selectOne(); void selectOneBut(const char *targetData); void appendTableEntry(CdDevice *); void import(); void importStatus(); private: CdDevice::DeviceType filterType_; class ListColumns : public Gtk::TreeModel::ColumnRecord { public: ListColumns() { add(dev); add(vendor); add(model); add(status); }; Gtk::TreeModelColumn<std::string> dev; Gtk::TreeModelColumn<std::string> vendor; Gtk::TreeModelColumn<std::string> model; Gtk::TreeModelColumn<std::string> status; }; Gtk::TreeView list_; Glib::RefPtr<Gtk::ListStore> listModel_; ListColumns listColumns_; }; #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/DumpCDProject.cc����������������������������������������������������0000664�0000000�0000000�00000012561�15114537466�0021626�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2000 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #include "config.h" #include "guiUpdate.h" #include "Project.h" #include "DumpCDProject.h" #include "RecordCDSource.h" #include "RecordHDTarget.h" #include "DeviceList.h" #include "MessageBox.h" #include "util.h" #include "Icons.h" #include <gtkmm.h> #include <glibmm/i18n.h> DumpCDProject::DumpCDProject(Gtk::Window *parent) : Project(parent) { // Top vbox Gtk::VBox* top_vbox = manage(new Gtk::VBox); top_vbox->set_border_width(10); top_vbox->set_spacing(10); parent_ = parent; CDSource = manage(new RecordCDSource(parent_)); CDSource->onTheFlyOption(false); CDSource->start(); top_vbox->pack_start(*CDSource); HDTarget = manage(new RecordHDTarget()); HDTarget->start(); top_vbox->pack_start(*HDTarget, Gtk::PACK_SHRINK); Gtk::HButtonBox* bbox = manage(new Gtk::HButtonBox); bbox->set_spacing(10); Gtk::Image *pixmap = manage(new Gtk::Image(Icons::DUMPCD, Gtk::ICON_SIZE_DIALOG)); Gtk::Label *startLabel = manage(new Gtk::Label(_("Start"))); Gtk::VBox *startBox = manage(new Gtk::VBox); Gtk::Button *button = manage(new Gtk::Button()); startBox->pack_start(*pixmap, false, false); startBox->pack_start(*startLabel, false, false); button->add(*startBox); button->signal_clicked().connect(mem_fun(*this, &DumpCDProject::start)); bbox->pack_start(*button, Gtk::PACK_EXPAND_PADDING); top_vbox->pack_start(*bbox, Gtk::PACK_SHRINK); pack_start(*top_vbox); guiUpdate(UPD_ALL); show_all(); } DumpCDProject::~DumpCDProject() { } void DumpCDProject::start() { DeviceList *sourceList = CDSource->getDeviceList(); if (sourceList->selection().empty()) { Gtk::MessageDialog d(*parent_, _("Please select one reader device"), Gtk::MESSAGE_INFO); d.run(); return; } // Read options int correction = CDSource->getCorrection(); int subChanReadMode = CDSource->getSubChanReadMode(); std::string imageName = HDTarget->getFilename(); if (imageName == "") { Gtk::MessageDialog d(*parent_, _("Please specify a name for the image"), Gtk::MESSAGE_INFO); d.run(); return; } char *tmp, *p; tmp = strdupCC(imageName.c_str()); if ((p = strrchr(tmp, '.')) != NULL && strcmp(p, ".toc") == 0) *p = 0; if (*tmp == 0 || strcmp(tmp, ".") == 0 || strcmp(tmp, "..") == 0) { Gtk::MessageDialog d(*parent_, _("The specified image name is invalid"), Gtk::MESSAGE_ERROR); d.run(); delete[] tmp; return; } imageName = tmp; delete[] tmp; std::string imagePath; std::string binPath; std::string tocPath; { std::string path = HDTarget->getPath(); const char *s = path.c_str(); long len = strlen(s); if (len == 0) { imagePath = imageName; } else { imagePath = path; if (s[len - 1] != '/') imagePath += "/"; imagePath += imageName; } } binPath = imagePath; binPath += ".bin"; tocPath = imagePath; tocPath += ".toc"; if (access(binPath.c_str(), R_OK) == 0) { std::string s = _("The image file \""); s += binPath; s += _("\" already exists."); Ask2Box msg(parent_, _("Dump CD"), 0, 1, s.c_str(), _("Do you want to overwrite it?"), "", NULL); if (msg.run() != 1) return; } if (access(tocPath.c_str(), R_OK) == 0) { std::string s = _("The toc-file \""); s += tocPath; s += _("\" already exists."); Ask2Box msg(parent_, _("Dump CD"), 0, 1, s.c_str(), _("Do you want to overwrite it?"), "", NULL); switch (msg.run()) { case 1: // remove the file an continue if (unlink(tocPath.c_str()) != -0) { MessageBox msg(parent_, _("Dump CD"), 0, _("Cannot delete toc-file"), tocPath.c_str(), NULL); msg.run(); return; } break; default: // cancel return; break; } } std::string sourceData = sourceList->selection(); if (sourceData.empty()) return; CdDevice *readDevice = CdDevice::find(sourceData.c_str()); if (readDevice == NULL) return; if (readDevice->extractDao(*parent_, imagePath.c_str(), correction, subChanReadMode) != 0) { Gtk::MessageDialog d(*parent_, _("Cannot start reading"), Gtk::MESSAGE_ERROR); d.run(); } else { guiUpdate(UPD_CD_DEVICE_STATUS); } } bool DumpCDProject::closeProject() { return true; // Close the project } void DumpCDProject::update(unsigned long level) { CDSource->update(level); HDTarget->update(level); if (level & UPD_CD_DEVICE_STATUS) CDSource->getDeviceList()->selectOne(); } �����������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/DumpCDProject.h�����������������������������������������������������0000664�0000000�0000000�00000002417�15114537466�0021467�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 2000 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __DUMP_CD_PROJECT_H__ #define __DUMP_CD_PROJECT_H__ class RecordCDSource; class RecordHDTarget; class DumpCDProject : public Project { public: DumpCDProject(Gtk::Window *parent); ~DumpCDProject(); bool closeProject(); protected: virtual void createToolbar() {}; private: RecordCDSource *CDSource; RecordHDTarget *HDTarget; void start(); void recordToc2CD() {} void projectInfo() {} void update(unsigned long level); }; #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/DuplicateCDProject.cc�����������������������������������������������0000664�0000000�0000000�00000014756�15114537466�0022643�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2000 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #include "config.h" #include "guiUpdate.h" #include "Project.h" #include "DuplicateCDProject.h" #include "RecordCDSource.h" #include "RecordCDTarget.h" #include "DeviceList.h" #include "MessageBox.h" #include "Icons.h" #include "ConfigManager.h" #include "xcdrdao.h" #include <gtkmm.h> #include <glibmm/i18n.h> DuplicateCDProject::DuplicateCDProject(Gtk::Window *parent) : Project(parent) { Gtk::VBox *vbox = new Gtk::VBox; vbox->set_border_width(10); vbox->set_spacing(10); Gtk::HBox *hbox = manage(new Gtk::HBox); hbox->set_spacing(10); vbox->pack_start(*hbox); pack_start(*vbox); parent_ = parent; CDSource = new RecordCDSource(parent_); CDSource->start(); CDTarget = new RecordCDTarget(parent_); CDTarget->start(); hbox->pack_start(*CDSource); hbox->pack_start(*CDTarget); hbox = manage(new Gtk::HBox); hbox->set_spacing(10); Gtk::VBox *frameBox = new Gtk::VBox; simulate_rb = new Gtk::RadioButton(_("Simulate"), 0); simulateBurn_rb = new Gtk::RadioButton(_("Simulate and Burn"), 0); burn_rb = new Gtk::RadioButton(_("Burn"), 0); frameBox->pack_start(*simulate_rb); frameBox->pack_start(*simulateBurn_rb); Gtk::RadioButton::Group rb_group = simulate_rb->get_group(); simulateBurn_rb->set_group(rb_group); frameBox->pack_start(*burn_rb); burn_rb->set_group(rb_group); hbox->pack_start(*frameBox, true, false); Gtk::Image *pixmap = manage(new Gtk::Image(Icons::GCDMASTER, Gtk::ICON_SIZE_DIALOG)); Gtk::Label *startLabel = manage(new Gtk::Label(_("Start"))); Gtk::VBox *startBox = manage(new Gtk::VBox); Gtk::Button *button = manage(new Gtk::Button()); startBox->pack_start(*pixmap, false, false); startBox->pack_start(*startLabel, false, false); button->add(*startBox); button->signal_clicked().connect(mem_fun(*this, &DuplicateCDProject::start)); hbox->pack_start(*button, true, false); Gtk::HBox *hbox2 = new Gtk::HBox; hbox2->pack_start(*hbox, true, false); vbox->pack_start(*hbox2, Gtk::PACK_SHRINK); guiUpdate(UPD_ALL); show_all(); } DuplicateCDProject::~DuplicateCDProject() { delete CDSource; delete CDTarget; } void DuplicateCDProject::start() { DeviceList *sourceList = CDSource->getDeviceList(); DeviceList *targetList = CDTarget->getDeviceList(); std::string sourceData = sourceList->selection(); std::string targetData = targetList->selection(); if (sourceData.empty()) { Gtk::MessageDialog d(*parent_, _("Please select one reader device"), Gtk::MESSAGE_INFO); d.run(); return; } if (targetData.empty()) { Gtk::MessageDialog d(*parent_, _("Please select at least one recorder device"), Gtk::MESSAGE_INFO); d.run(); return; } //Read options int onTheFly = CDSource->getOnTheFly(); if (onTheFly) { // We can't make on the fly copy with the same device, check that // We can only have one source device selected if (sourceData == targetData) { // If the user selects the same device for reading and writing // we can't do on the fly copying. More complex situations with // multiple target devices are not handled if (configManager->getDuplicateOnTheFlyWarning()) { Ask2Box msg(parent_, "Request", 1, 2, _("To duplicate a CD using the same device for reading " "and writing"), _("you need to copy the CD to disk before burning"), "", _("Proceed and copy to disk before burning?"), NULL); switch (msg.run()) { case 1: // proceed without on the fly CDSource->setOnTheFly(false); onTheFly = 0; if (msg.dontShowAgain()) { configManager->setDuplicateOnTheFlyWarning(false); } break; default: // do not proceed return; break; } } else { CDSource->setOnTheFly(false); onTheFly = 0; } } } int correction = CDSource->getCorrection(); int subChanReadMode = CDSource->getSubChanReadMode(); // Record options int simulate; if (simulate_rb->get_active()) simulate = 1; else if (simulateBurn_rb->get_active()) simulate = 2; else simulate = 0; int multiSession = CDTarget->getMultisession(); int burnSpeed = CDTarget->getSpeed(); int eject = CDTarget->checkEjectWarning(parent_); if (eject == -1) return; int reload = CDTarget->checkReloadWarning(parent_); if (reload == -1) return; int buffer = CDTarget->getBuffer(); CdDevice *readDevice = CdDevice::find(sourceData.c_str()); if (readDevice == NULL) return; CdDevice *writeDevice = CdDevice::find(targetData.c_str()); if (writeDevice == NULL) return; if (writeDevice->duplicateDao(*parent_, simulate, multiSession, burnSpeed, eject, reload, buffer, onTheFly, correction, subChanReadMode, readDevice) != 0) { Gtk::MessageDialog md(*parent_, _("Cannot start disk-at-once duplication"), Gtk::MESSAGE_ERROR); md.run(); } else { guiUpdate(UPD_CD_DEVICE_STATUS); } } bool DuplicateCDProject::closeProject() { return true; // Close the project } void DuplicateCDProject::update(unsigned long level) { CDSource->update(level); CDTarget->update(level); if (level & UPD_CD_DEVICE_STATUS) { DeviceList *sourceList = CDSource->getDeviceList(); DeviceList *targetList = CDTarget->getDeviceList(); targetList->selectOne(); if (targetList->selection().empty()) { sourceList->selectOne(); } else { sourceList->selectOneBut(targetList->selection().c_str()); } } } ������������������cdrdao-cdrdao-f00afb2/gcdmaster/DuplicateCDProject.h������������������������������������������������0000664�0000000�0000000�00000002610�15114537466�0022467�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 2000 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __DUPLICATECDPROJECT_H__ #define __DUPLICATECDPROJECT_H__ class RecordCDSource; class RecordCDTarget; class DuplicateCDProject : public Project { public: DuplicateCDProject(Gtk::Window *parent); ~DuplicateCDProject(); bool closeProject(); protected: virtual void createToolbar() {}; private: RecordCDSource *CDSource; RecordCDTarget *CDTarget; Gtk::RadioButton *simulate_rb; Gtk::RadioButton *simulateBurn_rb; Gtk::RadioButton *burn_rb; void start(); void recordToc2CD() {} void projectInfo() {} void update(unsigned long level); }; #endif ������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/GenericView.cc������������������������������������������������������0000664�0000000�0000000�00000002054�15114537466�0021366�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 2000 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #include "GenericView.h" GenericView::GenericView() { tocEditView_ = (TocEditView*)0; } GenericView::~GenericView() { tocEditView_ = (TocEditView*)0; } TocEditView *GenericView::tocEditView() const { return tocEditView_; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/GenericView.h�������������������������������������������������������0000664�0000000�0000000�00000002207�15114537466�0021230�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 2000 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __GENERIC_VIEW_H__ #define __GENERIC_VIEW_H__ #include <gtkmm.h> class TocEditView; class GenericView : public Gtk::VBox { public: GenericView(); ~GenericView(); virtual TocEditView *tocEditView() const; virtual void update(unsigned long level) = 0; protected: TocEditView *tocEditView_; }; #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/Icons.cc������������������������������������������������������������0000664�0000000�0000000�00000002553�15114537466�0020236�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "Icons.h" #include "stock/pixbufs.h" Gtk::StockID Icons::PLAY("gcdmaster-play"); Gtk::StockID Icons::STOP("gcdmaster-stop"); Gtk::StockID Icons::PAUSE("gcdmaster-pause"); Gtk::StockID Icons::GCDMASTER("gcdmaster-gcdmaster"); Gtk::StockID Icons::OPEN("gcdmaster-open"); Gtk::StockID Icons::AUDIOCD("gcdmaster-audiocd"); Gtk::StockID Icons::COPYCD("gcdmaster-copycd"); Gtk::StockID Icons::DUMPCD("gcdmaster-dumpcd"); Gtk::StockID Icons::RECORD("gcdmaster-record"); struct Icons::IconEntry Icons::iconList[] = { { Icons::PLAY, play_pixbuf }, { Icons::STOP, stop_pixbuf }, { Icons::PAUSE, pause_pixbuf }, { Icons::GCDMASTER, gcdmaster_pixbuf }, { Icons::OPEN, open_pixbuf }, { Icons::AUDIOCD, audiocd_pixbuf }, { Icons::COPYCD, copycd_pixbuf}, { Icons::DUMPCD, dumpcd_pixbuf}, { Icons::RECORD, record_pixbuf} }; void Icons::registerStockIcons() { Glib::RefPtr<Gtk::IconFactory> factory = Gtk::IconFactory::create(); factory->add_default(); for (unsigned i = 0; i < G_N_ELEMENTS(iconList); i++) { Glib::RefPtr<Gdk::Pixbuf> pixbuf = Gdk::Pixbuf::create_from_inline(-1, iconList[i].pixbuf); Gtk::IconSource* source = new Gtk::IconSource; source->set_pixbuf(pixbuf); Glib::RefPtr<Gtk::IconSet> set = Gtk::IconSet::create(); set->add_source(*source); factory->add(iconList[i].name, set); } } �����������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/Icons.h�������������������������������������������������������������0000664�0000000�0000000�00000000761�15114537466�0020077�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef ICONS_H #define ICONS_H #include <gtkmm.h> class Icons { public: static void registerStockIcons(); static Gtk::StockID PLAY; static Gtk::StockID STOP; static Gtk::StockID PAUSE; static Gtk::StockID GCDMASTER; static Gtk::StockID OPEN; static Gtk::StockID AUDIOCD; static Gtk::StockID COPYCD; static Gtk::StockID DUMPCD; static Gtk::StockID RECORD; private: static struct IconEntry { Gtk::StockID& name; const guint8* pixbuf; } iconList[]; }; #endif ���������������cdrdao-cdrdao-f00afb2/gcdmaster/Makefile.am���������������������������������������������������������0000664�0000000�0000000�00000006232�15114537466�0020706�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������SUBDIRS = stock bin_PROGRAMS = gcdmaster gcdmaster_SOURCES = \ AddFileDialog.cc \ AddSilenceDialog.cc \ AudioCDProject.cc \ AudioCDView.cc \ BlankCDDialog.cc \ CdDevice.cc \ CdTextDialog.cc \ ConfigManager.cc \ DeviceConfDialog.cc \ DeviceList.cc \ DumpCDProject.cc \ DuplicateCDProject.cc \ gcdmaster.cc \ GenericView.cc \ guiUpdate.cc \ Icons.cc \ MessageBox.cc \ PreferencesDialog.cc \ ProcessMonitor.cc \ ProgressDialog.cc \ Project.cc \ ProjectChooser.cc \ RecordCDSource.cc \ RecordCDTarget.cc \ RecordHDTarget.cc \ RecordTocDialog.cc \ RecordTocSource.cc \ SampleDisplay.cc \ SampleManager.cc \ Settings.cc \ TextEdit.cc \ TocEdit.cc \ TocEditView.cc \ TocInfoDialog.cc \ TrackDataScrap.cc \ TrackInfoDialog.cc \ TrackManager.cc \ xcdrdao.cc \ AddFileDialog.h \ DumpCDProject.h \ ProjectChooser.h \ SoundIF.h \ AddSilenceDialog.h \ DuplicateCDProject.h \ Project.h \ TextEdit.h \ gcdmaster.h \ RecordCDSource.h \ TocEdit.h \ AudioCDProject.h \ RecordCDTarget.h \ TocEditView.h \ AudioCDView.h \ GenericView.h \ RecordHDTarget.h \ TocInfoDialog.h \ BlankCDDialog.h \ guiUpdate.h \ RecordTocDialog.h \ TrackDataScrap.h \ CdDevice.h \ Icons.h \ RecordTocSource.h \ TrackInfoDialog.h \ CdTextDialog.h \ MessageBox.h \ SampleDisplay.h \ TrackManager.h \ DeviceConfDialog.h \ ProcessMonitor.h \ SampleManager.h \ xcdrdao.h \ DeviceList.h \ ProgressDialog.h \ ConfigManager.h \ PreferencesDialog.h \ Settings.h EXTRA_gcdmaster_SOURCES = \ SoundIF-ao.cc \ SoundIF-linux.cc \ SoundIF-none.cc \ SoundIF-solaris.cc gladedir = $(datadir)/gcdmaster/glade glade_DATA = \ glade/Preferences.glade \ glade/ProjectChooser.glade gcdmaster_LDADD = \ @sound_if_obj@ \ $(top_builddir)/dao/libdao.a \ $(top_builddir)/paranoia/libcdda_paranoia.a \ $(top_builddir)/trackdb/libtrackdb.a \ @scsilib_libs@ \ @GTKMM_LIBS@ \ @LIBICONV@ AM_CXXFLAGS = @GTKMM_CFLAGS@ @AO_CFLAGS@ if COND_MP3 gcdmaster_LDADD += @MAD_LIBS@ AM_CXXFLAGS += @MAD_CFLAGS@ endif if COND_OGG gcdmaster_LDADD += @VORBISFILE_LIBS@ AM_CXXFLAGS += @VORBISFILE_CFLAGS@ endif gcdmaster_LDADD += @AO_LIBS@ gcdmaster_DEPENDENCIES = \ $(top_builddir)/dao/libdao.a \ $(top_builddir)/paranoia/libcdda_paranoia.a \ $(top_builddir)/trackdb/libtrackdb.a \ @sound_if_obj@ AM_CPPFLAGS = \ -I$(srcdir)/../trackdb \ -I$(srcdir)/../paranoia \ -I$(srcdir)/../dao \ -DCDRDAO_GLADEDIR=\""$(gladedir)"\" man1_MANS = gcdmaster.man mimeinfodir = $(datadir)/mime-info mimeinfo_DATA = gcdmaster.keys gcdmaster.mime freedesktopdir = $(datadir)/mime/packages freedesktop_DATA = gcdmaster.xml desktopdir = $(datadir)/applications desktop_DATA = gcdmaster.desktop appregdir = $(datadir)/application-registry appreg_DATA = gcdmaster.applications icondir = $(datadir)/pixmaps icon_DATA = gcdmaster.png gcdmaster-doc.png gsettings_SCHEMAS = org.gnome.gcdmaster.gschema.xml @GSETTINGS_RULES@ EXTRA_DIST = \ $(man1_MANS) \ $(glade_DATA) \ $(mimeinfo_DATA)\ $(desktop_DATA) \ $(icon_DATA) \ $(freedesktop_DATA) \ $(appreg_DATA) \ org.gnome.gcdmaster.gschema.xml \ BUGS TASKS ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/MessageBox.cc�������������������������������������������������������0000664�0000000�0000000�00000011740�15114537466�0021216�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #include "config.h" #include <stddef.h> #include <stdarg.h> #include <gtkmm.h> #include <glibmm/i18n.h> #include "MessageBox.h" MessageBoxBase::MessageBoxBase(Gtk::Window * win) { done_ = 0; doneDefault_ = 0; dontShowAgain_ = NULL; if (win != NULL) { set_transient_for(*win); set_modal(true); } set_position(Gtk::WIN_POS_CENTER); } MessageBoxBase::~MessageBoxBase() { delete dontShowAgain_; dontShowAgain_ = NULL; } Gtk::Button *MessageBoxBase::createButton(const Gtk::BuiltinStockID id) { return new Gtk::Button(Gtk::StockID(id)); } void MessageBoxBase::init(const char *type, const char *title, int askDontShow, int nButtons, int defaultButton, Gtk::BuiltinStockID buttons[], va_list args) { int i; const char *s; done_ = 0; doneDefault_ = defaultButton; set_title(title); Gtk::HButtonBox* bbox = manage(new Gtk::HButtonBox(Gtk::BUTTONBOX_SPREAD)); bbox->show(); Gtk::VBox* contents = manage(new Gtk::VBox); contents->show(); for (i = 1; i <= nButtons; i++) { Gtk::Button* button = manage(createButton(buttons[i - 1])); button->show(); button->signal_clicked().connect(bind(mem_fun(*this, &MessageBoxBase::buttonAction), i)); bbox->add(*button); } while ((s = va_arg(args, const char *)) != NULL) { Gtk::HBox* lbox = manage(new Gtk::HBox); lbox->show(); Gtk::Label* label = manage(new Gtk::Label(s)); label->show(); lbox->pack_start(*label, Gtk::PACK_SHRINK); contents->pack_start(*lbox, Gtk::PACK_SHRINK); } if (askDontShow) { dontShowAgain_ = new Gtk::CheckButton(_("Don't show this message again")); dontShowAgain_->set_active(FALSE); dontShowAgain_->show(); Gtk::HBox* box = manage(new Gtk::HBox); Gtk::Label* label = manage(new Gtk::Label("")); label->show(); box->show(); box->pack_end(*dontShowAgain_, Gtk::PACK_SHRINK); contents->pack_start(*label, Gtk::PACK_SHRINK); contents->pack_start(*box, Gtk::PACK_SHRINK); } Gtk::HBox* hcontens = manage(new Gtk::HBox); hcontens->show(); hcontens->pack_start(*contents, TRUE, TRUE, 10); get_vbox()->pack_start(*hcontens, FALSE, FALSE, 10); get_vbox()->show(); get_action_area()->pack_start(*bbox); get_action_area()->show(); } void MessageBoxBase::buttonAction(int act) { done_ = act; } bool MessageBoxBase::on_delete_event(GdkEventAny*) { done_ = doneDefault_; return 1; } int MessageBoxBase::run() { Gtk::Main *app = Gtk::Main::instance(); show(); do { app->iteration(); } while (done_ == 0); hide(); return done_; } int MessageBoxBase::dontShowAgain() const { if (dontShowAgain_ != NULL) return dontShowAgain_->get_active() ? 1 : 0; else return 0; } MessageBox::MessageBox(Gtk::Window *win, const char *title, int askDontShow, ...) : MessageBoxBase(win) { va_list args; Gtk::BuiltinStockID buttons[1]; buttons[0] = Gtk::Stock::OK; va_start(args, askDontShow); init("info", title, askDontShow, 1, 1, buttons, args); va_end(args); } MessageBox::~MessageBox() { } Ask2Box::Ask2Box(Gtk::Window *win, const char *title, int askDontShow, int defaultButton, ...) : MessageBoxBase(win) { va_list args; Gtk::BuiltinStockID buttons[2]; buttons[0] = Gtk::Stock::YES; buttons[1] = Gtk::Stock::NO; if (defaultButton < 0 || defaultButton > 2) defaultButton = 0; va_start(args, defaultButton); init("question", title, askDontShow, 2, defaultButton, buttons, args); va_end(args); } Ask2Box::~Ask2Box() { } Ask3Box::Ask3Box(Gtk::Window *win, const char *title, int askDontShow, int defaultButton, ...) : MessageBoxBase(win) { va_list args; Gtk::BuiltinStockID buttons[3]; buttons[0] = Gtk::Stock::YES; buttons[1] = Gtk::Stock::NO; buttons[2] = Gtk::Stock::CANCEL; if (defaultButton < 0 || defaultButton > 3) defaultButton = 0; va_start(args, defaultButton); init("question", title, askDontShow, 3, defaultButton, buttons, args); va_end(args); } Ask3Box::~Ask3Box() { } ErrorBox::ErrorBox(const char* msg) : MessageDialog(msg, false, Gtk::MESSAGE_ERROR) { } ��������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/MessageBox.h��������������������������������������������������������0000664�0000000�0000000�00000003737�15114537466�0021067�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998, 1999 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __MESSAGE_BOX_H__ #define __MESSAGE_BOX_H__ #include <gtkmm.h> #include <gtk/gtk.h> #include <stdarg.h> class MessageBoxBase : public Gtk::Dialog { public: MessageBoxBase(Gtk::Window *); virtual ~MessageBoxBase(); void init(const char *type, const char *titel, int askDontShow, int nButtons, int defaultButton, Gtk::BuiltinStockID buttons[], va_list); int run(); int dontShowAgain() const; protected: int done_; int doneDefault_; Gtk::CheckButton *dontShowAgain_; Gtk::Button *createButton(const Gtk::BuiltinStockID); bool on_delete_event(GdkEventAny*); void buttonAction(int); }; class MessageBox : public MessageBoxBase { public: MessageBox(Gtk::Window *, const char *title, int askDontShow, ...); ~MessageBox(); }; class Ask2Box : public MessageBoxBase { public: Ask2Box(Gtk::Window *, const char *title, int askDontShow, int defaultButton, ...); ~Ask2Box(); }; class Ask3Box : public MessageBoxBase { public: Ask3Box(Gtk::Window *, const char *title, int askDontShow, int defaultButton, ...); ~Ask3Box(); }; class ErrorBox : public Gtk::MessageDialog { public: ErrorBox(const char* msg); }; #endif ���������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/PreferencesDialog.cc������������������������������������������������0000664�0000000�0000000�00000007405�15114537466�0022545�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 2007 Denis Leroy * * 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. */ #include <iostream> #include <glibmm/i18n.h> #include "config.h" #include "PreferencesDialog.h" #include "MessageBox.h" #include "trackdb/TempFileManager.h" #include "ConfigManager.h" #include "xcdrdao.h" PreferencesDialog::PreferencesDialog(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& refBuilder) : Gtk::Dialog(cobject), m_refBuilder(refBuilder) { m_refBuilder->get_widget("ApplyButton", _applyButton); m_refBuilder->get_widget("OkButton", _okButton); m_refBuilder->get_widget("CancelButton", _cancelButton); m_refBuilder->get_widget("TempDirectory", _tempDirEntry); m_refBuilder->get_widget("TempDirDialog", _tempDirDialog); m_refBuilder->get_widget("TempDialogButton", _browseButton); m_refBuilder->get_widget("TempBrowseCancel", _browseCancel); m_refBuilder->get_widget("TempBrowseOpen", _browseOpen); if (!_applyButton || !_okButton || !_cancelButton || !_tempDirEntry || !_tempDirDialog || !_browseButton || !_browseCancel || !_browseOpen) { std::cerr << "Unable to create all GUI widgets from glade file\n"; exit(1); } _applyButton->signal_clicked().connect( sigc::mem_fun(*this, &PreferencesDialog::on_button_apply)); _cancelButton->signal_clicked().connect( sigc::mem_fun(*this, &PreferencesDialog::on_button_cancel)); _okButton->signal_clicked().connect( sigc::mem_fun(*this, &PreferencesDialog::on_button_ok)); _browseButton->signal_clicked().connect( sigc::mem_fun(*this, &PreferencesDialog::on_button_browse)); _browseCancel->signal_clicked().connect( sigc::mem_fun(*this, &PreferencesDialog::on_button_browse_cancel)); _browseOpen->signal_clicked().connect( sigc::mem_fun(*this, &PreferencesDialog::on_button_browse_open)); _tempDirDialog->hide(); readFromGConf(); Gtk::Dialog::hide(); } PreferencesDialog::~PreferencesDialog() { } void PreferencesDialog::show() { readFromGConf(); Gtk::Dialog::show(); } void PreferencesDialog::readFromGConf() { _tempDirEntry->set_text(configManager->getTempDir()); } bool PreferencesDialog::saveToGConf() { const Glib::ustring& text = _tempDirEntry->get_text(); if (!tempFileManager.setTempDirectory(text.c_str())) { ErrorBox errBox(_("The directory you entered cannot be used as a " "temporary files directory.")); errBox.run(); readFromGConf(); return false; } try { configManager->setTempDir(text); } catch (const Glib::Error& error) { std::cerr << error.what() << std::endl; } return true; } void PreferencesDialog::on_button_apply() { saveToGConf(); } void PreferencesDialog::on_button_cancel() { readFromGConf(); hide(); } void PreferencesDialog::on_button_ok() { if (saveToGConf()) hide(); } void PreferencesDialog::on_button_browse() { _tempDirDialog->show(); } void PreferencesDialog::on_button_browse_cancel() { _tempDirDialog->hide(); } void PreferencesDialog::on_button_browse_open() { _tempDirEntry->set_text(_tempDirDialog->get_filename()); _tempDirDialog->hide(); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/PreferencesDialog.h�������������������������������������������������0000664�0000000�0000000�00000003167�15114537466�0022410�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 2007 Denis Leroy * * 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. */ #ifndef __PREFERENCES_DIALOG_H #define __PREFERENCES_DIALOG_H #include <gtkmm.h> class PreferencesDialog : public Gtk::Dialog { public: PreferencesDialog(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& refBuilder); virtual ~PreferencesDialog(); void show(); protected: void readFromGConf(); bool saveToGConf(); void on_button_apply(); void on_button_cancel(); void on_button_ok(); void on_button_browse(); void on_button_browse_cancel(); void on_button_browse_open(); Glib::RefPtr<Gtk::Builder> m_refBuilder; Gtk::Button* _applyButton; Gtk::Button* _cancelButton; Gtk::Button* _okButton; Gtk::Entry* _tempDirEntry; Gtk::FileChooserDialog* _tempDirDialog; Gtk::Button* _browseButton; Gtk::Button* _browseCancel; Gtk::Button* _browseOpen; }; #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/ProcessMonitor.cc���������������������������������������������������0000664�0000000�0000000�00000011125�15114537466�0022144�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #include <unistd.h> #include <stddef.h> #include <errno.h> #include <string.h> #include <signal.h> #include <sys/types.h> #include <sys/wait.h> #include "ProcessMonitor.h" #include "xcdrdao.h" #include "util.h" #include "log.h" Process::Process(int pid, int commFd) { pid_ = pid; commFd_ = commFd; exited_ = 0; exitStatus_ = 0; next_ = NULL; } Process::~Process() { if (commFd_ >= 0) close(commFd_); next_ = NULL; } int Process::pid() const { return pid_; } int Process::commFd() const { return commFd_; } int Process::exited() const { return exited_; } int Process::exitStatus() const { return exitStatus_; } ProcessMonitor::ProcessMonitor() { processes_ = NULL; statusChanged_ = 0; } ProcessMonitor::~ProcessMonitor() { Process *next; blockProcessMonitorSignals(); while (processes_ != NULL) { next = processes_->next_; delete processes_; processes_ = next; } unblockProcessMonitorSignals(); } int ProcessMonitor::statusChanged() { int s = statusChanged_; statusChanged_ = 0; return s; } /* Starts a child process 'prg' with arguments 'args'. * If 'pipeFdArgNum' is > 0 the file descriptor number will be written to * 'args[pipeFdArgNum]'. * Return: newly allocated 'Process' object or NULL on error */ Process *ProcessMonitor::start(const char *prg, const char **args, int pipeFdArgNum) { int pid; Process *p; int pipeFds[2]; char buf[20]; if (pipe(pipeFds) != 0) { log_message(-2, "Cannot create pipe: %s", strerror(errno)); return NULL; } if (pipeFdArgNum > 0) { snprintf(buf, sizeof(buf),"%d", pipeFds[1]); args[pipeFdArgNum] = buf; } log_message(0, "Starting: "); for (int i = 0; args[i] != NULL; i++) log_message(0, "%s ", args[i]); log_message(0, ""); blockProcessMonitorSignals(); pid = fork(); if (pid == 0) { // we are the new process // detach from controlling terminal setsid(); // close reading end of pipe close(pipeFds[0]); execvp(prg, (char*const*)args); log_message(-2, "Cannot execute '%s': %s", prg, strerror(errno)); _exit(255); } else if (pid < 0) { log_message(-2, "Cannot fork: %s", strerror(errno)); unblockProcessMonitorSignals(); return NULL; } // close writing end of pipe close(pipeFds[1]); p = new Process(pid, pipeFds[0]); p->next_ = processes_; processes_ = p; unblockProcessMonitorSignals(); return p; } Process *ProcessMonitor::find(Process *p, Process **pred) { Process *run; for (*pred = NULL, run = processes_; run != NULL; *pred = run, run = run->next_) { if (p == run) { return run; } } return NULL; } Process *ProcessMonitor::find(int pid) { Process *run; for (run = processes_; run != NULL; run = run->next_) { if (run->pid() == pid) { return run; } } return NULL; } void ProcessMonitor::stop(Process *p) { kill(p->pid(), SIGTERM); } void ProcessMonitor::remove(Process *p) { Process *act, *pred; blockProcessMonitorSignals(); if ((act = find(p, &pred)) != NULL) { if (pred == NULL) processes_ = act->next_; else pred->next_ = act->next_; delete act; } unblockProcessMonitorSignals(); } void ProcessMonitor::handleSigChld() { int pid; Process *p; int status; while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { if ((p = find(pid)) != NULL) { p->exited_ = 1; if (WIFEXITED(status)) { p->exitStatus_ = WEXITSTATUS(status); } else if (WIFSIGNALED(status)) { p->exitStatus_ = 254; } else { p->exitStatus_ = 253; } statusChanged_ = 1; } else { log_message(-3, "Unknown child with pid %d exited.", pid); } } /* if (pid < 0) log_message(-2, "waitpid failed: %s", strerror(errno)); */ } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/ProcessMonitor.h����������������������������������������������������0000664�0000000�0000000�00000004221�15114537466�0022005�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998, 1999 Andreas Mueller <mueller@daneb.ping.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 * (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. */ /* * $Log: ProcessMonitor.h,v $ * Revision 1.4 2009/02/21 13:49:17 poolshark * Compile warning fixes * * Revision 1.3 2004/02/12 01:13:31 poolshark * Merge from gnome2 branch * * Revision 1.2.6.1 2004/01/05 00:34:02 poolshark * First checking of gnome2 port * * Revision 1.1.1.1 2003/12/09 05:32:28 denis * Fooya * * Revision 1.2 2000/10/08 16:39:41 andreasm * Remote progress message now always contain the track relative and total * progress and the total number of processed tracks. * * Revision 1.1.1.1 2000/02/05 01:38:46 llanero * Uploaded cdrdao 1.1.3 with pre10 patch applied. * */ #ifndef __PROCESS_MONITOR_H__ #define __PROCESS_MONITOR_H__ class Process { public: Process(int pid, int commFd); ~Process(); int pid() const; int commFd() const; int exited() const; int exitStatus() const; private: friend class ProcessMonitor; int pid_; int commFd_; int exited_; int exitStatus_; Process *next_; }; class ProcessMonitor { public: ProcessMonitor(); ~ProcessMonitor(); int statusChanged(); Process *start(const char *, const char **args, int pipeFdArgNum); void stop(Process *); void remove(Process *); void handleSigChld(); private: int statusChanged_; Process *processes_; Process *find(Process *, Process **pred); Process *find(int pid); }; #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/ProgressDialog.cc���������������������������������������������������0000664�0000000�0000000�00000037674�15114537466�0022123�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #include <config.h> #include <stdio.h> #include <stddef.h> #include <ctype.h> #include <gtkmm.h> #include <glibmm/i18n.h> #include "ProgressDialog.h" #include "MessageBox.h" #include "TocEdit.h" #include "guiUpdate.h" #include "CdDevice.h" #include "remote.h" ProgressDialog::ProgressDialog(ProgressDialogPool *father) { Gtk::Label *label; Gtk::HBox *hbox; Gtk::VBox *contents = manage(new Gtk::VBox); Gtk::Table *table; Gtk::Alignment *align; poolFather_ = father; active_ = 0; device_ = NULL; poolNext_ = NULL; contents->set_spacing(5); statusMsg_ = manage(new Gtk::Label()); trackProgress_ = manage(new Gtk::ProgressBar); totalProgress_ = manage(new Gtk::ProgressBar); bufferFillRate_ = manage(new Gtk::ProgressBar); writerFillRate_ = manage(new Gtk::ProgressBar); tocName_ = manage(new Gtk::Label); hbox = manage(new Gtk::HBox); label = manage(new Gtk::Label(_("Project: "))); hbox->pack_start(*label, Gtk::PACK_SHRINK); hbox->pack_start(*tocName_, Gtk::PACK_SHRINK); contents->pack_start(*hbox, Gtk::PACK_SHRINK); hbox = manage(new Gtk::HBox); hbox->pack_start(*statusMsg_, Gtk::PACK_SHRINK); contents->pack_start(*hbox, Gtk::PACK_SHRINK); hbox = manage(new Gtk::HBox(true, true)); label = manage(new Gtk::Label(_("Elapsed Time: "), 1)); hbox->pack_start(*label, Gtk::PACK_SHRINK); currentTime_ = manage(new Gtk::Label()); hbox->pack_start(*currentTime_, Gtk::PACK_SHRINK); label = manage(new Gtk::Label(_("Remaining Time: "), 1)); hbox->pack_start(*label, Gtk::PACK_SHRINK); remainingTime_ = manage(new Gtk::Label("", 0)); hbox->pack_start(*remainingTime_, Gtk::PACK_SHRINK); contents->pack_start(*hbox, Gtk::PACK_SHRINK); table = manage(new Gtk::Table(4, 2, false)); table->set_row_spacings(5); table->set_col_spacings(5); contents->pack_start(*table, Gtk::PACK_SHRINK); trackLabel_ = manage(new Gtk::Label(_("Track:"))); align = manage(new Gtk::Alignment(1.0, 0.5, 0.0, 0.0)); align->add(*trackLabel_); table->attach(*align, 0, 1, 0, 1, Gtk::FILL); hbox = manage(new Gtk::HBox); hbox->pack_start(*trackProgress_); table->attach(*hbox, 1, 2, 0, 1); label = manage(new Gtk::Label(_("Total:"))); align = manage(new Gtk::Alignment(1.0, 0.5, 0.0, 0.0)); align->add(*label); table->attach(*align, 0, 1, 1, 2, Gtk::FILL); hbox = manage(new Gtk::HBox); hbox->pack_start(*totalProgress_); table->attach(*hbox, 1, 2, 1, 2); bufferFillRateLabel_ = manage(new Gtk::Label(_("Input Buffer:"))); align = manage(new Gtk::Alignment(1.0, 0.5, 0.0, 0.0)); align->add(*bufferFillRateLabel_); table->attach(*align, 0, 1, 2, 3, Gtk::FILL); hbox = manage(new Gtk::HBox); hbox->pack_start(*bufferFillRate_); table->attach(*hbox, 1, 2, 2, 3); writerFillRateLabel_ = manage(new Gtk::Label(_("Write Buffer:"))); table->attach(*writerFillRateLabel_, 0, 1, 3, 4, Gtk::FILL); table->attach(*writerFillRate_, 1, 2, 3, 4); hbox = manage(new Gtk::HBox); hbox->pack_start(*contents, true, true, 10); get_vbox()->pack_start(*hbox, false, false, 10); Gtk::HButtonBox *bbox = manage(new Gtk::HButtonBox(Gtk::BUTTONBOX_SPREAD, 20)); cancelButton_ = manage(new Gtk::Button(Gtk::StockID(Gtk::Stock::CANCEL))); bbox->pack_start(*cancelButton_); closeButton_ = manage(new Gtk::Button(Gtk::StockID(Gtk::Stock::CLOSE))); bbox->pack_start(*closeButton_); ejectButton_ = manage(new Gtk::Button("Eject")); bbox->pack_start(*ejectButton_); actCloseButtonLabel_ = 2; cancelButton_->signal_clicked(). connect(sigc::mem_fun(*this, &ProgressDialog::closeAction)); closeButton_->signal_clicked(). connect(sigc::mem_fun(*this, &ProgressDialog::closeAction)); ejectButton_->signal_clicked(). connect(sigc::mem_fun(*this, &ProgressDialog::ejectAction)); get_action_area()->pack_start(*bbox, TRUE, TRUE, 10); set_size_request(400, -1); show_all_children(); } ProgressDialog::~ProgressDialog() { } void ProgressDialog::start(CdDevice *device, const char *tocFileName) { std::string s; if (device == NULL) return; if (active_) { raise(); return; } active_ = true; device_ = device; clear(); Glib::signal_timeout().connect(mem_fun(*this, &ProgressDialog::time), 1000); statusMsg_->set_text(_("Initializing...")); tocName_->set_text(tocFileName); setCloseButtonLabel(1); cancelButton_->set_sensitive(true); ejectButton_->set_sensitive(false); s = device->vendor(); s += " "; s += device->product(); set_title(s); set_modal(true); show(); } void ProgressDialog::stop() { if (active_) { hide(); active_ = false; device_ = NULL; } } bool ProgressDialog::on_delete_event(GdkEventAny*) { if (finished_) { poolFather_->stop(this); } return true; } void ProgressDialog::ejectAction() { if (device_) if (device_->ejectCd()) { ejectButton_->set_sensitive(false); } } void ProgressDialog::closeAction() { if (finished_) { poolFather_->stop(this); return; } switch (device_->action()) { case CdDevice::A_RECORD: { Ask2Box msg(this, _("Abort Recording"), 0, 2, _("Abort recording process?"), NULL); if (msg.run() == 1 && device_ != NULL) { cancelButton_->set_sensitive(false); ejectButton_->set_sensitive(true); device_->abortDaoRecording(); } } break; case CdDevice::A_READ: { Ask2Box msg(this, _("Abort Reading"), 0, 2, _("Abort reading process?"), NULL); if (msg.run() == 1 && device_ != NULL) { cancelButton_->set_sensitive(false); ejectButton_->set_sensitive(true); device_->abortDaoReading(); } } break; case CdDevice::A_DUPLICATE: { Ask2Box msg(this, _("Abort Process"), 0, 2, _("Abort duplicating process?"), NULL); if (msg.run() == 1 && device_ != NULL) { cancelButton_->set_sensitive(false); ejectButton_->set_sensitive(true); device_->abortDaoDuplication(); } } break; case CdDevice::A_BLANK: { Ask2Box msg(this, _("Abort Process"), 0, 2, _("Abort blanking process?"), NULL); if (msg.run() == 1 && device_ != NULL) { cancelButton_->set_sensitive(false); ejectButton_->set_sensitive(true); device_->abortBlank(); } } break; default: break; } } void ProgressDialog::clear() { finished_ = 0; actStatus_ = 0; actTrack_ = 0; actTrackProgress_ = 0; actTotalProgress_ = 0; actBufferFill_ = 0; actWriterFill_ = 0; gettimeofday(&time_, NULL); currentTime_->set_text("0:00:00"); remainingTime_->set_text(""); leadTimeFilled_ = false; statusMsg_->set_text(""); trackProgress_->set_fraction(0.0); totalProgress_->set_fraction(0.0); bufferFillRate_->set_fraction(0.0); writerFillRate_->set_fraction(0.0); set_title(""); } void ProgressDialog::update(unsigned long level) { int status; int totalTracks; int track; int trackProgress; int totalProgress; int bufferFill; int writerFill; char buf[40]; std::string s; if (!active_ || device_ == NULL) return; if (finished_) return; if ((level & UPD_PROGRESS_STATUS) && device_->progressStatusChanged()) { device_->progress(&status, &totalTracks, &track, &trackProgress, &totalProgress, &bufferFill, &writerFill); if (status != actStatus_ || track != actTrack_) { actStatus_ = status; actTrack_ = track; switch (status) { case PGSMSG_RCD_ANALYZING: actTrack_ = track; s = _("Analyzing track "); snprintf(buf, sizeof(buf),"%d of %d", track, totalTracks); s += buf; statusMsg_->set_text(s); break; case PGSMSG_RCD_EXTRACTING: actTrack_ = track; s = _("Extracting "); snprintf(buf, sizeof(buf),"%d", totalTracks); s += buf; s += _(" tracks..."); statusMsg_->set_text(s); break; case PGSMSG_WCD_LEADIN: statusMsg_->set_text(_("Writing lead-in...")); break; case PGSMSG_WCD_DATA: actTrack_ = track; s = _("Writing track "); snprintf(buf, sizeof(buf),"%d of %d", track, totalTracks); s += buf; statusMsg_->set_text(s); break; case PGSMSG_WCD_LEADOUT: statusMsg_->set_text(_("Writing lead-out...")); break; case PGSMSG_BLK: statusMsg_->set_text(_("Blanking...")); break; } } if (trackProgress != actTrackProgress_) { actTrackProgress_ = trackProgress; if (trackProgress <= 1000) trackProgress_->set_fraction(trackProgress / 1000.0); } if (totalProgress != actTotalProgress_) { if (actTotalProgress_ == 0) gettimeofday(&time_, 0); actTotalProgress_ = totalProgress; if (totalProgress <= 1000) totalProgress_->set_fraction(totalProgress / 1000.0); } if (bufferFill != actBufferFill_) { actBufferFill_ = bufferFill; if (bufferFill <= 1000) bufferFillRate_->set_fraction(bufferFill / 100.0); } if (writerFill != actWriterFill_) { actWriterFill_ = writerFill; if (writerFill <= 1000) writerFillRate_->set_fraction(writerFill / 100.0); } } switch (device_->action()) { case CdDevice::A_RECORD: if (device_->status() != CdDevice::DEV_RECORDING) { switch (device_->exitStatus()) { case 0: statusMsg_->set_text(_("Recording finished successfully.")); break; case 255: statusMsg_->set_text(_("Cannot execute cdrdao. Please check " "your PATH.")); break; default: statusMsg_->set_text(_("Recording aborted with error.")); break; } finished_ = 1; setCloseButtonLabel(2); ejectButton_->set_sensitive(true); } break; case CdDevice::A_READ: if (device_->status() != CdDevice::DEV_READING) { switch (device_->exitStatus()) { case 0: statusMsg_->set_text(_("Reading finished successfully.")); break; case 255: statusMsg_->set_text(_("Cannot execute cdrdao. Please check " "your PATH.")); break; default: statusMsg_->set_text(_("Reading aborted.")); break; } finished_ = 1; setCloseButtonLabel(2); ejectButton_->set_sensitive(true); } break; case CdDevice::A_DUPLICATE: if (device_->status() != CdDevice::DEV_RECORDING) { switch (device_->exitStatus()) { case 0: statusMsg_->set_text(_("CD copying finished successfully.")); break; case 255: statusMsg_->set_text(_("Cannot execute cdrdao. Please check " "your PATH.")); break; default: statusMsg_->set_text(_("CD copying aborted with error.")); break; } finished_ = 1; setCloseButtonLabel(2); ejectButton_->set_sensitive(true); } break; case CdDevice::A_BLANK: if (device_->status() != CdDevice::DEV_BLANKING) { switch (device_->exitStatus()) { case 0: statusMsg_->set_text(_("Blanking finished successfully.")); break; case 255: statusMsg_->set_text(_("Cannot execute cdrdao. Please check " "your PATH.")); break; default: statusMsg_->set_text(_("Blanking aborted with error.")); break; } finished_ = 1; setCloseButtonLabel(2); ejectButton_->set_sensitive(true); } break; default: statusMsg_->set_text(_("Unknown device action!")); break; } } // Sets label of close button. // l: 1: 'abort' --> CANCEL gnome stock button (i18n) // 2: 'dismiss' --> CLOSE gnome stock button (i18n) void ProgressDialog::setCloseButtonLabel(int l) { if (actCloseButtonLabel_ == l) return; switch (l) { case 1: closeButton_->hide(); cancelButton_->show(); break; case 2: cancelButton_->hide(); closeButton_->show(); break; } actCloseButtonLabel_ = l; } bool ProgressDialog::time() { char buf[50]; struct timeval timenow; long time, time_remain, hours, mins, secs; gettimeofday(&timenow, NULL); time = timenow.tv_sec - time_.tv_sec; hours = time / 3600; mins = (time - (hours * 3600)) / 60; secs = time - ((hours * 3600) + (mins * 60)); snprintf(buf, sizeof(buf),"%ld:%02ld:%02ld", hours, mins, secs); currentTime_->set_text(buf); if (actTotalProgress_ > 10) { //Hack! // Denis: no shit gfloat aux1, aux2, aux3; if (!leadTimeFilled_) { leadTime_ = time; leadTimeFilled_ = true; } time_remain = (int) (((double)time / ((double)actTotalProgress_ / 1000.0)) + 0.5); time_remain -= time; if (time_remain < 0) time_remain = 0; hours = time_remain / 3600; mins = (time_remain - (hours * 3600)) / 60; secs = time_remain - ((hours * 3600) + (mins * 60)); snprintf(buf, sizeof(buf),"%ld:%02ld:%02ld", hours, mins, secs); remainingTime_->set_text(buf); } if (finished_) return false; else return true; } void ProgressDialog::needBufferProgress(bool visible) { if (visible) { bufferFillRate_->show(); bufferFillRateLabel_->show(); writerFillRate_->show(); writerFillRateLabel_->show(); } else { bufferFillRate_->hide(); bufferFillRateLabel_->hide(); writerFillRate_->hide(); writerFillRateLabel_->hide(); } } void ProgressDialog::needTrackProgress(bool visible) { if (visible) { trackProgress_->show(); trackLabel_->show(); } else { trackProgress_->hide(); trackLabel_->hide(); } } ProgressDialogPool::ProgressDialogPool() { activeDialogs_ = NULL; pool_ = NULL; } ProgressDialogPool::~ProgressDialogPool() { } void ProgressDialogPool::update(unsigned long status) { ProgressDialog *run; for (run = activeDialogs_; run != NULL; run = run->poolNext_) run->update(status); } ProgressDialog *ProgressDialogPool::start(CdDevice *device, const char *tocFileName, bool showBuffer, bool showTrack) { ProgressDialog *dialog; if (pool_ == NULL) { dialog = new ProgressDialog(this); } else { dialog = pool_; pool_ = pool_->poolNext_; } dialog->poolNext_ = activeDialogs_; activeDialogs_ = dialog; dialog->needBufferProgress(showBuffer); dialog->needTrackProgress(showTrack); dialog->start(device, tocFileName); return dialog; } ProgressDialog *ProgressDialogPool::start(Gtk::Window& parent, CdDevice *device, const char *tocFileName, bool showBuffer, bool showTrack) { ProgressDialog* dialog = start(device, tocFileName, showBuffer, showTrack); dialog->set_transient_for(parent); return dialog; } void ProgressDialogPool::stop(ProgressDialog *dialog) { ProgressDialog *run, *pred; for (pred = NULL, run = activeDialogs_; run != NULL; pred = run, run = run->poolNext_) { if (run == dialog) break; } if (run == NULL) return; dialog->stop(); if (pred == NULL) activeDialogs_ = activeDialogs_->poolNext_; else pred->poolNext_ = run->poolNext_; dialog->poolNext_ = pool_; pool_ = dialog; } ��������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/ProgressDialog.h����������������������������������������������������0000664�0000000�0000000�00000005451�15114537466�0021751�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __PROGRESS_DIALOG_H__ #define __PROGRESS_DIALOG_H__ #include <sys/time.h> #include <gtkmm.h> #include <gtk/gtk.h> class TocEdit; class CdDevice; class ProgressDialogPool; class ProgressDialog : public Gtk::Dialog { public: ProgressDialog(ProgressDialogPool *father); ~ProgressDialog(); bool on_delete_event(GdkEventAny*); private: friend class ProgressDialogPool; ProgressDialogPool *poolFather_; bool active_; CdDevice *device_; int finished_; int actStatus_; int actTrack_; int actTrackProgress_; int actTotalProgress_; int actBufferFill_; int actWriterFill_; int actCloseButtonLabel_; Gtk::Label *currentTime_; Gtk::Label *remainingTime_; long leadTime_; bool leadTimeFilled_; struct timeval time_; bool time(); Gtk::Button *cancelButton_; Gtk::Button *closeButton_; Gtk::Button *ejectButton_; Gtk::Label *tocName_; Gtk::Label *statusMsg_;; Gtk::ProgressBar *trackProgress_; Gtk::Label *trackLabel_; Gtk::ProgressBar *totalProgress_; Gtk::ProgressBar *bufferFillRate_; Gtk::ProgressBar *writerFillRate_; Gtk::Label *bufferFillRateLabel_; Gtk::Label *writerFillRateLabel_; void needBufferProgress(bool visible); void needTrackProgress(bool visible); ProgressDialog *poolNext_; void update(unsigned long); void start(CdDevice *, const char *tocFileName); void stop(); void closeAction(); void ejectAction(); void clear(); void setCloseButtonLabel(int l); }; class ProgressDialogPool { public: ProgressDialogPool(); ~ProgressDialogPool(); void update(unsigned long); ProgressDialog* start(CdDevice*, const char* tocFileName, bool showBuffer = true, bool showTrack = true); ProgressDialog* start(Gtk::Window& parent_window, CdDevice*, const char* tocFileName, bool showBuffer = true, bool showTrack = true); void stop(ProgressDialog*); private: ProgressDialog* activeDialogs_; ProgressDialog* pool_; }; #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/Project.cc����������������������������������������������������������0000664�0000000�0000000�00000007354�15114537466�0020575�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2000 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #include <errno.h> #include <gtkmm.h> #include <glibmm/i18n.h> #include "config.h" #include "Project.h" #include "util.h" #include "xcdrdao.h" #include "guiUpdate.h" #include "gcdmaster.h" #include "MessageBox.h" #include "AudioCDView.h" #include "TocEdit.h" #include "TocEditView.h" #include "RecordTocDialog.h" Project::Project(Gtk::Window* parent) { parent_ = parent; new_ = true; saveFileSelector_ = 0; recordTocDialog_ = 0; parent_ = NULL; progressbar_ = NULL; progressButton_ = NULL; tocEdit_ = NULL; saveFileSelector_ = NULL; projectNumber_ = 0; statusbar_ = NULL; } void Project::updateWindowTitle() { std::string s(tocEdit_->filename()); s += " - "; s += APP_NAME; if (tocEdit_->tocDirty()) s += " (*)"; if (parent_) parent_->set_title(s); } void Project::saveProject() { if (new_) { saveAsProject(); return; } if (tocEdit_->saveToc() == 0) { statusMessage(_("Project saved to \"%s\"."), tocEdit_->filename()); guiUpdate(UPD_TOC_DIRTY); } else { std::string s(_("Cannot save toc to \"")); s += tocEdit_->filename(); s+= "\":"; MessageBox msg(parent_, _("Save Project"), 0, s.c_str(), strerror(errno), NULL); msg.run(); } } void Project::saveAsProject() { if (!saveFileSelector_) { saveFileSelector_ = new Gtk::FileChooserDialog(_("Save Project"), Gtk::FILE_CHOOSER_ACTION_SAVE); saveFileSelector_->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); saveFileSelector_->add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK); saveFileSelector_->set_transient_for(*parent_); } saveFileSelector_->present(); int result = saveFileSelector_->run(); saveFileSelector_->hide(); if (result == Gtk::RESPONSE_OK) { char *s = g_strdup(saveFileSelector_->get_filename().c_str()); if (s != NULL && *s != 0 && s[strlen(s) - 1] != '/') { if (tocEdit_->saveAsToc(stripCwd(s)) == 0) { statusMessage(_("Project saved to \"%s\"."), tocEdit_->filename()); new_ = false; // The project is now saved updateWindowTitle(); guiUpdate(UPD_TOC_DIRTY); } else { std::string m(_("Cannot save toc to \"")); m += tocEdit_->filename(); m += "\":"; MessageBox msg(saveFileSelector_, _("Save Project"), 0, m.c_str(), strerror(errno), NULL); msg.run(); } } if (s) g_free(s); } } int Project::projectNumber() { return projectNumber_; } TocEdit *Project::tocEdit() { return tocEdit_; } void Project::statusMessage(const char *fmt, ...) { va_list args; va_start(args, fmt); char *s = g_strdup_vprintf(fmt, args); statusbar_->push(s); free(s); va_end(args); } void Project::tocBlockedMsg(const char *op) { MessageBox msg(parent_, op, 0, _("Cannot perform requested operation because " "project is in read-only state."), NULL); msg.run(); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/Project.h�����������������������������������������������������������0000664�0000000�0000000�00000003537�15114537466�0020436�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 2000 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __PROJECT_H__ #define __PROJECT_H__ #include <gtkmm.h> class RecordTocDialog; class TocEdit; class Project : public Gtk::VBox { public: Project(Gtk::Window* parent); void readToc(char *name); void statusMessage(const char *fmt, ...); void tocBlockedMsg(const char *); virtual bool closeProject() = 0; virtual void saveProject(); virtual void saveAsProject(); virtual void recordToc2CD() = 0; int projectNumber(); TocEdit* tocEdit(); Gtk::Window* getParentWindow() { return parent_; }; virtual void update(unsigned long level) = 0; protected: int projectNumber_; bool new_; // If it is a new project (not saved) Gtk::Window* parent_; TocEdit* tocEdit_; RecordTocDialog* recordTocDialog_; Gtk::Statusbar* statusbar_; Gtk::ProgressBar* progressbar_; Gtk::Button* progressButton_; Gtk::FileChooserDialog* saveFileSelector_; void updateWindowTitle(); virtual void projectInfo() = 0; }; #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/ProjectChooser.cc���������������������������������������������������0000664�0000000�0000000�00000004654�15114537466�0022120�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2000 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #include <gtkmm.h> #include <iostream> #include "xcdrdao.h" #include "gcdmaster.h" #include "guiUpdate.h" #include "ProjectChooser.h" #include "Icons.h" #define ICON_PADDING 10 #define LABEL_PADDING 10 #define BUTTONS_RELIEF Gtk::RELIEF_NORMAL ProjectChooser::ProjectChooser() { Glib::RefPtr<Gtk::Builder> builder; try { builder = Gtk::Builder::create_from_file(CDRDAO_GLADEDIR "/ProjectChooser.glade", "mainbox"); } catch(const Glib::Exception& ex) { try { builder = Gtk::Builder::create_from_file("glade/ProjectChooser.glade", "mainbox"); } catch(const Glib::Exception& ex) { std::cerr << ex.what() << std::endl; return; } } Gtk::Box* pBox = 0; builder->get_widget("mainbox", pBox); if(!pBox) return; Gtk::Image* pImage = 0; builder->get_widget("AudioImage", pImage); if (pImage) { pImage->set(Icons::AUDIOCD, Gtk::ICON_SIZE_DIALOG); } builder->get_widget("CopyImage", pImage); if (pImage) { pImage->set(Icons::COPYCD, Gtk::ICON_SIZE_DIALOG); } builder->get_widget("DumpImage", pImage); if (pImage) { pImage->set(Icons::DUMPCD, Gtk::ICON_SIZE_DIALOG); } Gtk::Button* pButton = 0; builder->get_widget("AudioButton", pButton); if (pButton) { pButton->signal_clicked().connect(ProjectChooser::newAudioCDProject); } builder->get_widget("CopyButton", pButton); if (pButton) { pButton->signal_clicked().connect( ProjectChooser::newDuplicateCDProject); } builder->get_widget("DumpButton", pButton); if (pButton) { pButton->signal_clicked().connect(ProjectChooser::newDumpCDProject); } pack_start(*pBox); } ������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/ProjectChooser.h����������������������������������������������������0000664�0000000�0000000�00000002144�15114537466�0021752�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 2000 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __PROJECT_CHOOSER_H__ #define __PROJECT_CHOOSER_H__ #include <gtkmm.h> class ProjectChooser : public Gtk::VBox { public: ProjectChooser(); sigc::signal0<void> newAudioCDProject; sigc::signal0<void> newDuplicateCDProject; sigc::signal0<void> newDumpCDProject; }; #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/RecordCDSource.cc���������������������������������������������������0000664�0000000�0000000�00000020137�15114537466�0021767�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #include "config.h" #include <stdio.h> #include <limits.h> #include <math.h> #include <assert.h> #include <unistd.h> #include <gtkmm.h> #include <glibmm/i18n.h> #include "RecordCDSource.h" #include "xcdrdao.h" #include "CdDevice.h" #include "guiUpdate.h" #include "util.h" #include "DeviceList.h" #define MAX_CORRECTION_ID 3 static RecordCDSource::CorrectionTable CORRECTION_TABLE[MAX_CORRECTION_ID + 1] = { { 3, N_("Jitter + scratch (slow)") }, { 2, N_("Jitter + checks") }, { 1, N_("Jitter correction") }, { 0, N_("No checking (fast)") } }; #define MAX_SUBCHAN_READ_MODE_ID 2 static RecordCDSource::SubChanReadModeTable SUBCHAN_READ_MODE_TABLE[MAX_SUBCHAN_READ_MODE_ID + 1] = { { 0, N_("none") }, { 1, N_("R-W packed") }, { 2, N_("R-W raw") } }; RecordCDSource::RecordCDSource(Gtk::Window *parent) { parent_ = parent; active_ = 0; // onTheFly_ = 0; correction_ = 0; speed_ = 1; subChanReadMode_ = 0; moreOptionsDialog_ = 0; set_spacing(10); DEVICES = new DeviceList(CdDevice::CD_ROM); pack_start(*DEVICES); // device settings Gtk::Frame *extractOptionsFrame = new Gtk::Frame(_(" Read Options ")); Gtk::VBox *vbox = new Gtk::VBox; vbox->set_border_width(5); vbox->set_spacing(5); vbox->show(); extractOptionsFrame->add(*vbox); onTheFlyButton_ = new Gtk::CheckButton(_("Copy to disk before burning"), 0); onTheFlyButton_->set_active(true); onTheFlyButton_->show(); vbox->pack_start(*onTheFlyButton_); Gtk::HBox *hbox = new Gtk::HBox; Gtk::Label *label = new Gtk::Label(_("Speed: "), 0); label->show(); hbox->pack_start(*label, false, false); hbox->show(); Glib::RefPtr<Gtk::Adjustment> adjustment = Gtk::Adjustment::create(1, 1, 50); speedSpinButton_ = new Gtk::SpinButton(adjustment); speedSpinButton_->set_digits(0); speedSpinButton_->show(); speedSpinButton_->set_sensitive(false); adjustment->signal_value_changed().connect(sigc::mem_fun(*this, &RecordCDSource::speedChanged)); hbox->pack_start(*speedSpinButton_, false, false, 10); speedButton_ = new Gtk::CheckButton(_("Use max."), 0); speedButton_->set_active(true); speedButton_->show(); speedButton_->signal_toggled().connect(sigc::mem_fun(*this, &RecordCDSource::speedButtonChanged)); hbox->pack_start(*speedButton_, true, true); vbox->pack_start(*hbox); Gtk::Image* moreOptionsPixmap = manage(new Gtk::Image(Gtk::StockID(Gtk::Stock::PROPERTIES), Gtk::ICON_SIZE_SMALL_TOOLBAR)); Gtk::Label *moreOptionsLabel = manage(new Gtk::Label(_("More Options"))); Gtk::HBox *moreOptionsBox = manage(new Gtk::HBox); moreOptionsBox->set_border_width(2); Gtk::Button *moreOptionsButton = manage(new Gtk::Button()); moreOptionsBox->pack_start(*moreOptionsPixmap, false, false, 3); moreOptionsBox->pack_start(*moreOptionsLabel, false, false, 4); moreOptionsButton->add(*moreOptionsBox); moreOptionsButton->signal_clicked().connect(mem_fun(*this, &RecordCDSource::moreOptions)); moreOptionsPixmap->show(); moreOptionsLabel->show(); moreOptionsBox->show(); moreOptionsButton->show(); moreOptionsBox = manage(new Gtk::HBox); moreOptionsBox->show(); vbox->pack_start(*moreOptionsBox); moreOptionsBox->pack_end(*moreOptionsButton, false, false); pack_start(*extractOptionsFrame, Gtk::PACK_SHRINK); extractOptionsFrame->show(); } RecordCDSource::~RecordCDSource() { if (moreOptionsDialog_) delete moreOptionsDialog_; } void RecordCDSource::start() { if (active_) { get_parent_window()->raise(); return; } active_ = 1; update(UPD_CD_DEVICES); show(); } void RecordCDSource::stop() { if (active_) { hide(); active_ = 0; } } void RecordCDSource::update(unsigned long level) { if (!active_) return; if (level & UPD_CD_DEVICES) DEVICES->import(); else if (level & UPD_CD_DEVICE_STATUS) DEVICES->importStatus(); } void RecordCDSource::moreOptions() { if (!moreOptionsDialog_) { Gtk::Table *table; Gtk::Label *label; table = new Gtk::Table(2, 4, false); table->set_row_spacings(2); table->set_col_spacings(10); table->set_border_width(5); moreOptionsDialog_ = new Gtk::MessageDialog(*parent_, _("Source options"),false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_CLOSE, true); Gtk::Box *box = moreOptionsDialog_->get_vbox(); Gtk::Frame *frame = new Gtk::Frame(_(" More Source Options ")); box->pack_start(*frame); Gtk::VBox *vbox = new Gtk::VBox; vbox->set_border_width(10); vbox->set_spacing(5); frame->add(*vbox); vbox->pack_start(*table); continueOnErrorButton_ = new Gtk::CheckButton(_("Continue if errors found"), 0); continueOnErrorButton_->set_active(false); table->attach(*continueOnErrorButton_, 0, 1, 0, 1); ignoreIncorrectTOCButton_ = new Gtk::CheckButton(_("Ignore incorrect TOC"), 0); ignoreIncorrectTOCButton_->set_active(false); table->attach(*ignoreIncorrectTOCButton_, 0, 1, 1, 2); for (int i = 0; i <= MAX_CORRECTION_ID; i++) { correctionMenu_.append(CORRECTION_TABLE[i].name); } correctionMenu_.signal_changed().connect(sigc::mem_fun(*this, &RecordCDSource::setCorrection)); correctionMenu_.set_active(correction_); Gtk::Alignment *align; label = new Gtk::Label(_("Audio Correction Method:")); align = new Gtk::Alignment(0, 0.5, 0, 1); align->add(*label); table->attach(*align, 0, 1, 2, 3, Gtk::FILL); table->attach(correctionMenu_, 1, 2, 2, 3); for (int i = 0; i <= MAX_SUBCHAN_READ_MODE_ID; i++) { subChanReadModeMenu_.append(SUBCHAN_READ_MODE_TABLE[i].name); } subChanReadModeMenu_.signal_changed().connect(sigc::mem_fun(*this, &RecordCDSource::setSubChanReadMode)); subChanReadModeMenu_.set_active(subChanReadMode_); label = new Gtk::Label(_("Sub-Channel Reading Mode:")); align = new Gtk::Alignment(0, 0.5, 0, 1); align->add(*label); table->attach(*align, 0, 1, 3, 4, Gtk::FILL); table->attach(subChanReadModeMenu_, 1, 2, 3, 4); } moreOptionsDialog_->show_all(); moreOptionsDialog_->run(); moreOptionsDialog_->hide(); } void RecordCDSource::setCorrection() { int s = correctionMenu_.get_active_row_number(); if (s >= 0 && s <= MAX_CORRECTION_ID) correction_ = s; } bool RecordCDSource::getOnTheFly() { return onTheFlyButton_->get_active() ? 0 : 1; } void RecordCDSource::setOnTheFly(bool active) { onTheFlyButton_->set_active(!active); } int RecordCDSource::getCorrection() { return CORRECTION_TABLE[correction_].correction; } void RecordCDSource::setSubChanReadMode() { int m = subChanReadModeMenu_.get_active_row_number(); if (m >= 0 && m <= MAX_SUBCHAN_READ_MODE_ID) subChanReadMode_ = m; } int RecordCDSource::getSubChanReadMode() { return SUBCHAN_READ_MODE_TABLE[subChanReadMode_].mode; } void RecordCDSource::speedButtonChanged() { if (speedButton_->get_active()) { speedSpinButton_->set_sensitive(false); } else { speedSpinButton_->set_sensitive(true); } } void RecordCDSource::speedChanged() { //Do some validating here. speed_ <= MAX read speed of CD. speed_ = speedSpinButton_->get_value_as_int(); } void RecordCDSource::onTheFlyOption(bool visible) { if (visible) onTheFlyButton_->show(); else onTheFlyButton_->hide(); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/RecordCDSource.h����������������������������������������������������0000664�0000000�0000000�00000004001�15114537466�0021621�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998, 1999 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __RECORD_CD_SOURCE_H #define __RECORD_CD_SOURCE_H class CdDevice; class DeviceList; class RecordCDSource : public Gtk::VBox { public: RecordCDSource(Gtk::Window *); ~RecordCDSource(); void start(); void stop(); void update(unsigned long level); bool getOnTheFly(); void setOnTheFly(bool); int getCorrection(); int getSubChanReadMode(); DeviceList *getDeviceList() { return DEVICES;} void onTheFlyOption(bool); struct CorrectionTable { int correction; const char *name; }; struct SubChanReadModeTable { int mode; const char *name; }; private: DeviceList *DEVICES; int active_; int correction_; int speed_; int subChanReadMode_; // bool onTheFly_; Gtk::Window *parent_; Gtk::MessageDialog *moreOptionsDialog_; Gtk::SpinButton *speedSpinButton_; Gtk::CheckButton *speedButton_; Gtk::ComboBoxText correctionMenu_; Gtk::ComboBoxText subChanReadModeMenu_; Gtk::CheckButton *onTheFlyButton_; Gtk::CheckButton *continueOnErrorButton_; Gtk::CheckButton *ignoreIncorrectTOCButton_; void moreOptions(); void setCorrection(); void setSubChanReadMode(); void speedButtonChanged(); void speedChanged(); }; #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/RecordCDTarget.cc���������������������������������������������������0000664�0000000�0000000�00000023147�15114537466�0021761�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.ping.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 * (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. */ #include <stdio.h> #include <limits.h> #include <math.h> #include <assert.h> #include <gtkmm.h> #include "RecordCDTarget.h" #include "MessageBox.h" #include "xcdrdao.h" #include "ConfigManager.h" #include "CdDevice.h" #include "guiUpdate.h" #include "TocEdit.h" #include "DeviceList.h" #include "util.h" RecordCDTarget::RecordCDTarget(Gtk::Window *parent) { active_ = 0; speed_ = 1; parent_ = parent; moreOptionsDialog_ = 0; set_spacing(10); DEVICES = new DeviceList(CdDevice::CD_R); pack_start(*DEVICES); // device settings Gtk::Frame *recordOptionsFrame = new Gtk::Frame(" Record Options "); Gtk::VBox *vbox = new Gtk::VBox; recordOptionsFrame->add(*vbox); vbox->set_border_width(5); vbox->set_spacing(5); vbox->show(); Gtk::HBox *hbox = new Gtk::HBox; hbox->show(); Gtk::Label *label = new Gtk::Label("Speed: ", 0); label->show(); hbox->pack_start(*label, false, false); Glib::RefPtr<Gtk::Adjustment> adjustment = Gtk::Adjustment::create(1, 1, 48); speedSpinButton_ = new Gtk::SpinButton(adjustment); speedSpinButton_->set_digits(0); speedSpinButton_->show(); speedSpinButton_->set_sensitive(false); adjustment->signal_value_changed().connect(sigc::mem_fun(*this, &RecordCDTarget::speedChanged)); hbox->pack_start(*speedSpinButton_, false, false, 10); speedButton_ = new Gtk::CheckButton("Use max.", 0); speedButton_->set_active(true); speedButton_->show(); speedButton_->signal_toggled().connect(sigc::mem_fun(*this, &RecordCDTarget::speedButtonChanged)); hbox->pack_start(*speedButton_, true, true); vbox->pack_start(*hbox); hbox = new Gtk::HBox; // hbox->show(); label = new Gtk::Label("Copies: ", 0); label->show(); hbox->pack_start(*label, false, false); adjustment = Gtk::Adjustment::create(1, 1, 999); copiesSpinButton_ = new Gtk::SpinButton(adjustment); copiesSpinButton_->set_digits(0); copiesSpinButton_->show(); hbox->pack_start(*copiesSpinButton_, false, false, 10); vbox->pack_start(*hbox); Gtk::Image* moreOptionsPixmap = manage(new Gtk::Image(Gtk::StockID(Gtk::Stock::PROPERTIES), Gtk::ICON_SIZE_SMALL_TOOLBAR)); Gtk::Label *moreOptionsLabel = manage(new Gtk::Label("More Options")); Gtk::HBox *moreOptionsBox = manage(new Gtk::HBox); moreOptionsBox->set_border_width(2); Gtk::Button *moreOptionsButton = manage(new Gtk::Button()); moreOptionsBox->pack_start(*moreOptionsPixmap, false, false, 3); moreOptionsBox->pack_start(*moreOptionsLabel, false, false, 4); moreOptionsButton->add(*moreOptionsBox); moreOptionsButton->signal_clicked().connect(mem_fun(*this, &RecordCDTarget::moreOptions)); moreOptionsPixmap->show(); moreOptionsLabel->show(); moreOptionsBox->show(); moreOptionsButton->show(); moreOptionsBox = manage(new Gtk::HBox); moreOptionsBox->show(); vbox->pack_start(*moreOptionsBox, false, false); moreOptionsBox->pack_end(*moreOptionsButton, false, false); pack_start(*recordOptionsFrame, Gtk::PACK_SHRINK); recordOptionsFrame->show(); } RecordCDTarget::~RecordCDTarget() { if (moreOptionsDialog_) delete moreOptionsDialog_; } void RecordCDTarget::start() { active_ = 1; update(UPD_ALL); show(); } void RecordCDTarget::stop() { if (active_) { hide(); active_ = 0; } } void RecordCDTarget::moreOptions() { if (!moreOptionsDialog_) { moreOptionsDialog_ = new Gtk::MessageDialog(*parent_, "Target options",false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_CLOSE, true); Gtk::Box *box = moreOptionsDialog_->get_vbox(); Gtk::Frame *frame = new Gtk::Frame(" More Target Options "); box->pack_start(*frame); Gtk::VBox* vbox = new Gtk::VBox; vbox->set_border_width(10); vbox->set_spacing(5); frame->add(*vbox); overburnButton_ = new Gtk::CheckButton("Allow over-burning", 0); overburnButton_->set_active(false); vbox->pack_start(*overburnButton_); ejectButton_ = new Gtk::CheckButton("Eject the CD after writing", 0); ejectButton_->set_active(false); vbox->pack_start(*ejectButton_); reloadButton_ = new Gtk::CheckButton("Reload the CD after writing, if necessary", 0); reloadButton_->set_active(false); vbox->pack_start(*reloadButton_); closeSessionButton_ = new Gtk::CheckButton("Close disk - no further writing possible!", 0); closeSessionButton_->set_active(true); vbox->pack_start(*closeSessionButton_); Gtk::HBox *hbox = new Gtk::HBox; Gtk::Label *label = new Gtk::Label("Buffer: ", 0); hbox->pack_start(*label, false, false); Glib::RefPtr<Gtk::Adjustment> adjustment = Gtk::Adjustment::create(10, 10, 1000); bufferSpinButton_ = new Gtk::SpinButton(adjustment); hbox->pack_start(*bufferSpinButton_, false, false, 10); label = new Gtk::Label("audio seconds "); hbox->pack_start(*label, false, false); bufferRAMLabel_ = new Gtk::Label("= 1.72 Mb buffer.", 0); hbox->pack_start(*bufferRAMLabel_, true, true); adjustment->signal_value_changed(). connect(sigc::mem_fun(*this, &RecordCDTarget::updateBufferRAMLabel)); vbox->pack_start(*hbox); } moreOptionsDialog_->show_all(); moreOptionsDialog_->run(); moreOptionsDialog_->hide(); } void RecordCDTarget::update(unsigned long level) { if (!active_) return; if (level & UPD_CD_DEVICES) DEVICES->import(); else if (level & UPD_CD_DEVICE_STATUS) DEVICES->importStatus(); } void RecordCDTarget::cancelAction() { stop(); } int RecordCDTarget::getMultisession() { if (moreOptionsDialog_) return closeSessionButton_->get_active() ? 0 : 1; else return 0; } int RecordCDTarget::getCopies() { return copiesSpinButton_->get_value_as_int(); } int RecordCDTarget::getSpeed() { if (speedButton_->get_active()) return 0; else return speed_; } int RecordCDTarget::getBuffer() { if (moreOptionsDialog_) return bufferSpinButton_->get_value_as_int(); else return 10; } bool RecordCDTarget::getEject() { if (moreOptionsDialog_) return ejectButton_->get_active() ? 1 : 0; else return 0; } bool RecordCDTarget::getOverburn() { if (moreOptionsDialog_) return overburnButton_->get_active() ? 1 : 0; else return 0; } int RecordCDTarget::checkEjectWarning(Gtk::Window *parent) { // If ejecting the CD after recording is requested issue a warning message // because buffer under runs may occur for other devices that are recording. if (getEject()) { if (configManager->getEjectWarning()) { Ask3Box msg(parent, "Request", 1, 2, "Ejecting a CD may block the SCSI bus and", "cause buffer under runs when other devices", "are still recording.", "", "Keep the eject setting anyway?", NULL); switch (msg.run()) { case 1: // keep eject setting if (msg.dontShowAgain()) { configManager->setEjectWarning(false); } return 1; break; case 2: // don't keep eject setting ejectButton_->set_active(false); return 0; break; default: // cancel return -1; break; } } return 1; } return 0; } bool RecordCDTarget::getReload() { if (moreOptionsDialog_) return reloadButton_->get_active() ? 1 : 0; else return 0; } int RecordCDTarget::checkReloadWarning(Gtk::Window *parent) { // The same is true for reloading the disk. if (getReload()) { if (configManager->getReloadWarning()) { Ask3Box msg(parent, "Request", 1, 2, "Reloading a CD may block the SCSI bus and", "cause buffer under runs when other devices", "are still recording.", "", "Keep the reload setting anyway?", NULL); switch (msg.run()) { case 1: // keep reload setting if (msg.dontShowAgain()) { configManager->setReloadWarning(false); } return 1; break; case 2: // don't keep reload setting reloadButton_->set_active(false); return 0; break; default: // cancel return -1; break; } } return 1; } return 0; } void RecordCDTarget::updateBufferRAMLabel() { char label[20]; snprintf(label, sizeof(label), "= %0.2f Mb buffer.", bufferSpinButton_->get_value() * 0.171875); bufferRAMLabel_->set_text(label); } void RecordCDTarget::speedButtonChanged() { if (speedButton_->get_active()) { speedSpinButton_->set_sensitive(false); } else { speedSpinButton_->set_sensitive(true); } } void RecordCDTarget::speedChanged() { // TODO: get max burn speed from selected burner(s) int new_speed; new_speed = speedSpinButton_->get_value_as_int(); if ((new_speed % 2) == 1) { if (new_speed > 2) { if (new_speed > speed_) new_speed = new_speed + 1; else new_speed = new_speed - 1; } speedSpinButton_->set_value(new_speed); } speed_ = new_speed; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/RecordCDTarget.h����������������������������������������������������0000664�0000000�0000000�00000003767�15114537466�0021631�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998, 1999 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __RECORD_CD_TARGET_H #define __RECORD_CD_TARGET_H #include <gtkmm.h> #include <gtk/gtk.h> class TocEdit; class CdDevice; class DeviceList; class RecordCDTarget : public Gtk::VBox { public: RecordCDTarget(Gtk::Window *); ~RecordCDTarget(); void start(); void stop(); void update(unsigned long level); DeviceList *getDeviceList() { return DEVICES;} int getMultisession(); int getCopies(); int getSpeed(); bool getEject(); bool getOverburn(); int checkEjectWarning(Gtk::Window *); bool getReload(); int checkReloadWarning(Gtk::Window *); int getBuffer(); void cancelAction(); private: int active_; DeviceList *DEVICES; int speed_; Gtk::Window *parent_; Gtk::MessageDialog *moreOptionsDialog_; Gtk::CheckButton *closeSessionButton_; Gtk::CheckButton *ejectButton_; Gtk::CheckButton *reloadButton_; Gtk::CheckButton *overburnButton_; Gtk::SpinButton *copiesSpinButton_; Gtk::SpinButton *speedSpinButton_; Gtk::CheckButton *speedButton_; Gtk::SpinButton *bufferSpinButton_; Gtk::Label *bufferRAMLabel_; void updateBufferRAMLabel(); void moreOptions(); void speedButtonChanged(); void speedChanged(); }; #endif ���������cdrdao-cdrdao-f00afb2/gcdmaster/RecordHDTarget.cc���������������������������������������������������0000664�0000000�0000000�00000004671�15114537466�0021767�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998, 1999 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #include "config.h" #include <stdio.h> #include <limits.h> #include <math.h> #include <assert.h> #include <gtkmm.h> #include <glibmm/i18n.h> #include "RecordHDTarget.h" #include "MessageBox.h" #include "xcdrdao.h" #include "CdDevice.h" #include "guiUpdate.h" #include "TocEdit.h" RecordHDTarget::RecordHDTarget() { active_ = false; set_spacing(10); // device settings Gtk::Frame *recordOptionsFrame = manage( new Gtk::Frame(_(" Record Options "))); Gtk::Table *table = manage(new Gtk::Table(2, 2, false)); table->set_row_spacings(2); table->set_col_spacings(10); table->set_border_width(5); recordOptionsFrame->add(*table); recordOptionsFrame->show_all(); pack_start(*recordOptionsFrame, Gtk::PACK_SHRINK); Gtk::Label *label = manage(new Gtk::Label(_("Directory: "))); table->attach(*label, 0, 1, 0, 1, Gtk::FILL); dirEntry_ = manage( new Gtk::FileChooserButton(Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); table->attach(*dirEntry_, 1, 2, 0, 1); label = manage(new Gtk::Label(_("Name: "))); table->attach(*label, 0, 1, 1, 2, Gtk::FILL); fileNameEntry_ = manage(new Gtk::Entry); table->attach(*fileNameEntry_, 1, 2, 1, 2); } void RecordHDTarget::start() { active_ = true; update(UPD_ALL); show(); } void RecordHDTarget::stop() { if (active_) { hide(); active_ = false; } } void RecordHDTarget::update(unsigned long level) { if (!active_) return; } void RecordHDTarget::cancelAction() { stop(); } std::string RecordHDTarget::getFilename() { return fileNameEntry_->get_text(); } std::string RecordHDTarget::getPath() { return dirEntry_->get_filename(); } �����������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/RecordHDTarget.h����������������������������������������������������0000664�0000000�0000000�00000002371�15114537466�0021624�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998, 1999 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __RECORD_HD_TARGET_H #define __RECORD_HD_TARGET_H class TocEdit; class CdDevice; class DeviceList; class RecordHDTarget : public Gtk::VBox { public: RecordHDTarget(); void start(); void stop(); void update(unsigned long level); void cancelAction(); std::string getFilename(); std::string getPath(); private: bool active_; Gtk::FileChooserButton *dirEntry_; Gtk::Entry *fileNameEntry_; }; #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/RecordTocDialog.cc��������������������������������������������������0000664�0000000�0000000�00000014671�15114537466�0022173�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #include <gtkmm.h> #include <glibmm/i18n.h> #include "config.h" #include "RecordTocDialog.h" #include "RecordTocSource.h" #include "RecordCDSource.h" #include "RecordCDTarget.h" #include "RecordHDTarget.h" #include "guiUpdate.h" #include "DeviceList.h" #include "MessageBox.h" #include "TocEdit.h" #include "Icons.h" RecordTocDialog::RecordTocDialog(TocEdit *tocEdit) { tocEdit_ = tocEdit; set_title(_("Record CD")); Gtk::VBox *vbox = manage(new Gtk::VBox); vbox->set_border_width(10); vbox->set_spacing(10); Gtk::HBox *hbox = manage(new Gtk::HBox); hbox->set_spacing(10); vbox->pack_start(*hbox); add(*vbox); active_ = 0; TocSource = new RecordTocSource(tocEdit_); TocSource->start(); CDTarget = new RecordCDTarget(this); CDTarget->start(); hbox->pack_start(*TocSource, Gtk::PACK_SHRINK); hbox->pack_start(*CDTarget); hbox = new Gtk::HBox; hbox->set_spacing(10); Gtk::VBox *frameBox = new Gtk::VBox; simulate_rb = new Gtk::RadioButton(_("Simulate"), 0); simulateBurn_rb = new Gtk::RadioButton(_("Simulate and Burn"), 0); burn_rb = new Gtk::RadioButton(_("Burn"), 0); frameBox->pack_start(*simulate_rb); frameBox->pack_start(*simulateBurn_rb); Gtk::RadioButton::Group rbgroup = simulate_rb->get_group(); simulateBurn_rb->set_group(rbgroup); frameBox->pack_start(*burn_rb); burn_rb->set_group(rbgroup); hbox->pack_start(*frameBox, true, false); Gtk::Image *pixmap = manage(new Gtk::Image(Icons::GCDMASTER, Gtk::ICON_SIZE_DIALOG)); Gtk::Label *startLabel = manage(new Gtk::Label(_("Start"))); Gtk::VBox *startBox = manage(new Gtk::VBox); Gtk::Button *button = manage(new Gtk::Button()); startBox->pack_start(*pixmap, false, false); startBox->pack_start(*startLabel, false, false); button->add(*startBox); button->signal_clicked().connect(mem_fun(*this, &RecordTocDialog::startAction)); hbox->pack_start(*button); Gtk::Button* cancel_but = manage(new Gtk::Button(Gtk::StockID(Gtk::Stock::CANCEL))); cancel_but->signal_clicked().connect(mem_fun(*this, &Gtk::Widget::hide)); hbox->pack_start(*cancel_but); vbox->pack_start(*hbox, Gtk::PACK_SHRINK); show_all_children(); } RecordTocDialog::~RecordTocDialog() { delete TocSource; delete CDTarget; } void RecordTocDialog::start(Gtk::Window *parent) { if (!active_) { active_ = true; TocSource->start(); CDTarget->start(); update(UPD_ALL); set_transient_for(*parent); } present(); } void RecordTocDialog::stop() { hide(); active_ = false; TocSource->stop(); CDTarget->stop(); } void RecordTocDialog::update(unsigned long level) { if (!active_) return; std::string title; title += _("Record project "); title += tocEdit_->filename(); title += _(" to CD"); set_title(title); TocSource->update(level); CDTarget->update(level); if (level & UPD_CD_DEVICE_STATUS) CDTarget->getDeviceList()->selectOne(); } bool RecordTocDialog::on_delete_event(GdkEventAny*) { stop(); return 1; } void RecordTocDialog::startAction() { if (tocEdit_ == NULL) return; DeviceList *targetList = CDTarget->getDeviceList(); if (targetList->selection().empty()) { Gtk::MessageDialog md(*this, _("Please select at least one recorder device"), Gtk::MESSAGE_INFO); md.run(); return; } Toc *toc = tocEdit_->toc(); if (toc->nofTracks() == 0 || toc->length().lba() < 300) { Gtk::MessageDialog md(*this, _("Current toc contains no tracks or length " "of at least one track is < 4 seconds"), Gtk::MESSAGE_ERROR); md.run(); return; } switch (toc->checkCdTextData()) { case 0: // OK break; case 1: // warning { Ask2Box msg(this, _("CD-TEXT Inconsistency"), 0, 2, _("Inconsistencies were detected in the defined CD-TEXT " "data"), _("which may produce undefined results. See the console"), _("output for more details."), "", _("Do you want to proceed anyway?"), NULL); if (msg.run() != 1) return; } break; default: // error { MessageBox msg(this, _("CD-TEXT Error"), 0, _("The defined CD-TEXT data is erroneous or " "incomplete."), _("See the console output for more details."), NULL); msg.run(); return; } break; } int simulate; if (simulate_rb->get_active()) simulate = 1; else if (simulateBurn_rb->get_active()) simulate = 2; else simulate = 0; int multiSession = CDTarget->getMultisession(); int burnSpeed = CDTarget->getSpeed(); int overburn = CDTarget->getOverburn(); int eject = CDTarget->checkEjectWarning(this); if (eject == -1) return; int reload = CDTarget->checkReloadWarning(this); if (reload == -1) return; int buffer = CDTarget->getBuffer(); DeviceList* target = CDTarget->getDeviceList(); if (target->selection().empty()) { Gtk::MessageDialog d(*this, _("Please select a writer device"), Gtk::MESSAGE_INFO); d.run(); return; } std::string targetData = target->selection(); CdDevice *writeDevice = CdDevice::find(targetData.c_str()); if (writeDevice) { if (!writeDevice->recordDao(*this, tocEdit_, simulate, multiSession, burnSpeed, eject, reload, buffer, overburn)) { Gtk::MessageDialog d(*this, _("Cannot start disk-at-once recording"), Gtk::MESSAGE_ERROR); d.run(); } else { guiUpdate(UPD_CD_DEVICE_STATUS); } } stop(); } �����������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/RecordTocDialog.h���������������������������������������������������0000664�0000000�0000000�00000002624�15114537466�0022030�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998, 1999 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __RECORD_TOC_DIALOG_H #define __RECORD_TOC_DIALOG_H class TocEdit; class RecordTocSource; class RecordCDTarget; class RecordTocDialog : public Gtk::Window { public: RecordTocDialog(TocEdit *); ~RecordTocDialog(); void start(Gtk::Window *); void update(unsigned long level); private: RecordTocSource *TocSource; RecordCDTarget *CDTarget; TocEdit *tocEdit_; bool active_; Gtk::RadioButton* simulate_rb; Gtk::RadioButton* simulateBurn_rb; Gtk::RadioButton* burn_rb; void stop(); void startAction(); bool on_delete_event(GdkEventAny*); }; #endif ������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/RecordTocSource.cc��������������������������������������������������0000664�0000000�0000000�00000006317�15114537466�0022232�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #include <stdio.h> #include <limits.h> #include <math.h> #include <assert.h> #include <gtkmm.h> #include <glibmm/i18n.h> #include "config.h" #include "RecordTocSource.h" #include "MessageBox.h" #include "xcdrdao.h" #include "CdDevice.h" #include "guiUpdate.h" #include "TocEdit.h" #include "DeviceList.h" #include "util.h" RecordTocSource::RecordTocSource(TocEdit *tocEdit) { Gtk::Table *table; Gtk::Label *label; active_ = false; tocEdit_ = tocEdit; // device settings Gtk::Frame *infoFrame = manage(new Gtk::Frame(_(" Project Information "))); table = manage(new Gtk::Table(5, 2, FALSE)); table->set_row_spacings(5); table->set_col_spacings(5); table->set_border_width(10); label = manage(new Gtk::Label(_("Project name: "), 1)); table->attach(*label, 0, 1, 0, 1); table->attach(projectLabel_, 1, 2, 0, 1); label = manage(new Gtk::Label(_("Toc Type: "), 1)); table->attach(*label, 0, 1, 1, 2); table->attach(tocTypeLabel_, 1, 2, 1, 2); label = manage(new Gtk::Label(_("Tracks: "), 1)); table->attach(*label, 0, 1, 2, 3); table->attach(nofTracksLabel_, 1, 2, 2, 3); label = manage(new Gtk::Label(_("Length: "), 1)); table->attach(*label, 0, 1, 3, 4); table->attach(tocLengthLabel_, 1, 2, 3, 4); infoFrame->add(*table); pack_start(*infoFrame, Gtk::PACK_SHRINK); } void RecordTocSource::start() { active_ = true; update(UPD_ALL); show_all(); } void RecordTocSource::stop() { if (active_) { hide(); active_ = false; } } void RecordTocSource::update(unsigned long level) { update(level, tocEdit_); } void RecordTocSource::update(unsigned long level, TocEdit *tedit) { if (!active_) return; if (tocEdit_ != tedit) { level = UPD_ALL; tocEdit_ = tedit; } if (tocEdit_ == NULL) { projectLabel_.set_text(""); tocTypeLabel_.set_text(""); nofTracksLabel_.set_text(""); tocLengthLabel_.set_text(""); } else { if (level & UPD_TOC_DATA) { char label[256]; char buf[50]; const Toc *toc = tocEdit_->toc(); projectLabel_.set_text(tocEdit_->filename()); tocTypeLabel_.set_text(toc->tocType2String(toc->tocType())); snprintf(label, sizeof(label), "%d", toc->nofTracks()); nofTracksLabel_.set_text(label); snprintf(buf, sizeof(buf),"%d:%02d:%02d", toc->length().min(), toc->length().sec(), toc->length().frac()); tocLengthLabel_.set_text(buf); } } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/RecordTocSource.h���������������������������������������������������0000664�0000000�0000000�00000002464�15114537466�0022073�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998, 1999 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __RECORD_TOC_SOURCE_H #define __RECORD_TOC_SOURCE_H #include <gtkmm.h> #include <gtk/gtk.h> class TocEdit; class RecordTocSource : public Gtk::VBox { public: RecordTocSource(TocEdit *); void start(); void stop(); void update(unsigned long level); void update(unsigned long level, TocEdit *); private: TocEdit* tocEdit_; bool active_; Gtk::Label projectLabel_; Gtk::Label tocTypeLabel_; Gtk::Label nofTracksLabel_; Gtk::Label tocLengthLabel_; }; #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/SampleDisplay.cc����������������������������������������������������0000664�0000000�0000000�00000075301�15114537466�0021733�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #include <stdio.h> #include <limits.h> #include <math.h> #include <assert.h> #include <iostream> #include <gtkmm.h> #include <glibmm/i18n.h> #include "config.h" #include "TocEdit.h" #include "SampleDisplay.h" #include "SampleManager.h" #include "TrackManager.h" #include "Toc.h" #include "util.h" #include "log.h" /* XPM data for track marker */ #define TRACK_MARKER_XPM_WIDTH 9 #define TRACK_MARKER_XPM_HEIGHT 12 static const gchar *TRACK_MARKER_XPM_DATA[] = { "9 12 3 1", " c None", "X c #000000000000", ". c #FFFFFFFFFFFF", " ", " XXXXXXX ", " XXXXXXX ", " XXXXXXX ", " XXXXXXX ", " XXXXXXX ", " XXXXXXX ", " XXXXX ", " XXX ", " X ", " X ", " X " }; /* XPM data for index marker */ static const gchar *INDEX_MARKER_XPM_DATA[] = { "9 12 3 1", " c None", "X c #000000000000", ". c #FFFFFFFFFFFF", " ", " XXXXXXX ", " X.....X ", " X.....X ", " X.....X ", " X.....X ", " X.....X ", " X...X ", " X.X ", " X ", " X ", " X " }; /* XPM data for extend track marker */ static const gchar *TRACK_EXTEND_XPM_DATA[] = { "9 12 3 1", " c None", "X c #000000000000", ". c #FFFFFFFFFFFF", "......XX.", ".....XXX.", "....XXXX.", "...XXXXX.", "..XXXXXX.", ".XXXXXXX.", "..XXXXXX.", "...XXXXX.", "....XXXX.", ".....XXX.", "......XX.", "........." }; /* XPM data for extend track marker */ static const gchar *INDEX_EXTEND_XPM_DATA[] = { "9 12 3 1", " c None", "X c #000000000000", ". c #FFFFFFFFFFFF", "......XX.", ".....X.X.", "....X..X.", "...X...X.", "..X....X.", ".X.....X.", "..X....X.", "...X...X.", "....X..X.", ".....X.X.", "......XX.", "........." }; static void draw_line(const Cairo::RefPtr<Cairo::Context>& cr, int x1, int y1, int x2, int y2) { cr->move_to(x1, y1); cr->line_to(x2, y2); cr->stroke(); } SampleDisplay::SampleDisplay() : pixmap_(NULL), trackMarkerPixmap_(NULL), indexMarkerPixmap_(NULL), trackMarkerSelectedPixmap_( NULL), indexMarkerSelectedPixmap_(NULL), trackExtendPixmap_(NULL), indexExtendPixmap_( NULL) { adjustment_ = Gtk::Adjustment::create(0.0, 0.0, 1.0); adjustment_->signal_value_changed().connect( mem_fun(*this, &SampleDisplay::scrollTo)); trackManager_ = new TrackManager(TRACK_MARKER_XPM_WIDTH); width_ = height_ = chanHeight_ = lcenter_ = rcenter_ = 0; timeLineHeight_ = timeLineY_ = 0; timeTickWidth_ = 0; timeTickSep_ = 20; sampleStartX_ = sampleEndX_ = sampleWidthX_ = 0; minSample_ = maxSample_ = resolution_ = 0; tocEdit_ = NULL; chanSep_ = 10; cursorControlExtern_ = false; drawCursor_ = false; cursorX_ = 0; markerSet_ = false; selectionSet_ = false; regionSet_ = false; dragMode_ = DRAG_NONE; pickedTrackMarker_ = NULL; selectedTrack_ = 0; selectedIndex_ = 0; signal_configure_event().connect( mem_fun(*this, &SampleDisplay::handleConfigureEvent)); signal_motion_notify_event().connect( mem_fun(*this, &SampleDisplay::handleMotionNotifyEvent)); signal_button_press_event().connect( mem_fun(*this, &SampleDisplay::handleButtonPressEvent)); signal_button_release_event().connect( mem_fun(*this, &SampleDisplay::handleButtonReleaseEvent)); signal_enter_notify_event().connect( mem_fun(*this, &SampleDisplay::handleEnterEvent)); signal_leave_notify_event().connect( mem_fun(*this, &SampleDisplay::handleLeaveEvent)); set_events( Gdk::EXPOSURE_MASK | Gdk::LEAVE_NOTIFY_MASK | Gdk::ENTER_NOTIFY_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::POINTER_MOTION_HINT_MASK); set_vexpand(true); } void SampleDisplay::setTocEdit(TocEdit *t) { tocEdit_ = t; Toc *toc = tocEdit_->toc(); markerSet_ = false; selectionSet_ = false; regionSet_ = false; minSample_ = 0; if (toc->length().samples() > 0) { maxSample_ = toc->length().samples() - 1; } else { maxSample_ = 0; } } void SampleDisplay::updateToc(unsigned long smin, unsigned long smax) { if (tocEdit_ == NULL) return; Toc *toc = tocEdit_->toc(); if (smin <= smax) { minSample_ = smin; maxSample_ = smax; } if (toc->length().samples() == 0) { minSample_ = maxSample_ = 0; } else { if (maxSample_ >= toc->length().samples()) { // adjust 'maxSample_' to reduced length unsigned long len = maxSample_ - minSample_; maxSample_ = toc->length().samples() - 1; if (maxSample_ > len) { minSample_ = maxSample_ - len; } else { minSample_ = 0; } } } setView(minSample_, maxSample_); } void SampleDisplay::setView(unsigned long start, unsigned long end) { if (tocEdit_ == NULL) return; Toc *toc = tocEdit_->toc(); if (end < start) end = start; unsigned long len = end - start + 1; if (len < 3 && toc != NULL) { end = start + 2; if (end >= toc->length().samples()) { if (toc->length().samples() != 0) end = toc->length().samples() - 1; else end = 0; if (end <= 2) start = 0; else start = end - 2; } len = (end == 0 ? 0 : 3); } minSample_ = start; maxSample_ = end; updateSamples(); queue_draw(); if (toc == NULL) { adjustment_->set_lower(0.0); adjustment_->set_upper(0.0); adjustment_->set_page_size(0.0); // important: set value after other values adjustment_->set_value(0.0); } else { adjustment_->set_lower(0.0); adjustment_->set_upper(toc->length().samples()); adjustment_->set_step_increment(len / 4); if (adjustment_->get_step_increment() == 0.0) adjustment_->set_step_increment(1.0); adjustment_->set_page_increment(len / 1.1); adjustment_->set_page_size(len); // important: set value after other values adjustment_->set_value(minSample_); } adjustment_->changed(); } void SampleDisplay::getView(unsigned long *start, unsigned long *end) { *start = minSample_; *end = maxSample_; } bool SampleDisplay::getSelection(unsigned long *start, unsigned long *end) { if (selectionSet_) { *start = selectionStartSample_; *end = selectionEndSample_; return true; } return false; } int SampleDisplay::getMarker(unsigned long *sample) { if (markerSet_) { *sample = markerSample_; return 1; } return 0; } void SampleDisplay::setSelectedTrackMarker(int trackNr, int indexNr) { selectedTrack_ = trackNr; selectedIndex_ = indexNr; } void SampleDisplay::setRegion(unsigned long start, unsigned long end) { if (tocEdit_ == NULL) return; Toc *toc = tocEdit_->toc(); if (end <= start || end >= toc->length().samples()) { regionSet_ = false; } else { regionStartSample_ = start; regionEndSample_ = end; regionSet_ = true; } setView(minSample_, maxSample_); } void SampleDisplay::clearRegion() { bool wasSet = regionSet_; regionSet_ = false; if (wasSet) { setView(minSample_, maxSample_); } } int SampleDisplay::getRegion(unsigned long *start, unsigned long *end) { if (regionSet_) { *start = regionStartSample_; *end = regionEndSample_; return 1; } return 0; } void SampleDisplay::setCursor(int ctrl, unsigned long sample) { if (ctrl == 0) { cursorControlExtern_ = false; } else { cursorControlExtern_ = true; gint x = sample2pixel(sample); if (x >= 0) drawCursor(x); else undrawCursor(); } } void SampleDisplay::getColor(const char *colorName, Gdk::Color *color) { if (!color->set(colorName)) { log_message(-1, _("Cannot allocate color \"%s\""), colorName); } } void SampleDisplay::scrollTo() { unsigned long minSample, maxSample; if (tocEdit_ == NULL) return; Toc *toc = tocEdit_->toc(); if (adjustment_->get_page_size() == 0.0) return; minSample = (unsigned long) adjustment_->get_value(); maxSample = (unsigned long) (adjustment_->get_value() + adjustment_->get_page_size()) - 1; if (maxSample >= toc->length().samples()) { maxSample = toc->length().samples() - 1; if (maxSample <= (unsigned long) (adjustment_->get_page_size() - 1)) minSample = 0; else minSample = maxSample - (unsigned long) (adjustment_->get_page_size() - 1); } viewModified(minSample, maxSample); } unsigned long SampleDisplay::pixel2sample(gint x) { if (tocEdit_ == NULL) return 0; Toc *toc = tocEdit_->toc(); unsigned long sample; if (toc->length().lba() == 0) return 0; assert(x >= sampleStartX_ && x <= sampleEndX_); x -= sampleStartX_; double res = maxSample_ - minSample_; res /= sampleWidthX_ - 1; sample = (unsigned long) (minSample_ + res * x + 0.5); unsigned long round = 75 * 588; // 1 second unsigned long rest; if (res >= 2 * round) { if ((rest = sample % round) != 0) sample += round - rest; } else { round = 588; // 1 block if (res >= 2 * round) { if ((rest = sample % round) != 0) sample += round - rest; } } if (sample > maxSample_) sample = maxSample_; return sample; } gint SampleDisplay::sample2pixel(unsigned long sample) { if (sample < minSample_ || sample > maxSample_) return -1; unsigned long len = maxSample_ - minSample_; double val = sample - minSample_; val *= sampleWidthX_ - 1; val /= len; return (gint) (sampleStartX_ + val + 0.5); } bool SampleDisplay::handleConfigureEvent(GdkEventConfigure *event) { getColor("darkslateblue", &sampleColor_); getColor("red3", &middleLineColor_); getColor("gold2", &cursorColor_); getColor("red", &markerColor_); getColor("#ffc0e0", &selectionBackgroundColor_); Glib::RefPtr<Pango::Context> context = get_pango_context(); Pango::FontMetrics metrics = context->get_metrics( get_style_context()->get_font()); timeLineHeight_ = ((metrics.get_ascent() + metrics.get_descent()) / Pango::SCALE); trackLineHeight_ = ((metrics.get_ascent() + metrics.get_descent()) / Pango::SCALE); trackMarkerPixmap_ = Gdk::Pixbuf::create_from_xpm_data(TRACK_MARKER_XPM_DATA); indexMarkerPixmap_ = Gdk::Pixbuf::create_from_xpm_data(INDEX_MARKER_XPM_DATA); trackMarkerSelectedPixmap_ = Gdk::Pixbuf::create_from_xpm_data( TRACK_MARKER_XPM_DATA); indexMarkerSelectedPixmap_ = Gdk::Pixbuf::create_from_xpm_data( INDEX_MARKER_XPM_DATA); trackExtendPixmap_ = Gdk::Pixbuf::create_from_xpm_data(TRACK_EXTEND_XPM_DATA); indexExtendPixmap_ = Gdk::Pixbuf::create_from_xpm_data(INDEX_EXTEND_XPM_DATA); trackMarkerWidth_ = ((metrics.get_approximate_digit_width() / Pango::SCALE) * 5) + TRACK_MARKER_XPM_WIDTH + 2; width_ = get_width(); height_ = get_height(); // Don't even try to do anything smart if we haven't received a // reasonable window size yet. This will keep pixmap_ to NULL. This // is important because during startup we don't control how the // configure_event are timed wrt to gcdmaster bringup. if (width_ <= 1 || height_ <= 1) return true; chanHeight_ = (height_ - timeLineHeight_ - trackLineHeight_ - 2) / 2; lcenter_ = chanHeight_ / 2 + trackLineHeight_; rcenter_ = lcenter_ + timeLineHeight_ + chanHeight_; trackLineY_ = trackLineHeight_ - 1; timeLineY_ = chanHeight_ + timeLineHeight_ + trackLineHeight_; timeTickWidth_ = ((metrics.get_approximate_digit_width() / Pango::SCALE) * 13) + 3; sampleStartX_ = 10; sampleEndX_ = width_ - 10; sampleWidthX_ = sampleEndX_ - sampleStartX_ + 1; if (width_ > 100 && height_ > 100) updateSamples(); return true; } bool SampleDisplay::on_draw(const Cairo::RefPtr<Cairo::Context>& cr) { if (!pixmap_) return true; cr->save(); cr->set_antialias(Cairo::ANTIALIAS_NONE); Gdk::Cairo::set_source_pixbuf(cr, pixmap_, 0, 0); cr->paint(); if (drawCursor_) { cr->set_line_width(1.0); Gdk::Cairo::set_source_color(cr, cursorColor_); draw_line(cr, cursorX_, trackLineY_, cursorX_, height_ - 1); } drawMarker(cr); drawSelection(cr); cr->restore(); return true; } bool SampleDisplay::handleButtonPressEvent(GdkEventButton *event) { gint x = (gint) event->x; gint y = (gint) event->y; dragMode_ = DRAG_NONE; // e.g. if audio is playing if (cursorControlExtern_) return true; if (event->button == 1 && x >= sampleStartX_ && x <= sampleEndX_) { if (y > trackLineY_) { dragMode_ = DRAG_SAMPLE_MARKER; selectionStart_ = x; selectionEnd_= x; } else { if ((pickedTrackMarker_ = trackManager_->pick(x - sampleStartX_ + 4, &dragStopMin_, &dragStopMax_)) != NULL) { dragMode_ = DRAG_TRACK_MARKER; dragStart_ = dragEnd_ = x; dragLastX_ = -1; dragStopMin_ += sampleStartX_; dragStopMax_ += sampleStartX_; } } } return true; } bool SampleDisplay::handleButtonReleaseEvent(GdkEventButton *event) { gint x = (gint) event->x; if (cursorControlExtern_) return false; if (x < sampleStartX_) { x = sampleStartX_; } else if (x > sampleEndX_) { x = sampleEndX_; } if (event->button == 1 && dragMode_ != DRAG_NONE) { if (dragMode_ == DRAG_SAMPLE_MARKER) { if (selectionStart_ - x >= -5 && selectionStart_ - x <= 5) { selectionSet_ = false; selectionCleared(); markerSet(pixel2sample(selectionStart_)); } else { selectionSet_ = true; selectionEnd_ = x; if (selectionStart_ > selectionEnd_) { std::swap(selectionStart_, selectionEnd_); } selectionStartSample_ = pixel2sample(selectionStart_); selectionEndSample_ = pixel2sample(selectionEnd_); selectionSet(selectionStartSample_, selectionEndSample_); } } else if (dragMode_ == DRAG_TRACK_MARKER) { if (dragStart_ - x >= -5 && dragStart_ - x <= 5) { trackManager_->select(pickedTrackMarker_); selectedTrack_ = pickedTrackMarker_->trackNr; selectedIndex_ = pickedTrackMarker_->indexNr; trackMarkSelected(pickedTrackMarker_->track, selectedTrack_, selectedIndex_); } else { selectedTrack_ = pickedTrackMarker_->trackNr; selectedIndex_ = pickedTrackMarker_->indexNr; trackMarkMoved(pickedTrackMarker_->track, selectedTrack_, selectedIndex_, pixel2sample(x)); } pickedTrackMarker_ = NULL; } dragMode_ = DRAG_NONE; drawCursor(x); queue_draw(); } return true; } bool SampleDisplay::handleMotionNotifyEvent(GdkEventMotion *event) { gint x, y; GdkModifierType state; if (cursorControlExtern_) return TRUE; if (event->is_hint) { gdk_window_get_device_position(event->window, event->device, &x, &y, &state); } else { x = (gint) event->x; y = (gint) event->y; state = (GdkModifierType) event->state; } if (dragMode_ == DRAG_SAMPLE_MARKER) { // to delete previous selection queue_draw_area(std::min(selectionEnd_, selectionStart_) - 1, 0, abs(selectionEnd_ - selectionStart_) + 3, height_); // restrict x to samples x = std::max(x, sampleStartX_); x = std::min(x, sampleEndX_); selectionEnd_ = x; // to draw new selection queue_draw_area(std::min(selectionEnd_, selectionStart_) - 1, 0, abs(selectionEnd_ - selectionStart_) + 3, height_); } else if (dragMode_ == DRAG_TRACK_MARKER) { x = std::max(x, dragStopMin_); x = std::min(x, dragStopMax_); if (dragLastX_ > 0) { queue_draw_area(dragLastX_ - 4, trackLineY_ - trackLineHeight_, trackMarkerWidth_, trackLineHeight_); } dragLastX_ = x; } drawCursor(x); return TRUE; } void SampleDisplay::drawSelection(const Cairo::RefPtr<Cairo::Context>& cr) { if (dragMode_ == DRAG_SAMPLE_MARKER) { int xstart = std::min(selectionStart_, selectionEnd_); int width = abs(selectionEnd_ - selectionStart_); cr->set_source_rgba(0.0, 0.25, 0.5, 0.5); cr->rectangle(xstart, 0, width, height_ - 1); cr->fill(); } else if (dragMode_ == DRAG_TRACK_MARKER) { drawTrackMarker(cr, 1, dragLastX_, pickedTrackMarker_->trackNr, pickedTrackMarker_->indexNr, 0, 0); } } bool SampleDisplay::handleEnterEvent(GdkEventCrossing *event) { if (cursorControlExtern_) return true; drawCursor((gint) event->x); return true; } bool SampleDisplay::handleLeaveEvent(GdkEventCrossing *event) { if (cursorControlExtern_) return true; undrawCursor(); return true; } void SampleDisplay::drawMarker(const Cairo::RefPtr<Cairo::Context>& cr) { if (markerSet_) { cr->set_line_width(1.0); Gdk::Cairo::set_source_color(cr, markerColor_); markerX_ = sample2pixel(markerSample_); if (markerX_ >= 0) draw_line(cr, markerX_, trackLineY_, markerX_, height_ - 1); } } void SampleDisplay::setMarker(unsigned long sample) { if (markerSet_) queue_draw_area(markerX_-1, 0, 3, height_); markerSample_ = sample; markerSet_ = true; } void SampleDisplay::clearMarker() { if (markerSet_) { markerSet_ = false; queue_draw_area(markerX_-1, 0, 3, height_); } } void SampleDisplay::updateSamples() { if (tocEdit_ == NULL) return; Toc *toc = tocEdit_->toc(); Cairo::RefPtr<Cairo::ImageSurface> imSur = Cairo::ImageSurface::create( Cairo::FORMAT_RGB24, width_, height_); Cairo::RefPtr<Cairo::Context> cr = Cairo::Context::create(imSur); gint halfHeight = chanHeight_ / 2; cr->set_source_rgb(1.0, 1.0, 1.0); cr->paint(); cr->translate(0.5, 0.5); cr->set_line_width(1.0); cr->set_antialias(Cairo::ANTIALIAS_NONE); long res = (maxSample_ - minSample_ + 1) / sampleWidthX_; long bres = res / tocEdit_->sampleManager()->blocking(); gint i; double pos; long j; unsigned long s; short lnegsum, lpossum, rnegsum, rpossum; gint regionStart = -1; gint regionEnd = -1; int regionActive = 0; if (regionSet_) { if (regionStartSample_ <= maxSample_ && regionEndSample_ >= minSample_) { if (regionStartSample_ > minSample_) regionStart = sample2pixel(regionStartSample_); else regionStart = sampleStartX_; if (regionEndSample_ < maxSample_) regionEnd = sample2pixel(regionEndSample_); else regionEnd = sampleEndX_; } if (regionStart >= 0 && regionEnd >= regionStart) { Gdk::Cairo::set_source_color(cr, selectionBackgroundColor_); cr->rectangle(regionStart, lcenter_ - halfHeight, regionEnd - regionStart + 1, chanHeight_); cr->fill(); cr->rectangle(regionStart, rcenter_ - halfHeight, regionEnd - regionStart + 1, chanHeight_); cr->fill(); } } Gdk::Cairo::set_source_color(cr, sampleColor_); if (bres > 0) { for (s = minSample_, i = sampleStartX_; s < maxSample_ && i <= sampleEndX_; s += res, i++) { lnegsum = lpossum = rnegsum = rpossum = 0; if (regionStart != -1 && i >= regionStart && regionActive == 0) { regionActive = 1; Gdk::Cairo::set_source_color(cr, markerColor_); } else if (regionActive == 1 && i > regionEnd) { regionActive = 2; Gdk::Cairo::set_source_color(cr, sampleColor_); } tocEdit_->sampleManager()->getPeak(s, s + res, &lnegsum, &lpossum, &rnegsum, &rpossum); pos = double(lnegsum) * halfHeight; pos /= SHRT_MAX; if (pos != 0) draw_line(cr, i, lcenter_, i, lcenter_ - (gint) pos); pos = double(lpossum) * halfHeight; pos /= SHRT_MAX; if (pos != 0) draw_line(cr, i, lcenter_, i, lcenter_ - (gint) pos); pos = double(rnegsum) * halfHeight; pos /= SHRT_MAX; if (pos != 0) draw_line(cr, i, rcenter_, i, rcenter_ - (gint) pos); pos = double(rpossum) * halfHeight; pos /= SHRT_MAX; if (pos != 0) draw_line(cr, i, rcenter_, i, rcenter_ - (gint) pos); } } else if (maxSample_ > 0 && res >= 1) { TocReader reader(toc); if (reader.openData() == 0) { Sample *sampleBuf = new Sample[tocEdit_->sampleManager()->blocking()]; double dres = double(maxSample_ - minSample_ + 1) / double(sampleWidthX_); double ds; for (ds = minSample_, i = sampleStartX_; ds < maxSample_ && i <= sampleEndX_; ds += dres, i++) { lnegsum = lpossum = rnegsum = rpossum = 0; if (reader.seekSample((long) ds) == 0 && reader.readSamples(sampleBuf, res) == res) { for (j = 0; j < res; j++) { if (sampleBuf[j].left() < lnegsum) lnegsum = sampleBuf[j].left(); if (sampleBuf[j].left() > lpossum) lpossum = sampleBuf[j].left(); if (sampleBuf[j].right() < rnegsum) rnegsum = sampleBuf[j].right(); if (sampleBuf[j].right() > rpossum) rpossum = sampleBuf[j].right(); } } if (regionStart != -1 && i >= regionStart && regionActive == 0) { regionActive = 1; Gdk::Cairo::set_source_color(cr, markerColor_); } else if (regionActive == 1 && i > regionEnd) { regionActive = 2; Gdk::Cairo::set_source_color(cr, sampleColor_); } pos = double(lnegsum) * halfHeight; pos /= SHRT_MAX; if (pos != 0) draw_line(cr, i, lcenter_, i, lcenter_ - (gint) pos); pos = double(lpossum) * halfHeight; pos /= SHRT_MAX; if (pos != 0) draw_line(cr, i, lcenter_, i, lcenter_ - (gint) pos); pos = double(rnegsum) * halfHeight; pos /= SHRT_MAX; if (pos != 0) draw_line(cr, i, rcenter_, i, rcenter_ - (gint) pos); pos = double(rpossum) * halfHeight; pos /= SHRT_MAX; if (pos != 0) draw_line(cr, i, rcenter_, i, rcenter_ - (gint) pos); } delete[] sampleBuf; reader.closeData(); } } else if (toc != NULL && maxSample_ > minSample_ + 1) { TocReader reader(toc); if (reader.openData() == 0) { long len = maxSample_ - minSample_ + 1; Sample *sampleBuf = new Sample[len]; double pres = double(sampleWidthX_ - 1) / double(len - 1); double di; gint pos1; gint lastPosLeft, lastPosRight; if (reader.seekSample(minSample_) == 0 && reader.readSamples(sampleBuf, len) == len) { for (j = 1, di = sampleStartX_ + pres; j < len && di < sampleEndX_ + 1; j++, di += pres) { if (regionStart != -1 && regionActive == 0 && minSample_ + j - 1 >= regionStartSample_ && minSample_ + j <= regionEndSample_) { regionActive = 1; Gdk::Cairo::set_source_color(cr, markerColor_); } else if (regionActive == 1 && minSample_ + j > regionEndSample_) { regionActive = 2; Gdk::Cairo::set_source_color(cr, sampleColor_); } pos = sampleBuf[j - 1].left() * halfHeight; pos /= SHRT_MAX; pos1 = sampleBuf[j].left() * halfHeight; pos1 /= SHRT_MAX; lastPosLeft = pos1; if (pos != 0 || pos1 != 0) draw_line(cr, long(di - pres), lcenter_ - (gint) pos, long(di), lcenter_ - pos1); pos = sampleBuf[j - 1].right() * halfHeight; pos /= SHRT_MAX; pos1 = sampleBuf[j].right() * halfHeight; pos1 /= SHRT_MAX; lastPosRight = pos1; if (pos != 0 || pos1 != 0) draw_line(cr, long(di - pres), rcenter_ - (gint) pos, long(di), rcenter_ - pos1); } if (0 && (gint) di < sampleEndX_) { pos = sampleBuf[len - 1].left() * halfHeight; pos /= SHRT_MAX; if (pos != 0 || lastPosLeft != 0) draw_line(cr, long(di), lcenter_ - lastPosLeft, sampleEndX_, lcenter_ - (gint) pos); pos = sampleBuf[len - 1].right() * halfHeight; pos /= SHRT_MAX; if (pos != 0 || lastPosRight != 0) draw_line(cr, long(di), rcenter_ - lastPosRight, sampleEndX_, rcenter_ - (gint) pos); } } delete[] sampleBuf; } } Gdk::Cairo::set_source_color(cr, middleLineColor_); draw_line(cr, sampleStartX_, lcenter_, sampleEndX_, lcenter_); draw_line(cr, sampleStartX_, rcenter_, sampleEndX_, rcenter_); cr->set_source_rgb(0.0, 0.0, 0.0); draw_line(cr, sampleStartX_ - 1, lcenter_ - halfHeight, sampleEndX_ + 1, lcenter_ - halfHeight); draw_line(cr, sampleStartX_ - 1, lcenter_ + halfHeight, sampleEndX_ + 1, lcenter_ + halfHeight); draw_line(cr, sampleStartX_ - 1, lcenter_ - halfHeight, sampleStartX_ - 1, lcenter_ + halfHeight); draw_line(cr, sampleEndX_ + 1, lcenter_ - halfHeight, sampleEndX_ + 1, lcenter_ + halfHeight); draw_line(cr, sampleStartX_ - 1, rcenter_ - halfHeight, sampleEndX_ + 1, rcenter_ - halfHeight); draw_line(cr, sampleStartX_ - 1, rcenter_ + halfHeight, sampleEndX_ + 1, rcenter_ + halfHeight); draw_line(cr, sampleStartX_ - 1, rcenter_ + halfHeight, sampleStartX_ - 1, rcenter_ - halfHeight); draw_line(cr, sampleEndX_ + 1, rcenter_ + halfHeight, sampleEndX_ + 1, rcenter_ - halfHeight); drawTimeLine(cr); trackManager_->update(toc, minSample_, maxSample_, sampleWidthX_); if (selectedTrack_ > 0) { trackManager_->select(selectedTrack_, selectedIndex_); } drawTrackLine(cr); pixmap_ = Gdk::Pixbuf::create(imSur, 0, 0, width_, height_); } void SampleDisplay::drawCursor(gint x) { if (x < sampleStartX_ || x > sampleEndX_) return; drawCursor_ = true; if (cursorX_ != x) { queue_draw_area(cursorX_-1, 0, 3, height_); cursorX_ = x; queue_draw_area(x-1, 0, 3, height_); } if (cursorControlExtern_ == false) cursorMoved(pixel2sample(x)); } void SampleDisplay::undrawCursor() { if (drawCursor_) { queue_draw_area(cursorX_-1, 0, 3, height_); drawCursor_ = false; } } void SampleDisplay::drawTimeTick(const Cairo::RefPtr<Cairo::Context>& cr, gint x, gint y, unsigned long sample) { char buf[50]; if (!pixmap_) return; unsigned long min = sample / (60 * 44100); sample %= 60 * 44100; unsigned long sec = sample / 44100; sample %= 44100; unsigned long frame = sample / 588; sample %= 588; snprintf(buf, sizeof(buf),"%lu:%02lu:%02lu.%03lu", min, sec, frame, sample); cr->set_source_rgb(0.0, 0.0, 0.0); draw_line(cr, x, y - timeLineHeight_, x, y); Glib::RefPtr<Pango::Layout> playout = create_pango_layout(buf); cr->move_to(x + 3, y - timeLineHeight_ + 1); playout->show_in_cairo_context(cr); } void SampleDisplay::drawTimeLine(const Cairo::RefPtr<Cairo::Context>& cr) { if (tocEdit_ == NULL) return; Toc *toc = tocEdit_->toc(); if (toc->length().lba() == 0) return; gint sep = timeTickWidth_ + timeTickSep_; unsigned long maxNofTicks = (sampleWidthX_ + timeTickSep_) / sep; gint x; unsigned long len = maxSample_ - minSample_ + 1; unsigned long dt; unsigned long dtx; unsigned long startSample; unsigned long s; if ((s = len / (60 * 44100)) > 1) { dt = 60 * 44100; } else if ((s = len / 44100) > 1) { dt = 44100; } else if ((s = len / 588) > 1) { dt = 588; } else { dt = 1; s = len; } if (s > maxNofTicks) { dtx = s / maxNofTicks; if (s % maxNofTicks != 0) dtx++; dtx *= dt; } else { dtx = dt; } if (dt > 1) { if (minSample_ % dt == 0) { startSample = minSample_; } else { startSample = minSample_ / dt; startSample = startSample * dt + dt; } } else { startSample = minSample_; } for (s = startSample; s < maxSample_; s += dtx) { x = sample2pixel(s); if (x + timeTickWidth_ <= sampleEndX_) drawTimeTick(cr, x, timeLineY_, s); } } // Draws track marker. // mode: 0: draw on 'pixmap_' // 1: draw on window void SampleDisplay::drawTrackMarker(const Cairo::RefPtr<Cairo::Context>& cr, int mode, gint x, int trackNr, int indexNr, int selected, int extend) { char buf[20]; snprintf(buf, sizeof(buf),"%d.%d", trackNr, indexNr); Glib::RefPtr<Gdk::Pixbuf> marker; if (extend) { marker = (indexNr == 1 ? trackExtendPixmap_ : indexExtendPixmap_); } else { if (selected) marker = ( indexNr == 1 ? trackMarkerSelectedPixmap_ : indexMarkerSelectedPixmap_); else marker = (indexNr == 1 ? trackMarkerPixmap_ : indexMarkerPixmap_); } if (mode == 0) { if (selected) Gdk::Cairo::set_source_color(cr, markerColor_); else cr->set_source_rgb(1.0, 1.0, 1.0); cr->rectangle(x - 4, trackLineY_ - trackLineHeight_, trackMarkerWidth_, trackLineHeight_); cr->fill(); } cr->set_source_rgb(0.0, 0.0, 0.0); cr->save(); Gdk::Cairo::set_source_pixbuf(cr, marker, x - 4, trackLineY_ - TRACK_MARKER_XPM_HEIGHT); cr->rectangle(x - 4, trackLineY_ - TRACK_MARKER_XPM_HEIGHT, TRACK_MARKER_XPM_WIDTH, TRACK_MARKER_XPM_HEIGHT); cr->clip(); cr->paint(); cr->restore(); Glib::RefPtr<Pango::Layout> playout = create_pango_layout(buf); cr->move_to(x + TRACK_MARKER_XPM_WIDTH / 2 + 2, trackLineY_ - trackLineHeight_ + 2); playout->show_in_cairo_context(cr); } void SampleDisplay::drawTrackLine(const Cairo::RefPtr<Cairo::Context>& cr) { const TrackManager::Entry *run; const TrackManager::Entry *selected = NULL; for (run = trackManager_->first(); run != NULL; run = trackManager_->next()) { if (run->selected != 0 && run->extend == 0) { selected = run; } else if (run->indexNr != 1 || run->extend != 0) { drawTrackMarker(cr, 0, sampleStartX_ + run->xpos, run->trackNr, run->indexNr, 0, run->extend); } } for (run = trackManager_->first(); run != NULL; run = trackManager_->next()) { if (run->indexNr == 1 && run->selected == 0 && run->extend == 0) { drawTrackMarker(cr, 0, sampleStartX_ + run->xpos, run->trackNr, run->indexNr, 0, run->extend); } } if (selected != NULL) drawTrackMarker(cr, 0, sampleStartX_ + selected->xpos, selected->trackNr, selected->indexNr, 1, 0); } void SampleDisplay::updateTrackMarks() { if (tocEdit_ == NULL) return; Toc *toc = tocEdit_->toc(); trackManager_->update(toc, minSample_, maxSample_, sampleWidthX_); if (selectedTrack_ > 0) { trackManager_->select(selectedTrack_, selectedIndex_); } updateSamples(); queue_draw_area(0, 0, width_, height_); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/SampleDisplay.h�����������������������������������������������������0000664�0000000�0000000�00000011652�15114537466�0021574�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __SAMPLE_DISPLAY_H #define __SAMPLE_DISPLAY_H #include <gtkmm.h> #include <gdkmm.h> #include <pangomm.h> #include <gtk/gtk.h> #include "TrackManager.h" class Toc; class Sample; class TocEdit; class SampleDisplay : public Gtk::DrawingArea { public: SampleDisplay(); void setTocEdit(TocEdit *); bool getSelection(unsigned long* start, unsigned long* end); void setSelectedTrackMarker(int trackNr, int indexNr); void setMarker(unsigned long sample); void clearMarker(); int getMarker(unsigned long *); void setView(unsigned long start, unsigned long end); void getView(unsigned long *start, unsigned long *end); void setRegion(unsigned long start, unsigned long end); int getRegion(unsigned long *start, unsigned long *end); void clearRegion(); Glib::RefPtr<Gtk::Adjustment> getAdjustment() { return adjustment_; } void updateTrackMarks(); void setCursor(int, unsigned long); void updateToc(unsigned long, unsigned long); sigc::signal1<void, unsigned long> markerSet; sigc::signal1<void, unsigned long> cursorMoved; sigc::signal2<void, unsigned long, unsigned long> selectionSet; sigc::signal0<void> selectionCleared; sigc::signal3<void, const Track *, int, int> trackMarkSelected; sigc::signal4<void, const Track *, int, int, unsigned long> trackMarkMoved; sigc::signal2<void, unsigned long, unsigned long> viewModified; protected: bool handleConfigureEvent(GdkEventConfigure *); bool handleMotionNotifyEvent(GdkEventMotion *event); bool handleButtonPressEvent(GdkEventButton*); bool handleButtonReleaseEvent(GdkEventButton*); bool handleEnterEvent(GdkEventCrossing*); bool handleLeaveEvent(GdkEventCrossing*); virtual bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr); private: enum DragMode { DRAG_NONE, DRAG_SAMPLE_MARKER, DRAG_TRACK_MARKER }; Glib::RefPtr<Gtk::Adjustment> adjustment_; Glib::RefPtr<Gdk::Pixbuf> pixmap_; Glib::RefPtr<Gdk::Pixbuf> trackMarkerPixmap_; Glib::RefPtr<Gdk::Pixbuf> indexMarkerPixmap_; Glib::RefPtr<Gdk::Pixbuf> trackMarkerSelectedPixmap_; Glib::RefPtr<Gdk::Pixbuf> indexMarkerSelectedPixmap_; Glib::RefPtr<Gdk::Pixbuf> trackExtendPixmap_; Glib::RefPtr<Gdk::Pixbuf> indexExtendPixmap_; Gdk::Color sampleColor_; Gdk::Color middleLineColor_; Gdk::Color cursorColor_; Gdk::Color markerColor_; Gdk::Color selectionBackgroundColor_; gint width_; gint height_; gint timeLineHeight_; gint timeLineY_; gint timeTickWidth_; gint timeTickSep_; gint sampleStartX_; gint sampleEndX_; gint sampleWidthX_; gint trackLineHeight_; gint trackLineY_; gint trackMarkerWidth_; const TrackManager::Entry *pickedTrackMarker_; gint chanSep_; gint chanHeight_; gint lcenter_; gint rcenter_; TrackManager *trackManager_; TocEdit *tocEdit_; unsigned long minSample_; unsigned long maxSample_; unsigned long resolution_; bool drawCursor_; gint cursorX_; bool cursorControlExtern_; bool markerSet_; gint markerX_; unsigned long markerSample_; bool selectionSet_; unsigned long selectionStartSample_; unsigned long selectionEndSample_; gint selectionStart_; gint selectionEnd_; bool regionSet_; unsigned long regionStartSample_; unsigned long regionEndSample_; int selectedTrack_; int selectedIndex_; DragMode dragMode_; gint dragStart_, dragEnd_; gint dragStopMin_, dragStopMax_; gint dragLastX_; void scrollTo(); void readSamples(long startBlock, long endBlock); void updateSamples(); void drawCursor(gint); void undrawCursor(); void getColor(const char *, Gdk::Color *); unsigned long pixel2sample(gint x); gint sample2pixel(unsigned long); void drawMarker(const Cairo::RefPtr<Cairo::Context>& cr); void removeMarker(); void drawTimeTick(const Cairo::RefPtr<Cairo::Context>& cr, gint x, gint y, unsigned long sample); void drawTimeLine(const Cairo::RefPtr<Cairo::Context>& cr); void drawTrackMarker(const Cairo::RefPtr<Cairo::Context>& cr, int mode, gint x, int trackNr, int indexNr, int selected, int extend); void drawTrackLine(const Cairo::RefPtr<Cairo::Context>& cr); void drawSelection(const Cairo::RefPtr<Cairo::Context>& cr); }; #endif ��������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/SampleManager.cc����������������������������������������������������0000664�0000000�0000000�00000025240�15114537466�0021675�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #include <stdio.h> #include <limits.h> #include <math.h> #include <assert.h> #include <gtkmm.h> #include <gtk/gtk.h> #include "SampleManager.h" #include "TocEdit.h" #include "guiUpdate.h" #include "Toc.h" #include "util.h" #include "log.h" #include "TrackDataScrap.h" class SampleManagerImpl : public sigc::trackable { public: SampleManagerImpl(unsigned long); ~SampleManagerImpl(); unsigned long blocking_; TocEdit *tocEdit_; TocReader tocReader_; short *leftNegSamples_; short *leftPosSamples_; short *rightNegSamples_; short *rightPosSamples_; long samplesSize_; long blocks_; unsigned long slength_; long chunk_; Sample *block_; long actBlock_; long endBlock_; long burstBlock_; const char* curFilename_; unsigned long length_; gfloat percent_; gfloat percentStep_; void getPeak(unsigned long start, unsigned long end, short *leftNeg, short *leftPos, short *rightNeg, short *rightPos); int scanToc(unsigned long start, unsigned long end, bool blocking); int readSamples(); void reallocSamples(unsigned long maxSample); void removeSamples(unsigned long start, unsigned long end, TrackDataScrap *); void insertSamples(unsigned long pos, unsigned long len, const TrackDataScrap *); }; SampleManager::SampleManager(unsigned long blocking) { impl_ = new SampleManagerImpl(blocking); } SampleManager::~SampleManager() { delete impl_; impl_ = NULL; } unsigned long SampleManager::blocking() const { return impl_->blocking_; } void SampleManager::setTocEdit(TocEdit *t) { impl_->tocEdit_ = t; impl_->tocReader_.init(t->toc()); impl_->blocks_ = 0; } int SampleManager::scanToc(unsigned long start, unsigned long end, bool blocking) { return impl_->scanToc(start, end, blocking); } int SampleManager::readSamples() { return impl_->readSamples(); } void SampleManager::getPeak(unsigned long start, unsigned long end, short *leftNeg, short *leftPos, short *rightNeg, short *rightPos) { impl_->getPeak(start, end, leftNeg, leftPos, rightNeg, rightPos); } void SampleManager::removeSamples(unsigned long start, unsigned long end, TrackDataScrap *scrap) { impl_->removeSamples(start, end, scrap); } void SampleManager::insertSamples(unsigned long pos, unsigned long len, const TrackDataScrap *scrap) { impl_->insertSamples(pos, len, scrap); } SampleManagerImpl::SampleManagerImpl(unsigned long blocking) : tocReader_(NULL) { blocking_ = blocking; tocEdit_ = NULL; leftNegSamples_ = leftPosSamples_ = NULL; rightNegSamples_ = rightPosSamples_ = NULL; samplesSize_ = 0; blocks_ = 0; slength_ = 0; block_ = new Sample[blocking_]; actBlock_ = endBlock_ = burstBlock_ = 0; // allocate space in chunks of 40 minutes chunk_ = 40 * 60 * 75 * 588 / blocking; curFilename_ = NULL; length_ = 0; percent_ = 0.0; percentStep_ = 0.0; } SampleManagerImpl::~SampleManagerImpl() { delete[] block_; delete[] leftNegSamples_; delete[] leftPosSamples_; delete[] rightNegSamples_; delete[] rightPosSamples_; tocEdit_ = NULL; } void SampleManagerImpl::getPeak(unsigned long start, unsigned long end, short *leftNeg, short *leftPos, short *rightNeg, short *rightPos) { *leftNeg = *leftPos = 0; *rightNeg = *rightPos = 0; long startBlock = start / blocking_; long endBlock = end / blocking_; long i; if (startBlock >= blocks_ || endBlock >= blocks_) return; for (i = startBlock; i <= endBlock; i++) { assert(leftNegSamples_[i] <= 0); assert(rightNegSamples_[i] <= 0); assert(leftPosSamples_[i] >= 0); assert(rightPosSamples_[i] >= 0); if (leftNegSamples_[i] < *leftNeg) *leftNeg = leftNegSamples_[i]; if (leftPosSamples_[i] > *leftPos) *leftPos = leftPosSamples_[i]; if (rightNegSamples_[i] < *rightNeg) *rightNeg = rightNegSamples_[i]; if (rightPosSamples_[i] > *rightPos) *rightPos = rightPosSamples_[i]; } } // Return values: // 0 : ok // 1 : incorrect parameters // 2 : unable to read from file int SampleManagerImpl::scanToc(unsigned long start, unsigned long end, bool blocking) { long i; const Toc *toc; actBlock_ = start / blocking_; endBlock_ = end / blocking_; curFilename_ = NULL; if (tocEdit_ == NULL || endBlock_ < actBlock_) return 1; toc = tocEdit_->toc(); length_ = toc->length().samples(); if (end >= length_) return 1; length_ -= actBlock_ * blocking_; reallocSamples(end); for (i = actBlock_; i <= endBlock_; i++) { leftNegSamples_[i] = rightNegSamples_[i] = -16000; leftPosSamples_[i] = rightPosSamples_[i] = 16000; } if (tocReader_.openData() != 0) return 2; if (tocReader_.seekSample(actBlock_ * blocking_) != 0) { tocReader_.closeData(); return 2; } long len = endBlock_ - actBlock_ + 1; if (len < 2000) { burstBlock_ = len; percentStep_ = 1.0; // withGui_ = false; } else if (len < 10000) { burstBlock_ = len / 100; percentStep_ = 0.01; // withGui_ = true; } else { burstBlock_ = 75; percentStep_ = gfloat(burstBlock_) / gfloat(len); // withGui_ = true; } if (burstBlock_ == 0) burstBlock_ = 1; percent_ = 0; if (blocking) { while (readSamples() == 0); return 0; } return 0; } // Returns: // 0 : in progress // 1 : done // -1 : read error int SampleManagerImpl::readSamples() { int j; long n; short lpossum, rpossum, lnegsum, rnegsum; int ret; long burstEnd = actBlock_ + burstBlock_; const char* cf = tocReader_.curFilename(); if (cf && cf != curFilename_) { std::string msg = "Scanning audio data \""; msg += cf; msg += "\""; tocEdit_->signalStatusMessage(msg.c_str()); curFilename_ = cf; guiUpdate(UPD_SAMPLES); } for (; actBlock_ <= endBlock_ && actBlock_ < burstEnd && length_ > 0; actBlock_++) { n = length_ > blocking_ ? blocking_ : length_; if ((ret = tocReader_.readSamples(block_, n)) == n) { lpossum = lnegsum = rpossum = rnegsum = 0; for (j = 0; j < n; j++) { short d = block_[j].left(); if (d > lpossum) lpossum = d; if (d < lnegsum) lnegsum = d; d = block_[j].right(); if (d > rpossum) rpossum = d; if (d < rnegsum) rnegsum = d; } leftNegSamples_[actBlock_] = lnegsum; leftPosSamples_[actBlock_] = lpossum; rightNegSamples_[actBlock_] = rnegsum; rightPosSamples_[actBlock_] = rpossum; } else { log_message(-2, "Cannot read audio data: %ld - %ld.", n, ret); tocReader_.closeData(); tocEdit_->signalProgressFraction(0.0); return -1; } length_ -= n; } if (actBlock_ >= endBlock_ && actBlock_ < burstEnd) { tocReader_.closeData(); tocEdit_->signalProgressFraction(0.0); return 1; } percent_ += percentStep_; if (percent_ > 1.0) percent_ = 1.0; tocEdit_->signalProgressFraction(percent_); return 0; } void SampleManagerImpl::reallocSamples(unsigned long maxSample) { long i; long maxBlock = (maxSample / blocking_) + 1; if (maxSample >= slength_) slength_ = maxSample + 1; if (maxBlock > blocks_) blocks_ = maxBlock; if (blocks_ > samplesSize_) { long newSize = samplesSize_ + chunk_; while (newSize < blocks_) newSize += chunk_; short *newLeftNeg = new short[newSize]; short *newLeftPos = new short[newSize]; short *newRightNeg = new short[newSize]; short *newRightPos = new short[newSize]; for (i = 0; i < samplesSize_; i++) { newLeftNeg[i] = leftNegSamples_[i]; newLeftPos[i] = leftPosSamples_[i]; newRightNeg[i] = rightNegSamples_[i]; newRightPos[i] = rightPosSamples_[i]; } samplesSize_ = newSize; delete[] leftNegSamples_; delete[] leftPosSamples_; delete[] rightNegSamples_; delete[] rightPosSamples_; leftNegSamples_ = newLeftNeg; leftPosSamples_ = newLeftPos; rightNegSamples_ = newRightNeg; rightPosSamples_ = newRightPos; } } void SampleManagerImpl::removeSamples(unsigned long start, unsigned long end, TrackDataScrap *scrap) { long i; long bstart; long oldBlocks = blocks_; long blen; unsigned long slen; if (start > end || end >= slength_) return; slen = end - start + 1; slength_ -= slen; if (slength_ == 0) { blocks_ = 0; return; } blocks_ = ((slength_ - 1) / blocking_) + 1; blen = oldBlocks - blocks_; bstart = start / blocking_; if (scrap != NULL) scrap->setPeaks(blen, &(leftNegSamples_[bstart]), &(leftPosSamples_[bstart]), &(rightNegSamples_[bstart]), &(rightPosSamples_[bstart])); if (blen > 0) { for (i = bstart; i < blocks_; i++) { leftNegSamples_[i] = leftNegSamples_[i + blen]; leftPosSamples_[i] = leftPosSamples_[i + blen]; rightNegSamples_[i] = rightNegSamples_[i + blen]; rightPosSamples_[i] = rightPosSamples_[i + blen] ; } } } void SampleManagerImpl::insertSamples(unsigned long pos, unsigned long len, const TrackDataScrap *scrap) { long blen; long bpos; long oldBlocks; long i; if (len == 0) return; bpos = pos / blocking_; if (bpos > blocks_) bpos = blocks_; oldBlocks = blocks_; reallocSamples(slength_ + (len - 1)); blen = blocks_ - oldBlocks; if (blen > 0) { for (i = blocks_ - 1; i >= bpos + blen; i--) { leftNegSamples_[i] = leftNegSamples_[i - blen]; leftPosSamples_[i] = leftPosSamples_[i - blen]; rightNegSamples_[i] = rightNegSamples_[i - blen]; rightPosSamples_[i] = rightPosSamples_[i - blen] ; } // initialize the new region for (i = bpos; i < bpos + blen; i++) { leftNegSamples_[i] = -16000; leftPosSamples_[i] = 16000; rightNegSamples_[i] = -16000; rightPosSamples_[i] = 16000; } if (scrap != NULL) scrap->getPeaks(blen, &(leftNegSamples_[bpos]), &(leftPosSamples_[bpos]), &(rightNegSamples_[bpos]), &(rightPosSamples_[bpos])); } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/SampleManager.h�����������������������������������������������������0000664�0000000�0000000�00000003045�15114537466�0021536�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __SAMPLE_MANAGER_H #define __SAMPLE_MANAGER_H #include <gtkmm.h> class TocEdit; class TrackDataScrap; class SampleManager { public: SampleManager(unsigned long blocking); ~SampleManager(); void setTocEdit(TocEdit *); unsigned long blocking() const; int scanToc(unsigned long start, unsigned long end, bool blocking = false); void getPeak(unsigned long start, unsigned long end, short *leftNeg, short *leftPos, short *rightNeg, short *rightPos); void removeSamples(unsigned long start, unsigned long end, TrackDataScrap *); void insertSamples(unsigned long pos, unsigned long len, const TrackDataScrap *); int readSamples(); private: class SampleManagerImpl *impl_; }; #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/Settings.cc���������������������������������������������������������0000664�0000000�0000000�00000002436�15114537466�0020763�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #include "Settings.h" const char *SET_CDRDAO_PATH = "/GnomeCDMaster/cdrdao/path=cdrdao"; const char *SET_RECORD_EJECT_WARNING = "/GnomeCDMaster/record/ejectWarning=true"; const char *SET_RECORD_RELOAD_WARNING = "/GnomeCDMaster/record/reloadWarning=true"; const char *SET_DUPLICATE_ONTHEFLY_WARNING = "/GnomeCDMaster/duplicate/ontheflyWarning=true"; const char *SET_SECTION_DEVICES = "/GnomeCDMaster/devices/"; const char *SET_DEVICES_NUM = "/GnomeCDMaster/devices/count=0"; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/Settings.h����������������������������������������������������������0000664�0000000�0000000�00000003407�15114537466�0020624�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2000 Andreas Mueller <mueller@daneb.ping.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 * (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. */ /* * $Log: Settings.h,v $ * Revision 1.4 2004/02/12 01:13:32 poolshark * Merge from gnome2 branch * * Revision 1.3.6.1 2004/01/05 00:34:03 poolshark * First checking of gnome2 port * * Revision 1.1.1.1 2003/12/09 05:32:28 denis * Fooya * * Revision 1.3 2001/08/18 19:15:43 llanero * added SET_DUPLICATE_ONTHEFLY_WARNING * * Revision 1.2 2000/05/01 18:15:00 andreasm * Switch to gnome-config settings. * Adapted Message Box to Gnome look, unfortunately the Gnome::MessageBox is * not implemented in gnome--, yet. * * Revision 1.1.1.1 2000/02/05 01:38:51 llanero * Uploaded cdrdao 1.1.3 with pre10 patch applied. * */ #ifndef __SETTINGS_H__ #define __SETTINGS_H__ extern const char *SET_CDRDAO_PATH; extern const char *SET_RECORD_EJECT_WARNING; extern const char *SET_RECORD_RELOAD_WARNING; extern const char *SET_DUPLICATE_ONTHEFLY_WARNING; extern const char *SET_SECTION_DEVICES; extern const char *SET_DEVICES_NUM; #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/SoundIF-ao.cc�������������������������������������������������������0000664�0000000�0000000�00000004511�15114537466�0021063�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #include <ao/ao.h> #include "SoundIF.h" #include "Sample.h" #include "util.h" class SoundIFImpl { public: int driverId; ao_device* device; ao_sample_format format; }; SoundIF::SoundIF() { ao_initialize(); impl_ = new SoundIFImpl; impl_->driverId = ao_default_driver_id(); impl_->format.bits = 16; impl_->format.rate = 44100; impl_->format.channels = 2; impl_->format.byte_format = AO_FMT_NATIVE; } SoundIF::~SoundIF() { if (impl_) delete impl_; impl_ = NULL; end(); ao_shutdown(); } // Initializes sound interface. // return: 0: OK // 1: sounde device not found // 2: cannot setup sound device int SoundIF::init() { return 0; } // Acquires sound device for playing. // return 0: OK // 1: error occured int SoundIF::start() { impl_->device = ao_open_live(impl_->driverId, &(impl_->format), NULL); if (!impl_->device) return 1; return 0; } // Playes given sample buffer. // return: 0: OK // 1: error occured int SoundIF::play(Sample *sbuf, long nofSamples) { if (!impl_->device) return 1; swapSamples(sbuf, nofSamples); int ret = ao_play(impl_->device, (char*)sbuf, nofSamples * sizeof(Sample)); if (ret == 0) return 1; return 0; } unsigned long SoundIF::getDelay() { // Unfortunately, ao doesn't have a getDelay() API, so let's return // a realistic audio buffering value. return 10000; } // Finishs playing, sound device is released. void SoundIF::end() { ao_close(impl_->device); impl_->device = NULL; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/SoundIF-linux.cc����������������������������������������������������0000664�0000000�0000000�00000010020�15114537466�0021613�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998 Andreas Mueller <mueller@daneb.ping.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 * (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. */ # if defined(__FreeBSD__) #include <sys/soundcard.h> # if !defined(SNDCTL_DSP_CHANNELS) # define SNDCTL_DSP_CHANNELS SOUND_PCM_WRITE_CHANNELS # endif # else #include <linux/soundcard.h> # endif #include <stdio.h> #include <gtkmm.h> #include <sys/ioctl.h> #include <sys/types.h> #include <fcntl.h> #include "SoundIF.h" #include "Sample.h" #include "util.h" class SoundIFImpl { public: SoundIFImpl() { dspFd_ = -1; } int setupDevice(); int openDevice(); void closeDevice(); int dspFd_; // sound device }; SoundIF::SoundIF() { impl_ = new SoundIFImpl; } SoundIF::~SoundIF() { end(); delete impl_; impl_ = NULL; } // Initializes sound interface. // return: 0: OK // 1: sounde device not found // 2: cannot setup sound device int SoundIF::init() { if (impl_->openDevice() != 0) return 1; if (impl_->setupDevice() != 0) { impl_->closeDevice(); return 2; } impl_->closeDevice(); return 0; } // Acquires sound device for playing. // return 0: OK // 1: error occured int SoundIF::start() { if (impl_->dspFd_ >= 0) return 0; // already opened if (impl_->openDevice() != 0) return 1; if (impl_->setupDevice() != 0) { impl_->closeDevice(); return 1; } return 0; } // Playes given sample buffer. // return: 0: OK // 1: error occured int SoundIF::play(Sample *sbuf, long nofSamples) { if (impl_->dspFd_ < 0) return 1; swapSamples(sbuf, nofSamples); long ret; long len = nofSamples * sizeof(Sample); long nwritten = 0; char *buf = (char *)sbuf; while (len > 0) { ret = write(impl_->dspFd_, buf + nwritten, len); if (ret <= 0) return 1; nwritten += ret; len -= ret; } return 0; } unsigned long SoundIF::getDelay() { if (impl_->dspFd_ < 0) return 1; #ifdef SNDCTL_DSP_GETODELAY int delay; if (ioctl(impl_->dspFd_, SNDCTL_DSP_GETODELAY, &delay) == 0) { return delay / 4; } #endif return 0; } // Finishs playing, sound device is released. void SoundIF::end() { impl_->closeDevice(); } int SoundIFImpl::openDevice() { int flags; if (dspFd_ >= 0) return 0; // already open if ((dspFd_ = open("/dev/dsp", O_WRONLY | O_NONBLOCK)) < 0) { log_message(-1, _("Cannot open \"/dev/dsp\": %s"), strerror(errno)); return 1; } if ((flags = fcntl(dspFd_, F_GETFL)) >= 0) { flags &= ~O_NONBLOCK; fcntl(dspFd_, F_SETFL, flags); } return 0; } void SoundIFImpl::closeDevice() { if (dspFd_ >= 0) { close(dspFd_); dspFd_ = -1; } } int SoundIFImpl::setupDevice() { if (dspFd_ < 0) return 1; int val = 44100; if (ioctl(dspFd_, SNDCTL_DSP_SPEED, &val) < 0) { log_message(-1, _("Cannot set sample rate to 44100: %s"), strerror(errno)); return 1; } val = 2; if (ioctl(dspFd_, SNDCTL_DSP_CHANNELS, &val) < 0) { log_message(-1, _("Cannot setup 2 channels: %s"), strerror(errno)); return 1; } val = AFMT_S16_LE; if (ioctl(dspFd_, SNDCTL_DSP_SETFMT, &val) < 0) { log_message(-1, _("Cannot setup sound format: %s"), strerror(errno)); return 1; } if (val != AFMT_S16_LE) { log_message(-1, _("Sound device does not support " "little endian signed 16 bit samples.")); return 1; } return 0; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/SoundIF-none.cc�����������������������������������������������������0000664�0000000�0000000�00000005732�15114537466�0021431�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998 Andreas Mueller <mueller@daneb.ping.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 * (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. */ /* * $Log: SoundIF-none.cc,v $ * Revision 1.2 2004/02/12 01:13:32 poolshark * Merge from gnome2 branch * * Revision 1.1.1.1.6.1 2004/01/05 00:34:03 poolshark * First checking of gnome2 port * * Revision 1.1.1.1 2003/12/09 05:32:28 denis * Fooya * * Revision 1.1.1.1 2000/02/05 01:39:57 llanero * Uploaded cdrdao 1.1.3 with pre10 patch applied. * * Revision 1.1 1999/05/24 18:07:11 mueller * Initial revision * */ /* * Dummy sound interface for platforms that are not supported, yet. * May serve as template for new implementations. */ #include "SoundIF.h" #include "Sample.h" #include "util.h" class SoundIFImpl { public: SoundIFImpl() { dspFd_ = -1; } int setupDevice(); int openDevice(); void closeDevice(); int dspFd_; // sound device }; SoundIF::SoundIF() { impl_ = new SoundIFImpl; } SoundIF::~SoundIF() { delete impl_; impl_ = NULL; } // Initializes sound interface. // return: 0: OK // 1: sounde device not found // 2: cannot setup sound device int SoundIF::init() { if (impl_->openDevice() != 0) return 1; if (impl_->setupDevice() != 0) { impl_->closeDevice(); return 2; } impl_->closeDevice(); return 0; } // Acquires sound device for playing. // return 0: OK // 1: error occured int SoundIF::start() { if (impl_->dspFd_ >= 0) return 0; // already opened if (impl_->openDevice() != 0) return 1; if (impl_->setupDevice() != 0) { impl_->closeDevice(); return 1; } return 0; } // Playes given sample buffer. // return: 0: OK // 1: error occured int SoundIF::play(Sample *sbuf, long nofSamples) { if (impl_->dspFd_ < 0) return 1; // ... return 0; } unsigned long SoundIF::getDelay() { if (impl_->dspFd_ < 0) return 1; // ... return 0; } // Finishs playing, sound device is released. void SoundIF::end() { impl_->closeDevice(); } int SoundIFImpl::openDevice() { if (dspFd_ >= 0) return 0; // already open // ... return 1; } void SoundIFImpl::closeDevice() { if (dspFd_ >= 0) { // ... dspFd_ = -1; } } int SoundIFImpl::setupDevice() { if (dspFd_ < 0) return 1; // ... return 0; } ��������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/SoundIF-solaris.cc��������������������������������������������������0000664�0000000�0000000�00000010340�15114537466�0022135�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998, 1999 Andreas Mueller <mueller@daneb.ping.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 * (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. */ /* * $Log: SoundIF-solaris.cc,v $ * Revision 1.3 2007/12/29 12:31:54 poolshark * Moved log code into own file, renamed message call * * Revision 1.2 2004/02/12 01:13:32 poolshark * Merge from gnome2 branch * * Revision 1.1.1.1.6.2 2004/01/12 20:50:26 poolshark * Added _( and N_( intl macros * * Revision 1.1.1.1.6.1 2004/01/05 00:34:03 poolshark * First checking of gnome2 port * * Revision 1.1.1.1 2003/12/09 05:32:28 denis * Fooya * * Revision 1.1.1.1 2000/02/05 01:40:00 llanero * Uploaded cdrdao 1.1.3 with pre10 patch applied. * * Revision 1.1 1999/05/24 18:07:37 mueller * Initial revision * */ /* * Sound interface for Solaris. Thanks to Tobias Oetiker <oetiker@ee.ethz.ch>. */ #include <sys/audioio.h> #include <stdio.h> #include <assert.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> #include <sys/types.h> #include "SoundIF.h" #include "Sample.h" #include "util.h" class SoundIFImpl { public: SoundIFImpl() { dspFd_ = -1; } int setupDevice(); int openDevice(); void closeDevice(); int dspFd_; // sound device }; SoundIF::SoundIF() { impl_ = new SoundIFImpl; } SoundIF::~SoundIF() { delete impl_; impl_ = NULL; } // Initializes sound interface. // return: 0: OK // 1: sounde device not found // 2: cannot setup sound device int SoundIF::init() { if (impl_->openDevice() != 0) return 1; if (impl_->setupDevice() != 0) { impl_->closeDevice(); return 2; } impl_->closeDevice(); return 0; } // Acquires sound device for playing. // return 0: OK // 1: error occured int SoundIF::start() { if (impl_->dspFd_ >= 0) return 0; // already opened if (impl_->openDevice() != 0) return 1; if (impl_->setupDevice() != 0) { impl_->closeDevice(); return 1; } return 0; } // Playes given sample buffer. // return: 0: OK // 1: error occured int SoundIF::play(Sample *sbuf, long nofSamples) { if (impl_->dspFd_ < 0) return 1; long ret; long len = nofSamples * sizeof(Sample); long nwritten = 0; char *buf = (char *)sbuf; while (len > 0) { ret = write(impl_->dspFd_, buf + nwritten, len); if (ret <= 0) return 1; nwritten += ret; len -= ret; } return 0; } unsigned long SoundIF::getDelay() { return 0; } // Finishs playing, sound device is released. void SoundIF::end() { impl_->closeDevice(); } int SoundIFImpl::openDevice() { if (dspFd_ >= 0) return 0; // already open if ((dspFd_ = open("/dev/audio", O_WRONLY | O_NONBLOCK)) < 0) { log_message(-1, _("Cannot open \"/dev/audio\": %s"), strerror(errno)); return 1; } /* Clear the non-blocking flag */ (void) fcntl(dspFd_, F_SETFL, (fcntl(dspFd_, F_GETFL, 0) & ~(O_NDELAY | O_NONBLOCK))); return 0; } void SoundIFImpl::closeDevice() { if (dspFd_ >= 0) { close(dspFd_); dspFd_ = -1; } } int SoundIFImpl::setupDevice() { struct audio_info auinf; if (dspFd_ < 0) return 1; if (ioctl(dspFd_, AUDIO_GETINFO, &auinf) < 0) { log_message(-1, _("Cannot get state of audio interface: %s"), strerror(errno)); return 1; } auinf.play.sample_rate=44100; auinf.play.channels=2; auinf.play.precision=16; auinf.play.encoding=AUDIO_ENCODING_LINEAR; if (ioctl(dspFd_, AUDIO_SETINFO, &auinf) < 0) { log_message(-1, _("Cannot setup audio interface: %s"), strerror(errno)); return 1; } return 0; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/SoundIF.h�����������������������������������������������������������0000664�0000000�0000000�00000002116�15114537466�0020327�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __SOUND_IF_H__ #define __SOUND_IF_H__ class Sample; class SoundIF { public: SoundIF(); ~SoundIF(); int init(); int start(); int play(Sample *, long); unsigned long getDelay(); void end(); private: class SoundIFImpl *impl_; }; #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/TASKS���������������������������������������������������������������0000664�0000000�0000000�00000003237�15114537466�0017464�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������Status Who Description ====== ====== ============================================================== - - Test for enough free disk space before some operations - - Device Listing class needs "Load" and "Eject" buttons - - Detect CD Drive driver automagically. - - Use Gnome::Dialog for dialogs. - Jonas? What we need to pass to cdrecord in fs=# to get the same buffer size that in cdrdao? - - Add a projects dir to cd in by default and a "Current dir" - - Create a Project Class that will contain AudioCDChild, IsoCDChild, ... as needed. DONE? Manuel Make RecordGenericDialog. - - CD player class that will be able to play from a .toc or from a CD, including diferent wav files and mixed mode tocs. So we can use it in a toolbar, in the AudioCDChild, ... - - Functions in the trackdb to be able to change the .bin file on a .toc, to allow reading an image and give it a name later, or don't give it a name if the user don't wants to save it. - Jonas? We should be able to translate it: add gettext support. - Andreas Are the .toc files compatibles with CdrWin? - - Add extraction to wav and MP3 files directly. For MP3 encoding we can use LAME http://www.sulaco.org/mp3/ - - Write extensive documentation: what's the right way to do this? docbook? how? - - Put a message in the record progress dialog telling: "Don't panic if the progressbar doesn't update, the lead in data/track (?) is being written". - - "Generate log" option in the record dialog, so we can dump lots of messages to a file like "log.txt" for later reviewing. - - Don't wait to buffer (on the fly) - option: it should began to write when you have already 10 audio seconds * speed. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/TextEdit.cc���������������������������������������������������������0000664�0000000�0000000�00000004437�15114537466�0020720�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #include "TextEdit.h" #include <stddef.h> #include <ctype.h> #include <cstring> TextEdit::TextEdit(const char *sample) : Gtk::Entry() { upper_ = 1; lower_ = 1; digits_ = 1; space_ = 1; if (sample != NULL && *sample != 0) setSize(sample); } TextEdit::~TextEdit() { } void TextEdit::upperCase(int f) { upper_ = (f != 0) ? 1 : 0; } void TextEdit::lowerCase(int f) { lower_ = (f != 0) ? 1 : 0; } void TextEdit::digits(int f) { digits_ = (f != 0) ? 1 : 0; } void TextEdit::space(int f) { space_ = (f != 0) ? 1 : 0; } void TextEdit::insert_text_impl(const gchar *c, gint p2, gint *p3) { char *s = new char[strlen(c) + 1]; char *p = s; while (*c != 0) { if (islower(*c)) { if (!lower_) { if (upper_) *p++ = toupper(*c); } else *p++ = *c; } else if (isupper(*c)) { if (!upper_) { if (lower_) *p++ = tolower(*c); } else *p++ = *c; } else if (isdigit(*c)) { if (digits_) *p++ = *c; } else if (isspace(*c)) { if (space_) *p++ = *c; } c++; } *p = 0; insert_text(s, p2, *p3); delete[] s; } void TextEdit::setSize(const char *sample) { Glib::RefPtr<Pango::Context> context = get_layout()->get_context(); Pango::FontDescription fdesc = context->get_font_description(); int cw = context->get_metrics(fdesc).get_approximate_char_width() / 1000; int ch = context->get_metrics(fdesc).get_ascent() / 1000; set_size_request((strlen(sample) * cw) + 8, -1); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/TextEdit.h����������������������������������������������������������0000664�0000000�0000000�00000003707�15114537466�0020561�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998, 1999 Andreas Mueller <mueller@daneb.ping.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 * (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. */ /* * $Log: TextEdit.h,v $ * Revision 1.3 2004/02/12 01:13:32 poolshark * Merge from gnome2 branch * * Revision 1.2.6.1 2004/01/05 00:34:03 poolshark * First checking of gnome2 port * * Revision 1.2 2003/12/29 09:31:48 denis * fixed all dialogs * * Revision 1.1.1.1 2003/12/09 05:32:28 denis * Fooya * * Revision 1.2 2000/02/20 23:34:54 llanero * fixed scsilib directory (files mising ?-() * ported xdao to 1.1.8 / gnome (MDI) app * * Revision 1.1.1.1 2000/02/05 01:38:51 llanero * Uploaded cdrdao 1.1.3 with pre10 patch applied. * * Revision 1.1 1999/08/19 20:28:12 mueller * Initial revision * */ #ifndef __TEXT_EDIT_H__ #define __TEXT_EDIT_H__ #include <gtkmm.h> #include <gtk/gtk.h> class TextEdit : public Gtk::Entry { public: TextEdit(const char *sample); ~TextEdit(); void upperCase(int); void lowerCase(int); void digits(int); void space(int); protected: virtual void insert_text_impl(const gchar *p1,gint p2,gint *p3); private: unsigned int upper_ : 1; unsigned int lower_ : 1; unsigned int digits_ : 1; unsigned int space_ : 1; void setSize(const char *sample); }; #endif ���������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/TocEdit.cc����������������������������������������������������������0000664�0000000�0000000�00000054101�15114537466�0020512�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #include "config.h" #include "TocEdit.h" #include <glibmm/i18n.h> #include <stddef.h> #include <iostream> #include <sstream> #include <set> #include "util.h" #include "Toc.h" #include "TocEditView.h" #include "TrackData.h" #include "TrackDataList.h" #include "TrackDataScrap.h" #include "guiUpdate.h" #include "SampleManager.h" TocEdit::TocEdit(Toc *t, const char *filename) { toc_ = NULL; sampleManager_ = NULL; filename_ = NULL; trackDataScrap_ = NULL; threadActive_ = false; curState_ = TE_IDLE; curConv_ = NULL; cur_ = NULL; updateLevel_ = 0; editBlocked_ = false; if (filename == NULL) toc(t, "unnamed.toc"); else toc(t, filename); } TocEdit::~TocEdit() { if (toc_) delete toc_; if (sampleManager_) delete sampleManager_; if (filename_) delete[] filename_; if (trackDataScrap_) delete trackDataScrap_; } void TocEdit::toc(Toc *t, const char *filename) { if (toc_) delete toc_; if (t == NULL) toc_ = new Toc; else toc_ = t; if (filename != NULL) { delete[] filename_; filename_ = strdupCC(filename); } tocDirty_ = false; editBlocked_ = false; if (sampleManager_) delete sampleManager_; sampleManager_ = new SampleManager(588); sampleManager_->setTocEdit(this); if (toc_->length().samples() > 0) { // First collect all filenames and queue their conversions to WAV std::set<std::string> set; toc_->collectFiles(set); std::set<std::string>::iterator i = set.begin(); for (; i != set.end(); i++) queueConversion((*i).c_str()); // Second, queue for toc scan. unsigned long maxSample = toc_->length().samples() - 1; queueScan(0, -1); } updateLevel_ = UPD_ALL; } Toc *TocEdit::toc() const { return toc_; } SampleManager *TocEdit::sampleManager() { return sampleManager_; } void TocEdit::tocDirty(bool f) { bool old = tocDirty_; tocDirty_ = f; if (old != tocDirty_) updateLevel_ |= UPD_TOC_DIRTY; } void TocEdit::blockEdit() { if (editBlocked_ == 0) updateLevel_ |= UPD_EDITABLE_STATE; editBlocked_ += 1; } void TocEdit::unblockEdit() { if (editBlocked_ > 0) { editBlocked_ -= 1; if (editBlocked_ == 0) updateLevel_ |= UPD_EDITABLE_STATE; } } unsigned long TocEdit::updateLevel() { unsigned long level = updateLevel_; updateLevel_ = 0; return level; } unsigned long TocEdit::lengthSample() const { return toc_->length().samples(); } void TocEdit::filename(const char *fname) { if (fname != NULL && *fname != 0) { char *s = strdupCC(fname); delete[] filename_; filename_ = s; updateLevel_ |= UPD_TOC_DATA; } } const char *TocEdit::filename() const { return filename_; } int TocEdit::readToc(const char *fname) { if (!editable()) return 0; if (fname == NULL || *fname == 0) return 1; Toc *t = Toc::read(fname); if (t != NULL) { // Check and resolve input files paths t->resolveFilenames(fname); // Sometimes length fields are ommited. Make sure we got everything. t->recomputeLength(); toc(t, fname); return 0; } return 1; } int TocEdit::saveToc() { int ret = toc_->write(filename_); if (ret == 0) tocDirty(0); return ret; } int TocEdit::saveAsToc(const char *fname) { int ret; if (fname != NULL && *fname != 0) { ret = toc_->write(fname); if (ret == 0) { filename(fname); tocDirty(0); updateLevel_ |= UPD_TOC_DATA; } return ret; } return 1; } int TocEdit::moveTrackMarker(int trackNr, int indexNr, long lba) { if (!editable()) return 0; int ret = toc_->moveTrackMarker(trackNr, indexNr, lba); if (ret == 0) { tocDirty(1); updateLevel_ |= UPD_TRACK_DATA; } return ret; } int TocEdit::addTrackMarker(long lba) { if (!editable()) return 0; int ret = toc_->addTrackMarker(lba); if (ret == 0) { tocDirty(1); //llanero: different views // updateLevel_ |= UPD_TOC_DATA | UPD_TRACK_DATA; } return ret; } int TocEdit::addIndexMarker(long lba) { if (!editable()) return 0; int ret = toc_->addIndexMarker(lba); if (ret == 0) { tocDirty(1); //llanero: different views // updateLevel_ |= UPD_TRACK_DATA; } return ret; } int TocEdit::addPregap(long lba) { if (!editable()) return 0; int ret = toc_->addPregap(lba); if (ret == 0) { tocDirty(1); //llanero: different views // updateLevel_ |= UPD_TRACK_DATA; } return ret; } int TocEdit::removeTrackMarker(int trackNr, int indexNr) { if (!editable()) return 0; int ret = toc_->removeTrackMarker(trackNr, indexNr); if (ret == 0) { tocDirty(1); //llanero: different views // updateLevel_ |= UPD_TOC_DATA | UPD_TRACK_DATA; } return ret; } bool TocEdit::curScan() { // An end position of -1 means recompute the toc length and scan to // the last sample position. if (cur_->end == -1) { // (Denis Leroy) The reason for this code is somewhat // complex. When importing a CUE file with MP3s, the length of the // last track is not known until the MP3 is actually converted to // a WAV (because, unlike TOC files, CUE files don't specify // explicitely the length of each track). Unlike WAV, you can't // guess the length of the track based on the mp3 file size // without scanning the whole thing, which we don't want to do // twice obviously. So the semantic of the "scan" job is changed // to integrate a length recalculation when the end is not // specified. It would be cleaner to create a specific job task to // do this. toc_->recomputeLength(); cur_->end = toc_->length().samples() - 1; updateLevel_ |= UPD_SAMPLES; } int ret = sampleManager_->scanToc(cur_->pos, cur_->end); if (ret == 0) return true; if (ret == 2) { signalError("Unable to open or read from input audio files"); return false; } return false; } bool TocEdit::curAppendTrack() { TrackData* data; int ret = curCreateAudioData(&data); if (ret != 0) return false; TrackDataList list; long start, end; list.append(data); toc_->appendTrack(&list, &start, &end); tocDirty(1); sampleManager_->scanToc(Msf(start).samples(), Msf(end).samples() - 1); return true; } bool TocEdit::curAppendFile() { TrackData* data; int ret = curCreateAudioData(&data); if (ret != 0) return false; TrackDataList list; long start, end; list.append(data); if (toc_->appendTrackData(&list, &start, &end) != 0) { delete data; return false; } tocDirty(1); sampleManager_->scanToc(Msf(start).samples(), Msf(end).samples() - 1); return true; } bool TocEdit::curInsertFile() { TrackData* data; int ret = curCreateAudioData(&data); if (ret != 0) return false; TrackDataList list; list.append(data); if (toc_->insertTrackData(cur_->pos, &list) != 0) { signalError(_("Cannot insert file into a data track")); delete data; return false; } cur_->len = list.length(); sampleManager_->insertSamples(cur_->pos, cur_->len, NULL); sampleManager_->scanToc(cur_->pos, cur_->pos + cur_->len); tocDirty(1); return true; } // Creates an audio data object for given filename. Errors are send to // status line. // data: filled with newly allocated TrackData object on success // return: 0: OK // 1: cannot open file // 2: file has wrong format int TocEdit::curCreateAudioData(TrackData **data) { unsigned long len; std::string msg; switch (TrackData::checkAudioFile(cur_->cfile.c_str(), &len)) { case 1: msg = _("Could not open file \""); msg += cur_->cfile; msg += "\""; signalError(msg.c_str()); return 1; // Cannot open file case 2: msg = _("Could not open file \""); msg += cur_->cfile; msg += "\" : wrong file format"; signalError(msg.c_str()); return 2; // File format error } *data = new TrackData(cur_->file.c_str(), 0, len); (*data)->effectiveFilename(cur_->cfile.c_str()); return 0; } void TocEdit::curSignalConversionError(FormatSupport::Status err) { std::string msg = _("Unable to decode audio file \""); msg += cur_->file; msg += "\" : "; switch (err) { case FormatSupport::FS_DISK_FULL: msg += _("disk is full"); break; case FormatSupport::FS_OUTPUT_PROBLEM: msg += _("error creating output file"); break; default: msg += _("read error or wrong file format"); } signalError(msg.c_str()); } void TocEdit::queueConversion(const char* filename) { QueueJob* job = new QueueJob("convert"); job->file = filename; queue_.push_back(job); if (!threadActive_) activateQueue(); } void TocEdit::queueAppendTrack(const char* filename) { QueueJob* job = new QueueJob("aptrack"); job->op = "aptrack"; job->file = filename; queue_.push_back(job); if (!threadActive_) activateQueue(); } void TocEdit::queueAppendFile(const char* filename) { QueueJob* job = new QueueJob("apfile"); job->file = filename; queue_.push_back(job); if (!threadActive_) activateQueue(); } void TocEdit::queueInsertFile(const char* filename, unsigned long pos) { QueueJob* job = new QueueJob("infile"); job->file = filename; job->pos = pos; queue_.push_back(job); if (!threadActive_) activateQueue(); } void TocEdit::queueScan(long start, long end) { QueueJob* job = new QueueJob("scan"); job->pos = start; job->end = end; queue_.push_back(job); if (!threadActive_) activateQueue(); } void TocEdit::activateQueue() { if (!threadActive_) { threadActive_ = true; blockEdit(); signalCancelEnable(true); Glib::signal_idle().connect(sigc::mem_fun(*this, &TocEdit::queueThread)); guiUpdate(); } } void TocEdit::queueAbort() { if (threadActive_) { queue_.clear(); curState_ = TE_IDLE; if (curConv_) { curConv_->convertAbort(); delete curConv_; curConv_ = NULL; signalStatusMessage(""); } } } bool TocEdit::isQueueActive() { return threadActive_; } // The queueThread is run by the Gtk idle thread when asynchronous // work has to be done, such as decoding an MP3 file or reading // samples from a WAV file. // // Asynchronous work (i.e. CPU-intensive work that has do be done in // the background without blocking the GUI) can be scheduled by adding // a new QueueJob object in the queue_ (see queueXXX methods above). bool TocEdit::queueThread() { static int pulse = 0; // If we're idle, pop next queue entry. if (curState_ == TE_IDLE) { // Queue empty ? Stop queue thread. if (queue_.empty()) { threadActive_ = false; unblockEdit(); signalProgressFraction(0.0); signalCancelEnable(false); guiUpdate(); return false; // false means disconnect idle thread } if (cur_) delete cur_; cur_ = queue_.front(); queue_.pop_front(); if (cur_->op == "scan") { if (curScan()) { curState_ = TE_READING; signalStatusMessage("Scanning audio data"); } else { curState_ = TE_IDLE; return true; } } else { if (curConv_) delete curConv_; FormatSupport::Status err; curConv_ = formatConverter.newConverterStart(cur_->file.c_str(), cur_->cfile, &err); if (curConv_) { std::string msg = "Decoding audio file "; msg += cur_->file; curState_ = TE_CONVERTING; signalStatusMessage(msg.c_str()); } else { if (err != FormatSupport::FS_SUCCESS) { curSignalConversionError(err); curState_ = TE_IDLE; return true; } // File is already converted, or can't be converted (it's a WAV // or RAW file already). if (cur_->cfile.empty()) cur_->cfile = cur_->file; curState_ = TE_CONVERTED; } } } // ------------------ TE_CONVERTING state: do file format conversion if (curState_ == TE_CONVERTING) { // Perform incremental file conversion. FormatSupport::Status status = curConv_->convertContinue(); if (pulse++ > 5) { signalProgressPulse(); pulse = 0; } // Still in progress, likely exit here. if (status == FormatSupport::FS_IN_PROGRESS) return true; // Conversion done. delete curConv_; curConv_ = NULL; if (status == FormatSupport::FS_SUCCESS) curState_ = TE_CONVERTED; else { curSignalConversionError(status); // Conversion failed, move on with next queue entry. curState_ = TE_IDLE; } return true; } // ------------------- TE_CONVERTED state: conversion done, prepare reading if (curState_ == TE_CONVERTED) { // Sanity check: the cfile (converted filename) will be read as // either a WAV file or a file containing raw samples. If the // extension is still that of an encoded audio file, return an // error. Otherwise it'll be read as a RAW samples file which is // not was users expect. TrackData::FileType ctype = TrackData::audioFileType(cur_->cfile.c_str()); if (ctype != TrackData::RAW && ctype != TrackData::WAVE) { std::string msg = _("Cannot decode file"); msg += " \""; msg += cur_->cfile; msg += "\" : "; msg += _("unsupported audio format"); signalError(msg.c_str()); curState_ = TE_IDLE; return true; } // If all we wanted to do was format conversion, we're done. if (cur_->op == "convert") { toc_->markFileConversion(cur_->file.c_str(), cur_->cfile.c_str()); curState_ = TE_IDLE; return true; } curState_ = TE_READING; signalProgressFraction(0.0); if (cur_->op == "aptrack") { if (!curAppendTrack()) { curState_ = TE_IDLE; return true; } } else if (cur_->op == "apfile") { if (!curAppendFile()) { curState_ = TE_IDLE; return true; } } else if (cur_->op == "infile") { if (!curInsertFile()) { curState_ = TE_IDLE; return true; } } std::string msg = "Scanning audio file "; msg += cur_->file; signalStatusMessage(msg.c_str()); } // ------------------- TE_READING state : read/scan WAV samples if (curState_ == TE_READING) { int result = sampleManager_->readSamples(); if (result != 0) { if (result < 0) signalError(_("An error occurred while reading audio data")); else { // Post operating code here. if (cur_->op == "aptrack") { updateLevel_ |= UPD_TOC_DATA | UPD_TRACK_DATA; signalFullView(); std::string msg = "Appended track "; msg += cur_->file; signalStatusMessage(msg.c_str()); guiUpdate(); } else if (cur_->op == "apfile") { updateLevel_ |= UPD_TOC_DATA | UPD_TRACK_DATA; signalFullView(); std::string msg = "Appended file "; msg += cur_->file; signalStatusMessage(msg.c_str()); guiUpdate(); } else if (cur_->op == "infile") { updateLevel_ |= UPD_TOC_DATA | UPD_TRACK_DATA | UPD_SAMPLE_SEL; signalFullView(); std::string msg = "Inserted file "; msg += cur_->file; signalStatusMessage(msg.c_str()); signalSampleSelection(cur_->pos, cur_->pos + cur_->len - 1); guiUpdate(); } else if (cur_->op == "scan") { std::stringstream ss; ss << "Scanned "; ss << (cur_->end - cur_->pos + 1); ss << " samples of data"; std::string msg = ss.str(); signalStatusMessage(msg.c_str()); updateLevel_ |= UPD_SAMPLES; } } curState_ = TE_IDLE; } return true; } return true; } int TocEdit::appendSilence(unsigned long length) { if (!editable()) return 0; if (length > 0) { long start, end; TrackData *data = new TrackData(length); TrackDataList list; list.append(data); if (toc_->appendTrackData(&list, &start, &end) == 0) { sampleManager_->scanToc(Msf(start).samples(), Msf(end).samples() - 1, true); tocDirty(1); updateLevel_ |= UPD_TOC_DATA | UPD_TRACK_DATA; } } return 0; } // Return: 0: OK // 1: No modify allowed // 2: error? int TocEdit::insertSilence(unsigned long length, unsigned long pos) { if (!editable()) return 1; if (length > 0) { TrackData *data = new TrackData(length); TrackDataList list; list.append(data); if (toc_->insertTrackData(pos, &list) == 0) { sampleManager_->insertSamples(pos, length, NULL); sampleManager_->scanToc(pos, pos + length, true); tocDirty(1); updateLevel_ |= UPD_TOC_DATA | UPD_TRACK_DATA | UPD_SAMPLE_SEL; return 0; } } return 2; } void TocEdit::setTrackCopyFlag(int trackNr, int flag) { if (!editable()) return; Track *t = toc_->getTrack(trackNr); if (t != NULL) { t->copyPermitted(flag); tocDirty(1); updateLevel_ |= UPD_TRACK_DATA; } } void TocEdit::setTrackPreEmphasisFlag(int trackNr, int flag) { if (!editable()) return; Track *t = toc_->getTrack(trackNr); if (t != NULL) { t->preEmphasis(flag); tocDirty(1); updateLevel_ |= UPD_TRACK_DATA; } } void TocEdit::setTrackAudioType(int trackNr, int flag) { if (!editable()) return; Track *t = toc_->getTrack(trackNr); if (t != NULL) { t->audioType(flag); tocDirty(1); updateLevel_ |= UPD_TRACK_DATA; } } void TocEdit::setTrackIsrcCode(int trackNr, const char *s) { if (!editable()) return; Track *t = toc_->getTrack(trackNr); if (t != NULL) { if (t->isrc(s) == 0) { tocDirty(1); updateLevel_ |= UPD_TRACK_DATA; } } } void TocEdit::setCdTextItem(int trackNr, CdTextItem::PackType type, int blockNr, const char *s) { if (!editable()) return; if (s != NULL) { CdTextItem *item = new CdTextItem(type, blockNr); item->setText(s); toc_->addCdTextItem(trackNr, item); } else { toc_->removeCdTextItem(trackNr, type, blockNr); } tocDirty(1); updateLevel_ |= (trackNr == 0) ? UPD_TOC_DATA : UPD_TRACK_DATA; } void TocEdit::setCdTextGenreItem(int blockNr, int code1, int code2, const char *description) { if (code1 > 255 || code2 > 255) return; if (!editable()) return; if (code1 < 0 || code2 < 0) { toc_->removeCdTextItem(0, CdTextItem::PackType::GENRE, blockNr); } else { CdTextItem *item = new CdTextItem(CdTextItem::PackType::GENRE, blockNr); item->setGenre((u8)code1, (u8)code2, description); toc_->addCdTextItem(0, item); } tocDirty(1); updateLevel_ |= UPD_TOC_DATA; } void TocEdit::setCdTextLanguage(int blockNr, int langCode) { if (!editable()) return; toc_->cdTextLanguage(blockNr, langCode); tocDirty(1); updateLevel_ |= UPD_TOC_DATA; } void TocEdit::setCatalogNumber(const char *s) { if (!editable()) return; if (toc_->catalog(s) == 0) { tocDirty(1); updateLevel_ |= UPD_TOC_DATA; } } void TocEdit::setTocType(Toc::Type type) { if (!editable()) return; toc_->tocType(type); tocDirty(1); updateLevel_ |= UPD_TOC_DATA; } // Removes selected track data // Return: 0: OK // 1: no selection // 2: selection crosses track boundaries // 3: cannot modify data track int TocEdit::removeTrackData(TocEditView *view) { TrackDataList *list; unsigned long selMin, selMax; if (!editable()) return 0; if (!view->sampleSelection(&selMin, &selMax)) return 1; switch (toc_->removeTrackData(selMin, selMax, &list)) { case 0: if (list != NULL) { if (list->length() > 0) { delete trackDataScrap_; trackDataScrap_ = new TrackDataScrap(list); } else { delete list; } sampleManager_->removeSamples(selMin, selMax, trackDataScrap_); view->sampleSelectionClear(); view->sampleMarker(selMin); tocDirty(1); } break; case 1: return 2; break; case 2: return 3; break; } return 0; } // Inserts track data from scrap // Return: 0: OK // 1: no scrap data to paste int TocEdit::insertTrackData(TocEditView *view) { if (!editable()) return 0; if (trackDataScrap_ == NULL) return 1; unsigned long len = trackDataScrap_->trackDataList()->length(); unsigned long marker; if (view->sampleMarker(&marker) && marker < toc_->length().samples()) { if (toc_->insertTrackData(marker, trackDataScrap_->trackDataList()) == 0) { sampleManager_->insertSamples(marker, len, trackDataScrap_); sampleManager_->scanToc(marker, marker, true); sampleManager_->scanToc(marker + len - 1, marker + len - 1, true); view->sampleSelect(marker, marker + len - 1); tocDirty(1); //llanero: different views // updateLevel_ |= UPD_TOC_DATA | UPD_TRACK_DATA | UPD_SAMPLE_SEL; } } else { long start, end; if (toc_->appendTrackData(trackDataScrap_->trackDataList(), &start, &end) == 0) { sampleManager_->insertSamples(Msf(start).samples(), Msf(end - start).samples(), trackDataScrap_); sampleManager_->scanToc(Msf(start).samples(), Msf(start).samples(), true); if (end > 0) sampleManager_->scanToc(Msf(start).samples() + len, Msf(end).samples() - 1, true); view->sampleSelect(Msf(start).samples(), Msf(end).samples() - 1); tocDirty(1); updateLevel_ |= UPD_TOC_DATA | UPD_TRACK_DATA | UPD_SAMPLE_SEL; } } return 0; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/TocEdit.h�����������������������������������������������������������0000664�0000000�0000000�00000010162�15114537466�0020353�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998, 1999 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __TOC_EDIT_H__ #define __TOC_EDIT_H__ #include <string> #include <list> #include <sigc++/signal.h> #include "Toc.h" #include "CdTextItem.h" #include "FormatConverter.h" class Toc; class TrackData; class TrackDataScrap; class SampleManager; class TocEditView; class TocEdit { public: TocEdit(Toc *, const char *); ~TocEdit(); void toc(Toc *, const char *); Toc *toc() const; SampleManager *sampleManager(); unsigned long lengthSample() const; void tocDirty(bool); bool tocDirty() const { return tocDirty_; } void blockEdit(); void unblockEdit(); bool editable() const { return (editBlocked_ == 0); } // returns and resets update level unsigned long updateLevel(); void filename(const char *); const char *filename() const; int readToc(const char *); int saveToc(); int saveAsToc(const char *); int moveTrackMarker(int trackNr, int indexNr, long lba); int addTrackMarker(long lba); int removeTrackMarker(int trackNr, int indexNr); int addIndexMarker(long lba); int addPregap(long lba); // Asynchronous interface. void queueConversion(const char* filename); void queueAppendTrack(const char* filename); void queueAppendFile(const char* filename); void queueInsertFile(const char* filename, unsigned long pos); void queueScan(long start, long end); // Abort all queued work. void queueAbort(); // Is queue active bool isQueueActive(); int appendSilence(unsigned long); int insertSilence(unsigned long length, unsigned long pos); int removeTrackData(TocEditView *); int insertTrackData(TocEditView *); void setTrackCopyFlag(int trackNr, int flag); void setTrackPreEmphasisFlag(int trackNr, int flag); void setTrackAudioType(int trackNr, int flag); void setTrackIsrcCode(int trackNr, const char *); void setCdTextItem(int trackNr, CdTextItem::PackType, int blockNr, const char *); void setCdTextGenreItem(int blockNr, int code1, int code2, const char *description); void setCdTextLanguage(int blockNr, int langCode); void setCatalogNumber(const char *); void setTocType(Toc::Type); // Signals sigc::signal0<void> signalProgressPulse; sigc::signal1<void, double> signalProgressFraction; sigc::signal1<void, const char*> signalStatusMessage; sigc::signal0<void> signalFullView; sigc::signal2<void, unsigned long, unsigned long> signalSampleSelection; sigc::signal1<void, bool> signalCancelEnable; sigc::signal1<void, const char*> signalError; private: Toc *toc_; SampleManager *sampleManager_; char *filename_; TrackDataScrap *trackDataScrap_; bool tocDirty_; int editBlocked_; unsigned long updateLevel_; class QueueJob { public: QueueJob(const char* o) { op = o; pos = 0; end = 0; len = 0; } ~QueueJob() {} std::string op; std::string file; std::string cfile; long pos; long end; long len; }; std::list<QueueJob*> queue_; QueueJob* cur_; bool threadActive_; enum { TE_IDLE, TE_CONVERTING, TE_CONVERTED, TE_READING } curState_; FormatSupport* curConv_; bool curScan(); bool curAppendTrack(); bool curAppendFile(); bool curInsertFile(); int curCreateAudioData(TrackData **); void curSignalConversionError(FormatSupport::Status); void activateQueue(); bool queueThread(); friend class TocEditView; }; #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/TocEditView.cc������������������������������������������������������0000664�0000000�0000000�00000010615�15114537466�0021347�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2000 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #include "TocEditView.h" #include <stddef.h> #include "guiUpdate.h" #include "TocEdit.h" TocEditView::TocEditView(TocEdit *t) { tocEdit_ = t; sampleMarkerValid_ = false; sampleSelectionValid_ = false; sampleViewMin_ = sampleViewMax_ = 0; trackSelectionValid_ = 0; indexSelectionValid_ = 0; } TocEditView::~TocEditView() { tocEdit_ = 0; } TocEdit *TocEditView::tocEdit() const { return tocEdit_; } void TocEditView::sampleMarker(unsigned long sample) { if (sample < tocEdit_->toc()->length().samples()) { sampleMarker_ = sample; sampleMarkerValid_ = true; } else { sampleMarkerValid_ = false; } } bool TocEditView::sampleMarker(unsigned long *sample) const { if (sampleMarkerValid_) *sample = sampleMarker_; return sampleMarkerValid_; } void TocEditView::sampleSelectAll() { unsigned long slength = tocEdit_->toc()->length().samples(); if (slength) { sampleSelectionMin_ = 0; sampleSelectionMax_ = slength - 1; sampleSelectionValid_ = true; } } void TocEditView::sampleSelect(unsigned long smin, unsigned long smax) { unsigned long tmp; if (smin > smax) { tmp = smin; smin = smax; smax = tmp; } if (smax < tocEdit_->toc()->length().samples()) { sampleSelectionMin_ = smin; sampleSelectionMax_ = smax; sampleSelectionValid_ = true; } else { sampleSelectionValid_ = false; } } bool TocEditView::sampleSelectionClear() { if (sampleSelectionValid_) { sampleSelectionValid_ = false; return true; } return false; } bool TocEditView::sampleSelection(unsigned long *smin, unsigned long *smax) const { if (sampleSelectionValid_) { *smin = sampleSelectionMin_; *smax = sampleSelectionMax_; } return sampleSelectionValid_; } bool TocEditView::sampleView(unsigned long smin, unsigned long smax) { if (smin <= smax && smax < tocEdit_->lengthSample()) { sampleViewMin_ = smin; sampleViewMax_ = smax; return true; } return false; } void TocEditView::sampleView(unsigned long *smin, unsigned long *smax) const { *smin = sampleViewMin_; *smax = sampleViewMax_; } void TocEditView::sampleViewFull() { sampleViewMin_ = 0; if ((sampleViewMax_ = tocEdit_->lengthSample()) > 0) sampleViewMax_ -= 1; } void TocEditView::sampleViewUpdate() { if (sampleViewMax_ >= tocEdit_->lengthSample()) { unsigned long len = sampleViewMax_ - sampleViewMin_; if ((sampleViewMax_ = tocEdit_->lengthSample()) > 0) sampleViewMax_ -= 1; if (sampleViewMax_ >= len) sampleViewMin_ = sampleViewMax_ - len; else sampleViewMin_ = 0; tocEdit_->updateLevel_ |= UPD_SAMPLES; } } void TocEditView::sampleViewInclude(unsigned long smin, unsigned long smax) { if (smin < sampleViewMin_) { sampleViewMin_ = smin; tocEdit_->updateLevel_ |= UPD_SAMPLES; } if (smax < tocEdit_->lengthSample() && smax > sampleViewMax_) { sampleViewMax_ = smax; tocEdit_->updateLevel_ |= UPD_SAMPLES; } } void TocEditView::trackSelection(int tnum) { if (tnum > 0) { trackSelection_ = tnum; trackSelectionValid_ = 1; } else { trackSelectionValid_ = 0; } } int TocEditView::trackSelection(int *tnum) const { if (trackSelectionValid_) *tnum = trackSelection_; return trackSelectionValid_; } void TocEditView::indexSelection(int inum) { if (inum >= 0) { indexSelection_ = inum; indexSelectionValid_ = 1; } else { indexSelectionValid_ = 0; } } int TocEditView::indexSelection(int *inum) const { if (indexSelectionValid_) *inum = indexSelection_; return indexSelectionValid_; } �������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/TocEditView.h�������������������������������������������������������0000664�0000000�0000000�00000003723�15114537466�0021213�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2000 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __TOC_EDIT_VIEW_H__ #define __TOC_EDIT_VIEW_H__ class TocEdit; class TocEditView { public: TocEditView(TocEdit *); ~TocEditView(); TocEdit *tocEdit() const; void sampleMarker(unsigned long); bool sampleMarker(unsigned long *) const; void sampleSelect(unsigned long, unsigned long); void sampleSelectAll(); bool sampleSelection(unsigned long *, unsigned long *) const; bool sampleSelectionClear(); void sampleViewFull(); void sampleViewUpdate(); void sampleViewInclude(unsigned long, unsigned long); void sampleView(unsigned long *, unsigned long *) const; bool sampleView(unsigned long smin, unsigned long smax); void trackSelection(int); int trackSelection(int *) const; void indexSelection(int); int indexSelection(int *) const; private: TocEdit *tocEdit_; bool sampleMarkerValid_; unsigned long sampleMarker_; bool sampleSelectionValid_; unsigned long sampleSelectionMin_; unsigned long sampleSelectionMax_; unsigned long sampleViewMin_; unsigned long sampleViewMax_; int trackSelectionValid_; int trackSelection_; int indexSelectionValid_; int indexSelection_; }; #endif ���������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/TocInfoDialog.cc����������������������������������������������������0000664�0000000�0000000�00000066517�15114537466�0021656�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2000 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #include "config.h" #include "TocInfoDialog.h" #include <gtkmm.h> #include <glibmm/i18n.h> #include <stdio.h> #include <stddef.h> #include <ctype.h> #include "TocEdit.h" //#include "TocEditView.h" #include "guiUpdate.h" #include "Toc.h" #include "CdTextItem.h" #include "TextEdit.h" #define MAX_CD_TEXT_LANGUAGE_CODES 22 struct LanguageCode { int code; const char *name; }; static LanguageCode CD_TEXT_LANGUAGE_CODES[MAX_CD_TEXT_LANGUAGE_CODES] = { { -1, "Unknown" }, { -1, "Undefined" }, { 0x75, "Chinese" }, { 0x06, "Czech" }, { 0x07, "Danish" }, { 0x1d, "Dutch" }, { 0x09, "English" }, { 0x27, "Finnish" }, { 0x0f, "French" }, { 0x08, "German" }, { 0x70, "Greek" }, { 0x1b, "Hungarian" }, { 0x15, "Italian" }, { 0x69, "Japanese" }, { 0x65, "Korean" }, { 0x1e, "Norwegian" }, { 0x20, "Polish" }, { 0x21, "Portuguese" }, { 0x56, "Russian" }, { 0x26, "Slovene" }, { 0x0a, "Spanish" }, { 0x28, "Swedish" } }; #define MAX_CD_TEXT_GENRE_CODES 28 struct GenreCode { int code1; int code2; const char *name; }; static GenreCode CD_TEXT_GENRE_CODES[MAX_CD_TEXT_GENRE_CODES] = { { -1, -1, "Unknown" }, { -1, -1, "Not Used" }, { 0x00, 0x01, "Not Defined" }, { 0x00, 0x02, "Adult Contemporary" }, { 0x00, 0x03, "Alternative Rock" }, { 0x00, 0x04, "Children's Music" }, { 0x00, 0x05, "Classical" }, { 0x00, 0x07, "Country" }, { 0x00, 0x08, "Dance" }, { 0x00, 0x09, "Easy Listening" }, { 0x00, 0x0a, "Erotic" }, { 0x00, 0x0b, "Folk" }, { 0x00, 0x0c, "Gospel" }, { 0x00, 0x0d, "Hip Hop" }, { 0x00, 0x0e, "Jazz" }, { 0x00, 0x0f, "Latin" }, { 0x00, 0x10, "Musical" }, { 0x00, 0x11, "New Age" }, { 0x00, 0x12, "Opera" }, { 0x00, 0x13, "Operetta" }, { 0x00, 0x14, "Pop Music" }, { 0x00, 0x15, "RAP" }, { 0x00, 0x16, "Reggae" }, { 0x00, 0x17, "Rock Music" }, { 0x00, 0x19, "Sound Effects" }, { 0x00, 0x1a, "Sound Track" }, { 0x00, 0x1b, "Spoken Word" }, { 0x00, 0x1c, "World Music" } }; static const char* TOC_TYPE_CD_DA = "CD-DA"; static const char* TOC_TYPE_CD_ROM = "CD-ROM"; static const char* TOC_TYPE_CD_ROM_XA = "CD-ROM-XA"; static const char* TOC_TYPE_CD_I = "CD-I"; TocInfoDialog::TocInfoDialog(Gtk::Window* parent) { int i; Gtk::Label *label; Gtk::HBox *hbox; Gtk::VBox *vbox, *vbox1; Gtk::Frame *frame; Gtk::Table *table; Gtk::Button *button; Gtk::VBox *contents = manage(new Gtk::VBox); tocEdit_ = NULL; active_ = false; selectedTocType_ = Toc::Type::CD_DA; nofTracks_ = manage(new Gtk::Label("99")); nofTracks_->set_alignment(Gtk::ALIGN_START); tocLength_ = manage(new Gtk::Label("100:00:00")); tocLength_->set_alignment(Gtk::ALIGN_START); catalog_ = manage(new TextEdit("1234567890123")); catalog_->set_max_length(13); catalog_->lowerCase(0); catalog_->upperCase(0); catalog_->space(0); catalog_->digits(1); tocType_.append(TOC_TYPE_CD_DA); tocType_.append(TOC_TYPE_CD_ROM); tocType_.append(TOC_TYPE_CD_ROM_XA); tocType_.append(TOC_TYPE_CD_I); tocType_.signal_changed().connect(sigc::mem_fun(*this, &TocInfoDialog::setSelectedTocType)); contents->set_spacing(10); // Summary frame (time & data) frame = manage(new Gtk::Frame(_(" Summary "))); table = manage(new Gtk::Table(2, 2, false)); table->set_border_width(5); table->set_row_spacings(5); table->set_col_spacings(5); label = manage(new Gtk::Label(_("Tracks:"))); table->attach(*label, 0, 1, 0, 1, Gtk::SHRINK); table->attach(*nofTracks_, 1, 2, 0, 1, Gtk::FILL | Gtk::SHRINK); label = manage(new Gtk::Label(_("Length:"))); table->attach(*label, 0, 1, 1, 2, Gtk::SHRINK); table->attach(*tocLength_, 1, 2, 1, 2, Gtk::FILL | Gtk::SHRINK); frame->add(*table); contents->pack_start(*frame, false, false); // Sub-channel frame frame = manage(new Gtk::Frame(_(" Sub-Channel "))); table = manage(new Gtk::Table(2, 2, false)); table->set_border_width(5); table->set_row_spacings(5); table->set_col_spacings(5); label = manage(new Gtk::Label(_("Toc Type: "))); table->attach(*label, 0, 1, 0, 1, Gtk::SHRINK); table->attach(tocType_, 1, 2, 0, 1); label = manage(new Gtk::Label("UPC/EAN: ")); table->attach(*label, 0, 1, 1, 2, Gtk::SHRINK); table->attach(*catalog_, 1, 2, 1, 2); frame->add(*table); contents->pack_start(*frame, Gtk::PACK_SHRINK); // CD-TEXT data frame = manage(new Gtk::Frame(" CD-TEXT ")); Gtk::Notebook *notebook = manage(new Gtk::Notebook); for (i = 0; i < 8; i++) { vbox = createCdTextPage(i); notebook->append_page(*vbox, *(cdTextPages_[i].label)); } vbox1 = manage(new Gtk::VBox); vbox1->pack_start(*notebook, false, false, 5); hbox = manage(new Gtk::HBox); hbox->pack_start(*vbox1, true, true, 5); frame->add(*hbox); contents->pack_start(*frame, Gtk::PACK_SHRINK); hbox = manage(new Gtk::HBox); hbox->pack_start(*contents, true, true, 10); get_vbox()->pack_start(*hbox, true, true, 10); Gtk::HButtonBox *bbox = manage(new Gtk::HButtonBox(Gtk::BUTTONBOX_SPREAD)); applyButton_ = manage(new Gtk::Button(Gtk::StockID(Gtk::Stock::APPLY))); bbox->pack_start(*applyButton_); applyButton_->signal_clicked().connect( sigc::mem_fun(*this, &TocInfoDialog::applyAction)); button = manage(new Gtk::Button(Gtk::StockID(Gtk::Stock::CLOSE))); bbox->pack_start(*button); button->signal_clicked().connect( sigc::mem_fun(*this, &TocInfoDialog::closeAction)); get_action_area()->pack_start(*bbox); show_all_children(); set_title(_("Project Info")); set_transient_for(*parent); } TocInfoDialog::~TocInfoDialog() { } void TocInfoDialog::start(TocEdit *view) { present(); active_ = true; update(UPD_ALL, view); } void TocInfoDialog::stop() { hide(); active_ = false; } void TocInfoDialog::setSelectedTocType() { if (tocType_.get_active_text() == TOC_TYPE_CD_DA) { selectedTocType_ = Toc::Type::CD_DA; } else if (tocType_.get_active_text() == TOC_TYPE_CD_ROM) { selectedTocType_ = Toc::Type::CD_ROM; } else if (tocType_.get_active_text() == TOC_TYPE_CD_ROM_XA) { selectedTocType_ = Toc::Type::CD_ROM_XA; } else if (tocType_.get_active_text() == TOC_TYPE_CD_I) { selectedTocType_ = Toc::Type::CD_I; } } void TocInfoDialog::setSelectedCDTextLanguage(int block) { int i; if (block < 0 || block >= 8) return; int value = cdTextPages_[block].language->get_active_row_number(); if (value <= 0) { // cannot set to 'unknown' or invalid value, restore old setting if (cdTextPages_[block].selectedLanguage != 0) cdTextPages_[block].language->set_active( cdTextPages_[block].selectedLanguage); return; } if (value != 1) { // check if same language is already used bool found = false; for (i = 0; i < 8; i++) { if (i != block && cdTextPages_[i].selectedLanguage == value) { found = true; break; } } if (found || (block > 0 && cdTextPages_[block - 1].selectedLanguage == 1)) { // reset to old value if the same language is already used or // if the language of the previous block is undefined cdTextPages_[block].language->set_active( cdTextPages_[block].selectedLanguage); return; } } cdTextPages_[block].selectedLanguage = value; } void TocInfoDialog::setSelectedCDTextGenre(int block) { if (block < 0 || block >= 8) return; int value = cdTextPages_[block].genre->get_active_row_number(); if (value <= 0) { // cannot set to 'unknown', restore old setting if (cdTextPages_[block].selectedGenre != 0) cdTextPages_[block].genre->set_active( cdTextPages_[block].selectedGenre); return; } cdTextPages_[block].selectedGenre = value; } void TocInfoDialog::createCdTextLanguageMenu(int n) { cdTextPages_[n].language = manage(new Gtk::ComboBoxText); for (int i = 0; i < MAX_CD_TEXT_LANGUAGE_CODES; i++) { cdTextPages_[n].language->append(CD_TEXT_LANGUAGE_CODES[i].name); } cdTextPages_[n].language->show(); cdTextPages_[n].language->signal_changed().connect( bind(mem_fun(*this, &TocInfoDialog::setSelectedCDTextLanguage), n)); } void TocInfoDialog::createCdTextGenreMenu(int n) { cdTextPages_[n].genre = manage(new Gtk::ComboBoxText); for (int i = 0; i < MAX_CD_TEXT_GENRE_CODES; ++i) { cdTextPages_[n].genre->append(CD_TEXT_GENRE_CODES[i].name); } cdTextPages_[n].genre->signal_changed().connect( bind(mem_fun(*this, &TocInfoDialog::setSelectedCDTextGenre), n)); } Gtk::VBox *TocInfoDialog::createCdTextPage(int n) { char buf[20]; Gtk::Table *table = manage(new Gtk::Table(11, 2, false)); Gtk::VBox *vbox1; Gtk::HBox *hbox; Gtk::Label *label; snprintf(buf, sizeof(buf)," %d ", n); cdTextPages_[n].label = manage(new Gtk::Label(buf)); cdTextPages_[n].label->show(); cdTextPages_[n].title = manage(new Gtk::Entry); cdTextPages_[n].performer = manage(new Gtk::Entry); cdTextPages_[n].songwriter = manage(new Gtk::Entry); cdTextPages_[n].composer = manage(new Gtk::Entry); cdTextPages_[n].arranger = manage(new Gtk::Entry); cdTextPages_[n].message = manage(new Gtk::Entry); cdTextPages_[n].catalog = manage(new Gtk::Entry); cdTextPages_[n].upcEan = manage(new Gtk::Entry); cdTextPages_[n].genreInfo = manage(new Gtk::Entry); createCdTextLanguageMenu(n); createCdTextGenreMenu(n); table->set_row_spacings(5); table->set_col_spacings(5); table->show(); label = manage(new Gtk::Label(_("Language:"))); hbox = manage(new Gtk::HBox); hbox->pack_end(*label, Gtk::PACK_SHRINK); table->attach(*hbox, 0, 1, 0, 1, Gtk::FILL); hbox->show(); label->show(); table->attach(*(cdTextPages_[n].language), 1, 2, 0, 1); cdTextPages_[n].language->show(); label = manage(new Gtk::Label(_("Title:"))); hbox = manage(new Gtk::HBox); hbox->pack_end(*label, Gtk::PACK_SHRINK); table->attach(*hbox, 0, 1, 1, 2, Gtk::FILL); hbox->show(); label->show(); table->attach(*(cdTextPages_[n].title), 1, 2, 1, 2); cdTextPages_[n].title->show(); label = manage(new Gtk::Label(_("Performer:"))); hbox = manage(new Gtk::HBox); hbox->pack_end(*label, Gtk::PACK_SHRINK); table->attach(*hbox, 0, 1, 2, 3, Gtk::FILL); hbox->show(); label->show(); table->attach(*(cdTextPages_[n].performer), 1, 2, 2, 3); cdTextPages_[n].performer->show(); label = new Gtk::Label(_("Songwriter:")); hbox = manage(new Gtk::HBox); hbox->pack_end(*label, Gtk::PACK_SHRINK); table->attach(*hbox, 0, 1, 3, 4, Gtk::FILL); hbox->show(); label->show(); table->attach(*(cdTextPages_[n].songwriter), 1, 2, 3, 4); cdTextPages_[n].songwriter->show(); label = new Gtk::Label(_("Composer:")); hbox = manage(new Gtk::HBox); hbox->pack_end(*label, Gtk::PACK_SHRINK); table->attach(*hbox, 0, 1, 4, 5, Gtk::FILL); hbox->show(); label->show(); table->attach(*(cdTextPages_[n].composer), 1, 2, 4, 5); cdTextPages_[n].composer->show(); label = new Gtk::Label(_("Arranger:")); hbox = manage(new Gtk::HBox); hbox->pack_end(*label, Gtk::PACK_SHRINK); table->attach(*hbox, 0, 1, 5, 6, Gtk::FILL); hbox->show(); label->show(); table->attach(*(cdTextPages_[n].arranger), 1, 2, 5, 6); cdTextPages_[n].arranger->show(); label = new Gtk::Label(_("Message:")); hbox = manage(new Gtk::HBox); hbox->pack_end(*label, Gtk::PACK_SHRINK); table->attach(*hbox, 0, 1, 6, 7, Gtk::FILL); hbox->show(); label->show(); table->attach(*(cdTextPages_[n].message), 1, 2, 6, 7); cdTextPages_[n].message->show(); label = new Gtk::Label(_("Catalog:")); hbox = manage(new Gtk::HBox); hbox->pack_end(*label, Gtk::PACK_SHRINK); table->attach(*hbox, 0, 1, 7, 8, Gtk::FILL); hbox->show(); label->show(); table->attach(*(cdTextPages_[n].catalog), 1, 2, 7, 8); cdTextPages_[n].catalog->show(); label = new Gtk::Label("UPC/EAN:"); hbox = manage(new Gtk::HBox); hbox->pack_end(*label, Gtk::PACK_SHRINK); table->attach(*hbox, 0, 1, 8, 9, Gtk::FILL); hbox->show(); label->show(); table->attach(*(cdTextPages_[n].upcEan), 1, 2, 8, 9); cdTextPages_[n].upcEan->show(); label = new Gtk::Label(_("Genre:")); hbox = manage(new Gtk::HBox); hbox->pack_end(*label, Gtk::PACK_SHRINK); table->attach(*hbox, 0, 1, 9, 10, Gtk::FILL); hbox->show(); label->show(); table->attach(*(cdTextPages_[n].genre), 1, 2, 9, 10); cdTextPages_[n].genre->show(); label = new Gtk::Label(_("Genre Info:")); hbox = manage(new Gtk::HBox); hbox->pack_end(*label, Gtk::PACK_SHRINK); table->attach(*hbox, 0, 1, 10, 11, Gtk::FILL); hbox->show(); label->show(); table->attach(*(cdTextPages_[n].genreInfo), 1, 2, 10, 11); cdTextPages_[n].genreInfo->show(); hbox = manage(new Gtk::HBox); hbox->pack_start(*table, true, true, 3); table->show(); vbox1 = manage(new Gtk::VBox); vbox1->pack_start(*hbox, true, true, 3); hbox->show(); vbox1->show(); return vbox1; } bool TocInfoDialog::on_delete_event(GdkEventAny*) { stop(); return 1; } void TocInfoDialog::closeAction() { stop(); } void TocInfoDialog::clear() { nofTracks_->set_text(""); tocLength_->set_text(""); tocType_.set_active(0); selectedTocType_ = Toc::Type::CD_DA; catalog_->set_text(""); catalog_->set_editable(false); clearCdText(); } void TocInfoDialog::update(unsigned long level, TocEdit *view) { const Toc *toc; if (!active_) return; tocEdit_ = view; if (view == NULL) { clear(); return; } std::string s(view->filename()); s += " - "; s += APP_NAME; if (view->tocDirty()) s += "(*)"; set_title(s); if (level & UPD_TOC_DATA) { toc = tocEdit_->toc(); importData(toc); } if (level & UPD_EDITABLE_STATE) { applyButton_->set_sensitive(tocEdit_->editable() ? true : false); } } void TocInfoDialog::clearCdText() { int l; for (l = 0; l < 8; l++) { cdTextPages_[l].title->set_text(""); cdTextPages_[l].title->set_editable(false); cdTextPages_[l].performer->set_text(""); cdTextPages_[l].performer->set_editable(false); cdTextPages_[l].songwriter->set_text(""); cdTextPages_[l].songwriter->set_editable(false); cdTextPages_[l].composer->set_text(""); cdTextPages_[l].composer->set_editable(false); cdTextPages_[l].arranger->set_text(""); cdTextPages_[l].arranger->set_editable(false); cdTextPages_[l].message->set_text(""); cdTextPages_[l].message->set_editable(false); cdTextPages_[l].catalog->set_text(""); cdTextPages_[l].catalog->set_editable(false); cdTextPages_[l].upcEan->set_text(""); cdTextPages_[l].upcEan->set_editable(false); cdTextPages_[l].language->set_active(1); cdTextPages_[l].selectedLanguage = 1; cdTextPages_[l].genre->set_active(1); cdTextPages_[l].selectedGenre = 1; } } void TocInfoDialog::applyAction() { if (tocEdit_ == NULL || !tocEdit_->editable()) return; exportData(tocEdit_); guiUpdate(UPD_TOC_DATA); } const char *TocInfoDialog::checkString(const std::string &str) { static char *buf = NULL; static long bufLen = 0; char *p, *s; long len = strlen(str.c_str()); if (len == 0) return NULL; if (buf == NULL || len + 1 > bufLen) { delete[] buf; bufLen = len + 1; buf = new char[bufLen]; } strcpy(buf, str.c_str()); s = buf; p = buf + len - 1; while (*s != 0 && isspace(*s)) s++; if (*s == 0) return NULL; while (p > s && isspace(*p)) { *p = 0; p--; } return s; } int TocInfoDialog::getCdTextLanguageIndex(int code) { int i; if (code < 0) return 1; // undefined for (i = 2; i < MAX_CD_TEXT_LANGUAGE_CODES; i++) { if (CD_TEXT_LANGUAGE_CODES[i].code == code) return i; } return 0; // unknown } int TocInfoDialog::getCdTextGenreIndex(int code1, int code2) { int i; for (i = 2; i < MAX_CD_TEXT_GENRE_CODES; i++) { if (CD_TEXT_GENRE_CODES[i].code1 == code1 && CD_TEXT_GENRE_CODES[i].code2 == code2) return i; } return 0; } void TocInfoDialog::importCdText(const Toc *toc) { int l; const CdTextItem *item; for (l = 0; l < 8; l++) { if ((item = toc->getCdTextItem(0, l, CdTextItem::PackType::TITLE)) != NULL) cdTextPages_[l].title->set_text((const char*) (item->data())); else cdTextPages_[l].title->set_text(""); cdTextPages_[l].title->set_editable(true); if ((item = toc->getCdTextItem(0, l, CdTextItem::PackType::PERFORMER)) != NULL) cdTextPages_[l].performer->set_text((const char*) (item->data())); else cdTextPages_[l].performer->set_text(""); cdTextPages_[l].performer->set_editable(true); if ((item = toc->getCdTextItem(0, l, CdTextItem::PackType::SONGWRITER)) != NULL) cdTextPages_[l].songwriter->set_text((const char*) (item->data())); else cdTextPages_[l].songwriter->set_text(""); cdTextPages_[l].songwriter->set_editable(true); if ((item = toc->getCdTextItem(0, l, CdTextItem::PackType::COMPOSER)) != NULL) cdTextPages_[l].composer->set_text((const char*) (item->data())); else cdTextPages_[l].composer->set_text(""); cdTextPages_[l].composer->set_editable(true); if ((item = toc->getCdTextItem(0, l, CdTextItem::PackType::ARRANGER)) != NULL) cdTextPages_[l].arranger->set_text((const char*) (item->data())); else cdTextPages_[l].arranger->set_text(""); cdTextPages_[l].arranger->set_editable(true); if ((item = toc->getCdTextItem(0, l, CdTextItem::PackType::MESSAGE)) != NULL) cdTextPages_[l].message->set_text((const char*) (item->data())); else cdTextPages_[l].message->set_text(""); cdTextPages_[l].message->set_editable(true); if ((item = toc->getCdTextItem(0, l, CdTextItem::PackType::DISK_ID)) != NULL) cdTextPages_[l].catalog->set_text((const char*) (item->data())); else cdTextPages_[l].catalog->set_text(""); cdTextPages_[l].catalog->set_editable(true); if ((item = toc->getCdTextItem(0, l, CdTextItem::PackType::UPCEAN_ISRC)) != NULL) cdTextPages_[l].upcEan->set_text((const char*) (item->data())); else cdTextPages_[l].upcEan->set_text(""); cdTextPages_[l].upcEan->set_editable(true); if ((item = toc->getCdTextItem(0, l, CdTextItem::PackType::GENRE)) != NULL) { if (item->dataLen() >= 2) { cdTextPages_[l].selectedGenre = getCdTextGenreIndex(item->data()[0], item->data()[1]); } else { cdTextPages_[l].selectedGenre = 0; // Unknwon } if (item->dataLen() > 2) { // Copy the supplementary genre information from the CD-TEXT item. // Carefully handle the case that the terminating 0 is missing. int len = item->dataLen() - 2 + 1; char *s = new char[len]; memcpy(s, item->data() + 2, len - 1); s[len - 1] = 0; cdTextPages_[l].genreInfo->set_text(s); delete[] s; } else { cdTextPages_[l].genreInfo->set_text(""); } } else { cdTextPages_[l].selectedGenre = 1; // not used cdTextPages_[l].genreInfo->set_text(""); } cdTextPages_[l].genre->set_active(cdTextPages_[l].selectedGenre); cdTextPages_[l].selectedLanguage = getCdTextLanguageIndex( toc->cdTextLanguage(l)); cdTextPages_[l].language->set_active(cdTextPages_[l].selectedLanguage); } } void TocInfoDialog::importData(const Toc *toc) { char buf[50]; int i; snprintf(buf, sizeof(buf),"%3d:%02d:%02d", toc->length().min(), toc->length().sec(), toc->length().frac()); tocLength_->set_text(buf); snprintf(buf, sizeof(buf),"%3d", toc->nofTracks()); nofTracks_->set_text(buf); if (toc->catalogValid()) { for (i = 0; i < 13; i++) buf[i] = toc->catalog(i) + '0'; buf[13] = 0; catalog_->set_text(buf); } else { catalog_->set_text(""); } catalog_->set_editable(true); switch (toc->tocType()) { case Toc::Type::CD_DA: tocType_.set_active(0); break; case Toc::Type::CD_ROM: tocType_.set_active(1); break; case Toc::Type::CD_ROM_XA: tocType_.set_active(2); break; case Toc::Type::CD_I: tocType_.set_active(3); break; } selectedTocType_ = toc->tocType(); importCdText(toc); } void TocInfoDialog::exportData(TocEdit *tocEdit) { const char *s, *s1; Toc *toc = tocEdit->toc(); if (toc->tocType() != selectedTocType_) { tocEdit->setTocType(selectedTocType_); } s = checkString(catalog_->get_text()); if (s == NULL) { if (toc->catalogValid()) tocEdit->setCatalogNumber(NULL); } else if (strlen(s) == 13) { if ((s1 = toc->catalog()) == NULL || strcmp(s1, s) != 0) tocEdit->setCatalogNumber(s); } exportCdText(tocEdit); } void TocInfoDialog::exportCdText(TocEdit *tocEdit) { int l; const char *s; const Toc *toc = tocEdit->toc(); const CdTextItem *item; CdTextItem *newItem; for (l = 0; l < 8; l++) { // Title if ((s = checkString(cdTextPages_[l].title->get_text())) != NULL) { newItem = new CdTextItem(CdTextItem::PackType::TITLE, l); newItem->setText(s); } else newItem = NULL; if ((item = toc->getCdTextItem(0, l, CdTextItem::PackType::TITLE)) != NULL) { if (newItem == NULL) tocEdit->setCdTextItem(0, CdTextItem::PackType::TITLE, l, NULL); else if (*newItem != *item) tocEdit->setCdTextItem(0, CdTextItem::PackType::TITLE, l, s); } else if (newItem != NULL) { tocEdit->setCdTextItem(0, CdTextItem::PackType::TITLE, l, s); } delete newItem; // Performer if ((s = checkString(cdTextPages_[l].performer->get_text())) != NULL) { newItem = new CdTextItem(CdTextItem::PackType::PERFORMER, l); newItem->setText(s); } else newItem = NULL; if ((item = toc->getCdTextItem(0, l, CdTextItem::PackType::PERFORMER)) != NULL) { if (newItem == NULL) tocEdit->setCdTextItem(0, CdTextItem::PackType::PERFORMER, l, NULL); else if (*newItem != *item) tocEdit->setCdTextItem(0, CdTextItem::PackType::PERFORMER, l, s); } else if (newItem != NULL) { tocEdit->setCdTextItem(0, CdTextItem::PackType::PERFORMER, l, s); } delete newItem; // Songwriter if ((s = checkString(cdTextPages_[l].songwriter->get_text())) != NULL) { newItem = new CdTextItem(CdTextItem::PackType::SONGWRITER, l); newItem->setText(s); } else newItem = NULL; if ((item = toc->getCdTextItem(0, l, CdTextItem::PackType::SONGWRITER)) != NULL) { if (newItem == NULL) tocEdit->setCdTextItem(0, CdTextItem::PackType::SONGWRITER, l, NULL); else if (*newItem != *item) tocEdit->setCdTextItem(0, CdTextItem::PackType::SONGWRITER, l, s); } else if (newItem != NULL) { tocEdit->setCdTextItem(0, CdTextItem::PackType::SONGWRITER, l, s); } delete newItem; // Composer if ((s = checkString(cdTextPages_[l].composer->get_text())) != NULL) { newItem = new CdTextItem(CdTextItem::PackType::COMPOSER, l); newItem->setText(s); } else newItem = NULL; if ((item = toc->getCdTextItem(0, l, CdTextItem::PackType::COMPOSER)) != NULL) { if (newItem == NULL) tocEdit->setCdTextItem(0, CdTextItem::PackType::COMPOSER, l, NULL); else if (*newItem != *item) tocEdit->setCdTextItem(0, CdTextItem::PackType::COMPOSER, l, s); } else if (newItem != NULL) { tocEdit->setCdTextItem(0, CdTextItem::PackType::COMPOSER, l, s); } delete newItem; // Arranger if ((s = checkString(cdTextPages_[l].arranger->get_text())) != NULL) { newItem = new CdTextItem(CdTextItem::PackType::ARRANGER, l); newItem->setText(s); } else newItem = NULL; if ((item = toc->getCdTextItem(0, l, CdTextItem::PackType::ARRANGER)) != NULL) { if (newItem == NULL) tocEdit->setCdTextItem(0, CdTextItem::PackType::ARRANGER, l, NULL); else if (*newItem != *item) tocEdit->setCdTextItem(0, CdTextItem::PackType::ARRANGER, l, s); } else if (newItem != NULL) { tocEdit->setCdTextItem(0, CdTextItem::PackType::ARRANGER, l, s); } delete newItem; // Message if ((s = checkString(cdTextPages_[l].message->get_text())) != NULL) { newItem = new CdTextItem(CdTextItem::PackType::MESSAGE, l); newItem->setText(s); } else newItem = NULL; if ((item = toc->getCdTextItem(0, l, CdTextItem::PackType::MESSAGE)) != NULL) { if (newItem == NULL) tocEdit->setCdTextItem(0, CdTextItem::PackType::MESSAGE, l, NULL); else if (*newItem != *item) tocEdit->setCdTextItem(0, CdTextItem::PackType::MESSAGE, l, s); } else if (newItem != NULL) { tocEdit->setCdTextItem(0, CdTextItem::PackType::MESSAGE, l, s); } delete newItem; // Catalog if ((s = checkString(cdTextPages_[l].catalog->get_text())) != NULL) { newItem = new CdTextItem(CdTextItem::PackType::DISK_ID, l); newItem->setText(s); } else newItem = NULL; if ((item = toc->getCdTextItem(0, l, CdTextItem::PackType::DISK_ID)) != NULL) { if (newItem == NULL) tocEdit->setCdTextItem(0, CdTextItem::PackType::DISK_ID, l, NULL); else if (*newItem != *item) tocEdit->setCdTextItem(0, CdTextItem::PackType::DISK_ID, l, s); } else if (newItem != NULL) { tocEdit->setCdTextItem(0, CdTextItem::PackType::DISK_ID, l, s); } delete newItem; // Upc/Ean if ((s = checkString(cdTextPages_[l].upcEan->get_text())) != NULL) { newItem = new CdTextItem(CdTextItem::PackType::UPCEAN_ISRC, l); newItem->setText(s); } else newItem = NULL; if ((item = toc->getCdTextItem(0, l, CdTextItem::PackType::UPCEAN_ISRC)) != NULL) { if (newItem == NULL) tocEdit->setCdTextItem(0, CdTextItem::PackType::UPCEAN_ISRC, l, NULL); else if (*newItem != *item) tocEdit->setCdTextItem(0, CdTextItem::PackType::UPCEAN_ISRC, l, s); } else if (newItem != NULL) { tocEdit->setCdTextItem(0, CdTextItem::PackType::UPCEAN_ISRC, l, s); } delete newItem; // Genre if (cdTextPages_[l].selectedGenre != 0) { int code1 = CD_TEXT_GENRE_CODES[cdTextPages_[l].selectedGenre].code1; int code2 = CD_TEXT_GENRE_CODES[cdTextPages_[l].selectedGenre].code2; s = checkString(cdTextPages_[l].genreInfo->get_text()); if (cdTextPages_[l].selectedGenre > 1) { newItem = new CdTextItem(CdTextItem::PackType::GENRE, l); newItem->setGenre(code1, code2, s); } else newItem = NULL; if ((item = toc->getCdTextItem(0, l, CdTextItem::PackType::GENRE)) != NULL) { if (newItem == NULL) tocEdit->setCdTextGenreItem(l, -1, -1, NULL); else if (*newItem != *item) tocEdit->setCdTextGenreItem(l, code1, code2, s); } else if (newItem != NULL) { tocEdit->setCdTextGenreItem(l, code1, code2, s); } delete newItem; } // language if (cdTextPages_[l].selectedLanguage != 0) { int langCode = CD_TEXT_LANGUAGE_CODES[cdTextPages_[l].selectedLanguage].code; if (langCode != toc->cdTextLanguage(l)) tocEdit->setCdTextLanguage(l, langCode); } } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/TocInfoDialog.h�����������������������������������������������������0000664�0000000�0000000�00000005310�15114537466�0021500�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2000 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __TOC_INFO_DIALOG_H__ #define __TOC_INFO_DIALOG_H__ #include <gtkmm.h> #include <gtk/gtk.h> #include "Toc.h" class TocEdit; class TextEdit; class TocInfoDialog : public Gtk::Dialog { public: TocInfoDialog(Gtk::Window* parent); ~TocInfoDialog(); bool on_delete_event(GdkEventAny*); void update(unsigned long, TocEdit *); void start(TocEdit *); void stop(); private: TocEdit *tocEdit_; bool active_; Gtk::Button *applyButton_; Gtk::Label *tocLength_; Gtk::Label *nofTracks_; TextEdit *catalog_; //Tree model columns: class ModelColumns : public Gtk::TreeModel::ColumnRecord { public: ModelColumns() { add(m_col_id); add(m_col_name); } Gtk::TreeModelColumn<int> m_col_id; Gtk::TreeModelColumn<Glib::ustring> m_col_name; }; Gtk::ComboBoxText tocType_; Toc::Type selectedTocType_; struct BlockValue { int block; int value; }; struct CdTextPage { Gtk::ComboBoxText *language; int selectedLanguage; Gtk::ComboBoxText *genre; int selectedGenre; Gtk::Label *label; Gtk::Entry *title; Gtk::Entry *performer; Gtk::Entry *songwriter; Gtk::Entry *composer; Gtk::Entry *arranger; Gtk::Entry *message; Gtk::Entry *catalog; Gtk::Entry *upcEan; Gtk::Entry *genreInfo; }; CdTextPage cdTextPages_[8]; void closeAction(); void applyAction(); void createCdTextLanguageMenu(int); void createCdTextGenreMenu(int n); Gtk::VBox *createCdTextPage(int); void clear(); void clearCdText(); const char *checkString(const std::string &); int getCdTextLanguageIndex(int code); int getCdTextGenreIndex(int code1, int code2); void importCdText(const Toc *); void importData(const Toc *); void exportCdText(TocEdit *); void exportData(TocEdit *); void setSelectedTocType(); void setSelectedCDTextLanguage(int); void setSelectedCDTextGenre(int); }; #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/TrackDataScrap.cc���������������������������������������������������0000664�0000000�0000000�00000005500�15114537466�0022005�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.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 * (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. */ #include "TrackDataScrap.h" #include <stddef.h> #include "util.h" #include "TrackData.h" #include "TrackDataList.h" TrackDataScrap::TrackDataScrap(TrackDataList *l) { list_ = l; blocks_ = 0; leftNegSamples_ = NULL; leftPosSamples_ = NULL; rightNegSamples_ = NULL; rightPosSamples_ = NULL; } TrackDataScrap::~TrackDataScrap() { delete list_; list_ = NULL; delete[] leftNegSamples_; leftNegSamples_ = NULL; delete[] leftPosSamples_; leftPosSamples_ = NULL; delete[] rightNegSamples_; rightNegSamples_ = NULL; delete[] rightPosSamples_; rightPosSamples_ = NULL; } const TrackDataList *TrackDataScrap::trackDataList() const { return (const TrackDataList*)list_; } void TrackDataScrap::setPeaks(long blocks, short *leftNegSamples, short *leftPosSamples, short *rightNegSamples, short *rightPosSamples) { long i; blocks_ = blocks; delete[] leftNegSamples_; delete[] leftPosSamples_; delete[] rightNegSamples_; delete[] rightPosSamples_; if (blocks > 0) { leftNegSamples_ = new short[blocks]; leftPosSamples_ = new short[blocks]; rightNegSamples_ = new short[blocks]; rightPosSamples_ = new short[blocks]; for (i = 0; i < blocks; i++) { leftNegSamples_[i] = leftNegSamples[i]; leftPosSamples_[i] = leftPosSamples[i]; rightNegSamples_[i] = rightNegSamples[i]; rightPosSamples_[i] = rightPosSamples[i]; } } else { leftNegSamples_ = NULL; leftPosSamples_ = NULL; rightNegSamples_ = NULL; rightPosSamples_ = NULL; } } void TrackDataScrap::getPeaks(long blocks, short *leftNegSamples, short *leftPosSamples, short *rightNegSamples, short *rightPosSamples) const { long n, i; if (leftNegSamples_ == NULL) return; n = (blocks_ < blocks) ? blocks_ : blocks; for (i = 0; i < n; i++) { leftNegSamples[i] = leftNegSamples_[i]; leftPosSamples[i] = leftPosSamples_[i]; rightNegSamples[i] = rightNegSamples_[i]; rightPosSamples[i] = rightPosSamples_[i]; } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/TrackDataScrap.h����������������������������������������������������0000664�0000000�0000000�00000003614�15114537466�0021653�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998, 1999 Andreas Mueller <mueller@daneb.ping.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 * (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. */ /* * $Log: TrackDataScrap.h,v $ * Revision 1.2 2004/02/12 01:13:32 poolshark * Merge from gnome2 branch * * Revision 1.1.1.1.6.1 2004/01/05 00:34:03 poolshark * First checking of gnome2 port * * Revision 1.1.1.1 2003/12/09 05:32:28 denis * Fooya * * Revision 1.1.1.1 2000/02/05 01:38:55 llanero * Uploaded cdrdao 1.1.3 with pre10 patch applied. * * Revision 1.1 1999/08/27 18:39:38 mueller * Initial revision * */ #ifndef __TRACK_DATA_SCRAP_H__ #define __TRACK_DATA_SCRAP_H__ class TrackDataList; class TrackDataScrap { public: TrackDataScrap(TrackDataList *); ~TrackDataScrap(); const TrackDataList *trackDataList() const; void setPeaks(long blocks, short *leftNegSamples, short *leftPosSamples, short *rightNegSamples, short *rightPosSamples); void getPeaks(long blocks, short *leftNegSamples, short *leftPosSamples, short *rightNegSamples, short *rightPosSamples) const; private: TrackDataList *list_; long blocks_; short *leftNegSamples_; short *leftPosSamples_; short *rightNegSamples_; short *rightPosSamples_; }; #endif ��������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/TrackInfoDialog.cc��������������������������������������������������0000664�0000000�0000000�00000055413�15114537466�0022166�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2000 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #include "config.h" #include "TrackInfoDialog.h" #include <glibmm/i18n.h> #include <stdio.h> #include <stddef.h> #include <string.h> #include <ctype.h> #include "TocEdit.h" #include "TocEditView.h" #include "guiUpdate.h" #include "Toc.h" #include "Track.h" #include "CdTextItem.h" #include "TextEdit.h" TrackInfoDialog::TrackInfoDialog() { int i; Gtk::Label *label, *label1; Gtk::HBox *hbox; Gtk::VBox *vbox, *vbox1; Gtk::Frame *frame; Gtk::Table *table; Gtk::Button *button; Gtk::VBox *contents = manage(new Gtk::VBox); Gtk::HBox *topBox = manage(new Gtk::HBox); tocEditView_ = NULL; active_ = 0; trackNr_ = 0; trackNr_ = new Gtk::Label("99"); pregapLen_ = new Gtk::Label("100:00:00"); trackStart_ = new Gtk::Label("100:00:00"); trackEnd_ = new Gtk::Label("100:00:00"); trackLen_ = new Gtk::Label("100:00:00"); indexMarks_ = new Gtk::Label("99"); copyFlag_ = new Gtk::CheckButton(_("Copy")); preEmphasisFlag_ = new Gtk::CheckButton(_("Pre Emphasis")); twoChannelAudio_ = new Gtk::RadioButton(_("Two Channel Audio")); fourChannelAudio_ = new Gtk::RadioButton(_("Four Channel Audio")); Gtk::RadioButton::Group rbgroup = twoChannelAudio_->get_group(); fourChannelAudio_->set_group(rbgroup); isrcCodeCountry_ = manage(new TextEdit("XX")); isrcCodeCountry_->set_max_length(2); isrcCodeCountry_->lowerCase(0); isrcCodeCountry_->space(0); isrcCodeCountry_->digits(0); isrcCodeOwner_ = manage(new TextEdit("XXX")); isrcCodeOwner_->set_max_length(3); isrcCodeOwner_->lowerCase(0); isrcCodeOwner_->space(0); isrcCodeYear_ = manage(new TextEdit("00")); isrcCodeYear_->set_max_length(2); isrcCodeYear_->lowerCase(0); isrcCodeYear_->upperCase(0); isrcCodeYear_->space(0); isrcCodeSerial_ = manage(new TextEdit("00000")); isrcCodeSerial_->set_max_length(5); isrcCodeSerial_->lowerCase(0); isrcCodeSerial_->upperCase(0); isrcCodeSerial_->space(0); topBox->set_spacing(5); contents->set_spacing(10); hbox = manage(new Gtk::HBox); label = new Gtk::Label(_("Track: ")); hbox->pack_start(*label, FALSE, FALSE); hbox->pack_start(*trackNr_, FALSE, FALSE); contents->pack_start(*hbox, FALSE, FALSE); // time data frame = new Gtk::Frame(_(" Summary ")); table = new Gtk::Table(5, 2, FALSE); table->set_row_spacings(5); table->set_col_spacings(5); hbox = manage(new Gtk::HBox); hbox->pack_start(*table, FALSE, FALSE, 5); vbox = manage(new Gtk::VBox); vbox->pack_start(*hbox, TRUE, TRUE, 5); frame->add(*vbox); label = new Gtk::Label(_("Pre-Gap:")); hbox = manage(new Gtk::HBox); hbox->pack_end(*label, FALSE, FALSE); table->attach(*hbox, 0, 1, 0, 1); hbox = manage(new Gtk::HBox); hbox->pack_start(*pregapLen_, FALSE, FALSE); table->attach(*hbox, 1, 2, 0, 1); label = new Gtk::Label(_("Start:")); hbox = manage(new Gtk::HBox); hbox->pack_end(*label, FALSE, FALSE); table->attach(*hbox, 0, 1, 1, 2); hbox = manage(new Gtk::HBox); hbox->pack_start(*trackStart_, FALSE, FALSE); table->attach(*hbox, 1, 2, 1, 2); label = new Gtk::Label(_("End:")); hbox = manage(new Gtk::HBox); hbox->pack_end(*label, FALSE, FALSE); table->attach(*hbox, 0, 1, 2, 3); hbox = manage(new Gtk::HBox); hbox->pack_start(*trackEnd_, FALSE, FALSE); table->attach(*hbox, 1, 2, 2, 3); label = new Gtk::Label(_("Length:")); hbox = manage(new Gtk::HBox); hbox->pack_end(*label, FALSE, FALSE); table->attach(*hbox, 0, 1, 3, 4); hbox = manage(new Gtk::HBox); hbox->pack_start(*trackLen_, FALSE, FALSE); table->attach(*hbox, 1, 2, 3, 4); label = new Gtk::Label(_("Index Marks:")); hbox = manage(new Gtk::HBox); hbox->pack_end(*label, FALSE, FALSE); table->attach(*hbox, 0, 1, 4, 5); hbox = manage(new Gtk::HBox); hbox->pack_start(*indexMarks_, FALSE, FALSE); table->attach(*hbox, 1, 2, 4, 5); topBox->pack_start(*frame, FALSE, FALSE); // sub-channel data frame = new Gtk::Frame(_(" Sub-Channel ")); vbox = manage(new Gtk::VBox); vbox->set_spacing(0); vbox->pack_start(*copyFlag_); vbox->pack_start(*preEmphasisFlag_); vbox->pack_start(*twoChannelAudio_); twoChannelAudio_->set_active(TRUE); vbox->pack_start(*fourChannelAudio_); hbox = manage(new Gtk::HBox); label = new Gtk::Label("ISRC: "); hbox->pack_start(*label, Gtk::PACK_SHRINK); hbox->pack_start(*isrcCodeCountry_, Gtk::PACK_SHRINK); label1 = new Gtk::Label("-"); hbox->pack_start(*label1, Gtk::PACK_SHRINK); hbox->pack_start(*isrcCodeOwner_, Gtk::PACK_SHRINK); label1 = new Gtk::Label("-"); hbox->pack_start(*label1, Gtk::PACK_SHRINK); hbox->pack_start(*isrcCodeYear_, Gtk::PACK_SHRINK); label1 = new Gtk::Label("-"); hbox->pack_start(*label1, Gtk::PACK_SHRINK); hbox->pack_start(*isrcCodeSerial_, Gtk::PACK_SHRINK); vbox->pack_start(*hbox); vbox1 = manage(new Gtk::VBox); vbox1->pack_start(*vbox, TRUE, TRUE, 5); hbox = manage(new Gtk::HBox); hbox->pack_start(*vbox1, TRUE, TRUE, 5); frame->add(*hbox); topBox->pack_start(*frame, Gtk::PACK_SHRINK); contents->pack_start(*topBox, Gtk::PACK_SHRINK); // CD-TEXT data frame = new Gtk::Frame(" CD-TEXT "); Gtk::Notebook *notebook = new Gtk::Notebook; for (i = 0; i < 8; i++) { vbox = createCdTextPage(i); notebook->append_page(*vbox, *(cdTextPages_[i].label)); } vbox1 = manage(new Gtk::VBox); vbox1->pack_start(*notebook, TRUE, TRUE, 5); hbox = manage(new Gtk::HBox); hbox->pack_start(*vbox1, TRUE, TRUE, 5); frame->add(*hbox); contents->pack_start(*frame); hbox = manage(new Gtk::HBox); hbox->pack_start(*contents, TRUE, TRUE, 10); get_vbox()->pack_start(*hbox, TRUE, TRUE, 10); Gtk::HButtonBox *bbox = new Gtk::HButtonBox(Gtk::BUTTONBOX_SPREAD); applyButton_ = new Gtk::Button(Gtk::StockID(Gtk::Stock::APPLY)); bbox->pack_start(*applyButton_); applyButton_->signal_clicked().connect(mem_fun(*this, &TrackInfoDialog::applyAction)); button = new Gtk::Button(Gtk::StockID(Gtk::Stock::CLOSE)); bbox->pack_start(*button); button->signal_clicked().connect(mem_fun(*this, &TrackInfoDialog::closeAction)); get_action_area()->pack_start(*bbox); show_all_children(); set_title(_("Track Info")); } TrackInfoDialog::~TrackInfoDialog() { } void TrackInfoDialog::start(TocEditView *view) { if (active_) { raise(); return; } active_ = 1; update(UPD_ALL, view); show(); } void TrackInfoDialog::stop() { if (active_) { hide(); active_ = 0; } } Gtk::VBox *TrackInfoDialog::createCdTextPage(int n) { char buf[20]; Gtk::Table *table = new Gtk::Table(7, 2, FALSE); Gtk::VBox *vbox = manage(new Gtk::VBox); Gtk::HBox *hbox; Gtk::Label *label; snprintf(buf, sizeof(buf), " %d ", n); cdTextPages_[n].label = new Gtk::Label(buf); cdTextPages_[n].title = manage(new Gtk::Entry); cdTextPages_[n].performer = manage(new Gtk::Entry); cdTextPages_[n].songwriter = manage(new Gtk::Entry); cdTextPages_[n].composer = manage(new Gtk::Entry); cdTextPages_[n].arranger = manage(new Gtk::Entry); cdTextPages_[n].message = manage(new Gtk::Entry); cdTextPages_[n].isrc = manage(new Gtk::Entry); table->set_border_width(5); table->set_row_spacings(5); table->set_col_spacings(5); label = new Gtk::Label(_("Title:")); hbox = manage(new Gtk::HBox); hbox->pack_end(*label, Gtk::PACK_SHRINK); table->attach(*hbox, 0, 1, 0, 1, Gtk::FILL); table->attach(*(cdTextPages_[n].title), 1, 2, 0, 1); label = new Gtk::Label(_("Performer:")); hbox = manage(new Gtk::HBox); hbox->pack_end(*label, Gtk::PACK_SHRINK); table->attach(*hbox, 0, 1, 1, 2, Gtk::FILL); table->attach(*(cdTextPages_[n].performer), 1, 2, 1, 2); label = new Gtk::Label(_("Songwriter:")); hbox = manage(new Gtk::HBox); hbox->pack_end(*label, Gtk::PACK_SHRINK); table->attach(*hbox, 0, 1, 2, 3, Gtk::FILL); table->attach(*(cdTextPages_[n].songwriter), 1, 2, 2, 3); label = new Gtk::Label(_("Composer:")); hbox = manage(new Gtk::HBox); hbox->pack_end(*label, Gtk::PACK_SHRINK); table->attach(*hbox, 0, 1, 3, 4, Gtk::FILL); table->attach(*(cdTextPages_[n].composer), 1, 2, 3, 4); label = new Gtk::Label(_("Arranger:")); hbox = manage(new Gtk::HBox); hbox->pack_end(*label, Gtk::PACK_SHRINK); table->attach(*hbox, 0, 1, 4, 5, Gtk::FILL); table->attach(*(cdTextPages_[n].arranger), 1, 2, 4, 5); label = new Gtk::Label(_("Message:")); hbox = manage(new Gtk::HBox); hbox->pack_end(*label, Gtk::PACK_SHRINK); table->attach(*hbox, 0, 1, 5, 6, Gtk::FILL); table->attach(*(cdTextPages_[n].message), 1, 2, 5, 6); label = new Gtk::Label("ISRC:"); hbox = manage(new Gtk::HBox); hbox->pack_end(*label, Gtk::PACK_SHRINK); table->attach(*hbox, 0, 1, 6, 7, Gtk::FILL); table->attach(*(cdTextPages_[n].isrc), 1, 2, 6, 7); vbox->pack_start(*table); return vbox; } bool TrackInfoDialog::on_delete_event(GdkEventAny*) { stop(); return 1; } void TrackInfoDialog::closeAction() { stop(); } void TrackInfoDialog::clear() { trackNr_->set_text(""); pregapLen_->set_text(""); trackStart_->set_text(""); trackEnd_->set_text(""); trackLen_->set_text(""); indexMarks_->set_text(""); isrcCodeCountry_->set_text(""); isrcCodeCountry_->set_editable(false); isrcCodeOwner_->set_text(""); isrcCodeOwner_->set_editable(false); isrcCodeYear_->set_text(""); isrcCodeYear_->set_editable(false); isrcCodeSerial_->set_text(""); isrcCodeSerial_->set_editable(false); copyFlag_->set_sensitive(false); preEmphasisFlag_->set_sensitive(false); twoChannelAudio_->set_sensitive(false); fourChannelAudio_->set_sensitive(false); clearCdText(); } void TrackInfoDialog::update(unsigned long level, TocEditView *view) { const Toc *toc; if (!active_) return; tocEditView_ = view; if (view == NULL || !view->trackSelection(&selectedTrack_)) { selectedTrack_ = 0; applyButton_->set_sensitive(FALSE); clear(); return; } std::string s(view->tocEdit()->filename()); s += " - "; s += APP_NAME; if (view->tocEdit()->tocDirty()) s += "(*)"; set_title(s); if (level & (UPD_TRACK_DATA | UPD_TRACK_MARK_SEL)) { toc = view->tocEdit()->toc(); importData(toc, selectedTrack_); applyButton_->set_sensitive(view->tocEdit()->editable() ? TRUE : FALSE); } else if (level & UPD_EDITABLE_STATE) { applyButton_->set_sensitive(view->tocEdit()->editable() ? TRUE : FALSE); } } void TrackInfoDialog::clearCdText() { int l; for (l = 0; l < 8; l++) { cdTextPages_[l].title->set_text(""); cdTextPages_[l].title->set_editable(false); cdTextPages_[l].performer->set_text(""); cdTextPages_[l].performer->set_editable(false); cdTextPages_[l].songwriter->set_text(""); cdTextPages_[l].songwriter->set_editable(false); cdTextPages_[l].composer->set_text(""); cdTextPages_[l].composer->set_editable(false); cdTextPages_[l].arranger->set_text(""); cdTextPages_[l].arranger->set_editable(false); cdTextPages_[l].message->set_text(""); cdTextPages_[l].message->set_editable(false); cdTextPages_[l].isrc->set_text(""); cdTextPages_[l].isrc->set_editable(false); } } void TrackInfoDialog::applyAction() { if (tocEditView_ == NULL || !tocEditView_->tocEdit()->editable() || selectedTrack_ == 0) return; exportData(tocEditView_->tocEdit(), selectedTrack_); guiUpdate(UPD_TRACK_DATA); } const char *TrackInfoDialog::checkString(const std::string &str) { static char *buf = NULL; static long bufLen = 0; char *p, *s; long len = strlen(str.c_str()); if (len == 0) return NULL; if (buf == NULL || len + 1 > bufLen) { delete[] buf; bufLen = len + 1; buf = new char[bufLen]; } strcpy(buf, str.c_str()); s = buf; p = buf + len - 1; while (*s != 0 && isspace(*s)) s++; if (*s == 0) return NULL; while (p > s && isspace(*p)) { *p = 0; p--; } return s; } void TrackInfoDialog::importCdText(const Toc *toc, int trackNr) { int l; const CdTextItem *item; for (l = 0; l < 8; l++) { if ((item = toc->getCdTextItem(trackNr, l, CdTextItem::PackType::TITLE)) != NULL) cdTextPages_[l].title->set_text((const char*)item->data()); else cdTextPages_[l].title->set_text(""); cdTextPages_[l].title->set_editable(true); if ((item = toc->getCdTextItem(trackNr, l, CdTextItem::PackType::PERFORMER)) != NULL) cdTextPages_[l].performer->set_text((const char*)item->data()); else cdTextPages_[l].performer->set_text(""); cdTextPages_[l].performer->set_editable(true); if ((item = toc->getCdTextItem(trackNr, l, CdTextItem::PackType::SONGWRITER)) != NULL) cdTextPages_[l].songwriter->set_text((const char*)item->data()); else cdTextPages_[l].songwriter->set_text(""); cdTextPages_[l].songwriter->set_editable(true); if ((item = toc->getCdTextItem(trackNr, l, CdTextItem::PackType::COMPOSER)) != NULL) cdTextPages_[l].composer->set_text((const char*)item->data()); else cdTextPages_[l].composer->set_text(""); cdTextPages_[l].composer->set_editable(true); if ((item = toc->getCdTextItem(trackNr, l, CdTextItem::PackType::ARRANGER)) != NULL) cdTextPages_[l].arranger->set_text((const char*)item->data()); else cdTextPages_[l].arranger->set_text(""); cdTextPages_[l].arranger->set_editable(true); if ((item = toc->getCdTextItem(trackNr, l, CdTextItem::PackType::MESSAGE)) != NULL) cdTextPages_[l].message->set_text((const char*)item->data()); else cdTextPages_[l].message->set_text(""); cdTextPages_[l].message->set_editable(true); if ((item = toc->getCdTextItem(trackNr, l, CdTextItem::PackType::UPCEAN_ISRC)) != NULL) cdTextPages_[l].isrc->set_text((const char*)item->data()); else cdTextPages_[l].isrc->set_text(""); cdTextPages_[l].isrc->set_editable(true); } } void TrackInfoDialog::importData(const Toc *toc, int trackNr) { char buf[50]; TrackIterator itr(toc); Msf start, end; const Track *track = itr.find(trackNr, start, end); if (track == NULL) { clear(); return; } snprintf(buf, sizeof(buf),"%d", trackNr); trackNr_->set_text(buf); snprintf(buf, sizeof(buf),"%3d:%02d:%02d", track->start().min(), track->start().sec(), track->start().frac()); pregapLen_->set_text(buf); snprintf(buf, sizeof(buf),"%3d:%02d:%02d", start.min(), start.sec(), start.frac()); trackStart_->set_text(buf); snprintf(buf, sizeof(buf),"%3d:%02d:%02d", end.min(), end.sec(), end.frac()); trackEnd_->set_text(buf); Msf len(track->length() - track->start()); snprintf(buf, sizeof(buf),"%3d:%02d:%02d", len.min(), len.sec(), len.frac()); trackLen_->set_text(buf); snprintf(buf, sizeof(buf),"%3d", track->nofIndices()); indexMarks_->set_text(buf); copyFlag_->set_sensitive(true); preEmphasisFlag_->set_sensitive(true); twoChannelAudio_->set_sensitive(true); fourChannelAudio_->set_sensitive(true); copyFlag_->set_active(track->copyPermitted()); preEmphasisFlag_->set_active(track->preEmphasis()); if (track->audioType() == 0) twoChannelAudio_->set_active(true); else fourChannelAudio_->set_active(true); if (track->isrcValid()) { snprintf(buf, sizeof(buf),"%c%c", track->isrcCountry(0), track->isrcCountry(1)); isrcCodeCountry_->set_text(buf); snprintf(buf, sizeof(buf),"%c%c%c", track->isrcOwner(0), track->isrcOwner(1), track->isrcOwner(2)); isrcCodeOwner_->set_text(buf); snprintf(buf, sizeof(buf),"%c%c", '0' + track->isrcYear(0), '0' + track->isrcYear(1)); isrcCodeYear_->set_text(buf); snprintf(buf, sizeof(buf),"%c%c%c%c%c", '0' + track->isrcSerial(0), '0' + track->isrcSerial(1), '0' + track->isrcSerial(2), '0' + track->isrcSerial(3), '0' + track->isrcSerial(4)); isrcCodeSerial_->set_text(buf); } else { isrcCodeCountry_->set_text(""); isrcCodeOwner_->set_text(""); isrcCodeYear_->set_text(""); isrcCodeSerial_->set_text(""); } isrcCodeCountry_->set_editable(true); isrcCodeOwner_->set_editable(true); isrcCodeYear_->set_editable(true); isrcCodeSerial_->set_editable(true); importCdText(toc, trackNr); } void TrackInfoDialog::exportData(TocEdit *tocEdit, int trackNr) { char buf[13]; const char *s; Toc *toc = tocEdit->toc(); Track *t = toc->getTrack(trackNr); int flag; if (t == NULL) return; flag = copyFlag_->get_active() ? 1 : 0; if (t->copyPermitted() != flag) tocEdit->setTrackCopyFlag(trackNr, flag); if (t->type() == TrackData::AUDIO) { flag = preEmphasisFlag_->get_active() ? 1 : 0; if (t->preEmphasis() != flag) tocEdit->setTrackPreEmphasisFlag(trackNr, flag); flag = twoChannelAudio_->get_active() ? 0 : 1; if (t->audioType() != flag) tocEdit->setTrackAudioType(trackNr, flag); buf[0] = 0; if ((s = checkString(isrcCodeCountry_->get_text())) != NULL && strlen(s) == 2) { strcat(buf, s); } if ((s = checkString(isrcCodeOwner_->get_text())) != NULL && strlen(s) == 3) { strcat(buf, s); } if ((s = checkString(isrcCodeYear_->get_text())) != NULL && strlen(s) == 2) { strcat(buf, s); } if ((s = checkString(isrcCodeSerial_->get_text())) != NULL && strlen(s) == 5) { strcat(buf, s); } if (strlen(buf) == 0) { if (t->isrcValid()) tocEdit->setTrackIsrcCode(trackNr, NULL); } else if (strlen(buf) == 12) { if ((s = t->isrc()) == NULL || strcmp(s, buf) != 0) tocEdit->setTrackIsrcCode(trackNr, buf); } } exportCdText(tocEdit, trackNr); } void TrackInfoDialog::exportCdText(TocEdit *tocEdit, int trackNr) { int l; const char *s; const Toc *toc = tocEdit->toc(); const CdTextItem *item; CdTextItem *newItem; for (l = 0; l < 8; l++) { // Title if ((s = checkString(cdTextPages_[l].title->get_text())) != NULL) { newItem = new CdTextItem(CdTextItem::PackType::TITLE, l); newItem->setText(s); } else newItem = NULL; if ((item = toc->getCdTextItem(trackNr, l, CdTextItem::PackType::TITLE)) != NULL) { if (newItem == NULL) tocEdit->setCdTextItem(trackNr, CdTextItem::PackType::TITLE, l, NULL); else if (*newItem != *item) tocEdit->setCdTextItem(trackNr, CdTextItem::PackType::TITLE, l, s); } else if (newItem != NULL) { tocEdit->setCdTextItem(trackNr, CdTextItem::PackType::TITLE, l, s); } delete newItem; // Performer if ((s = checkString(cdTextPages_[l].performer->get_text())) != NULL) { newItem = new CdTextItem(CdTextItem::PackType::PERFORMER, l); newItem->setText(s); } else newItem = NULL; if ((item = toc->getCdTextItem(trackNr, l, CdTextItem::PackType::PERFORMER)) != NULL) { if (newItem == NULL) tocEdit->setCdTextItem(trackNr, CdTextItem::PackType::PERFORMER, l, NULL); else if (*newItem != *item) tocEdit->setCdTextItem(trackNr, CdTextItem::PackType::PERFORMER, l, s); } else if (newItem != NULL) { tocEdit->setCdTextItem(trackNr, CdTextItem::PackType::PERFORMER, l, s); } delete newItem; // Songwriter if ((s = checkString(cdTextPages_[l].songwriter->get_text())) != NULL) { newItem = new CdTextItem(CdTextItem::PackType::SONGWRITER, l); newItem->setText(s); } else newItem = NULL; if ((item = toc->getCdTextItem(trackNr, l, CdTextItem::PackType::SONGWRITER)) != NULL) { if (newItem == NULL) tocEdit->setCdTextItem(trackNr, CdTextItem::PackType::SONGWRITER, l, NULL); else if (*newItem != *item) tocEdit->setCdTextItem(trackNr, CdTextItem::PackType::SONGWRITER, l, s); } else if (newItem != NULL) { tocEdit->setCdTextItem(trackNr, CdTextItem::PackType::SONGWRITER, l, s); } delete newItem; // Composer if ((s = checkString(cdTextPages_[l].composer->get_text())) != NULL) { newItem = new CdTextItem(CdTextItem::PackType::COMPOSER, l); newItem->setText(s); } else newItem = NULL; if ((item = toc->getCdTextItem(trackNr, l, CdTextItem::PackType::COMPOSER)) != NULL) { if (newItem == NULL) tocEdit->setCdTextItem(trackNr, CdTextItem::PackType::COMPOSER, l, NULL); else if (*newItem != *item) tocEdit->setCdTextItem(trackNr, CdTextItem::PackType::COMPOSER, l, s); } else if (newItem != NULL) { tocEdit->setCdTextItem(trackNr, CdTextItem::PackType::COMPOSER, l, s); } delete newItem; // Arranger if ((s = checkString(cdTextPages_[l].arranger->get_text())) != NULL) { newItem = new CdTextItem(CdTextItem::PackType::ARRANGER, l); newItem->setText(s); } else newItem = NULL; if ((item = toc->getCdTextItem(trackNr, l, CdTextItem::PackType::ARRANGER)) != NULL) { if (newItem == NULL) tocEdit->setCdTextItem(trackNr, CdTextItem::PackType::ARRANGER, l, NULL); else if (*newItem != *item) tocEdit->setCdTextItem(trackNr, CdTextItem::PackType::ARRANGER, l, s); } else if (newItem != NULL) { tocEdit->setCdTextItem(trackNr, CdTextItem::PackType::ARRANGER, l, s); } delete newItem; // Message if ((s = checkString(cdTextPages_[l].message->get_text())) != NULL) { newItem = new CdTextItem(CdTextItem::PackType::MESSAGE, l); newItem->setText(s); } else newItem = NULL; if ((item = toc->getCdTextItem(trackNr, l, CdTextItem::PackType::MESSAGE)) != NULL) { if (newItem == NULL) tocEdit->setCdTextItem(trackNr, CdTextItem::PackType::MESSAGE, l, NULL); else if (*newItem != *item) tocEdit->setCdTextItem(trackNr, CdTextItem::PackType::MESSAGE, l, s); } else if (newItem != NULL) { tocEdit->setCdTextItem(trackNr, CdTextItem::PackType::MESSAGE, l, s); } delete newItem; // Isrc if ((s = checkString(cdTextPages_[l].isrc->get_text())) != NULL) { newItem = new CdTextItem(CdTextItem::PackType::UPCEAN_ISRC, l); newItem->setText(s); } else newItem = NULL; if ((item = toc->getCdTextItem(trackNr, l, CdTextItem::PackType::UPCEAN_ISRC)) != NULL) { if (newItem == NULL) tocEdit->setCdTextItem(trackNr, CdTextItem::PackType::UPCEAN_ISRC, l, NULL); else if (*newItem != *item) tocEdit->setCdTextItem(trackNr, CdTextItem::PackType::UPCEAN_ISRC, l, s); } else if (newItem != NULL) { tocEdit->setCdTextItem(trackNr, CdTextItem::PackType::UPCEAN_ISRC, l, s); } delete newItem; } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/TrackInfoDialog.h���������������������������������������������������0000664�0000000�0000000�00000004477�15114537466�0022034�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2000 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __TRACK_INFO_DIALOG_H__ #define __TRACK_INFO_DIALOG_H__ #include <gtkmm.h> #include <gtk/gtk.h> #include <string> class Toc; class TocEdit; class TocEditView; class TextEdit; class TrackInfoDialog : public Gtk::Dialog { public: TrackInfoDialog(); ~TrackInfoDialog(); bool on_delete_event(GdkEventAny*); void update(unsigned long, TocEditView *); void start(TocEditView *); void stop(); private: TocEditView *tocEditView_; int active_; int selectedTrack_; Gtk::Button *applyButton_; Gtk::Label *trackNr_; Gtk::Label *pregapLen_; Gtk::Label *trackStart_; Gtk::Label *trackEnd_; Gtk::Label *trackLen_; Gtk::Label *indexMarks_; Gtk::CheckButton *copyFlag_; Gtk::CheckButton *preEmphasisFlag_; Gtk::RadioButton *twoChannelAudio_; Gtk::RadioButton *fourChannelAudio_; TextEdit *isrcCodeCountry_; TextEdit *isrcCodeOwner_; TextEdit *isrcCodeYear_; TextEdit *isrcCodeSerial_; struct CdTextPage { Gtk::Label *label; Gtk::Entry *title; Gtk::Entry *performer; Gtk::Entry *songwriter; Gtk::Entry *composer; Gtk::Entry *arranger; Gtk::Entry *message; Gtk::Entry *isrc; }; CdTextPage cdTextPages_[8]; void closeAction(); void applyAction(); Gtk::VBox *createCdTextPage(int); void clear(); void clearCdText(); const char *checkString(const std::string &); void importCdText(const Toc *, int); void importData(const Toc *, int); void exportCdText(TocEdit *, int); void exportData(TocEdit *, int); }; #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/TrackManager.cc�����������������������������������������������������0000664�0000000�0000000�00000015033�15114537466�0021517�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998 Andreas Mueller <mueller@daneb.ping.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 * (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. */ /* * $Log: TrackManager.cc,v $ * Revision 1.2 2004/02/12 01:13:32 poolshark * Merge from gnome2 branch * * Revision 1.1.1.1.6.1 2004/01/05 00:34:03 poolshark * First checking of gnome2 port * * Revision 1.1.1.1 2003/12/09 05:32:28 denis * Fooya * * Revision 1.1.1.1 2000/02/05 01:40:19 llanero * Uploaded cdrdao 1.1.3 with pre10 patch applied. * * Revision 1.2 1999/05/24 18:10:25 mueller * Adapted to new reading interface of 'trackdb'. * * Revision 1.1 1998/11/20 18:56:46 mueller * Initial revision * */ #include <stdio.h> #include <assert.h> #include "TrackManager.h" #include "Toc.h" #include "util.h" TrackManager::TrackManager(gint trackMarkerWidth) { trackMarkerWidth_ = trackMarkerWidth; width_ = 0; entries_ = NULL; lastEntry_ = NULL; iterator_ = NULL; } TrackManager::~TrackManager() { clear(); } void TrackManager::clear() { EntryList *next; while (entries_ != NULL) { next = entries_->next; delete entries_->ent; delete entries_; entries_ = next; } lastEntry_ = NULL; iterator_ = NULL; } void TrackManager::append(Entry *ent) { EntryList *entry = new EntryList; entry->ent = ent; entry->next = NULL; if (entries_ == NULL) entries_ = entry; else lastEntry_->next = entry; lastEntry_ = entry; } const TrackManager::Entry *TrackManager::first() { if ((iterator_ = entries_) != NULL) return iterator_->ent; else return NULL; } const TrackManager::Entry *TrackManager::next() { if (iterator_ == NULL || (iterator_ = iterator_->next) == NULL) return NULL; else return iterator_->ent; } void TrackManager::select(const Entry *ent) { EntryList *run; for (run = entries_; run != NULL; run = run->next) { if (run->ent == ent) run->ent->selected = 1; else run->ent->selected = 0; } } void TrackManager::select(int trackNr, int indexNr) { EntryList *run; for (run = entries_; run != NULL; run = run->next) { if (run->ent->trackNr == trackNr && run->ent->indexNr == indexNr) run->ent->selected = 1; else run->ent->selected = 0; } } const TrackManager::Entry *TrackManager::pick(gint x, gint *stopXMin, gint *stopXMax) { EntryList *run; Entry *pred; for (run = entries_, pred = NULL; run != NULL; pred = run->ent, run = run->next) { if ((run->ent->indexNr == 1 || run->ent->selected)&& run->ent->extend == 0 && run->ent->drawn && x >= run->ent->xpos && x < run->ent->xpos + trackMarkerWidth_) { if (stopXMin != NULL) *stopXMin = pred != NULL ? pred->xpos + 1 : 0; if (stopXMax != NULL) *stopXMax = run->next != NULL ? run->next->ent->xpos - 1 : width_ - 1; return run->ent; } } for (run = entries_, pred = NULL; run != NULL; pred = run->ent, run = run->next) { if (run->ent->indexNr != 1 && run->ent->extend == 0 && run->ent->drawn && x >= run->ent->xpos && x < run->ent->xpos + trackMarkerWidth_) { if (stopXMin != NULL) *stopXMin = pred != NULL ? pred->xpos : 0; if (stopXMax != NULL) *stopXMax = run->next != NULL ? run->next->ent->xpos : width_; return run->ent; } } return NULL; } void TrackManager::update(const Toc *toc, unsigned long start, unsigned long end, gint width) { Msf tstart, tend; long startLba = start / SAMPLES_PER_BLOCK; long startRest = start % SAMPLES_PER_BLOCK; long endLba = end / SAMPLES_PER_BLOCK; int trackNr; const Track *t; Entry *ent; int nindex, index; long markStart = -1; int last = 0; clear(); width_ = width; TrackIterator itr(toc); if (toc == NULL || start == end || (t = itr.find(start, tstart, tend, &trackNr)) == NULL) return; double samp2pix = double(width - 1) / double(end - start); #define lba2pixel(lba) \ gint(double(((lba) * SAMPLES_PER_BLOCK) - start) * samp2pix + 0.5) nindex = t->nofIndices(); if (startLba < tstart.lba()) { // 'start' is in pre-gap of track ent = new Entry(t, trackNr, 0, 0); markStart = tstart.lba() - t->start().lba(); index = 0; } else { if (nindex == 0 || startLba <= tstart.lba() + t->getIndex(0).lba()) { markStart = tstart.lba(); index = 1; } else { for (index = 3; index - 2 < nindex; index++) { if (startLba >= tstart.lba() + t->getIndex(index - 3).lba() && startLba < tstart.lba() + t->getIndex(index - 2).lba()) { markStart = tstart.lba() + t->getIndex(index - 3).lba(); index--; break; } } if (markStart == -1) { markStart = tstart.lba() + t->getIndex(nindex - 1).lba(); index = nindex + 1; } } } ent = new Entry(t, trackNr, index, 0); if (startLba != markStart || startRest > 0) ent->extend = 1; append(ent); if (index == 0 && tstart.lba() <= endLba) append(new Entry(t, trackNr, 1, lba2pixel(tstart.lba()))); if (index == 0) index = 1; index++; for (; index - 2 < nindex; index++) { if (tstart.lba() + t->getIndex(index - 2).lba() > endLba) break; append(new Entry(t, trackNr, index, lba2pixel(tstart.lba() + t->getIndex(index - 2).lba()))); } while ((t = itr.next(tstart, tend)) != NULL) { trackNr++; if (t->start().lba() != 0) { if (tstart.lba() - t->start().lba() > endLba) break; append(new Entry(t, trackNr, 0, lba2pixel(tstart.lba() - t->start().lba()))); } if (tstart.lba() > endLba) break; append(new Entry(t, trackNr, 1, lba2pixel(tstart.lba()))); last = 0; nindex = t->nofIndices(); for (index = 0; index < nindex; index++) { if (tstart.lba() + t->getIndex(index).lba() > endLba) { last = 1; break; } append(new Entry(t, trackNr, index + 2, lba2pixel(tstart.lba() + t->getIndex(index).lba()))); } if (last) break; } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/TrackManager.h������������������������������������������������������0000664�0000000�0000000�00000004656�15114537466�0021372�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998 Andreas Mueller <mueller@daneb.ping.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 * (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. */ /* * $Log: TrackManager.h,v $ * Revision 1.2 2004/02/12 01:13:32 poolshark * Merge from gnome2 branch * * Revision 1.1.1.1.6.1 2004/01/05 00:34:03 poolshark * First checking of gnome2 port * * Revision 1.1.1.1 2003/12/09 05:32:28 denis * Fooya * * Revision 1.1.1.1 2000/02/05 01:38:55 llanero * Uploaded cdrdao 1.1.3 with pre10 patch applied. * * Revision 1.1 1998/11/20 18:56:46 mueller * Initial revision * */ #ifndef __TRACK_MANAGER_H #define __TRACK_MANAGER_H #include <glib.h> class Toc; class Track; class TrackManager { public: struct Entry { Entry(const Track *t, int tn, int in, gint x) { track = t; trackNr = tn; indexNr = in; xpos = x; extend = 0; drawn = 1; selected = 0; } const Track *track; int trackNr; int indexNr; gint xpos; unsigned int extend : 1; unsigned int drawn : 1; unsigned int selected : 1; }; TrackManager(gint trackMarkerWidth); ~TrackManager(); void update(const Toc *, unsigned long start, unsigned long end, gint width); // returns entry that is picked at given x-postion const Entry *pick(gint x, gint *stopXMin, gint *stopXMax); // selects given entry, use 'NULL' to unselect all void select(const Entry *); // selected entry with specified track/index void select(int trackNr, int indexNr); // iterates entries const Entry *first(); const Entry *next(); private: struct EntryList { Entry *ent; EntryList *next; }; gint trackMarkerWidth_; gint width_; EntryList *entries_; EntryList *lastEntry_; EntryList *iterator_; void clear(); void append(Entry *); }; #endif ����������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/cdrdao.txt����������������������������������������������������������0000664�0000000�0000000�00000000412�15114537466�0020641�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������Track progress (%) when recording Total progress (%) when reading Pool messages for "copy" ? reading pool messages only go to 99.90 % ???? should print speed in stdout. accept --read-speed 24, to set the max. read speed stablish what --force does and what not. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/gcdmaster-doc.png���������������������������������������������������0000664�0000000�0000000�00000017164�15114537466�0022102�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���`���`���ā˜w8���sBIT|dˆ��+IDATxœķ{xTÕ¹’?{ö\’™If !f‘@%7“""‰ˆõ‚˜ÓZŃjÄö©õņ“Ój«Uėķi+…S±¶?ū;z”#m¼ą —Ŗ ·Bn\‚@2I ‰$™É=sŪē=÷LīAśüN¾Ļ³ŸŁYkķµ÷ž¾k½ė]ļz׌cćĒ8Ę1ŽqŒcćĒ8Ę1ŽqŒć „Kż�ƒĄ $ #9HłĻqŌsŌPözO½E@ń(žń’+€åĄŪĄY@åŃ |ā©ÓpŸēBŹ=ęYĢžōO€/źSü³ō€„Ąż@^`bzz:iii˜Ķf²²²�X°`�’$żī޽€ņņr, ”””„ާX¬›vĒ*=Lõ;?¦©ōÆG=÷®õ<Kžēy0ĢX€iĄÕmĆvjĄZąßĒźÅ/„� ĄJäM0 ää䐓“CVVƒčKvæįŅöģŁCaa![·n„®®ĪWīŪ/#"Ęę æąÜ— z0ĶD¦%O“q;ŹHƒ·f¾ųæœżč)<Ļ;z2.•�žC&ߐ““ý÷ŽKNNŽÆĄhHļļ·¤¤„Gy„ÉȜ§Keå8»¬t֗ FŠOMĒ—)į?Gāą³iō¶Xʬ(Ē¢’a`)rNČĻĻē駟Ęl–ÕópH·Z­�tttąt:ƒņDQDÆ×#I’Æ̟?›ĶFÜĶŹ žę§Ō1¤dć'Ś›)y~<ēčÓčm± f ߔ� Čŗ7äæfĶĢfóHoooĒjµbµZéčč §§FƒB”@­V£R©‚nęp8hllÄårŃŪŪ‹F£A§ÓqšąAŚŚŚHÉĢĮG0ųõ€ä;ĮŸ,}b:-å…IcEĢ7!€ `#d6›yć7ČĪĪ'½®®«ÕŠÓéD«ÕI||<¾ŹA{ųwOO===lß¾]b:1^ƒ(°¼")øŒ HīĮc‹-€åČ-Ÿüü|Ö¬Y3čĄzīÜ9Īž=‹ÓéDÆ×7$Āū# 22’ČČHJJJ0\}_?Ņ#ĀõAóQób ąmą~ƒĮĄš5køļ¾ūŌé‹…³gĻ¢R©0 DGGC#| ņ½ēĒ§½½׎HuH÷źi¶ŠŪ\‹!%kX/?T\,ųČß¹s'aIhmm„ŖŖ AˆG«ÕśņƊ|€>śˆˆSą–@’ś„­z–-æĘvJž_Ȧé/騫�y–=&øfčŪĄżf³™ 6ōK¾Ćį ŖŖŠęęfbcc‰ŽŽ6įC%_²²²P~+”»V#I²�¼G  œ]VĪlų9M„Į`Ša³u‚ģŽ(Bž³X‘‰1q_Œuš‘šąA CŸŠŅŅBYY³ŁŒ(Š•ücĒŽŃŠŠĄµ÷ę¢Ün W€�¼ē–2Ŗßł1ŹöÓ¼’Į/ÉŹNå֛Ÿ¦¼ül’·ŗņŅ/cX×r<jēĆ? ²æĮßśkkk9rä'Ndņäɝ|€;w¢ŅHHĶF-‚Z) T P*@)@kŁfŹ_¹•ä‰ķ”XKNī<ŒF=Ūvüšōōi ·žēFČMæ+\¬3 üķo#==č;ŲVVVņÕW_‘0āAvøäģŲ±ÓÕ9h””D‚*Q€^§>x‚Ź×—q÷W±mĒÆ1›ć}׍zžßa0č�žGžLŽĘ¢Ku¤ńĶ7ß$??O~ss3 ˆ¢(ßü æ””¬¬,nžÅ˜®Ī„|ĖkøÜ`0„s”¦ŒSŪžˆŚŃĢļÖüłł7öū’›7•²ģĪ߀<d2F¾ ±ÖĘüüü:ņA`ĒŽht®X‹Ė §‹ÖÓ\#ū}tQŃ|/ļŪ<żĢ³A­>¾³t?xģN ^żĄčyē¼`ˆmX lģoŠ•$钒pŪm·įžp9wüźCšĻךēĪäߞ|‘Ō«ēs{¶–)Q}ÉFQG“RĄ½™÷rŖģČcĀzń Ķ`@v¬ńę›o†tkkkill¼dä·µµqüųqҳ—¢SCķĮĶ�,Ź[Ę­ ¢%ߎ‚3Ŗ >ņž}­Ļ ŗÖĆĮØ0¬’rssĆśvZZZ|ī„ dėąšE¹čŌÕ{7qĶ¢[™1ŎɊ8ąĖŁN©cčTØƒŅÆZxK–/Ł•¾rĄJ†€‘Ŗ ߥ[]]ŻĒ«ép8Ų³g'N¼ØÖĪĪ;Łæ?ĒŽóå%&&2oŽ<n¹åüqšķ<öb³YytQĻ’ž%~žPFæ/ęB QŌѬŌõ[¦ŻŚN^R¶+²cĪÖoįA0Ņ°ĻĄĪ„\UU…F£¹häļŲ±ƒģģl|šA>Ūu˜U<gßLŌ“¹«żš'žx‚ °cĒęĢ»ž(Ąń’M�¬ųAræ/Õ-(9£š0 ł�QĘ(īZyŒA/ihŒ'Ožō-¦€_õ9rä¢ĶpŸxā >žųc®ø1Ÿ…łĻ0yjZčŌ:5hUī…ė’Ąŗ?¼Čū»¾"vJĻüų»(gŲ¾ć7a_肨å¼2jČ4¬#gÖ ›„IŒ°Œ¤,Œ999$%%ł[llģ˜“ßŁŁÉ³Ļ>ĖĒĢ¢G߱֕o0qrJØEJ­ācŒ<üÄÆŲ°ó03/Ÿ†Škeßē›Čə×ēe\œQMą¼2Švk;‡‹søč0ķÖö°/ÆiėeĀ+WŚ”|É"{A^ŲĀCĄHęy@X÷ņ¹sēp»ŻcźXkll¤¼¼œ“'ORPPĄ5÷ÆfÖ¢| ½®…<«UAÆøś*yå°äŠ.�rrÆ ŗG‡ ¢VeÄ-(ųżŹßóž«ļ÷yŁ+Ææ½QOJf —ė$ėŒL‡nJw.YĆĀ/`&ép`�ņĢf³o=P§OŸfҤIcB¾ŻngļŽ½Ō××c·Ū•••č&™UW,yAu§PB0T ЈZDE AńöOIOŸ4Ł:'ź}ŗ~Ėŗ-¼’źūL»ćwžy� [õnžŃm£óX9ūwļ ·ÅōœW̘ę=]ˆģ'*BVIeC%tøš­éB°{ŁŪśĒŸßŅŅĀĪ;éģģtÅĘĘöĢ™3§wĖ–-zż$³oŠ|#XPšēW!ȱY­l+ÜČ3Ļ|Śze4= ’:rńĘb&fÜNĀ=‹¼PŒžęZz›kéØ+§£Ū†y½Ąvj÷ó!EkšGéYé'ZoøXųģ~/$IĀb±0aĀ_ڐļČĢĢģ2›Ķ=¢(ŗ£¢¢“’h•dß}Š!į–Ł­ģ–]Ė—DS@Ńū„Ķf#'÷.ˆZEnĮ?ōµ[ŪŁõé.¦Żń»0Æų|rc‹ˆ1c–…#KüłrxK…,¤KRG]y’«Ūŗ°£¾W·oŒ.B¶œŹ`„= 77·ĻzWW“'Oä”Ø/łsēĪķJHHčņ–»ņŹ+{ü×;½V"ŒFŸßå!Žé’°»zŠ­{Ż%ń—õė08¦s>`FėEńĘb�b2sśäĆū¼R?I‚'¼% Ė—ryg—[õ,…æYŲŁP±/i8V0fgg‡|Ēb wļŽ½tvvŗ233ƒČČĖĖėV N÷¶n¦»Ć*·v78]ąpŻ…L¾C¢Óm=_ńÉ{•%ķŁ|2čžbƓč†v޲7$Rb0č¾Ą¤ą“>™J­‘˜ŒŪ‰Éø<š†×2>¾~€ÆæžšøøøQ[;õõõÄĘĘö˜Ķꞩrz½^xź©§:_xįż‡?½F˜w÷3̹%»( tIˆN…BAĄ%Ilxūüõ/rĖ-·tßpà Mŗęšf¦LŌ£½ŠīB7�;¾(%~±¼Īāģ²Rś³)fČ-ؐ’ķ‹”ÓxTOĄ“Ó§7HŽ‚óā‹zäÜ·¦<l˜L¦ ņŪŚŚ°Ūķ£)//Ēn·;®¼ņŹQ݁å‡r÷īŻ‘'Nœč™={vńŃ£GõūĆ w’×ć\–œArf6JĻ ×¹ÆŹ8yø˜®wÜqGē“O>ŁÖŽŽ®Ł¹s§ŗvėqUĘ·ż3įmÅūiėčdVf ZŹegŻQ­TUŸEO=ĒN zfĶD1ftSÓQFŹ*ĒĪ¢’Ā ”¹l xBu`xHČČšūQ$I¢µµ½ŽÆ[G:Éjll$66Ö®Õjå\.—b÷īŻ‘lŚ·oßŖśśśw€ĄÜŪiĖ«-ßµ°¶|—ˆŠėõ)F£Ńš£ūó»æóļt%&&ŗ�t:=66ÖŽųu›Ŗ½ĖN”Vv°m+ŽODŒ m¬Ü²»<ń”ūž^ Ą±Sg}3}£ŃˆÕj%))‰£G2cŠ‚āĀb(ō?«i@Ÿ˜Ž&Ę#¤Ät”‘_HKsŁļ`¼Ń{ͰXÕŚŚŠF£šĮÜ uuuŲķvWrr²]”P­ā×ÖÖF”——÷xČ’ĻĄ,ąUĻ€Ńh\±pįĀ__żõJ/ł� …BJNN¶ļßæ?¢¦É&¦%MBĆöāżÄĶ»„Bn«3—­&eŁj]VŚėŹé¹PKw³…Žŗ2¬Ż6lµeŌÖŹVdqq1ƒ¤¤$jjj°ŁløŗmVŪ©ŻVNłÜF1ŅĄµ’Ń�ąmż5˜¢Ćž §§§ ĀÄĒĒŹ«ŁŲ؈ÓétÅÅŹĖŗ\.Eee„ŲŠŠPģił¢¾¾ž†††%‹L&“"P•Mš4Éķv»]]¢Aœ2w)G„­£“ŌłˆSÄž¢ŠQĻŹö›ŗxĀW�$°VļĀŁe£³¾œó͵F¬„·ÅbÄńķ5&ćvßßl Č–�Œ� …"h ŠétL˜0ŽŽ^Ün÷ˆüłv»ččh·B”Ņż.—Ki±X8}śōGČjg0ōœ>}ś£3f,r¹\JQķŽ Q]ŃŃђ­½€uėÖkb¢YV©~²%Ižoø|1Dąö”3¦d#ŽtķØ+“7sTļĀŁm3ŹVąK'@’ĆaÆŗńbžüłC® »»;lŗZ­Ęétö jkkS�X,Kß«ĀĆb±Xģv{Ų<»ŻīšĘ™rU.*Ńß²½BšNģø Į+I‚; |(ōSe…2JŠTśWÕO›āŻ6]”č:āt:{Zė\.ūöķ£¶¶–ßĶB%BkMö.›<`š3B"ēÜnp#įĀ? š "LܙV�Ķe›!DżĄšp”Įw)Žį„ķV*•F£ŃlµZK‡RÉd2©ÕjAčCZ­Vø\.>śč#TZÓ®ÉEźöü…ŸżŃWN„5`0„£5k&jj:b¤‘ 3³pIxłWdA…‡,„ŽŗrÆ#Æ(“Äp`FŁ!£·ķ*ĮŻnŻn·BEß@,Š¢Ód2ięĢ™óƒ/æüņSļ ʤ¤¤{L& …"t@/\ø $%%±mŪ6’ęŹaŠPh3Ė–-㮻®Žŗŗ:, uugØüb'ŪŚ‚n2!% Qk@Ÿ˜&ʄ&ƌ6!„ÖH8“Č­ß |š7lTSS“3Tø]6ģķptŚpŚ»pvÉ/éĘķv‹V«Uœ4i’o Š¢{öģŁī3gĪĢ7K­Vk_‡}�fΜ™o2™®œ9s¦3t2×ŌŌ¤ŒˆˆŻn7UUU,~ņ9ŌJøp¶ŒŽÆkY±ā-ŅŅŅ|åC ˆ½{÷ņ>3›ĶFee%–²w8°ńšŁžS=⤅°ÖĆīC€³· Wo—lG— —=ü� 0e¢µZ-ž>}Zä†HJJź™5k–¶··÷7;wīÄjµ†ė ‰‰‰÷„§§ÆLOOטL¦®ĄL·Ū-TWW«ŌjµXV&3ÆĖą«¢õL:u@ņAąŗė®üŪd˽ūī»<üšĆ�EõåG•q׎ ČīkĻĄQ ą(WSS”čģķĀŃeĆŁe£·ķŽ.’Ė9ŒjĮ«Ē«Ēb±ØRSSÕz½>Č|¼ńĘ»8Fódž††9r¤Ąjµ6‚¬ó“““旐0?==="++«;“õwtth¬V«*%%…Õ«W3ćŚ"”2y§K7³ųæ%7’P˜�#­ŁŅ!&C6Q›nöęõQ?0|P]q[ķU8ŗl#";½QjŚ/ÓŃ3!‚ä‰ÖwŪT•••š¹sē:gÄ*•ŹyÓM7u„¤¤h*++™ĶęEõ˜L&ŅŅҜ&“©3”|—Ė„(//רÕj•Łl¦ŖŖŠ¼'V”ė?jhkŖeń‑Ē!…`„.Ń?4•žśiż0<Ō�óȲ›†qY_tĘFŅÆĆ”óÆJÅϊ'vZ¬P²>211ŃźŽEŃ5}śō.³Ł¬p¹\AĻ-Šbņ„Ŗŗŗ:²©©I“’’By¹ģėÉČĪ%B _•n&::šŪn»mTA`ޤ£@^¼Gżģ?īW�ĆY(¬^GÕpįŚōœĻ˜Dėtcł� ÉĶmKĢ :ńĄچ†møĶ¢(ŗÕjµ=ščü††ķńćĒ#cbbÄE‹ńŁgŸ‘–•Ė„ ˆT ŁžĪØÉ÷ČČ t!؟2Ÿś“�rĖŪ{ø’łW„é§Z¤-AO×$mæe¢]=$:Ū£īśĮ Ž+8„:pą€vīܹLž<¹{:JKKՇņÅŗŻnUCCƒröģŁŹ{žž¶mŪĘ÷W®!RĶēkhųŖœÅĻž,؞į®i|¢ČÓ'¦kĘ-M¾ś‘�¶ļT�ŻF —éčÖō[F!¹‰wuėņ-ńńZņīLåĆ÷Ž«JKKõ‰‰‰ŹŌŌŌNgm©6›MXæ~½nƆ ŗĪĪN…Fg >9ņ’äٲ]|žłē|ņÉ'>—ɼ—¢U ģŽ#·NÆuĆ'_ }žčĄŗŲĢĄÕm„E6?‹āiøŲ¬Ż¶k?/üō_ūdŗEī “%čqi®:Āķ ŃŁF¤<ˆ;\"ē„ŁĢŗ9•Ś_ŠMõŚ­[·Ŗ.»ģ2Grr²=..Ī„P(Ü'NœžóŸZŪ{”³żŌ›ņI¼<µRŅR+åš”¦³ešŽ=ę™L5%”P@õߋY¼x±Ļ½>ŅPš��ćęÜčzšrÖ/†+€Ząhżł¦ĢŖź³ĢN™Čj¦ć2±‘HŹĮ‡•g'ń®NÄ0ī¬ĆēgŃa×”ŃAŹ ¹D^8-œ9^©>ž¼z’žżN§ÓÕŻŻ-½õÖ[jͤdį{Ļo f²DQšiÉŃrj%LŸ•Į·^|‹łßYJo§HtwŲ8šÅ&^{ķ5`h„WVVb³ŁŲ³gF£‘““4***°Ł| , #bLD™2p¹ĮV½’hԈœqkuo¼·™U«§36r@ż…ä&ŃŁ†ĮŻ6æŖiv`¬^”˜™œÄÉI“··S[[+ž8qBüÅ/~aś\–¼°µ(e‰ „ą”“—'U Š(4JXpÓRĻŽ0=E²I:�‡3/’üē?SPP@[ˆ;"5@^üœ\ŁY'ųģ’uƒq2l¬Ÿķ9`üńd5QĘ”‘ÆsŪ1;¬a[=Ą™ÖĪwL J›į{£¢¢HKK£““—BĆ €B č UTŠŽž€/nT棠·ļoŸ’šš“©$”ü×_U«V!j'vÓrf\›Će³Æ§×)Ńė„ö6+u»8õåzo^ øą^.ٌ3dé±?Œ$8׬ė°ušŽŚ÷†tĮdg;Ó­ż’®=–3­ Ai1*7QĶĆKжmۘśķ4:£/N!€č=žC©PIž’‘*];6q×]wõ©Ū{žšĆóōÓOsżń亃,}t Ó3ÆG!Č­[ BgÄ|uY?ū€ģ_n'2VŽ…/�äÖ_Ć6ņtĄZ€÷Ö¾×o1€Jrq¹½9ČŹ E{Ɩc_Oļ“>9Ā/¬@‚öķŪ‡~’Łź‚—… ų„į ÜU¾żĮ[?üo@V?”u{[ž»ļ¾Ėƒ/¼ÉæüųYōŃF9ž4¤· ž› @Ü·²¹į„ż¾z¾>Ž÷#@-°¶ĆÖĮĻæ¶€ŃÕĶ {s+'ķ½ZŸŸÕ'=FåFćy²PÓ3::ȗĮ/ī!»‡÷‘ššŠÉdźC¾ĶfcÕŖUää?Ź yĖźĒ/poyü÷B�•Ö“ו{ÕĻŗ”9š=bĻÖ÷_}Ÿź£Õž %7&‡•©Ī¶~UČęfÕ×Ópŗƒ‡!‰ÄHłŗp3ŌłóēÓxl—?-ō7D(>AķVvnż”»ļ¾;ģą»uėVŚŚŚøē‘ēüŌķ½“@ŸDß3œ+ł „Yz죀 Y¼x’‹€<ŠĪ°7÷kåxįp‰>s3q „Šæc쁠ńŲn,å-G”"ö®ė"I¾oRz×oYž]Œ†hī¾ūī>õ‚ģÕLžVŗhĆ�M'ä3r!éMG6ĮÕŒžSÆE§ŹNQš«?1ŻŃŠšA½T7›Ā’/"ƑōĶ\wŻu,[¶ŒŻz€šż›|Ņžˆ†€CĻŗī¹śī¹õ*Ŗ«Ž°~żś'_’n7ĮėĀõJę}ü¢åÄ.ŗ›-š �<Ÿpyõ„wŲµ«b°²œ¼`źcnz1%BB©Ü1öŅK/ń/9·²}՝|üō͜ڷY^$$Ķ ū?’”WžśWīYx9½ķ-lړɷš®^“Éęe“٬A_S‘CąCĀāéūŪųwŸõS<ā ¬&–ė „Öö»ķ’\{lX‹@­Hī׃ĶP?ūģ3VÆ^MUU�:Sfdpī«2z:d’×Ō©SyšĮyšĮ­·­­ōōtnŗū’óĄ³t; Ē =‰§}Żć™Ų]Šė’p8Įī†ę³e’jČjł…ĮóŻØ‡€W€•ééÓŲ¶ć׍Į±ų­ŻQ>’­~/NŅŗ‰ Ų=L]]%%%¾³ ‚ĄŌ©S¹īŗėĀZ;æžśė<õŌSüšWorÕ­÷yˆ÷  7@�v—„Ż–ƒ›8ōŸ+pvيę7$ĘR�ął`SؼęfØÅćE¤(1;*¼Ż?š÷‘^’ŠCQPP@ZV.‹–?ĆĤ ?ł.°{pf’&Žo}ÆļYļßĻ0·«Žµ� Čī×LÆtQJź2ś%`¦Ž?ė½Ōä{’žķoĖĖ/æ €Fg ~zFŠ€Ü|VęBÖł+égĶw0Œµ� Dæ|ķm““śN¶¼ˆRJĢŌ÷µū/%ł,Y²Äėé\‡Lr&žĄŪdOgĆŲC�ą’’ŹżŗØh~łŚ:Ņꆏ!õ¶žņ ųÉO~āMÓ/„‡ƒx‘źķEī’F‡½wŽåxŖP!ÄØ%ā5’ä[­V~ō£ńŹ+Æx“ļV ō’c‹%�/¶#wÕ[+ī(żü3f¦_ńIq�ĢŠd÷_*ņ·lŁĀ=÷ÜĆ”C‡Ąæø¾}Čo9 \, 3².]“’�žōqŅ.‹ö?Č% ßb±šŠC±gĻo҈,™Ńą›€!OTŒŃŃŃ<šĄ¬X±bĄ…‘pēC-×ß¹Åbįå—_¦  Ą›TƒLüg°c…oZ� ŠĻćłĪNtt4‹/fŊ¤¦ś#-.ł……….¤[‘Ś!Ļ\Ē—B�^˜ń’ #ČnƒÅ‹³xńb_øČhČ·Łl”””PXXHaa”׬¹ÅÆC&’S7įp)ą…ł+ Ł�2ž|RSS} (ƒ”_gšW—””ųž‰'b-‘‰ѤéĢų’uT+ų\ś#=Ī"»G–3_8¼ųgč!yæm¦ē7) / Y‡īÜń~¦ˆ!.ŠcćĒ8Ę1ŽqŒcćĒ8Ę1Žo’Éöśž"ø����IEND®B`‚������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/gcdmaster.applications����������������������������������������������0000664�0000000�0000000�00000000304�15114537466�0023225�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gcdmaster command=gcdmaster name=Gnome Audio CD Master can_open_multiple_files=true expects_uris=false requires_terminal=false mime_types=application/x-toc,application/x-cue,audio/x-mpegurl ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/gcdmaster.cc��������������������������������������������������������0000664�0000000�0000000�00000031662�15114537466�0021137�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2000 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #include <gtkmm.h> #include <glibmm/i18n.h> #include "config.h" #include "xcdrdao.h" #include "guiUpdate.h" #include "DeviceConfDialog.h" #include "PreferencesDialog.h" #include "ProjectChooser.h" #include "gcdmaster.h" #include "TocEdit.h" #include "util.h" #include "AudioCDProject.h" #include "DuplicateCDProject.h" #include "BlankCDDialog.h" #include "DumpCDProject.h" #include "Icons.h" // Static class members std::list<GCDMaster *> GCDMaster::apps; GCDMaster::GCDMaster() { set_title(APP_NAME); set_show_menubar(true); project_number = 0; about_ = 0; project_ = 0; chooser_ = 0; set_resizable(); set_wmclass("gcdmaster", "GCDMaster"); readFileSelector_ = new Gtk::FileChooserDialog(_("Please select a project"), Gtk::FILE_CHOOSER_ACTION_OPEN); readFileSelector_->set_transient_for(*this); readFileSelector_->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); readFileSelector_->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK); Glib::RefPtr<Gtk::FileFilter> filter_tocs = Gtk::FileFilter::create(); #ifdef HAVE_MP3_SUPPORT filter_tocs->set_name("Content Files (*.toc, *.cue, *.m3u)"); #else filter_tocs->set_name("Content Files (*.toc, *.cue)"); #endif filter_tocs->add_pattern("*.toc"); filter_tocs->add_pattern("*.cue"); #ifdef HAVE_MP3_SUPPORT filter_tocs->add_pattern("*.m3u"); #endif readFileSelector_->add_filter(filter_tocs); Glib::RefPtr<Gtk::FileFilter> filter_all = Gtk::FileFilter::create(); filter_all->set_name("Any files"); filter_all->add_pattern("*"); readFileSelector_->add_filter(filter_all); Icons::registerStockIcons(); notebook_.set_show_border(false); notebook_.show(); add(box_); box_.set_orientation(Gtk::ORIENTATION_VERTICAL); createMenus(); createStatusbar(); box_.add(notebook_); box_.add(*container_); box_.show_all(); if (!apps.empty()) set_application(app); apps.push_back(this); } void GCDMaster::createMenus() { //Define the actions: m_refActionGroup = Gtk::ActionGroup::create("Actions"); // File m_refActionGroup->add(Gtk::Action::create("FileMenu", _("_File"))); m_refActionGroup->add(Gtk::Action::create("New", Gtk::Stock::NEW), sigc::mem_fun(*this, &GCDMaster::newChooserWindow)); // File->New m_refActionGroup->add(Gtk::Action::create("FileNewMenu", _("N_ew"))); m_refActionGroup->add( Gtk::Action::create("NewAudioCD", Gtk::Stock::NEW, _("_Audio CD"), _("New Audio CD")), sigc::mem_fun(*this, &GCDMaster::newAudioCDProject2)); m_refActionGroup->add( Gtk::Action::create("NewDuplicateCD", Gtk::Stock::NEW, _("_Duplicate CD"), _("Make a copy of a CD")), sigc::mem_fun(*this, &GCDMaster::newDuplicateCDProject)); m_refActionGroup->add( Gtk::Action::create("NewDumpCD", Gtk::Stock::NEW, _("_Copy CD to disk"), _("Dump CD to disk")), sigc::mem_fun(*this, &GCDMaster::newDumpCDProject)); m_refActionGroup->add(Gtk::Action::create("Open", Gtk::Stock::OPEN), sigc::mem_fun(*this, &GCDMaster::openProject)); m_refActionGroup->add(Gtk::Action::create("Close", Gtk::Stock::CLOSE), sigc::hide_return(sigc::mem_fun(*this, &GCDMaster::closeProject))); m_refActionGroup->add(Gtk::Action::create("Quit", Gtk::Stock::QUIT), &GCDMaster::appClose); // Edit m_refActionGroup->add(Gtk::Action::create("EditMenu", _("_Edit"))); // Actions menu m_refActionGroup->add(Gtk::Action::create("ActionsMenu", _("_Actions"))); m_refActionGroup->add( Gtk::Action::create("BlankCD", Gtk::Stock::CDROM, _("Blank CD-RW"), _("Erase a CD-RW")), sigc::mem_fun(*this, &GCDMaster::blankCDRW)); // Settings m_refActionGroup->add(Gtk::Action::create("SettingsMenu", _("_Settings"))); m_refActionGroup->add( Gtk::Action::create("ConfigureDevices", Gtk::Stock::PREFERENCES, _("Configure Devices..."), _("Configure the read and recording devices")), sigc::mem_fun(*this, &GCDMaster::configureDevices)); m_refActionGroup->add( Gtk::Action::create("Preferences", Gtk::Stock::PREFERENCES, _("_Preferences..."), _("Set various preferences and parameters")), sigc::mem_fun(*this, &GCDMaster::configurePreferences)); // Help m_refActionGroup->add(Gtk::Action::create("HelpMenu", _("_Help"))); //FIXME: llanero Gtk::Stock::ABOUT ??? m_refActionGroup->add(Gtk::Action::create("About", _("About")), sigc::mem_fun(*this, &GCDMaster::aboutDialog)); m_refUIManager = Gtk::UIManager::create(); m_refUIManager->insert_action_group(m_refActionGroup); add_accel_group(m_refUIManager->get_accel_group()); //Layout the actions in a menubar and toolbar: try { Glib::ustring ui_info = "<ui>" " <menubar name='MenuBar'>" " <menu action='FileMenu'>" " <menuitem action='New'/>" " <menu action='FileNewMenu'>" " <menuitem action='NewAudioCD'/>" " <menuitem action='NewDuplicateCD'/>" " <menuitem action='NewDumpCD'/>" " </menu>" " <menuitem action='Open'/>" " <placeholder name='FileSaveHolder'/>" " <separator/>" " <menuitem action='Close'/>" " <menuitem action='Quit'/>" " </menu>" " <menu action='EditMenu'/>" " <menu action='ActionsMenu'>" " <placeholder name='ActionsRecordHolder'/>" " <menuitem action='BlankCD'/>" " <separator/>" " </menu>" " <menu action='SettingsMenu'>" " <menuitem action='ConfigureDevices'/>" " <separator/>" " <menuitem action='Preferences'/>" " </menu>" " <menu action='HelpMenu'>" " <menuitem action='About'/>" " </menu>" " </menubar>" " <toolbar name='ToolBar'>" " <toolitem action='New'/>" " <toolitem action='Open'/>" " </toolbar>" "</ui>"; m_refUIManager->add_ui_from_string(ui_info); } catch (const Glib::Error& ex) { std::cerr << "building menus failed: " << ex.what() << "\n"; exit(1); } Gtk::Widget* pMenuBar = m_refUIManager->get_widget("/MenuBar"); box_.add(*pMenuBar); Gtk::Widget* pToolbar = m_refUIManager->get_widget("/ToolBar"); box_.add(*pToolbar); } bool GCDMaster::openNewProject(const std::string& str) { TocEdit* tocEdit; const char* s = str.c_str(); if (s == NULL || *s == 0 || s[strlen(s) - 1] == '/') return false; auto type = Util::fileExtension(s); switch (type) { case Util::FileExtension::M3U: newAudioCDProject("", NULL, s); break; case Util::FileExtension::TOC: tocEdit = new TocEdit(NULL, NULL); if (tocEdit->readToc(stripCwd(s)) == 0) newAudioCDProject(stripCwd(s), tocEdit); else return false; break; case Util::FileExtension::CUE: tocEdit = new TocEdit(NULL, NULL); if (tocEdit->readToc(stripCwd(s)) == 0) newAudioCDProject("", tocEdit); else return false; break; default: printf("Could not open \"%s\": format not supported.\n", s); return false; break; } return true; } void GCDMaster::openProject() { readFileSelector_->present(); int result = readFileSelector_->run(); readFileSelector_->hide(); if (result == Gtk::RESPONSE_OK) { std::string s = readFileSelector_->get_filename(); openNewProject(s.c_str()); } } bool GCDMaster::closeProject() { if (chooser_) closeChooser(); if (project_) { if (project_->closeProject()) { delete project_; project_ = NULL; } else { return false; // User clicked on cancel } } if (readFileSelector_) delete readFileSelector_; GCDMaster::apps.remove(this); delete this; return true; } void GCDMaster::closeChooser() { delete chooser_; chooser_ = NULL; } bool GCDMaster::on_delete_event(GdkEventAny* e) { closeProject(); return true; } // Application Close. Called when the user selects 'Quit' from the // menu. Try to close all project windows and quit. void GCDMaster::appClose() { // Can't just iterate, as closeProject will remove its object from // the list. while (!GCDMaster::apps.empty()) { if (!(GCDMaster::apps.front())->closeProject()) return; } return; } void GCDMaster::newChooserWindow() { if (project_ || chooser_) { GCDMaster *gcdmaster = new GCDMaster; gcdmaster->newChooserWindow(); gcdmaster->show(); } else { chooser_ = new ProjectChooser(); chooser_->newAudioCDProject.connect( sigc::mem_fun(*this, &GCDMaster::newAudioCDProject2)); chooser_->newDuplicateCDProject.connect( sigc::mem_fun(*this, &GCDMaster::newDuplicateCDProject)); chooser_->newDumpCDProject.connect( sigc::mem_fun(*this, &GCDMaster::newDumpCDProject)); chooser_->show(); notebook_.set_show_tabs(false); notebook_.append_page(*chooser_); container_->hide(); } } void GCDMaster::newAudioCDProject(const char *name, TocEdit *tocEdit, const char* tracks) { if (!project_) { AudioCDProject* p = new AudioCDProject(project_number++, name, tocEdit, this); p->add_menus(m_refUIManager); p->configureAppBar(statusbar_, progressbar_, progressButton_); project_ = p; project_->show(); if (chooser_) closeChooser(); notebook_.remove_page(); notebook_.set_show_tabs(false); notebook_.append_page(*project_); if (tracks) p->appendTrack(tracks); container_->show(); } else { GCDMaster *gcdmaster = new GCDMaster; gcdmaster->newAudioCDProject(name, tocEdit, tracks); gcdmaster->show(); } } void GCDMaster::newAudioCDProject2() { newAudioCDProject("", NULL); } void GCDMaster::newDuplicateCDProject() { if (!project_) { project_ = new DuplicateCDProject(this); project_->show(); if (chooser_) closeChooser(); notebook_.remove_page(); notebook_.set_show_tabs(false); notebook_.append_page(*project_); container_->show(); set_title(_("Duplicate CD")); } else { GCDMaster *gcdmaster = new GCDMaster; gcdmaster->newDuplicateCDProject(); gcdmaster->show(); } } void GCDMaster::newDumpCDProject() { if (!project_) { project_ = new DumpCDProject(this); project_->show(); if (chooser_) closeChooser(); notebook_.remove_page(); notebook_.set_show_tabs(false); notebook_.append_page(*project_); container_->show(); set_title(_("Dump CD to disk")); } else { GCDMaster *gcdmaster = new GCDMaster; gcdmaster->newDumpCDProject(); gcdmaster->show(); } } void GCDMaster::update(unsigned long level) { if (project_) project_->update(level); blankCDDialog_.update(level); } void GCDMaster::configureDevices() { deviceConfDialog->start(); } void GCDMaster::configurePreferences() { preferencesDialog->show_all(); } void GCDMaster::blankCDRW() { blankCDDialog_.start(*this); } void GCDMaster::createStatusbar() { container_ = new Gtk::HBox(); statusbar_ = new Gtk::Statusbar(); progressbar_ = new Gtk::ProgressBar; progressButton_ = new Gtk::Button(_("Cancel")); progressButton_->set_sensitive(false); progressbar_->set_size_request(150, -1); container_->pack_start(*statusbar_, true, true); container_->pack_start(*progressbar_, false, false); container_->pack_start(*progressButton_, false, false); container_->set_spacing(2); container_->set_border_width(2); } void GCDMaster::aboutDialog() { if (about_) { // "About" dialog hasn't been closed, so just raise it about_->present(); } else { std::vector<Glib::ustring> authors; authors.push_back("Andreas Mueller <mueller@daneb.ping.de>"); authors.push_back("Manuel Clos <llanero@jazzfree.com>"); authors.push_back("Denis Leroy <denis@poolshark.org>"); authors.push_back("Stefan Roellin <stefan.roellin@gmx.ch>"); about_ = new Gtk::AboutDialog; about_->signal_response().connect( sigc::mem_fun(*this, &GCDMaster::on_about_ok)); about_->set_program_name("gcdmaster"); about_->set_version(VERSION); about_->set_copyright("(C) Andreas Mueller"); about_->set_authors(authors); about_->set_transient_for(*this); about_->show(); } } void GCDMaster::on_about_ok(int) { if (about_) { about_->hide(); } } ������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/gcdmaster.desktop���������������������������������������������������0000664�0000000�0000000�00000000374�15114537466�0022217�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������[Desktop Entry] Name=Gnome CD Master Comment=Gnome Audio CD editor and burner Exec=gcdmaster %F Icon=gcdmaster Terminal=false Type=Application StartupNotify=true Categories=GTK;GNOME;Audio;AudioVideo;DiscBurning; Keywords=cdrom;cd;dvd;disc;burn;audio; ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/gcdmaster.h���������������������������������������������������������0000664�0000000�0000000�00000004333�15114537466�0020774�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 2000 Andreas Mueller <mueller@daneb.ping.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 * (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. */ #ifndef __GCDMASTER_H__ #define __GCDMASTER_H__ #include <gtkmm.h> #include <gtk/gtk.h> #include <list> class ProjectChooser; class BlankCDDialog; #include "Project.h" #include "BlankCDDialog.h" class GCDMaster : public Gtk::ApplicationWindow { public: GCDMaster(); bool closeProject(); void closeChooser(); bool on_delete_event(GdkEventAny* e); bool openNewProject(const std::string&); void openProject(); void newChooserWindow(); void newAudioCDProject2(); void newAudioCDProject(const char *name, TocEdit *tocEdit, const char* tracks = NULL); void newDuplicateCDProject(); void newDumpCDProject(); void update(unsigned long level); void configureDevices(); void configurePreferences(); void blankCDRW(); void registerStockIcons(); static void appClose(); static std::list<GCDMaster *> apps; private: Project* project_; ProjectChooser* chooser_; gint project_number; BlankCDDialog blankCDDialog_; Gtk::Box box_; Gtk::Notebook notebook_; Gtk::HBox* container_; Glib::RefPtr<Gtk::UIManager> m_refUIManager; Glib::RefPtr<Gtk::ActionGroup> m_refActionGroup; Gtk::Statusbar* statusbar_; Gtk::ProgressBar* progressbar_; Gtk::Button* progressButton_; Gtk::AboutDialog* about_; Gtk::FileChooserDialog* readFileSelector_; void createMenus(); void createStatusbar(); void aboutDialog(); void on_about_ok(int); }; #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/gcdmaster.keys������������������������������������������������������0000664�0000000�0000000�00000001774�15114537466�0021526�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ application/x-toc description=Audio CD content category=Audio open=gcdmaster %f view=gcdmaster %f icon-filename=/usr/share/pixmaps/gcdmaster-doc.png application/x-cue description=Audio CD content category=Audio open=gcdmaster %f view=gcdmaster %f icon-filename=/usr/share/pixmaps/gcdmaster-doc.png application/x-ogg short_list_application_ids_for_novice_user_level=gcdmaster short_list_application_ids_for_intermediate_user_level=gcdmaster short_list_application_ids_for_advanced_user_level=gcdmaster application/ogg short_list_application_ids_for_novice_user_level=gcdmaster short_list_application_ids_for_intermediate_user_level=gcdmaster short_list_application_ids_for_advanced_user_level=gcdmaster application/x-mp3 short_list_application_ids_for_novice_user_level=gcdmaster short_list_application_ids_for_intermediate_user_level=gcdmaster short_list_application_ids_for_advanced_user_level=gcdmaster ����cdrdao-cdrdao-f00afb2/gcdmaster/gcdmaster.man�������������������������������������������������������0000664�0000000�0000000�00000050530�15114537466�0021320�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������.TH GCDMASTER 1 "Oct 10, 1999" .SH NAME gcdmaster \- Graphical front end to cdrdao for composing audio CDs .SH SYNOPSIS .B gcdmaster .RI [ toc-file ] .SH DESCRIPTION .I gcdmaster allows the creation of toc-files for cdrdao and can control the recording process. Its main application is the composition of audio CDs from one or more audio files. It supports PQ-channel editing, entry of meta data like ISRC codes/CD-TEXT and non destructive cut of the audio data. If a .I toc-file is specified it will be read and the referenced audio data will be displayed. It is also possible to specify a ".cue" file. The GUI periodically polls all configured CD-ROM and CD-recorder devices (see section DEVICE CONFIGURE DIALOG) to retrieve their status (ready, busy, no disk). This is done by sending a TEST UNIT READY command to the devices. Following problems may arise: .TP o Some devices (e.g. the Philips CDD2600) block the SCSI bus when a TEST UNIT READY is issued while it logs in a new medium. This will cause a buffer under run for all currently recording devices that are connected to the same bus. .TP o The GUI cannot detect if a device is used by another program. It will continue to poll the device which may disturb the operation of the other program. .PP The GUI supports recording of the same or different projects on multiple devices in parallel. However, there are some caveats and your system must meat some prerequisites: .TP o Under Linux a kernel version >= 2.2.6 should be used. The generic SCSI device of older kernels does not support parallel access to multiple devices. .TP o The bandwidths of the disks that contain the source data and the involved busses must be big enough to serve all recorder devices. .TP o Some recorder devices may block the SCSI bus when the disk is ejected by the software after the burning process (e.g. the Plextor PX-R412). For this reason a warning message will be displayed if the "Eject" button is checked in the "Record" dialog. Manually ejecting a disk seems not to be a problem. .TP o ATAPI devices supported by the 'generic-mmc' driver will block the IDE bus while writing the lead-in and lead-out. Thus parallel writing with such devices connected to the same IDE channel will not work. There is a way to avoid this blocking with some ATAPI devices but it is not implemented, yet. .SH CONCEPTS The main idea of this GUI is to maintain a continuous stream of audio data that can be composed of several audio files. It is possible to use only portions of audio files in the audio stream which is the basic idea for the non destructive cut capability. For example, if you cut out some samples in the middle of an audio file the result will be a portion that starts at the beginning of the audio file and ends at the beginning of the cut region and a second portion that starts at the end of the cut region and reaches until the end of the audio file. Of course, all of this is hidden by the GUI and you will just see the result. Track and index marks are placed relatively to the continuous audio stream. It is not necessary to have a separate audio file for each track. Track/index marks can be set, moved and deleted without influencing the audio data stream. .SS Sample Marker A sample marker serves as an insertion position for audio data. It is equivalent to the cursor of a text editor. All functions that insert audio data require a defined marker. At most one sample marker may be active at any time. .SS Sample Selection A sample selection specifies a continuous range of audio samples. At most one sample selection may be active at any time. .SS Track Mark A track mark specifies a point in the audio stream where the track number or the index number changes. Track marks are written as a pair of two numbers like 5.1 for track 5, index 1. Track numbers may be in the range 1..99, the valid range for index numbers is 0..99. Index 0 represents the pre-gap of a track where the track relative time counts backwards down to zero. Index 1 marks the real start of the track. This position is stored in the central toc of the CD and is used by CD players to directly jump to a track. All index numbers > 2 may be used to subdivide a track but have no further effect. Some CD players may jump to such index marks. Track marks may be selected to show data about a track or to perform operations on the complete track. At most one track mark may be selected at any time. .SS Times The time is usually displayed as m:s:f.x where m represents minutes, s represents seconds (0..59), f represents frames (0..74, 1/75 second) and x stands for samples (0..587, 1/44100 second). .SH MAIN WINDOW The main window consists of a menu bar, a sample display, a marker/selection line, a button line and a status line. The title of the main window shows the current toc-file name. A "(*)" behind the name indicates that changes have not been saved. .SS Menu Bar The functions that are accessible via the menu bar are described in section MENU FUNCTIONS. .SS Sample Display The sample display provides a visual representation of the audio stream and the placed track/index markers. The samples are displayed as two separate graphs for the left and right channel where the x-axis represents the time and the y-axis denotes the amplitude (linearly scaled). If a pixel represents more than 1 sample the maximum and minimum amplitude of all samples that fall within this pixel is displayed. It is possible to zoom in and out and change the displayed portion with the scroll bar. The track/index markers are shown on top of the two graphs. Track marks with index 1 are represented by filled track symbol. All other track marks use a hollow track symbol. The track/index number pair is displayed on the right side of a track symbol. Track marks can be selected or moved by clicking or dragging with the mouse pointer located over a track symbol. The track/index number pairs are not sensitive. .SS Marker/Selection Line This line shows the actual cursor and active marker position and the active sample selection. The cursor field is read-only and shows the time value of the actual mouse pointer position within the audio stream if it is located inside the sample display. During playback the cursor field shows the time value of currently audible sound. The marker field shows the time value of the active marker. A time value may be entered and hitting the return key sets the new marker position if the time value is valid. The sample selection fields show the active selected sample range. Time values may be entered and hitting the return key in one of these fields sets the new sample selection if the time values are valid. .SS Button Line The zoom/select radio buttons specify the behavior when dragging with the mouse in the sample display. If "zoom" is active the sample display will zoom to selected sample range. If "select" is active the active sample selection will be set to the selected sample range. The play button will playback the currently active sample selection via the sound card. If no sample selection is active the currently displayed sample range will be used. While playing the current project is set to read-only state and all operations that would modify the project are disabled. .SS Status Line The status line shows more information about the last executed action or an error message if an action could not be executed. .SH MENU FUNCTIONS .SS File->New Starts a new project. If the current work is not saved a confirmation box will be opened. .SS File->Open Opens a file selector box to select a toc-file or a .cue file that should be read. If the current work is not saved a confirmation box will pop up. .SS File->Save Saves current work as a toc-file with the current file name. .SS File->Save As Opens a file sector box to select a toc-file to which the current work is saved. .SS File->Quit Quits gcdmaster. If the current work is not saved a confirmation box will pop up. .SS View->Zoom To Selection Zooms the sample display to the currently active sample selection. If no sample selection is active nothing will happen. .SS View->Zoom out Doubles the range of displayed samples. .SS View->Fullview Shows all samples of the audio stream in the sample display. .SS Edit->Cut Removes the active selected sample range from the audio stream. The audio file on the disk will not be touched by this operation. The sample marker will be set so that a following "Paste" operation will revert the effect of this operation. If no sample selection is active nothing will happen. .SS Edit->Paste Pastes the samples that were previously removed with "Cut" at the current sample marker position. The sample selection is set to the pasted samples so that a following "Cut" operation will revert the effect of this operation. If no sample marker is set nothing will happen. .SS Edit->Add Track Mark Adds a track mark with index 1 at the active sample marker position. The position will be rounded to the next frame boundary. If the previous or the new track would be shorter than 4 seconds no track mask is created. If no sample marker is active nothing will happen. .SS Edit->Add Index Mark Adds a track mark with index > 1 at the active sample marker position. The position will be rounded to the next frame boundary. Index marks cannot be created in the pre-gap area of a track. If no sample marker is active nothing will happen. .SS Edit->Add Pre-Gap Adds a track mark with index 0 (pre-gap) at the active sample marker position. Index 0 can only be added right before a track mark with index 1. If the length of the previous track would be shorter than 4 seconds after inserting the pre-gap this operation is not performed. If no sample marker is active nothing will happen. .SS Edit->Remove Track Mark Removes selected track mark with any index. If a track mark with index 1 is removed all track marks of this track will be removed. If no track marker is selected nothing will happen. .SS Tools->Disk Info Opens the non modal "Disk Info" dialog box. See section DISK INFO DIALOG for more details. .SS Tools->Track Info Opens the non modal "Track Info" dialog box. See section TRACK INFO DIALOG for more details. .SS Tools->Append Track Opens a non modal file selector dialog box to select an audio file that will be completely appended to the audio stream. A track mark with index 1 is added at the beginning of the appended audio data. The non modal file selector box is shared for "Tools->Append Track", "Tools->Append File" and "Tools->Insert File". .SS Tools->Append File Opens a non modal file selector dialog box to select an audio file that will be completely appended to the audio stream. The non modal file selector box is shared for "Tools->Append Track", "Tools->Append File" and "Tools->Insert File". .SS Tools->Insert File Opens a non modal file selector dialog box to select an audio file that will be completely inserted in the audio stream at the active marker position. If no sample marker is active nothing will happen. The non modal file selector box is shared for "Tools->Append Track", "Tools->Append File" and "Tools->Insert File". .SS Tools->Append Silence Opens a non modal dialog box that can be used to append silence to the audio stream. The non model dialog box is shared for "Tools->Append Silence" and "Tools->Insert Silence". .SS Tools->Insert Silence Opens a non modal dialog box that can be used to insert silence in the audio stream at the active marker position. If no sample marker is active nothing will happen. The non model dialog box is shared for "Tools->Append Silence" and "Tools->Insert Silence". .SS Settings->Devices Opens the non modal "Configure Devices" dialog box. See section DEVICE CONFIGURE DIALOG for more details. .SS Actions->Record Opens the non modal "Record" dialog box. See section RECORD DIALOG for more details. .SH DISK INFO DIALOG (Tools->Disk Info) This non modal dialog shows summary information about the whole project and allows editing of meta data that is valid for the complete disk. The "Apply" button must be used to make changes permanent. If the summary information changes before the "Apply" button was hit, e.g. by adding a new track, all changes will be lost. The "Cancel" button withdraws all changes and closes the dialog box. .SS Summary Frame Shows the total number of tracks, i.e. number of track marks with index 1, and the total length of the audio stream. .SS Sub-Channel Frame Allows entry and editing of data that is written to the sub-channels of a disk. The scope of this data covers the whole disk. The "Toc Type" option menu can be used to select the type of the table of contents that will be written to the disk. Currently, for projects that are solely created with this GUI only the type "CD-DA" or "CD-ROM-XA" makes sense. If you read a toc-file that contains data track specifications another type may be displayed. The "UPC/EAN" edit field sets the catalog number of the disk. Exactly 13 digits must be entered to set the catalog number. To clear the catalog number the edit field must be completely cleared. .SS CD-TEXT Frame CD-TEXT data can be specified for up to 8 different languages. Each language is reference by a language number 0..7. The first language should have language number 0. Language numbers should be used continuously. The actual language for a language number is specified with the "Language" option menu: The option "Unknown" is shown for an unknown language code (e.g. if the toc-file was edited manually). It is not possible to select this option. Option "Undefined" means that no language was assigned for this language number. It is possible to enter CD-TEXT data and the entered data will be saved to the toc-file but it will not be recorded to a CD-R/CD-RW. The remaining options select the desired language. Each language can be assigned only to one language number. The remaining CD-TEXT fields contain ASCII data. It is not necessary to use them all but at least "Title" and "Performer" should be filled. .SH TRACK INFO DIALOG (Tools->Track Info) This non modal dialog shows information about a selected track and allows editing of track specific meta data. If no track mark is selected all fields will be cleared and set insensitive. The "Apply" button must be used to make changes permanent. If the track information changes, e.g. by adding a index mark, or another track mark is selected before the "Apply" button was hit all changes will be lost. The "Cancel" button withdraws all changes and closes the dialog box. .SS Summary Frame Shows the length of the pre-gap (0 if no pre-gap is defined), the absolute start and end time, the track length excluding the pre-gap length and the number of index marks > 1. .SS Sub-Channel Frame Allows editing of all data that is written to the Q sub-channels of the track: .TP Copy: Digital copy permitted when selected. .TP Pre Emphasis: Audio data of track has pre emphasis when selected. .TP Two/Four Channel Audio: Select "Four Channel Audio" if the audio data encodes more than two channels. Of course, only two real channels will be recorded on a CD-R/CD-RW in any case. .TP ISRC: Allows one to edit the ISRC code of the track. The first fields holds the country code; it will only accept capital letters. The second field holds the owner code, capital letters and digits are allowed. The remaining fields holds the year and a serial number and will only accept digits. All fields must be filled to set the ISRC code and all fields must be cleared to remove it. .SS CD-TEXT Frame Allows one to enter and edit the CD-TEXT data of each language number for this track. All fields are optional but at least "Title" and "Performer" should be filled. .SH DEVICE CONFIGURE DIALOG (Settings->Devices) This non modal dialog shows the settings of all attached SCSI or ATAPI devices that identify themselves as CD-ROM or WORM device. All device settings that differ from the default settings will be permanently stored in the .I $HOME/.gnome/GnomeCDMaster configuration file. The "Apply" button must be used to make all changes permanent. The "Reset" button reverts all changes since the last apply or the dialog box was opened. The "Cancel" button withdraws all changes and closes the dialog box. .SS Devices Frame The browser shows the SCSI address (bus,id,lun) and the vendor/model string of all available devices. If devices are not automatically detected it is possible to add devices manually to the browser (see "Add Device" Frame). The "Status" column shows the actual device status: .TP Ready: Device has a disk loaded and is ready for an action. .TP Busy: Device is active with an unspecified action. .TP Recording: Device is recording. .TP No disk: Device has no disk loaded. .TP Not available: Device cannot be accessed. .PP The "Rescan" button can be used to start the automatic drive detection process. All changes will be lost and the newly detected devices take immediate effect without hitting "Apply". The "Delete" button removes the selected device. The change takes immediate effect and all other changes will be lost. .SS Device Settings Frame This frame allows one to edit the settings of the currently selected device. .TP Device Type: This option menu defines the device type which is used to control which actions can be performed with this device: CD-ROM: read only device, CD-R: CD-R recorder device, CD-RW: CD-RW/CD-R recorder device. .TP Driver: Option menu to select the driver that is used to access the device. If the device is known by the internal device database the correct driver is selected automatically. Otherwise "Undefined" will be shown and a suitable driver must be selected before any action can be performed with this device. .TP Driver Options: Enter special driver options here. The available options are described in the README (the documentation will be moved to this place soon). If the device is known by the internal device database the correct option flags are selected automatically. .TP Device Node: This field is only required for operating systems that cannot access a SCSI device by the bus,id,lun triple. In this case the device node that must be used to access the device should be entered here. .SS Add Device Frame This frame can be used to manually add a device. The bus,id,lun triple of the device and the vendor/product string must be specified before the "Add" button has an effect. It is not possible to overwrite an existing device with the same bus,id,lun triple. Use the "Delete" button of the "Devices" frame first in this case. .SH RECORD DIALOG (Actions->Record) This non modal dialog can be used to record the actual project on a CD-R/CD-RW. It is possible to record the actual project on multiple recorders simultaneously. The "Start" button will start recording processes on all devices that are selected in the "Available Recorder Devices" browser. For this purpose the .I cdrdao executable will be called and should be available in your PATH. For each selected device a non modal progress dialog will be opened. After the recording is started on all selected devices it is possible to load another toc-file or continue editing the existing project. It is also safely possible to quit the GUI. The recording will continue in background but you will have no feedback about the progress. The "Cancel" button will close the dialog box. .SS Available Recorder Devices Frame The browser shows all devices with device type CD-R or CD-RW. Only devices with "Ready" status are selectable. .SS Record Options Frame .TP Simulate/Write: Selects between simulated or real writing process. .TP Close Disk: If selected disk will not be appendable. Otherwise the recorded session is kept open. Note: The drivers 'generic-mmc-raw', 'sony-cdu920' and 'yamaha-cdr10x' cannot keep the recorded session open. .TP Eject: If selected the disk will be ejected after a successful writing process. Warning: This may cause buffer under runs with certain device combinations if multiple devices are recording. .TP Recording Speed: May be used to set an upper limit for the used recording speed. If a recorder device does not support the speed the next lower possible speed is used. .TP Reload: If selected the disk will be automatically reloaded if it appears to be not empty or not appendable. This is required after a simulation run for some devices (e.g. the Philips CDD2x00 recorder familiy). Warning: This may cause buffer under runs with certain device combinations if multiple devices are recording. .SH FILES .TP cdrdao: executed for recording .TP $HOME/.gnome/GnomeCDMaster: stores settings permanently .SH AUTHOR Andreas Mueller mueller@daneb.ping.de .SH SEE ALSO .BR cdrdao "(1), "cdda2wav "(1), "cdparanoia "(1)" ������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/gcdmaster.mime������������������������������������������������������0000664�0000000�0000000�00000000153�15114537466�0021470�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# mime types for gcdmaster application/x-toc ext: toc TOC application/x-cue ext: cue CUE ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/gcdmaster.png�������������������������������������������������������0000664�0000000�0000000�00000010462�15114537466�0021331�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���0���0���Wł‡���gAMA��± üa���bKGD�’�’�’ ½§“��� pHYs�� �� ŅŻ~ü���tIMEŠŪ^š&��ÆIDATxœĶ™{¬-W]Ē?æµÖ¬™Ł³÷>ēžūč½-ō¶÷ŚŅņ°Ä–hRĈbC@A„@D ‰IhlØÅŌ¢RĮ*ÅWå©Bil(oÅ链ァ÷<÷kfÖśłĒš}Īī„“4&ĘI&ūœ³ē¬õżž~ßßkš×E €¬B�ꯀ>Ö’ü_^ƒ1ßĒs Ø@ü’@AŻc= é#�±ū|¼Ėo~8X²Ż„؁Uą6ąĖĄ ĄĒ»õŸš„ Ļėāī™›Ūśo~8 pĶ[ŽĮ™g%ĻrØGLńŒ›Œ!Ė"³é6÷=x;W’ńoLæxßGąß-ä¬@+0Uh^ś=ö¾äq <ĪõZąĄžw]łF.»ģRœ°vR©[!„­1ĀØ.ĮZŹŅÓė;öģ-AkVテ¹łF®ūšŸsnz1üó³į~ŪĄ wŲøüQ¼tˆż_€æ xżŪ~įÕÕ»ÆzO?’(>+ČJOŻ(”1 šš:Dźč°ÖāsGŁĖ({Žzk›IӲƚ‚ĆG8wŗõd}xõ2ĻĄ™ĄPa#ĀźõМ ą’fŸču6š%`ļ?^żŪ>Ü'Ė""3T-“–~ß3GA¬Ć“0VčUõtĢhż$£ūīCļŗā–Æqö±cxcp1ž®p(Ą [ ]w½üQāš‰8ųśįƒg”×^ń*†Å˜z P[€¶PxCžBk3DD ƹ·8§Œ:ĮÖż÷n’ł-_#æ÷nüö&>F   Ūp®Ā%|SS𯟠č‰JčŽóĪ>Ņ’Š•o ×«Š&'Ž7‰šäiœĮø”lī™Œ uؙ…Œ,wģŁ[Šl­±ö»˜Žv+ł-_Ć?påö&yųĪŖPs'ZÆFø÷„°ńw§�śžø(­ _NYąėĄŅŽteįŃ�Į ±ŽOÜj˜ŽÖŠ ˊJkšYɤc ƲĢ"ڰ}’½Lļų6ö¶obz€|{‹"ņ‹ ·Ū¶K’Æ|.ÜŽGÄĀ£² A4݆”Fß \šŁk®błĄ2Y•‘•WX²ž ŒŪĒ䞖ńk4ė#D7XZj0F°VCĻųū}ēĀ=·c|€bc²i(TÉaēv¤räą!&pń§ą²ī«ļĻšy~Ūo\ń Ī<ņ44¶ÆŲ²%Ō‘8SÄE\^ь›·NŲó̜GsŠ}§­0žeŠŽY[ŻęųĆĒ0=H¹~’²©)U)H=K§ØUq“ =‡ŽqŪ«>HJÆßčWąåĄ¾Ÿ¹ōE˜b”E5‚4LÖ¢½WŚI ™Pī;ƒrx·|ćn>ųÉkłÜ© >ēüóyį¹ē±o²E³¹NYĻvĄÅ-I>*’45ūņœ�¼.>łølB?מė_łåģ9tÖN¶QAŃ@#1“˜¢ÅöZ†KK+ųƒ?½–ß{ļ{�žÓĮµ”śÆ{ī¾"~źG^pą4MĘä!Pt1'`ę�Ɛ…€kž{Įqż7¾śā÷Ƨi”Ø}®u“~ęfųĮ—=’§3HßhDęĀZ™¢A‰(J±r:ł‘权æę„šöKa°Īó`NĄküńc‡3c(;ŻĻId€šĢ4āTÉBĖӞü$Ā7¾śģsżØ.‰©1@”dŒ„żēķ'š. 4¦ž“öÉ)bˆh«ŲaÉ{’ģ�¼õ(d}Xńp~ĢC,c4e¾� Y·q«ÉÄ^Įň™M©Ś@G$ńÜ!šˆ,¤õ;čeéwSöH¤…F *:Ž„‰§šŒ0U~ł_šsĄ;Oļစs<œķą@LÕ/ŅBį ÷‰ĻĄ‹ā|ŒŲéŒl2ŅJī:ėĄ\·8\“ =ś“.mi­č,Y8ÖJœDā $:QĮ#źŸÜä?ż2Žü¦·�\õ»šÅĻĄ÷Ć Ęp^®w ų܁/ +»;‡</Åˆkjd<ŃL:G9Ö.JHŗ»óž¾L+ātkbśĆ!`0 jLŠņ(Ø a¦hĢŲžmaėe^żóÆåł\§žś/ĪoætÓłn<fOōB»#›Ņģ‚·˜¼kŽk%šņ\ÓŠŒ¶›=p/ x 3Yh¤ć  Ł •ƒ³÷A½~b£ WPDŠJl”Š" u>fÖ(ć‘rģŲ ś~“•źÆ|įK؋œšÅ›(W'«wą‹ |ށÆ$™\›% ē|�ak«=†¶ DśØ•ųéąœīą™Ļ€ńĒnųWb+ÄŚq LĶø„ig„Ž„©1G¶Ö[\oqjXŸU¬Ż{?ėwßĶä®»1ė”1Rv[dēąJ0}Ź •bz ˜œ‡Ģ‚‹éĆ«ń8)°l’:v ßNźxČ2,;xЇ šw}čO­m¦PkŖ¾ż Į˜NgL§ķ͆“Ūk,…ž xbÖVq[›m³cł² XWvŃܤJĄ©@*Ų2—Čx¬§§fفd å©Y(ž’ sZOĶἋ”÷ą†/|XG¢6ÄjL3m˜60µl®ÕlM”č=F…Y¾—Œ)v{Y=ŽmQÄH)]¶™[¾ōM^*ōś@?‘0E’‚čƒVŠw0p y'ÅEś,ŠåōŠ™>eŒC=(øņ=æÉš>Dš#š¦e6 L¶FŪ-u+LÄ!mdd–É­’…)²½=¹ŠŸN(є.,Æsk÷¾vŸÉ ō:eČĮ8(,dß%;ĒśŌ“öžŽpVöT‚ż1ÆųįW\Īx4f:no×L'6£:bė"…5”>āŚ1²¹†ŪÜ hjzų¬�Ū›—N61™xĄ#< Ų.¼`ō2(³äœä ;żŸ•$Wy8#‡s{pØo(éešG%üˆ×½ćķl­Øk”–ķZPO˜øyĻą“AF›Čź1Üö&Eh)ēérAćōŖ$énģĂé%Ö¤|ļRšŚ<IHJŁ•œž‚~ŁĮY9œŻ3¬ō®—CQÆąo–@¾u+W^s£ķ £‚³H=eŅ–d¤qŅI‹Œ·‘µ‡É'c ÉóŽtÖÕ Ø*EŖ]˳(£Lž4“LGB²®d¶#ą@ĻMéx%ƒĆ¹pØ“Teä}pƒ“ń|fžtļ]\žė?˱Ē‘°uÓ–"g!bB‹›Nš””pJV&T �{ ½…æB@:ցāøä¼I-‡ł 菂ž®€åN+ Ėe†ĻK°}Į®‹÷öįŸöĄ›¼ńWpƧ?Źśś˜¼™KÄŚˆ-̦ø¦&#’eÉ:ó€ÕžÜśģØ¾Ūś >5<VĄ¦¬ Ž¢YŽyąé¹¾ƒ¹p °TEøjA›óĄŖ˜«Kų؁oāĆńŻx%·ÜōqĘ«!m õ6×±“1ž€ó)£ģ�­HŚļ‚ł»Ą÷ɓÉłŌ@cĮ:A3‡ø¼ė…|JQƒ yĆžÜSł2Ɇ~—ÆhŗˆŸĆ%ŽŌŌ7Ą}_ųģõ³÷}öśŲ€üźWžē’½­M2ZÜ¢õ�r*©r!©/ b@„hŅø .7!EG Hr+JaX8ś>'³a’yG Ģ4iÓMĄ ŁJ}>v9üĆļĆ9Ÿ’ą»_ŅĀ󶆿v€³åų9¢ólŁżŽ[ ;¾#`әXׯ©5ØĶŗ:Ńż‹óP䆪Č(|‰±}`Ų„5ß=5ėŠF±[ę3ƒqĀĀ „ŽUšå2qģw\’{VLƓā|½ł$³~Žc+Š><0é W„h»fČĢ=ŠB)г¬džŅUȎõē4„+Zq"ŠUIÉ"„UV¦=8ĆĀ^gÉ]žņłĪZs«ūs9åŻ>5»¾M Jś¦1»PęØŠå Ķé»N>;p š¤7)ŗé)™¾IąKź×Ÿd…=™%·EKƒn½ł(6ļ ųĪĆsšóS©ŌŇĪ3±ńˆ”Ż<ą!Ļ„”s,Ł‚Bśƅ ³naÓYg;0Y×ī ¹QögJ*œūœ”“ÖĶ­æø^'rvÓhÉī“ėĄ“Œ§šŅˆĄĢ8ZS Ru(SX\īq®‡±ƒS\ī:¶Ū ·Ū§8Np–ž,)m/;ƒubŹnåī.»õ쁹 )€,??äR„Ę"ŒŒ%Hžˆ;€JˆeF›—Ø«¬5ģ6˜˜{`+¹_ņ®Ż5ˆ Lņ@a`Æ5xė»ō9$½lZb”…\Ń\’’blnu"Żč f [bi%G„īż …”Ī=Ó¬¤±łfóĘŖ Ž „~'…Ņ)‡" D(Œ”“¾ ąEó„  2šßŻk“3X›>UiU™D8°Ž„eīDa*Ž5S°)jY"g©‹ƒ¹Ė悄ūõ<MŲ™ąœ²ŌBeҁ“³¾ė: Ü.0\灼›‡›ŲåŅ›³)h1lX°”–tßKŌ¶‚į ī‘«,Q0Ąļ¤¼¹„čīZŠ9‰,_c\L 01yē­a§’„4“Sw Ptme&B„‰Āt :EcĖ,*G8…‘"¾ó€Ō0Ž’¦ąó2ąt–ȲŸ99ņhęÅĒÉ ]U£éXŅŲ®—éCIg “LBR“%½“ō©Ż„ź#`£‹µ [¶ƒ²Žy`¬¦“b•:P2‡Śœuéń9Y"c‰MœKÅ~r–°dD a†Ū¾;ŲœŪ¤01Ņõ/Ż&ō <TYz„uś“xß½JV…YP6Tõ$Ź:N˜jĖń <ąD,ŖE’¦ū ąÖ \A“}ŽĖO0ä<“Š3ńœ‰•=Ą F+f”ōÉØpōšR!&Ē»®g7ŠPIPz"ōŠ+•¢PB-4 ! ĘD²L±¹ „IŠ“4œ`×Ē«±åvüG„U…Vē±3°)žæĒ‚Yęa–¹™”|›’żdrg�‡°ŗ—&.3Še*†Tx©ŲŽe8kp&bÉ|“ŹDŖÜR ®g d­BĄÅ-¦×cC#5Óø¶ć1ÖćIÖĀ„c1p—ĀŽ«Ȁ^ņźĪɜ+Į @–EY’ Sr9AfoĆŁ1lØØŪ>UX¢ŌCJRROϼ€Ač‹ĮāÅѳ–²hqC‹*qC‘‘E¦3Œm¢FŹm$޵­Ēŗm6źć2ž×õv“ flĒĄ°”0C4™ „ƒ²Ś%°r#Ģž'Š·‰]Ž’I‹µ-6›bĢ:„K®=^sr¼dĘć%Į‰ą°äd8¼²R±CKšŽµ]$ڈø|½ g4ÓY»mėÉĶÖM;%dJ)?Ej¬—Ōˆ¹Į#ßäæ3ļeA×÷‚Ń4B‹WÄ*&@6 䓚b6”l‘>"}D Ĥ–WTŗCėR e~ĢĮT“]…8Q¤Pt9ĀŽˆ„1Ö­ėšQ2‚u ĶjČbŖ9Ę;šĢ„wń?{ö^$ž/O����IEND®B`‚��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/gcdmaster.xml�������������������������������������������������������0000664�0000000�0000000�00000002712�15114537466�0021344�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mime-info [ <!ELEMENT mime-info (mime-type)+> <!ATTLIST mime-info xmlns CDATA #FIXED "http://www.freedesktop.org/standards/shared-mime-info"> <!ELEMENT mime-type (comment|glob|magic|root-XML|alias|sub-class-of)*> <!ATTLIST mime-type type CDATA #REQUIRED> <!ELEMENT comment (#PCDATA)> <!ATTLIST comment xml:lang CDATA #IMPLIED> <!ELEMENT glob EMPTY> <!ATTLIST glob pattern CDATA #REQUIRED> <!ELEMENT magic (match)+> <!ATTLIST magic priority CDATA #IMPLIED> <!ELEMENT match (match)*> <!ATTLIST match offset CDATA #REQUIRED> <!ATTLIST match type (string|big16|big32|little16|little32|host16|host32|byte) #REQUIRED> <!ATTLIST match value CDATA #REQUIRED> <!ATTLIST match mask CDATA #IMPLIED> <!ELEMENT root-XML EMPTY> <!ATTLIST root-XML namespaceURI CDATA #REQUIRED localName CDATA #REQUIRED> <!ELEMENT alias EMPTY> <!ATTLIST alias type CDATA #REQUIRED> <!ELEMENT sub-class-of EMPTY> <!ATTLIST sub-class-of type CDATA #REQUIRED> ]> <mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info"> <mime-type type="application/x-toc"> <comment>Audio CD Table Of Content</comment> <magic priority="50"> <match offset="0" type="string" value="CD_DA" /> </magic> <glob pattern="*.toc" /> </mime-type> <mime-type type="application/x-cue"> <comment>Audio CD Table Of Content</comment> <glob pattern="*.cue" /> </mime-type> </mime-info> ������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/glade/��������������������������������������������������������������0000775�0000000�0000000�00000000000�15114537466�0017723�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/glade/Preferences.glade���������������������������������������������0000664�0000000�0000000�00000044147�15114537466�0023174�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <!--*- mode: xml -*--> <interface> <object class="GtkDialog" id="PrefDialog"> <property name="border_width">5</property> <property name="visible">True</property> <property name="title" translatable="yes">Preferences</property> <property name="type">GTK_WINDOW_TOPLEVEL</property> <property name="window_position">GTK_WIN_POS_CENTER</property> <property name="modal">False</property> <property name="resizable">True</property> <property name="destroy_with_parent">False</property> <property name="decorated">True</property> <property name="skip_taskbar_hint">False</property> <property name="skip_pager_hint">False</property> <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> <property name="focus_on_map">True</property> <property name="urgency_hint">False</property> <child internal-child="vbox"> <object class="GtkVBox" id="dialog-vbox1"> <property name="visible">True</property> <property name="homogeneous">False</property> <property name="spacing">2</property> <child internal-child="action_area"> <object class="GtkHButtonBox" id="dialog-action_area1"> <property name="visible">True</property> <property name="layout_style">GTK_BUTTONBOX_END</property> <child> <object class="GtkButton" id="ApplyButton"> <property name="visible">True</property> <property name="can_default">True</property> <property name="can_focus">True</property> <property name="label">gtk-apply</property> <property name="use_stock">True</property> <property name="relief">GTK_RELIEF_NORMAL</property> <property name="focus_on_click">True</property> </object> </child> <child> <object class="GtkButton" id="CancelButton"> <property name="visible">True</property> <property name="can_default">True</property> <property name="can_focus">True</property> <property name="label">gtk-cancel</property> <property name="use_stock">True</property> <property name="relief">GTK_RELIEF_NORMAL</property> <property name="focus_on_click">True</property> </object> </child> <child> <object class="GtkButton" id="OkButton"> <property name="visible">True</property> <property name="can_default">True</property> <property name="can_focus">True</property> <property name="label">gtk-ok</property> <property name="use_stock">True</property> <property name="relief">GTK_RELIEF_NORMAL</property> <property name="focus_on_click">True</property> </object> </child> </object> <packing> <property name="padding">0</property> <property name="expand">False</property> <property name="fill">True</property> <property name="pack_type">GTK_PACK_END</property> </packing> </child> <child> <object class="GtkNotebook" id="notebook1"> <property name="border_width">2</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="show_tabs">True</property> <property name="show_border">True</property> <property name="tab_pos">GTK_POS_TOP</property> <property name="scrollable">False</property> <property name="enable_popup">False</property> <child> <object class="GtkVBox" id="vbox1"> <property name="border_width">12</property> <property name="visible">True</property> <property name="homogeneous">False</property> <property name="spacing">6</property> <child> <object class="GtkLabel" id="label3"> <property name="visible">True</property> <property name="label" translatable="yes">Temporary files directory:</property> <property name="use_underline">False</property> <property name="use_markup">False</property> <property name="justify">GTK_JUSTIFY_LEFT</property> <property name="wrap">False</property> <property name="selectable">False</property> <property name="xalign">0</property> <property name="yalign">0.5</property> <property name="xpad">0</property> <property name="ypad">0</property> <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> <property name="width_chars">-1</property> <property name="single_line_mode">False</property> <property name="angle">0</property> </object> <packing> <property name="padding">0</property> <property name="expand">False</property> <property name="fill">False</property> </packing> </child> <child> <object class="GtkHBox" id="hbox1"> <property name="border_width">5</property> <property name="visible">True</property> <property name="homogeneous">False</property> <property name="spacing">10</property> <child> <object class="GtkEntry" id="TempDirectory"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="editable">True</property> <property name="visibility">True</property> <property name="max_length">0</property> <property name="text" translatable="yes"/> <property name="has_frame">True</property> <property name="invisible_char">•</property> <property name="activates_default">False</property> </object> <packing> <property name="padding">0</property> <property name="expand">True</property> <property name="fill">True</property> </packing> </child> <child> <object class="GtkButton" id="TempDialogButton"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="relief">GTK_RELIEF_NORMAL</property> <property name="focus_on_click">True</property> <child> <object class="GtkAlignment" id="alignment1"> <property name="visible">True</property> <property name="xalign">0.5</property> <property name="yalign">0.5</property> <property name="xscale">0</property> <property name="yscale">0</property> <property name="top_padding">0</property> <property name="bottom_padding">0</property> <property name="left_padding">0</property> <property name="right_padding">0</property> <child> <object class="GtkHBox" id="hbox2"> <property name="visible">True</property> <property name="homogeneous">False</property> <property name="spacing">2</property> <child> <object class="GtkImage" id="image1"> <property name="visible">True</property> <property name="stock">gtk-open</property> <property name="icon_size">4</property> <property name="xalign">0.5</property> <property name="yalign">0.5</property> <property name="xpad">0</property> <property name="ypad">0</property> </object> <packing> <property name="padding">0</property> <property name="expand">False</property> <property name="fill">False</property> </packing> </child> <child> <object class="GtkLabel" id="label5"> <property name="visible">True</property> <property name="label" translatable="yes">Browse...</property> <property name="use_underline">True</property> <property name="use_markup">False</property> <property name="justify">GTK_JUSTIFY_LEFT</property> <property name="wrap">False</property> <property name="selectable">False</property> <property name="xalign">0.5</property> <property name="yalign">0.5</property> <property name="xpad">0</property> <property name="ypad">0</property> <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> <property name="width_chars">-1</property> <property name="single_line_mode">False</property> <property name="angle">0</property> </object> <packing> <property name="padding">0</property> <property name="expand">False</property> <property name="fill">False</property> </packing> </child> </object> </child> </object> </child> </object> <packing> <property name="padding">0</property> <property name="expand">False</property> <property name="fill">False</property> </packing> </child> </object> <packing> <property name="padding">0</property> <property name="expand">False</property> <property name="fill">True</property> </packing> </child> <child> <object class="GtkLabel" id="label10"> <property name="visible">True</property> <property name="label" translatable="yes"><small><i>Make sure selected directory has sufficient available disk space</i></small></property> <property name="use_underline">False</property> <property name="use_markup">True</property> <property name="justify">GTK_JUSTIFY_LEFT</property> <property name="wrap">False</property> <property name="selectable">False</property> <property name="xalign">0</property> <property name="yalign">0.5</property> <property name="xpad">0</property> <property name="ypad">0</property> <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> <property name="width_chars">-1</property> <property name="single_line_mode">False</property> <property name="angle">0</property> </object> <packing> <property name="padding">0</property> <property name="expand">False</property> <property name="fill">True</property> </packing> </child> </object> <packing> <property name="tab_expand">False</property> <property name="tab_fill">False</property> <property name="menu_label" translatable="yes"/> </packing> </child> <child type="tab"> <object class="GtkLabel" id="label1"> <property name="visible">True</property> <property name="label" translatable="yes">Files</property> <property name="use_underline">False</property> <property name="use_markup">False</property> <property name="justify">GTK_JUSTIFY_LEFT</property> <property name="wrap">False</property> <property name="selectable">False</property> <property name="xalign">0.5</property> <property name="yalign">0.5</property> <property name="xpad">0</property> <property name="ypad">0</property> <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> <property name="width_chars">-1</property> <property name="single_line_mode">True</property> <property name="angle">0</property> </object> </child> </object> <packing> <property name="padding">0</property> <property name="expand">True</property> <property name="fill">True</property> </packing> </child> </object> </child> <action-widgets> <action-widget response="-10">ApplyButton</action-widget> <action-widget response="-6">CancelButton</action-widget> <action-widget response="-5">OkButton</action-widget> </action-widgets> </object> <object class="GtkFileChooserDialog" id="TempDirDialog"> <property name="visible">True</property> <property name="action">GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER</property> <property name="local_only">False</property> <property name="select_multiple">False</property> <property name="show_hidden">False</property> <property name="do_overwrite_confirmation">False</property> <property name="title" translatable="yes">Select directory to use for temporary audio data. </property> <property name="type">GTK_WINDOW_TOPLEVEL</property> <property name="window_position">GTK_WIN_POS_NONE</property> <property name="modal">False</property> <property name="resizable">True</property> <property name="destroy_with_parent">False</property> <property name="decorated">True</property> <property name="skip_taskbar_hint">False</property> <property name="skip_pager_hint">False</property> <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> <property name="focus_on_map">True</property> <property name="urgency_hint">False</property> <child internal-child="vbox"> <object class="GtkVBox" id="dialog-vbox2"> <property name="visible">True</property> <property name="homogeneous">False</property> <property name="spacing">24</property> <child internal-child="action_area"> <object class="GtkHButtonBox" id="dialog-action_area2"> <property name="visible">True</property> <property name="layout_style">GTK_BUTTONBOX_END</property> <child> <object class="GtkButton" id="TempBrowseCancel"> <property name="visible">True</property> <property name="can_default">True</property> <property name="can_focus">True</property> <property name="label">gtk-cancel</property> <property name="use_stock">True</property> <property name="relief">GTK_RELIEF_NORMAL</property> <property name="focus_on_click">True</property> <signal handler="gtk_widget_hide" last_modification_time="Thu, 09 Aug 2007 15:19:18 GMT" name="clicked" object="TempDirDialog"/> </object> </child> <child> <object class="GtkButton" id="TempBrowseOpen"> <property name="visible">True</property> <property name="can_default">True</property> <property name="has_default">True</property> <property name="can_focus">True</property> <property name="label">gtk-open</property> <property name="use_stock">True</property> <property name="relief">GTK_RELIEF_NORMAL</property> <property name="focus_on_click">True</property> </object> </child> </object> <packing> <property name="padding">0</property> <property name="expand">False</property> <property name="fill">True</property> <property name="pack_type">GTK_PACK_END</property> </packing> </child> </object> </child> <action-widgets> <action-widget response="-6">TempBrowseCancel</action-widget> <action-widget response="-5">TempBrowseOpen</action-widget> </action-widgets> </object> </interface> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/glade/ProjectChooser.glade������������������������������������������0000664�0000000�0000000�00000100026�15114537466�0023651�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <interface> <!-- interface-requires gtk+ 3.0 --> <object class="GtkWindow" id="window1"> <property name="can_focus">False</property> <child> <object class="GtkBox" id="box1"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="orientation">vertical</property> <child> <object class="GtkMenuBar" id="menubar1"> <property name="visible">True</property> <property name="can_focus">False</property> <child> <object class="GtkMenuItem" id="menuitem1"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">_Datei</property> <property name="use_underline">True</property> <child type="submenu"> <object class="GtkMenu" id="menu1"> <property name="visible">True</property> <property name="can_focus">False</property> <child> <object class="GtkImageMenuItem" id="imagemenuitem1"> <property name="label">gtk-new</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> <child> <object class="GtkImageMenuItem" id="imagemenuitem2"> <property name="label">gtk-open</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> <child> <object class="GtkImageMenuItem" id="imagemenuitem3"> <property name="label">gtk-save</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> <child> <object class="GtkImageMenuItem" id="imagemenuitem4"> <property name="label">gtk-save-as</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> <child> <object class="GtkSeparatorMenuItem" id="separatormenuitem1"> <property name="visible">True</property> <property name="can_focus">False</property> </object> </child> <child> <object class="GtkImageMenuItem" id="imagemenuitem5"> <property name="label">gtk-quit</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> </object> </child> </object> </child> <child> <object class="GtkMenuItem" id="menuitem2"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">_Bearbeiten</property> <property name="use_underline">True</property> <child type="submenu"> <object class="GtkMenu" id="menu2"> <property name="visible">True</property> <property name="can_focus">False</property> <child> <object class="GtkImageMenuItem" id="imagemenuitem6"> <property name="label">gtk-cut</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> <child> <object class="GtkImageMenuItem" id="imagemenuitem7"> <property name="label">gtk-copy</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> <child> <object class="GtkImageMenuItem" id="imagemenuitem8"> <property name="label">gtk-paste</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> <child> <object class="GtkImageMenuItem" id="imagemenuitem9"> <property name="label">gtk-delete</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> </object> </child> </object> </child> <child> <object class="GtkMenuItem" id="menuitem3"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">_Ansicht</property> <property name="use_underline">True</property> </object> </child> <child> <object class="GtkMenuItem" id="menuitem4"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">_Hilfe</property> <property name="use_underline">True</property> <child type="submenu"> <object class="GtkMenu" id="menu3"> <property name="visible">True</property> <property name="can_focus">False</property> <child> <object class="GtkImageMenuItem" id="imagemenuitem10"> <property name="label">gtk-about</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> </object> </child> </object> </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">0</property> </packing> </child> <child> <object class="GtkToolbar" id="toolbar1"> <property name="visible">True</property> <property name="can_focus">False</property> <child> <object class="GtkToolButton" id="toolbutton1"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="stock_id">gtk-new</property> </object> <packing> <property name="expand">False</property> <property name="homogeneous">True</property> </packing> </child> <child> <object class="GtkToolButton" id="toolbutton2"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="stock_id">gtk-open</property> </object> <packing> <property name="expand">False</property> <property name="homogeneous">True</property> </packing> </child> <child> <object class="GtkToolButton" id="toolbutton3"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="stock_id">gtk-save</property> </object> <packing> <property name="expand">False</property> <property name="homogeneous">True</property> </packing> </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">1</property> </packing> </child> <child> <object class="GtkBox" id="mainbox"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="spacing">10</property> <child> <object class="GtkImage" id="image1"> <property name="visible">True</property> <property name="can_focus">False</property> </object> <packing> <property name="expand">True</property> <property name="fill">True</property> <property name="position">0</property> </packing> </child> <child> <object class="GtkBox" id="box3"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="orientation">vertical</property> <child> <object class="GtkLabel" id="label11"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="xalign">0</property> <property name="ypad">1</property> <property name="label" translatable="yes">New Projct</property> <property name="ellipsize">start</property> <attributes> <attribute name="weight" value="bold"/> </attributes> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">0</property> </packing> </child> <child> <object class="GtkButton" id="DataButton"> <property name="can_focus">False</property> <property name="receives_default">True</property> <property name="relief">none</property> <child> <object class="GtkBox" id="box6"> <property name="visible">True</property> <property name="can_focus">False</property> <child> <object class="GtkImage" id="DataImage"> <property name="visible">True</property> <property name="can_focus">False</property> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">0</property> </packing> </child> <child> <object class="GtkBox" id="box7"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="orientation">vertical</property> <child> <object class="GtkLabel" id="label1"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="xalign">0</property> <property name="label" translatable="yes">Data</property> <attributes> <attribute name="weight" value="bold"/> </attributes> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">0</property> </packing> </child> <child> <object class="GtkLabel" id="label2"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">Store files in a CD</property> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">1</property> </packing> </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">1</property> </packing> </child> </object> </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">1</property> </packing> </child> <child> <object class="GtkButton" id="AudioButton"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="receives_default">True</property> <property name="valign">end</property> <property name="relief">none</property> <child> <object class="GtkBox" id="box8"> <property name="visible">True</property> <property name="can_focus">False</property> <child> <object class="GtkImage" id="AudioImage"> <property name="visible">True</property> <property name="can_focus">False</property> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">0</property> </packing> </child> <child> <object class="GtkBox" id="box9"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="orientation">vertical</property> <child> <object class="GtkLabel" id="label3"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="xalign">0</property> <property name="label" translatable="yes">Audio</property> <attributes> <attribute name="weight" value="bold"/> </attributes> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">0</property> </packing> </child> <child> <object class="GtkLabel" id="label4"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">Create an audio CD from audio files</property> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">1</property> </packing> </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">1</property> </packing> </child> </object> </child> </object> <packing> <property name="expand">False</property> <property name="fill">False</property> <property name="position">2</property> </packing> </child> <child> <object class="GtkButton" id="VideoButton"> <property name="can_focus">False</property> <property name="receives_default">True</property> <property name="relief">none</property> <child> <object class="GtkBox" id="box10"> <property name="visible">True</property> <property name="can_focus">False</property> <child> <object class="GtkImage" id="VideoImage"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="stock">gtk-missing-image</property> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">0</property> </packing> </child> <child> <object class="GtkBox" id="box11"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="orientation">vertical</property> <child> <object class="GtkLabel" id="label5"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="xalign">0</property> <property name="label" translatable="yes">Video</property> <attributes> <attribute name="weight" value="bold"/> </attributes> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">0</property> </packing> </child> <child> <object class="GtkLabel" id="label6"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">Create a Video CD from mpeg files</property> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">1</property> </packing> </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">1</property> </packing> </child> </object> </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">3</property> </packing> </child> <child> <object class="GtkButton" id="CopyButton"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="receives_default">True</property> <property name="relief">none</property> <property name="focus_on_click">False</property> <child> <object class="GtkBox" id="box12"> <property name="visible">True</property> <property name="can_focus">False</property> <child> <object class="GtkImage" id="CopyImage"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="stock">gtk-missing-image</property> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">0</property> </packing> </child> <child> <object class="GtkBox" id="box13"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="orientation">vertical</property> <child> <object class="GtkLabel" id="label7"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="xalign">0</property> <property name="label" translatable="yes">Copy</property> <attributes> <attribute name="weight" value="bold"/> </attributes> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">0</property> </packing> </child> <child> <object class="GtkLabel" id="label8"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">Make an exact copy of a CD</property> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">1</property> </packing> </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">1</property> </packing> </child> </object> </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">4</property> </packing> </child> <child> <object class="GtkButton" id="DumpButton"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="receives_default">True</property> <property name="relief">none</property> <child> <object class="GtkBox" id="box14"> <property name="visible">True</property> <property name="can_focus">False</property> <child> <object class="GtkImage" id="DumpImage"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="stock">gtk-missing-image</property> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">0</property> </packing> </child> <child> <object class="GtkBox" id="box15"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="orientation">vertical</property> <child> <object class="GtkLabel" id="label9"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="xalign">0</property> <property name="label" translatable="yes">Image</property> <attributes> <attribute name="weight" value="bold"/> </attributes> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">0</property> </packing> </child> <child> <object class="GtkLabel" id="label10"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">Create a file image from a CD</property> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">1</property> </packing> </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">1</property> </packing> </child> </object> </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">5</property> </packing> </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">1</property> </packing> </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">2</property> </packing> </child> <child> <object class="GtkStatusbar" id="statusbar1"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="orientation">vertical</property> <property name="spacing">2</property> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">3</property> </packing> </child> </object> </child> </object> </interface> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/glade/about.glade���������������������������������������������������0000664�0000000�0000000�00000002464�15114537466�0022041�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <GTK-Interface> <project> <name>about</name> <program_name>about</program_name> <directory></directory> <source_directory>src</source_directory> <pixmaps_directory>pixmaps</pixmaps_directory> <language>C++</language> <gnome_support>True</gnome_support> <gettext_support>True</gettext_support> <use_widget_names>False</use_widget_names> <output_main_file>True</output_main_file> <output_support_files>True</output_support_files> <output_build_files>True</output_build_files> <backup_source_files>True</backup_source_files> <main_source_file>interface.c</main_source_file> <main_header_file>interface.h</main_header_file> <handler_source_file>callbacks.c</handler_source_file> <handler_header_file>callbacks.h</handler_header_file> <support_source_file>support.c</support_source_file> <support_header_file>support.h</support_header_file> <translatable_strings_file></translatable_strings_file> </project> <widget> <class>GnomeAbout</class> <name>about_dialog</name> <modal>True</modal> <copyright>Copyright © 2000 (see Authors)</copyright> <authors>Andreas Mueller <mueller@daneb.ping.de> Jonas Munsin <jmunsin@iki.fi> Manuel Clos <llanero@jazzfree.com> </authors> <comments>The Gnome (CD) Burner (?)</comments> </widget> </GTK-Interface> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������cdrdao-cdrdao-f00afb2/gcdmaster/glade/blank-cdrw.glade����������������������������������������������0000664�0000000�0000000�00000014204�15114537466�0022746�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <GTK-Interface> <project> <name>blank-cdrw</name> <program_name>blank-cdrw</program_name> <directory></directory> <source_directory>src</source_directory> <pixmaps_directory>pixmaps</pixmaps_directory> <language>C++</language> <gnome_support>True</gnome_support> <gettext_support>True</gettext_support> <output_main_file>False</output_main_file> </project> <widget> <class>GtkWindow</class> <name>window1</name> <width>400</width> <height>300</height> <title>Blank CDRW GTK_WINDOW_TOPLEVEL GTK_WIN_POS_NONE False False True False GtkVBox vbox2 False 0 GtkFrame frame2 5 0 GTK_SHADOW_ETCHED_IN 0 True True GtkVBox vbox4 False 0 GtkScrolledWindow scrolledwindow1 5 GTK_POLICY_AUTOMATIC GTK_POLICY_ALWAYS GTK_UPDATE_CONTINUOUS GTK_UPDATE_CONTINUOUS 0 True True GtkCList clist3 True 4 22,80,104,80 GTK_SELECTION_SINGLE True GTK_SHADOW_IN GtkLabel CList:title label16 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkLabel CList:title label17 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkLabel CList:title label18 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkLabel CList:title label19 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkHButtonBox hbuttonbox2 GTK_BUTTONBOX_SPREAD 30 85 27 7 0 0 False False GtkButton button3 True True GtkButton button4 True True GtkFrame frame3 5 0 GTK_SHADOW_ETCHED_IN 0 False True GtkVBox vbox3 False 0 GtkRadioButton radiobutton2 True False True blank_type 0 False False GtkRadioButton radiobutton3 True False True blank_type 0 False False GtkHButtonBox hbuttonbox1 GTK_BUTTONBOX_SPREAD 30 85 27 7 0 5 False True GtkButton button1 True True GtkButton button2 True True GNOME_STOCK_BUTTON_CLOSE cdrdao-cdrdao-f00afb2/gcdmaster/glade/devices.glade000066400000000000000000000523431511453746600223520ustar00rootroot00000000000000 Devices devices src pixmaps C True True GtkWindow Configure_Devices 450 320 Configure Devices GTK_WINDOW_TOPLEVEL GTK_WIN_POS_NONE False False True False GtkTable table1 4 1 False 0 0 GtkFrame frame1 5 340 165 0 GTK_SHADOW_ETCHED_IN 0 1 0 1 0 0 True True False False True True GtkVBox vbox2 5 False 0 GtkScrolledWindow scrolledwindow1 GTK_POLICY_AUTOMATIC GTK_POLICY_ALWAYS GTK_UPDATE_CONTINUOUS GTK_UPDATE_CONTINUOUS 0 True True GtkCList clist1 True 6 25,15,27,74,84,75 GTK_SELECTION_SINGLE True GTK_SHADOW_IN GtkLabel CList:title label1 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkLabel CList:title label2 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkLabel CList:title label3 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkLabel CList:title label4 GTK_JUSTIFY_LEFT False 0.5 0.5 0 0 GtkLabel CList:title label5 GTK_JUSTIFY_LEFT False 0.5 0.5 0 0 GtkLabel CList:title label6 GTK_JUSTIFY_LEFT False 0.5 0.5 0 0 GtkHButtonBox hbuttonbox4 GTK_BUTTONBOX_SPREAD 20 85 27 7 0 0 False False GtkButton button9 True True GtkButton button10 True True GtkButton button11 True True GtkButton button12 True True GtkFrame frame2 5 0 GTK_SHADOW_ETCHED_IN 0 1 1 2 0 0 True True False False True True GtkTable table1 5 2 4 False 3 0 GtkLabel label7 GTK_JUSTIFY_CENTER False 1 0.5 0 0 0 1 0 1 0 0 False False False False True False GtkHBox hbox2 False 0 1 2 0 1 0 0 False False False False True True GtkOptionMenu optionmenu2 True CD-ROM CD-R CD-RW 0 0 False False GtkHBox hbox4 False 0 3 4 1 2 0 0 False False False False True True GtkEntry entry2 100 True True True 0 0 False False GtkOptionMenu optionmenu1 True Undefined cdd2600 generic-mmc generic-mmc-raw plextor plextor-scan ricoh-mp6200 sony-cdu920 sony-cdu948 taiyo-yuden teac-cdr55 yamaha-cdr10x 3 1 2 1 2 0 0 False False False False False False GtkHBox hbox3 False 0 3 4 0 1 0 0 False False False False True True GtkHBox hbox5 False 0 0 False False GtkEntry entry1 100 True True True 0 0 False False GtkLabel label10 GTK_JUSTIFY_CENTER False 1 0.5 0 0 2 3 0 1 0 0 False False False False True False GtkLabel label9 GTK_JUSTIFY_CENTER False 1 0.5 0 0 2 3 1 2 0 0 True False False False True False GtkLabel label8 GTK_JUSTIFY_CENTER False 1 0.5 0 0 0 1 1 2 0 0 True False False False True False GtkHButtonBox hbuttonbox1 GTK_BUTTONBOX_SPREAD 30 25 27 7 0 0 1 3 4 0 0 True True False False True True GtkButton button1 True True GNOME_STOCK_BUTTON_OK GtkButton button3 True True GNOME_STOCK_BUTTON_CANCEL GtkHSeparator hseparator1 0 1 2 3 0 0 False True False False True True GtkWindow Add_device Add Device GTK_WINDOW_TOPLEVEL GTK_WIN_POS_NONE False False True False GtkVBox vbox3 False 0 GtkFrame frame3 5 0 GTK_SHADOW_ETCHED_IN 0 True True GtkTable table2 5 3 2 False 5 5 GtkLabel label14 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 0 1 1 2 0 0 False False False False False False GtkLabel label15 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 0 1 2 3 0 0 False False False False False False GtkEntry entry3 True True True 0 1 2 1 2 0 0 True False False False True False GtkEntry entry4 True True True 0 1 2 2 3 0 0 True False False False True False GtkHBox hbox1 False 0 0 2 0 1 0 0 True True False False True True GtkLabel label11 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 0 False False GtkSpinButton spinbutton1 True 1 0 False GTK_UPDATE_ALWAYS False False 0 0 100 1 10 10 0 False False GtkLabel label12 GTK_JUSTIFY_CENTER False 1 0.5 0 0 0 True False GtkSpinButton spinbutton2 True 1 0 False GTK_UPDATE_ALWAYS False False 0 0 100 1 10 10 0 False False GtkLabel label13 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 0 True True GtkSpinButton spinbutton3 True 1 0 False GTK_UPDATE_ALWAYS False False 0 0 100 1 10 10 0 False False GtkHSeparator hseparator2 0 False False GtkHButtonBox hbuttonbox3 GTK_BUTTONBOX_SPREAD 30 85 27 7 0 0 False False GtkButton button7 True True GNOME_STOCK_BUTTON_OK GtkButton button8 True True GNOME_STOCK_BUTTON_CANCEL cdrdao-cdrdao-f00afb2/gcdmaster/glade/duplicate-cd.glade000066400000000000000000000246601511453746600232670ustar00rootroot00000000000000 duplicate-cd duplicate-cd src pixmaps C++ True True False GtkWindow window1 350 400 window1 GTK_WINDOW_TOPLEVEL GTK_WIN_POS_NONE False False True False GtkVBox vbox2 False 0 GtkFrame frame4 5 0 GTK_SHADOW_ETCHED_IN 0 False False GtkVBox vbox3 False 0 GtkScrolledWindow scrolledwindow1 5 GTK_POLICY_AUTOMATIC GTK_POLICY_ALWAYS GTK_UPDATE_CONTINUOUS GTK_UPDATE_CONTINUOUS 0 True True GtkCList clist3 True 4 22,67,104,80 GTK_SELECTION_SINGLE True GTK_SHADOW_IN GtkLabel CList:title label16 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkLabel CList:title label17 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkLabel CList:title label18 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkLabel CList:title label19 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkHButtonBox hbuttonbox1 GTK_BUTTONBOX_SPREAD 30 85 27 7 0 0 False False GtkButton button1 True True GtkButton button2 True True GtkScrolledWindow scrolledwindow2 5 GTK_POLICY_ALWAYS GTK_POLICY_ALWAYS GTK_UPDATE_CONTINUOUS GTK_UPDATE_CONTINUOUS 0 True True GtkCList clist2 True 3 45,136,80 GTK_SELECTION_MULTIPLE True GTK_SHADOW_IN GtkLabel CList:title label9 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkLabel CList:title label10 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkLabel CList:title label11 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkFrame frame3 5 0 GTK_SHADOW_ETCHED_IN 0 False False GtkTable table2 4 1 False 0 0 GtkHBox hbox2 False 0 0 1 0 1 0 0 False True False False True True GtkLabel label14 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 5 False False GtkSpinButton spinbutton1 True 1 0 False GTK_UPDATE_ALWAYS False False 50 0 100 1 10 10 0 False False GtkCheckButton checkbutton5 True True True 5 False False GtkCheckButton checkbutton6 True False True 0 1 3 4 0 0 False True False False True False GtkCheckButton checkbutton3 True False True 0 1 2 3 0 0 False True False False True False GtkHBox hbox3 False 0 0 1 1 2 0 0 False True False False True True GtkLabel label15 GTK_JUSTIFY_LEFT False 0 0.5 5 0 0 False False GtkOptionMenu optionmenu1 True No checking Avoid jitter Jitter + checks Jitter + Scratch 3 0 False False cdrdao-cdrdao-f00afb2/gcdmaster/glade/fixate-cd.glade000066400000000000000000000117551511453746600225760ustar00rootroot00000000000000 fixate-cd fixate-cd src pixmaps C++ True True False GtkWindow window1 400 230 Fixate CD GTK_WINDOW_TOPLEVEL GTK_WIN_POS_NONE False False True False GtkVBox vbox2 False 0 GtkFrame frame2 5 0 GTK_SHADOW_ETCHED_IN 0 True True GtkVBox vbox2 False 0 GtkScrolledWindow scrolledwindow1 5 GTK_POLICY_AUTOMATIC GTK_POLICY_ALWAYS GTK_UPDATE_CONTINUOUS GTK_UPDATE_CONTINUOUS 0 True True GtkCList clist3 True 4 22,80,104,80 GTK_SELECTION_SINGLE True GTK_SHADOW_IN GtkLabel CList:title label16 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkLabel CList:title label17 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkLabel CList:title label18 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkLabel CList:title label19 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkHButtonBox hbuttonbox1 GTK_BUTTONBOX_SPREAD 30 85 27 7 0 0 False False GtkButton button1 True True GtkButton button2 True True GtkHButtonBox hbuttonbox2 5 GTK_BUTTONBOX_SPREAD 30 85 27 7 0 0 False False GtkButton button3 True True GtkButton button4 True True GNOME_STOCK_BUTTON_CLOSE cdrdao-cdrdao-f00afb2/gcdmaster/glade/get-info.glade000066400000000000000000000300161511453746600224310ustar00rootroot00000000000000 get-info get-info src pixmaps C++ True True False GtkWindow window1 400 400 CD Info GTK_WINDOW_TOPLEVEL GTK_WIN_POS_NONE False False True False GtkVBox vbox2 False 0 GtkFrame frame2 5 0 GTK_SHADOW_ETCHED_IN 0 False False GtkVBox vbox2 False 0 GtkScrolledWindow scrolledwindow1 5 GTK_POLICY_AUTOMATIC GTK_POLICY_ALWAYS GTK_UPDATE_CONTINUOUS GTK_UPDATE_CONTINUOUS 0 True True GtkCList clist3 True 4 22,80,104,80 GTK_SELECTION_SINGLE True GTK_SHADOW_IN GtkLabel CList:title label16 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkLabel CList:title label17 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkLabel CList:title label18 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkLabel CList:title label19 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkHButtonBox hbuttonbox2 GTK_BUTTONBOX_SPREAD 30 85 27 7 0 0 False False GtkButton button2 True True GtkButton button3 True True GtkFrame frame4 5 0 GTK_SHADOW_ETCHED_IN 0 True True GtkVBox vbox3 False 0 GtkScrolledWindow scrolledwindow2 5 GTK_POLICY_AUTOMATIC GTK_POLICY_ALWAYS GTK_UPDATE_CONTINUOUS GTK_UPDATE_CONTINUOUS 0 True True GtkCList clist2 True 3 45,152,80 GTK_SELECTION_MULTIPLE True GTK_SHADOW_IN GtkLabel CList:title label9 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkLabel CList:title label10 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkLabel CList:title label11 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkHButtonBox hbuttonbox3 GTK_BUTTONBOX_SPREAD 30 85 27 7 0 0 False False GtkButton button4 True True GtkButton button5 True True GtkFrame frame3 5 0 GTK_SHADOW_ETCHED_IN 0 False False GtkTable table2 3 2 False 0 0 GtkLabel label22 GTK_JUSTIFY_LEFT False 7.45058e-09 3.42727e-07 50 0 0 1 2 3 0 0 True False False False True False GtkLabel label21 GTK_JUSTIFY_CENTER False 7.45058e-09 0.5 50 0 0 1 1 2 0 0 True False False False True False GtkLabel label20 GTK_JUSTIFY_LEFT False 7.45058e-09 0.5 50 0 0 1 0 1 0 0 False False False False True False GtkLabel label23 GTK_JUSTIFY_CENTER False 7.45058e-09 0.5 0 0 1 2 0 1 0 0 False False False False True False GtkLabel label24 GTK_JUSTIFY_CENTER False 7.45058e-09 0.5 0 0 1 2 1 2 0 0 False False False False True False GtkLabel label25 GTK_JUSTIFY_CENTER False 7.45058e-09 0.5 0 0 1 2 2 3 0 0 False False False False True False GtkHButtonBox hbuttonbox1 GTK_BUTTONBOX_DEFAULT_STYLE 30 85 27 7 0 0 False False GtkButton button1 True True GNOME_STOCK_BUTTON_CLOSE cdrdao-cdrdao-f00afb2/gcdmaster/glade/record-dialog.glade000066400000000000000000000213461511453746600234420ustar00rootroot00000000000000 record-dialog record-dialog src pixmaps C++ True True False GtkWindow window1 400 300 ASUS CD-S500/A GTK_WINDOW_TOPLEVEL GTK_WIN_POS_NONE False False True False GtkVBox vbox2 5 False 0 GtkLabel label10 GTK_JUSTIFY_CENTER False 0.5 0.5 7 2 5 False False GtkScrolledWindow scrolledwindow2 GTK_POLICY_AUTOMATIC GTK_POLICY_ALWAYS GTK_UPDATE_CONTINUOUS GTK_UPDATE_CONTINUOUS 0 True True GtkCList clist2 True 2 32,80 GTK_SELECTION_SINGLE True GTK_SHADOW_IN GtkLabel CList:title label5 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkLabel CList:title label6 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkHBox hbox1 5 False 0 0 False True GtkLabel label11 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 0 True True GtkLabel label12 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 0 True True GtkLabel label13 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 0 True True GtkTable table1 3 2 False 0 0 5 False False GtkProgressBar progressbar3 30 0 100 GTK_PROGRESS_CONTINUOUS GTK_PROGRESS_LEFT_TO_RIGHT False True 30.00 %% 0.500001 0.5 1 2 0 1 15 0 True False False False True False GtkProgressBar progressbar2 50 0 100 GTK_PROGRESS_CONTINUOUS GTK_PROGRESS_LEFT_TO_RIGHT False True 50.00 %% 0.5 0.5 1 2 1 2 15 0 True False False False True False GtkProgressBar progressbar1 97 0 100 GTK_PROGRESS_CONTINUOUS GTK_PROGRESS_LEFT_TO_RIGHT False True 97.00 %% 0.5 0.5 1 2 2 3 15 0 True False False False True False GtkLabel label9 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 0 1 0 1 15 0 False False False False True False GtkLabel label8 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 0 1 1 2 15 0 False False False False True False GtkLabel label7 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 0 1 2 3 15 0 False False False False True False GtkHButtonBox hbuttonbox2 GTK_BUTTONBOX_DEFAULT_STYLE 30 85 27 7 0 0 False False GtkButton button2 True True GNOME_STOCK_BUTTON_CANCEL cdrdao-cdrdao-f00afb2/gcdmaster/glade/record-generic.glade000066400000000000000000000057551511453746600236250ustar00rootroot00000000000000 Project1 project1 src pixmaps C True True GtkWindow window1 10 630 460 Task xxxx GTK_WINDOW_TOPLEVEL GTK_WIN_POS_NONE False False True False GtkVBox vbox2 False 5 GtkHBox hbox1 False 8 5 True True GtkVBox vbox3 False 0 0 True True Placeholder GtkVSeparator vseparator1 0 False True GtkVBox vbox4 False 0 0 True True Placeholder GtkHSeparator hseparator1 0 False False GtkHButtonBox hbuttonbox1 GTK_BUTTONBOX_END 30 85 27 7 0 0 False True GtkButton button8 True True GNOME_STOCK_BUTTON_OK GtkButton button9 True True GNOME_STOCK_BUTTON_CLOSE GtkButton button10 True True GNOME_STOCK_BUTTON_HELP cdrdao-cdrdao-f00afb2/gcdmaster/glade/record.glade000066400000000000000000000321521511453746600222020ustar00rootroot00000000000000 record record src pixmaps C++ True True False GtkWindow window1 350 400 window1 GTK_WINDOW_TOPLEVEL GTK_WIN_POS_NONE False False True False GtkVBox vbox3 False 0 GtkHBox hbox3 False 0 0 True True GtkRadioButton radiobutton1 True False True target 0 False False GtkRadioButton radiobutton2 True False True target 0 False False GtkFrame frame2 5 0 GTK_SHADOW_ETCHED_IN 0 True True GtkVBox vbox2 False 0 GtkScrolledWindow scrolledwindow1 5 GTK_POLICY_AUTOMATIC GTK_POLICY_ALWAYS GTK_UPDATE_CONTINUOUS GTK_UPDATE_CONTINUOUS 0 True True GtkCList clist3 True 4 28,69,86,80 GTK_SELECTION_SINGLE True GTK_SHADOW_IN GtkLabel CList:title label10 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkLabel CList:title label11 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkLabel CList:title label12 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkLabel CList:title label13 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 GtkHButtonBox hbuttonbox2 GTK_BUTTONBOX_SPREAD 30 85 27 7 0 0 False False GtkButton button4 True True GtkButton button5 True True GtkFrame frame3 5 0 GTK_SHADOW_ETCHED_IN 0 True True GtkTable table2 4 2 False 0 0 GtkCheckButton checkbutton4 True False True 0 1 1 2 0 0 False True False False True False GtkCheckButton checkbutton5 True True True 0 1 0 1 0 0 True False False False True False GtkCheckButton checkbutton7 True True True 1 2 0 1 0 0 True False False False True False GtkCheckButton checkbutton3 True False True 1 2 1 2 0 0 False True False False True False GtkHBox hbox5 False 0 0 2 3 4 0 0 False True False False True True GtkLabel label15 GTK_JUSTIFY_CENTER False 0.5 0.5 5 0 0 False False GtkOptionMenu optionmenu1 True Max 1x 2x 4x 6x 8x 10x 12x 0 0 False False GtkHBox hbox4 False 0 0 2 2 3 0 0 False False False False True False GtkLabel label16 GTK_JUSTIFY_CENTER False 0.5 0.5 5 0 0 False False GtkSpinButton spinbutton1 True 1 0 False GTK_UPDATE_ALWAYS False False 60 0 100 1 10 10 0 False False GtkLabel label17 GTK_JUSTIFY_CENTER False 0.5 0.5 5 0 0 False False GtkLabel label18 GTK_JUSTIFY_CENTER False 0.5 0.5 0 0 0 False False GtkFrame frame4 5 0 GTK_SHADOW_ETCHED_IN 0 True True GtkVBox vbox3 False 0 GtkRadioButton radiobutton3 True False True image_type 0 False False GtkRadioButton radiobutton4 True False True image_type 0 False False GtkLabel label14 GTK_JUSTIFY_CENTER False 7.45058e-09 0.5 0 0 0 False False GtkEntry entry1 True True True 0 0 False False cdrdao-cdrdao-f00afb2/gcdmaster/guiUpdate.cc000066400000000000000000000027171511453746600211140ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller * * 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. */ #include "guiUpdate.h" #include "xcdrdao.h" #include "gcdmaster.h" #include "DeviceConfDialog.h" #include "ProgressDialog.h" #include "ProcessMonitor.h" #include "CdDevice.h" #include "TocEdit.h" #include "util.h" void guiUpdate(unsigned long level) { std::list::iterator i = GCDMaster::apps.begin(); for (; i != GCDMaster::apps.end(); i++) { (*i)->update(level); } if (deviceConfDialog != NULL) deviceConfDialog->update(level); if (PROGRESS_POOL != NULL) PROGRESS_POOL->update(level); } bool guiUpdatePeriodic() { if (CdDevice::updateDeviceStatus()) guiUpdate(UPD_CD_DEVICE_STATUS); return true; } cdrdao-cdrdao-f00afb2/gcdmaster/guiUpdate.h000066400000000000000000000030001511453746600207400ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998, 1999 Andreas Mueller * * 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. */ #ifndef __GUIUPDATE_H__ #define __GUIUPDATE_H__ #define APP_NAME "Gnome CD Master" #define UPD_ALL 0xffffffff #define UPD_TOC_DATA 0x00000001 #define UPD_TRACK_DATA 0x00000002 #define UPD_SAMPLES 0x00000004 #define UPD_TRACK_MARK_SEL 0x00000008 #define UPD_SAMPLE_SEL 0x00000010 #define UPD_SAMPLE_MARKER 0x00000020 #define UPD_EDITABLE_STATE 0x00000040 #define UPD_TOC_DIRTY 0x00000080 #define UPD_CD_DEVICES 0x00000100 #define UPD_CD_DEVICE_STATUS 0x00000200 #define UPD_PROGRESS_STATUS 0x00000400 #define UPD_PLAY_STATUS 0x00000800 extern void guiUpdate(unsigned long level = 0); extern bool guiUpdatePeriodic(); #endif cdrdao-cdrdao-f00afb2/gcdmaster/org.gnome.gcdmaster.gschema.xml000066400000000000000000000016531511453746600246470ustar00rootroot00000000000000 'cdrdao' path to cdrdao executable '' directory for temporary files true eject warning true reload warning true on-the-fly warning [] Configured devices cdrdao-cdrdao-f00afb2/gcdmaster/stock/000077500000000000000000000000001511453746600177725ustar00rootroot00000000000000cdrdao-cdrdao-f00afb2/gcdmaster/stock/.cvsignore000066400000000000000000000000371511453746600217720ustar00rootroot00000000000000Makefile Makefile.in pixbufs.h cdrdao-cdrdao-f00afb2/gcdmaster/stock/Makefile.am000066400000000000000000000020361511453746600220270ustar00rootroot00000000000000IMAGES = \ play.png \ pause.png \ stop.png \ gcdmaster.png \ open.png \ audiocd.png \ copycd.png \ dumpcd.png \ record.png noinst_DATA = pixbufs.h CLEANFILES = $(noinst_DATA) pixbufs.h: $(IMAGES) gdk-pixbuf-csource --raw --name play_pixbuf $(srcdir)/play.png > $(srcdir)/pixbufs.h gdk-pixbuf-csource --raw --name pause_pixbuf $(srcdir)/pause.png >> $(srcdir)/pixbufs.h gdk-pixbuf-csource --raw --name stop_pixbuf $(srcdir)/stop.png >> $(srcdir)/pixbufs.h gdk-pixbuf-csource --raw --name gcdmaster_pixbuf $(srcdir)/gcdmaster.png >> $(srcdir)/pixbufs.h gdk-pixbuf-csource --raw --name open_pixbuf $(srcdir)/open.png >> $(srcdir)/pixbufs.h gdk-pixbuf-csource --raw --name audiocd_pixbuf $(srcdir)/audiocd.png >> $(srcdir)/pixbufs.h gdk-pixbuf-csource --raw --name copycd_pixbuf $(srcdir)/copycd.png >> $(srcdir)/pixbufs.h gdk-pixbuf-csource --raw --name dumpcd_pixbuf $(srcdir)/dumpcd.png >> $(srcdir)/pixbufs.h gdk-pixbuf-csource --raw --name record_pixbuf $(srcdir)/record.png >> $(srcdir)/pixbufs.h EXTRA_DIST = $(IMAGES) pixbufs.h cdrdao-cdrdao-f00afb2/gcdmaster/stock/audiocd.png000066400000000000000000000046461511453746600221220ustar00rootroot00000000000000‰PNG  IHDR00Wł‡gAMA± üabKGD’’’ ½§“ pHYs  ŅŻ~ütIMEŃ/!¶Īē #IDATxœķ˜}ŒUÅĘ3sęœsļŻ½»Ė— µ(Fʶ4Z?@”`µAQLm#b“ U¢¦5’ZmćR±Õb5Ę[°•šųHjÕ¶ĮŚ(µQ”ÕJ—–ݽ÷|Ÿ™žq/‹ZwĮe­i²Or“›óĪyēyμó¾3/ bƒÄg qļŚcqŸ˜üHüOį €ĆYÅżč÷j„Ø­ä9ĄĄ$ą8`$ŠP·W€oÆ[€gsøÄxø(Ü}ćŒ},žö ©į¤>H‰Ö†8ŖšŽĪ·ø}ł÷Bą—ĄCĄ żåÓ__^ųįu ™6m*ŽŪHĒ^K’ LnIŖ¹ š@) —bƒCĖŠŲ„Ż;Žfß^dÅ£?;,>żŁÄwī'0kęi”<_ø>(!B „ĀZ‹Å"…@*Ö „i5Äś LžāVܿӏśžŌ“ĻKÖŽ¾¬ē”1Ų²˜†‰ å …JP,iŅ8$«T‚ˆ8˱qśĮ9–Ōēhhƀ cGŽž±ž–„ŒōƒCĒląė Ļ)A)!$R É„$·‚ׯ0„>÷a 8Xøžī%4hF—4ŗ qü¤3ŒšŸĮū¤ūŖŪISSŠ”„BŹMĮžvŗ÷ķ”;­ŅīxT¤Cā8äā@ā)ś„‚‡«]ī]ńĄĀ:‡~ øł¶łó3ī$„."=§TÄkņzč’ÄZ"«éŚ’–c<ĘLĶųÉć™xʱŒ;„¦!šĪ‚ĖįPµK‰TŠ‚ļöųj,ś4ą <UĢ(75įĮ=¬ä®ūļų+šĄŽlæjõ“Oœ¼ąźkYpåUģÜŁF„³ GI¤=p *»²Vßėó”4—ͽ”ĒVÆŗ°?Μ;å|„lGOūraÜ×ĪķłÆFĮbń‡É/_³ŸüĄ­šµXöąOī[zĢ‘#™=ė|Nœ5€ē~õėžAEu ¢E½(ŸwÖŁ<¶zՙ½‘ģkL~ĀpLcś!ņ…é֘Ź Ü’ąĆ+?B~?nVžü‘G8±õ =g^<»ēƒÖ”MŃq(8¾£8¢e(Ą„ž^(6"ņ¾'&’jņČrõåWĢ–}ĢŠeĄük,čÕWŃó)zE×£ 5E­i(śĆū#›XlÜ÷‰Wā"¬K°·‹yĢå†E7,„³ß®’^–.¾įz.»äā^}łĻõš¼Z*Վ‹§Ż^ĒCß{ =źG6”˼³į%ĘM?õæ¼łäÉ*991•ø•4sÅ70õ”©¬Z»ęä—^޲ÜXĖi§Oeī¼9œ<~m»ŽļŒvĄ±XĘ,†°+hļķ¾ācƦŸvŌ±Ē`©ŹĘMŸÜcܶś% )‰§– °“U2=ŸęĻEyD 椩V#R«ć€ī®÷aCŠ.§~õėž›7# XĮžėĘæŽŽĮŁ—ćy`śĒŠīCĄęßnz~ŚÕcÆÄZ0iĪ›æy“ŒČČ !q–j5gW`q•d_҈iļ ö€Ć®öNR#A; Ķ^‘}aĀļ×=EÉńń”ƒ²µ3“ÅÖųck©THÖ®{`sV`°õµUńü&›[l9$’’ÄPéĪčĮ:ŽŁ0Œ†…7¬‘“F`‰Ü!‹’‚/ŃEå»X,&7ÄqFšäkR’X9މÄä9Ö„”DqĢ5‹—ŠÖÖ¶ ˜w0r‡"ą©¶öŻ3^~żĻ£¦NšJŒKę¹k hĘ׊†¢Äóާ®ƒµc išÅiķž,ØÆŒÄZPNŽRĄšœ(JųΒżńśė[Y@p^‡|„Ü L’ūŽķėęÜt)mķ»Ę¢8ZįūGŁŚ Ģ©u#öo.!@1°ˆzUÉsEœ:äX¬ģé øąāóyóoŪÖQĖł»…Ų”®@< ųOo^{FY»“Œ<‰r©H© p}vÖÕ)ȍĮKšå$iV j7“Z¶,iššĀĘÜŗtĄ€Ėės§±upī¢o-fŹ”™ 5·äb}!!Ķ2ņ,':»B’8ÅXp“"5–(JŲŗu +ü]Øķ³;€?|R"‡Ū˜\A½µxĒ-÷q|ėDZšĖ(§Ūa”ŠŁ!aXåŻ÷¶s×÷o€·7õ—Ą@t–į3lībƒÄ ń’ ŁÆ;Žž«IEND®B`‚cdrdao-cdrdao-f00afb2/gcdmaster/stock/copycd.png000066400000000000000000000055221511453746600217650ustar00rootroot00000000000000‰PNG  IHDR00Wł‡gAMA± üabKGD’’’ ½§“ pHYs  d_‘tIMEŃ6#Ā×lä ĻIDATxœķ˜}WÕyĒ?ēœūöūķ‹ūfEAŖpѼ  ZQ#ZŃ@Zėčų’Ńh51ĘŌ¦©iRµÕbM'‰†šv4¦3Ō‰±`Ö£Ē Ń y©™BÕeewæū~ĪÓ?ījv©:ķL3³ßīÜū™;÷|ļsĪóœóĄ„&4” MhBæÅRā ,½ĄIĄ$ u”7€ ½€¶CųŪĄėĄĻ­Ą3€ūcł@×+Śż·ßĖ “gś!äMRā"­ń}G–6ŲżÖė|yݟx>ó{ĻdžéĖ8yƜĆ8ßž’ß6p&ppį·ü K—.Ę ŚÜ/ä„ĀY!o[E3Ɓ1ŌjõVĪīHĪŽ’Į³/æĄß=žmfŸ|W|ā*zēĢ“O÷/¾ęą_[sõµ3’võĶĢ>uį×ņB°…[ää֑;c AčQ«ūŌźłHƒŌ Ż=“Yvī8•šõoŻug~lža¼§§sę+ƽzÕŌ{öĆč6WoüņWXŠ;…°ę”=Rć{$±Ć:…s–Ņ:rė£&Œ<::#\™Ņfؑ–ÉR¦¶·±ä¼e<ō÷ńŹömœvŹl’ÜĘ’µoóB`šæYOļĖ@°yź¤É 6Üv Ż-%N(£Ńž ~ą‘åŠŅ*p—%¹ 0ž¦µ5 µŻ'ŚĻžFLœåŽ`‹˜F‘kŸ‹.¾”ē~²‰g·ö1gV/ĶćæśåöCCĪ6ńū5šō)'NŸ’½[n¦^oAŠć¤JŚ«L€Ā„I\E%·9™õńC®že38<ÄH3F5ö+”éäŚPj¤t|ō̳yķ՗łŁĖ/Š;ļŒ1ł®Æ»’¾łĄwߏµĄŹ§¾tõÖm4Ź(”jAbEŁ­1Fa"…oIźQ–Pø*QäÓŅjhīchx˜"dČ ˆ•Ga<¬RX@i J3’¬³yņÉą@’0ķŌ¹cņĶ?Ś8č¦ZąļŃĮYh šćĶ÷ÆęųÉSpVĀRꂔ‚+5e&””°ĒQ›ŌIŠŻģŁŠĢš Ę5Ž9¶•²1ĄŠö)C¢(”Ęi]EPkŒŃž‡g4¾1JnżĢµ\yżmLŸyŹøX ōoŽsŻŖ“}l!hƒ2ćū˜P£<Ö eĄ‹ŹŲ#ė/»#ŗOģ$ź˜L÷ń=tMꔽ#DŁaž3ĶČ-‰0c QčÓ…ŌƀZP Ņ;‹.»œß; ŽŲÅŽ}ƒŌĆßӄž‡§žÖh„ŠHąćóĪ`ķŗŽūÓ§M“Sķz©*ų{"pćM+VœsŽ’óŃ&@ū!Ź0A ķG蠆ņ"ta¢ˆ¶ć£mŹdÖ>¾žOÆYM2Ņą.XĘi3¦ńģÖ-<ŗž1¢(dłēÓś„J8ŖŅājž&4šš§“&Š _ƒo ž6ōæż&§Ļ™3.’·Æõρ³ÆXt J·U«BjŌ=])¢Ą ‚uĒ?=¹ūy˜›®¹’Ļß|j”_uòīŃļ³ö‘‡9ńøI\¶üž+O@œCD”śĶņS£Kń¢s–p’7æA«QćņüĮg<…ōčuÖѧk+p-®ÕįZ,®ī<@҉}܈ō1eG¾õ]V.æ˜Ļ_ÓaüīĻ~‘ö¶v[æžöZ£‚£ü€£Āˆ¶ ¤=Œhõ}Z<ŸŗēQó<"ĻpLg7»vļ>"fµŽ®ÕŪPV«ž¢@@JA¬ąD!N£DcSįĘk>Ķķ÷|®¶Nnæś†÷šÆ<šĆ#ĆüÅ]waŒ”­½ gÖZœsˆ­"łN4D„90‹[6šN®ź¶½śDaTĆY+H{‚Ķrr yīhŒ” & ž‡' [{hķ4„=mŲ²`Ļži^ üķ AøŸšS„8"ćh­…D&Ą¼óae4qc˜y\Čż6³gĪ—ó8ؐ½“F<óü–-øÜį¤ĄµÄiAZ@Ņ,Ģi¤ą‚-Š,ģ&«m5"h­Qœ”8ŹRÓhJ“:MRjFšI™Rˆ £õD9ś6o棧ŸĪ“§ŒĖ©ĪĪļž`÷ŻņšŸ1(ocƒ&EQ’e–¤QŠl”äÖ›ķ ©;ˆ<…ż*ŌNŠj“œY‹³EDR ārŃ$ÖŠHqž‘9‡U ģ}ūMn’ėæįņ+Čū8Dč֝µjq3& āFNšXJgh8]MČhj5tą!RŚh Ŗš³Z8,óÉqˆń(Ņ’šiFjsFŅ„…—ÆāĖ’€YsN—ė8d' ‡Ÿž–¾ō‹W§ž3wÖłÕą Ą÷QiŠE½®©Eæ`¢ąŻ\e%En«œÖXQˆ²x4g-āJkŅ,ć¦;WÓŃż;ܱęžqy’óĄŖC?–€§śöžžO·’ģŲŽ‹É(Ć%BL‘oh­kĀHį…>*šŖ¢ćEaI³”Ź€Ud4"`<‹1ŗŚ39KšęܶśNFš·žéר·ųcņŪ·o–3Ī‘Rńl/pīÆw¾±iÅ>E’Ą” Ļ7D‘Ā3‚6ķ™jc6ś¢R ”Ā9£µk YįaD+ö Ē\śÉK0^+wܵ–zK÷˜üWæüÅ&ąÜŃ1©ńŗ)š8=½ećĀv? sŅļŃŽR§„f"…$šQZaCœP”–¼(+ŖŚQVŁDįŠ"ē'}}ÜżÅ[¹hł•Üš™»ńĀpLüp GčHĄllŻz՝,Zt>=Ēv“H¢4e‰--q’34œgNĄó …Ņ4gŪ¶­|ē_ā“Žł\|ÉUL?iö˜œŲŲśŠ­Å{ļz˜™óęŅŁŃŽńŖ¹›¤9CC1iœ$Mvķ~ƒū¾ś9‚ äœ%ĖXzŽr¦œpźaœ’ćÖā”śÕÜŠ„&4” Mč·Z’ J ÆĪ“éI«IEND®B`‚cdrdao-cdrdao-f00afb2/gcdmaster/stock/dumpcd.png000066400000000000000000000073071511453746600217630ustar00rootroot00000000000000‰PNG  IHDR00Wł‡gAMA± üabKGD’’’ ½§“ pHYs  d_‘tIMEŃeŒIaDIDATxœķ™ip\ՕĒ÷­ŻOŻ-µvY^‘l<ƒŁń‚M;dS•™b&©É„©©šL‘Ą K RÉ@ T  a7a¶± f±!Ų€ĮĘxŲ„Y’å–ZŻRoÆß~ēƒ E cŪ—ńæź}zļw~÷œ{޹÷ĀaÖaÖaż–ų ļ*Ą9Ą"`Š “‰÷Ė@Ų lŽ^¢ÆšĶOéĖ,®.ā·žŪĶLmļĄŌMš*8Ų~ ]p2ūwņ‹»nØO«æm€łĄõĄy·]ż/œqĘ4#Éh^ā‚(”x•QģPPńā ŖÄćVB#Żé1Ņ»‹Uļ½ĶŻKļXÜ ¬ż6~üüŗ+®äūē. ¦¦T ³ČåBŖ…0”ø•e?¤āĒQ5xA2eP›6q cŒ•ŠmĒÆņīĘ7yųń„æ®ż¦ŅĄ“ĄYĖ~q Ó¦%ŠŖi ……Š-ÜŠ`d8¾S”āz”¼8Ŗ®Q“4ij¶@ŗ”Fó䋪AHäTŠÜeCć§7ü ąUąr`ō/PqÆX9­µ}į3’z5 5‘”@Ø Š&‘tCĆõA( /š"USH$ )Ɛ'_¶±]œ”oS6bxŠĪł^L÷Ž: …±³gūėX1{ʧ>zõO°¬¤oŁE"9^DmŖiPµ¼ŠĆ utS£¾1NąŚō 0<’ĆōJTØhž¢(Õ ā¤ł§Ńß»³-ŸĻ <ōuÜ \öĀ’Ž•ˆ”Ø BQƒ“A„Š‚Ŗ Ԙ@WUG#ĄĘ#‹éŌ$TööīäōkYŪ³‰Ķ½»q#‡Ž¾Żų¼0@J‰P5,ZĀŹ—–MŸą_ą;ĄŻ+oż9Ķm-ć#­B Ø č:RZxYVQ4-¢ź&¶­D>N ÓŠhQ¢»'ƒJČŌćgꜣ|÷Ä£ŃU…Ž2ż»°‹£(H|Ļ嬳Ļeķ[«O Ćp °ēĖüīś«.ļ\|ņ"PT„Ŗ¢ź:Ŗ© 4E“˜A`køC>fCŒ†ibuķ4Ln¤¾µ‘T‰cgyķĆnd*‰süŌ6¦670}śTęĶ;†#œÉäö6 M2:2L¹T`źä©”Ė„ǟpĀh[kkn`` |(€‰Uh°ńżG Ußa€”Č…Hy!A5Ąw#āķŌ4µ°s°—„/=ϟß\‡Dpā¼ć˜ʙ¬Śō>õGt0­­•ļĻ?‘”©į8…Ā(¾ļ}üįRɦT*1::ŹČHžžž]¹mŪ¶mŠucø}Źä(]¾|yą ą¦_rɍ×üųjH$9 #¢0@F20kk‰Õ7sū½÷ó_÷ü`+pļ[?ŖokŸ{ņÅߣiŹT¾·hērŗŖE!žēaŪe …QŹå"„R)%AR*•©TŹ ÉĶ›·8żƒƒ{zööm |ļ5#{¶Æ«k@›pŚ„‹/B(Éq4!7J½ƒ "DH$±śI<öä39’+ą??aėī֎ޱŗęÖdK:͌Ö<ǦčT©­M“H$I$’45µ’ šéėŪC&3ŅéZŅéZŚŪ'‰¹ĒĢŽæŪ74§s87;Źē.īyĆEFżćĪžīĢD€9M³›ˆ’>ć~ Hž1”¢0B5ēž?<p’ē™Ée'¾›Ōtƒ™“Ūého'iÅB”T*P,0M“D"€®›ttĢfśōNņł†‡3”ĖE|ߣä{ ŒhilTN>mqlm"qŅ+_“³§;£LhŠ[ID(ąKšų ‰“#ĀŖ$ršuBGņO’#€«€[>™šc™ż·5N™NmÅœiS‰žē’J„hjj„¾¾(Š(ĒČ冩Vm\×A…¦¦VŽ:jóęĢōét åQT•ęt=–¦£łü•J9s°BzE @‚PP„„HH;_äņ‹/„?»Ÿ;ī¼żZąBąŽśIķ3¢(<-ŻÜĀä¦&žjŚ|ß§Zµ !L3F:Ż€mWŸ P]×1Mӌ!b ö15Ötš=»>,~Ų½ć„M6uJÕÖD*((¤¢@2H)]‰ōCB\Źn Õ«ćŹæż!KNYĀĖž™»ö5w)Éӎ9Ó08¶sõ©Bt]'*•2®ė`&ńxĖŖ \×Įu,Kć•õØŗ.“°tƒµŪ¶ ÷tm_Ļxkž)€ķcŁBk2U?>ŹB  ”D¾$ōC"|<ÓĘõ%vE24”%i–hœ|$×]÷Kzötń‡§'ŁÜ‚qڱsBČsććĖ÷Ē«ćŲ&mš¦”i5†‰‚‘B‘žž‚޶I ō»]Ū¶®ŚŹ…ŃÄ9°fłź×ˆAäC`‡„Õßš—Ъ⨪vDi,`’X€&Ƽ$łģ(™|‘—W®BIÖ¢Ø*‹K"Ÿ˜„hšFOjžŁ@%P Įś­ė(Æ«CĮ޽ż¬Łŗ ĒõTU%n§ŌDÅbq ĆDJxÆūCÖw÷€„c;;ĀLæżĀsĻüq47ņ§O¾s°^hߋė_æā—^€ƒ ”xnˆcŲvˆŖ”UM‚­ŌQc ,Ka¤’g}×&Ā M7ąx;śX×ÕM&7JѶ1 øi¢*`<*…J…U7±{p?mķQS²VyiłsŻ][·üĘ®T?łü§-ĄėĄ] .æ»bćŲ>vŁĆ©†‘J9RŠ$(bŖB<>¾.Ų—$k—Šc‰_.1·­…t<†”×÷Y·£›‡_z•‡^|…‡^|…×7n¦źŗŸĮ‘{÷ch:-é4ÅbQ®]żĘ{#ĆC[&>ūYėĄėŗ¶L;ż˜…„‘>ī¼č:‰cŌcY ń˜‚y¬Łų6e]ňʼn|­ēoĪ9“) “Õ¦RRr\B))Ł›bēĄ [wķ”?›e֔ÉhŖJÕuykŪlݽ‡ęTŪŽŌ¤­sĶĄšU+ļņ}ļƒ/ šĀPvä¬w?ŲŠ¶dŽ\ Ó@H‰M1]%a)˜1AŵY¹~ ń¦V„"šŖUĢhgάYŌÄbŌh:s˜Ę¹s ÉKųQ„ēūäŠ%z÷ńśĘͬܰ‘HJŽķځķøĢjŸ¢ĘU]ÜwēŻ™Į˜Š‰~€ <•;žÉWŸīX|Ā™X‰$‚H·Ø±bč¦JWo7]Ł}ÄRµ„AˆĢgłĮE¢Ŗ*ŖŖ€P0tĘtsfLgÉ1G1©.E”\Ęö|¢(Āń<*ŽĆöŽ>Jv•t"Į¤†F±ķ½ułåO?q°į`N Ą–±k–-JééÖ£HÕXŌÄUŒ˜@Õ,{ £¹UÓq+e:RĢéģ@;PĻ!(•+”‡ī{_~…9GĢąü…§0³­éū ĖDJ­¢(LijņjĶO?ņąĪĮžk6śpšI|0] ,xšXńĻלĖ[ž*…<ŠDHTE”œĖR-•Ąs8éŲ£ńü€0Œˆ¢EÄL“m{ū0“µ„ÉZž_łnÕaöōiĢ™>E9PZ%X†„¬ķĆ®ķaqlģ  ņYŽ}QßA;XrēŅ[¾ō‡gVOæš8Ö¬~›Å'ŸĪģ†6Ŗ™AjB—xÜ ’žļ†ÖB°{(K†(B”­.EKK ~°qO^~ü³KYqM“][6ļ®Ų•gåŌ§ŗŃ/ Õ®+s®’åOóM›„›±¶©V\āÜ3æK[}3ŗ®”F‚\©DĮ®E’Ą¶9ę¤y(ŠĀīĮ ż#y‚(BCӂśTŹŚ·OĖ­ĖåöŹ™æ$1^n’ø ‚™æ»ū7ɦiG¤‹öüß?śŌŖžx‚ĢHŽ0ŠčĖå(;.¾ė"›…óOÅq]6īī%W:°n—]ÓØµģݳ+;“oąÕJ¹ō™é_.Ÿ©øā*łĒĒ)Ö¦SėĢXģģŸŽ|ūéü÷æżĪüS;-\ -˜ÕĮ+ļ¬ć²óĪEAf˜¾Ģšų䕀ŖČ¶tCµZ*&†÷ļ/;”éås¶ćæŹłĄ!õź/)DpŪŅēź†ö \a ®øš¬3g=sV¼¶¶ŽD"F׹Z摉¦ŖÄt#š;}F¾wĒv–?±ōĘ==Ż÷ŸžUé•U/ Uhāę›Ū?šw-õõē.<į„£k“I­ÆReŌõ±LĖ0Pƒ@Fž›éķé~å²goĖ¼óyöæq€“śÕ"fšāg÷Ü· 7°÷ā”Usjš“¦N”ųŖ ĆĮ\vhU¦oļ›#ƙ­ż»wmē3j’'õ­|¤÷׿'~żŌs©-oæ9§°Æ’ˆ†¦ę–( ³š¦õnY·v;ć[ģ_ė1Ō7&”(š¢ŖVKē,żäæ¾ģ[ĢĆ:,ą’r©ĢŪ×CŠ"IEND®B`‚cdrdao-cdrdao-f00afb2/gcdmaster/stock/gcdmaster.png000066400000000000000000000104621511453746600224540ustar00rootroot00000000000000‰PNG  IHDR00Wł‡gAMA± üabKGD’’’ ½§“ pHYs  ŅŻ~ütIMEŠŪ^š&ÆIDATxœĶ™{¬-W]Ē?æµÖ¬™Ł³÷>ēžūč½-ō¶÷ŚŅņ°Ä–hRĈbC@A„@D ‰IhlØÅŌ¢RĮ*ÅWå©Bil(oÅ链ァ÷<÷kfÖśłĒš}Īī„“4&ĘI&ūœ³ē¬õżž~ßßkš×E €¬Bꯀ>Ö’ü_^ƒ1ßĒs Ø@ü’@AŻc= é#±ū|¼Ėo~8X²Ż„؁Uą6ąĖĄ ĄĒ»õŸš„ Ļėāī™›Ūśo~8 pĶ[ŽĮ™g%ĻrØGLńŒ›Œ!Ė"³é6÷=x;W’ńoLæxßGąß-ä¬@+0Uh^ś=ö¾äq <ĪõZąĄžw]łF.»ģRœ°vR©[!„­1ĀØ.ĮZŹŅÓė;öģ-AkVテ¹łF®ūšŸsnz1üó³į~ŪĄ wŲøüQ¼tˆż_€æ xżŪ~įÕÕ»ÆzO?’(>+ČJOŻ(”1 šš:Dźč°ÖāsGŁĖ({Žzk›IӲƚ‚ĆG8wŗõd}xõ2ĻĄ™ĄPa#ĀźõМ ą’fŸču6š%`ļ?^żŪ>Ü'Ė""3T-“–~ß3GA¬Ć“0VčUõtĢhż$£ūīCļŗā–Æqö±cxcp1ž®p(Ą [ ]w½üQāš‰8ųśįƒg”×^ń*†Å˜z P[€¶PxCžBk3DD ƹ·8§Œ:ĮÖż÷n’ł-_#æ÷nüö&>F   Ūp®Ā%|SS𯟠č‰JčŽóĪ>Ņ’Š•o ×«Š&'Ž7‰šäiœĮø”lī™Œ uؙ…Œ,wģŁ[Šl­±ö»˜Žv+ł-_Ć?påö&yųĪŖPs'ZÆFø÷„°ńw§śžø(­ _NYąėĄŅŽteįŃĮ ±ŽOÜj˜ŽÖŠ ˊJkšYɤc ƲĢ"ڰ}’½Lļų6ö¶obz€|{‹"ņ‹ ·Ū¶K’Æ|.ÜŽGÄĀ£² A4݆”Fß \šŁk®błĄ2Y•‘•WX²ž ŒŪĒ䞖ńk4ė#D7XZj0F°VCĻųū}ēĀ=·c|€bc²i(TÉaēv¤räą!&pń§ą²ī«ļĻšy~Ūo\ń Ī<ņ44¶ÆŲ²%Ō‘8SÄE\^ь›·NŲó̜GsŠ}§­0žeŠŽY[ŻęųĆĒ0=H¹~’²©)U)H=K§ØUq“ =‡ŽqŪ«>HJÆßčWąåĄ¾Ÿ¹ōE˜b”E5‚4LÖ¢½WŚI ™Pī;ƒrx·|ćn>ųÉkłÜ© >ēüóyį¹ē±o²E³¹NYĻvĄÅ-I>*’45ūņœ¼.>łølB?מė_łåģ9tÖN¶QAŃ@#1“˜¢ÅöZ†KK+ųƒ?½–ß{ļ{žÓĮµ”śÆ{ī¾"~źG^pą4MĘä!Pt1'`ęƐ…€kž{Įqż7¾śā÷Ƨi”Ø}®u“~ęfųĮ—=’§3HßhDęĀZ™¢A‰(J±r:ł‘权æę„šöKa°Īó`NĄküńc‡3c(;ŻĻId€šĢ4āTÉBĖӞü$Ā7¾śģsżØ.‰©1@”dŒ„żēķ'š. 4¦ž“öÉ)bˆh«ŲaÉ{’ģ¼õ(d}Xńp~ĢC,c4e¾ Y·q«ÉÄ^Įň™M©Ś@G$ńÜ!šˆ,¤õ;čeéwSöH¤…F *:Ž„‰§šŒ0U~ł_šsĄ;Oļစs<œķą@LÕ/ŅBį ÷‰ĻĄ‹ā|ŒŲéŒl2ŅJī:ėĄ\·8\“ =ś“.mi­č,Y8ÖJœDā $:QĮ#źŸÜä?ż2Žü¦·\õ»šÅĻĄ÷Ć Ęp^®w ų܁/ +»;‡</Åˆkjd<ŃL:G9Ö.JHŗ»óž¾L+ātkbśĆ!`0 jLŠņ(Ø a¦hĢŲžmaėe^żóÆåł\§žś/ĪoætÓłnfÖ(ć‘rģŲ ś~“•źÆ|įK؋œšÅ›(W'«wą‹ |ށÆ$™\›% ē|ak«=†¶ DśØ•ųéąœīą™Ļ€ńĒnųWb+ÄŚq LĶø„ig„Ž„©1G¶Ö[\oqjXŸU¬Ż{?ėwßĶä®»1ė”1Rv[dēąJ0}Ź •bz ˜œ‡Ģ‚‹éĆ«ń8)°l’:v ßNźxČ2,;xЇ šw}čO­m¦PkŖ¾ż Į˜NgL§ķ͆“Ūk,…ž xbÖVq[›m³cł² XWvŃܤJĄ©@*Ų2—Čx¬§§fفd å©Y(ž’ sZOĶἋ”÷ą†/|XG¢6ÄjL3m˜60µl®ÕlM”č=F…Y¾—Œ)v{Y=ŽmQÄH)]¶™[¾ōM^*ōś@?‘0E’‚čƒVŠw0p y'ÅEś,ŠåōŠ™>eŒC=(øņ=æÉš>Dš#š¦e6 L¶FŪ-u+LÄ!mdd–É­’…)²½=¹ŠŸN(є.,Æsk÷¾vŸÉ ō:eČĮ8(,dß%;ĒśŌ“öžŽpVöT‚ż1ÆųįW\Īx4f:no×L'6£:bė"…5”>āŚ1²¹†ŪÜ hjzų¬Ū›—N61™xĄ#< Ų.¼`ō2(³äœä ;żŸ•$Wy8#‡s{pØo(éešG%üˆ×½ćķl­Øk”–ķZPO˜øyĻą“AF›Čź1Üö&Eh)ēérAćōŖ$énģĂé%Ö¤|ļRšŚ5'³a’yG Ģ4iÓMĄ ŁJ}>v9üĆļĆ9Ÿ’ą»_ŅĀ󶆿v€³åų9¢ólŁżŽ[ ;¾#`әXׯ©5ØĶŗ:Ńż‹óP䆪Č(|‰±}`Ų„5ß=5ėŠF±[ę3ƒqĀĀ „ŽUšå2qģw\’{VLƓā|½ł$³~Žc+Š><0é W„h»fČĢ=ŠB)г¬džŅUȎõē4„+Zq"ŠUIÉ"„UV¦=8ĆĀ^gÉ]žņłĪZs«ūs9åŻ>5»¾M Jś¦1»PęØŠå Ķé»N>;p š¤7)ŗé)™¾IąKź×Ÿd…=™%·EKƒn½ł(6ļ ųĪĆsšóS©ŌŇĪ3±ńˆ”Ż<ą!Ļ„”s,Ł‚Bśƅ ³naÓYg;0Y×ī ¹QögJ*œūœ”“ÖĶ­æø^'rvÓhÉī“ėĄ“Œ§šŅˆĄĢ8ZS Ru(SX\īq®‡±ƒS\ī:¶Ū ·Ū§8Np–ž,)m/;ƒubŹnåī.»õ쁹 )€,??äR„Ę"ŒŒ%Hžˆ;€JˆeF›—Ø«¬5ģ6˜˜{`+¹_ņ®Ż5ˆ Lņ@a`Æ5xė»ō9$½lZb”…\Ń\’’blnu"Żč f [bi%G„īż …”Ī=Ó¬¤±łfóĘŖ Ž „~'…Ņ)‡" D(Œ”“¾ ąEó„  2šßŻk“3X›>UiU™D8°Ž„eīDa*Ž5S°)jY"g©‹ƒ¹Ė悄ūõUX¢ŌCJRROϼ€Ač‹ĮāÅѳ–²hqC‹*qC‘‘E¦3Œm¢FŹm$޵­Ēŗm6źć2ž×õv“ flĒĄ°”0C4™ „ƒ²Ś%°r#Ģž'Š·‰]Ž’I‹µ-6›bĢ:„K®=^sr¼dĘć%Į‰ą°äd8¼²R±CKšŽµ]$ڈø|½ g4ÓY»mėÉĶÖM;%dJ)?Ej¬—Ōˆ¹Į#ßäæ3ļeA×÷‚Ń4B‹WÄ*&@6 䓚b6”l‘>"}D Ĥ–WTŗCėR e~ĢĮT“]…8Q¤Pt9ĀŽˆ„1Ö­ėšQ2‚u ĶjČbŖ9Ę;šĢ„wń?{ö^$ž/OIEND®B`‚cdrdao-cdrdao-f00afb2/gcdmaster/stock/open.png000066400000000000000000000052411511453746600214430ustar00rootroot00000000000000‰PNG  IHDR00Wł‡gAMA± üabKGD’’’ ½§“ pHYs  d_‘tIMEŃ5Ļ#‹ IDATxœķ™[lÕĒgf/³ėĖŚŽ/‰Cˆ©\„$@¤6…”ŖŌ—¼•‡öVH•č[#!¤¶¤ŖčK„Z•”¶/m…P‰„Ø\ IøÄ¤ĮĉÓŲ ¬½Ų‰½ö®½»3ē҇™Ł]'v.¤ž¤Ńœ={vüż¾’w¾ó «¶j«¶j«v &nń÷ęŸe–™»©ēÜ €łÅ?_ēR6ĖŪūŸ¾óĪĶž óŻgžaĆך\‰ō\>|żuž{ōčMły£WFŚüō7/²ł[ßdq¾ˆÖ „®ėįV]ŖÕ —3 ™,§ŽįģŠŠU|čÉ]Üūš#T*e”RheŠ“ÖcJį¹.£ļæĻŲ‘#+śz#f×®]ŒQ(ČårŲ¶MsG=›śčŁŲdž~ŗo߈ÓŌäÓƒ1mĄhėŗēęX(–X(•hIµO$©V*h­QJÕ/©‚€ųóĮ›/žś†–ĖGžņź«ģ|ā ŗ{z(•Jäóy¦§§9uŠ£ĒŽńŁČétšĖ—.sZ;;IuwÓµį6ÖmŽLĻĘ>¬X ؤ•FzŅóPŗītm8®¤Fk‰ROz¼æ’²į„łÕļ_fėŽGŠU—r±D6“ajzŠźÜ<ł‰4^Õå¶µk¹ū®»hii!՚bóę;éźé ¼°ĄĒĒs|hˆÓ§Osrx˜ōÄ…™ĖÄIšŚŚhīź¤­g-]7ŅÖŪKŌ‰#=‰ €dؔD)ƒRŅWĆŠ““|zšąU5€CŸ}Ęä\O+ⱉhŒØmį Zõ(Ķΐł"Ķēé/ؖhwŹ 4·“šŠ–-ܱi]ŻŻ“„R$››PžĒ»ƒƒ ¾÷gFG97>N:fnv–Øćlk#ŁŃAӚ5¤Ö®£„³+Å(ēV} ­1ĀāĆ?¼¼2ĄĻ_ł#÷oŪĘŁģEŒc4ŹObŒńóŗ%įŠ’Hµ#DµFV*T+²łT§”5ŪݘZž½µ«›ĆƒƒĢĢ̐L&q‡£ĒŽ!IęĒĪĮ5z¶åÄ/ōcŗRmK„×õ؆Q— i!×*… U‘²ö}ØDćšHl;ĘĪĒw¬čē58xą¾ŗmŅ,ĖBX˲ķŚĖFXušBB`jĪj ¢a/L šēzĢĢĪR( ×s9qāķmķ|ć ir’ģŲłčõß®00śĮ51o ā$š” 42Ų±"PƲüTĀĀXĀ‚å+e ,ßł@|ž0??Ļåéi,!83rš¶ö5ēŠ”Šsō®_ϔnjeGųĪć;k ×U `ņĢ™%™iŪ6H45aĒćˆhŪIqDÄF0aŚa%BųB =Ļó(—Ė<¹{Ę‚Åź"ւM4*˜šŽS©TY×ÓĖG}d|šAq3ĖĀ(„ ĄĀüüU cN‚XĀĮŽÅ …H;ī€%üKųPŹõ0J„–%ˆĒ$œ¤’vhRŗh%QŚ_Ś—ø& µĆ­”A€ķyX–…[© =X2‰bÅćD›[ˆbČäóttt0;[Ąhƒ a "›ØĮ‰%Y»v-‰d3NĀłæ\ČõÓbiA40• Q;‚V’r¤ŹĢĢ {öģ!ˆÄtwvŅԚ¢w]/]k:ˆD#<ŗciEŗÕ’|Y[¶ĀļŪ·ĻˆF¢l¹’>¾żšŹ%tÕVmÕVmÕVķBƒ[²”¼cIEND®B`‚cdrdao-cdrdao-f00afb2/gcdmaster/stock/pause.png000066400000000000000000000005571511453746600216240ustar00rootroot00000000000000‰PNG  IHDRąw=ųgAMA± üabKGDźčćÕVŪ pHYs  ŅŻ~ütIMEŅ4 TęJćģIDATxŚķ•1n1EŸwʰ¬WV ˆH›&GƒŽ’.7KƶOi#;‰_É~S|Ļ—lĆC·–Kšąéøö@ ģŽū3nf_ι"ćwĄNĖĢģ æ(Mš `½^Ń÷=ŖŹf³żi¦x‰!^—Kö‡COžōšbŒōóy6Ļ5ˆÓÉU!„0j¦xńmšŽÓ„&‹’*¢æźf`±x¦mĶlEŠß_Du=EEŹeńƒ=€Š¢ŖT"ćŪ™ą%@DčŗļżØ™ā%zūÆĒ.5ĮĪĢ8­a>/qąćńóŻÆ¾ļJfµr _IEND®B`‚cdrdao-cdrdao-f00afb2/gcdmaster/stock/play.png000066400000000000000000000005761511453746600214550ustar00rootroot00000000000000‰PNG  IHDRąw=ųgAMA± üabKGDłC» pHYs  ŅŻ~ütIMEŅ!%9XxūIDATxŚķŅA.QĘń«zÓ¼×éĢX !LŪwp ŲāĀ$œCĀvīįĻBf9¦ŖĶģę[W¾_UR°ĢŒˆaę؀ļ6ĄŠafĶ¢€IZ!fąīö¦bÖbäśźŅ˜aøĒćý 1"‚ŠŅ4G¼œsī9žėbŻÅ?d€AĄ‰l>Šš@÷Aą9`xųØA¤ÕČöüżf0<¼Ÿ“­³/>v”¹Tœ#V€æ+Ę×õ+•]FĘ&>ÆT*§ž .ĪeO¾õh†égČĶg`x€Īõ®}’ WŹ—øškorŗŗ¹¹9v;@ģ65ĻļĖ$N¾=‘fö„7Č=1‡“H`ł>x>±øCj|ŠģÄ#Œ’t™o+ÕōS ‹Æmmm}°`ļ;g€cI‹Å×GSLž8Ij$‡šuŌØ”F ÓØ”fš5ŅGfņÄ)^äŅźŹx©TZŻˆļ;/œĶ&)‘Īå wo`&Ŗ§ BAhDv4O"ĻammmQRѲ¬Æīp€ć³ƒqbaŻ.Aļę­ążč ž„ ÄBńxŅęāś:Ą2pG@.ķyXt~ł `£¾G©BķNBC²Õęźn`ž łA`,Øm_!γĄśĆaFP»¶ÓæÆ[rź @ŲŁµü!ÆGcē:¦Ł&™L€„„~ż…ŻžĒ^«M׈v*ĶŌŠwkrųīņĶ Ÿ ¶ų-¼˜M<ėwB`dšü€nŅ2¢-ųĮ ˜?3põ @ų°|cļĢl:@²Bü(ž®DĖ@džĻ~«óåņ2ĄśAs°2<š’¢ŌńŁó õHž”凓|CĆ7Ōż†oŲ ÷B^u]ŠÅ"ĄG÷“MgffŖį֏£ q›„ބ̀č z–ͧ2L>ż,årą‚eYoŽó:]ZZŖ$@§‡²z'›Ņ9ŪÖ9ŪÖ»CYŹŹ¹®«HŹ÷µ³K„ŅŖėŗ* rGŽćØP(Ču]mllüüüżJ’Š’ĪKŚ–äEŗيü/’jł!F‘®µöø£IEND®B`‚cdrdao-cdrdao-f00afb2/gcdmaster/stock/stop.png000066400000000000000000000005241511453746600214660ustar00rootroot00000000000000‰PNG  IHDRąw=ųgAMA± üabKGDźčćÕVŪ pHYs  ŅŻ~ütIMEŅ%Õ2ģŃIDATxŚķ”A‚0EĢ•!‰Ąč֍GӍÅÓ¹į"øa„ iŒ‰?iŅLēϟ¦|AGl ĢŪ½.@ 4-æ¹ć+P產Ū6É[«ÅC2ķöūyž£Ŗ/+:޽g½·ĶŒõjEu½~ōOĖ«ėš<ĖFØ&Q„Ŗ`f~$‰įœ#¶ų#Š÷?čmQQ,H#žż ¦Ó *‚„Į耊¢Ŗ„"£ "Bš¦8ēFoŪĘ÷,*»ˆpņ>ū‡:č%’į7¬nF÷bŠIEND®B`‚cdrdao-cdrdao-f00afb2/gcdmaster/xcdrdao.cc000066400000000000000000000100211511453746600205740ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2000 Andreas Mueller * * 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. */ #include #include #include #include #include #include "config.h" #include "xcdrdao.h" #include "TocEdit.h" #include "TrackInfoDialog.h" #include "AddSilenceDialog.h" #include "AddFileDialog.h" #include "DeviceConfDialog.h" #include "PreferencesDialog.h" #include "ProgressDialog.h" #include "guiUpdate.h" #include "CdDevice.h" #include "ProcessMonitor.h" #include "ProjectChooser.h" #include "ConfigManager.h" #include "gcdmaster.h" #include "port.h" DeviceConfDialog* deviceConfDialog = NULL; ProcessMonitor* PROCESS_MONITOR = NULL; ProgressDialogPool* PROGRESS_POOL = NULL; PreferencesDialog* preferencesDialog = NULL; ConfigManager* configManager = NULL; Glib::RefPtr app; static int PROCESS_MONITOR_SIGNAL_BLOCKED = 0; void blockProcessMonitorSignals() { if (PROCESS_MONITOR_SIGNAL_BLOCKED == 0) blockSignal(SIGCHLD); PROCESS_MONITOR_SIGNAL_BLOCKED++; } void unblockProcessMonitorSignals() { if (PROCESS_MONITOR_SIGNAL_BLOCKED > 0) { PROCESS_MONITOR_SIGNAL_BLOCKED--; if (PROCESS_MONITOR_SIGNAL_BLOCKED == 0) unblockSignal(SIGCHLD); } } static RETSIGTYPE signalHandler(int sig) { if (sig == SIGCHLD) PROCESS_MONITOR->handleSigChld(); } void GCDMasterApplication::on_activate() { auto appwindow = new GCDMaster(); appwindow->newChooserWindow(); add_window(*appwindow); appwindow->present(); } void GCDMasterApplication::on_open(const Gio::Application::type_vec_files& files, const Glib::ustring&) { for (const auto& file: files) { if (file->is_native()) { auto window = new GCDMaster(); window->openNewProject(file->get_path()); add_window(*window); window->present(); } } } int main(int argc, char* argv[]) { app = Glib::RefPtr(new GCDMasterApplication()); // create GConf configuration manager configManager = new ConfigManager(); // settings CdDevice::importSettings(); // setup process monitor PROCESS_MONITOR = new ProcessMonitor; installSignalHandler(SIGCHLD, signalHandler); // setup periodic GUI updates Glib::signal_timeout().connect(sigc::ptr_fun(&guiUpdatePeriodic), 2000); installSignalHandler(SIGPIPE, SIG_IGN); // scan for SCSI devices CdDevice::scan(); // this forces a CdDevice::updateDeviceStatus() so // when gcdmaster is first show we already have the device status guiUpdatePeriodic(); deviceConfDialog = new DeviceConfDialog; PROGRESS_POOL = new ProgressDialogPool; Glib::RefPtr builder; try { builder = Gtk::Builder::create_from_file(CDRDAO_GLADEDIR "/Preferences.glade"); } catch(std::exception& ex) { std::cerr << ex.what() << std::endl; exit(1); } builder->get_widget_derived("PrefDialog", preferencesDialog); if (!preferencesDialog) { std::cerr << "Unable to create Preferences dialog from glade file\n" CDRDAO_GLADEDIR "/Preferences.glade" << std::endl; exit(1); } //Shows the window and returns when it is closed. int retval = app->run(argc, argv); // save settings CdDevice::exportSettings(); delete configManager; return retval; } cdrdao-cdrdao-f00afb2/gcdmaster/xcdrdao.h000066400000000000000000000033341511453746600204470ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998 Andreas Mueller * * 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. */ #ifndef __XCDRDAO_H__ #define __XCDRDAO_H__ #include // // GLOBAL objects. // // Warning: those may be shared by multiple open project windows. // extern class DeviceConfDialog* deviceConfDialog; extern class ProcessMonitor* PROCESS_MONITOR; extern class ProgressDialogPool* PROGRESS_POOL; extern class PreferencesDialog* preferencesDialog; extern class ConfigManager* configManager; void blockProcessMonitorSignals(); void unblockProcessMonitorSignals(); class GCDMasterApplication: public Gtk::Application { public: GCDMasterApplication() : Gtk::Application("Gonme.CDMaster", Gio::APPLICATION_HANDLES_OPEN) {} protected: void on_activate() override; void on_open(const Gio::Application::type_vec_files& files, const Glib::ustring& hint) override; private: void on_hide_window(Gtk::Window* window); }; extern Glib::RefPtr app; #endif cdrdao-cdrdao-f00afb2/install-sh000077500000000000000000000361151511453746600167100ustar00rootroot00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2024-06-19.01; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. tab=' ' nl=' ' IFS=" $tab$nl" # Set DOITPROG to "echo" to test this script. doit=${DOITPROG-} doit_exec=${doit:-exec} # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_mkdir= # Desired mode of installed file. mode=0755 # Create dirs (including intermediate dirs) using mode 755. # This is like GNU 'install' as of coreutils 8.32 (2020). mkdir_umask=22 backupsuffix= chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false is_target_a_directory=possibly usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -p pass -p to $cpprog. -s $stripprog installed files. -S SUFFIX attempt to back up existing files, with suffix SUFFIX. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG By default, rm is invoked with -f; when overridden with RMPROG, it's up to you to specify -f if you want it. If -S is not specified, no backups are attempted. Report bugs to . GNU Automake home page: . General help using GNU software: ." while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -p) cpprog="$cpprog -p";; -s) stripcmd=$stripprog;; -S) backupsuffix="$2" shift;; -t) is_target_a_directory=always dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) is_target_a_directory=never;; --version) echo "$0 (GNU Automake) $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done # We allow the use of options -d and -T together, by making -d # take the precedence; this is for compatibility with GNU install. if test -n "$dir_arg"; then if test -n "$dst_arg"; then echo "$0: target directory not allowed when installing a directory." >&2 exit 1 fi fi if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then if test $# -gt 1 || test "$is_target_a_directory" = always; then if test ! -d "$dst_arg"; then echo "$0: $dst_arg: Is not a directory." >&2 exit 1 fi fi fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? # Don't chown directories that already exist. if test $dstdir_status = 0; then chowncmd="" fi else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename. if test -d "$dst"; then if test "$is_target_a_directory" = never; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dstbase=`basename "$src"` case $dst in */) dst=$dst$dstbase;; *) dst=$dst/$dstbase;; esac dstdir_status=0 else dstdir=`dirname "$dst"` test -d "$dstdir" dstdir_status=$? fi fi case $dstdir in */) dstdirslash=$dstdir;; *) dstdirslash=$dstdir/;; esac obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false # The $RANDOM variable is not portable (e.g., dash). Use it # here however when possible just to lower collision chance. tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap ' ret=$? rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null exit $ret ' 0 # Because "mkdir -p" follows existing symlinks and we likely work # directly in world-writable /tmp, make sure that the '$tmpdir' # directory is successfully created first before we actually test # 'mkdir -p'. if (umask $mkdir_umask && $mkdirprog $mkdir_mode "$tmpdir" && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibility with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. test_tmpdir="$tmpdir/a" ls_ld_tmpdir=`ls -ld "$test_tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null fi trap '' 0;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac oIFS=$IFS IFS=/ set -f set fnord $dstdir shift set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=${dstdirslash}_inst.$$_ rmtmp=${dstdirslash}_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && { test -z "$stripcmd" || { # Create $dsttmp read-write so that cp doesn't create it read-only, # which would cause strip to fail. if test -z "$doit"; then : >"$dsttmp" # No need to fork-exec 'touch'. else $doit touch "$dsttmp" fi } } && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # If $backupsuffix is set, and the file being installed # already exists, attempt a backup. Don't worry if it fails, # e.g., if mv doesn't support -f. if test -n "$backupsuffix" && test -f "$dst"; then $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null fi # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: cdrdao-cdrdao-f00afb2/m4/000077500000000000000000000000001511453746600152165ustar00rootroot00000000000000cdrdao-cdrdao-f00afb2/m4/ax_cxx_compile_stdcxx.m4000066400000000000000000000550171511453746600220670ustar00rootroot00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html # =========================================================================== # # SYNOPSIS # # AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional]) # # DESCRIPTION # # Check for baseline language coverage in the compiler for the specified # version of the C++ standard. If necessary, add switches to CXX and # CXXCPP to enable support. VERSION may be '11', '14', '17', '20', or # '23' for the respective C++ standard version. # # The second argument, if specified, indicates whether you insist on an # extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. # -std=c++11). If neither is specified, you get whatever works, with # preference for no added switch, and then for an extended mode. # # The third argument, if specified 'mandatory' or if left unspecified, # indicates that baseline support for the specified C++ standard is # required and that the macro should error out if no mode with that # support is found. If specified 'optional', then configuration proceeds # regardless, after defining HAVE_CXX${VERSION} if and only if a # supporting mode is found. # # LICENSE # # Copyright (c) 2008 Benjamin Kosnik # Copyright (c) 2012 Zack Weinberg # Copyright (c) 2013 Roy Stogner # Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov # Copyright (c) 2015 Paul Norman # Copyright (c) 2015 Moritz Klammler # Copyright (c) 2016, 2018 Krzesimir Nowak # Copyright (c) 2019 Enji Cooper # Copyright (c) 2020 Jason Merrill # Copyright (c) 2021, 2024 Jƶrn Heusipp # Copyright (c) 2015, 2022, 2023, 2024 Olly Betts # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 25 dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro dnl (serial version number 13). AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"], [$1], [14], [ax_cxx_compile_alternatives="14 1y"], [$1], [17], [ax_cxx_compile_alternatives="17 1z"], [$1], [20], [ax_cxx_compile_alternatives="20"], [$1], [23], [ax_cxx_compile_alternatives="23"], [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl m4_if([$2], [], [], [$2], [ext], [], [$2], [noext], [], [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true], [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true], [$3], [optional], [ax_cxx_compile_cxx$1_required=false], [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) AC_LANG_PUSH([C++])dnl ac_success=no m4_if([$2], [], [dnl AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, ax_cv_cxx_compile_cxx$1, [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], [ax_cv_cxx_compile_cxx$1=yes], [ax_cv_cxx_compile_cxx$1=no])]) if test x$ax_cv_cxx_compile_cxx$1 = xyes; then ac_success=yes fi]) m4_if([$2], [noext], [], [dnl if test x$ac_success = xno; then for alternative in ${ax_cxx_compile_alternatives}; do switch="-std=gnu++${alternative}" cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, $cachevar, [ac_save_CXX="$CXX" CXX="$CXX $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], [eval $cachevar=yes], [eval $cachevar=no]) CXX="$ac_save_CXX"]) if eval test x\$$cachevar = xyes; then CXX="$CXX $switch" if test -n "$CXXCPP" ; then CXXCPP="$CXXCPP $switch" fi ac_success=yes break fi done fi]) m4_if([$2], [ext], [], [dnl if test x$ac_success = xno; then dnl HP's aCC needs +std=c++11 according to: dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf dnl Cray's crayCC needs "-h std=c++11" dnl MSVC needs -std:c++NN for C++17 and later (default is C++14) for alternative in ${ax_cxx_compile_alternatives}; do for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}" MSVC; do if test x"$switch" = xMSVC; then dnl AS_TR_SH maps both `:` and `=` to `_` so -std:c++17 would collide dnl with -std=c++17. We suffix the cache variable name with _MSVC to dnl avoid this. switch=-std:c++${alternative} cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_${switch}_MSVC]) else cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) fi AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, $cachevar, [ac_save_CXX="$CXX" CXX="$CXX $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], [eval $cachevar=yes], [eval $cachevar=no]) CXX="$ac_save_CXX"]) if eval test x\$$cachevar = xyes; then CXX="$CXX $switch" if test -n "$CXXCPP" ; then CXXCPP="$CXXCPP $switch" fi ac_success=yes break fi done if test x$ac_success = xyes; then break fi done fi]) AC_LANG_POP([C++]) if test x$ax_cxx_compile_cxx$1_required = xtrue; then if test x$ac_success = xno; then AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.]) fi fi if test x$ac_success = xno; then HAVE_CXX$1=0 AC_MSG_NOTICE([No compiler with C++$1 support was found]) else HAVE_CXX$1=1 AC_DEFINE(HAVE_CXX$1,1, [define if the compiler supports basic C++$1 syntax]) fi AC_SUBST(HAVE_CXX$1) ]) dnl Test body for checking C++11 support m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], [_AX_CXX_COMPILE_STDCXX_testbody_new_in_11] ) dnl Test body for checking C++14 support m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], [_AX_CXX_COMPILE_STDCXX_testbody_new_in_11 _AX_CXX_COMPILE_STDCXX_testbody_new_in_14] ) dnl Test body for checking C++17 support m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17], [_AX_CXX_COMPILE_STDCXX_testbody_new_in_11 _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 _AX_CXX_COMPILE_STDCXX_testbody_new_in_17] ) dnl Test body for checking C++20 support m4_define([_AX_CXX_COMPILE_STDCXX_testbody_20], [_AX_CXX_COMPILE_STDCXX_testbody_new_in_11 _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 _AX_CXX_COMPILE_STDCXX_testbody_new_in_20] ) dnl Test body for checking C++23 support m4_define([_AX_CXX_COMPILE_STDCXX_testbody_23], [_AX_CXX_COMPILE_STDCXX_testbody_new_in_11 _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 _AX_CXX_COMPILE_STDCXX_testbody_new_in_20 _AX_CXX_COMPILE_STDCXX_testbody_new_in_23] ) dnl Tests for new features in C++11 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ // If the compiler admits that it is not ready for C++11, why torture it? // Hopefully, this will speed up the test. #ifndef __cplusplus #error "This is not a C++ compiler" // MSVC always sets __cplusplus to 199711L in older versions; newer versions // only set it correctly if /Zc:__cplusplus is specified as well as a // /std:c++NN switch: // // https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/ // // The value __cplusplus ought to have is available in _MSVC_LANG since // Visual Studio 2015 Update 3: // // https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros // // This was also the first MSVC version to support C++14 so we can't use the // value of either __cplusplus or _MSVC_LANG to quickly rule out MSVC having // C++11 or C++14 support, but we can check _MSVC_LANG for C++17 and later. #elif __cplusplus < 201103L && !defined _MSC_VER #error "This is not a C++11 compiler" #else namespace cxx11 { namespace test_static_assert { template struct check { static_assert(sizeof(int) <= sizeof(T), "not big enough"); }; } namespace test_final_override { struct Base { virtual ~Base() {} virtual void f() {} }; struct Derived : public Base { virtual ~Derived() override {} virtual void f() override {} }; } namespace test_double_right_angle_brackets { template < typename T > struct check {}; typedef check single_type; typedef check> double_type; typedef check>> triple_type; typedef check>>> quadruple_type; } namespace test_decltype { int f() { int a = 1; decltype(a) b = 2; return a + b; } } namespace test_type_deduction { template < typename T1, typename T2 > struct is_same { static const bool value = false; }; template < typename T > struct is_same { static const bool value = true; }; template < typename T1, typename T2 > auto add(T1 a1, T2 a2) -> decltype(a1 + a2) { return a1 + a2; } int test(const int c, volatile int v) { static_assert(is_same::value == true, ""); static_assert(is_same::value == false, ""); static_assert(is_same::value == false, ""); auto ac = c; auto av = v; auto sumi = ac + av + 'x'; auto sumf = ac + av + 1.0; static_assert(is_same::value == true, ""); static_assert(is_same::value == true, ""); static_assert(is_same::value == true, ""); static_assert(is_same::value == false, ""); static_assert(is_same::value == true, ""); return (sumf > 0.0) ? sumi : add(c, v); } } namespace test_noexcept { int f() { return 0; } int g() noexcept { return 0; } static_assert(noexcept(f()) == false, ""); static_assert(noexcept(g()) == true, ""); } namespace test_constexpr { template < typename CharT > unsigned long constexpr strlen_c_r(const CharT *const s, const unsigned long acc) noexcept { return *s ? strlen_c_r(s + 1, acc + 1) : acc; } template < typename CharT > unsigned long constexpr strlen_c(const CharT *const s) noexcept { return strlen_c_r(s, 0UL); } static_assert(strlen_c("") == 0UL, ""); static_assert(strlen_c("1") == 1UL, ""); static_assert(strlen_c("example") == 7UL, ""); static_assert(strlen_c("another\0example") == 7UL, ""); } namespace test_rvalue_references { template < int N > struct answer { static constexpr int value = N; }; answer<1> f(int&) { return answer<1>(); } answer<2> f(const int&) { return answer<2>(); } answer<3> f(int&&) { return answer<3>(); } void test() { int i = 0; const int c = 0; static_assert(decltype(f(i))::value == 1, ""); static_assert(decltype(f(c))::value == 2, ""); static_assert(decltype(f(0))::value == 3, ""); } } namespace test_uniform_initialization { struct test { static const int zero {}; static const int one {1}; }; static_assert(test::zero == 0, ""); static_assert(test::one == 1, ""); } namespace test_lambdas { void test1() { auto lambda1 = [](){}; auto lambda2 = lambda1; lambda1(); lambda2(); } int test2() { auto a = [](int i, int j){ return i + j; }(1, 2); auto b = []() -> int { return '0'; }(); auto c = [=](){ return a + b; }(); auto d = [&](){ return c; }(); auto e = [a, &b](int x) mutable { const auto identity = [](int y){ return y; }; for (auto i = 0; i < a; ++i) a += b--; return x + identity(a + b); }(0); return a + b + c + d + e; } int test3() { const auto nullary = [](){ return 0; }; const auto unary = [](int x){ return x; }; using nullary_t = decltype(nullary); using unary_t = decltype(unary); const auto higher1st = [](nullary_t f){ return f(); }; const auto higher2nd = [unary](nullary_t f1){ return [unary, f1](unary_t f2){ return f2(unary(f1())); }; }; return higher1st(nullary) + higher2nd(nullary)(unary); } } namespace test_variadic_templates { template struct sum; template struct sum { static constexpr auto value = N0 + sum::value; }; template <> struct sum<> { static constexpr auto value = 0; }; static_assert(sum<>::value == 0, ""); static_assert(sum<1>::value == 1, ""); static_assert(sum<23>::value == 23, ""); static_assert(sum<1, 2>::value == 3, ""); static_assert(sum<5, 5, 11>::value == 21, ""); static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); } // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function // because of this. namespace test_template_alias_sfinae { struct foo {}; template using member = typename T::member_type; template void func(...) {} template void func(member*) {} void test(); void test() { func(0); } } } // namespace cxx11 #endif // __cplusplus >= 201103L ]]) dnl Tests for new features in C++14 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[ // If the compiler admits that it is not ready for C++14, why torture it? // Hopefully, this will speed up the test. #ifndef __cplusplus #error "This is not a C++ compiler" #elif __cplusplus < 201402L && !defined _MSC_VER #error "This is not a C++14 compiler" #else namespace cxx14 { namespace test_polymorphic_lambdas { int test() { const auto lambda = [](auto&&... args){ const auto istiny = [](auto x){ return (sizeof(x) == 1UL) ? 1 : 0; }; const int aretiny[] = { istiny(args)... }; return aretiny[0]; }; return lambda(1, 1L, 1.0f, '1'); } } namespace test_binary_literals { constexpr auto ivii = 0b0000000000101010; static_assert(ivii == 42, "wrong value"); } namespace test_generalized_constexpr { template < typename CharT > constexpr unsigned long strlen_c(const CharT *const s) noexcept { auto length = 0UL; for (auto p = s; *p; ++p) ++length; return length; } static_assert(strlen_c("") == 0UL, ""); static_assert(strlen_c("x") == 1UL, ""); static_assert(strlen_c("test") == 4UL, ""); static_assert(strlen_c("another\0test") == 7UL, ""); } namespace test_lambda_init_capture { int test() { auto x = 0; const auto lambda1 = [a = x](int b){ return a + b; }; const auto lambda2 = [a = lambda1(x)](){ return a; }; return lambda2(); } } namespace test_digit_separators { constexpr auto ten_million = 100'000'000; static_assert(ten_million == 100000000, ""); } namespace test_return_type_deduction { auto f(int& x) { return x; } decltype(auto) g(int& x) { return x; } template < typename T1, typename T2 > struct is_same { static constexpr auto value = false; }; template < typename T > struct is_same { static constexpr auto value = true; }; int test() { auto x = 0; static_assert(is_same::value, ""); static_assert(is_same::value, ""); return x; } } } // namespace cxx14 #endif // __cplusplus >= 201402L ]]) dnl Tests for new features in C++17 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[ // If the compiler admits that it is not ready for C++17, why torture it? // Hopefully, this will speed up the test. #ifndef __cplusplus #error "This is not a C++ compiler" #elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 201703L #error "This is not a C++17 compiler" #else #include #include #include namespace cxx17 { namespace test_constexpr_lambdas { constexpr int foo = [](){return 42;}(); } namespace test::nested_namespace::definitions { } namespace test_fold_expression { template int multiply(Args... args) { return (args * ... * 1); } template bool all(Args... args) { return (args && ...); } } namespace test_extended_static_assert { static_assert (true); } namespace test_auto_brace_init_list { auto foo = {5}; auto bar {5}; static_assert(std::is_same, decltype(foo)>::value); static_assert(std::is_same::value); } namespace test_typename_in_template_template_parameter { template typename X> struct D; } namespace test_fallthrough_nodiscard_maybe_unused_attributes { int f1() { return 42; } [[nodiscard]] int f2() { [[maybe_unused]] auto unused = f1(); switch (f1()) { case 17: f1(); [[fallthrough]]; case 42: f1(); } return f1(); } } namespace test_extended_aggregate_initialization { struct base1 { int b1, b2 = 42; }; struct base2 { base2() { b3 = 42; } int b3; }; struct derived : base1, base2 { int d; }; derived d1 {{1, 2}, {}, 4}; // full initialization derived d2 {{}, {}, 4}; // value-initialized bases } namespace test_general_range_based_for_loop { struct iter { int i; int& operator* () { return i; } const int& operator* () const { return i; } iter& operator++() { ++i; return *this; } }; struct sentinel { int i; }; bool operator== (const iter& i, const sentinel& s) { return i.i == s.i; } bool operator!= (const iter& i, const sentinel& s) { return !(i == s); } struct range { iter begin() const { return {0}; } sentinel end() const { return {5}; } }; void f() { range r {}; for (auto i : r) { [[maybe_unused]] auto v = i; } } } namespace test_lambda_capture_asterisk_this_by_value { struct t { int i; int foo() { return [*this]() { return i; }(); } }; } namespace test_enum_class_construction { enum class byte : unsigned char {}; byte foo {42}; } namespace test_constexpr_if { template int f () { if constexpr(cond) { return 13; } else { return 42; } } } namespace test_selection_statement_with_initializer { int f() { return 13; } int f2() { if (auto i = f(); i > 0) { return 3; } switch (auto i = f(); i + 4) { case 17: return 2; default: return 1; } } } namespace test_template_argument_deduction_for_class_templates { template struct pair { pair (T1 p1, T2 p2) : m1 {p1}, m2 {p2} {} T1 m1; T2 m2; }; void f() { [[maybe_unused]] auto p = pair{13, 42u}; } } namespace test_non_type_auto_template_parameters { template struct B {}; B<5> b1; B<'a'> b2; } namespace test_structured_bindings { int arr[2] = { 1, 2 }; std::pair pr = { 1, 2 }; auto f1() -> int(&)[2] { return arr; } auto f2() -> std::pair& { return pr; } struct S { int x1 : 2; volatile double y1; }; S f3() { return {}; } auto [ x1, y1 ] = f1(); auto& [ xr1, yr1 ] = f1(); auto [ x2, y2 ] = f2(); auto& [ xr2, yr2 ] = f2(); const auto [ x3, y3 ] = f3(); } namespace test_exception_spec_type_system { struct Good {}; struct Bad {}; void g1() noexcept; void g2(); template Bad f(T*, T*); template Good f(T1*, T2*); static_assert (std::is_same_v); } namespace test_inline_variables { template void f(T) {} template inline T g(T) { return T{}; } template<> inline void f<>(int) {} template<> int g<>(int) { return 5; } } } // namespace cxx17 #endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 201703L ]]) dnl Tests for new features in C++20 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_20], [[ #ifndef __cplusplus #error "This is not a C++ compiler" #elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202002L #error "This is not a C++20 compiler" #else #include namespace cxx20 { // As C++20 supports feature test macros in the standard, there is no // immediate need to actually test for feature availability on the // Autoconf side. } // namespace cxx20 #endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202002L ]]) dnl Tests for new features in C++23 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_23], [[ #ifndef __cplusplus #error "This is not a C++ compiler" #elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202302L #error "This is not a C++23 compiler" #else #include namespace cxx23 { // As C++23 supports feature test macros in the standard, there is no // immediate need to actually test for feature availability on the // Autoconf side. } // namespace cxx23 #endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202302L ]]) cdrdao-cdrdao-f00afb2/m4/ax_cxx_compile_stdcxx_14.m4000066400000000000000000000025131511453746600223640ustar00rootroot00000000000000# ============================================================================= # https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_14.html # ============================================================================= # # SYNOPSIS # # AX_CXX_COMPILE_STDCXX_14([ext|noext], [mandatory|optional]) # # DESCRIPTION # # Check for baseline language coverage in the compiler for the C++14 # standard; if necessary, add switches to CXX and CXXCPP to enable # support. # # This macro is a convenience alias for calling the AX_CXX_COMPILE_STDCXX # macro with the version set to C++14. The two optional arguments are # forwarded literally as the second and third argument respectively. # Please see the documentation for the AX_CXX_COMPILE_STDCXX macro for # more information. If you want to use this macro, you also need to # download the ax_cxx_compile_stdcxx.m4 file. # # LICENSE # # Copyright (c) 2015 Moritz Klammler # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 5 AX_REQUIRE_DEFINED([AX_CXX_COMPILE_STDCXX]) AC_DEFUN([AX_CXX_COMPILE_STDCXX_14], [AX_CXX_COMPILE_STDCXX([14], [$1], [$2])]) cdrdao-cdrdao-f00afb2/m4/ax_pthread.m4000066400000000000000000000326761511453746600176150ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_pthread.html # =========================================================================== # # SYNOPSIS # # AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) # # DESCRIPTION # # This macro figures out how to build C programs using POSIX threads. It # sets the PTHREAD_LIBS output variable to the threads library and linker # flags, and the PTHREAD_CFLAGS output variable to any special C compiler # flags that are needed. (The user can also force certain compiler # flags/libs to be tested by setting these environment variables.) # # Also sets PTHREAD_CC to any special C compiler that is needed for # multi-threaded programs (defaults to the value of CC otherwise). (This # is necessary on AIX to use the special cc_r compiler alias.) # # NOTE: You are assumed to not only compile your program with these flags, # but also link it with them as well. e.g. you should link with # $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS # # If you are only building threads programs, you may wish to use these # variables in your default LIBS, CFLAGS, and CC: # # LIBS="$PTHREAD_LIBS $LIBS" # CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # CC="$PTHREAD_CC" # # In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant # has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name # (e.g. PTHREAD_CREATE_UNDETACHED on AIX). # # Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the # PTHREAD_PRIO_INHERIT symbol is defined when compiling with # PTHREAD_CFLAGS. # # ACTION-IF-FOUND is a list of shell commands to run if a threads library # is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it # is not found. If ACTION-IF-FOUND is not specified, the default action # will define HAVE_PTHREAD. # # Please let the authors know if this macro fails on any platform, or if # you have any other suggestions or comments. This macro was based on work # by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help # from M. Frigo), as well as ac_pthread and hb_pthread macros posted by # Alejandro Forero Cuervo to the autoconf macro repository. We are also # grateful for the helpful feedback of numerous users. # # Updated for Autoconf 2.68 by Daniel Richard G. # # LICENSE # # Copyright (c) 2008 Steven G. Johnson # Copyright (c) 2011 Daniel Richard G. # # 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 3 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, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 21 AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) AC_DEFUN([AX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_LANG_PUSH([C]) ax_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on True64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes]) AC_MSG_RESULT([$ax_pthread_ok]) if test x"$ax_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items starting with a "-" are # C compiler flags, and other items are library names, except for "none" # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) # -pthreads: Solaris/gcc # -mthreads: Mingw32/gcc, Lynx/gcc # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) # ... -mt is also the pthreads flag for HP/aCC # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case ${host_os} in solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthreads/-mt/ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags" ;; darwin*) ax_pthread_flags="-pthread $ax_pthread_flags" ;; esac # Clang doesn't consider unrecognized options an error unless we specify # -Werror. We throw in some extra Clang-specific options to ensure that # this doesn't happen for GCC, which also accepts -Werror. AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags]) save_CFLAGS="$CFLAGS" ax_pthread_extra_flags="-Werror" CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])], [AC_MSG_RESULT([yes])], [ax_pthread_extra_flags= AC_MSG_RESULT([no])]) CFLAGS="$save_CFLAGS" if test x"$ax_pthread_ok" = xno; then for flag in $ax_pthread_flags; do case $flag in none) AC_MSG_CHECKING([whether pthreads work without any flags]) ;; -*) AC_MSG_CHECKING([whether pthreads work with $flag]) PTHREAD_CFLAGS="$flag" ;; pthread-config) AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) if test x"$ax_pthread_config" = xno; then continue; fi PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) AC_MSG_CHECKING([for the pthreads library -l$flag]) PTHREAD_LIBS="-l$flag" ;; esac save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. AC_LINK_IFELSE([AC_LANG_PROGRAM([#include static void routine(void *a) { a = 0; } static void *start_routine(void *a) { return a; }], [pthread_t th; pthread_attr_t attr; pthread_create(&th, 0, start_routine, 0); pthread_join(th, 0); pthread_attr_init(&attr); pthread_cleanup_push(routine, 0); pthread_cleanup_pop(0) /* ; */])], [ax_pthread_ok=yes], []) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" AC_MSG_RESULT([$ax_pthread_ok]) if test "x$ax_pthread_ok" = xyes; then break; fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$ax_pthread_ok" = xyes; then save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. AC_MSG_CHECKING([for joinable pthread attribute]) attr_name=unknown for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], [int attr = $attr; return attr /* ; */])], [attr_name=$attr; break], []) done AC_MSG_RESULT([$attr_name]) if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name], [Define to necessary symbol if this constant uses a non-standard name on your system.]) fi AC_MSG_CHECKING([if more special flags are required for pthreads]) flag=no case ${host_os} in aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";; osf* | hpux*) flag="-D_REENTRANT";; solaris*) if test "$GCC" = "yes"; then flag="-D_REENTRANT" else # TODO: What about Clang on Solaris? flag="-mt -D_REENTRANT" fi ;; esac AC_MSG_RESULT([$flag]) if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], [ax_cv_PTHREAD_PRIO_INHERIT], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[int i = PTHREAD_PRIO_INHERIT;]])], [ax_cv_PTHREAD_PRIO_INHERIT=yes], [ax_cv_PTHREAD_PRIO_INHERIT=no]) ]) AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"], [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])]) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: compile with *_r variant if test "x$GCC" != xyes; then case $host_os in aix*) AS_CASE(["x/$CC"], [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], [#handle absolute path differently from PATH based program lookup AS_CASE(["x$CC"], [x/*], [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) ;; esac fi fi test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" AC_SUBST([PTHREAD_LIBS]) AC_SUBST([PTHREAD_CFLAGS]) AC_SUBST([PTHREAD_CC]) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$ax_pthread_ok" = xyes; then ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) : else ax_pthread_ok=no $2 fi AC_LANG_POP ])dnl AX_PTHREAD cdrdao-cdrdao-f00afb2/m4/gconf-2.m4000066400000000000000000000030171511453746600167140ustar00rootroot00000000000000dnl AM_GCONF_SOURCE_2 dnl Defines GCONF_SCHEMA_CONFIG_SOURCE which is where you should install schemas dnl (i.e. pass to gconftool-2 dnl Defines GCONF_SCHEMA_FILE_DIR which is a filesystem directory where dnl you should install foo.schemas files dnl AC_DEFUN([AM_GCONF_SOURCE_2], [ if test "x$GCONF_SCHEMA_INSTALL_SOURCE" = "x"; then GCONF_SCHEMA_CONFIG_SOURCE=`gconftool-2 --get-default-source` else GCONF_SCHEMA_CONFIG_SOURCE=$GCONF_SCHEMA_INSTALL_SOURCE fi AC_ARG_WITH([gconf-source], AS_HELP_STRING([--with-gconf-source=sourceaddress],[Config database for installing schema files.]), [GCONF_SCHEMA_CONFIG_SOURCE="$withval"],) AC_SUBST(GCONF_SCHEMA_CONFIG_SOURCE) AC_MSG_RESULT([Using config source $GCONF_SCHEMA_CONFIG_SOURCE for schema installation]) if test "x$GCONF_SCHEMA_FILE_DIR" = "x"; then GCONF_SCHEMA_FILE_DIR='$(sysconfdir)/gconf/schemas' fi AC_ARG_WITH([gconf-schema-file-dir], AS_HELP_STRING([--with-gconf-schema-file-dir=dir],[Directory for installing schema files.]), [GCONF_SCHEMA_FILE_DIR="$withval"],) AC_SUBST(GCONF_SCHEMA_FILE_DIR) AC_MSG_RESULT([Using $GCONF_SCHEMA_FILE_DIR as install directory for schema files]) AC_ARG_ENABLE(schemas-install, AS_HELP_STRING([--disable-schemas-install],[Disable the schemas installation]), [case ${enableval} in yes|no) ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-schemas-install]) ;; esac]) AM_CONDITIONAL([GCONF_SCHEMAS_INSTALL], [test "$enable_schemas_install" != no]) ]) cdrdao-cdrdao-f00afb2/m4/gsettings.m4000066400000000000000000000070051511453746600174710ustar00rootroot00000000000000# Increment this whenever this file is changed. #serial 2 dnl GLIB_GSETTINGS dnl Defines GSETTINGS_SCHEMAS_INSTALL which controls whether dnl the schema should be compiled dnl AC_DEFUN([GLIB_GSETTINGS], [ dnl We can't use PKG_PREREQ because that needs 0.29. m4_ifndef([PKG_PROG_PKG_CONFIG], [pkg.m4 version 0.28 or later is required]) m4_pattern_allow([AM_V_GEN]) AC_ARG_ENABLE(schemas-compile, AS_HELP_STRING([--disable-schemas-compile], [Disable regeneration of gschemas.compiled on install]), [case ${enableval} in yes) GSETTINGS_DISABLE_SCHEMAS_COMPILE="" ;; no) GSETTINGS_DISABLE_SCHEMAS_COMPILE="1" ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-schemas-compile]) ;; esac]) AC_SUBST([GSETTINGS_DISABLE_SCHEMAS_COMPILE]) PKG_PROG_PKG_CONFIG([0.16]) AC_SUBST(gsettingsschemadir, [${datadir}/glib-2.0/schemas]) AS_IF([test x$cross_compiling != xyes], [PKG_CHECK_VAR([GLIB_COMPILE_SCHEMAS], [gio-2.0], [glib_compile_schemas])], [AC_PATH_PROG([GLIB_COMPILE_SCHEMAS], [glib-compile-schemas])]) AC_SUBST(GLIB_COMPILE_SCHEMAS) if test "x$GLIB_COMPILE_SCHEMAS" = "x"; then ifelse([$2],,[AC_MSG_ERROR([glib-compile-schemas not found.])],[$2]) else ifelse([$1],,[:],[$1]) fi GSETTINGS_RULES=' .PHONY : uninstall-gsettings-schemas install-gsettings-schemas clean-gsettings-schemas mostlyclean-am: clean-gsettings-schemas gsettings__enum_file = $(addsuffix .enums.xml,$(gsettings_ENUM_NAMESPACE)) %.gschema.valid: %.gschema.xml $(gsettings__enum_file) $(AM_V_GEN) $(GLIB_COMPILE_SCHEMAS) --strict --dry-run $(addprefix --schema-file=,$(gsettings__enum_file)) --schema-file=$< && mkdir -p [$](@D) && touch [$]@ all-am: $(gsettings_SCHEMAS:.xml=.valid) uninstall-am: uninstall-gsettings-schemas install-data-am: install-gsettings-schemas .SECONDARY: $(gsettings_SCHEMAS) install-gsettings-schemas: $(gsettings_SCHEMAS) $(gsettings__enum_file) @$(NORMAL_INSTALL) if test -n "$^"; then \ test -z "$(gsettingsschemadir)" || $(MKDIR_P) "$(DESTDIR)$(gsettingsschemadir)"; \ $(INSTALL_DATA) $^ "$(DESTDIR)$(gsettingsschemadir)"; \ test -n "$(GSETTINGS_DISABLE_SCHEMAS_COMPILE)$(DESTDIR)" || $(GLIB_COMPILE_SCHEMAS) $(gsettingsschemadir); \ fi uninstall-gsettings-schemas: @$(NORMAL_UNINSTALL) @list='\''$(gsettings_SCHEMAS) $(gsettings__enum_file)'\''; test -n "$(gsettingsschemadir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e '\''s|^.*/||'\''`; \ test -n "$$files" || exit 0; \ echo " ( cd '\''$(DESTDIR)$(gsettingsschemadir)'\'' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(gsettingsschemadir)" && rm -f $$files test -n "$(GSETTINGS_DISABLE_SCHEMAS_COMPILE)$(DESTDIR)" || $(GLIB_COMPILE_SCHEMAS) $(gsettingsschemadir) clean-gsettings-schemas: rm -f $(gsettings_SCHEMAS:.xml=.valid) $(gsettings__enum_file) ifdef gsettings_ENUM_NAMESPACE $(gsettings__enum_file): $(gsettings_ENUM_FILES) $(AM_V_GEN) glib-mkenums --comments '\'''\'' --fhead "" --vhead " <@type@ id='\''$(gsettings_ENUM_NAMESPACE).@EnumName@'\''>" --vprod " " --vtail " " --ftail "" [$]^ > [$]@.tmp && mv [$]@.tmp [$]@ endif ' _GSETTINGS_SUBST(GSETTINGS_RULES) ]) dnl _GSETTINGS_SUBST(VARIABLE) dnl Abstract macro to do either _AM_SUBST_NOTMAKE or AC_SUBST AC_DEFUN([_GSETTINGS_SUBST], [ AC_SUBST([$1]) m4_ifdef([_AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE([$1])]) ] ) cdrdao-cdrdao-f00afb2/m4/host-cpu-c-abi.m4000066400000000000000000000414521511453746600202010ustar00rootroot00000000000000# host-cpu-c-abi.m4 # serial 18 dnl Copyright (C) 2002-2024 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl This file is offered as-is, without any warranty. dnl From Bruno Haible and Sam Steingold. dnl Sets the HOST_CPU variable to the canonical name of the CPU. dnl Sets the HOST_CPU_C_ABI variable to the canonical name of the CPU with its dnl C language ABI (application binary interface). dnl Also defines __${HOST_CPU}__ and __${HOST_CPU_C_ABI}__ as C macros in dnl config.h. dnl dnl This canonical name can be used to select a particular assembly language dnl source file that will interoperate with C code on the given host. dnl dnl For example: dnl * 'i386' and 'sparc' are different canonical names, because code for i386 dnl will not run on SPARC CPUs and vice versa. They have different dnl instruction sets. dnl * 'sparc' and 'sparc64' are different canonical names, because code for dnl 'sparc' and code for 'sparc64' cannot be linked together: 'sparc' code dnl contains 32-bit instructions, whereas 'sparc64' code contains 64-bit dnl instructions. A process on a SPARC CPU can be in 32-bit mode or in 64-bit dnl mode, but not both. dnl * 'mips' and 'mipsn32' are different canonical names, because they use dnl different argument passing and return conventions for C functions, and dnl although the instruction set of 'mips' is a large subset of the dnl instruction set of 'mipsn32'. dnl * 'mipsn32' and 'mips64' are different canonical names, because they use dnl different sizes for the C types like 'int' and 'void *', and although dnl the instruction sets of 'mipsn32' and 'mips64' are the same. dnl * The same canonical name is used for different endiannesses. You can dnl determine the endianness through preprocessor symbols: dnl - 'arm': test __ARMEL__. dnl - 'mips', 'mipsn32', 'mips64': test _MIPSEB vs. _MIPSEL. dnl - 'powerpc64': test __BIG_ENDIAN__ vs. __LITTLE_ENDIAN__. dnl * The same name 'i386' is used for CPUs of type i386, i486, i586 dnl (Pentium), AMD K7, Pentium II, Pentium IV, etc., because dnl - Instructions that do not exist on all of these CPUs (cmpxchg, dnl MMX, SSE, SSE2, 3DNow! etc.) are not frequently used. If your dnl assembly language source files use such instructions, you will dnl need to make the distinction. dnl - Speed of execution of the common instruction set is reasonable across dnl the entire family of CPUs. If you have assembly language source files dnl that are optimized for particular CPU types (like GNU gmp has), you dnl will need to make the distinction. dnl See . AC_DEFUN([gl_HOST_CPU_C_ABI], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([gl_C_ASM]) AC_CACHE_CHECK([host CPU and C ABI], [gl_cv_host_cpu_c_abi], [case "$host_cpu" in changequote(,)dnl i[34567]86 ) changequote([,])dnl gl_cv_host_cpu_c_abi=i386 ;; x86_64 ) # On x86_64 systems, the C compiler may be generating code in one of # these ABIs: # - 64-bit instruction set, 64-bit pointers, 64-bit 'long': x86_64. # - 64-bit instruction set, 64-bit pointers, 32-bit 'long': x86_64 # with native Windows (mingw, MSVC). # - 64-bit instruction set, 32-bit pointers, 32-bit 'long': x86_64-x32. # - 32-bit instruction set, 32-bit pointers, 32-bit 'long': i386. AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#if (defined __x86_64__ || defined __amd64__ \ || defined _M_X64 || defined _M_AMD64) int ok; #else error fail #endif ]])], [AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#if defined __ILP32__ || defined _ILP32 int ok; #else error fail #endif ]])], [gl_cv_host_cpu_c_abi=x86_64-x32], [gl_cv_host_cpu_c_abi=x86_64])], [gl_cv_host_cpu_c_abi=i386]) ;; changequote(,)dnl alphaev[4-8] | alphaev56 | alphapca5[67] | alphaev6[78] ) changequote([,])dnl gl_cv_host_cpu_c_abi=alpha ;; arm* | aarch64 ) # Assume arm with EABI. # On arm64 systems, the C compiler may be generating code in one of # these ABIs: # - aarch64 instruction set, 64-bit pointers, 64-bit 'long': arm64. # - aarch64 instruction set, 32-bit pointers, 32-bit 'long': arm64-ilp32. # - 32-bit instruction set, 32-bit pointers, 32-bit 'long': arm or armhf. AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#ifdef __aarch64__ int ok; #else error fail #endif ]])], [AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#if defined __ILP32__ || defined _ILP32 int ok; #else error fail #endif ]])], [gl_cv_host_cpu_c_abi=arm64-ilp32], [gl_cv_host_cpu_c_abi=arm64])], [# Don't distinguish little-endian and big-endian arm, since they # don't require different machine code for simple operations and # since the user can distinguish them through the preprocessor # defines __ARMEL__ vs. __ARMEB__. # But distinguish arm which passes floating-point arguments and # return values in integer registers (r0, r1, ...) - this is # gcc -mfloat-abi=soft or gcc -mfloat-abi=softfp - from arm which # passes them in float registers (s0, s1, ...) and double registers # (d0, d1, ...) - this is gcc -mfloat-abi=hard. GCC 4.6 or newer # sets the preprocessor defines __ARM_PCS (for the first case) and # __ARM_PCS_VFP (for the second case), but older GCC does not. echo 'double ddd; void func (double dd) { ddd = dd; }' > conftest.c # Look for a reference to the register d0 in the .s file. AC_TRY_COMMAND(${CC-cc} $CFLAGS $CPPFLAGS $gl_c_asm_opt conftest.c) >/dev/null 2>&1 if LC_ALL=C grep 'd0,' conftest.$gl_asmext >/dev/null; then gl_cv_host_cpu_c_abi=armhf else gl_cv_host_cpu_c_abi=arm fi rm -f conftest* ]) ;; hppa1.0 | hppa1.1 | hppa2.0* | hppa64 ) # On hppa, the C compiler may be generating 32-bit code or 64-bit # code. In the latter case, it defines _LP64 and __LP64__. AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#ifdef __LP64__ int ok; #else error fail #endif ]])], [gl_cv_host_cpu_c_abi=hppa64], [gl_cv_host_cpu_c_abi=hppa]) ;; ia64* ) # On ia64 on HP-UX, the C compiler may be generating 64-bit code or # 32-bit code. In the latter case, it defines _ILP32. AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#ifdef _ILP32 int ok; #else error fail #endif ]])], [gl_cv_host_cpu_c_abi=ia64-ilp32], [gl_cv_host_cpu_c_abi=ia64]) ;; mips* ) # We should also check for (_MIPS_SZPTR == 64), but gcc keeps this # at 32. AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#if defined _MIPS_SZLONG && (_MIPS_SZLONG == 64) int ok; #else error fail #endif ]])], [gl_cv_host_cpu_c_abi=mips64], [# In the n32 ABI, _ABIN32 is defined, _ABIO32 is not defined (but # may later get defined by ), and _MIPS_SIM == _ABIN32. # In the 32 ABI, _ABIO32 is defined, _ABIN32 is not defined (but # may later get defined by ), and _MIPS_SIM == _ABIO32. AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#if (_MIPS_SIM == _ABIN32) int ok; #else error fail #endif ]])], [gl_cv_host_cpu_c_abi=mipsn32], [gl_cv_host_cpu_c_abi=mips])]) ;; powerpc* ) # Different ABIs are in use on AIX vs. Mac OS X vs. Linux,*BSD. # No need to distinguish them here; the caller may distinguish # them based on the OS. # On powerpc64 systems, the C compiler may still be generating # 32-bit code. And on powerpc-ibm-aix systems, the C compiler may # be generating 64-bit code. AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#if defined __powerpc64__ || defined __LP64__ int ok; #else error fail #endif ]])], [# On powerpc64, there are two ABIs on Linux: The AIX compatible # one and the ELFv2 one. The latter defines _CALL_ELF=2. AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#if defined _CALL_ELF && _CALL_ELF == 2 int ok; #else error fail #endif ]])], [gl_cv_host_cpu_c_abi=powerpc64-elfv2], [gl_cv_host_cpu_c_abi=powerpc64]) ], [gl_cv_host_cpu_c_abi=powerpc]) ;; rs6000 ) gl_cv_host_cpu_c_abi=powerpc ;; riscv32 | riscv64 ) # There are 2 architectures (with variants): rv32* and rv64*. AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#if __riscv_xlen == 64 int ok; #else error fail #endif ]])], [cpu=riscv64], [cpu=riscv32]) # There are 6 ABIs: ilp32, ilp32f, ilp32d, lp64, lp64f, lp64d. # Size of 'long' and 'void *': AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#if defined __LP64__ int ok; #else error fail #endif ]])], [main_abi=lp64], [main_abi=ilp32]) # Float ABIs: # __riscv_float_abi_double: # 'float' and 'double' are passed in floating-point registers. # __riscv_float_abi_single: # 'float' are passed in floating-point registers. # __riscv_float_abi_soft: # No values are passed in floating-point registers. AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#if defined __riscv_float_abi_double int ok; #else error fail #endif ]])], [float_abi=d], [AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#if defined __riscv_float_abi_single int ok; #else error fail #endif ]])], [float_abi=f], [float_abi='']) ]) gl_cv_host_cpu_c_abi="${cpu}-${main_abi}${float_abi}" ;; s390* ) # On s390x, the C compiler may be generating 64-bit (= s390x) code # or 31-bit (= s390) code. AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#if defined __LP64__ || defined __s390x__ int ok; #else error fail #endif ]])], [gl_cv_host_cpu_c_abi=s390x], [gl_cv_host_cpu_c_abi=s390]) ;; sparc | sparc64 ) # UltraSPARCs running Linux have `uname -m` = "sparc64", but the # C compiler still generates 32-bit code. AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[#if defined __sparcv9 || defined __arch64__ int ok; #else error fail #endif ]])], [gl_cv_host_cpu_c_abi=sparc64], [gl_cv_host_cpu_c_abi=sparc]) ;; *) gl_cv_host_cpu_c_abi="$host_cpu" ;; esac ]) dnl In most cases, $HOST_CPU and $HOST_CPU_C_ABI are the same. HOST_CPU=`echo "$gl_cv_host_cpu_c_abi" | sed -e 's/-.*//'` HOST_CPU_C_ABI="$gl_cv_host_cpu_c_abi" AC_SUBST([HOST_CPU]) AC_SUBST([HOST_CPU_C_ABI]) # This was # AC_DEFINE_UNQUOTED([__${HOST_CPU}__]) # AC_DEFINE_UNQUOTED([__${HOST_CPU_C_ABI}__]) # earlier, but KAI C++ 3.2d doesn't like this. sed -e 's/-/_/g' >> confdefs.h <. dnl Don't make changes that are incompatible with that documentation! AC_DEFUN([AM_ICONV_LINKFLAGS_BODY], [ dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV dnl accordingly. AC_LIB_LINKFLAGS_BODY([iconv]) ]) AC_DEFUN([AM_ICONV_LINK], [ dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and dnl those with the standalone portable GNU libiconv installed). AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV dnl accordingly. AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) dnl Add $INCICONV to CPPFLAGS before performing the following checks, dnl because if the user has installed libiconv and not disabled its use dnl via --without-libiconv-prefix, he wants to use it. The first dnl AC_LINK_IFELSE will then fail, the second AC_LINK_IFELSE will succeed. gl_saved_CPPFLAGS="$CPPFLAGS" AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV]) AC_CACHE_CHECK([for iconv], [am_cv_func_iconv], [ am_cv_func_iconv="no, consider installing GNU libiconv" am_cv_lib_iconv=no AC_LINK_IFELSE( [AC_LANG_PROGRAM( [[ #include #include ]], [[iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd);]])], [am_cv_func_iconv=yes]) if test "$am_cv_func_iconv" != yes; then gl_saved_LIBS="$LIBS" LIBS="$LIBS $LIBICONV" AC_LINK_IFELSE( [AC_LANG_PROGRAM( [[ #include #include ]], [[iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd);]])], [am_cv_lib_iconv=yes] [am_cv_func_iconv=yes]) LIBS="$gl_saved_LIBS" fi ]) if test "$am_cv_func_iconv" = yes; then AC_CACHE_CHECK([for working iconv], [am_cv_func_iconv_works], [ dnl This tests against bugs in AIX 5.1, AIX 6.1..7.1, HP-UX 11.11, dnl Solaris 10, macOS 14.4. gl_saved_LIBS="$LIBS" if test $am_cv_lib_iconv = yes; then LIBS="$LIBS $LIBICONV" fi am_cv_func_iconv_works=no for ac_iconv_const in '' 'const'; do AC_RUN_IFELSE( [AC_LANG_PROGRAM( [[ #include #include #ifndef ICONV_CONST # define ICONV_CONST $ac_iconv_const #endif ]], [[int result = 0; /* Test against AIX 5.1...7.2 bug: Failures are not distinguishable from successful returns. This is even documented in */ { iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8"); if (cd_utf8_to_88591 != (iconv_t)(-1)) { static ICONV_CONST char input[] = "\342\202\254"; /* EURO SIGN */ char buf[10]; ICONV_CONST char *inptr = input; size_t inbytesleft = strlen (input); char *outptr = buf; size_t outbytesleft = sizeof (buf); size_t res = iconv (cd_utf8_to_88591, &inptr, &inbytesleft, &outptr, &outbytesleft); if (res == 0) result |= 1; iconv_close (cd_utf8_to_88591); } } /* Test against Solaris 10 bug: Failures are not distinguishable from successful returns. */ { iconv_t cd_ascii_to_88591 = iconv_open ("ISO8859-1", "646"); if (cd_ascii_to_88591 != (iconv_t)(-1)) { static ICONV_CONST char input[] = "\263"; char buf[10]; ICONV_CONST char *inptr = input; size_t inbytesleft = strlen (input); char *outptr = buf; size_t outbytesleft = sizeof (buf); size_t res = iconv (cd_ascii_to_88591, &inptr, &inbytesleft, &outptr, &outbytesleft); if (res == 0) result |= 4; iconv_close (cd_ascii_to_88591); } } /* Test against AIX 6.1..7.1 bug: Buffer overrun. */ { iconv_t cd_88591_to_utf8 = iconv_open ("UTF-8", "ISO-8859-1"); if (cd_88591_to_utf8 != (iconv_t)(-1)) { static ICONV_CONST char input[] = "\304"; static char buf[2] = { (char)0xDE, (char)0xAD }; ICONV_CONST char *inptr = input; size_t inbytesleft = 1; char *outptr = buf; size_t outbytesleft = 1; size_t res = iconv (cd_88591_to_utf8, &inptr, &inbytesleft, &outptr, &outbytesleft); if (res != (size_t)(-1) || outptr - buf > 1 || buf[1] != (char)0xAD) result |= 8; iconv_close (cd_88591_to_utf8); } } #if 0 /* This bug could be worked around by the caller. */ /* Test against HP-UX 11.11 bug: Positive return value instead of 0. */ { iconv_t cd_88591_to_utf8 = iconv_open ("utf8", "iso88591"); if (cd_88591_to_utf8 != (iconv_t)(-1)) { static ICONV_CONST char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337"; char buf[50]; ICONV_CONST char *inptr = input; size_t inbytesleft = strlen (input); char *outptr = buf; size_t outbytesleft = sizeof (buf); size_t res = iconv (cd_88591_to_utf8, &inptr, &inbytesleft, &outptr, &outbytesleft); if ((int)res > 0) result |= 16; iconv_close (cd_88591_to_utf8); } } #endif /* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is provided. */ { /* Try standardized names. */ iconv_t cd1 = iconv_open ("UTF-8", "EUC-JP"); /* Try IRIX, OSF/1 names. */ iconv_t cd2 = iconv_open ("UTF-8", "eucJP"); /* Try AIX names. */ iconv_t cd3 = iconv_open ("UTF-8", "IBM-eucJP"); /* Try HP-UX names. */ iconv_t cd4 = iconv_open ("utf8", "eucJP"); if (cd1 == (iconv_t)(-1) && cd2 == (iconv_t)(-1) && cd3 == (iconv_t)(-1) && cd4 == (iconv_t)(-1)) result |= 32; if (cd1 != (iconv_t)(-1)) iconv_close (cd1); if (cd2 != (iconv_t)(-1)) iconv_close (cd2); if (cd3 != (iconv_t)(-1)) iconv_close (cd3); if (cd4 != (iconv_t)(-1)) iconv_close (cd4); } return result; ]])], [am_cv_func_iconv_works=yes], , [case "$host_os" in aix* | hpux*) am_cv_func_iconv_works="guessing no" ;; *) am_cv_func_iconv_works="guessing yes" ;; esac]) test "$am_cv_func_iconv_works" = no || break done LIBS="$gl_saved_LIBS" ]) case "$am_cv_func_iconv_works" in *no) am_func_iconv=no am_cv_lib_iconv=no ;; *) am_func_iconv=yes ;; esac else am_func_iconv=no am_cv_lib_iconv=no fi if test "$am_func_iconv" = yes; then AC_DEFINE([HAVE_ICONV], [1], [Define if you have the iconv() function and it works.]) fi if test "$am_cv_lib_iconv" = yes; then AC_MSG_CHECKING([how to link with libiconv]) AC_MSG_RESULT([$LIBICONV]) else dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV dnl either. CPPFLAGS="$gl_saved_CPPFLAGS" LIBICONV= LTLIBICONV= fi AC_SUBST([LIBICONV]) AC_SUBST([LTLIBICONV]) ]) dnl Define AM_ICONV using AC_DEFUN_ONCE, in order to avoid warnings like dnl "warning: AC_REQUIRE: `AM_ICONV' was expanded before it was required". AC_DEFUN_ONCE([AM_ICONV], [ AM_ICONV_LINK if test "$am_cv_func_iconv" = yes; then AC_CACHE_CHECK([whether iconv is compatible with its POSIX signature], [gl_cv_iconv_nonconst], [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[ #include #include extern #ifdef __cplusplus "C" #endif size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); ]], [[]])], [gl_cv_iconv_nonconst=yes], [gl_cv_iconv_nonconst=no]) ]) else dnl When compiling GNU libiconv on a system that does not have iconv yet, dnl pick the POSIX compliant declaration without 'const'. gl_cv_iconv_nonconst=yes fi if test $gl_cv_iconv_nonconst = yes; then iconv_arg1="" else iconv_arg1="const" fi AC_DEFINE_UNQUOTED([ICONV_CONST], [$iconv_arg1], [Define as const if the declaration of iconv() needs const.]) dnl Also substitute ICONV_CONST in the gnulib generated . m4_ifdef([gl_ICONV_H_DEFAULTS], [AC_REQUIRE([gl_ICONV_H_DEFAULTS]) if test $gl_cv_iconv_nonconst != yes; then ICONV_CONST="const" fi ]) dnl A summary result, for those packages which want to print a summary at the dnl end of the configuration. if test "$am_func_iconv" = yes; then if test -n "$LIBICONV"; then am_cv_func_iconv_summary='yes, in libiconv' else am_cv_func_iconv_summary='yes, in libc' fi else if test "$am_cv_func_iconv" = yes; then am_cv_func_iconv_summary='not working, consider installing GNU libiconv' else am_cv_func_iconv_summary='no, consider installing GNU libiconv' fi fi ]) cdrdao-cdrdao-f00afb2/m4/lib-ld.m4000066400000000000000000000125001511453746600166210ustar00rootroot00000000000000# lib-ld.m4 # serial 13 dnl Copyright (C) 1996-2003, 2009-2024 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl This file is offered as-is, without any warranty. dnl Subroutines of libtool.m4, dnl with replacements s/_*LT_PATH/AC_LIB_PROG/ and s/lt_/acl_/ to avoid dnl collision with libtool.m4. dnl From libtool-2.4. Sets the variable with_gnu_ld to yes or no. AC_DEFUN([AC_LIB_PROG_LD_GNU], [AC_CACHE_CHECK([if the linker ($LD) is GNU ld], [acl_cv_prog_gnu_ld], [# I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 /dev/null 2>&1 \ && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ || PATH_SEPARATOR=';' } fi if test -n "$LD"; then AC_MSG_CHECKING([for ld]) elif test "$GCC" = yes; then AC_MSG_CHECKING([for ld used by $CC]) elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi if test -n "$LD"; then # Let the user override the test with a path. : else AC_CACHE_VAL([acl_cv_path_LD], [ acl_cv_path_LD= # Final result of this test ac_prog=ld # Program to search in $PATH if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. case $host in *-*-mingw* | windows*) # gcc leaves a trailing carriage return which upsets mingw acl_output=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) acl_output=`($CC -print-prog-name=ld) 2>&5` ;; esac case $acl_output in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld acl_output=`echo "$acl_output" | sed 's%\\\\%/%g'` while echo "$acl_output" | grep "$re_direlt" > /dev/null 2>&1; do acl_output=`echo $acl_output | sed "s%$re_direlt%/%"` done # Got the pathname. No search in PATH is needed. acl_cv_path_LD="$acl_output" ac_prog= ;; "") # If it fails, then pretend we aren't using GCC. ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac fi if test -n "$ac_prog"; then # Search for $ac_prog in $PATH. acl_saved_IFS="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$acl_saved_IFS" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then acl_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$acl_cv_path_LD" -v 2>&1 conftest.sh . ./conftest.sh rm -f ./conftest.sh acl_cv_rpath=done ]) wl="$acl_cv_wl" acl_libext="$acl_cv_libext" acl_shlibext="$acl_cv_shlibext" acl_libname_spec="$acl_cv_libname_spec" acl_library_names_spec="$acl_cv_library_names_spec" acl_hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" acl_hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" acl_hardcode_direct="$acl_cv_hardcode_direct" acl_hardcode_minus_L="$acl_cv_hardcode_minus_L" dnl Determine whether the user wants rpath handling at all. AC_ARG_ENABLE([rpath], [ --disable-rpath do not hardcode runtime library paths], :, enable_rpath=yes) ]) dnl AC_LIB_FROMPACKAGE(name, package) dnl declares that libname comes from the given package. The configure file dnl will then not have a --with-libname-prefix option but a dnl --with-package-prefix option. Several libraries can come from the same dnl package. This declaration must occur before an AC_LIB_LINKFLAGS or similar dnl macro call that searches for libname. AC_DEFUN([AC_LIB_FROMPACKAGE], [ pushdef([NAME],[m4_translit([$1],[abcdefghijklmnopqrstuvwxyz./+-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])]) define([acl_frompackage_]NAME, [$2]) popdef([NAME]) pushdef([PACK],[$2]) pushdef([PACKUP],[m4_translit(PACK,[abcdefghijklmnopqrstuvwxyz./+-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])]) define([acl_libsinpackage_]PACKUP, m4_ifdef([acl_libsinpackage_]PACKUP, [m4_defn([acl_libsinpackage_]PACKUP)[, ]],)[lib$1]) popdef([PACKUP]) popdef([PACK]) ]) dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and dnl the libraries corresponding to explicit and implicit dependencies. dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables. dnl Also, sets the LIB${NAME}_PREFIX variable to nonempty if libname was found dnl in ${LIB${NAME}_PREFIX}/$acl_libdirstem. AC_DEFUN([AC_LIB_LINKFLAGS_BODY], [ AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) pushdef([NAME],[m4_translit([$1],[abcdefghijklmnopqrstuvwxyz./+-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])]) pushdef([PACK],[m4_ifdef([acl_frompackage_]NAME, [acl_frompackage_]NAME, lib[$1])]) pushdef([PACKUP],[m4_translit(PACK,[abcdefghijklmnopqrstuvwxyz./+-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])]) pushdef([PACKLIBS],[m4_ifdef([acl_frompackage_]NAME, [acl_libsinpackage_]PACKUP, lib[$1])]) dnl By default, look in $includedir and $libdir. use_additional=yes AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" eval additional_libdir2=\"$exec_prefix/$acl_libdirstem2\" eval additional_libdir3=\"$exec_prefix/$acl_libdirstem3\" ]) AC_ARG_WITH(PACK[-prefix], [[ --with-]]PACK[[-prefix[=DIR] search for ]]PACKLIBS[[ in DIR/include and DIR/lib --without-]]PACK[[-prefix don't search for ]]PACKLIBS[[ in includedir and libdir]], [ if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" eval additional_libdir2=\"$exec_prefix/$acl_libdirstem2\" eval additional_libdir3=\"$exec_prefix/$acl_libdirstem3\" ]) else additional_includedir="$withval/include" additional_libdir="$withval/$acl_libdirstem" additional_libdir2="$withval/$acl_libdirstem2" additional_libdir3="$withval/$acl_libdirstem3" fi fi ]) if test "X$additional_libdir2" = "X$additional_libdir"; then additional_libdir2= fi if test "X$additional_libdir3" = "X$additional_libdir"; then additional_libdir3= fi dnl Search the library and its dependencies in $additional_libdir and dnl $LDFLAGS. Use breadth-first search. LIB[]NAME= LTLIB[]NAME= INC[]NAME= LIB[]NAME[]_PREFIX= dnl HAVE_LIB${NAME} is an indicator that LIB${NAME}, LTLIB${NAME} have been dnl computed. So it has to be reset here. HAVE_LIB[]NAME= rpathdirs= ltrpathdirs= names_already_handled= names_next_round='$1 $2' while test -n "$names_next_round"; do names_this_round="$names_next_round" names_next_round= for name in $names_this_round; do already_handled= for n in $names_already_handled; do if test "$n" = "$name"; then already_handled=yes break fi done if test -z "$already_handled"; then names_already_handled="$names_already_handled $name" dnl See if it was already located by an earlier AC_LIB_LINKFLAGS dnl or AC_LIB_HAVE_LINKFLAGS call. uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./+-|ABCDEFGHIJKLMNOPQRSTUVWXYZ____|'` eval value=\"\$HAVE_LIB$uppername\" if test -n "$value"; then if test "$value" = yes; then eval value=\"\$LIB$uppername\" test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value" eval value=\"\$LTLIB$uppername\" test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value" else dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined dnl that this library doesn't exist. So just drop it. : fi else dnl Search the library lib$name in $additional_libdir and $LDFLAGS dnl and the already constructed $LIBNAME/$LTLIBNAME. found_dir= found_la= found_so= found_a= eval libname=\"$acl_libname_spec\" # typically: libname=lib$name if test -n "$acl_shlibext"; then shrext=".$acl_shlibext" # typically: shrext=.so else shrext= fi if test $use_additional = yes; then for additional_libdir_variable in additional_libdir additional_libdir2 additional_libdir3; do if test "X$found_dir" = "X"; then eval dir=\$$additional_libdir_variable if test -n "$dir"; then dnl The same code as in the loop below: dnl First look for a shared library. if test -n "$acl_shlibext"; then if test -f "$dir/$libname$shrext" && acl_is_expected_elfclass < "$dir/$libname$shrext"; then found_dir="$dir" found_so="$dir/$libname$shrext" else if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then ver=`(cd "$dir" && \ for f in "$libname$shrext".*; do echo "$f"; done \ | sed -e "s,^$libname$shrext\\\\.,," \ | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ | sed 1q ) 2>/dev/null` if test -n "$ver" && test -f "$dir/$libname$shrext.$ver" && acl_is_expected_elfclass < "$dir/$libname$shrext.$ver"; then found_dir="$dir" found_so="$dir/$libname$shrext.$ver" fi else eval library_names=\"$acl_library_names_spec\" for f in $library_names; do if test -f "$dir/$f" && acl_is_expected_elfclass < "$dir/$f"; then found_dir="$dir" found_so="$dir/$f" break fi done fi fi fi dnl Then look for a static library. if test "X$found_dir" = "X"; then if test -f "$dir/$libname.$acl_libext" && ${AR-ar} -p "$dir/$libname.$acl_libext" | acl_is_expected_elfclass; then found_dir="$dir" found_a="$dir/$libname.$acl_libext" fi fi if test "X$found_dir" != "X"; then if test -f "$dir/$libname.la"; then found_la="$dir/$libname.la" fi fi fi fi done fi if test "X$found_dir" = "X"; then for x in $LDFLAGS $LTLIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) case "$x" in -L*) dir=`echo "X$x" | sed -e 's/^X-L//'` dnl First look for a shared library. if test -n "$acl_shlibext"; then if test -f "$dir/$libname$shrext" && acl_is_expected_elfclass < "$dir/$libname$shrext"; then found_dir="$dir" found_so="$dir/$libname$shrext" else if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then ver=`(cd "$dir" && \ for f in "$libname$shrext".*; do echo "$f"; done \ | sed -e "s,^$libname$shrext\\\\.,," \ | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ | sed 1q ) 2>/dev/null` if test -n "$ver" && test -f "$dir/$libname$shrext.$ver" && acl_is_expected_elfclass < "$dir/$libname$shrext.$ver"; then found_dir="$dir" found_so="$dir/$libname$shrext.$ver" fi else eval library_names=\"$acl_library_names_spec\" for f in $library_names; do if test -f "$dir/$f" && acl_is_expected_elfclass < "$dir/$f"; then found_dir="$dir" found_so="$dir/$f" break fi done fi fi fi dnl Then look for a static library. if test "X$found_dir" = "X"; then if test -f "$dir/$libname.$acl_libext" && ${AR-ar} -p "$dir/$libname.$acl_libext" | acl_is_expected_elfclass; then found_dir="$dir" found_a="$dir/$libname.$acl_libext" fi fi if test "X$found_dir" != "X"; then if test -f "$dir/$libname.la"; then found_la="$dir/$libname.la" fi fi ;; esac if test "X$found_dir" != "X"; then break fi done fi if test "X$found_dir" != "X"; then dnl Found the library. LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name" if test "X$found_so" != "X"; then dnl Linking with a shared library. We attempt to hardcode its dnl directory into the executable's runpath, unless it's the dnl standard /usr/lib. if test "$enable_rpath" = no \ || test "X$found_dir" = "X/usr/$acl_libdirstem" \ || test "X$found_dir" = "X/usr/$acl_libdirstem2" \ || test "X$found_dir" = "X/usr/$acl_libdirstem3"; then dnl No hardcoding is needed. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else dnl Use an explicit option to hardcode DIR into the resulting dnl binary. dnl Potentially add DIR to ltrpathdirs. dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. haveit= for x in $ltrpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $found_dir" fi dnl The hardcoding into $LIBNAME is system dependent. if test "$acl_hardcode_direct" = yes; then dnl Using DIR/libNAME.so during linking hardcodes DIR into the dnl resulting binary. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then dnl Use an explicit option to hardcode DIR into the resulting dnl binary. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" dnl Potentially add DIR to rpathdirs. dnl The rpathdirs will be appended to $LIBNAME at the end. haveit= for x in $rpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $found_dir" fi else dnl Rely on "-L$found_dir". dnl But don't add it if it's already contained in the LDFLAGS dnl or the already constructed $LIBNAME haveit= for x in $LDFLAGS $LIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir" fi if test "$acl_hardcode_minus_L" != no; then dnl FIXME: Not sure whether we should use dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" dnl here. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else dnl We cannot use $acl_hardcode_runpath_var and LD_RUN_PATH dnl here, because this doesn't fit in flags passed to the dnl compiler. So give up. No hardcoding. This affects only dnl very old systems. dnl FIXME: Not sure whether we should use dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" dnl here. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" fi fi fi fi else if test "X$found_a" != "X"; then dnl Linking with a static library. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a" else dnl We shouldn't come here, but anyway it's good to have a dnl fallback. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name" fi fi dnl Assume the include files are nearby. additional_includedir= case "$found_dir" in */$acl_libdirstem | */$acl_libdirstem/) basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` if test "$name" = '$1'; then LIB[]NAME[]_PREFIX="$basedir" fi additional_includedir="$basedir/include" ;; */$acl_libdirstem2 | */$acl_libdirstem2/) basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem2/"'*$,,'` if test "$name" = '$1'; then LIB[]NAME[]_PREFIX="$basedir" fi additional_includedir="$basedir/include" ;; */$acl_libdirstem3 | */$acl_libdirstem3/) basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem3/"'*$,,'` if test "$name" = '$1'; then LIB[]NAME[]_PREFIX="$basedir" fi additional_includedir="$basedir/include" ;; esac if test "X$additional_includedir" != "X"; then dnl Potentially add $additional_includedir to $INCNAME. dnl But don't add it dnl 1. if it's the standard /usr/include, dnl 2. if it's /usr/local/include and we are using GCC on Linux, dnl 3. if it's already present in $CPPFLAGS or the already dnl constructed $INCNAME, dnl 4. if it doesn't exist as a directory. if test "X$additional_includedir" != "X/usr/include"; then haveit= if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then for x in $CPPFLAGS $INC[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_includedir"; then dnl Really add $additional_includedir to $INCNAME. INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir" fi fi fi fi fi dnl Look for dependencies. if test -n "$found_la"; then dnl Read the .la file. It defines the variables dnl dlname, library_names, old_library, dependency_libs, current, dnl age, revision, installed, dlopen, dlpreopen, libdir. saved_libdir="$libdir" case "$found_la" in */* | *\\*) . "$found_la" ;; *) . "./$found_la" ;; esac libdir="$saved_libdir" dnl We use only dependency_libs. for dep in $dependency_libs; do case "$dep" in -L*) dependency_libdir=`echo "X$dep" | sed -e 's/^X-L//'` dnl Potentially add $dependency_libdir to $LIBNAME and $LTLIBNAME. dnl But don't add it dnl 1. if it's the standard /usr/lib, dnl 2. if it's /usr/local/lib and we are using GCC on Linux, dnl 3. if it's already present in $LDFLAGS or the already dnl constructed $LIBNAME, dnl 4. if it doesn't exist as a directory. if test "X$dependency_libdir" != "X/usr/$acl_libdirstem" \ && test "X$dependency_libdir" != "X/usr/$acl_libdirstem2" \ && test "X$dependency_libdir" != "X/usr/$acl_libdirstem3"; then haveit= if test "X$dependency_libdir" = "X/usr/local/$acl_libdirstem" \ || test "X$dependency_libdir" = "X/usr/local/$acl_libdirstem2" \ || test "X$dependency_libdir" = "X/usr/local/$acl_libdirstem3"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then haveit= for x in $LDFLAGS $LIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$dependency_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$dependency_libdir"; then dnl Really add $dependency_libdir to $LIBNAME. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$dependency_libdir" fi fi haveit= for x in $LDFLAGS $LTLIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$dependency_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$dependency_libdir"; then dnl Really add $dependency_libdir to $LTLIBNAME. LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$dependency_libdir" fi fi fi fi ;; -R*) dir=`echo "X$dep" | sed -e 's/^X-R//'` if test "$enable_rpath" != no; then dnl Potentially add DIR to rpathdirs. dnl The rpathdirs will be appended to $LIBNAME at the end. haveit= for x in $rpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $dir" fi dnl Potentially add DIR to ltrpathdirs. dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. haveit= for x in $ltrpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $dir" fi fi ;; -l*) dnl Handle this in the next round. dnl But on GNU systems, ignore -lc options, because dnl - linking with libc is the default anyway, dnl - linking with libc.a may produce an error dnl "/usr/bin/ld: dynamic STT_GNU_IFUNC symbol `strcmp' with pointer equality in `/usr/lib/libc.a(strcmp.o)' can not be used when making an executable; recompile with -fPIE and relink with -pie" dnl or may produce an executable that always crashes, see dnl . dep=`echo "X$dep" | sed -e 's/^X-l//'` if test "X$dep" != Xc \ || case $host_os in linux* | gnu* | k*bsd*-gnu) false ;; *) true ;; esac; then names_next_round="$names_next_round $dep" fi ;; *.la) dnl Handle this in the next round. Throw away the .la's dnl directory; it is already contained in a preceding -L dnl option. names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` ;; *) dnl Most likely an immediate library name. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep" LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep" ;; esac done fi else dnl Didn't find the library; assume it is in the system directories dnl known to the linker and runtime loader. (All the system dnl directories known to the linker should also be known to the dnl runtime loader, otherwise the system is severely misconfigured.) LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name" fi fi fi done done if test "X$rpathdirs" != "X"; then if test -n "$acl_hardcode_libdir_separator"; then dnl Weird platform: only the last -rpath option counts, the user must dnl pass all path elements in one option. We can arrange that for a dnl single library, but not when more than one $LIBNAMEs are used. alldirs= for found_dir in $rpathdirs; do alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir" done dnl Note: acl_hardcode_libdir_flag_spec uses $libdir and $wl. acl_saved_libdir="$libdir" libdir="$alldirs" eval flag=\"$acl_hardcode_libdir_flag_spec\" libdir="$acl_saved_libdir" LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" else dnl The -rpath options are cumulative. for found_dir in $rpathdirs; do acl_saved_libdir="$libdir" libdir="$found_dir" eval flag=\"$acl_hardcode_libdir_flag_spec\" libdir="$acl_saved_libdir" LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" done fi fi if test "X$ltrpathdirs" != "X"; then dnl When using libtool, the option that works for both libraries and dnl executables is -R. The -R options are cumulative. for found_dir in $ltrpathdirs; do LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir" done fi popdef([PACKLIBS]) popdef([PACKUP]) popdef([PACK]) popdef([NAME]) ]) dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR, dnl unless already present in VAR. dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes dnl contains two or three consecutive elements that belong together. AC_DEFUN([AC_LIB_APPENDTOVAR], [ for element in [$2]; do haveit= for x in $[$1]; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X$element"; then haveit=yes break fi done if test -z "$haveit"; then [$1]="${[$1]}${[$1]:+ }$element" fi done ]) dnl For those cases where a variable contains several -L and -l options dnl referring to unknown libraries and directories, this macro determines the dnl necessary additional linker options for the runtime path. dnl AC_LIB_LINKFLAGS_FROM_LIBS([LDADDVAR], [LIBSVALUE], [USE-LIBTOOL]) dnl sets LDADDVAR to linker options needed together with LIBSVALUE. dnl If USE-LIBTOOL evaluates to non-empty, linking with libtool is assumed, dnl otherwise linking without libtool is assumed. AC_DEFUN([AC_LIB_LINKFLAGS_FROM_LIBS], [ AC_REQUIRE([AC_LIB_RPATH]) AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) $1= if test "$enable_rpath" != no; then if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then dnl Use an explicit option to hardcode directories into the resulting dnl binary. rpathdirs= next= for opt in $2; do if test -n "$next"; then dir="$next" dnl No need to hardcode the standard /usr/lib. if test "X$dir" != "X/usr/$acl_libdirstem" \ && test "X$dir" != "X/usr/$acl_libdirstem2" \ && test "X$dir" != "X/usr/$acl_libdirstem3"; then rpathdirs="$rpathdirs $dir" fi next= else case $opt in -L) next=yes ;; -L*) dir=`echo "X$opt" | sed -e 's,^X-L,,'` dnl No need to hardcode the standard /usr/lib. if test "X$dir" != "X/usr/$acl_libdirstem" \ && test "X$dir" != "X/usr/$acl_libdirstem2" \ && test "X$dir" != "X/usr/$acl_libdirstem3"; then rpathdirs="$rpathdirs $dir" fi next= ;; *) next= ;; esac fi done if test "X$rpathdirs" != "X"; then if test -n ""$3""; then dnl libtool is used for linking. Use -R options. for dir in $rpathdirs; do $1="${$1}${$1:+ }-R$dir" done else dnl The linker is used for linking directly. if test -n "$acl_hardcode_libdir_separator"; then dnl Weird platform: only the last -rpath option counts, the user dnl must pass all path elements in one option. alldirs= for dir in $rpathdirs; do alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$dir" done acl_saved_libdir="$libdir" libdir="$alldirs" eval flag=\"$acl_hardcode_libdir_flag_spec\" libdir="$acl_saved_libdir" $1="$flag" else dnl The -rpath options are cumulative. for dir in $rpathdirs; do acl_saved_libdir="$libdir" libdir="$dir" eval flag=\"$acl_hardcode_libdir_flag_spec\" libdir="$acl_saved_libdir" $1="${$1}${$1:+ }$flag" done fi fi fi fi fi AC_SUBST([$1]) ]) cdrdao-cdrdao-f00afb2/m4/lib-prefix.m4000066400000000000000000000304461511453746600175300ustar00rootroot00000000000000# lib-prefix.m4 # serial 23 dnl Copyright (C) 2001-2005, 2008-2024 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl This file is offered as-is, without any warranty. dnl From Bruno Haible. dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed dnl to access previously installed libraries. The basic assumption is that dnl a user will want packages to use other packages he previously installed dnl with the same --prefix option. dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate dnl libraries, but is otherwise very convenient. AC_DEFUN([AC_LIB_PREFIX], [ AC_BEFORE([$0], [AC_LIB_LINKFLAGS]) AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) dnl By default, look in $includedir and $libdir. use_additional=yes AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) AC_ARG_WITH([lib-prefix], [[ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib --without-lib-prefix don't search for libraries in includedir and libdir]], [ if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) else additional_includedir="$withval/include" additional_libdir="$withval/$acl_libdirstem" fi fi ]) if test $use_additional = yes; then dnl Potentially add $additional_includedir to $CPPFLAGS. dnl But don't add it dnl 1. if it's the standard /usr/include, dnl 2. if it's already present in $CPPFLAGS, dnl 3. if it's /usr/local/include and we are using GCC on Linux, dnl 4. if it doesn't exist as a directory. if test "X$additional_includedir" != "X/usr/include"; then haveit= for x in $CPPFLAGS; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then if test -d "$additional_includedir"; then dnl Really add $additional_includedir to $CPPFLAGS. CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir" fi fi fi fi dnl Potentially add $additional_libdir to $LDFLAGS. dnl But don't add it dnl 1. if it's the standard /usr/lib, dnl 2. if it's already present in $LDFLAGS, dnl 3. if it's /usr/local/lib and we are using GCC on Linux, dnl 4. if it doesn't exist as a directory. if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then haveit= for x in $LDFLAGS; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then if test -n "$GCC"; then case $host_os in linux*) haveit=yes;; esac fi fi if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LDFLAGS. LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir" fi fi fi fi fi ]) dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix, dnl acl_final_exec_prefix, containing the values to which $prefix and dnl $exec_prefix will expand at the end of the configure script. AC_DEFUN([AC_LIB_PREPARE_PREFIX], [ dnl Unfortunately, prefix and exec_prefix get only finally determined dnl at the end of configure. if test "X$prefix" = "XNONE"; then acl_final_prefix="$ac_default_prefix" else acl_final_prefix="$prefix" fi if test "X$exec_prefix" = "XNONE"; then acl_final_exec_prefix='${prefix}' else acl_final_exec_prefix="$exec_prefix" fi acl_saved_prefix="$prefix" prefix="$acl_final_prefix" eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" prefix="$acl_saved_prefix" ]) dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the dnl variables prefix and exec_prefix bound to the values they will have dnl at the end of the configure script. AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX], [ acl_saved_prefix="$prefix" prefix="$acl_final_prefix" acl_saved_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" $1 exec_prefix="$acl_saved_exec_prefix" prefix="$acl_saved_prefix" ]) dnl AC_LIB_PREPARE_MULTILIB creates dnl - a function acl_is_expected_elfclass, that tests whether standard input dn; has a 32-bit or 64-bit ELF header, depending on the host CPU ABI, dnl - 3 variables acl_libdirstem, acl_libdirstem2, acl_libdirstem3, containing dnl the basename of the libdir to try in turn, either "lib" or "lib64" or dnl "lib/64" or "lib32" or "lib/sparcv9" or "lib/amd64" or similar. AC_DEFUN([AC_LIB_PREPARE_MULTILIB], [ dnl There is no formal standard regarding lib, lib32, and lib64. dnl On most glibc systems, the current practice is that on a system supporting dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under dnl $prefix/lib64 and 32-bit libraries go under $prefix/lib. However, on dnl Arch Linux based distributions, it's the opposite: 32-bit libraries go dnl under $prefix/lib32 and 64-bit libraries go under $prefix/lib. dnl We determine the compiler's default mode by looking at the compiler's dnl library search path. If at least one of its elements ends in /lib64 or dnl points to a directory whose absolute pathname ends in /lib64, we use that dnl for 64-bit ABIs. Similarly for 32-bit ABIs. Otherwise we use the default, dnl namely "lib". dnl On Solaris systems, the current practice is that on a system supporting dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under dnl $prefix/lib/64 (which is a symlink to either $prefix/lib/sparcv9 or dnl $prefix/lib/amd64) and 32-bit libraries go under $prefix/lib. AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([gl_HOST_CPU_C_ABI_32BIT]) AC_CACHE_CHECK([for ELF binary format], [gl_cv_elf], [AC_EGREP_CPP([Extensible Linking Format], [#if defined __ELF__ || (defined __linux__ && (defined __EDG__ || defined __SUNPRO_C)) Extensible Linking Format #endif ], [gl_cv_elf=yes], [gl_cv_elf=no]) ]) if test $gl_cv_elf = yes; then # Extract the ELF class of a file (5th byte) in decimal. # Cf. https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header if od -A x < /dev/null >/dev/null 2>/dev/null; then # Use POSIX od. func_elfclass () { od -A n -t d1 -j 4 -N 1 } else # Use BSD hexdump. func_elfclass () { dd bs=1 count=1 skip=4 2>/dev/null | hexdump -e '1/1 "%3d "' echo } fi # Use 'expr', not 'test', to compare the values of func_elfclass, because on # Solaris 11 OpenIndiana and Solaris 11 OmniOS, the result is 001 or 002, # not 1 or 2. changequote(,)dnl case $HOST_CPU_C_ABI_32BIT in yes) # 32-bit ABI. acl_is_expected_elfclass () { expr "`func_elfclass | sed -e 's/[ ]//g'`" = 1 > /dev/null } ;; no) # 64-bit ABI. acl_is_expected_elfclass () { expr "`func_elfclass | sed -e 's/[ ]//g'`" = 2 > /dev/null } ;; *) # Unknown. acl_is_expected_elfclass () { : } ;; esac changequote([,])dnl else acl_is_expected_elfclass () { : } fi dnl Allow the user to override the result by setting acl_cv_libdirstems. AC_CACHE_CHECK([for the common suffixes of directories in the library search path], [acl_cv_libdirstems], [dnl Try 'lib' first, because that's the default for libdir in GNU, see dnl . acl_libdirstem=lib acl_libdirstem2= acl_libdirstem3= case "$host_os" in solaris*) dnl See Solaris 10 Software Developer Collection > Solaris 64-bit Developer's Guide > The Development Environment dnl . dnl "Portable Makefiles should refer to any library directories using the 64 symbolic link." dnl But we want to recognize the sparcv9 or amd64 subdirectory also if the dnl symlink is missing, so we set acl_libdirstem2 too. if test $HOST_CPU_C_ABI_32BIT = no; then acl_libdirstem2=lib/64 case "$host_cpu" in sparc*) acl_libdirstem3=lib/sparcv9 ;; i*86 | x86_64) acl_libdirstem3=lib/amd64 ;; esac fi ;; netbsd*) dnl On NetBSD/sparc64, there is a 'sparc' subdirectory that contains dnl 32-bit libraries. if test $HOST_CPU_C_ABI_32BIT != no; then case "$host_cpu" in sparc*) acl_libdirstem2=lib/sparc ;; esac fi ;; *) dnl If $CC generates code for a 32-bit ABI, the libraries are dnl surely under $prefix/lib or $prefix/lib32, not $prefix/lib64. dnl Similarly, if $CC generates code for a 64-bit ABI, the libraries dnl are surely under $prefix/lib or $prefix/lib64, not $prefix/lib32. dnl Find the compiler's search path. However, non-system compilers dnl sometimes have odd library search paths. But we can't simply invoke dnl '/usr/bin/gcc -print-search-dirs' because that would not take into dnl account the -m32/-m31 or -m64 options from the $CC or $CFLAGS. searchpath=`(LC_ALL=C $CC $CPPFLAGS $CFLAGS -print-search-dirs) 2>/dev/null \ | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` if test $HOST_CPU_C_ABI_32BIT != no; then # 32-bit or unknown ABI. if test -d /usr/lib32; then acl_libdirstem2=lib32 fi fi if test $HOST_CPU_C_ABI_32BIT != yes; then # 64-bit or unknown ABI. if test -d /usr/lib64; then acl_libdirstem3=lib64 fi fi if test -n "$searchpath"; then acl_saved_IFS="${IFS= }"; IFS=":" for searchdir in $searchpath; do if test -d "$searchdir"; then case "$searchdir" in */lib32/ | */lib32 ) acl_libdirstem2=lib32 ;; */lib64/ | */lib64 ) acl_libdirstem3=lib64 ;; */../ | */.. ) # Better ignore directories of this form. They are misleading. ;; *) searchdir=`cd "$searchdir" && pwd` case "$searchdir" in */lib32 ) acl_libdirstem2=lib32 ;; */lib64 ) acl_libdirstem3=lib64 ;; esac ;; esac fi done IFS="$acl_saved_IFS" if test $HOST_CPU_C_ABI_32BIT = yes; then # 32-bit ABI. acl_libdirstem3= fi if test $HOST_CPU_C_ABI_32BIT = no; then # 64-bit ABI. acl_libdirstem2= fi fi ;; esac test -n "$acl_libdirstem2" || acl_libdirstem2="$acl_libdirstem" test -n "$acl_libdirstem3" || acl_libdirstem3="$acl_libdirstem" acl_cv_libdirstems="$acl_libdirstem,$acl_libdirstem2,$acl_libdirstem3" ]) dnl Decompose acl_cv_libdirstems into acl_libdirstem, acl_libdirstem2, and dnl acl_libdirstem3. changequote(,)dnl acl_libdirstem=`echo "$acl_cv_libdirstems" | sed -e 's/,.*//'` acl_libdirstem2=`echo "$acl_cv_libdirstems" | sed -e 's/^[^,]*,//' -e 's/,.*//'` acl_libdirstem3=`echo "$acl_cv_libdirstems" | sed -e 's/^[^,]*,[^,]*,//' -e 's/,.*//'` changequote([,])dnl ]) cdrdao-cdrdao-f00afb2/m4/pkg.m4000066400000000000000000000305761511453746600162540ustar00rootroot00000000000000# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # serial 11 (pkg-config-0.29.1) dnl Copyright Ā© 2004 Scott James Remnant . dnl Copyright Ā© 2012-2015 Dan Nicholson dnl dnl This program is free software; you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by dnl the Free Software Foundation; either version 2 of the License, or dnl (at your option) any later version. dnl dnl This program is distributed in the hope that it will be useful, but dnl WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program; if not, write to the Free Software dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA dnl 02111-1307, USA. dnl dnl As a special exception to the GNU General Public License, if you dnl distribute this file as part of a program that contains a dnl configuration script generated by Autoconf, you may include it under dnl the same distribution terms that you use for the rest of that dnl program. dnl PKG_PREREQ(MIN-VERSION) dnl ----------------------- dnl Since: 0.29 dnl dnl Verify that the version of the pkg-config macros are at least dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's dnl installed version of pkg-config, this checks the developer's version dnl of pkg.m4 when generating configure. dnl dnl To ensure that this macro is defined, also add: dnl m4_ifndef([PKG_PREREQ], dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) dnl dnl See the "Since" comment for each macro you use to see what version dnl of the macros you require. m4_defun([PKG_PREREQ], [m4_define([PKG_MACROS_VERSION], [0.29.1]) m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) ])dnl PKG_PREREQ dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) dnl ---------------------------------- dnl Since: 0.16 dnl dnl Search for the pkg-config tool and set the PKG_CONFIG variable to dnl first found in the path. Checks that the version of pkg-config found dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is dnl used since that's the first version where most current features of dnl pkg-config existed. AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])dnl PKG_PROG_PKG_CONFIG dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------------------------------- dnl Since: 0.18 dnl dnl Check to see whether a particular set of modules exists. Similar to dnl PKG_CHECK_MODULES(), but does not set variables or print errors. dnl dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) dnl only at the first occurence in configure.ac, so if the first place dnl it's called might be skipped (such as if it is within an "if", you dnl have to call PKG_CHECK_EXISTS manually AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) dnl --------------------------------------------- dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting dnl pkg_failed based on the result. m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])dnl _PKG_CONFIG dnl _PKG_SHORT_ERRORS_SUPPORTED dnl --------------------------- dnl Internal check to see if pkg-config supports short errors. AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])dnl _PKG_SHORT_ERRORS_SUPPORTED dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl -------------------------------------------------------------- dnl Since: 0.4.0 dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES might not happen, you should be sure to include an dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $1]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])[]dnl ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])dnl PKG_CHECK_MODULES dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl --------------------------------------------------------------------- dnl Since: 0.29 dnl dnl Checks for existence of MODULES and gathers its build flags with dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags dnl and VARIABLE-PREFIX_LIBS from --libs. dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to dnl include an explicit call to PKG_PROG_PKG_CONFIG in your dnl configure.ac. AC_DEFUN([PKG_CHECK_MODULES_STATIC], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl _save_PKG_CONFIG=$PKG_CONFIG PKG_CONFIG="$PKG_CONFIG --static" PKG_CHECK_MODULES($@) PKG_CONFIG=$_save_PKG_CONFIG[]dnl ])dnl PKG_CHECK_MODULES_STATIC dnl PKG_INSTALLDIR([DIRECTORY]) dnl ------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable pkgconfigdir as the location where a module dnl should install pkg-config .pc files. By default the directory is dnl $libdir/pkgconfig, but the default can be changed by passing dnl DIRECTORY. The user can override through the --with-pkgconfigdir dnl parameter. AC_DEFUN([PKG_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([pkgconfigdir], [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, [with_pkgconfigdir=]pkg_default) AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_INSTALLDIR dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) dnl -------------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable noarch_pkgconfigdir as the location where a dnl module should install arch-independent pkg-config .pc files. By dnl default the directory is $datadir/pkgconfig, but the default can be dnl changed by passing DIRECTORY. The user can override through the dnl --with-noarch-pkgconfigdir parameter. AC_DEFUN([PKG_NOARCH_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([noarch-pkgconfigdir], [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, [with_noarch_pkgconfigdir=]pkg_default) AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_NOARCH_INSTALLDIR dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------- dnl Since: 0.28 dnl dnl Retrieves the value of the pkg-config variable for the given module. AC_DEFUN([PKG_CHECK_VAR], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl _PKG_CONFIG([$1], [variable="][$3]["], [$2]) AS_VAR_COPY([$1], [pkg_cv_][$1]) AS_VAR_IF([$1], [""], [$5], [$4])dnl ])dnl PKG_CHECK_VAR dnl PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND], dnl [DESCRIPTION], [DEFAULT]) dnl ------------------------------------------ dnl dnl Prepare a "--with-" configure option using the lowercase dnl [VARIABLE-PREFIX] name, merging the behaviour of AC_ARG_WITH and dnl PKG_CHECK_MODULES in a single macro. AC_DEFUN([PKG_WITH_MODULES], [ m4_pushdef([with_arg], m4_tolower([$1])) m4_pushdef([description], [m4_default([$5], [build with ]with_arg[ support])]) m4_pushdef([def_arg], [m4_default([$6], [auto])]) m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes]) m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no]) m4_case(def_arg, [yes],[m4_pushdef([with_without], [--without-]with_arg)], [m4_pushdef([with_without],[--with-]with_arg)]) AC_ARG_WITH(with_arg, AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),, [AS_TR_SH([with_]with_arg)=def_arg]) AS_CASE([$AS_TR_SH([with_]with_arg)], [yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)], [auto],[PKG_CHECK_MODULES([$1],[$2], [m4_n([def_action_if_found]) $3], [m4_n([def_action_if_not_found]) $4])]) m4_popdef([with_arg]) m4_popdef([description]) m4_popdef([def_arg]) ])dnl PKG_WITH_MODULES dnl PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [DESCRIPTION], [DEFAULT]) dnl ----------------------------------------------- dnl dnl Convenience macro to trigger AM_CONDITIONAL after PKG_WITH_MODULES dnl check._[VARIABLE-PREFIX] is exported as make variable. AC_DEFUN([PKG_HAVE_WITH_MODULES], [ PKG_WITH_MODULES([$1],[$2],,,[$3],[$4]) AM_CONDITIONAL([HAVE_][$1], [test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"]) ])dnl PKG_HAVE_WITH_MODULES dnl PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [DESCRIPTION], [DEFAULT]) dnl ------------------------------------------------------ dnl dnl Convenience macro to run AM_CONDITIONAL and AC_DEFINE after dnl PKG_WITH_MODULES check. HAVE_[VARIABLE-PREFIX] is exported as make dnl and preprocessor variable. AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES], [ PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4]) AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"], [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])]) ])dnl PKG_HAVE_DEFINE_WITH_MODULES cdrdao-cdrdao-f00afb2/missing000077500000000000000000000170601511453746600163010ustar00rootroot00000000000000#! /bin/sh # Common wrapper for a few potentially missing GNU and other programs. scriptversion=2024-06-07.14; # UTC # shellcheck disable=SC2006,SC2268 # we must support pre-POSIX shells # Copyright (C) 1996-2024 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # 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, 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, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try '$0 --help' for more information" exit 1 fi case $1 in --is-lightweight) # Used by our autoconf macros to check whether the available missing # script is modern enough. exit 0 ;; --run) # Back-compat with the calling convention used by older automake. shift ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due to PROGRAM being missing or too old. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal autoconf autogen autoheader autom4te automake autoreconf bison flex help2man lex makeinfo perl yacc Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. Report bugs to . GNU Automake home page: . General help using GNU software: ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing (GNU Automake) $scriptversion" exit $? ;; -*) echo 1>&2 "$0: unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac # Run the given program, remember its exit status. "$@"; st=$? # If it succeeded, we are done. test $st -eq 0 && exit 0 # Also exit now if we it failed (or wasn't found), and '--version' was # passed; such an option is passed most likely to detect whether the # program is present and works. case $2 in --version|--help) exit $st;; esac # Exit code 63 means version mismatch. This often happens when the user # tries to use an ancient version of a tool on a file that requires a # minimum version. if test $st -eq 63; then msg="probably too old" elif test $st -eq 127; then # Program was missing. msg="missing on your system" else # Program was found and executed, but failed. Give up. exit $st fi perl_URL=https://www.perl.org/ flex_URL=https://github.com/westes/flex gnu_software_URL=https://www.gnu.org/software program_details () { case $1 in aclocal|automake|autoreconf) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/autoconf>" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; autoconf|autom4te|autoheader) echo "The '$1' program is part of the GNU Autoconf package:" echo "<$gnu_software_URL/autoconf/>" echo "It also requires GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; *) : ;; esac } give_advice () { # Normalize program name to check for. normalized_program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" autoheader_deps="'acconfig.h'" automake_deps="'Makefile.am'" aclocal_deps="'acinclude.m4'" case $normalized_program in aclocal*) echo "You should only need it if you modified $aclocal_deps or" echo "$configure_deps." ;; autoconf*) echo "You should only need it if you modified $configure_deps." ;; autogen*) echo "You should only need it if you modified a '.def' or '.tpl' file." echo "You may want to install the GNU AutoGen package:" echo "<$gnu_software_URL/autogen/>" ;; autoheader*) echo "You should only need it if you modified $autoheader_deps or" echo "$configure_deps." ;; automake*) echo "You should only need it if you modified $automake_deps or" echo "$configure_deps." ;; autom4te*) echo "You might have modified some maintainer files that require" echo "the 'autom4te' program to be rebuilt." ;; autoreconf*) echo "You should only need it if you modified $aclocal_deps or" echo "$automake_deps or $autoheader_deps or $automake_deps or" echo "$configure_deps." ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; lex*|flex*) echo "You should only need it if you modified a '.l' file." echo "You may want to install the Fast Lexical Analyzer package:" echo "<$flex_URL>" ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." echo "You might want to install the Texinfo package:" echo "<$gnu_software_URL/texinfo/>" echo "The spurious makeinfo call might also be the consequence of" echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; perl*) echo "You should only need it to run GNU Autoconf, GNU Automake, " echo " assorted other tools, or if you modified a Perl source file." echo "You may want to install the Perl 5 language interpreter:" echo "<$perl_URL>" ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" echo "often tells you about the needed prerequisites for installing" echo "this package. You may also peek at any GNU archive site, in" echo "case some other package contains this missing '$1' program." ;; esac program_details "$normalized_program" } give_advice "$1" | sed -e '1s/^/WARNING: /' \ -e '2,$s/^/ /' >&2 # Propagate the correct exit status (expected to be 127 for a program # not found, 63 for a program that failed due to version mismatch). exit $st # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: cdrdao-cdrdao-f00afb2/mkinstalldirs000077500000000000000000000071141511453746600175070ustar00rootroot00000000000000#! /bin/sh # mkinstalldirs --- make directory hierarchy scriptversion=2024-06-19.01; # UTC # Original author: Noah Friedman # Created: 1993-05-16 # Public domain. # # This file is maintained in Automake, please report # bugs to or send patches to # . nl=' ' IFS=" "" $nl" errstatus=0 dirmode= usage="\ Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ... Create each directory DIR (with mode MODE, if specified), including all leading file name components. Report bugs to . GNU Automake home page: . General help using GNU software: ." # process command line arguments while test $# -gt 0 ; do case $1 in -h | --help | --h*) # -h for help echo "$usage" exit $? ;; -m) # -m PERM arg shift test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } dirmode=$1 shift ;; --version) echo "$0 (GNU Automake) $scriptversion" exit $? ;; --) # stop option processing shift break ;; -*) # unknown option echo "$usage" 1>&2 exit 1 ;; *) # first non-opt arg break ;; esac done for file do if test -d "$file"; then shift else break fi done case $# in 0) exit 0 ;; esac # Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and # mkdir -p a/c at the same time, both will detect that a is missing, # one will create a, then the other will try to create a and die with # a "File exists" error. This is a problem when calling mkinstalldirs # from a parallel make. We use --version in the probe to restrict # ourselves to GNU mkdir, which is thread-safe. case $dirmode in '') if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then echo "mkdir -p -- $*" exec mkdir -p -- "$@" else # On NextStep and OpenStep, the 'mkdir' command does not # recognize any option. It will interpret all options as # directories to create, and then abort because '.' already # exists. test -d ./-p && rmdir ./-p test -d ./--version && rmdir ./--version fi ;; *) if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 && test ! -d ./--version; then echo "umask 22" umask 22 echo "mkdir -m $dirmode -p -- $*" exec mkdir -m "$dirmode" -p -- "$@" else # Clean up after NextStep and OpenStep mkdir. for d in ./-m ./-p ./--version "./$dirmode"; do test -d $d && rmdir $d done fi ;; esac echo "umask 22" umask 22 for file do case $file in /*) pathcomp=/ ;; *) pathcomp= ;; esac oIFS=$IFS IFS=/ set fnord $file shift IFS=$oIFS for d do test "x$d" = x && continue pathcomp=$pathcomp$d case $pathcomp in -*) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" mkdir "$pathcomp" || lasterr=$? if test ! -d "$pathcomp"; then errstatus=$lasterr fi fi pathcomp=$pathcomp/ done if test ! -z "$dirmode"; then echo "chmod $dirmode $file" chmod "$dirmode" "$file" || errstatus=$? fi done exit $errstatus # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: cdrdao-cdrdao-f00afb2/paranoia/000077500000000000000000000000001511453746600164705ustar00rootroot00000000000000cdrdao-cdrdao-f00afb2/paranoia/.cvsignore000066400000000000000000000000331511453746600204640ustar00rootroot00000000000000Makefile Makefile.in .deps cdrdao-cdrdao-f00afb2/paranoia/Makefile.am000066400000000000000000000002431511453746600205230ustar00rootroot00000000000000noinst_LIBRARIES = libcdda_paranoia.a libcdda_paranoia_a_SOURCES = paranoia.c p_block.c overlap.c gap.c isort.c cdda_paranoia.h gap.h isort.h overlap.h p_block.h cdrdao-cdrdao-f00afb2/paranoia/README000066400000000000000000000013151511453746600173500ustar00rootroot00000000000000This is Monty's paranoia library that allows high quality digital audio extraction even with scratched CDs. It is taken from the cdparanoia-III-alpha9.8 package. Changes: - Provided my own version of the 'cdrom_drive' structure and changed the include path for "cdda_interface.h". It is now located in "dao/cdda_interface.h". - Removed include of "../interface/smallft.h" because nothing from it was used. - Commented out the functions 'i_paranoia_firstlast()' and 'paranoia_seek()' to reduce the required cdda interface functions. Now only 'cdda_read()' is referenced by the library. - Added function 'paranoia_set_range()' to set the valid range of audio sectors. cdrdao-cdrdao-f00afb2/paranoia/cdda_paranoia.h000066400000000000000000000031561511453746600214130ustar00rootroot00000000000000/*** * CopyPolicy: GNU Public License 2 applies * Copyright (C) by Monty (xiphmont@mit.edu) * ***/ #ifndef _CDROM_PARANOIA_ #define _CDROM_PARANOIA_ #define CD_FRAMEWORDS (CD_FRAMESIZE_RAW/2) #define PARANOIA_CB_READ 0 #define PARANOIA_CB_VERIFY 1 #define PARANOIA_CB_FIXUP_EDGE 2 #define PARANOIA_CB_FIXUP_ATOM 3 #define PARANOIA_CB_SCRATCH 4 #define PARANOIA_CB_REPAIR 5 #define PARANOIA_CB_SKIP 6 #define PARANOIA_CB_DRIFT 7 #define PARANOIA_CB_BACKOFF 8 #define PARANOIA_CB_OVERLAP 9 #define PARANOIA_CB_FIXUP_DROPPED 10 #define PARANOIA_CB_FIXUP_DUPED 11 #define PARANOIA_CB_READERR 12 #define PARANOIA_MODE_FULL 0xff #define PARANOIA_MODE_DISABLE 0 #define PARANOIA_MODE_VERIFY 1 #define PARANOIA_MODE_FRAGMENT 2 #define PARANOIA_MODE_OVERLAP 4 #define PARANOIA_MODE_SCRATCH 8 #define PARANOIA_MODE_REPAIR 16 #define PARANOIA_MODE_NEVERSKIP 32 #ifndef CDP_COMPILE typedef void cdrom_paranoia; #endif #ifdef __cplusplus extern "C" { #endif extern cdrom_paranoia *paranoia_init(cdrom_drive *d); extern void paranoia_modeset(cdrom_paranoia *p,int mode); extern long paranoia_seek(cdrom_paranoia *p,long seek,int mode); extern int16_t *paranoia_read(cdrom_paranoia *p,void(*callback)(long,int)); extern int16_t *paranoia_read_limited(cdrom_paranoia *p,void(*callback)(long,int),int maxretries); extern void paranoia_free(cdrom_paranoia *p); extern void paranoia_overlapset(cdrom_paranoia *p,long overlap); extern void paranoia_set_range(cdrom_paranoia *p, long start, long end); #ifdef __cplusplus } #endif #endif cdrdao-cdrdao-f00afb2/paranoia/gap.c000066400000000000000000000101401511453746600173770ustar00rootroot00000000000000/*** * CopyPolicy: GNU Public License 2 applies * Copyright (C) by Monty (xiphmont@mit.edu) * * Gapa analysis support code for paranoia * ***/ #include #include "p_block.h" #include "cdda_paranoia.h" #include "gap.h" /**** Gap analysis code ***************************************************/ long i_paranoia_overlap_r(int16_t *buffA,int16_t *buffB, long offsetA, long offsetB){ long beginA=offsetA; long beginB=offsetB; for(;beginA>=0 && beginB>=0;beginA--,beginB--) if(buffA[beginA]!=buffB[beginB])break; beginA++; beginB++; return(offsetA-beginA); } long i_paranoia_overlap_f(int16_t *buffA,int16_t *buffB, long offsetA, long offsetB, long sizeA,long sizeB){ long endA=offsetA; long endB=offsetB; for(;endA or <- */ void i_analyze_rift_f(int16_t *A,int16_t *B, long sizeA, long sizeB, long aoffset, long boffset, long *matchA,long *matchB,long *matchC){ long apast=sizeA-aoffset; long bpast=sizeB-boffset; long i; *matchA=0, *matchB=0, *matchC=0; /* Look for three possible matches... (A) Ariftv->B, (B) Briftv->A and (c) AB->AB. */ for(i=0;;i++){ if(i=MIN_WORDS_RIFT){ *matchA=i; break; } if(i=MIN_WORDS_RIFT){ *matchB=i; break; } if(i=MIN_WORDS_RIFT){ *matchC=i; break; } }else if(i>=bpast)break; } if(*matchA==0 && *matchB==0 && *matchC==0)return; if(*matchC)return; if(*matchA){ if(i_stutter_or_gap(A,B,aoffset-*matchA,boffset,*matchA)) return; *matchB=-*matchA; /* signify we need to remove n bytes from B */ *matchA=0; return; }else{ if(i_stutter_or_gap(B,A,boffset-*matchB,aoffset,*matchB)) return; *matchA=-*matchB; *matchB=0; return; } } /* riftv must be first even val of rift moving back */ void i_analyze_rift_r(int16_t *A,int16_t *B, long sizeA, long sizeB, long aoffset, long boffset, long *matchA,long *matchB,long *matchC){ long apast=aoffset+1; long bpast=boffset+1; long i; *matchA=0, *matchB=0, *matchC=0; /* Look for three possible matches... (A) Ariftv->B, (B) Briftv->A and (c) AB->AB. */ for(i=0;;i++){ if(i=MIN_WORDS_RIFT){ *matchA=i; break; } if(i=MIN_WORDS_RIFT){ *matchB=i; break; } if(i=MIN_WORDS_RIFT){ *matchC=i; break; } }else if(i>=bpast)break; } if(*matchA==0 && *matchB==0 && *matchC==0)return; if(*matchC)return; if(*matchA){ if(i_stutter_or_gap(A,B,aoffset+1,boffset-*matchA+1,*matchA)) return; *matchB=-*matchA; /* signify we need to remove n bytes from B */ *matchA=0; return; }else{ if(i_stutter_or_gap(B,A,boffset+1,aoffset-*matchB+1,*matchB)) return; *matchA=-*matchB; *matchB=0; return; } } void analyze_rift_silence_f(int16_t *A,int16_t *B,long sizeA,long sizeB, long aoffset, long boffset, long *matchA, long *matchB){ *matchA=-1; *matchB=-1; sizeA=prna_min(sizeA,aoffset+MIN_WORDS_RIFT); sizeB=prna_min(sizeB,boffset+MIN_WORDS_RIFT); aoffset++; boffset++; while(aoffset #include #include "p_block.h" #include "isort.h" sort_info *sort_alloc(long size){ sort_info *ret=calloc(1,sizeof(sort_info)); ret->vector=NULL; ret->sortbegin=-1; ret->size=-1; ret->maxsize=size; ret->head=calloc(65536,sizeof(sort_link *)); ret->bucketusage=malloc(65536*sizeof(long)); ret->revindex=calloc(size,sizeof(sort_link)); ret->lastbucket=0; return(ret); } void sort_unsortall(sort_info *i){ if(i->lastbucket>2000){ /* a guess */ memset(i->head,0,65536*sizeof(sort_link *)); }else{ long b; for(b=0;blastbucket;b++) i->head[i->bucketusage[b]]=NULL; } i->lastbucket=0; i->sortbegin=-1; } void sort_free(sort_info *i){ free(i->revindex); free(i->head); free(i->bucketusage); free(i); } static void sort_sort(sort_info *i,long sortlo,long sorthi){ long j; for(j=sorthi-1;j>=sortlo;j--){ sort_link **hv=i->head+i->vector[j]+32768; sort_link *l=i->revindex+j; if(*hv==NULL){ i->bucketusage[i->lastbucket]=i->vector[j]+32768; i->lastbucket++; } l->next=*hv; *hv=l; } i->sortbegin=0; } /* size *must* be less than i->maxsize */ void sort_setup(sort_info *i,int16_t *vector,long *abspos, long size,long sortlo,long sorthi){ if(i->sortbegin!=-1)sort_unsortall(i); i->vector=vector; i->size=size; i->abspos=abspos; i->lo=prna_min(size,prna_max(sortlo-*abspos,0)); i->hi=prna_max(0,prna_min(sorthi-*abspos,size)); } sort_link *sort_getmatch(sort_info *i,long post,long overlap,int value){ sort_link *ret; if(i->sortbegin==-1)sort_sort(i,i->lo,i->hi); /* Now we reuse lo and hi */ post=prna_max(0,prna_min(i->size,post)); i->val=value+32768; i->lo=prna_max(0,post-overlap); /* absolute position */ i->hi=prna_min(i->size,post+overlap); /* absolute position */ ret=i->head[i->val]; while(ret){ if(ipos(i,ret)lo){ ret=ret->next; }else{ if(ipos(i,ret)>=i->hi) ret=NULL; break; } } /*i->head[i->val]=ret;*/ return(ret); } sort_link *sort_nextmatch(sort_info *i,sort_link *prev){ sort_link *ret=prev->next; if(!ret || ipos(i,ret)>=i->hi)return(NULL); return(ret); } cdrdao-cdrdao-f00afb2/paranoia/isort.h000066400000000000000000000026201511453746600200010ustar00rootroot00000000000000/*** * CopyPolicy: GNU Public License 2 applies * Copyright (C) by Monty (xiphmont@mit.edu) ***/ #ifndef _ISORT_H_ #define _ISORT_H_ #include typedef struct sort_link{ struct sort_link *next; } sort_link; typedef struct sort_info{ int16_t *vector; /* vector (storage doesn't belong to us) */ long *abspos; /* pointer for side effects */ long size; /* vector size */ long maxsize; /* maximum vector size */ long sortbegin; /* range of contiguous sorted area */ long lo,hi; /* current post, overlap range */ int val; /* ...and val */ /* sort structs */ sort_link **head; /* sort buckets (65536) */ long *bucketusage; /* of used buckets (65536) */ long lastbucket; sort_link *revindex; } sort_info; extern sort_info *sort_alloc(long size); extern void sort_unsortall(sort_info *i); extern void sort_setup(sort_info *i,int16_t *vector,long *abspos,long size, long sortlo, long sorthi); extern void sort_free(sort_info *i); extern sort_link *sort_getmatch(sort_info *i,long post,long overlap,int value); extern sort_link *sort_nextmatch(sort_info *i,sort_link *prev); #define is(i) (i->size) #define ib(i) (*i->abspos) #define ie(i) (i->size+*i->abspos) #define iv(i) (i->vector) #define ipos(i,l) (l-i->revindex) #endif cdrdao-cdrdao-f00afb2/paranoia/overlap.c000066400000000000000000000102421511453746600203030ustar00rootroot00000000000000/*** * CopyPolicy: GNU Public License 2 applies * Copyright (C) by Monty (xiphmont@mit.edu) * * Statistic code and cache management for overlap settings * ***/ #include #include #include #include "p_block.h" #include "cdda_paranoia.h" #include "overlap.h" #include "isort.h" /**** Internal cache management *****************************************/ void paranoia_resetcache(cdrom_paranoia *p){ c_block *c=c_first(p); v_fragment *v; while(c){ free_c_block(c); c=c_first(p); } v=v_first(p); while(v){ free_v_fragment(v); v=v_first(p); } } void paranoia_resetall(cdrom_paranoia *p){ p->root.returnedlimit=0; p->dyndrift=0; p->root.lastsector=0; if(p->root.vector){ i_cblock_destructor(p->root.vector); p->root.vector=NULL; } paranoia_resetcache(p); } void i_paranoia_trim(cdrom_paranoia *p,long beginword,long endword){ root_block *root=&(p->root); if(root->vector!=NULL){ long target=beginword-MAX_SECTOR_OVERLAP*CD_FRAMEWORDS; long rbegin=cb(root->vector); long rend=ce(root->vector); if(rbegin>beginword) goto rootfree; if(rbegin+MAX_SECTOR_OVERLAP*CD_FRAMEWORDSrend) goto rootfree; { long offset=target-rbegin; c_removef(root->vector,offset); } } { c_block *c=c_first(p); while(c){ c_block *next=c_next(c); if(ce(c)vector); root->vector=NULL; root->returnedlimit=-1; root->lastsector=0; } /**** Statistical and heuristic[al? :-] management ************************/ void offset_adjust_settings(cdrom_paranoia *p, void(*callback)(long,int)){ if(p->stage2.offpoints>=10){ /* drift: look at the average offset value. If it's over one sector, frob it. We just want a little hysteresis [sp?]*/ long av=(p->stage2.offpoints?p->stage2.offaccum/p->stage2.offpoints:0); if(labs(av)>p->dynoverlap/4){ av=(av/MIN_SECTOR_EPSILON)*MIN_SECTOR_EPSILON; if(callback)(*callback)(ce(p->root.vector),PARANOIA_CB_DRIFT); p->dyndrift+=av; /* Adjust all the values in the cache otherwise we get a (potentially unstable) feedback loop */ { c_block *c=c_first(p); v_fragment *v=v_first(p); while(v && v->one){ /* safeguard beginning bounds case with a hammer */ if(fb(v)one)one=NULL; }else{ fb(v)-=av; } v=v_next(v); } while(c){ long adj=prna_min(av,cb(c)); c_set(c,cb(c)-adj); c=c_next(c); } } p->stage2.offaccum=0; p->stage2.offmin=0; p->stage2.offmax=0; p->stage2.offpoints=0; p->stage2.newpoints=0; p->stage2.offdiff=0; } } if(p->stage1.offpoints>=10){ /* dynoverlap: we arbitrarily set it to 4x the running difference value, unless min/max are more */ p->dynoverlap=(p->stage1.offpoints?p->stage1.offdiff/ p->stage1.offpoints*3:CD_FRAMEWORDS); if(p->dynoverlap<-p->stage1.offmin*1.5) p->dynoverlap=-p->stage1.offmin*1.5; if(p->dynoverlapstage1.offmax*1.5) p->dynoverlap=p->stage1.offmax*1.5; if(p->dynoverlapdynoverlap=MIN_SECTOR_EPSILON; if(p->dynoverlap>MAX_SECTOR_OVERLAP*CD_FRAMEWORDS) p->dynoverlap=MAX_SECTOR_OVERLAP*CD_FRAMEWORDS; if(callback)(*callback)(p->dynoverlap,PARANOIA_CB_OVERLAP); if(p->stage1.offpoints>600){ /* bit of a bug; this routine is called too often due to the overlap mesh alg we use in stage 1 */ p->stage1.offpoints/=1.2; p->stage1.offaccum/=1.2; p->stage1.offdiff/=1.2; } p->stage1.offmin=0; p->stage1.offmax=0; p->stage1.newpoints=0; } } void offset_add_value(cdrom_paranoia *p,offsets *o,long value, void(*callback)(long,int)){ if(o->offpoints!=-1){ o->offdiff+=labs(value); o->offpoints++; o->newpoints++; o->offaccum+=value; if(valueoffmin)o->offmin=value; if(value>o->offmax)o->offmax=value; if(o->newpoints>=10)offset_adjust_settings(p,callback); } } cdrdao-cdrdao-f00afb2/paranoia/overlap.h000066400000000000000000000010731511453746600203120ustar00rootroot00000000000000/*** * CopyPolicy: GNU Public License 2 applies * Copyright (C) by Monty (xiphmont@mit.edu) ***/ #ifndef _OVERLAP_H_ #define _OVERLAP_H_ extern void offset_add_value(cdrom_paranoia *p,offsets *o,long value, void(*callback)(long,int)); extern void offset_clear_settings(offsets *o); extern void offset_adjust_settings(cdrom_paranoia *p, void(*callback)(long,int)); extern void i_paranoia_trim(cdrom_paranoia *p,long beginword,long endword); extern void paranoia_resetall(cdrom_paranoia *p); extern void paranoia_resetcache(cdrom_paranoia *p); #endif cdrdao-cdrdao-f00afb2/paranoia/overlapdef.txt000066400000000000000000000003731511453746600213630ustar00rootroot00000000000000 0 70 100 A |----------|-----| B |-----|---------| 0 40 100 offset=-30 begin=30 end=100 0 70 100 A |----------|-----| B |-----|---------| 50 90 150 offset=20 begin=30 end=100 cdrdao-cdrdao-f00afb2/paranoia/p_block.c000066400000000000000000000157001511453746600202500ustar00rootroot00000000000000#include #include #include #include #include "p_block.h" #include "../dao/cdda_interface.h" #include "cdda_paranoia.h" linked_list *new_list(void *(*newp)(void),void (*freep)(void *)){ linked_list *ret=calloc(1,sizeof(linked_list)); ret->new_poly=newp; ret->free_poly=freep; return(ret); } linked_element *add_elem(linked_list *l,void *elem){ linked_element *ret=calloc(1,sizeof(linked_element)); ret->stamp=l->current++; ret->ptr=elem; ret->list=l; if(l->head) l->head->prev=ret; else l->tail=ret; ret->next=l->head; ret->prev=NULL; l->head=ret; l->active++; return(ret); } linked_element *new_elem(linked_list *list){ void *new=list->new_poly(); return(add_elem(list,new)); } void free_elem(linked_element *e,int free_ptr){ linked_list *l=e->list; if(free_ptr)l->free_poly(e->ptr); if(e==l->head) l->head=e->next; if(e==l->tail) l->tail=e->prev; if(e->prev) e->prev->next=e->next; if(e->next) e->next->prev=e->prev; l->active--; free(e); } void free_list(linked_list *list,int free_ptr){ while(list->head) free_elem(list->head,free_ptr); free(list); } void *get_elem(linked_element *e){ return(e->ptr); } linked_list *copy_list(linked_list *list){ linked_list *new=new_list(list->new_poly,list->free_poly); linked_element *i=list->tail; while(i){ add_elem(new,i->ptr); i=i->prev; } return(new); } /**** C_block stuff ******************************************************/ static c_block *i_cblock_constructor(cdrom_paranoia *p){ c_block *ret=calloc(1,sizeof(c_block)); return(ret); } void i_cblock_destructor(c_block *c){ if(c){ if(c->vector)free(c->vector); if(c->flags)free(c->flags); c->e=NULL; free(c); } } c_block *new_c_block(cdrom_paranoia *p){ linked_element *e=new_elem(p->cache); c_block *c=e->ptr; c->e=e; c->p=p; return(c); } void free_c_block(c_block *c){ /* also rid ourselves of v_fragments that reference this block */ v_fragment *v=v_first(c->p); while(v){ v_fragment *next=v_next(v); if(v->one==c)free_v_fragment(v); v=next; } free_elem(c->e,1); } static v_fragment *i_vfragment_constructor(void){ v_fragment *ret=calloc(1,sizeof(v_fragment)); return(ret); } static void i_v_fragment_destructor(v_fragment *v){ free(v); } v_fragment *new_v_fragment(cdrom_paranoia *p,c_block *one, long begin, long end, int last){ linked_element *e=new_elem(p->fragments); v_fragment *b=e->ptr; b->e=e; b->p=p; b->one=one; b->begin=begin; b->vector=one->vector+begin-one->begin; b->size=end-begin; b->lastsector=last; return(b); } void free_v_fragment(v_fragment *v){ free_elem(v->e,1); } c_block *c_first(cdrom_paranoia *p){ if(p->cache->head) return(p->cache->head->ptr); return(NULL); } c_block *c_last(cdrom_paranoia *p){ if(p->cache->tail) return(p->cache->tail->ptr); return(NULL); } c_block *c_next(c_block *c){ if(c->e->next) return(c->e->next->ptr); return(NULL); } c_block *c_prev(c_block *c){ if(c->e->prev) return(c->e->prev->ptr); return(NULL); } v_fragment *v_first(cdrom_paranoia *p){ if(p->fragments->head){ return(p->fragments->head->ptr); } return(NULL); } v_fragment *v_last(cdrom_paranoia *p){ if(p->fragments->tail) return(p->fragments->tail->ptr); return(NULL); } v_fragment *v_next(v_fragment *v){ if(v->e->next) return(v->e->next->ptr); return(NULL); } v_fragment *v_prev(v_fragment *v){ if(v->e->prev) return(v->e->prev->ptr); return(NULL); } void recover_cache(cdrom_paranoia *p){ linked_list *l=p->cache; /* Are we at/over our allowed cache size? */ while(l->active>p->cache_limit) /* cull from the tail of the list */ free_c_block(c_last(p)); } int16_t *v_buffer(v_fragment *v){ if(!v->one)return(NULL); if(!cv(v->one))return(NULL); return(v->vector); } /* alloc a c_block not on a cache list */ c_block *c_alloc(int16_t *vector,long begin,long size){ c_block *c=calloc(1,sizeof(c_block)); c->vector=vector; c->begin=begin; c->size=size; return(c); } void c_set(c_block *v,long begin){ v->begin=begin; } /* pos here is vector position from zero */ void c_insert(c_block *v,long pos,int16_t *b,long size){ int vs=cs(v); if(pos<0 || pos>vs)return; if(v->vector) v->vector=realloc(v->vector,sizeof(int16_t)*(size+vs)); else v->vector=malloc(sizeof(int16_t)*size); if(posvector+pos+size,v->vector+pos, (vs-pos)*sizeof(int16_t)); memcpy(v->vector+pos,b,size*sizeof(int16_t)); v->size+=size; } void c_remove(c_block *v,long cutpos,long cutsize){ int vs=cs(v); if(cutpos<0 || cutpos>vs)return; if(cutpos+cutsize>vs)cutsize=vs-cutpos; if(cutsize<0)cutsize=vs-cutpos; if(cutsize<1)return; memmove(v->vector+cutpos,v->vector+cutpos+cutsize, (vs-cutpos-cutsize)*sizeof(int16_t)); v->size-=cutsize; } void c_overwrite(c_block *v,long pos,int16_t *b,long size){ int vs=cs(v); if(pos<0)return; if(pos+size>vs)size=vs-pos; memcpy(v->vector+pos,b,size*sizeof(int16_t)); } void c_append(c_block *v, int16_t *vector, long size){ int vs=cs(v); /* update the vector */ if(v->vector) v->vector=realloc(v->vector,sizeof(int16_t)*(size+vs)); else v->vector=malloc(sizeof(int16_t)*size); memcpy(v->vector+vs,vector,sizeof(int16_t)*size); v->size+=size; } void c_removef(c_block *v, long cut){ c_remove(v,0,cut); v->begin+=cut; } /**** Initialization *************************************************/ /* void i_paranoia_firstlast(cdrom_paranoia *p){ int i; cdrom_drive *d=p->d; p->current_lastsector=-1; for(i=cdda_sector_gettrack(d,p->cursor);icurrent_lastsector=cdda_track_lastsector(d,i-1); if(p->current_lastsector==-1) p->current_lastsector=cdda_disc_lastsector(d); p->current_firstsector=-1; for(i=cdda_sector_gettrack(d,p->cursor);i>0;i--) if(!cdda_track_audiop(d,i)) p->current_firstsector=cdda_track_firstsector(d,i+1); if(p->current_firstsector==-1) p->current_firstsector=cdda_disc_firstsector(d); } */ cdrom_paranoia *paranoia_init(cdrom_drive *d){ cdrom_paranoia *p=calloc(1,sizeof(cdrom_paranoia)); p->cache=new_list((void *)&i_cblock_constructor, (void *)&i_cblock_destructor); p->fragments=new_list((void *)&i_vfragment_constructor, (void *)&i_v_fragment_destructor); p->readahead=150; p->sortcache=sort_alloc(p->readahead*CD_FRAMEWORDS); p->d=d; p->dynoverlap=MAX_SECTOR_OVERLAP*CD_FRAMEWORDS; p->cache_limit=JIGGLE_MODULO; p->enable=PARANOIA_MODE_FULL; /*p->cursor=cdda_disc_firstsector(d);*/ p->lastread=LONG_MAX; /* One last one... in case data and audio tracks are mixed... */ /* i_paranoia_firstlast(p); ++AM: I use paranoia_set_range instead */ return(p); } void paranoia_set_range(cdrom_paranoia *p, long start, long end) { p->cursor = start; p->current_firstsector = start; p->current_lastsector = end; } cdrdao-cdrdao-f00afb2/paranoia/p_block.h000066400000000000000000000113051511453746600202520ustar00rootroot00000000000000/*** * CopyPolicy: GNU Public License 2 applies * Copyright (C) by Monty (xiphmont@mit.edu) ***/ #ifndef _p_block_h_ #define _p_block_h_ #include "../dao/cdda_interface.h" #define MIN_WORDS_OVERLAP 64 /* 16 bit words */ #define MIN_WORDS_SEARCH 64 /* 16 bit words */ #define MIN_WORDS_RIFT 16 /* 16 bit words */ #define MAX_SECTOR_OVERLAP 32 /* sectors */ #define MIN_SECTOR_EPSILON 128 /* words */ #define MIN_SECTOR_BACKUP 16 /* sectors */ #define JIGGLE_MODULO 15 /* sectors */ #define MIN_SILENCE_BOUNDARY 1024 /* 16 bit words */ #define prna_min(x,y) ((x)>(y)?(y):(x)) #define prna_max(x,y) ((x)<(y)?(y):(x)) #include "isort.h" typedef struct linked_list{ /* linked list */ struct linked_element *head; struct linked_element *tail; void *(*new_poly)(); void (*free_poly)(void *poly); long current; long active; } linked_list; typedef struct linked_element{ void *ptr; struct linked_element *prev; struct linked_element *next; struct linked_list *list; int stamp; } linked_element; extern linked_list *new_list(void *(*new)(void),void (*free)(void *)); extern linked_element *new_elem(linked_list *list); extern linked_element *add_elem(linked_list *list,void *elem); extern void free_list(linked_list *list,int free_ptr); /* unlink or free */ extern void free_elem(linked_element *e,int free_ptr); /* unlink or free */ extern void *get_elem(linked_element *e); extern linked_list *copy_list(linked_list *list); /* shallow; doesn't copy contained structures */ typedef struct c_block{ /* The buffer */ int16_t *vector; long begin; long size; /* auxiliary support structures */ unsigned char *flags; /* 1 known boundaries in read data 2 known blanked data 4 matched sample 8 reserved 16 reserved 32 reserved 64 reserved 128 reserved */ /* end of session cases */ long lastsector; struct cdrom_paranoia *p; struct linked_element *e; } c_block; extern void free_c_block(c_block *c); extern void i_cblock_destructor(c_block *c); extern c_block *new_c_block(struct cdrom_paranoia *p); typedef struct v_fragment{ c_block *one; long begin; long size; int16_t *vector; /* end of session cases */ long lastsector; /* linked list */ struct cdrom_paranoia *p; struct linked_element *e; } v_fragment; extern void free_v_fragment(v_fragment *c); extern v_fragment *new_v_fragment(struct cdrom_paranoia *p,c_block *one, long begin, long end, int lastsector); extern int16_t *v_buffer(v_fragment *v); extern c_block *c_first(struct cdrom_paranoia *p); extern c_block *c_last(struct cdrom_paranoia *p); extern c_block *c_next(c_block *c); extern c_block *c_prev(c_block *c); extern v_fragment *v_first(struct cdrom_paranoia *p); extern v_fragment *v_last(struct cdrom_paranoia *p); extern v_fragment *v_next(v_fragment *v); extern v_fragment *v_prev(v_fragment *v); typedef struct root_block{ long returnedlimit; long lastsector; struct cdrom_paranoia *p; c_block *vector; /* doesn't use any sorting */ int silenceflag; long silencebegin; } root_block; typedef struct offsets{ long offpoints; long newpoints; long offaccum; long offdiff; long offmin; long offmax; } offsets; typedef struct cdrom_paranoia{ cdrom_drive *d; root_block root; /* verified/reconstructed cached data */ linked_list *cache; /* our data as read from the cdrom */ long cache_limit; linked_list *fragments; /* fragments of blocks that have been 'verified' */ sort_info *sortcache; int readahead; /* sectors of readahead in each readop */ int jitter; long lastread; int enable; long cursor; long current_lastsector; long current_firstsector; /* statistics for drift/overlap */ struct offsets stage1; struct offsets stage2; long dynoverlap; long dyndrift; /* statistics for verification */ } cdrom_paranoia; extern c_block *c_alloc(int16_t *vector,long begin,long size); extern void c_set(c_block *v,long begin); extern void c_insert(c_block *v,long pos,int16_t *b,long size); extern void c_remove(c_block *v,long cutpos,long cutsize); extern void c_overwrite(c_block *v,long pos,int16_t *b,long size); extern void c_append(c_block *v, int16_t *vector, long size); extern void c_removef(c_block *v, long cut); #define ce(v) (v->begin+v->size) #define cb(v) (v->begin) #define cs(v) (v->size) /* pos here is vector position from zero */ extern void recover_cache(cdrom_paranoia *p); extern void i_paranoia_firstlast(cdrom_paranoia *p); #define cv(c) (c->vector) #define fe(f) (f->begin+f->size) #define fb(f) (f->begin) #define fs(f) (f->size) #define fv(f) (v_buffer(f)) #define CDP_COMPILE #endif cdrdao-cdrdao-f00afb2/paranoia/paranoia.c000066400000000000000000001040551511453746600204330ustar00rootroot00000000000000/*** * CopyPolicy: GNU Public License 2 applies * Copyright (C) by Monty (xiphmont@mit.edu) * * Toplevel file for the paranoia abstraction over the cdda lib * ***/ /* immediate todo:: */ /* Allow disabling of root fixups? */ /* Dupe bytes are creeping into cases that require greater overlap than a single fragment can provide. We need to check against a larger area* (+/-32 sectors of root?) to better eliminate dupes. Of course this leads to other problems... Is it actually a practically solvable problem? */ /* Bimodal overlap distributions break us. */ /* scratch detection/tolerance not implemented yet */ /*************************************************************** Da new shtick: verification now a two-step assymetric process. A single 'verified/reconstructed' data segment cache, and then the multiple fragment cache verify a newly read block against previous blocks; do it only this once. We maintain a list of 'verified sections' from these matches. We then glom these verified areas into a new data buffer. Defragmentation fixups are allowed here alone. We also now track where read boundaries actually happened; do not verify across matching boundaries. **************************************************************/ /*************************************************************** Silence. "It's BAAAAAAaaack." audio is now treated as great continents of values floating on a mantle of molten silence. Silence is not handled by basic verification at all; we simply anchor sections of nonzero audio to a position and fill in everything else as silence. We also note the audio that interfaces with silence; an edge must be 'wet'. **************************************************************/ #include #include #include #include #include #include "../dao/cdda_interface.h" #include "p_block.h" #include "cdda_paranoia.h" #include "overlap.h" #include "gap.h" #include "isort.h" static inline long re(root_block *root){ if(!root)return(-1); if(!root->vector)return(-1); return(ce(root->vector)); } static inline long rb(root_block *root){ if(!root)return(-1); if(!root->vector)return(-1); return(cb(root->vector)); } static inline long rs(root_block *root){ if(!root)return(-1); if(!root->vector)return(-1); return(cs(root->vector)); } static inline int16_t *rv(root_block *root){ if(!root)return(NULL); if(!root->vector)return(NULL); return(cv(root->vector)); } #define rc(r) (r->vector) /**** matching and analysis code *****************************************/ static inline long i_paranoia_overlap(int16_t *buffA,int16_t *buffB, long offsetA, long offsetB, long sizeA,long sizeB, long *ret_begin, long *ret_end){ long beginA=offsetA,endA=offsetA; long beginB=offsetB,endB=offsetB; for(;beginA>=0 && beginB>=0;beginA--,beginB--) if(buffA[beginA]!=buffB[beginB])break; beginA++; beginB++; for(;endA=0 && beginB>=0;beginA--,beginB--){ if(buffA[beginA]!=buffB[beginB])break; /* don't allow matching across matching sector boundaries */ /* don't allow matching through known missing data */ if((flagsA[beginA]&flagsB[beginB]&1)){ beginA--; beginB--; break; } if((flagsA[beginA]&2)|| (flagsB[beginB]&2))break; } beginA++; beginB++; for(;endAflags; long ret=0; if(flagB==NULL) ret=i_paranoia_overlap(cv(A),iv(B),posA,posB, cs(A),is(B),begin,end); else if((flagB[posB]&2)==0) ret=i_paranoia_overlap2(cv(A),iv(B),flagA,flagB,posA,posB,cs(A), is(B),begin,end); if(ret>MIN_WORDS_SEARCH){ *offset=+(posA+cb(A))-(posB+ib(B)); *begin+=cb(A); *end+=cb(A); return(ret); } return(0); } /* post is w.r.t. B. in stage one, we post from old. In stage 2 we post from root. Begin, end, offset count from B's frame of reference */ static inline long try_sort_sync(cdrom_paranoia *p, sort_info *A,char *Aflags, c_block *B, long post,long *begin,long *end, long *offset,void (*callback)(long,int)){ long dynoverlap=p->dynoverlap; sort_link *ptr=NULL; char *Bflags=(char*)B->flags; /* block flag matches 0x02 (unmatchable) */ if(Bflags==NULL || (Bflags[post-cb(B)]&2)==0){ /* always try absolute offset zero first! */ { long zeropos=post-ib(A); if(zeropos>=0 && zeroposstage1),*offset,callback); return(1); } } } } }else return(0); ptr=sort_getmatch(A,post-ib(A),dynoverlap,cv(B)[post-cb(B)]); while(ptr){ if(do_const_sync(B,A,Aflags, post-cb(B),ipos(A,ptr), begin,end,offset)){ offset_add_value(p,&(p->stage1),*offset,callback); return(1); } ptr=sort_nextmatch(A,ptr); } *begin=-1; *end=-1; *offset=-1; return(0); } static inline void stage1_matched(c_block *old,c_block *new, long matchbegin,long matchend, long matchoffset,void (*callback)(long,int)){ long i; long oldadjbegin=matchbegin-cb(old); long oldadjend=matchend-cb(old); long newadjbegin=matchbegin-matchoffset-cb(new); long newadjend=matchend-matchoffset-cb(new); if(matchbegin-matchoffset<=cb(new) || matchbegin<=cb(old) || (new->flags[newadjbegin]&1) || (old->flags[oldadjbegin]&1)){ if(matchoffset) if(callback)(*callback)(matchbegin,PARANOIA_CB_FIXUP_EDGE); }else if(callback)(*callback)(matchbegin,PARANOIA_CB_FIXUP_ATOM); if(matchend-matchoffset>=ce(new) || (new->flags[newadjend]&1) || matchend>=ce(old) || (old->flags[oldadjend]&1)){ if(matchoffset) if(callback)(*callback)(matchend,PARANOIA_CB_FIXUP_EDGE); }else if(callback)(*callback)(matchend,PARANOIA_CB_FIXUP_ATOM); /* Mark the verification flags. Don't mark the first or last OVERLAP/2 elements so that overlapping fragments have to overlap by OVERLAP to actually merge. We also remove elements from the sort such that later sorts do not have to sift through already matched data */ newadjbegin+=OVERLAP_ADJ; newadjend-=OVERLAP_ADJ; for(i=newadjbegin;iflags[i]|=4; /* mark verified */ oldadjbegin+=OVERLAP_ADJ; oldadjend-=OVERLAP_ADJ; for(i=oldadjbegin;iflags[i]|=4; /* mark verified */ } static long i_iterate_stage1(cdrom_paranoia *p,c_block *old,c_block *new, void(*callback)(long,int)){ long matchbegin=-1,matchend=-1,matchoffset; /* we no longer try to spread the stage one search area by dynoverlap */ long searchend=prna_min(ce(old),ce(new)); long searchbegin=prna_max(cb(old),cb(new)); long searchsize=searchend-searchbegin; sort_info *i=p->sortcache; long ret=0; long j; long tried=0,matched=0; if(searchsize<=0)return(0); /* match return values are in terms of the new vector, not old */ for(j=searchbegin;jflags[j-cb(new)]&6)==0){ tried++; if(try_sort_sync(p,i,(char*)new->flags,old,j,&matchbegin,&matchend,&matchoffset, callback)==1){ matched+=matchend-matchbegin; /* purely cosmetic: if we're matching zeros, don't use the callback because they will appear to be all skewed */ { long j=matchbegin-cb(old); long end=matchend-cb(old); for(;jj)j=matchend-1; } } } #ifdef NOISY fprintf(stderr,"iterate_stage1: search area=%ld[%ld-%ld] tried=%ld matched=%ld spans=%ld\n", searchsize,searchbegin,searchend,tried,matched,ret); #endif return(ret); } static long i_stage1(cdrom_paranoia *p,c_block *new, void(*callback)(long,int)){ long size=cs(new); c_block *ptr=c_last(p); int ret=0; long begin=0,end; if(ptr)sort_setup(p->sortcache,cv(new),&cb(new),cs(new), cb(new),ce(new)); while(ptr && ptr!=new){ if(callback)(*callback)(cb(new),PARANOIA_CB_VERIFY); i_iterate_stage1(p,ptr,new,callback); ptr=c_prev(ptr); } /* parse the verified areas of new into v_fragments */ begin=0; while(beginflags[begin]&4)break; for(end=begin;endflags[end]&4)==0)break; if(begin>=size)break; ret++; new_v_fragment(p,new,cb(new)+prna_max(0,begin-OVERLAP_ADJ), cb(new)+prna_min(size,end+OVERLAP_ADJ), (end+OVERLAP_ADJ>=size && new->lastsector)); begin=end; } return(ret); } /* reconcile v_fragments to root buffer. Free if matched, fragment/fixup root if necessary */ typedef struct sync_result { long offset; long begin; long end; } sync_result; /* do *not* match using zero posts */ static long i_iterate_stage2(cdrom_paranoia *p,v_fragment *v, sync_result *r,void(*callback)(long,int)){ root_block *root=&(p->root); long matchbegin=-1,matchend=-1,offset; long fbv,fev; #ifdef NOISY fprintf(stderr,"Stage 2 search: fbv=%ld fev=%ld\n",fb(v),fe(v)); #endif if(prna_min(fe(v)+p->dynoverlap,re(root))- prna_max(fb(v)-p->dynoverlap,rb(root))<=0)return(0); if(callback)(*callback)(fb(v),PARANOIA_CB_VERIFY); /* just a bit of v; determine the correct area */ fbv=prna_max(fb(v),rb(root)-p->dynoverlap); /* we want to avoid zeroes */ while(fbvdynoverlap),fe(v)); { /* spread the search area a bit. We post from root, so containment must strictly adhere to root */ long searchend=prna_min(fev+p->dynoverlap,re(root)); long searchbegin=prna_max(fbv-p->dynoverlap,rb(root)); sort_info *i=p->sortcache; long j; sort_setup(i,fv(v),&fb(v),fs(v),fbv,fev); for(j=searchbegin;jbegin=matchbegin; r->end=matchend; r->offset=-offset; if(offset)if(callback)(*callback)(r->begin,PARANOIA_CB_FIXUP_EDGE); return(1); } } } return(0); } /* simple test for a root vector that ends in silence*/ static void i_silence_test(root_block *root){ int16_t *vec=rv(root); long end=re(root)-rb(root)-1; long j; for(j=end-1;j>=0;j--)if(vec[j]!=0)break; if(j<0 || end-j>MIN_SILENCE_BOUNDARY){ if(j<0)j=0; root->silenceflag=1; root->silencebegin=rb(root)+j; if(root->silencebeginreturnedlimit) root->silencebegin=root->returnedlimit; } } /* match into silence vectors at offset zero if at all possible. This also must be called with vectors in ascending begin order in case there are nonzero islands */ static long i_silence_match(root_block *root, v_fragment *v, void(*callback)(long,int)){ cdrom_paranoia *p=v->p; int16_t *vec=fv(v); long end=fs(v),begin; long j; /* does this vector begin wet? */ if(enddynoverlap? */ if(fb(v)>=re(root) && fb(v)-p->dynoverlapsilencebegin); end=prna_min(j,re(root)); if(beginre(root)){ long voff=begin-fb(v); c_remove(rc(root),begin-rb(root),-1); c_append(rc(root),vec+voff,fs(v)-voff); } offset_add_value(p,&p->stage2,0,callback); }else{ if(jre(root)){ c_remove(rc(root),root->silencebegin-rb(root),-1); c_append(rc(root),vec+voff,fs(v)-voff); } offset_add_value(p,&p->stage2,end-begin,callback); }else return(0); } /* test the new root vector for ending in silence */ root->silenceflag=0; i_silence_test(root); if(v->lastsector)root->lastsector=1; free_v_fragment(v); return(1); } static long i_stage2_each(root_block *root, v_fragment *v, void(*callback)(long,int)){ cdrom_paranoia *p=v->p; long dynoverlap=p->dynoverlap/2*2; if(!v || !v->one)return(0); if(!rv(root)){ return(0); }else{ sync_result r; if(i_iterate_stage2(p,v,&r,callback)){ long begin=r.begin-rb(root); long end=r.end-rb(root); long offset=r.begin+r.offset-fb(v)-begin; long temp; c_block *l=NULL; /* we have a match! We don't rematch off rift, we chase the match all the way to both extremes doing rift analysis. */ #ifdef NOISY fprintf(stderr,"Stage 2 match\n"); #endif /* chase backward */ /* note that we don't extend back right now, only forward. */ while((begin+offset>0 && begin>0)){ long matchA=0,matchB=0,matchC=0; long beginL=begin+offset; if(l==NULL){ int16_t *buff=malloc(fs(v)*sizeof(int16_t)); l=c_alloc(buff,fb(v),fs(v)); memcpy(buff,fv(v),fs(v)*sizeof(int16_t)); } i_analyze_rift_r(rv(root),cv(l), rs(root),cs(l), begin-1,beginL-1, &matchA,&matchB,&matchC); #ifdef NOISY fprintf(stderr,"matching rootR: matchA:%ld matchB:%ld matchC:%ld\n", matchA,matchB,matchC); #endif if(matchA){ /* a problem with root */ if(matchA>0){ /* dropped bytes; add back from v */ if(callback)(*callback)(begin+rb(root)-1,PARANOIA_CB_FIXUP_DROPPED); if(rb(root)+beginroot.returnedlimit) break; else{ c_insert(rc(root),begin,cv(l)+beginL-matchA, matchA); offset-=matchA; begin+=matchA; end+=matchA; } }else{ /* duplicate bytes; drop from root */ if(callback)(*callback)(begin+rb(root)-1,PARANOIA_CB_FIXUP_DUPED); if(rb(root)+begin+matchAroot.returnedlimit) break; else{ c_remove(rc(root),begin+matchA,-matchA); offset-=matchA; begin+=matchA; end+=matchA; } } }else if(matchB){ /* a problem with the fragment */ if(matchB>0){ /* dropped bytes */ if(callback)(*callback)(begin+rb(root)-1,PARANOIA_CB_FIXUP_DROPPED); c_insert(l,beginL,rv(root)+begin-matchB, matchB); offset+=matchB; }else{ /* duplicate bytes */ if(callback)(*callback)(begin+rb(root)-1,PARANOIA_CB_FIXUP_DUPED); c_remove(l,beginL+matchB,-matchB); offset+=matchB; } }else if(matchC){ /* Uhh... problem with both */ /* Set 'disagree' flags in root */ if(rb(root)+begin-matchCroot.returnedlimit) break; c_overwrite(rc(root),begin-matchC, cv(l)+beginL-matchC,matchC); }else{ /* do we have a mismatch due to silence beginning/end case? */ /* in the 'chase back' case, we don't do anything. */ /* Did not determine nature of difficulty... report and bail */ /*RRR(*callback)(post,PARANOIA_CB_XXX);*/ break; } /* not the most efficient way, but it will do for now */ beginL=begin+offset; i_paranoia_overlap(rv(root),cv(l), begin,beginL, rs(root),cs(l), &begin,&end); } /* chase forward */ temp=l?cs(l):fs(v); while(end+offset0){ /* dropped bytes; add back from v */ if(callback)(*callback)(end+rb(root),PARANOIA_CB_FIXUP_DROPPED); if(end+rb(root)root.returnedlimit) break; c_insert(rc(root),end,cv(l)+endL,matchA); }else{ /* duplicate bytes; drop from root */ if(callback)(*callback)(end+rb(root),PARANOIA_CB_FIXUP_DUPED); if(end+rb(root)root.returnedlimit) break; c_remove(rc(root),end,-matchA); } }else if(matchB){ /* a problem with the fragment */ if(matchB>0){ /* dropped bytes */ if(callback)(*callback)(end+rb(root),PARANOIA_CB_FIXUP_DROPPED); c_insert(l,endL,rv(root)+end,matchB); }else{ /* duplicate bytes */ if(callback)(*callback)(end+rb(root),PARANOIA_CB_FIXUP_DUPED); c_remove(l,endL,-matchB); } }else if(matchC){ /* Uhh... problem with both */ /* Set 'disagree' flags in root */ if(end+rb(root)root.returnedlimit) break; c_overwrite(rc(root),end,cv(l)+endL,matchC); }else{ analyze_rift_silence_f(rv(root),cv(l), rs(root),cs(l), end,endL, &matchA,&matchB); if(matchA){ /* silence in root */ /* Can only do this if we haven't already returned data */ if(end+rb(root)>=p->root.returnedlimit){ c_remove(rc(root),end,-1); } }else if(matchB){ /* silence in fragment; lose it */ if(l)i_cblock_destructor(l); free_v_fragment(v); return(1); }else{ /* Could not determine nature of difficulty... report and bail */ /*RRR(*callback)(post,PARANOIA_CB_XXX);*/ } break; } /* not the most efficient way, but it will do for now */ i_paranoia_overlap(rv(root),cv(l), begin,beginL, rs(root),cs(l), NULL,&end); } /* if this extends our range, let's glom */ { long sizeA=rs(root); long sizeB; long vecbegin; int16_t *vector; if(l){ sizeB=cs(l); vector=cv(l); vecbegin=cb(l); }else{ sizeB=fs(v); vector=fv(v); vecbegin=fb(v); } if(sizeB-offset>sizeA || v->lastsector){ if(v->lastsector){ root->lastsector=1; } if(endstage2,offset+vecbegin-rb(root),callback); } } if(l)i_cblock_destructor(l); free_v_fragment(v); return(1); }else{ /* D'oh. No match. What to do with the fragment? */ if(fe(v)+dynoverlapsilenceflag){ /* It *should* have matched. No good; free it. */ free_v_fragment(v); } /* otherwise, we likely want this for an upcoming match */ /* we don't free the sort info (if it was collected) */ return(0); } } } static int i_init_root(root_block *root, v_fragment *v,long begin, void(*callback)(long,int)){ if(fb(v)<=begin && fe(v)>begin){ root->lastsector=v->lastsector; root->returnedlimit=begin; if(rv(root)){ i_cblock_destructor(rc(root)); rc(root)=NULL; } { int16_t *buff=malloc(fs(v)*sizeof(int16_t)); memcpy(buff,fv(v),fs(v)*sizeof(int16_t)); root->vector=c_alloc(buff,fb(v),fs(v)); } i_silence_test(root); return(1); }else return(0); } static int vsort(const void *a,const void *b){ return((*(v_fragment **)a)->begin-(*(v_fragment **)b)->begin); } static int i_stage2(cdrom_paranoia *p,long beginword,long endword, void(*callback)(long,int)){ int flag=1,ret=0; root_block *root=&(p->root); #ifdef NOISY fprintf(stderr,"Fragments:%ld\n",p->fragments->active); fflush(stderr); #endif /* even when the 'silence flag' is lit, we try to do non-silence matching in the event that there are still audio vectors with content to be sunk before the silence */ while(flag){ /* loop through all the current fragments */ v_fragment *first=v_first(p); long active=p->fragments->active,count=0; v_fragment *list[active]; while(first){ v_fragment *next=v_next(first); list[count++]=first; first=next; } flag=0; if(count){ /* sorted in ascending order of beginning */ qsort(list,active,sizeof(v_fragment *),&vsort); /* we try a nonzero based match even if in silent mode in the case that there are still cached vectors to sink behind continent->ocean boundary */ for(count=0;countone){ if(rv(root)==NULL){ if(i_init_root(&(p->root),first,beginword,callback)){ free_v_fragment(first); flag=1; ret++; } }else{ if(i_stage2_each(root,first,callback)){ ret++; flag=1; } } } } /* silence handling */ if(!flag && p->root.silenceflag){ for(count=0;countone){ if(rv(root)!=NULL){ if(i_silence_match(root,first,callback)){ ret++; flag=1; } } } } } } } return(ret); } static void i_end_case(cdrom_paranoia *p,long endword, void(*callback)(long,int)){ root_block *root=&p->root; /* have an 'end' flag; if we've just read in the last sector in a session, set the flag. If we verify to the end of a fragment which has the end flag set, we're done (set a done flag). Pad zeroes to the end of the read */ if(root->lastsector==0)return; if(endwordroot); c_block *graft=NULL; int vflag=0; int gend=0; long post; #ifdef NOISY fprintf(stderr,"\nskipping\n"); #endif if(rv(root)==NULL){ post=0; }else{ post=re(root); } if(post==-1)post=0; if(callback)(*callback)(post,PARANOIA_CB_SKIP); /* We want to add a sector. Look for a c_block that spans, preferrably a verified area */ { c_block *c=c_first(p); while(c){ long cbegin=cb(c); long cend=ce(c); if(cbegin<=post && cend>post){ long vend=post; if(c->flags[post-cbegin]&4){ /* verified area! */ while(vendflags[vend-cbegin]&4))vend++; if(!vflag || vend>vflag){ graft=c; gend=vend; } vflag=1; }else{ /* not a verified area */ if(!vflag){ while(vendflags[vend-cbegin]&4)==0)vend++; if(graft==NULL || gend>vend){ /* smallest unverified area */ graft=c; gend=vend; } } } } c=c_next(c); } if(graft){ long cbegin=cb(graft); long cend=ce(graft); while(gendflags[gend-cbegin]&4))gend++; gend=prna_min(gend+OVERLAP_ADJ,cend); if(rv(root)==NULL){ int16_t *buff=malloc(cs(graft)); memcpy(buff,cv(graft),cs(graft)); rc(root)=c_alloc(buff,cb(graft),cs(graft)); }else{ c_append(rc(root),cv(graft)+post-cbegin, gend-post); } root->returnedlimit=re(root); return; } } /* No? Fine. Great. Write in some zeroes :-P */ { void *temp=calloc(CD_FRAMESIZE_RAW,sizeof(int16_t)); if(rv(root)==NULL){ rc(root)=c_alloc(temp,post,CD_FRAMESIZE_RAW); }else{ c_append(rc(root),temp,CD_FRAMESIZE_RAW); free(temp); } root->returnedlimit=re(root); } } /**** toplevel ****************************************/ void paranoia_free(cdrom_paranoia *p){ paranoia_resetall(p); sort_free(p->sortcache); free(p); } void paranoia_modeset(cdrom_paranoia *p,int enable){ p->enable=enable; } #if 0 long paranoia_seek(cdrom_paranoia *p,long seek,int mode){ long sector; long ret; switch(mode){ case SEEK_SET: sector=seek; break; case SEEK_END: sector=cdda_disc_lastsector(p->d)+seek; break; default: sector=p->cursor+seek; break; } if(cdda_sector_gettrack(p->d,sector)==-1)return(-1); i_cblock_destructor(p->root.vector); p->root.vector=NULL; p->root.lastsector=0; p->root.returnedlimit=0; ret=p->cursor; p->cursor=sector; i_paranoia_firstlast(p); /* Evil hack to fix pregap patch for NEC drives! To be rooted out in a10 */ p->current_firstsector=sector; return(ret); } #endif /* returns last block read, -1 on error */ c_block *i_read_c_block(cdrom_paranoia *p,long beginword,long endword, void(*callback)(long,int)){ /* why do it this way? We need to read lots of sectors to kludge around stupid read ahead buffers on cheap drives, as well as avoid expensive back-seeking. We also want to 'jiggle' the start address to try to break borderline drives more noticeably (and make broken drives with unaddressable sectors behave more often). */ long readat,firstread; long totaltoread=p->readahead; long sectatonce=p->d->nsectors; long driftcomp=(float)p->dyndrift/CD_FRAMEWORDS+.5; c_block *new=NULL; root_block *root=&p->root; int16_t *buffer=NULL; char *flags=NULL; long sofar; long dynoverlap=(p->dynoverlap+CD_FRAMEWORDS-1)/CD_FRAMEWORDS; long anyflag=0; /* What is the first sector to read? want some pre-buffer if we're not at the extreme beginning of the disc */ if(p->enable&(PARANOIA_MODE_VERIFY|PARANOIA_MODE_OVERLAP)){ /* we want to jitter the read alignment boundary */ long target; if(rv(root)==NULL || rb(root)>beginword) target=p->cursor-dynoverlap; else target=re(root)/(CD_FRAMEWORDS)-dynoverlap; if(target+MIN_SECTOR_BACKUP>p->lastread && target<=p->lastread) target=p->lastread-MIN_SECTOR_BACKUP; /* we want to jitter the read alignment boundary, as some drives, beginning from a specific point, will tend to lose bytes between sectors in the same place. Also, as our vectors are being made up of multiple reads, we want the overlap boundaries to move.... */ readat=(target&(~((long)JIGGLE_MODULO-1)))+p->jitter; if(readat>target)readat-=JIGGLE_MODULO; p->jitter++; if(p->jitter>=JIGGLE_MODULO)p->jitter=0; }else{ readat=p->cursor; } readat+=driftcomp; if(p->enable&(PARANOIA_MODE_OVERLAP|PARANOIA_MODE_VERIFY)){ flags=calloc(totaltoread*CD_FRAMEWORDS,1); new=new_c_block(p); recover_cache(p); }else{ /* in the case of root it's just the buffer */ paranoia_resetall(p); new=new_c_block(p); } buffer=malloc(totaltoread*CD_FRAMESIZE_RAW); sofar=0; firstread=-1; /* actual read loop */ while(sofarcurrent_firstsector){ secread-=p->current_firstsector-adjread; adjread=p->current_firstsector; } if(adjread+secread-1>p->current_lastsector) secread=p->current_lastsector-adjread+1; if(sofar+secread>totaltoread)secread=totaltoread-sofar; if(secread>0){ if(firstread<0)firstread=adjread; if((thisread=cdda_read(p->d,buffer+sofar*CD_FRAMEWORDS,adjread, secread))lastread=adjread+secread; if(adjread+secread-1==p->current_lastsector) new->lastsector=-1; if(callback)(*callback)((adjread+secread-1)*CD_FRAMEWORDS,PARANOIA_CB_READ); sofar+=secread; readat=adjread+secread; }else if(readatcurrent_firstsector) readat+=sectatonce; /* due to being before the readable area */ else break; /* due to being past the readable area */ } if(anyflag){ new->vector=buffer; new->begin=firstread*CD_FRAMEWORDS-p->dyndrift; new->size=sofar*CD_FRAMEWORDS; new->flags=(unsigned char*)flags; }else{ if(new)free_c_block(new); free(buffer); free(flags); new=NULL; } return(new); } /* The returned buffer is *not* to be freed by the caller. It will persist only until the next call to paranoia_read() for this p */ int16_t *paranoia_read(cdrom_paranoia *p, void(*callback)(long,int)){ return paranoia_read_limited(p,callback,20); } /* I added max_retry functionality this way in order to avoid breaking any old apps using the nerw libs. cdparanoia 9.8 will need the updated libs, but nothing else will require it. */ int16_t *paranoia_read_limited(cdrom_paranoia *p, void(*callback)(long,int), int max_retries){ long beginword=p->cursor*(CD_FRAMEWORDS); long endword=beginword+CD_FRAMEWORDS; long retry_count=0,lastend=-2; root_block *root=&p->root; if(beginword>p->root.returnedlimit)p->root.returnedlimit=beginword; lastend=re(root); /* First, is the sector we want already in the root? */ while(rv(root)==NULL || rb(root)>beginword || (re(root)enable&(PARANOIA_MODE_VERIFY|PARANOIA_MODE_OVERLAP)) || re(root)enable&(PARANOIA_MODE_VERIFY|PARANOIA_MODE_OVERLAP)){ i_paranoia_trim(p,beginword,endword); recover_cache(p); if(rb(root)!=-1 && p->root.lastsector) i_end_case(p,endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS), callback); else i_stage2(p,beginword, endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS), callback); }else i_end_case(p,endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS), callback); /* only trips if we're already done */ if(!(rb(root)==-1 || rb(root)>beginword || re(root)enable&(PARANOIA_MODE_OVERLAP|PARANOIA_MODE_VERIFY)){ if(p->enable&PARANOIA_MODE_VERIFY) i_stage1(p,new,callback); else{ /* just make v_fragments from the boundary information. */ long begin=0,end=0; while(beginflags[begin]&1))begin++; end=begin+1; while(endflags[end]&1)==0)end++; { new_v_fragment(p,new,begin+cb(new), end+cb(new), (new->lastsector && cb(new)+end==ce(new))); } begin=end; } } }else{ if(p->root.vector)i_cblock_destructor(p->root.vector); free_elem(new->e,0); p->root.vector=new; i_end_case(p,endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS), callback); } } } /* Are we doing lots of retries? **************************************/ /* Check unaddressable sectors first. There's no backoff here; jiggle and minimum backseek handle that for us */ if(rb(root)!=-1 && lastend+588dynoverlap==MAX_SECTOR_OVERLAP*CD_FRAMEWORDS || retry_count==max_retries){ if(!(p->enable&PARANOIA_MODE_NEVERSKIP))verify_skip_case(p,callback); retry_count=0; }else{ if(p->stage1.offpoints!=-1){ /* hack */ p->dynoverlap*=1.5; if(p->dynoverlap>MAX_SECTOR_OVERLAP*CD_FRAMEWORDS) p->dynoverlap=MAX_SECTOR_OVERLAP*CD_FRAMEWORDS; if(callback)(*callback)(p->dynoverlap,PARANOIA_CB_OVERLAP); } } } } } p->cursor++; return(rv(root)+(beginword-rb(root))); } /* a temporary hack */ void paranoia_overlapset(cdrom_paranoia *p, long overlap){ p->dynoverlap=overlap*CD_FRAMEWORDS; p->stage1.offpoints=-1; } cdrdao-cdrdao-f00afb2/pccts/000077500000000000000000000000001511453746600160125ustar00rootroot00000000000000cdrdao-cdrdao-f00afb2/pccts/.cvsignore000066400000000000000000000000251511453746600200070ustar00rootroot00000000000000Makefile Makefile.in cdrdao-cdrdao-f00afb2/pccts/Makefile.am000066400000000000000000000000441511453746600200440ustar00rootroot00000000000000SUBDIRS = antlr dlg EXTRA_DIST = h cdrdao-cdrdao-f00afb2/pccts/antlr/000077500000000000000000000000001511453746600171325ustar00rootroot00000000000000cdrdao-cdrdao-f00afb2/pccts/antlr/.cvsignore000066400000000000000000000000331511453746600211260ustar00rootroot00000000000000Makefile Makefile.in .deps cdrdao-cdrdao-f00afb2/pccts/antlr/Makefile.am000066400000000000000000000005571511453746600211750ustar00rootroot00000000000000noinst_PROGRAMS = antlr antlr_SOURCES = antlr.c dumpcycles.c err.c fset.c hash.c misc.c scan.c bits.c dumpnode.c fcache.c gen.c lex.c mrhoist.c build.c egman.c fset2.c globals.c main.c pred.c set.c generic.h hash.h mode.h proto.h stdpccts.h syn.h tokens.h AM_CFLAGS = -std=c9x -Wno-deprecated-non-prototype -DUSER_ZZSYN -DZZLEXBUFSIZE=32000 AM_CPPFLAGS = -I../h cdrdao-cdrdao-f00afb2/pccts/antlr/antlr.c000066400000000000000000002716711511453746600204340ustar00rootroot00000000000000/* * A n t l r T r a n s l a t i o n H e a d e r * * Terence Parr, Will Cohen, and Hank Dietz: 1989-2001 * Purdue University Electrical Engineering * With AHPCRC, University of Minnesota * ANTLR Version 1.33MR32 * * ..\bin\antlr -gh antlr.g * */ #define ANTLR_VERSION 13332 #include "pcctscfg.h" #include "pccts_stdio.h" #include "pcctscfg.h" #include "set.h" #include #include "syn.h" #include "hash.h" #include "generic.h" #define zzcr_attr(attr,tok,t) {(attr)->left = 0; (attr)->right = 0;} #define zzSET_SIZE 20 #include "antlr.h" #include "tokens.h" #include "dlgdef.h" #include "mode.h" /* MR23 In order to remove calls to PURIFY use the antlr -nopurify option */ #ifndef PCCTS_PURIFY #define PCCTS_PURIFY(r,s) memset((char *) &(r),'\0',(s)); #endif ANTLR_INFO /* MR20 G. Hobbelt For Borland C++ 4.x & 5.x compiling with ALL warnings enabled */ #if defined(__TURBOC__) #pragma warn -aus /* unused assignment of 'xxx' */ #endif #ifdef __USE_PROTOS static void chkToken(char *, char *, char *, int); #else static void chkToken(); #endif #ifdef __USE_PROTOS static int isDLGmaxToken(char *Token); /* MR3 */ #else static int isDLGmaxToken(); /* MR3 */ #endif static int class_nest_level = 0; /* MR20 G. Hobbelt extern definitions moved to antlr.h */ void #ifdef __USE_PROTOS grammar(void) #else grammar() #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { Graph g; { zzBLOCK(zztasp2); zzMake0; { for (;;) { if ( !((setwd1[LA(1)]&0x1))) break; if ( (LA(1)==94) ) { zzmatch(94); zzCONSUME; zzmatch(Action); if ( HdrAction==NULL ) { HdrAction = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char)); require(HdrAction!=NULL, "rule grammar: cannot allocate header action"); strcpy(HdrAction, LATEXT(1)); } else warn("additional #header statement ignored"); zzCONSUME; } else { if ( (LA(1)==95) ) { zzmatch(95); zzCONSUME; zzmatch(Action); if ( FirstAction==NULL ) { FirstAction = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char)); require(FirstAction!=NULL, "rule grammar: cannot allocate #first action"); strcpy(FirstAction, LATEXT(1)); } else { warn("additional #first statement ignored"); }; zzCONSUME; } else { if ( (LA(1)==96) ) { zzmatch(96); zzCONSUME; zzmatch(QuotedTerm); if ( GenCC ) { warn("#parser meta-op incompatible with -CC; ignored"); } else { if ( strcmp(ParserName,"zzparser")==0 ) { ParserName=StripQuotes(mystrdup(LATEXT(1))); if ( RulePrefix[0]!='\0' ) { warn("#parser meta-op incompatible with '-gp prefix'; '-gp' ignored"); RulePrefix[0]='\0'; } } else warn("additional #parser statement ignored"); } zzCONSUME; } else { if ( (LA(1)==97) ) { zzmatch(97); zzCONSUME; zzmatch(QuotedTerm); { char *fname; zzantlr_state st; FILE *f; struct zzdlg_state dst; UserTokenDefsFile = mystrdup(LATEXT(1)); zzsave_antlr_state(&st); zzsave_dlg_state(&dst); fname = mystrdup(LATEXT(1)); f = fopen(StripQuotes(fname), "r"); if ( f==NULL ) {warn(eMsg1("cannot open token defs file '%s'", fname+1));} else { ANTLRm(enum_file(fname+1), f, PARSE_ENUM_FILE); UserDefdTokens = 1; } zzrestore_antlr_state(&st); zzrestore_dlg_state(&dst); } zzCONSUME; } else break; /* MR6 code for exiting loop "for sure" */ } } } zzLOOP(zztasp2); } zzEXIT(zztasp2); } } { zzBLOCK(zztasp2); zzMake0; { for (;;) { if ( !((setwd1[LA(1)]&0x2))) break; if ( (LA(1)==Action) ) { zzmatch(Action); { UserAction *ua = newUserAction(LATEXT(1)); ua->file = action_file; ua->line = action_line; if ( class_nest_level>0 ) list_add(&class_before_actions, ua); else list_add(&BeforeActions, ua); } zzCONSUME; } else { if ( (LA(1)==108) ) { laction(); } else { if ( (LA(1)==109) ) { lmember(); } else { if ( (LA(1)==110) ) { lprefix(); } else { if ( (LA(1)==116) ) { aLexclass(); } else { if ( (LA(1)==120) ) { token(); } else { if ( (LA(1)==117) ) { error(); } else { if ( (LA(1)==118) ) { tclass(); } else { if ( (LA(1)==111) ) { aPred(); } else { if ( (LA(1)==133) ) { default_exception_handler(); } else { if ( (LA(1)==99) ) { class_def(); } else { if ( (LA(1)==98) ) { zzmatch(98); if ( class_nest_level==0 ) warn("missing class definition for trailing '}'"); class_nest_level--; zzCONSUME; } else break; /* MR6 code for exiting loop "for sure" */ } } } } } } } } } } } zzLOOP(zztasp2); } zzEXIT(zztasp2); } } rule(); g=zzaArg(zztasp1,3); SynDiag = (Junction *) zzaArg(zztasp1,3 ).left; { zzBLOCK(zztasp2); zzMake0; { for (;;) { if ( !((setwd1[LA(1)]&0x4))) break; if ( (LA(1)==NonTerminal) ) { rule(); if ( zzaArg(zztasp2,1 ).left!=NULL ) { g.right = NULL; /* MR21a */ /* Avoid use of a malformed graph when CannotContinue */ /* MR21a */ /* is already set */ /* MR21a */ /* MR21a */ if (! (CannotContinue && g.left == NULL)) { /* MR21a */ g = Or(g, zzaArg(zztasp2,1)); /* MR21a */ } /* MR21a */ } } else { if ( (LA(1)==116) ) { aLexclass(); } else { if ( (LA(1)==120) ) { token(); } else { if ( (LA(1)==117) ) { error(); } else { if ( (LA(1)==118) ) { tclass(); } else { if ( (LA(1)==111) ) { aPred(); } else { if ( (LA(1)==99) ) { class_def(); } else { if ( (LA(1)==98) ) { zzmatch(98); if ( class_nest_level==0 ) warn("missing class definition for trailing '}'"); class_nest_level--; zzCONSUME; } else break; /* MR6 code for exiting loop "for sure" */ } } } } } } } zzLOOP(zztasp2); } zzEXIT(zztasp2); } } { zzBLOCK(zztasp2); zzMake0; { for (;;) { if ( !((setwd1[LA(1)]&0x8))) break; if ( (LA(1)==Action) ) { zzmatch(Action); { UserAction *ua = newUserAction(LATEXT(1)); ua->file = action_file; ua->line = action_line; if ( class_nest_level>0 ) list_add(&class_after_actions, ua); else list_add(&AfterActions, ua); } zzCONSUME; } else { if ( (LA(1)==108) ) { laction(); } else { if ( (LA(1)==109) ) { lmember(); } else { if ( (LA(1)==110) ) { lprefix(); } else { if ( (LA(1)==117) ) { error(); } else { if ( (LA(1)==118) ) { tclass(); } else { if ( (LA(1)==99) ) { class_def(); } else { if ( (LA(1)==111) ) { aPred(); } else { if ( (LA(1)==98) ) { zzmatch(98); if ( class_nest_level==0 ) warn("missing class definition for trailing '}'"); class_nest_level--; zzCONSUME; } else break; /* MR6 code for exiting loop "for sure" */ } } } } } } } } zzLOOP(zztasp2); } zzEXIT(zztasp2); } } zzmatch(Eof); zzCONSUME; zzEXIT(zztasp1); return; fail: zzEXIT(zztasp1); CannotContinue=TRUE; zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd1, 0x10); } } void #ifdef __USE_PROTOS class_def(void) #else class_def() #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { int go=1; char name[MaxRuleName+1]; zzmatch(99); zzCONSUME; { zzBLOCK(zztasp2); zzMake0; { if ( (LA(1)==NonTerminal) ) { zzmatch(NonTerminal); if(go) strncpy(name,LATEXT(1),MaxRuleName); zzCONSUME; } else { if ( (LA(1)==TokenTerm) ) { zzmatch(TokenTerm); if(go) strncpy(name,LATEXT(1),MaxRuleName); zzCONSUME; } else {zzFAIL(1,zzerr1,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } if ( CurrentClassName[0]!='\0' && strcmp(CurrentClassName,name)!=0 && GenCC ) { err("only one grammar class allowed in this release"); go = 0; } else strcpy(CurrentClassName, name); if ( !GenCC ) { err("class meta-op used without C++ option"); } { zzBLOCK(zztasp2); zzMake0; { while ( (setwd1[LA(1)]&0x20) ) { zzsetmatch(zzerr2, zzerr3); if (ClassDeclStuff == NULL) { /* MR10 */ ClassDeclStuff=(char *)calloc(MaxClassDeclStuff+1,sizeof(char)); /* MR10 */ }; /* MR10 */ strncat(ClassDeclStuff," ",MaxClassDeclStuff); /* MR10 */ strncat(ClassDeclStuff,LATEXT(1),MaxClassDeclStuff); /* MR22 */ do { /* MR22 */ if (0 == strcmp(LATEXT(1),"public")) break; /* MR22 */ if (0 == strcmp(LATEXT(1),"private")) break; /* MR22 */ if (0 == strcmp(LATEXT(1),"protected")) break; /* MR22 */ if (0 == strcmp(LATEXT(1),"virtual")) break; /* MR22 */ if (0 == strcmp(LATEXT(1),",")) break; /* MR22 */ if (0 == strcmp(LATEXT(1),":")) break; /* MR22 */ if (BaseClassName != NULL) break; /* MR22 */ BaseClassName=(char *)calloc(strlen(LATEXT(1))+1,sizeof(char)); /* MR22 */ require(BaseClassName!=NULL, "rule grammar: cannot allocate base class name"); /* MR22 */ strcpy(BaseClassName,LATEXT(1)); /* MR22 */ } while (0); /* MR10 */ zzCONSUME; zzLOOP(zztasp2); } zzEXIT(zztasp2); } } zzmatch(102); no_classes_found = 0; if ( class_nest_level>=1 ) {warn("cannot have nested classes");} else class_nest_level++; zzCONSUME; zzEXIT(zztasp1); return; fail: zzEXIT(zztasp1); CannotContinue=TRUE; zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd1, 0x40); } } void #ifdef __USE_PROTOS rule(void) #else rule() #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { ExceptionGroup *eg; RuleEntry *q; Junction *p; Graph r; int f, l; ECnode *e; set toksrefd, rulesrefd; char *pdecl=NULL, *ret=NULL, *a; CurRetDef = CurParmDef = NULL; CurExGroups = NULL; CurElementLabels = NULL; CurAstLabelsInActions = NULL; /* MR27 */ /* We want a new element label hash table for each rule */ if ( Elabel!=NULL ) killHashTable(Elabel); Elabel = newHashTable(); attribsRefdFromAction = empty; zzmatch(NonTerminal); q=NULL; if ( hash_get(Rname, LATEXT(1))!=NULL ) { err(eMsg1("duplicate rule definition: '%s'",LATEXT(1))); CannotContinue=TRUE; } else { q = (RuleEntry *)hash_add(Rname, LATEXT(1), (Entry *)newRuleEntry(LATEXT(1))); CurRule = q->str; } CurRuleNode = q; f = CurFile; l = zzline; NumRules++; zzCONSUME; { zzBLOCK(zztasp2); zzMake0; { if ( (LA(1)==103) ) { zzmatch(103); if ( q!=NULL ) q->noAST = TRUE; zzCONSUME; } else { if ( (setwd1[LA(1)]&0x80) ) { } else {zzFAIL(1,zzerr4,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } { zzBLOCK(zztasp2); zzMake0; { ; if ( (setwd2[LA(1)]&0x1) ) { { zzBLOCK(zztasp3); zzMake0; { if ( (LA(1)==104) ) { zzmatch(104); zzCONSUME; } else { if ( (LA(1)==PassAction) ) { } else {zzFAIL(1,zzerr5,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp3); } } zzmatch(PassAction); pdecl = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char)); require(pdecl!=NULL, "rule rule: cannot allocate param decl"); strcpy(pdecl, LATEXT(1)); CurParmDef = pdecl; zzCONSUME; } else { if ( (setwd2[LA(1)]&0x2) ) { } else {zzFAIL(1,zzerr6,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } { zzBLOCK(zztasp2); zzMake0; { if ( (LA(1)==105) ) { zzmatch(105); zzCONSUME; zzmatch(PassAction); ret = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char)); require(ret!=NULL, "rule rule: cannot allocate ret type"); strcpy(ret, LATEXT(1)); CurRetDef = ret; zzCONSUME; } else { if ( (setwd2[LA(1)]&0x4) ) { } else {zzFAIL(1,zzerr7,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } { zzBLOCK(zztasp2); zzMake0; { if ( (LA(1)==QuotedTerm) ) { zzmatch(QuotedTerm); if ( q!=NULL ) q->egroup=mystrdup(LATEXT(1)); zzCONSUME; } else { if ( (LA(1)==106) ) { } else {zzFAIL(1,zzerr8,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } if ( GenEClasseForRules && q!=NULL ) { e = newECnode; require(e!=NULL, "cannot allocate error class node"); if ( q->egroup == NULL ) {a = q->str; a[0] = (char)toupper(a[0]);} else a = q->egroup; if ( Tnum( a ) == 0 ) { e->tok = addTname( a ); list_add(&eclasses, (char *)e); if ( q->egroup == NULL ) a[0] = (char)tolower(a[0]); /* refers to itself */ list_add(&(e->elist), mystrdup(q->str)); } else { warn(eMsg1("default errclass for '%s' would conflict with token/errclass/tokclass",a)); if ( q->egroup == NULL ) a[0] = (char)tolower(a[0]); free((char *)e); } } BlkLevel++; if (BlkLevel >= MAX_BLK_LEVEL) fatal("Blocks nested too deeply"); /* MR23 */ CurBlockID_array[BlkLevel] = CurBlockID; /* MR23 */ CurAltNum_array[BlkLevel] = CurAltNum; zzmatch(106); inAlt=1; zzCONSUME; block( &toksrefd, &rulesrefd ); r = makeBlk(zzaArg(zztasp1,7),0, NULL /* pFirstSetSymbol */ ); CurRuleBlk = (Junction *)r.left; CurRuleBlk->blockid = CurBlockID; CurRuleBlk->jtype = RuleBlk; if ( q!=NULL ) CurRuleBlk->rname = q->str; CurRuleBlk->file = f; CurRuleBlk->line = l; CurRuleBlk->pdecl = pdecl; CurRuleBlk->ret = ret; CurRuleBlk->lock = makelocks(); CurRuleBlk->pred_lock = makelocks(); CurRuleBlk->tokrefs = toksrefd; CurRuleBlk->rulerefs = rulesrefd; p = newJunction(); /* add EndRule Node */ ((Junction *)r.right)->p1 = (Node *)p; r.right = (Node *) p; p->jtype = EndRule; p->lock = makelocks(); p->pred_lock = makelocks(); CurRuleBlk->end = p; if ( q!=NULL ) q->rulenum = NumRules; zzaArg(zztasp1,7) = r; /* MR23 */ CurBlockID_array[BlkLevel] = (-1); /* MR23 */ CurAltNum_array[BlkLevel] = (-1); --BlkLevel; altFixup();leFixup();egFixup(); zzmatch(107); inAlt=0; zzCONSUME; { zzBLOCK(zztasp2); zzMake0; { if ( (LA(1)==Action) ) { zzmatch(Action); a = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char)); require(a!=NULL, "rule rule: cannot allocate error action"); strcpy(a, LATEXT(1)); CurRuleBlk->erraction = a; zzCONSUME; } else { if ( (setwd2[LA(1)]&0x8) ) { } else {zzFAIL(1,zzerr9,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } { zzBLOCK(zztasp2); zzMake0; { while ( (LA(1)==133) ) { eg = exception_group(); if ( eg!=NULL ) { list_add(&CurExGroups, (void *)eg); if (eg->label == NULL || *eg->label=='\0' ) q->has_rule_exception = 1; } zzLOOP(zztasp2); } zzEXIT(zztasp2); } } if ( q==NULL ) zzaArg(zztasp1,0 ).left = NULL; else zzaArg(zztasp1,0) = zzaArg(zztasp1,7); CurRuleBlk->exceptions = CurExGroups; CurRuleBlk->el_labels = CurElementLabels; CurRuleNode->ast_labels_in_actions = CurAstLabelsInActions; CurRuleNode = NULL; zzEXIT(zztasp1); return; fail: zzEXIT(zztasp1); CannotContinue=TRUE; zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd2, 0x10); } } void #ifdef __USE_PROTOS laction(void) #else laction() #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { char *a; zzmatch(108); zzCONSUME; zzmatch(Action); a = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char)); require(a!=NULL, "rule laction: cannot allocate action"); strcpy(a, LATEXT(1)); list_add(&LexActions, a); zzCONSUME; zzEXIT(zztasp1); return; fail: zzEXIT(zztasp1); CannotContinue=TRUE; zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd2, 0x20); } } void #ifdef __USE_PROTOS lmember(void) #else lmember() #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { char *a; zzmatch(109); zzCONSUME; zzmatch(Action); /* MR1 */ if (! GenCC) { /* MR1 */ err("Use #lexmember only in C++ mode (to insert code in DLG class header"); /* MR1 */ } else { /* MR1 */ a = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char)); /* MR1 */ require(a!=NULL, "rule lmember: cannot allocate action"); /* MR1 */ strcpy(a, LATEXT(1)); /* MR1 */ list_add(&LexMemberActions, a); /* MR1 */ }; /* MR1 */ zzCONSUME; zzEXIT(zztasp1); return; fail: zzEXIT(zztasp1); CannotContinue=TRUE; zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd2, 0x40); } } void #ifdef __USE_PROTOS lprefix(void) #else lprefix() #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { char *a; zzmatch(110); zzCONSUME; zzmatch(Action); /* MR1 */ if (! GenCC) { /* MR1 */ err("Use #lexprefix only in C++ mode (to insert code in DLG class header"); /* MR1 */ } else { /* MR1 */ a = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char)); /* MR1 */ require(a!=NULL, "rule lprefix: cannot allocate action"); /* MR1 */ strcpy(a, LATEXT(1)); /* MR1 */ list_add(&LexPrefixActions, a); /* MR1 */ }; /* MR1 */ zzCONSUME; zzEXIT(zztasp1); return; fail: zzEXIT(zztasp1); CannotContinue=TRUE; zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd2, 0x80); } } void #ifdef __USE_PROTOS aPred(void) #else aPred() #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { PredEntry *predEntry=NULL; char *name=NULL; Predicate *predExpr=NULL; char *predLiteral=NULL; int save_file; int save_line; int predExprPresent=0; zzmatch(111); MR_usingPredNames=1; /* will need to use -mrhoist version of genPredTree */ zzCONSUME; zzmatch(TokenTerm); name=mystrdup(LATEXT(1)); zzCONSUME; /* don't free - referenced in predicates */ CurPredName=(char *)calloc(1,strlen(name) + 10); strcat(CurPredName,"#pred "); strcat(CurPredName,name); predEntry=(PredEntry *) hash_get(Pname,name); if (predEntry != NULL) { warnFL(eMsg1("#pred %s previously defined - ignored",name), FileStr[action_file],action_line); name=NULL; }; { zzBLOCK(zztasp2); zzMake0; { if ( (LA(1)==Pred) ) { zzmatch(Pred); predLiteral=mystrdup(LATEXT(1)); save_line=action_line; save_file=action_file; zzCONSUME; { zzBLOCK(zztasp3); zzMake0; { if ( (setwd3[LA(1)]&0x1) ) { predExpr = predOrExpr(); predExprPresent=1; } else { if ( (setwd3[LA(1)]&0x2) ) { } else {zzFAIL(1,zzerr10,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp3); } } if (predLiteral != NULL && name != NULL) { /* * predExpr may be NULL due to syntax errors * or simply omitted by the user */ predEntry=newPredEntry(name); predEntry->file=save_file; predEntry->line=save_line; predExpr=MR_predFlatten(predExpr); predEntry->predLiteral=predLiteral; if (! predExprPresent || predExpr == NULL) { predExpr=new_pred(); predExpr->expr=predLiteral; predExpr->source=newActionNode(); predExpr->source->action=predExpr->expr; predExpr->source->rname=CurPredName; predExpr->source->line=action_line; predExpr->source->file=action_file; predExpr->source->is_predicate=1; predExpr->k=predicateLookaheadDepth(predExpr->source); }; predEntry->pred=predExpr; hash_add(Pname,name,(Entry *)predEntry); predExpr=NULL; }; predicate_free(predExpr); } else { if ( (setwd3[LA(1)]&0x4) ) { save_line=zzline; save_file=CurFile; predExpr = predOrExpr(); if (predExpr != NULL && name != NULL) { predEntry=newPredEntry(name); predEntry->file=CurFile; predEntry->line=zzline; predExpr=MR_predFlatten(predExpr); predEntry->pred=predExpr; hash_add(Pname,name,(Entry *)predEntry); predExpr=NULL; }; predicate_free(predExpr); } else {zzFAIL(1,zzerr11,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } { zzBLOCK(zztasp2); zzMake0; { if ( (LA(1)==107) ) { zzmatch(107); zzCONSUME; } else { if ( (setwd3[LA(1)]&0x8) ) { } else {zzFAIL(1,zzerr12,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } zzEXIT(zztasp1); return; fail: zzEXIT(zztasp1); predicate_free(predExpr); zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd3, 0x10); } } Predicate * #ifdef __USE_PROTOS predOrExpr(void) #else predOrExpr() #endif { Predicate * _retv; zzRULE; zzBLOCK(zztasp1); PCCTS_PURIFY(_retv,sizeof(Predicate * )) zzMake0; { Predicate *ORnode; Predicate *predExpr; Predicate **tail=NULL; predExpr = predAndExpr(); ORnode=new_pred(); ORnode->expr=PRED_OR_LIST; if (predExpr != NULL) { ORnode->down=predExpr; tail=&predExpr->right; }; { zzBLOCK(zztasp2); zzMake0; { while ( (LA(1)==112) ) { zzmatch(112); zzCONSUME; predExpr = predAndExpr(); if (predExpr != NULL) { *tail=predExpr; tail=&predExpr->right; }; zzLOOP(zztasp2); } zzEXIT(zztasp2); } } _retv=ORnode; ORnode=NULL; zzEXIT(zztasp1); return _retv; fail: zzEXIT(zztasp1); predicate_free(ORnode); zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd3, 0x20); return _retv; } } Predicate * #ifdef __USE_PROTOS predAndExpr(void) #else predAndExpr() #endif { Predicate * _retv; zzRULE; zzBLOCK(zztasp1); PCCTS_PURIFY(_retv,sizeof(Predicate * )) zzMake0; { Predicate *ANDnode; Predicate *predExpr; Predicate **tail=NULL; predExpr = predPrimary(); ANDnode=new_pred(); ANDnode->expr=PRED_AND_LIST; if (predExpr != NULL) { ANDnode->down=predExpr; tail=&predExpr->right; }; { zzBLOCK(zztasp2); zzMake0; { while ( (LA(1)==113) ) { zzmatch(113); zzCONSUME; predExpr = predPrimary(); if (predExpr != NULL) { *tail=predExpr; tail=&predExpr->right; }; zzLOOP(zztasp2); } zzEXIT(zztasp2); } } _retv=ANDnode; ANDnode=NULL; zzEXIT(zztasp1); return _retv; fail: zzEXIT(zztasp1); predicate_free(ANDnode); zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd3, 0x40); return _retv; } } Predicate * #ifdef __USE_PROTOS predPrimary(void) #else predPrimary() #endif { Predicate * _retv; zzRULE; zzBLOCK(zztasp1); PCCTS_PURIFY(_retv,sizeof(Predicate * )) zzMake0; { char *name=NULL; PredEntry *predEntry=NULL; Predicate *predExpr=NULL; if ( (LA(1)==TokenTerm) ) { zzmatch(TokenTerm); name=mystrdup(LATEXT(1)); zzCONSUME; predEntry=(PredEntry *) hash_get(Pname,name); if (predEntry == NULL) { warnFL(eMsg1("no previously defined #pred with name \"%s\"",name), FileStr[CurFile],zzline); name=NULL; _retv=NULL; } else { predExpr=predicate_dup(predEntry->pred); predExpr->predEntry=predEntry; _retv=predExpr; }; } else { if ( (LA(1)==114) ) { zzmatch(114); zzCONSUME; predExpr = predOrExpr(); zzmatch(115); _retv=predExpr; zzCONSUME; } else { if ( (LA(1)==103) ) { zzmatch(103); zzCONSUME; predExpr = predPrimary(); predExpr->inverted=!predExpr->inverted; _retv=predExpr; } else {zzFAIL(1,zzerr13,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } } zzEXIT(zztasp1); return _retv; fail: zzEXIT(zztasp1); predicate_free(predExpr); zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd3, 0x80); return _retv; } } void #ifdef __USE_PROTOS aLexclass(void) #else aLexclass() #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { zzmatch(116); zzCONSUME; zzmatch(TokenTerm); lexclass(mystrdup(LATEXT(1))); zzCONSUME; zzEXIT(zztasp1); return; fail: zzEXIT(zztasp1); CannotContinue=TRUE; zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd4, 0x1); } } void #ifdef __USE_PROTOS error(void) #else error() #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { char *t=NULL; ECnode *e; int go=1; TermEntry *p; zzmatch(117); zzCONSUME; { zzBLOCK(zztasp2); zzMake0; { ; if ( (LA(1)==TokenTerm) ) { zzmatch(TokenTerm); t=mystrdup(LATEXT(1)); zzCONSUME; } else { if ( (LA(1)==QuotedTerm) ) { zzmatch(QuotedTerm); t=mystrdup(LATEXT(1)); zzCONSUME; } else {zzFAIL(1,zzerr14,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } e = newECnode; require(e!=NULL, "cannot allocate error class node"); e->lexclass = CurrentLexClass; if ( Tnum( (t=StripQuotes(t)) ) == 0 ) { if ( hash_get(Texpr, t) != NULL ) warn(eMsg1("errclass name conflicts with regular expression '%s'",t)); e->tok = addTname( t ); set_orel(e->tok, &imag_tokens); require((p=(TermEntry *)hash_get(Tname, t)) != NULL, "hash table mechanism is broken"); p->classname = 1; /* entry is errclass name, not token */ list_add(&eclasses, (char *)e); } else { warn(eMsg1("redefinition of errclass or conflict w/token or tokclass '%s'; ignored",t)); free( (char *)e ); go=0; } zzmatch(102); zzCONSUME; { zzBLOCK(zztasp2); zzMake0; { if ( (LA(1)==NonTerminal) ) { zzmatch(NonTerminal); if ( go ) t=mystrdup(LATEXT(1)); zzCONSUME; } else { if ( (LA(1)==TokenTerm) ) { zzmatch(TokenTerm); if ( go ) t=mystrdup(LATEXT(1)); zzCONSUME; } else { if ( (LA(1)==QuotedTerm) ) { zzmatch(QuotedTerm); if ( go ) t=mystrdup(LATEXT(1)); zzCONSUME; } else {zzFAIL(1,zzerr15,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } } zzEXIT(zztasp2); } } if ( go ) list_add(&(e->elist), t); { zzBLOCK(zztasp2); zzMake0; { while ( (setwd4[LA(1)]&0x2) ) { { zzBLOCK(zztasp3); zzMake0; { if ( (LA(1)==NonTerminal) ) { zzmatch(NonTerminal); if ( go ) t=mystrdup(LATEXT(1)); zzCONSUME; } else { if ( (LA(1)==TokenTerm) ) { zzmatch(TokenTerm); if ( go ) t=mystrdup(LATEXT(1)); zzCONSUME; } else { if ( (LA(1)==QuotedTerm) ) { zzmatch(QuotedTerm); if ( go ) t=mystrdup(LATEXT(1)); zzCONSUME; } else {zzFAIL(1,zzerr16,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } } zzEXIT(zztasp3); } } if ( go ) list_add(&(e->elist), t); zzLOOP(zztasp2); } zzEXIT(zztasp2); } } zzmatch(98); zzCONSUME; zzEXIT(zztasp1); return; fail: zzEXIT(zztasp1); CannotContinue=TRUE; zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd4, 0x4); } } void #ifdef __USE_PROTOS tclass(void) #else tclass() #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { char *t=NULL; TCnode *e; int go=1,tok,totok; TermEntry *p = NULL; char *term, *toterm; char *akaString=NULL; int save_file = 0; int save_line = 0; char *totext=NULL; zzmatch(118); zzCONSUME; zzmatch(TokenTerm); t=mystrdup(LATEXT(1)); zzCONSUME; e = newTCnode; require(e!=NULL, "cannot allocate token class node"); e->lexclass = CurrentLexClass; if ( Tnum( t ) == 0 ) { e->tok = addTname( t ); set_orel(e->tok, &imag_tokens); set_orel(e->tok, &tokclasses); require((p=(TermEntry *)hash_get(Tname, t)) != NULL, "hash table mechanism is broken"); p->classname = 1; /* entry is class name, not token */ p->tclass = e; /* save ptr to this tclass def */ list_add(&tclasses, (char *)e); } else { warn(eMsg1("redefinition of tokclass or conflict w/token '%s'; ignored",t)); free( (char *)e ); go=0; } { zzBLOCK(zztasp2); zzMake0; { if ( (LA(1)==114) ) { zzmatch(114); zzCONSUME; zzmatch(QuotedTerm); akaString=mystrdup(StripQuotes(LATEXT(1))); /* MR11 */ save_file=CurFile;save_line=zzline; /* MR23 */ zzCONSUME; zzmatch(115); zzCONSUME; } else { if ( (LA(1)==102) ) { } else {zzFAIL(1,zzerr17,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } /* MR23 */ if (p!= NULL && akaString != NULL) { /* MR23 */ if (p->akaString != NULL) { /* MR23 */ if (strcmp(p->akaString,akaString) != 0) { /* MR23 */ warnFL(eMsg2("this #tokclass statment conflicts with a previous #tokclass %s(\"%s\") statement", /* MR23 */ t,p->akaString), /* MR23 */ FileStr[save_file],save_line); /* MR23 */ }; /* MR23 */ } else { /* MR23 */ p->akaString=akaString; /* MR23 */ }; /* MR23 */ }; /* MR23 */ zzmatch(102); zzCONSUME; { zzBLOCK(zztasp2); int zzcnt=1; zzMake0; { do { { zzBLOCK(zztasp3); zzMake0; { if ( (LA(1)==TokenTerm) ) { zzmatch(TokenTerm); if ( go ) { term = (char *) hash_get(Tname, LATEXT(1)); if ( term==NULL && UserDefdTokens ) { err("implicit token definition not allowed with #tokdefs"); go = 0; } else {t=mystrdup(LATEXT(1)); tok=addTname(LATEXT(1));} } zzCONSUME; { zzBLOCK(zztasp4); zzMake0; { if ( (LA(1)==119) ) { zzmatch(119); zzCONSUME; zzmatch(TokenTerm); if ( go ) { toterm = (char *) hash_get(Tname, LATEXT(1)); if ( toterm==NULL && UserDefdTokens ) { err("implicit token definition not allowed with #tokdefs"); go = 0; } else { totext=mystrdup(LATEXT(1)); totok=addTname(LATEXT(1)); } } zzCONSUME; } else { if ( (setwd4[LA(1)]&0x8) ) { } else {zzFAIL(1,zzerr18,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp4); } } } else { if ( (LA(1)==QuotedTerm) ) { zzmatch(QuotedTerm); if ( go ) { term = (char *) hash_get(Texpr, LATEXT(1)); if ( term==NULL && UserDefdTokens ) { err("implicit token definition not allowed with #tokdefs"); go = 0; } else {t=mystrdup(LATEXT(1)); tok=addTexpr(LATEXT(1));} } zzCONSUME; } else {zzFAIL(1,zzerr19,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp3); } } if ( go ) { if (totext == NULL) { list_add(&(e->tlist), t); } else { list_add(&(e->tlist),".."); list_add(&(e->tlist),t); list_add(&(e->tlist),totext); } totext=NULL; } zzLOOP(zztasp2); } while ( (setwd4[LA(1)]&0x10) ); zzEXIT(zztasp2); } } zzmatch(98); zzCONSUME; zzEXIT(zztasp1); return; fail: zzEXIT(zztasp1); CannotContinue=TRUE; zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd4, 0x20); } } void #ifdef __USE_PROTOS token(void) #else token() #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { char *t=NULL, *e=NULL, *a=NULL; int tnum=0; char *akaString=NULL; TermEntry *te;int save_file=0,save_line=0; zzmatch(120); tokenActionActive=1; zzCONSUME; { zzBLOCK(zztasp2); zzMake0; { if ( (LA(1)==TokenTerm) ) { zzmatch(TokenTerm); t=mystrdup(LATEXT(1)); zzCONSUME; { zzBLOCK(zztasp3); zzMake0; { if ( (LA(1)==114) ) { zzmatch(114); zzCONSUME; zzmatch(QuotedTerm); akaString=mystrdup(StripQuotes(LATEXT(1))); /* MR11 */ save_file=CurFile;save_line=zzline; /* MR11 */ zzCONSUME; zzmatch(115); zzCONSUME; } else { if ( (setwd4[LA(1)]&0x40) ) { } else {zzFAIL(1,zzerr20,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp3); } } { zzBLOCK(zztasp3); zzMake0; { if ( (LA(1)==121) ) { zzmatch(121); zzCONSUME; zzmatch(122); tnum = atoi(LATEXT(1)); zzCONSUME; } else { if ( (setwd4[LA(1)]&0x80) ) { } else {zzFAIL(1,zzerr21,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp3); } } } else { if ( (setwd5[LA(1)]&0x1) ) { } else {zzFAIL(1,zzerr22,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } { zzBLOCK(zztasp2); zzMake0; { if ( (LA(1)==QuotedTerm) ) { zzmatch(QuotedTerm); e=mystrdup(LATEXT(1)); zzCONSUME; } else { if ( (setwd5[LA(1)]&0x2) ) { } else {zzFAIL(1,zzerr23,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } { zzBLOCK(zztasp2); zzMake0; { if ( (LA(1)==Action) ) { zzmatch(Action); a = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char)); require(a!=NULL, "rule token: cannot allocate action"); strcpy(a, LATEXT(1)); zzCONSUME; } else { if ( (setwd5[LA(1)]&0x4) ) { } else {zzFAIL(1,zzerr24,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } { zzBLOCK(zztasp2); zzMake0; { if ( (LA(1)==107) ) { zzmatch(107); zzCONSUME; } else { if ( (setwd5[LA(1)]&0x8) ) { } else {zzFAIL(1,zzerr25,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } chkToken(t, e, a, tnum); if (t != NULL) { te=(TermEntry *)hash_get(Tname,t); if (te != NULL && akaString != NULL) { if (te->akaString != NULL) { if (strcmp(te->akaString,akaString) != 0) { warnFL(eMsg2("this #token statment conflicts with a previous #token %s(\"%s\") statement", t,te->akaString), FileStr[save_file],save_line); }; } else { te->akaString=akaString; }; }; }; zzEXIT(zztasp1); return; fail: zzEXIT(zztasp1); CannotContinue=TRUE; zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd5, 0x10); } } void #ifdef __USE_PROTOS block(set * toksrefd,set * rulesrefd) #else block(toksrefd,rulesrefd) set *toksrefd; set *rulesrefd ; #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { Graph g, b; set saveblah; int saveinalt = inAlt; ExceptionGroup *eg; * toksrefd = empty; * rulesrefd = empty; set_clr(AST_nodes_refd_in_actions); CurBlockID++; /* MR23 */ CurBlockID_array[BlkLevel] = CurBlockID; CurAltNum = 1; /* MR23 */ CurAltNum_array[BlkLevel] = CurAltNum; saveblah = attribsRefdFromAction; attribsRefdFromAction = empty; alt( toksrefd,rulesrefd ); b = g = zzaArg(zztasp1,1); if ( ((Junction *)g.left)->p1->ntype == nAction ) { ActionNode *actionNode=(ActionNode *) ( ( (Junction *)g.left) ->p1); if (!actionNode->is_predicate ) { actionNode->init_action = TRUE; /* MR12c */ if (actionNode->noHoist) { /* MR12c */ errFL("<> appears as init-action - use <<>> <>", /* MR12c */ FileStr[actionNode->file],actionNode->line); /* MR12c */ }; } } ((Junction *)g.left)->blockid = CurBlockID; { zzBLOCK(zztasp2); zzMake0; { while ( (LA(1)==133) ) { eg = exception_group(); if ( eg!=NULL ) { /* MR7 ***** eg->altID = makeAltID(CurBlockID,CurAltNum); *****/ /* MR7 ***** CurAltStart->exception_label = eg->altID; *****/ list_add(&CurExGroups, (void *)eg); } zzLOOP(zztasp2); } zzEXIT(zztasp2); } } CurAltNum++; /* MR23 */ CurAltNum_array[BlkLevel] = CurAltNum; { zzBLOCK(zztasp2); zzMake0; { while ( (LA(1)==123) ) { zzmatch(123); inAlt=1; zzCONSUME; alt( toksrefd,rulesrefd ); g = Or(g, zzaArg(zztasp2,2)); ((Junction *)g.left)->blockid = CurBlockID; { zzBLOCK(zztasp3); zzMake0; { while ( (LA(1)==133) ) { eg = exception_group(); if ( eg!=NULL ) { /* MR7 ***** eg->altID = makeAltID(CurBlockID,CurAltNum); *****/ /* MR7 ***** CurAltStart->exception_label = eg->altID; *****/ list_add(&CurExGroups, (void *)eg); } zzLOOP(zztasp3); } zzEXIT(zztasp3); } } CurAltNum++; /* MR23 */ CurAltNum_array[BlkLevel] = CurAltNum; zzLOOP(zztasp2); } zzEXIT(zztasp2); } } zzaArg(zztasp1,0) = b; attribsRefdFromAction = saveblah; inAlt = saveinalt; zzEXIT(zztasp1); return; fail: zzEXIT(zztasp1); CannotContinue=TRUE; zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd5, 0x20); } } void #ifdef __USE_PROTOS alt(set * toksrefd,set * rulesrefd) #else alt(toksrefd,rulesrefd) set *toksrefd; set *rulesrefd ; #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { int n=0; Graph g; int e_num=0, old_not=0; Node *node; set elems, dif; int first_on_line = 1, use_def_MT_handler = 0; g.left=NULL; g.right=NULL; CurAltStart = NULL; elems = empty; inAlt = 1; { zzBLOCK(zztasp2); zzMake0; { if ( (LA(1)==88) ) { zzmatch(88); use_def_MT_handler = 1; zzCONSUME; } else { if ( (setwd5[LA(1)]&0x40) ) { } else {zzFAIL(1,zzerr26,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } { zzBLOCK(zztasp2); zzMake0; { ; while ( (setwd5[LA(1)]&0x80) ) { { zzBLOCK(zztasp3); zzMake0; { old_not=0; if ( (LA(1)==124) ) { zzmatch(124); old_not=1; zzCONSUME; } else { if ( (setwd6[LA(1)]&0x1) ) { } else {zzFAIL(1,zzerr27,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp3); } } node = element( old_not, first_on_line, use_def_MT_handler ); if ( node!=NULL && node->ntype!=nAction ) first_on_line = 0; if ( zzaArg(zztasp2,2 ).left!=NULL ) { g = Cat(g, zzaArg(zztasp2,2)); n++; if ( node!=NULL ) { if ( node->ntype!=nAction ) e_num++; /* record record number of all rule and token refs */ if ( node->ntype==nToken ) { TokNode *tk = (TokNode *)((Junction *)zzaArg(zztasp2,2 ).left)->p1; tk->elnum = e_num; set_orel(e_num, &elems); } else if ( node->ntype==nRuleRef ) { RuleRefNode *rn = (RuleRefNode *)((Junction *)zzaArg(zztasp2,2 ).left)->p1; rn->elnum = e_num; set_orel(e_num, rulesrefd); } } } zzLOOP(zztasp2); } zzEXIT(zztasp2); } } if ( n == 0 ) g = emptyAlt(); zzaArg(zztasp1,0) = g; /* We want to reduce number of LT(i) calls and the number of * local attribute variables in C++ mode (for moment, later we'll * do for C also). However, if trees are being built, they * require most of the attrib variables to create the tree nodes * with; therefore, we gen a token ptr for each token ref in C++ */ if ( GenCC && !GenAST ) { /* This now free's the temp set -ATG 5/6/95 */ set temp; temp = set_and(elems, attribsRefdFromAction); set_orin( toksrefd, temp); set_free(temp); } else set_orin( toksrefd, elems); if ( GenCC ) { dif = set_dif(attribsRefdFromAction, elems); if ( set_deg(dif)>0 ) err("one or more $i in action(s) refer to non-token elements"); set_free(dif); } set_free(elems); set_free(attribsRefdFromAction); inAlt = 0; zzEXIT(zztasp1); return; fail: zzEXIT(zztasp1); CannotContinue=TRUE; zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd6, 0x2); } } LabelEntry * #ifdef __USE_PROTOS element_label(void) #else element_label() #endif { LabelEntry * _retv; zzRULE; zzBLOCK(zztasp1); PCCTS_PURIFY(_retv,sizeof(LabelEntry * )) zzMake0; { TermEntry *t=NULL; LabelEntry *l=NULL; RuleEntry *r=NULL; char *lab; zzmatch(LABEL); lab = mystrdup(LATEXT(1)); zzCONSUME; UsedNewStyleLabel = 1; if ( UsedOldStyleAttrib ) err("cannot mix with new-style labels with old-style $i"); t = (TermEntry *) hash_get(Tname, lab); if ( t==NULL ) t = (TermEntry *) hash_get(Texpr, lab); if ( t==NULL ) r = (RuleEntry *) hash_get(Rname, lab); if ( t!=NULL ) { err(eMsg1("label definition clashes with token/tokclass definition: '%s'", lab)); _retv = NULL; } else if ( r!=NULL ) { err(eMsg1("label definition clashes with rule definition: '%s'", lab)); _retv = NULL; } else { /* we don't clash with anybody else */ l = (LabelEntry *) hash_get(Elabel, lab); if ( l==NULL ) { /* ok to add new element label */ l = (LabelEntry *)hash_add(Elabel, lab, (Entry *)newLabelEntry(lab)); /* add to list of element labels for this rule */ list_add(&CurElementLabels, (void *)lab); /* MR7 */ leAdd(l); /* list of labels waiting for exception group definitions */ _retv = l; } else { err(eMsg1("label definitions must be unique per rule: '%s'", lab)); _retv = NULL; } } zzmatch(106); zzCONSUME; zzEXIT(zztasp1); return _retv; fail: zzEXIT(zztasp1); zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd6, 0x4); return _retv; } } Node * #ifdef __USE_PROTOS element(int old_not,int first_on_line,int use_def_MT_handler) #else element(old_not,first_on_line,use_def_MT_handler) int old_not; int first_on_line; int use_def_MT_handler ; #endif { Node * _retv; zzRULE; zzBLOCK(zztasp1); PCCTS_PURIFY(_retv,sizeof(Node * )) zzMake0; { Attrib blk; Predicate *pred = NULL; int local_use_def_MT_handler=0; ActionNode *act; RuleRefNode *rr; set toksrefd, rulesrefd; TermEntry *term; TokNode *p=NULL; RuleRefNode *q; int approx=0; LabelEntry *label=NULL; int predMsgDone=0; int semDepth=0; int ampersandStyle; int height; /* MR11 */ int equal_height; /* MR11 */ char* pFirstSetSymbol = NULL; /* MR21 */ _retv = NULL; if ( (setwd6[LA(1)]&0x8) ) { { zzBLOCK(zztasp2); zzMake0; { if ( (LA(1)==LABEL) ) { label = element_label(); } else { if ( (setwd6[LA(1)]&0x10) ) { } else {zzFAIL(1,zzerr28,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } { zzBLOCK(zztasp2); zzMake0; { if ( (LA(1)==TokenTerm) ) { zzmatch(TokenTerm); term = (TermEntry *) hash_get(Tname, LATEXT(1)); if ( term==NULL && UserDefdTokens ) { err("implicit token definition not allowed with #tokdefs"); zzaRet.left = zzaRet.right = NULL; } else { zzaRet = buildToken(LATEXT(1)); p=((TokNode *)((Junction *)zzaRet.left)->p1); term = (TermEntry *) hash_get(Tname, LATEXT(1)); require( term!= NULL, "hash table mechanism is broken"); p->tclass = term->tclass; p->complement = old_not; if ( label!=NULL ) { p->el_label = label->str; label->elem = (Node *)p; } } zzCONSUME; { zzBLOCK(zztasp3); zzMake0; { if ( (LA(1)==119) ) { zzmatch(119); zzCONSUME; { zzBLOCK(zztasp4); zzMake0; { if ( (LA(1)==QuotedTerm) ) { zzmatch(QuotedTerm); if ( p!=NULL ) setUpperRange(p, LATEXT(1)); zzCONSUME; } else { if ( (LA(1)==TokenTerm) ) { zzmatch(TokenTerm); if ( p!=NULL ) setUpperRange(p, LATEXT(1)); zzCONSUME; } else {zzFAIL(1,zzerr29,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp4); } } } else { if ( (setwd6[LA(1)]&0x20) ) { } else {zzFAIL(1,zzerr30,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp3); } } if ( p!=NULL && (p->upper_range!=0 || p->tclass || old_not) ) list_add(&MetaTokenNodes, (void *)p); { zzBLOCK(zztasp3); zzMake0; { if ( (LA(1)==125) ) { zzmatch(125); if ( p!=NULL ) p->astnode=ASTroot; zzCONSUME; } else { if ( (setwd6[LA(1)]&0x40) ) { if ( p!=NULL ) p->astnode=ASTchild; } else { if ( (LA(1)==103) ) { zzmatch(103); if ( p!=NULL ) p->astnode=ASTexclude; zzCONSUME; } else {zzFAIL(1,zzerr31,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } } zzEXIT(zztasp3); } } { zzBLOCK(zztasp3); zzMake0; { if ( (LA(1)==88) ) { zzmatch(88); local_use_def_MT_handler = 1; zzCONSUME; } else { if ( (setwd6[LA(1)]&0x80) ) { } else {zzFAIL(1,zzerr32,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp3); } } if ( p!=NULL && first_on_line ) { CurAltStart = (Junction *)zzaRet.left; altAdd(CurAltStart); /* MR7 */ p->altstart = CurAltStart; } if ( p!=NULL ) p->use_def_MT_handler = use_def_MT_handler || local_use_def_MT_handler; _retv = (Node *)p; } else { if ( (LA(1)==QuotedTerm) ) { zzmatch(QuotedTerm); term = (TermEntry *) hash_get(Texpr, LATEXT(1)); if ( term==NULL && UserDefdTokens ) { err("implicit token definition not allowed with #tokdefs"); zzaRet.left = zzaRet.right = NULL; } else { zzaRet = buildToken(LATEXT(1)); p=((TokNode *)((Junction *)zzaRet.left)->p1); p->complement = old_not; if ( label!=NULL ) { p->el_label = label->str; label->elem = (Node *)p; } } zzCONSUME; { zzBLOCK(zztasp3); zzMake0; { if ( (LA(1)==119) ) { zzmatch(119); zzCONSUME; { zzBLOCK(zztasp4); zzMake0; { if ( (LA(1)==QuotedTerm) ) { zzmatch(QuotedTerm); if ( p!=NULL ) setUpperRange(p, LATEXT(1)); zzCONSUME; } else { if ( (LA(1)==TokenTerm) ) { zzmatch(TokenTerm); if ( p!=NULL ) setUpperRange(p, LATEXT(1)); zzCONSUME; } else {zzFAIL(1,zzerr33,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp4); } } } else { if ( (setwd7[LA(1)]&0x1) ) { } else {zzFAIL(1,zzerr34,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp3); } } { zzBLOCK(zztasp3); zzMake0; { if ( (LA(1)==125) ) { zzmatch(125); if ( p!=NULL ) p->astnode=ASTroot; zzCONSUME; } else { if ( (setwd7[LA(1)]&0x2) ) { if ( p!=NULL ) p->astnode=ASTchild; } else { if ( (LA(1)==103) ) { zzmatch(103); if ( p!=NULL ) p->astnode=ASTexclude; zzCONSUME; } else {zzFAIL(1,zzerr35,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } } zzEXIT(zztasp3); } } { zzBLOCK(zztasp3); zzMake0; { if ( (LA(1)==88) ) { zzmatch(88); local_use_def_MT_handler = 1; zzCONSUME; } else { if ( (setwd7[LA(1)]&0x4) ) { } else {zzFAIL(1,zzerr36,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp3); } } if ( p!=NULL && (p->upper_range!=0 || p->tclass || old_not) ) list_add(&MetaTokenNodes, (void *)p); if ( first_on_line ) { CurAltStart = (Junction *)zzaRet.left; altAdd(CurAltStart); /* MR7 */ p->altstart = CurAltStart; } if ( p!=NULL ) p->use_def_MT_handler = use_def_MT_handler || local_use_def_MT_handler; _retv = (Node *)p; } else { if ( (LA(1)==WildCard) ) { if ( old_not ) warn("~ WILDCARD is an undefined operation (implies 'nothing')"); zzmatch(WildCard); zzaRet = buildWildCard(LATEXT(1)); p=((TokNode *)((Junction *)zzaRet.left)->p1); zzCONSUME; { zzBLOCK(zztasp3); zzMake0; { if ( (LA(1)==125) ) { zzmatch(125); p->astnode=ASTroot; zzCONSUME; } else { if ( (setwd7[LA(1)]&0x8) ) { p->astnode=ASTchild; } else { if ( (LA(1)==103) ) { zzmatch(103); p->astnode=ASTexclude; zzCONSUME; } else {zzFAIL(1,zzerr37,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } } zzEXIT(zztasp3); } } list_add(&MetaTokenNodes, (void *)p); if ( first_on_line ) { CurAltStart = (Junction *)zzaRet.left; altAdd(CurAltStart); /* MR7 */ p->altstart = CurAltStart; if ( label!=NULL ) { p->el_label = label->str; label->elem = (Node *)p; } } _retv = (Node *)p; } else { if ( (LA(1)==NonTerminal) ) { if ( old_not ) warn("~ NONTERMINAL is an undefined operation"); zzmatch(NonTerminal); zzaRet = buildRuleRef(LATEXT(1)); zzCONSUME; { zzBLOCK(zztasp3); zzMake0; { if ( (LA(1)==103) ) { zzmatch(103); q = (RuleRefNode *) ((Junction *)zzaRet.left)->p1; q->astnode=ASTexclude; zzCONSUME; } else { if ( (setwd7[LA(1)]&0x10) ) { } else {zzFAIL(1,zzerr38,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp3); } } { zzBLOCK(zztasp3); zzMake0; { if ( (setwd7[LA(1)]&0x20) ) { { zzBLOCK(zztasp4); zzMake0; { if ( (LA(1)==104) ) { zzmatch(104); zzCONSUME; } else { if ( (LA(1)==PassAction) ) { } else {zzFAIL(1,zzerr39,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp4); } } zzmatch(PassAction); addParm(((Junction *)zzaRet.left)->p1, LATEXT(1)); zzCONSUME; } else { if ( (setwd7[LA(1)]&0x40) ) { } else {zzFAIL(1,zzerr40,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp3); } } rr=(RuleRefNode *) ((Junction *)zzaRet.left)->p1; { zzBLOCK(zztasp3); zzMake0; { char *a; if ( (LA(1)==105) ) { zzmatch(105); zzCONSUME; zzmatch(PassAction); a = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char)); require(a!=NULL, "rule element: cannot allocate assignment"); strcpy(a, LATEXT(1)); rr->assign = a; zzCONSUME; } else { if ( (setwd7[LA(1)]&0x80) ) { } else {zzFAIL(1,zzerr41,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp3); } } if ( label!=NULL ) { rr->el_label = label->str; label->elem = (Node *)rr; } if ( first_on_line ) { CurAltStart = (Junction *)zzaRet.left; altAdd(CurAltStart); /* MR7 */ ((RuleRefNode *)((Junction *)zzaRet.left)->p1)->altstart = CurAltStart; } _retv = (Node *)rr; } else {zzFAIL(1,zzerr42,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } } } zzEXIT(zztasp2); } } } else { if ( (LA(1)==Action) ) { if ( old_not ) warn("~ ACTION is an undefined operation"); zzmatch(Action); zzaArg(zztasp1,0) = buildAction(LATEXT(1),action_file,action_line, 0); zzCONSUME; if ( first_on_line ) { /* MR7 */ CurAltStart = (Junction *)zzaArg(zztasp1,0 ).left; /* MR7 */ altAdd(CurAltStart); /* MR7 */ }; _retv = (Node *) ((Junction *)zzaArg(zztasp1,0 ).left)->p1; } else { if ( (LA(1)==Pred) ) { if ( old_not ) warn("~ SEMANTIC-PREDICATE is an undefined operation"); zzmatch(Pred); zzaArg(zztasp1,0) = buildAction(LATEXT(1),action_file,action_line, 1); zzCONSUME; act = (ActionNode *) ((Junction *)zzaArg(zztasp1,0 ).left)->p1; if (numericActionLabel) { /* MR10 */ list_add(&NumericPredLabels,act); /* MR10 */ numericActionLabel=0; /* MR10 */ }; /* MR10 */ { zzBLOCK(zztasp2); zzMake0; { char *a; if ( (LA(1)==PassAction) ) { zzmatch(PassAction); a = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char)); require(a!=NULL, "rule element: cannot allocate predicate fail action"); strcpy(a, LATEXT(1)); act->pred_fail = a; zzCONSUME; } else { if ( (setwd8[LA(1)]&0x1) ) { } else {zzFAIL(1,zzerr43,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } if ( first_on_line ) { /* MR7 */ CurAltStart = (Junction *)zzaArg(zztasp1,0 ).left; /* MR7 */ altAdd(CurAltStart); /* MR7 */ }; _retv = (Node *)act; } else { if ( (setwd8[LA(1)]&0x2) ) { if ( old_not ) warn("~ BLOCK is an undefined operation"); BlkLevel++; if (BlkLevel >= MAX_BLK_LEVEL) fatal("Blocks nested too deeply"); /* MR23 */ CurBlockID_array[BlkLevel] = CurBlockID; /* MR23 */ CurAltNum_array[BlkLevel] = CurAltNum; { zzBLOCK(zztasp2); zzMake0; { if ( (LA(1)==Pragma) ) { zzmatch(Pragma); zzCONSUME; { zzBLOCK(zztasp3); zzMake0; { if ( (LA(1)==126) ) { zzmatch(126); approx=LL_k; zzCONSUME; } else { if ( (LA(1)==127) ) { zzmatch(127); approx = 1; zzCONSUME; } else { if ( (LA(1)==128) ) { zzmatch(128); approx = 2; zzCONSUME; } else {zzFAIL(1,zzerr44,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } } zzEXIT(zztasp3); } } } else { if ( (setwd8[LA(1)]&0x4) ) { } else {zzFAIL(1,zzerr45,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } { zzBLOCK(zztasp2); zzMake0; { if ( (LA(1)==FirstSetSymbol) ) { zzmatch(FirstSetSymbol); zzCONSUME; zzmatch(114); zzCONSUME; { zzBLOCK(zztasp3); zzMake0; { if ( (LA(1)==NonTerminal) ) { zzmatch(NonTerminal); /* MR21 */ pFirstSetSymbol = (char *) calloc(strlen(LATEXT(1))+1, /* MR21 */ sizeof(char)); /* MR21 */ require(pFirstSetSymbol!=NULL, /* MR21 */ "cannot allocate first set name"); /* MR21 */ strcpy(pFirstSetSymbol, LATEXT(1)); /* MR21 */ zzCONSUME; } else { if ( (LA(1)==TokenTerm) ) { zzmatch(TokenTerm); /* MR21 */ pFirstSetSymbol = (char *) calloc(strlen(LATEXT(1))+1, /* MR21 */ sizeof(char)); /* MR21 */ require(pFirstSetSymbol!=NULL, /* MR21 */ "cannot allocate first set name"); /* MR21 */ strcpy(pFirstSetSymbol, LATEXT(1)); /* MR21 */ zzCONSUME; } else {zzFAIL(1,zzerr46,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp3); } } zzmatch(115); zzCONSUME; } else { if ( (setwd8[LA(1)]&0x8) ) { } else {zzFAIL(1,zzerr47,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } { zzBLOCK(zztasp2); zzMake0; { if ( (LA(1)==114) ) { zzmatch(114); zzCONSUME; block( &toksrefd,&rulesrefd ); zzmatch(115); blk = zzaRet = zzaArg(zztasp2,2); /* MR23 */ CurBlockID_array[BlkLevel] = (-1); /* MR23 */ CurAltNum_array[BlkLevel] = (-1); --BlkLevel; zzCONSUME; { zzBLOCK(zztasp3); zzMake0; { if ( (LA(1)==129) ) { zzmatch(129); zzaRet = makeLoop(zzaRet,approx,pFirstSetSymbol); zzCONSUME; } else { if ( (LA(1)==130) ) { zzmatch(130); zzaRet = makePlus(zzaRet,approx,pFirstSetSymbol); zzCONSUME; } else { if ( (LA(1)==131) ) { zzmatch(131); zzCONSUME; { zzBLOCK(zztasp4); zzMake0; { if ( (setwd8[LA(1)]&0x10) ) { { zzBLOCK(zztasp5); zzMake0; { if ( (LA(1)==132) ) { zzmatch(132); ampersandStyle=0; zzCONSUME; } else { if ( (LA(1)==113) ) { zzmatch(113); ampersandStyle=1; zzCONSUME; } else {zzFAIL(1,zzerr48,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp5); } } zzmatch(Pred); zzaRet = buildAction(LATEXT(1),action_file,action_line,1); zzCONSUME; act = (ActionNode *) ((Junction *)zzaRet.left)->p1; semDepth=predicateLookaheadDepth(act); if (numericActionLabel) { /* MR10 */ list_add(&NumericPredLabels,act); /* MR10 */ numericActionLabel=0; /* MR10 */ }; /* MR10 */ { zzBLOCK(zztasp5); zzMake0; { char *a; if ( (LA(1)==PassAction) ) { zzmatch(PassAction); a = (char *)calloc(strlen(LATEXT(1))+1, sizeof(char)); require(a!=NULL, "rule element: cannot allocate predicate fail action"); strcpy(a, LATEXT(1)); act->pred_fail = a; zzCONSUME; } else { if ( (setwd8[LA(1)]&0x20) ) { } else {zzFAIL(1,zzerr49,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp5); } } if ( first_on_line) { /* MR7 */ CurAltStart=(Junction *)zzaRet.left; /* MR7 */ altAdd(CurAltStart); /* MR7 */ }; _retv = (Node *)act; pred = computePredFromContextGuard(blk,&predMsgDone); /* MR10 */ if ( pred==NULL) { /* MR10 */ if ( !predMsgDone) err("invalid or missing context guard"); /* MR10 */ predMsgDone=1; /* MR10 */ } else { /* MR10 */ act->guardNodes=(Junction *)blk.left; /* MR11 */ pred->expr = act->action; pred->source = act; /* MR10 */ pred->ampersandStyle = ampersandStyle; /* 0 means (g)? => ... 1 means (g)? && ... */ /* MR13 */ if (pred->tcontext != NULL) { /* MR13 */ height=MR_max_height_of_tree(pred->tcontext); /* MR13 */ equal_height=MR_all_leaves_same_height(pred->tcontext,height); /* MR13 */ if (! equal_height) { /* MR13 */ errFL("in guarded predicates all tokens in the guard must be at the same height", /* MR13 */ FileStr[act->file],act->line); /* MR13 */ }; /* MR13 */ } /* MR10 */ if (ampersandStyle) { /* MR10 */ act->ampersandPred = pred; /* MR11 */ if (! HoistPredicateContext) { /* MR11 */ errFL("without \"-prc on\" (guard)? && <>? ... doesn't make sense", /* MR11 */ FileStr[act->file],act->line); /* MR11 */ }; /* MR10 */ } else { /* MR10 */ act->guardpred = pred; /* MR10 */ }; /* MR10 */ if (pred->k != semDepth) { /* MR10 */ warn(eMsgd2("length of guard (%d) does not match the length of semantic predicate (%d)", /* MR10 */ pred->k,semDepth)); /* MR10 */ }; } } else { if ( (setwd8[LA(1)]&0x40) ) { zzaRet = makeBlk(zzaRet,approx,pFirstSetSymbol); FoundGuessBlk = 1; ((Junction *) ((Junction *)zzaRet.left)->p1)->guess=1; if ( ! first_on_line ) { err("(...)? predicate must be first element of production"); } } else {zzFAIL(1,zzerr50,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp4); } } } else { if ( (setwd8[LA(1)]&0x80) ) { zzaRet = makeBlk(zzaRet,approx,pFirstSetSymbol); } else {zzFAIL(1,zzerr51,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } } } zzEXIT(zztasp3); } } if ( pred==NULL && !predMsgDone) { /* MR10 */ ((Junction *)((Junction *)zzaRet.left)->p1)->blockid = CurBlockID; ((Junction *)((Junction *)zzaRet.left)->p1)->tokrefs = toksrefd; ((Junction *)((Junction *)zzaRet.left)->p1)->rulerefs = rulesrefd; if ( first_on_line ) { /* MR7 */ CurAltStart = (Junction *)((Junction *)((Junction *)zzaRet.left)->p1); /* MR7 */ altAdd(CurAltStart); /* MR7 */ }; /* MR7 */ _retv = (Node *) ((Junction *)zzaRet.left)->p1; } } else { if ( (LA(1)==102) ) { zzmatch(102); zzCONSUME; block( &toksrefd,&rulesrefd ); zzaRet = makeOpt(zzaArg(zztasp2,2),approx,pFirstSetSymbol); /* MR23 */ CurBlockID_array[BlkLevel] = (-1); /* MR23 */ CurAltNum_array[BlkLevel] = (-1); --BlkLevel; zzmatch(98); ((Junction *)((Junction *)zzaRet.left)->p1)->blockid = CurBlockID; ((Junction *)((Junction *)zzaRet.left)->p1)->tokrefs = toksrefd; ((Junction *)((Junction *)zzaRet.left)->p1)->rulerefs = rulesrefd; zzCONSUME; if ( first_on_line ) { /* MR7 */ CurAltStart = (Junction *) ((Junction *)((Junction *)zzaRet.left)->p1); /* MR7 */ altAdd(CurAltStart); /* MR7 */ }; _retv = (Node *) ((Junction *)zzaRet.left)->p1; } else {zzFAIL(1,zzerr52,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } } else { if ( (LA(1)==129) ) { zzmatch(129); warn("don't you want a ')' with that '*'?"); CannotContinue=TRUE; zzCONSUME; } else { if ( (LA(1)==130) ) { zzmatch(130); warn("don't you want a ')' with that '+'?"); CannotContinue=TRUE; zzCONSUME; } else { if ( (LA(1)==105) ) { zzmatch(105); warn("'>' can only appear after a nonterminal"); CannotContinue=TRUE; zzCONSUME; } else { if ( (LA(1)==PassAction) ) { zzmatch(PassAction); warn("[...] out of context 'rule > [...]'"); CannotContinue=TRUE; zzCONSUME; } else {zzFAIL(1,zzerr53,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } } } } } } } zzEXIT(zztasp1); return _retv; fail: zzEXIT(zztasp1); CannotContinue=TRUE; zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd9, 0x1); return _retv; } } void #ifdef __USE_PROTOS default_exception_handler(void) #else default_exception_handler() #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { DefaultExGroup = exception_group(); zzEXIT(zztasp1); return; /* fail: */ zzEXIT(zztasp1); zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd9, 0x2); } } ExceptionGroup * #ifdef __USE_PROTOS exception_group(void) #else exception_group() #endif { ExceptionGroup * _retv; zzRULE; zzBLOCK(zztasp1); PCCTS_PURIFY(_retv,sizeof(ExceptionGroup * )) zzMake0; { ExceptionHandler *h; LabelEntry *label=NULL; /* MR6 */ FoundException = 1; FoundExceptionGroup = 1; zzmatch(133); _retv = (ExceptionGroup *)calloc(1, sizeof(ExceptionGroup)); zzCONSUME; { zzBLOCK(zztasp2); zzMake0; { char *p; if ( (LA(1)==PassAction) ) { zzmatch(PassAction); p = LATEXT(1)+1; p[strlen(p)-1] = '\0'; /* kill trailing space */ label = (LabelEntry *) hash_get(Elabel, LATEXT(1)+1); if ( label==NULL ) { err(eMsg1("unknown label in exception handler: '%s'", LATEXT(1)+1)); } zzCONSUME; } else { if ( (setwd9[LA(1)]&0x4) ) { } else {zzFAIL(1,zzerr54,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } { zzBLOCK(zztasp2); zzMake0; { while ( (LA(1)==135) ) { h = exception_handler(); list_add(&(_retv->handlers), (void *)h); zzLOOP(zztasp2); } zzEXIT(zztasp2); } } { zzBLOCK(zztasp2); zzMake0; { if ( (LA(1)==134) ) { zzmatch(134); zzCONSUME; zzmatch(106); zzCONSUME; zzmatch(Action); { ExceptionHandler *eh = (ExceptionHandler *) calloc(1, sizeof(ExceptionHandler)); char *a = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char)); require(eh!=NULL, "exception: cannot allocate handler"); require(a!=NULL, "exception: cannot allocate action"); strcpy(a, LATEXT(1)); eh->action = a; eh->signalname = (char *) calloc(strlen("default")+1, sizeof(char)); require(eh->signalname!=NULL, "exception: cannot allocate sig name"); strcpy(eh->signalname, "default"); list_add(&(_retv->handlers), (void *)eh); } zzCONSUME; } else { if ( (setwd9[LA(1)]&0x8) ) { } else {zzFAIL(1,zzerr55,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } if ( label!=NULL ) { /* Record ex group in sym tab for this label */ if ( label->ex_group!=NULL ) { err(eMsg1("duplicate exception handler for label '%s'",label->str)); } else { label->ex_group = _retv; /* Label the exception group itself */ _retv->label = label->str; /* Make the labelled element pt to the exception also */ /* MR6 */ if (label->elem == NULL) { /* MR6 */ err(eMsg1("reference in exception handler to undefined label '%s'",label->str)); /* MR6 */ } else { switch ( label->elem->ntype ) { case nRuleRef : { RuleRefNode *r = (RuleRefNode *)label->elem; r->ex_group = _retv; break; } case nToken : { TokNode *t = (TokNode *)label->elem; t->ex_group = _retv; break; } } /* end switch */ /* MR6 */ }; /* end test on label->elem */ } /* end test on label->ex_group */ } /* end test on exception label */ /* MR7 */ /* MR7 */ if (BlkLevel == 1 && label == NULL) { /* MR7 */ _retv->forRule=1; /* MR7 */ } else if (label == NULL) { /* MR7 */ _retv->altID = makeAltID(CurBlockID_array[BlkLevel], CurAltNum_array[BlkLevel]); /* MR7 */ egAdd(_retv); /* MR7 */ } else { /* MR7 */ _retv->labelEntry=label; /* MR7 */ }; /* MR7 */ /* MR7 */ /* You may want to remove this exc from the rule list */ /* MR7 */ /* and handle at the labeled element site. */ /* MR7 */ /* MR7 */ if (label != NULL) { /* MR7 */ _retv = NULL; /* MR7 */ }; zzEXIT(zztasp1); return _retv; fail: zzEXIT(zztasp1); CannotContinue=TRUE; zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd9, 0x10); return _retv; } } ExceptionHandler * #ifdef __USE_PROTOS exception_handler(void) #else exception_handler() #endif { ExceptionHandler * _retv; zzRULE; zzBLOCK(zztasp1); PCCTS_PURIFY(_retv,sizeof(ExceptionHandler * )) zzMake0; { ; zzmatch(135); _retv = (ExceptionHandler *)calloc(1, sizeof(ExceptionHandler)); require(_retv!=NULL, "exception: cannot allocate handler"); zzCONSUME; { zzBLOCK(zztasp2); zzMake0; { if ( (LA(1)==NonTerminal) ) { zzmatch(NonTerminal); _retv->signalname = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char)); require(_retv->signalname!=NULL, "exception: cannot allocate sig name"); strcpy(_retv->signalname, LATEXT(1)); zzCONSUME; } else { if ( (LA(1)==TokenTerm) ) { zzmatch(TokenTerm); _retv->signalname = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char)); require(_retv->signalname!=NULL, "exception: cannot allocate sig name"); strcpy(_retv->signalname, LATEXT(1)); zzCONSUME; } else {zzFAIL(1,zzerr56,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } zzmatch(106); zzCONSUME; { zzBLOCK(zztasp2); zzMake0; { _retv->action = NULL; if ( (LA(1)==Action) ) { zzmatch(Action); _retv->action = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char)); require(_retv->action!=NULL, "exception: cannot allocate action"); strcpy(_retv->action, LATEXT(1)); zzCONSUME; } else { if ( (setwd9[LA(1)]&0x20) ) { } else {zzFAIL(1,zzerr57,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } zzEXIT(zztasp1); return _retv; fail: zzEXIT(zztasp1); CannotContinue=TRUE; zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd9, 0x40); return _retv; } } void #ifdef __USE_PROTOS enum_file(char * fname) #else enum_file(fname) char *fname ; #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { if ( (setwd9[LA(1)]&0x80) ) { { zzBLOCK(zztasp2); zzMake0; { if ( (LA(1)==143) ) { zzmatch(143); zzCONSUME; zzmatch(ID); zzCONSUME; { zzBLOCK(zztasp3); zzMake0; { if ( (LA(1)==149) ) { zzmatch(149); zzCONSUME; zzmatch(ID); zzCONSUME; } else { if ( (setwd10[LA(1)]&0x1) ) { } else {zzFAIL(1,zzerr58,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp3); } } } else { if ( (setwd10[LA(1)]&0x2) ) { } else {zzFAIL(1,zzerr59,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } { zzBLOCK(zztasp2); zzMake0; { if ( (LA(1)==151) ) { { zzBLOCK(zztasp3); int zzcnt=1; zzMake0; { do { enum_def( fname ); zzLOOP(zztasp3); } while ( (LA(1)==151) ); zzEXIT(zztasp3); } } } else { if ( (LA(1)==149) ) { defines( fname ); } else {zzFAIL(1,zzerr60,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } } else { if ( (LA(1)==Eof) ) { } else {zzFAIL(1,zzerr61,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp1); return; fail: zzEXIT(zztasp1); zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd10, 0x4); } } void #ifdef __USE_PROTOS defines(char * fname) #else defines(fname) char *fname ; #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { int v; int maxt=(-1); char *t; { zzBLOCK(zztasp2); int zzcnt=1; zzMake0; { do { zzmatch(149); zzCONSUME; zzmatch(ID); t = mystrdup(LATEXT(1)); zzCONSUME; zzmatch(INT); v = atoi(LATEXT(1)); /* fprintf(stderr, "#token %s=%d\n", t, v);*/ /* MR2 Andreas Magnusson (Andreas.Magnusson@mailbox.swipnet.se) */ /* MR2 Fix to bug introduced by 1.33MR1 for #tokdefs */ /* MR2 Don't let #tokdefs be confused by */ /* MR2 DLGminToken and DLGmaxToken */ if ( ! isDLGmaxToken(t)) { /* MR2 */ TokenNum = v; if ( v>maxt ) maxt=v; if ( Tnum( t ) == 0 ) { addForcedTname( t, v ); } else { warnFL(eMsg1("redefinition of token %s; ignored",t), fname,zzline); }; }; zzCONSUME; zzLOOP(zztasp2); } while ( (LA(1)==149) ); zzEXIT(zztasp2); } } TokenNum = maxt + 1; zzEXIT(zztasp1); return; fail: zzEXIT(zztasp1); zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd10, 0x8); } } void #ifdef __USE_PROTOS enum_def(char * fname) #else enum_def(fname) char *fname ; #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { int v= 0; int maxt=(-1); char *t; zzmatch(151); zzCONSUME; zzmatch(ID); zzCONSUME; zzmatch(152); zzCONSUME; zzmatch(ID); t = mystrdup(LATEXT(1)); zzCONSUME; { zzBLOCK(zztasp2); zzMake0; { if ( (LA(1)==153) ) { zzmatch(153); zzCONSUME; zzmatch(INT); v=atoi(LATEXT(1)); zzCONSUME; } else { if ( (setwd10[LA(1)]&0x10) ) { v++; } else {zzFAIL(1,zzerr62,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } /* fprintf(stderr, "#token %s=%d\n", t, v);*/ TokenNum = v; if ( v>maxt ) maxt=v; /* MR3 */ if ( Tnum( t ) == 0 ) addForcedTname( t, v ); else { warnFL(eMsg1("redefinition of token %s; ignored",t), fname,zzline); } { zzBLOCK(zztasp2); zzMake0; { while ( (LA(1)==154) ) { zzmatch(154); zzCONSUME; { zzBLOCK(zztasp3); zzMake0; { if ( (LA(1)==ID)&&(isDLGmaxToken(LATEXT(1))) ) { if (!(isDLGmaxToken(LATEXT(1))) ) {zzfailed_pred(" isDLGmaxToken(LATEXT(1))",0 /* report */, { 0; /* no user action */ } );} zzmatch(ID); zzCONSUME; { zzBLOCK(zztasp4); zzMake0; { if ( (LA(1)==153) ) { zzmatch(153); zzCONSUME; zzmatch(INT); zzCONSUME; } else { if ( (setwd10[LA(1)]&0x20) ) { } else {zzFAIL(1,zzerr63,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp4); } } } else { if ( (LA(1)==ID) ) { zzmatch(ID); t = mystrdup(LATEXT(1)); zzCONSUME; { zzBLOCK(zztasp4); zzMake0; { if ( (LA(1)==153) ) { zzmatch(153); zzCONSUME; zzmatch(INT); v=atoi(LATEXT(1)); zzCONSUME; } else { if ( (setwd10[LA(1)]&0x40) ) { v++; } else {zzFAIL(1,zzerr64,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp4); } } /* fprintf(stderr, "#token %s=%d\n", t, v);*/ TokenNum = v; if ( v>maxt ) maxt=v; /* MR3 */ if ( Tnum( t ) == 0 ) addForcedTname( t, v ); else { warnFL(eMsg1("redefinition of token %s; ignored",t), fname,zzline); } } else { if ( (setwd10[LA(1)]&0x80) ) { } else {zzFAIL(1,zzerr65,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } } zzEXIT(zztasp3); } } zzLOOP(zztasp2); } zzEXIT(zztasp2); } } zzmatch(155); zzCONSUME; zzmatch(156); TokenNum = maxt + 1; zzCONSUME; zzEXIT(zztasp1); return; fail: zzEXIT(zztasp1); zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd11, 0x1); } } /* MR2 Andreas Magnusson (Andreas.Magnusson@mailbox.swipnet.se) */ /* MR2 Fix to bug introduced by 1.33MR1 for #tokdefs */ /* MR2 Don't let #tokdefs be confused by */ /* MR2 DLGminToken and DLGmaxToken */ /* semantic check on DLGminToken and DLGmaxmaxToken in #tokdefs */ #ifdef __USE_PROTOS static int isDLGmaxToken(char *Token) #else static int isDLGmaxToken(Token) char * Token; #endif { static char checkStr1[] = "DLGmaxToken"; static char checkStr2[] = "DLGminToken"; if (strcmp(Token, checkStr1) == 0) return 1; else if (strcmp(Token, checkStr2) == 0) return 1; else return 0; } /* semantics of #token */ static void #ifdef __USE_PROTOS chkToken(char *t, char *e, char *a, int tnum) #else chkToken(t,e,a,tnum) char *t, *e, *a; int tnum; #endif { TermEntry *p; /* check to see that they don't try to redefine a token as a token class */ if ( t!=NULL ) { p = (TermEntry *) hash_get(Tname, t); if ( p!=NULL && p->classname ) { err(eMsg1("redefinition of #tokclass '%s' to #token not allowed; ignored",t)); if ( a!=NULL ) free((char *)a); return; } } if ( t==NULL && e==NULL ) { /* none found */ err("#token requires at least token name or rexpr"); } else if ( t!=NULL && e!=NULL ) { /* both found */ if ( UserDefdTokens ) { /* if #tokdefs, must not define new */ p = (TermEntry *) hash_get(Tname, t); if ( p == NULL) { err(eMsg1("new token definition '%s' not allowed - only #token with name already defined by #tokdefs file allowed",t)); return; }; } Tklink(t, e); if ( a!=NULL ) { if ( hasAction(e) ) { err(eMsg1("redefinition of action for %s; ignored",e)); } else setHasAction(e, a); } } else if ( t!=NULL ) { /* only one found */ if ( UserDefdTokens ) { p = (TermEntry *) hash_get(Tname, t); if (p == NULL) { err(eMsg1("new token definition '%s' not allowed - only #token with name already defined by #tokdefs file allowed",t)); }; return; } if ( Tnum( t ) == 0 ) addTname( t ); else { err(eMsg1("redefinition of token %s; ignored",t)); } if ( a!=NULL ) { err(eMsg1("action cannot be attached to a token name (%s); ignored",t)); free((char *)a); } } else if ( e!=NULL ) { if ( Tnum( e ) == 0 ) addTexpr( e ); else { if ( hasAction(e) ) { err(eMsg1("redefinition of action for expr %s; ignored",e)); } else if ( a==NULL ) { err(eMsg1("redefinition of expr %s; ignored",e)); } } if ( a!=NULL ) setHasAction(e, a); } /* if a token type number was specified, then add the token ID and 'tnum' * pair to the ForcedTokens list. (only applies if an id was given) */ if ( t!=NULL && tnum>0 ) { if ( set_el(tnum, reserved_positions) ) { err(eMsgd("a token has already been forced to token number %d; ignored", tnum)); } else { list_add(&ForcedTokens, newForcedToken(t,tnum)); set_orel(tnum, &reserved_positions); } } } static int #ifdef __USE_PROTOS match_token(char *s, char **nxt) #else match_token(s,nxt) char *s; char **nxt; #endif { if ( !(*s>='A' && *s<='Z') ) return 0; s++; while ( (*s>='a' && *s<='z') || (*s>='A' && *s<='Z') || (*s>='0' && *s<='9') || *s=='_' ) { s++; } if ( *s!=' ' && *s!='}' ) return 0; *nxt = s; return 1; } static int #ifdef __USE_PROTOS match_rexpr(char *s, char **nxt) #else match_rexpr(s,nxt) char *s; char **nxt; #endif { if ( *s!='"' ) return 0; s++; while ( *s!='"' ) { if ( *s=='\n' || *s=='\r' ) /* MR13 */ warn("eoln found in regular expression"); if ( *s=='\\' ) s++; s++; } *nxt = s+1; return 1; } /* * Walk a string "{ A .. Z }" where A..Z is a space separated list * of token references (either labels or reg exprs). Return a * string "inlineX_set" for some unique integer X. Basically, * we pretend as if we had seen "#tokclass inlineX { A .. Z }" * on the input stream outside of an action. */ char * #ifdef __USE_PROTOS inline_set(char *s) #else inline_set(s) char *s; #endif { char *nxt; fprintf(stderr, "found consumeUntil( {...} )\n"); while ( *s==' ' || *s=='\t' || *s=='\n' || *s=='\r' ) {s++;} if ( *s!='{' ) { err("malformed consumeUntil( {...} ); missing '{'"); return "bad_set"; } s++; while ( *s==' ' || *s=='\t' || *s=='\n' || *s=='\r' ) {s++;} while ( *s!='}' ) { if ( match_token(s,&nxt) ) fprintf(stderr, "found token %s\n", s); else if ( match_rexpr(s,&nxt) ) fprintf(stderr, "found rexpr %s\n", s); else { err("invalid element in consumeUntil( {...} )"); return "bad_set"; } s = nxt; while ( *s==' ' || *s=='\t' || *s=='\n' || *s=='\r' ) {s++;} } return "inlineX_set"; } /* ANTLR-specific syntax error message generator * (define USER_ZZSYN when compiling so don't get 2 definitions) */ void #ifdef __USE_PROTOS zzsyn(char *text, int tok, char *egroup, SetWordType *eset, int etok, int k, char *bad_text) #else zzsyn(text, tok, egroup, eset, etok, k, bad_text) char *text, *egroup, *bad_text; int tok; int etok; int k; SetWordType *eset; #endif { fprintf(stderr, ErrHdr, FileStr[CurFile]!=NULL?FileStr[CurFile]:"stdin", zzline); fprintf(stderr, " syntax error at \"%s\"", (tok==zzEOF_TOKEN)?"EOF":text); if ( !etok && !eset ) {fprintf(stderr, "\n"); return;} if ( k==1 ) fprintf(stderr, " missing"); else { fprintf(stderr, "; \"%s\" not", bad_text); if ( zzset_deg(eset)>1 ) fprintf(stderr, " in"); } if ( zzset_deg(eset)>0 ) zzedecode(eset); else fprintf(stderr, " %s", zztokens[etok]); if ( strlen(egroup) > (size_t)0 ) fprintf(stderr, " in %s", egroup); fprintf(stderr, "\n"); } cdrdao-cdrdao-f00afb2/pccts/antlr/bits.c000066400000000000000000000661011511453746600202430ustar00rootroot00000000000000/* bits.c -- manage creation and output of bit sets used by the parser. * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2001 */ #include #include #include #include #include "pcctscfg.h" #include "set.h" #include "syn.h" #include "hash.h" #include "generic.h" #include "dlgdef.h" /* char is only thing that is pretty much always known == 8 bits * This allows output of antlr (set stuff, anyway) to be androgynous (portable) */ typedef unsigned char SetWordType; #define BitsPerByte 8 #define BitsPerWord BitsPerByte*sizeof(SetWordType) static SetWordType *setwd = NULL; int setnum = -1; int wordnum = 0; int esetnum = 0; /* Used to convert native wordsize, which ANTLR uses (via set.c) to manipulate sets, to bytes that are most portable size-wise. */ void #ifdef __USE_PROTOS DumpIntAsChars( FILE *f, char *format, unsigned wd ) #else DumpIntAsChars( f, format, wd ) FILE *f; char *format; unsigned wd; #endif { int i; /* uses max of 32 bit unsigned integer for the moment */ static unsigned long byte_mask[sizeof(unsigned long)] = { 0xFF, 0xFF00UL, 0xFF0000UL, 0xFF000000UL }; /* MR20 G. Hobbelt */ /* 0xFF00000000, 0xFF0000000000, 0xFF000000000000, 0xFF00000000000000 };*/ /* for each byte in the word */ assert(sizeof(unsigned) <= 4); /* M20 G. Hobbelt Sanity check */ for (i=0; i>(i*BitsPerByte)); if ( itok))); return empty; } r = RulePtr[q->rulenum]; r->end->halt = TRUE; /* don't let reach fall off end of rule here */ rk = empty; REACH(r, 1, &rk, a); r->end->halt = FALSE; return a; } /* * scan the list of tokens/eclasses/nonterminals filling the new eclass * with the set described by the list. Note that an eclass can be * quoted to allow spaces etc... However, an eclass must not conflict * with a reg expr found elsewhere. The reg expr will be taken over * the eclass name. */ static void #ifdef __USE_PROTOS doEclass( char *eclass ) #else doEclass( eclass ) char *eclass; #endif { TermEntry *q; ECnode *p; TCnode *tcnode; ListNode *e; unsigned int t; unsigned deg=0; set a; require(eclass!=NULL, "doEclass: NULL eset"); p = (ECnode *) eclass; lexmode(p->lexclass); /* switch to lexclass where errclass is defined */ p->eset = empty; for (e = (p->elist)->next; e!=NULL; e=e->next) { q = NULL; /* MR23 */ if ( islower( *((char *)e->elem) ) ) /* is it a rule ref? (alias FIRST request) */ { a = Efirst((char *)e->elem, p); set_orin(&p->eset, a); deg += set_deg(a); set_free( a ); continue; } else if ( *((char *)e->elem)=='"' ) { t = 0; q = (TermEntry *) hash_get(Texpr, (char *) e->elem); if ( q == NULL ) { /* if quoted and not an expr look for eclass name */ e->elem=(void *)StripQuotes((char *)e->elem); q = (TermEntry *) hash_get(Tname, (char *) e->elem); if ( q != NULL ) t = q->token; } else t = q->token; } else /* labelled token/eclass/tokclass */ { q = (TermEntry *) hash_get(Tname, (char *)e->elem); if ( q != NULL ) { if ( strcmp((char *)e->elem, TokenString(p->tok))==0 ) { warnNoFL(eMsg1("self-referential error class '%s'; ignored", (char *)e->elem)); continue; } else t = q->token; } else t=0; } if ( t!=0 ) { if (isTermEntryTokClass(q)) { /* MR23 */ tcnode = q->tclass; /* MR23 */ set_orin(&p->eset, tcnode->tset); /* MR23 */ deg = set_deg(p->eset); /* MR23 */ } /* MR23 */ else { set_orel(t, &p->eset); deg++; } } else warnNoFL(eMsg2("undefined token '%s' referenced in errclass '%s'; ignored", (char *)e->elem, TokenString(p->tok))); } p->setdeg = deg; } void #ifdef __USE_PROTOS ComputeErrorSets( void ) #else ComputeErrorSets( ) #endif { #ifdef __cplusplus list_apply(eclasses, (void (*)(void *)) doEclass); #else #ifdef __USE_PROTOS list_apply(eclasses, (void (*)(void *)) doEclass); #else list_apply(eclasses, doEclass); #endif #endif } void #ifdef __USE_PROTOS ComputeTokSets( void ) #else ComputeTokSets( ) #endif { ListNode *t, *e = NULL, *e1, *e2; int something_changed; int i; TCnode *p; TermEntry *q, *q1, *q2; if ( tclasses == NULL ) return; /* turn lists of token/tokclass references into sets */ for (t = tclasses->next; t!=NULL; t=t->next) { p = (TCnode *) t->elem; /* if wild card, then won't have entries in tclass, assume all_tokens */ if ( p->tok == WildCardToken ) { p->tset = set_dup(all_tokens); continue; } lexmode(p->lexclass); /* switch to lexclass where tokclass is defined */ p->tset = empty; /* instantiate all tokens/token_classes into the tset */ for (e = (p->tlist)->next; e!=NULL; e=e->next) { char *tokstr; tokstr = (char *)e->elem; if ( *tokstr == '"' ) { q = (TermEntry *) hash_get(Texpr, tokstr); require(q!=NULL, "ComputeTokSets: no token def"); set_orel(q->token, &p->tset); } else if (tokstr[0] == '.') { e1=e->next; e2=e1->next; e=e2; q1= (TermEntry *) hash_get(Tname, (char *)e1->elem); require(q1!=NULL, "ComputeTokSets: no token def"); q2= (TermEntry *) hash_get(Tname, (char *)e2->elem); require(q2!=NULL, "ComputeTokSets: no token def"); if (set_el(q1->token,imag_tokens)) { errNoFL(eMsg2("can't define #tokclass %s using #tokclass or #errclass %s", TokenString(p->tok),(char *)e1->elem) ); } if (set_el(q2->token,imag_tokens)) { errNoFL(eMsg2("can't define #tokclass %s using #tokclass or #errclass %s", TokenString(p->tok),(char *)e2->elem) ); } if (q1->token > q2->token) { errNoFL(eMsg3("for #tokclass %s %s..%s - first token number > second token number", TokenString(p->tok),(char *)e1->elem,(char *)e2->elem) ); for (i=q2->token; i<=q1->token; i++) { set_orel(i, &p->tset); } } else { for (i=q1->token; i<=q2->token; i++) { set_orel(i, &p->tset); } } } else { q = (TermEntry *) hash_get(Tname, tokstr); require(q!=NULL, "ComputeTokSets: no token def"); set_orel(q->token, &p->tset); } } } /* Go thru list of tokclasses again looking for tokclasses in sets */ again: something_changed = 0; for (t = tclasses->next; t!=NULL; t=t->next) { set tcl; p = (TCnode *) t->elem; tcl = set_and(p->tset, tokclasses); if ( !set_nil(tcl) ) { int tk; /* replace refs to tokclasses with the associated set of tokens */ something_changed = 1; while ( !set_nil(tcl) ) { tk = set_int(tcl); /* grab one of the tok class refs */ set_rm(tk, tcl); if ( p->tok != tk ) /* tokclass ref to yourself? */ { q = (TermEntry *) hash_get(Tname, TokenString(tk)); require(q!=NULL, "#tokclass not in hash table"); set_orin(&p->tset, q->tclass->tset); } set_rm(tk, p->tset); /* remove ref that we replaced */ } } set_free(tcl); } if ( something_changed ) goto again; } void #ifdef __USE_PROTOS DumpRemainingTokSets(void) #else DumpRemainingTokSets() #endif { TCnode *p; ListNode *t; /* Go thru tclasses (for the last time) and dump the sets not dumped * during code gen; yes, this is a bogus way to do this, but ComputeTokSets() * can't dump the defs as the error file and tok file has not been created * yet etc... */ if ( tclasses==NULL ) return; for (t = tclasses->next; t!=NULL; t=t->next) { unsigned e; p = (TCnode *) t->elem; if ( p->dumped ) continue; e = DefErrSet(&(p->tset), 0, TokenString(p->tok)); p->dumped = 1; p->setnum = e; } } /* replace a subset of an error set with an error class name if a subset is found * repeat process until no replacements made */ void #ifdef __USE_PROTOS SubstErrorClass( set *f ) #else SubstErrorClass( f ) set *f; #endif { int max, done = 0; ListNode *p; ECnode *ec, *maxclass = NULL; set a; require(f!=NULL, "SubstErrorClass: NULL eset"); if ( eclasses == NULL ) return; while ( !done ) { max = 0; maxclass = NULL; for (p=eclasses->next; p!=NULL; p=p->next) /* chk all error classes */ { ec = (ECnode *) p->elem; if ( ec->setdeg > max ) { if ( set_sub(ec->eset, *f) || set_equ(ec->eset, *f) ) {maxclass = ec; max=ec->setdeg;} } } if ( maxclass != NULL ) /* if subset found, replace with token */ { a = set_dif(*f, maxclass->eset); set_orel((unsigned)maxclass->tok, &a); set_free(*f); *f = a; } else done = 1; } } int #ifdef __USE_PROTOS DefErrSet1(int nilOK, set *f, int subst, char *name ) #else DefErrSet1(nilOK, f, subst, name ) int nilOK; set *f; int subst; /* should be substitute error classes? */ char *name; #endif { if ( GenCC ) return DefErrSetForCC1(nilOK, f, subst, name, "_set"); else return DefErrSetForC1(nilOK, f, subst, name, "_set"); } int #ifdef __USE_PROTOS DefErrSet( set *f, int subst, char *name ) #else DefErrSet( f, subst, name ) set *f; int subst; /* should be substitute error classes? */ char *name; #endif { return DefErrSet1(0,f,subst,name); } int #ifdef __USE_PROTOS DefErrSetWithSuffix(int nilOK, set *f, int subst, char *name, const char* suffix) #else DefErrSetWithSuffix(nilOK, f, subst, name, suffix ) int nilOK; set *f; int subst; /* should be substitute error classes? */ char *name; char *suffix; #endif { if ( GenCC ) return DefErrSetForCC1(nilOK, f, subst, name, suffix ); else return DefErrSetForC1(nilOK, f, subst, name, suffix); } /* Define a new error set. WARNING...set-implementation dependent. */ int #ifdef __USE_PROTOS DefErrSetForC1(int nilOK, set *f, int subst, char * name, const char * suffix) #else DefErrSetForC1(nilOK, f, subst, name, suffix) int nilOK; /* MR13 */ set *f; int subst; /* should be substitute error classes? */ char *name; const char *suffix; #endif { unsigned *p, *endp; int e=1; if (!nilOK) require(!set_nil(*f), "DefErrSetForC1: nil set to dump?"); if ( subst ) SubstErrorClass(f); p = f->setword; endp = &(f->setword[f->n]); esetnum++; if ( name!=NULL ) fprintf(DefFile, "extern SetWordType %s%s[];\n", name, suffix); else fprintf(DefFile, "extern SetWordType zzerr%d[];\n", esetnum); if ( name!=NULL ) { fprintf(ErrFile, "SetWordType %s%s[%lu] = {", name, suffix, NumWords(TokenNum-1)*sizeof(unsigned)); } else { fprintf(ErrFile, "SetWordType zzerr%d[%lu] = {", esetnum, NumWords(TokenNum-1)*sizeof(unsigned)); } while ( p < endp ) { if ( e > 1 ) fprintf(ErrFile, ", "); DumpIntAsChars(ErrFile, "0x%x", *p++); if ( e == 3 ) { DAWDLE; if ( p < endp ) fprintf(ErrFile, ","); fprintf(ErrFile, "\n\t"); e=1; } else e++; } fprintf(ErrFile, "};\n"); return esetnum; } int #ifdef __USE_PROTOS DefErrSetForC( set *f, int subst, char *name ) #else DefErrSetForC( f, subst, name ) set *f; int subst; /* should be substitute error classes? */ char *name; #endif { return DefErrSetForC1(0,f,subst,name, "_set"); } /* Define a new error set. WARNING...set-implementation dependent; * Only used when -CC on. */ int #ifdef __USE_PROTOS DefErrSetForCC1(int nilOK, set *f, int subst, char *name, const char *suffix ) #else DefErrSetForCC1(nilOK, f, subst, name, suffix ) int nilOK; /* MR13 */ set *f; int subst; /* should be substitute error classes? */ char *name; const char *suffix; #endif { unsigned *p, *endp; int e=1; if (!nilOK) require(!set_nil(*f), "DefErrSetForCC1: nil set to dump?"); if ( subst ) SubstErrorClass(f); p = f->setword; endp = &(f->setword[f->n]); esetnum++; if ( name!=NULL ) { fprintf(Parser_h, "\tstatic SetWordType %s%s[%lu];\n", name, suffix, NumWords(TokenNum-1)*sizeof(unsigned)); fprintf(Parser_c, "SetWordType %s::%s%s[%lu] = {", CurrentClassName, name, suffix, NumWords(TokenNum-1)*sizeof(unsigned)); } else { fprintf(Parser_c, "SetWordType %s::err%d[%lu] = {", CurrentClassName, esetnum, NumWords(TokenNum-1)*sizeof(unsigned)); fprintf(Parser_h, "\tstatic SetWordType err%d[%lu];\n", esetnum, NumWords(TokenNum-1)*sizeof(unsigned)); } while ( p < endp ) { if ( e > 1 ) fprintf(Parser_c, ", "); DumpIntAsChars(Parser_c, "0x%x", *p++); if ( e == 3 ) { if ( p < endp ) fprintf(Parser_c, ","); fprintf(Parser_c, "\n\t"); e=1; } else e++; } fprintf(Parser_c, "};\n"); return esetnum; } int #ifdef __USE_PROTOS DefErrSetForCC( set *f, int subst, char *name ) #else DefErrSetForCC( f, subst, name ) set *f; int subst; /* should be substitute error classes? */ char *name; #endif { return DefErrSetForCC1(0,f,subst,name, "_set"); } void #ifdef __USE_PROTOS GenParser_c_Hdr(void) #else GenParser_c_Hdr() #endif { int i,j; TermEntry *te; char * hasAkaName = NULL; /* MR23 */ hasAkaName = (char *) malloc(TokenNum+1); /* MR23 */ require(hasAkaName!=NULL, "Cannot alloc hasAkaName\n"); /* MR23 */ for (i = 0; i < TokenNum; i++) hasAkaName[i]='0'; /* MR23 */ hasAkaName[TokenNum] = 0; /* MR23 */ fprintf(Parser_c, "/*\n"); fprintf(Parser_c, " * %s: P a r s e r S u p p o r t\n", CurrentClassName); fprintf(Parser_c, " *\n"); fprintf(Parser_c, " * Generated from:"); for (i=0; i=LastTokenCounted ) { fprintf(Parser_c, ",\n\t/* %02d */\t\"invalid\"", i); continue; } if ( TokenString(i) != NULL ) { te=(TermEntry *) hash_get(Tname,TokenString(i)); /* MR11 */ if (te == NULL || te->akaString == NULL) { /* MR11 */ fprintf(Parser_c, ",\n\t/* %02d */\t\"%s\"", i, TokenString(i)); } else { hasAkaName[i] = '1'; /* MR23 */ fprintf(Parser_c, ",\n\t/* %02d */\t\"%s\"", i, te->akaString); /* MR11 */ } } else { /* look in all lexclasses for the reg expr */ for (j=0; j=NumLexClasses ) { if ( UserDefdTokens ) { fprintf(Parser_c, ",\n\t/* %02d */\t\"\"", i); } else fatal_internal(eMsgd("No label or expr for token %d",i)); } } } fprintf(Parser_c, "\n};\n"); /* Build constructors */ fprintf(Parser_c, "\n%s::", CurrentClassName); fprintf(Parser_c, "%s(ANTLRTokenBuffer *input) : %s(input,%d,%d,%d,%lu)\n", CurrentClassName, (BaseClassName == NULL ? "ANTLRParser" : BaseClassName), OutputLL_k, FoundGuessBlk, DemandLookahead, NumWords(TokenNum-1)*sizeof(unsigned)); fprintf(Parser_c, "{\n"); fprintf(Parser_c, "\ttoken_tbl = _token_tbl;\n"); if (TraceGen) { fprintf(Parser_c, "\ttraceOptionValueDefault=1;\t\t// MR10 turn trace ON\n"); } else { fprintf(Parser_c, "\ttraceOptionValueDefault=0;\t\t// MR10 turn trace OFF\n"); }; fprintf(Parser_c, "}\n\n"); free ( (void *) hasAkaName); } void #ifdef __USE_PROTOS GenParser_h_Hdr(void) #else GenParser_h_Hdr() #endif { int i; fprintf(Parser_h, "/*\n"); fprintf(Parser_h, " * %s: P a r s e r H e a d e r \n", CurrentClassName); fprintf(Parser_h, " *\n"); fprintf(Parser_h, " * Generated from:"); for (i=0; i 1 ) fprintf(ErrFile, "#define LL_K %d\n", OutputLL_k); #ifdef DUM if ( LexGen ) fprintf(ErrFile, "#define zzEOF_TOKEN %d\n", (TokenInd!=NULL?TokenInd[EofToken]:EofToken)); #endif fprintf(ErrFile, "#define zzSET_SIZE %lu\n", NumWords(TokenNum-1)*sizeof(unsigned)); if ( DemandLookahead ) fprintf(ErrFile, "#define DEMAND_LOOK\n"); fprintf(ErrFile, "#include \"antlr.h\"\n"); if ( GenAST ) fprintf(ErrFile, "#include \"ast.h\"\n"); if ( UserDefdTokens ) fprintf(ErrFile, "#include %s\n", UserTokenDefsFile); /* still need this one as it has the func prototypes */ fprintf(ErrFile, "#include \"%s\"\n", DefFileName); fprintf(ErrFile, "#include \"dlgdef.h\"\n"); fprintf(ErrFile, "#include \"err.h\"\n\n"); /* Dump a zztokens for each automaton */ if ( strcmp(ParserName, DefaultParserName)!=0 ) { fprintf(ErrFile, "ANTLRChar *%s_zztokens[%d]={\n", ParserName, TokenNum-1); } else { fprintf(ErrFile, "ANTLRChar *zztokens[%d]={\n", TokenNum-1); } fprintf(ErrFile, "\t/* 00 */\t\"Invalid\""); for (i=1; i=LastTokenCounted ) { fprintf(ErrFile, ",\n\t/* %02d */\t\"invalid\"", i); continue; } if ( TokenString(i) != NULL ) { te=(TermEntry *) hash_get(Tname,TokenString(i)); /* MR11 */ if (te == NULL || te->akaString == NULL) { /* MR11 */ fprintf(ErrFile, ",\n\t/* %02d */\t\"%s\"", i, TokenString(i)); } else { fprintf(ErrFile, ",\n\t/* %02d */\t\"%s\"", i, te->akaString); /* MR11 */ } } else { /* look in all lexclasses for the reg expr */ for (j=0; j=NumLexClasses ) { if ( UserDefdTokens ) { fprintf(ErrFile, ",\n\t/* %02d */\t\"\"", i); } else fatal_internal(eMsgd("No label or expr for token %d",i)); } } } fprintf(ErrFile, "\n};\n"); } void #ifdef __USE_PROTOS dumpExpr( FILE *f, char *e ) #else dumpExpr( f, e ) FILE *f; char *e; #endif { while ( *e!='\0' ) { if ( *e=='\\' && *(e+1)=='\\' ) {putc('\\', f); putc('\\', f); e+=2;} else if ( *e=='\\' && *(e+1)=='"' ) {putc('\\', f); putc('"', f); e+=2;} else if ( *e=='\\' ) {putc('\\', f); putc('\\', f); e++;} else {putc(*e, f); e++;} } } int #ifdef __USE_PROTOS isTermEntryTokClass(TermEntry *te) #else isTermEntryTokClass(te) TermEntry *te; #endif { ListNode *t; TCnode *p; TermEntry *q; char *tokstr; if (tclasses == NULL) return 0; for (t = tclasses->next; t!=NULL; t=t->next) { p = (TCnode *) t->elem; tokstr = TokenString(p->tok); lexmode(p->lexclass); /* switch to lexclass where tokclass is defined */ q = (TermEntry *) hash_get(Tname, tokstr); if (q == te) return 1; } return 0; } cdrdao-cdrdao-f00afb2/pccts/antlr/build.c000066400000000000000000000476671511453746600204210ustar00rootroot00000000000000/* * build.c -- functions associated with building syntax diagrams. * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2001 */ #include #include #include #include "pcctscfg.h" #include "set.h" #include "syn.h" #include "hash.h" #include "generic.h" #include "dlgdef.h" #define SetBlk(g, t, approx, first_set_symbol) { \ ((Junction *)g.left)->jtype = t; \ ((Junction *)g.left)->approx = approx; \ ((Junction *)g.left)->pFirstSetSymbol = first_set_symbol; \ ((Junction *)g.left)->end = (Junction *) g.right; \ ((Junction *)g.right)->jtype = EndBlk;} /* Add the parameter string 'parm' to the parms field of a block-type junction * g.left points to the sentinel node on a block. i.e. g.left->p1 points to * the actual junction with its jtype == some block-type. */ void #ifdef __USE_PROTOS addParm( Node *p, char *parm ) #else addParm( p, parm ) Node *p; char *parm; #endif { char *q = (char *) malloc( strlen(parm) + 1 ); require(p!=NULL, "addParm: NULL object\n"); require(q!=NULL, "addParm: unable to alloc parameter\n"); strcpy(q, parm); if ( p->ntype == nRuleRef ) { ((RuleRefNode *)p)->parms = q; } else if ( p->ntype == nJunction ) { ((Junction *)p)->parm = q; /* only one parameter allowed on subrules */ } else fatal_internal("addParm: invalid node for adding parm"); } /* * Build an action node for the syntax diagram * * buildAction(ACTION) ::= --o-->ACTION-->o-- * * Where o is a junction node. */ Graph #ifdef __USE_PROTOS buildAction( char *action, int file, int line, int is_predicate ) #else buildAction( action, file, line, is_predicate ) char *action; int file; int line; int is_predicate; #endif { Junction *j1, *j2; Graph g; ActionNode *a; require(action!=NULL, "buildAction: invalid action"); j1 = newJunction(); j2 = newJunction(); a = newActionNode(); a->action = (char *) malloc( strlen(action)+1 ); require(a->action!=NULL, "buildAction: cannot alloc space for action\n"); strcpy(a->action, action); j1->p1 = (Node *) a; a->next = (Node *) j2; a->is_predicate = is_predicate; if (is_predicate) { PredEntry *predEntry; char *t; char *key; char *u; int inverted=0; t=key=(char *)calloc(1,strlen(a->action)+1); for (u=a->action; *u != '\0' ; u++) { if (*u != ' ') { if (t==key && *u=='!') { inverted=!inverted; } else { *t++=*u; }; }; }; *t='\0'; predEntry=(PredEntry *)hash_get(Pname,key); a->predEntry=predEntry; if (predEntry != NULL) a->inverted=inverted; } else { /* MR12c */ char *strStart=a->action; /* MR12c */ char *strEnd; /* MR12c */ strEnd=strStart+strlen(strStart)-1; /* MR12c */ for ( ; strEnd >= strStart && isspace(*strEnd); strEnd--) *strEnd=0; /* MR12c */ while (*strStart != '\0' && isspace(*strStart)) strStart++; /* MR12c */ if (ci_strequ(strStart,"nohoist")) { /* MR12c */ a->noHoist=1; /* MR12c */ } } g.left = (Node *) j1; g.right = (Node *) j2; a->file = file; a->line = line; a->rname = CurRule; /* MR10 */ return g; } /* * Build a token node for the syntax diagram * * buildToken(TOKEN) ::= --o-->TOKEN-->o-- * * Where o is a junction node. */ Graph #ifdef __USE_PROTOS buildToken( char *text ) #else buildToken( text ) char *text; #endif { Junction *j1, *j2; Graph g; TokNode *t; require(text!=NULL, "buildToken: invalid token name"); j1 = newJunction(); j2 = newJunction(); t = newTokNode(); t->altstart = CurAltStart; if ( *text == '"' ) {t->label=FALSE; t->token = addTexpr( text );} else {t->label=TRUE; t->token = addTname( text );} j1->p1 = (Node *) t; t->next = (Node *) j2; g.left = (Node *) j1; g.right = (Node *) j2; return g; } /* * Build a wild-card node for the syntax diagram * * buildToken(TOKEN) ::= --o-->'.'-->o-- * * Where o is a junction node. */ Graph #ifdef __USE_PROTOS buildWildCard( char *text ) #else buildWildCard( text ) char *text; #endif { Junction *j1, *j2; Graph g; TokNode *t; TCnode *w; TermEntry *p; require(text!=NULL, "buildWildCard: invalid token name"); j1 = newJunction(); j2 = newJunction(); t = newTokNode(); /* If the ref a wild card, make a token class for it */ if ( Tnum(WildCardString) == 0 ) { w = newTCnode; w->tok = addTname( WildCardString ); set_orel(w->tok, &imag_tokens); set_orel(w->tok, &tokclasses); WildCardToken = w->tok; require((p=(TermEntry *)hash_get(Tname, WildCardString)) != NULL, "hash table mechanism is broken"); p->classname = 1; /* entry is class name, not token */ p->tclass = w; /* save ptr to this tclass def */ list_add(&tclasses, (char *)w); } else { p=(TermEntry *)hash_get(Tname, WildCardString); require( p!= NULL, "hash table mechanism is broken"); w = p->tclass; } t->token = w->tok; t->wild_card = 1; t->tclass = w; t->altstart = CurAltStart; j1->p1 = (Node *) t; t->next = (Node *) j2; g.left = (Node *) j1; g.right = (Node *) j2; return g; } void #ifdef __USE_PROTOS setUpperRange(TokNode *t, char *text) #else setUpperRange(t, text) TokNode *t; char *text; #endif { require(t!=NULL, "setUpperRange: NULL token node"); require(text!=NULL, "setUpperRange: NULL token string"); if ( *text == '"' ) {t->upper_range = addTexpr( text );} else {t->upper_range = addTname( text );} } /* * Build a rule reference node of the syntax diagram * * buildRuleRef(RULE) ::= --o-->RULE-->o-- * * Where o is a junction node. * * If rule 'text' has been defined already, don't alloc new space to store string. * Set r->text to point to old copy in string table. */ Graph #ifdef __USE_PROTOS buildRuleRef( char *text ) #else buildRuleRef( text ) char *text; #endif { Junction *j1, *j2; Graph g; RuleRefNode *r; RuleEntry *p; require(text!=NULL, "buildRuleRef: invalid rule name"); j1 = newJunction(); j2 = newJunction(); r = newRNode(); r->altstart = CurAltStart; r->assign = NULL; if ( (p=(RuleEntry *)hash_get(Rname, text)) != NULL ) r->text = p->str; else r->text = mystrdup( text ); j1->p1 = (Node *) r; r->next = (Node *) j2; g.left = (Node *) j1; g.right = (Node *) j2; return g; } /* * Or two subgraphs into one graph via: * * Or(G1, G2) ::= --o-G1-o-- * | ^ * v | * o-G2-o * * Set the altnum of junction starting G2 to 1 + altnum of junction starting G1. * If, however, the G1 altnum is 0, make it 1 and then * make G2 altnum = G1 altnum + 1. */ Graph #ifdef __USE_PROTOS Or( Graph g1, Graph g2 ) #else Or( g1, g2 ) Graph g1; Graph g2; #endif { Graph g; require(g1.left != NULL, "Or: invalid graph"); require(g2.left != NULL && g2.right != NULL, "Or: invalid graph"); ((Junction *)g1.left)->p2 = g2.left; ((Junction *)g2.right)->p1 = g1.right; /* set altnums */ if ( ((Junction *)g1.left)->altnum == 0 ) ((Junction *)g1.left)->altnum = 1; ((Junction *)g2.left)->altnum = ((Junction *)g1.left)->altnum + 1; g.left = g2.left; g.right = g1.right; return g; } /* * Catenate two subgraphs * * Cat(G1, G2) ::= --o-G1-o-->o-G2-o-- * Cat(NULL,G2)::= --o-G2-o-- * Cat(G1,NULL)::= --o-G1-o-- */ Graph #ifdef __USE_PROTOS Cat( Graph g1, Graph g2 ) #else Cat( g1, g2 ) Graph g1; Graph g2; #endif { Graph g; if ( g1.left == NULL && g1.right == NULL ) return g2; if ( g2.left == NULL && g2.right == NULL ) return g1; ((Junction *)g1.right)->p1 = g2.left; g.left = g1.left; g.right = g2.right; return g; } /* * Make a subgraph an optional block * * makeOpt(G) ::= --o-->o-G-o-->o-- * | ^ * v | * o-------o * * Note that this constructs {A|B|...|Z} as if (A|B|...|Z|) was found. * * The node on the far right is added so that every block owns its own * EndBlk node. */ Graph #ifdef __USE_PROTOS makeOpt( Graph g1, int approx, char * pFirstSetSymbol ) #else makeOpt( g1, approx, pFirstSetSymbol ) Graph g1; int approx; char * pFirstSetSymbol; #endif { Junction *j1,*j2,*p; Graph g; require(g1.left != NULL && g1.right != NULL, "makeOpt: invalid graph"); j1 = newJunction(); j2 = newJunction(); ((Junction *)g1.right)->p1 = (Node *) j2; /* add node to G at end */ /* MR21 * * There is code in genBlk which recognizes the node created * by emptyAlt() as a special case and bypasses it. We don't * want this to happen for the optBlk. */ g = emptyAlt3(); /* MR21 */ if ( ((Junction *)g1.left)->altnum == 0 ) ((Junction *)g1.left)->altnum = 1; ((Junction *)g.left)->altnum = ((Junction *)g1.left)->altnum + 1; for(p=(Junction *)g1.left; p->p2!=NULL; p=(Junction *)p->p2) {;} /* find last alt */ p->p2 = g.left; /* add optional alternative */ ((Junction *)g.right)->p1 = (Node *)j2; /* opt alt points to EndBlk */ g1.right = (Node *)j2; SetBlk(g1, aOptBlk, approx, pFirstSetSymbol); j1->p1 = g1.left; /* add generic node in front */ g.left = (Node *) j1; g.right = g1.right; return g; } /* * Make a graph into subblock * * makeBlk(G) ::= --o-->o-G-o-->o-- * * The node on the far right is added so that every block owns its own * EndBlk node. */ Graph #ifdef __USE_PROTOS makeBlk( Graph g1, int approx, char * pFirstSetSymbol ) #else makeBlk( g1, approx, pFirstSetSymbol ) Graph g1; int approx; char * pFirstSetSymbol; #endif { Junction *j,*j2; Graph g; require(g1.left != NULL && g1.right != NULL, "makeBlk: invalid graph"); j = newJunction(); j2 = newJunction(); ((Junction *)g1.right)->p1 = (Node *) j2; /* add node to G at end */ g1.right = (Node *)j2; SetBlk(g1, aSubBlk, approx, pFirstSetSymbol); j->p1 = g1.left; /* add node in front */ g.left = (Node *) j; g.right = g1.right; return g; } /* * Make a subgraph into a loop (closure) block -- (...)* * * makeLoop(G) ::= |---| * v | * --o-->o-->o-G-o-->o-- * | ^ * v | * o-----------o * * After making loop, always place generic node out front. It becomes * the start of enclosing block. The aLoopBlk is the target of the loop. * * Loop blks have TWO EndBlk nodes--the far right and the node that loops back * to the aLoopBlk node. Node with which we can branch past loop == aLoopBegin and * one which is loop target == aLoopBlk. * The branch-past (initial) aLoopBegin node has end * pointing to the last EndBlk node. The loop-target node has end==NULL. * * Loop blocks have a set of locks (from 1..CLL_k) on the aLoopBlk node. */ Graph #ifdef __USE_PROTOS makeLoop( Graph g1, int approx, char * pFirstSetSymbol ) #else makeLoop( g1, approx, pFirstSetSymbol) Graph g1; int approx; char * pFirstSetSymbol; #endif { Junction *back, *front, *begin; Graph g; require(g1.left != NULL && g1.right != NULL, "makeLoop: invalid graph"); back = newJunction(); front = newJunction(); begin = newJunction(); g = emptyAlt3(); ((Junction *)g1.right)->p2 = g1.left; /* add loop branch to G */ ((Junction *)g1.right)->p1 = (Node *) back; /* add node to G at end */ ((Junction *)g1.right)->jtype = EndBlk; /* mark 1st EndBlk node */ ((Junction *)g1.left)->jtype = aLoopBlk; /* mark 2nd aLoopBlk node */ ((Junction *)g1.left)->end = (Junction *) g1.right; ((Junction *)g1.left)->lock = makelocks(); ((Junction *)g1.left)->pred_lock = makelocks(); g1.right = (Node *) back; begin->p1 = (Node *) g1.left; g1.left = (Node *) begin; begin->p2 = (Node *) g.left; /* make bypass arc */ ((Junction *)g.right)->p1 = (Node *) back; SetBlk(g1, aLoopBegin, approx, pFirstSetSymbol); front->p1 = g1.left; /* add node to front */ g1.left = (Node *) front; return g1; } /* * Make a subgraph into a plus block -- (...)+ -- 1 or more times * * makePlus(G) ::= |---| * v | * --o-->o-G-o-->o-- * * After making loop, always place generic node out front. It becomes * the start of enclosing block. The aPlusBlk is the target of the loop. * * Plus blks have TWO EndBlk nodes--the far right and the node that loops back * to the aPlusBlk node. * * Plus blocks have a set of locks (from 1..CLL_k) on the aPlusBlk node. */ Graph #ifdef __USE_PROTOS makePlus( Graph g1, int approx, char * pFirstSetSymbol) #else makePlus( g1, approx, pFirstSetSymbol) Graph g1; int approx; char * pFirstSetSymbol; #endif { int has_empty_alt_already = 0; Graph g; Junction *j2, *j3, *first_alt; Junction *last_alt=NULL, *p; require(g1.left != NULL && g1.right != NULL, "makePlus: invalid graph"); first_alt = (Junction *)g1.left; j2 = newJunction(); j3 = newJunction(); if ( ((Junction *)g1.left)->altnum == 0 ) ((Junction *)g1.left)->altnum = 1; ((Junction *)g1.right)->p2 = g1.left; /* add loop branch to G */ ((Junction *)g1.right)->p1 = (Node *) j2; /* add node to G at end */ ((Junction *)g1.right)->jtype = EndBlk; /* mark 1st EndBlk node */ g1.right = (Node *) j2; SetBlk(g1, aPlusBlk, approx, pFirstSetSymbol); ((Junction *)g1.left)->lock = makelocks(); ((Junction *)g1.left)->pred_lock = makelocks(); j3->p1 = g1.left; /* add node to front */ g1.left = (Node *) j3; /* add an optional branch which is the "exit" branch of loop */ /* FIRST, check to ensure that there does not already exist * an optional path. */ /* find last alt */ for(p=first_alt; p!=NULL; p=(Junction *)p->p2) { if ( p->p1->ntype == nJunction && p->p1!=NULL && ((Junction *)p->p1)->jtype==Generic && ((Junction *)p->p1)->p1!=NULL && ((Junction *)((Junction *)p->p1)->p1)->jtype==EndBlk ) { has_empty_alt_already = 1; } last_alt = p; } if ( !has_empty_alt_already ) { require(last_alt!=NULL, "last_alt==NULL; bad (..)+"); g = emptyAlt(); last_alt->p2 = g.left; ((Junction *)g.right)->p1 = (Node *) j2; /* make sure lookahead computation ignores this alt for * FIRST("(..)+"); but it's still used for computing the FIRST * of each alternative. */ ((Junction *)g.left)->ignore = 1; } return g1; } /* * Return an optional path: --o-->o-- */ Graph #ifdef __USE_PROTOS emptyAlt( void ) #else emptyAlt( ) #endif { Junction *j1, *j2; Graph g; j1 = newJunction(); j2 = newJunction(); j1->p1 = (Node *) j2; g.left = (Node *) j1; g.right = (Node *) j2; return g; } /* MR21 * * There is code in genBlk which recognizes the node created * by emptyAlt() as a special case and bypasses it. We don't * want this to happen for the optBlk. */ Graph #ifdef __USE_PROTOS emptyAlt3( void ) #else emptyAlt3( ) #endif { Junction *j1, *j2, *j3; Graph g; j1 = newJunction(); j2 = newJunction(); j3 = newJunction(); j1->p1 = (Node *) j2; j2->p1 = (Node *) j3; g.left = (Node *) j1; g.right = (Node *) j3; return g; } /* N o d e A l l o c a t i o n */ TokNode * #ifdef __USE_PROTOS newTokNode( void ) #else newTokNode( ) #endif { static TokNode *FreeList = NULL; TokNode *p, *newblk; if ( FreeList == NULL ) { newblk = (TokNode *)calloc(TokenBlockAllocSize, sizeof(TokNode)); if ( newblk == NULL ) fatal_internal(eMsg1("out of memory while building rule '%s'",CurRule)); for (p=newblk; p<&(newblk[TokenBlockAllocSize]); p++) { p->next = (Node *)FreeList; /* add all new token nodes to FreeList */ FreeList = p; } } p = FreeList; FreeList = (TokNode *)FreeList->next;/* remove a TokNode node */ p->next = NULL; /* NULL the ptr we used */ memset( (char *) p, 0, sizeof(TokNode)); /* MR10 */ p->ntype = nToken; p->rname = CurRule; p->file = CurFile; p->line = zzline; p->altstart = NULL; return p; } RuleRefNode * #ifdef __USE_PROTOS newRNode( void ) #else newRNode( ) #endif { static RuleRefNode *FreeList = NULL; RuleRefNode *p, *newblk; if ( FreeList == NULL ) { newblk = (RuleRefNode *)calloc(RRefBlockAllocSize, sizeof(RuleRefNode)); if ( newblk == NULL ) fatal_internal(eMsg1("out of memory while building rule '%s'",CurRule)); for (p=newblk; p<&(newblk[RRefBlockAllocSize]); p++) { p->next = (Node *)FreeList; /* add all new rref nodes to FreeList */ FreeList = p; } } p = FreeList; FreeList = (RuleRefNode *)FreeList->next;/* remove a Junction node */ p->next = NULL; /* NULL the ptr we used */ memset( (char *) p, 0, sizeof(RuleRefNode)); /* MR10 */ p->ntype = nRuleRef; p->rname = CurRule; p->file = CurFile; p->line = zzline; p->astnode = ASTinclude; p->altstart = NULL; return p; } static int junctionSeqNumber=0; /* MR10 */ Junction * #ifdef __USE_PROTOS newJunction( void ) #else newJunction( ) #endif { static Junction *FreeList = NULL; Junction *p, *newblk; if ( FreeList == NULL ) { newblk = (Junction *)calloc(JunctionBlockAllocSize, sizeof(Junction)); if ( newblk == NULL ) fatal_internal(eMsg1("out of memory while building rule '%s'",CurRule)); for (p=newblk; p<&(newblk[JunctionBlockAllocSize]); p++) { p->p1 = (Node *)FreeList; /* add all new Junction nodes to FreeList */ FreeList = p; } } p = FreeList; FreeList = (Junction *)FreeList->p1;/* remove a Junction node */ p->p1 = NULL; /* NULL the ptr we used */ memset( (char *) p, 0, sizeof(Junction)); /* MR10 */ p->ntype = nJunction; p->visited = 0; p->jtype = Generic; p->rname = CurRule; p->file = CurFile; p->line = zzline; p->exception_label = NULL; p->fset = (set *) calloc(CLL_k+1, sizeof(set)); require(p->fset!=NULL, "cannot allocate fset in newJunction"); p->seq=++junctionSeqNumber; /* MR10 */ return p; } ActionNode * #ifdef __USE_PROTOS newActionNode( void ) #else newActionNode( ) #endif { static ActionNode *FreeList = NULL; ActionNode *p, *newblk; if ( FreeList == NULL ) { newblk = (ActionNode *)calloc(ActionBlockAllocSize, sizeof(ActionNode)); if ( newblk == NULL ) fatal_internal(eMsg1("out of memory while building rule '%s'",CurRule)); for (p=newblk; p<&(newblk[ActionBlockAllocSize]); p++) { p->next = (Node *)FreeList; /* add all new Action nodes to FreeList */ FreeList = p; } } p = FreeList; FreeList = (ActionNode *)FreeList->next;/* remove an Action node */ memset( (char *) p, 0, sizeof(ActionNode)); /* MR10 */ p->ntype = nAction; p->next = NULL; /* NULL the ptr we used */ p->done = 0; p->pred_fail = NULL; p->guardpred = NULL; p->ampersandPred = NULL; return p; } /* * allocate the array of locks (1..CLL_k) used to inhibit infinite recursion. * Infinite recursion can occur in (..)* blocks, FIRST calcs and FOLLOW calcs. * Therefore, we need locks on aLoopBlk, RuleBlk, EndRule nodes. * * if ( lock[k]==TRUE ) then we have been here before looking for k tokens * of lookahead. */ char * #ifdef __USE_PROTOS makelocks( void ) #else makelocks( ) #endif { char *p = (char *) calloc(CLL_k+1, sizeof(char)); require(p!=NULL, "cannot allocate lock array"); return p; } #if 0 ** #ifdef __USE_PROTOS ** void my_memset(char *p,char value,int count) ** #else ** void my_memset(p,value,count) ** char *p; ** char value; ** int count; ** #endif ** { ** int i; ** ** for (i=0; i #include #include "set.h" #include "syn.h" #include "hash.h" #include "generic.h" void #ifdef __USE_PROTOS dumpcycles(void) #else dumpcycles() #endif { Cycle *c; CacheEntry *f; ListNode *p; int i=0; int k; int degree; for (k=1; k <= CLL_k; k++) { if (Cycles[k] == NULL) continue; for (p = Cycles[k]->next; p!=NULL; p=p->next) { c = (Cycle *) p->elem; degree=set_deg(c->cyclicDep); fprintf(stderr,"Cycle %d: (degree %d) %s -->\n", i++, degree, RulePtr[c->croot]->rname); fprintf(stderr," *self*\n"); MR_dumpRuleSet(c->cyclicDep); fprintf(stderr,"\n"); f = (CacheEntry *) hash_get(Fcache,Fkey(RulePtr[c->croot]->rname,'o',k)); if (f == NULL) { fprintf(stderr," *** FOLLOW(%s) must be in cache but isn't ***\n", RulePtr[c->croot]->rname); }; }; }; } void #ifdef __USE_PROTOS dumpfostack(int k) #else dumpfostack(k) int k; #endif { int i=0; int *pi; fprintf(stderr,"\n"); if (FoStack[k] == NULL) { fprintf(stderr,"FoStack[%d] is null\n",k); }; if (FoTOS[k] == NULL) { fprintf(stderr,"FoTOS[%d] is null\n",k); } if (FoTOS[k] != NULL && FoStack[k] != NULL) { for (pi=FoStack[k]; pi <= FoTOS[k]; pi++) { i++; fprintf(stderr,"#%d rule %d %s\n",i,*pi,RulePtr[*pi]->rname); } } } cdrdao-cdrdao-f00afb2/pccts/antlr/dumpnode.c000066400000000000000000000214221511453746600211120ustar00rootroot00000000000000#include #include #include "set.h" #include "syn.h" #include "hash.h" #include "generic.h" #ifdef __USE_PROTOS void dumpset1(set s) #else void dumpset1(s) set s; #endif { if (set_nil(s)) { fprintf(stderr,"{}"); } else { s_fprT(stderr,s); }; } #ifdef __USE_PROTOS void dumpset(set s) #else void dumpset(s) set s; #endif { dumpset1(s); fprintf(stderr,"\n"); } #ifdef __USE_PROTOS int isEndRule(Node * p) #else int isEndRule(p) Node * p; #endif { int result=0; if ( p->ntype == nJunction && ( (Junction *) p)->jtype == EndRule) { result=1; }; return result; } #ifdef __USE_PROTOS void dumppred1(int depth,Predicate *p) #else void dumppred1(depth,p) int depth; Predicate *p; #endif { int i; int k; for (i=0; iexpr == PRED_AND_LIST || p->expr == PRED_OR_LIST) { fprintf(stderr," %s", (p->expr == NULL ? "null expr" : p->expr)); if (p->inverted) fprintf(stderr," predicate inverted !"); if (p->redundant) { fprintf(stderr," Redundant!"); }; if (p->isConst) fprintf(stderr," const %d !",p->constValue); fprintf(stderr,"\n"); } else { fprintf(stderr,"predicate k=%d",p->k); k=set_int(p->completionSet); if (k >= 0) { fprintf(stderr," Incomplete Set=%d !",k); }; k=set_int(p->completionTree); if (k >= 0) { fprintf(stderr," Incomplete Tree=%d !",k); }; if (p->redundant) { fprintf(stderr," Redundant!"); }; fprintf(stderr," \"%s\" (%p)", (p->expr == NULL ? "null expr" : p->expr) , p); if (p->source != NULL) { fprintf(stderr,"line %d",p->source->line); }; if (p->inverted) fprintf(stderr," predicate inverted !"); fprintf(stderr,"\n"); for (i=0; iscontext[1]); for (i=0; itcontext); fprintf(stderr,"\n"); }; fprintf(stderr,"\n"); if (p->down != NULL) { dumppred1(depth+1,p->down); }; if (p->right != NULL) { dumppred1(depth,p->right); }; } #ifdef __USE_PROTOS void dumppred(Predicate *p) #else void dumppred(p) Predicate *p; #endif { fprintf(stderr,"---------------------------------\n"); dumppred1(0,p); fprintf(stderr,"\n"); } #ifdef __USE_PROTOS void dumppredtree(Predicate *p) #else void dumppredtree(p) Predicate *p; #endif { fprintf(stderr,"predicate k=%d \"%s\" line %d\n",p->k,p->expr,p->source->line); dumpset(p->scontext[1]); } #ifdef __USE_PROTOS void dumppredexpr(Predicate *p) #else void dumppredexpr(p) Predicate *p; #endif { fprintf(stderr," pred expr \"%s\"\n",p->expr); } #ifdef __USE_PROTOS void dt(Tree *t) #else void dt(t) Tree *t; #endif { MR_dumpTreeF(stderr,0,t,5); } #ifdef __USE_PROTOS void d(Node * p) #else void d(p) Node * p; #endif { Junction *j; RuleRefNode *r; TokNode *t; ActionNode *a; if (p==NULL) { fprintf(stderr,"dumpNode: Node is NULL"); return; }; switch (p->ntype) { case nJunction : j = (Junction *) p; fprintf(stderr, "Junction (#%d in rule %s line %d) ",j->seq,j->rname,j->line); if (j->guess) fprintf(stderr,"guess block "); switch (j->jtype ) { case aSubBlk : fprintf(stderr,"aSubBlk"); break; case aOptBlk : fprintf(stderr,"aOptBlk"); break; case aLoopBegin : fprintf(stderr,"aLoopBeginBlk"); break; case aLoopBlk : fprintf(stderr,"aLoopBlk"); break; case aPlusBlk : fprintf(stderr,"aPlusBlk"); break; case EndBlk : fprintf(stderr,"EndBlk"); break; case RuleBlk : fprintf(stderr,"RuleBlk"); break; case Generic : fprintf(stderr,"Generic"); break; case EndRule : fprintf(stderr,"EndRule"); break; }; if (j->halt) fprintf(stderr," halt!"); if (j->p1) fprintf(stderr," p1 valid"); if (j->p2) { if (j->p2->ntype == nJunction) { fprintf(stderr," (p2=#%d)",( (Junction *) j->p2)->seq); } else { fprintf(stderr," (p2 valid)"); }; }; if (j->ignore) fprintf(stderr, " ignore/plus-block-bypass"); if (j->fset != NULL && set_deg(*j->fset) != 0) { fprintf(stderr,"\nfset:\n"); dumpset(*j->fset); }; if (j->ftree != NULL) { fprintf(stderr,"\nftree:\n"); preorder(j->ftree); }; fprintf(stderr,"\n"); break; case nRuleRef : r = (RuleRefNode *) p; fprintf(stderr, "RuleRefNode (in rule %s line %d) to rule %s\n", r->rname,r->line,r->text); break; case nToken : t = (TokNode *) p; fprintf(stderr, "TokNode (in rule %s line %d) token %s\n",t->rname,t->line,TerminalString(t->token)); break; case nAction : a =(ActionNode *) p; if (a->is_predicate) { fprintf(stderr, "Predicate (in rule %s line %d) %s",a->rname,a->line,a->action); if (a->inverted) fprintf(stderr," action inverted !"); if (a->guardpred != NULL) { fprintf(stderr," guarded"); dumppredexpr(a->guardpred); if (a->ampersandPred) { fprintf(stderr," \"&&\" style"); } else { fprintf(stderr," \"=>\" style"); }; }; if (a->predEntry != NULL) fprintf(stderr," predEntry \"%s\" ",a->predEntry->str); fprintf(stderr,"\n"); } else if (a->init_action) { fprintf(stderr, "Init-Action (in rule %s line %d) %s\n",a->rname,a->line,a->action); } else { fprintf(stderr, "Action (in rule %s line %d) %s\n",a->rname,a->line,a->action); }; break; }; } #ifdef __USE_PROTOS Node * dp1(Node * p) #else Node * dp1(p) Node * p; #endif { Node *result=NULL; if (p->ntype == nJunction) { result=( (Junction *) p )->p1; d(result); } else { fprintf(stderr,"dp1: Not a Junction node"); }; return result; } #ifdef __USE_PROTOS Node * dp2(Node * p) #else Node * dp2(p) Node * p; #endif { Node *result=NULL; if (p->ntype == nJunction) { result=( (Junction *) p )->p2; d(result); } else { fprintf(stderr,"dp2: Not a Junction node"); }; return result; } #ifdef __USE_PROTOS Node * dn(Node * p) #else Node * dn(p) Node * p; #endif { Node *result=NULL; if (p->ntype == nRuleRef) { result=( (RuleRefNode *)p )->next; } else if (p->ntype == nAction) { result=( (ActionNode *)p )->next; } else if (p->ntype == nToken) { result=( (TokNode *)p )->next; } else { fprintf(stderr,"No next field: Neither a RuleRefNode, ActionNode, nor TokNode"); }; if (result != NULL) d(result); return result; } #ifdef __USE_PROTOS void df(Node * p) #else void df(p) Node * p; #endif { int count=0; Node *next; fprintf(stderr,"\n#%d ",++count); d(p); for (next=p; next != NULL && !isEndRule(next) ; ) { fprintf(stderr,"#%d ",++count); if (next->ntype == nJunction) { next=dp1(next); } else { next=dn(next); }; }; } #ifdef __USE_PROTOS Node * dfn(Node * p,int target) #else Node * dfn(p,target) Node * p; int target; #endif { Node *result=NULL; int count=0; Node *next; fprintf(stderr,"#%d ",++count); d(p); for (next=p; next != NULL && !isEndRule(next) ; ) { fprintf(stderr,"#%d ",++count); if (next->ntype == nJunction) { next=dp1(next); } else { next=dn(next); }; if (count == target) { result=next; break; }; }; return result; } static int findnodeMatch; #ifdef __USE_PROTOS Junction *findnode1(Node *n) #else Junction *findnode1(n) Node *n; #endif { Node *next; Junction *j; Junction *match; if (n == NULL) return NULL; if (n->ntype == nJunction) { j=(Junction *) n; if (j->seq == findnodeMatch) return j; if (j->jtype == EndRule) return NULL; if (j->jtype != RuleBlk && j->jtype != EndBlk) { if (j->p2 != NULL && !j->ignore) { match=findnode1(j->p2); if (match != NULL) return match; }; }; }; next=MR_advance(n); return findnode1(next); } #ifdef __USE_PROTOS Junction *findnode(int match) #else Junction *findnode(match) int match; #endif { Junction *j; Junction *result=NULL; findnodeMatch=match; for (j=SynDiag; j != NULL; j=(Junction *)j->p2) { require (j->ntype == nJunction && j->jtype == RuleBlk,"Not a rule block"); result=findnode1( (Node *) j); if (result != NULL) break; }; if (result != NULL) { d( (Node *) result); }; return result; } cdrdao-cdrdao-f00afb2/pccts/antlr/egman.c000066400000000000000000000220361511453746600203700ustar00rootroot00000000000000/* * egman.c * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33MR10 * 2001 * */ #include #include #include "set.h" #include "syn.h" #include "hash.h" #include "generic.h" #include "proto.h" static ExceptionGroup **egArray=NULL; /* ExceptionGroup by BlkLevel */ static LabelEntry **leArray=NULL; /* LabelEntry by BlkLevel */ static Junction **altArray=NULL; /* start of alternates */ static int arraySize=0; static int highWater=0; static ExceptionGroup *lastEG=NULL; /* used in altFixup() */ static int lastBlkLevel=0; /* used in altFixup() */ #ifdef __USE_PROTOS static void arrayCheck(void); #else static void arrayCheck(); #endif /* Called to add an exception group for an alternative EG */ #ifdef __USE_PROTOS void egAdd(ExceptionGroup * eg) #else void egAdd(eg) ExceptionGroup *eg; #endif { int i; ExceptionGroup *nextEG; ExceptionGroup *innerEG; LabelEntry *nextLE; LabelEntry *innerLE; Junction *nextAlt; Junction *innerAlt; lastEG=eg; lastBlkLevel=BlkLevel; arrayCheck(); eg->pendingLink=egArray[BlkLevel]; egArray[BlkLevel]=eg; /* EG for alternates already have their altID filled in */ for (i=BlkLevel+1; i<=highWater ; i++) { for (innerEG=egArray[i]; innerEG != NULL ; innerEG=nextEG) { nextEG=innerEG->pendingLink; innerEG->pendingLink=NULL; innerEG->outerEG=eg; }; egArray[i]=NULL; }; /* * for patching up the LabelEntry you might use an EG for the * current alternative - unlike patching up an alternative EG * i.e. start the loop at BlkLevel rather than (BlkLevel+1) * fill it in only if the EG and the LE are for the very * same alternative if they're at the same BlkLevel * it's easier to leave the LE on this list (filled in) rather than * trying to selectively remove it. It will eventually be * removed anyway when the BlkLevel gets small enough. */ for (i=BlkLevel; i<=highWater ; i++) { for (innerLE=leArray[i]; innerLE != NULL ; innerLE=nextLE) { nextLE=innerLE->pendingLink; if (BlkLevel != i || innerLE->curAltNum == CurAltNum_array[BlkLevel]) { if (innerLE->outerEG == NULL) { innerLE->outerEG=eg; }; }; }; if (BlkLevel != i) leArray[i]=NULL; }; /* * For the start of alternatives it is necessary to make a * distinction between the exception group for the current * alternative and the "fallback" EG for the block which * contains the alternative * * The fallback outerEG is used to handle the case where * no alternative of a block matches. In that case the * signal is "NoViableAlt" (or "NoSemViableAlt" and the * generator needs the EG of the block CONTAINING the * current one. * * rule: ( ( ( a * | b * ) * | c * ) * | d * ); */ for (i=BlkLevel; i <= highWater ; i++) { for (innerAlt=altArray[i]; innerAlt != NULL ; innerAlt=nextAlt) { nextAlt=innerAlt->pendingLink; /* first fill in the EG for the current alternative */ /* but leave it on the list in order to get the fallback EG */ /* if the EG is at the same LEVEL as the alternative then */ /* fill it in only if in the very same alternative */ /* */ /* rule: ( a */ /* | b */ /* | c exception ... */ /* ) */ /* */ /* if the EG is outside the alternative (e.g. BlkLevel < i) */ /* then it doesn't matter about the alternative */ /* */ /* rule: ( a */ /* | b */ /* | c */ /* ) exception ... */ /* */ #if 0 printf("BlkLevel=%d i=%d altnum=%d CurAltNum=%d altID=%s\n", BlkLevel,i,innerAlt->curAltNum,CurAltNum_array[BlkLevel],eg->altID); #endif if (BlkLevel != i || innerAlt->curAltNum == CurAltNum_array[BlkLevel]) { if (innerAlt->exception_label == NULL) { innerAlt->exception_label=eg->altID; }; }; /* ocurs at a later pass then for the exception_label */ /* if an outerEG has been found then fill in the outer EG */ /* remove if from the list when the BlkLevel gets smaller */ if (BlkLevel != i) { if (innerAlt->outerEG == NULL) { innerAlt->outerEG=eg; }; }; }; if (BlkLevel != i) altArray[i]=NULL; }; } #ifdef __USE_PROTOS void leAdd(LabelEntry * le) #else void leAdd(le) LabelEntry *le; #endif { arrayCheck(); le->pendingLink=leArray[BlkLevel]; le->curAltNum=CurAltNum_array[BlkLevel]; leArray[BlkLevel]=le; } #ifdef __USE_PROTOS void altAdd(Junction *alt) #else void altAdd(alt) Junction *alt; #endif { arrayCheck(); #if 0 printf("BlkLevel=%d CurAltNum=%d\n", BlkLevel,CurAltNum_array[BlkLevel]); #endif alt->curAltNum=CurAltNum_array[BlkLevel]; alt->pendingLink=altArray[BlkLevel]; altArray[BlkLevel]=alt; } static void #ifdef __USE_PROTOS arrayCheck(void) #else arrayCheck() #endif { ExceptionGroup **egArrayNew; LabelEntry **leArrayNew; Junction **altArrayNew; int arraySizeNew; int i; if (BlkLevel > highWater) highWater=BlkLevel; if (BlkLevel >= arraySize) { arraySizeNew=BlkLevel+5; /* MR20 */ egArrayNew=(ExceptionGroup **) calloc(arraySizeNew,sizeof(ExceptionGroup *)); leArrayNew=(LabelEntry **) calloc(arraySizeNew,sizeof(LabelEntry *)); altArrayNew=(Junction **) calloc(arraySizeNew,sizeof(Junction *)); for (i=0; ipendingLink; innerEG->pendingLink=NULL; }; egArray[i]=NULL; }; lastEG=NULL; lastBlkLevel=0; } /* always call leFixup() BEFORE egFixup() */ #ifdef __USE_PROTOS void leFixup(void) #else void leFixup() #endif { int i; LabelEntry *nextLE; LabelEntry *innerLE; for (i=BlkLevel; i<=highWater ; i++) { for (innerLE=leArray[i]; innerLE != NULL ; innerLE=nextLE) { nextLE=innerLE->pendingLink; innerLE->pendingLink=NULL; }; leArray[i]=NULL; }; } /* always call altFixup() BEFORE egFixup() */ #ifdef __USE_PROTOS void altFixup(void) #else void altFixup() #endif { int i; Junction *nextAlt; Junction *innerAlt; for (i=BlkLevel; i<=highWater ; i++) { for (innerAlt=altArray[i]; innerAlt != NULL ; innerAlt=nextAlt) { /* if an outerEG has been found then fill in the outer EG */ if (lastBlkLevel <= i) { if (innerAlt->outerEG == NULL) { innerAlt->outerEG=lastEG; }; }; nextAlt=innerAlt->pendingLink; innerAlt->pendingLink=NULL; }; altArray[i]=NULL; }; } cdrdao-cdrdao-f00afb2/pccts/antlr/err.c000066400000000000000000000466021511453746600200760ustar00rootroot00000000000000/* * A n t l r S e t s / E r r o r F i l e H e a d e r * * Generated from: antlr.g * * Terence Parr, Russell Quong, Will Cohen, and Hank Dietz: 1989-2001 * Parr Research Corporation * with Purdue University Electrical Engineering * With AHPCRC, University of Minnesota * ANTLR Version 1.33MR32 */ #define ANTLR_VERSION 13332 #include "pcctscfg.h" #include "pccts_stdio.h" #include "pcctscfg.h" #include "set.h" #include #include "syn.h" #include "hash.h" #include "generic.h" #define zzcr_attr(attr,tok,t) #define zzSET_SIZE 20 #include "antlr.h" #include "tokens.h" #include "dlgdef.h" #include "err.h" ANTLRChar *zztokens[157]={ /* 00 */ "Invalid", /* 01 */ "Eof", /* 02 */ "QuotedTerm", /* 03 */ "\\n|\\r|\\r\\n", /* 04 */ "\\(\\n|\\r|\\r\\n)", /* 05 */ "\\~[]", /* 06 */ "~[\\n\\r\"\\]+", /* 07 */ "\"", /* 08 */ "\\n|\\r|\\r\\n", /* 09 */ "\\(\\n|\\r|\\r\\n)", /* 10 */ "\\~[]", /* 11 */ "~[\\n\\r\"\\]+", /* 12 */ "'", /* 13 */ "\\n|\\r|\\r\\n", /* 14 */ "\\~[]", /* 15 */ "~[\\n\\r'\\]+", /* 16 */ "\\*/", /* 17 */ "\\*", /* 18 */ "\\n|\\r|\\r\\n", /* 19 */ "~[\\n\\r\\*]+", /* 20 */ "\\*/", /* 21 */ "\\*", /* 22 */ "\\n|\\r|\\r\\n", /* 23 */ "~[\\n\\r\\*]+", /* 24 */ "\\n|\\r|\\r\\n", /* 25 */ "~[\\n\\r]+", /* 26 */ "\\n|\\r|\\r\\n", /* 27 */ "~[\\n\\r]+", /* 28 */ "\\n|\\r|\\r\\n", /* 29 */ "~[\\n\\r]+", /* 30 */ "\\*/", /* 31 */ "\\*", /* 32 */ "\\n|\\r|\\r\\n", /* 33 */ "~[\\n\\r\\*]+", /* 34 */ "Action", /* 35 */ "Pred", /* 36 */ "PassAction", /* 37 */ "consumeUntil\\( [\\ \\t]* \\{~[\\}]+\\} [\\ \\t]* \\)", /* 38 */ "consumeUntil\\( ~[\\)]+ \\)", /* 39 */ "\\n|\\r|\\r\\n", /* 40 */ "\\>", /* 41 */ "$", /* 42 */ "$$", /* 43 */ "$\\[\\]", /* 44 */ "$\\[", /* 45 */ "$[0-9]+", /* 46 */ "$[0-9]+.", /* 47 */ "$[0-9]+.[0-9]+", /* 48 */ "$[_a-zA-Z][_a-zA-Z0-9]*", /* 49 */ "#0", /* 50 */ "#\\[\\]", /* 51 */ "#\\(\\)", /* 52 */ "#[0-9]+", /* 53 */ "#line[\\ \\t]* [0-9]+ {[\\ \\t]* \"~[\"]+\" ([\\ \\t]* [0-9]*)* } (\\n|\\r|\\r\\n)", /* 54 */ "#line ~[\\n\\r]* (\\n|\\r|\\r\\n)", /* 55 */ "#[_a-zA-Z][_a-zA-Z0-9]*", /* 56 */ "#\\[", /* 57 */ "#\\(", /* 58 */ "#", /* 59 */ "\\)", /* 60 */ "\\[", /* 61 */ "\\(", /* 62 */ "\\\\]", /* 63 */ "\\\\)", /* 64 */ "\\>", /* 65 */ "'", /* 66 */ "\"", /* 67 */ "\\$", /* 68 */ "\\#", /* 69 */ "\\(\\n|\\r|\\r\\n)", /* 70 */ "\\~[\\]\\)>$#]", /* 71 */ "/", /* 72 */ "/\\*", /* 73 */ "\\*/", /* 74 */ "//", /* 75 */ "~[\\n\\r\\)\\(\\$#\\>\\]\\[\"'/]+", /* 76 */ "[\\t\\ ]+", /* 77 */ "\\n|\\r|\\r\\n", /* 78 */ "\\[", /* 79 */ "\\<\\<", /* 80 */ "\"", /* 81 */ "/\\*", /* 82 */ "\\*/", /* 83 */ "//", /* 84 */ "#line[\\ \\t]* [0-9]+ {[\\ \\t]* \"~[\"]+\" ([\\ \\t]* [0-9]*)* } (\\n|\\r|\\r\\n)", /* 85 */ "#line ~[\\n\\r]* (\\n|\\r|\\r\\n)", /* 86 */ "\\>\\>", /* 87 */ "WildCard", /* 88 */ "\\@", /* 89 */ "LABEL", /* 90 */ "grammar-element", /* 91 */ "meta-symbol", /* 92 */ "Pragma", /* 93 */ "FirstSetSymbol", /* 94 */ "{\\}#header", /* 95 */ "{\\}#first", /* 96 */ "{\\}#parser", /* 97 */ "{\\}#tokdefs", /* 98 */ "\\}", /* 99 */ "class", /* 100 */ "NonTerminal", /* 101 */ "TokenTerm", /* 102 */ "\\{", /* 103 */ "!", /* 104 */ "\\<", /* 105 */ "\\>", /* 106 */ ":", /* 107 */ ";", /* 108 */ "{\\}#lexaction", /* 109 */ "{\\}#lexmember", /* 110 */ "{\\}#lexprefix", /* 111 */ "{\\}#pred", /* 112 */ "\\|\\|", /* 113 */ "&&", /* 114 */ "\\(", /* 115 */ "\\)", /* 116 */ "{\\}#lexclass", /* 117 */ "{\\}#errclass", /* 118 */ "{\\}#tokclass", /* 119 */ "..", /* 120 */ "{\\}#token", /* 121 */ "=", /* 122 */ "[0-9]+", /* 123 */ "\\|", /* 124 */ "\\~", /* 125 */ "^", /* 126 */ "approx", /* 127 */ "LL\\(1\\)", /* 128 */ "LL\\(2\\)", /* 129 */ "\\*", /* 130 */ "\\+", /* 131 */ "?", /* 132 */ "=>", /* 133 */ "exception", /* 134 */ "default", /* 135 */ "catch", /* 136 */ "{\\}#[A-Za-z0-9_]*", /* 137 */ "[\\t\\ ]+", /* 138 */ "\\n|\\r|\\r\\n", /* 139 */ "//", /* 140 */ "/\\*", /* 141 */ "#ifdef", /* 142 */ "#if", /* 143 */ "#ifndef", /* 144 */ "#else", /* 145 */ "#endif", /* 146 */ "#undef", /* 147 */ "#import", /* 148 */ "ID", /* 149 */ "#define", /* 150 */ "INT", /* 151 */ "enum", /* 152 */ "\\{", /* 153 */ "=", /* 154 */ ",", /* 155 */ "\\}", /* 156 */ ";" }; SetWordType zzerr1[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x30,0x0,0x0,0x0, 0x0,0x0,0x0,0x0}; SetWordType zzerr2[20] = {0xfc,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xf3, 0xbf,0xff,0xff,0xff, 0xff,0xff,0xff,0x1f}; SetWordType zzerr3[20] = {0xfc,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xfb, 0x3b,0xf7,0xf7,0xc7, 0xff,0xff,0xff,0x1f}; SetWordType zzerr4[20] = {0x4,0x0,0x0,0x0, 0x10,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x80,0x7,0x0,0x0, 0x0,0x0,0x0,0x0}; SetWordType setwd1[157] = {0x0,0x50,0xa0,0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x6a,0x20,0xa0,0x20,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x0,0x0,0x20,0x20,0x21, 0x21,0x21,0x21,0x6e,0x6e,0x64,0x20,0x0, 0x20,0xa0,0xa0,0xa0,0x20,0x6a,0x6a,0x6a, 0x6e,0x20,0x20,0x20,0x20,0x66,0x6e,0x6e, 0x20,0x66,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x62,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x20,0x20,0x20}; SetWordType zzerr5[20] = {0x0,0x0,0x0,0x0, 0x10,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x1,0x0,0x0, 0x0,0x0,0x0,0x0}; SetWordType zzerr6[20] = {0x4,0x0,0x0,0x0, 0x10,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x7,0x0,0x0, 0x0,0x0,0x0,0x0}; SetWordType zzerr7[20] = {0x4,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x6,0x0,0x0, 0x0,0x0,0x0,0x0}; SetWordType zzerr8[20] = {0x4,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x4,0x0,0x0, 0x0,0x0,0x0,0x0}; SetWordType zzerr9[20] = {0x2,0x0,0x0,0x0, 0x4,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x1c,0xf0,0x70,0x1, 0x20,0x0,0x0,0x0}; SetWordType setwd2[157] = {0x0,0xf8,0x6,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0xf8,0x0,0x1,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0xf8,0xf8,0xf8,0x0,0x0, 0x0,0x1,0x2,0x6,0x0,0xf8,0xf8,0xf8, 0xf8,0x0,0x0,0x0,0x0,0xf8,0xf8,0xf8, 0x0,0xf8,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0xe8,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0}; SetWordType zzerr10[20] = {0x2,0x0,0x0,0x0, 0x4,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0xbc,0xf8,0x74,0x1, 0x20,0x0,0x0,0x0}; SetWordType zzerr11[20] = {0x0,0x0,0x0,0x0, 0x8,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0xa0,0x0,0x4,0x0, 0x0,0x0,0x0,0x0}; SetWordType zzerr12[20] = {0x2,0x0,0x0,0x0, 0x4,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x1c,0xf8,0x70,0x1, 0x20,0x0,0x0,0x0}; SetWordType zzerr13[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0xa0,0x0,0x4,0x0, 0x0,0x0,0x0,0x0}; SetWordType setwd3[157] = {0x0,0xfa,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0xfa,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0xfa,0xfa,0xfa,0x5,0x0, 0x5,0x0,0x0,0x0,0xe2,0xfa,0xfa,0xfa, 0xfa,0xc0,0x80,0x5,0xe0,0xfa,0xfa,0xfa, 0x0,0xfa,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0xfa,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0}; SetWordType zzerr14[20] = {0x4,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x20,0x0,0x0,0x0, 0x0,0x0,0x0,0x0}; SetWordType zzerr15[20] = {0x4,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x30,0x0,0x0,0x0, 0x0,0x0,0x0,0x0}; SetWordType zzerr16[20] = {0x4,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x30,0x0,0x0,0x0, 0x0,0x0,0x0,0x0}; SetWordType zzerr17[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x40,0x0,0x4,0x0, 0x0,0x0,0x0,0x0}; SetWordType zzerr18[20] = {0x4,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x24,0x0,0x80,0x0, 0x0,0x0,0x0,0x0}; SetWordType zzerr19[20] = {0x4,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x20,0x0,0x0,0x0, 0x0,0x0,0x0,0x0}; SetWordType zzerr20[20] = {0x6,0x0,0x0,0x0, 0x4,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x1c,0xf8,0x74,0x3, 0x20,0x0,0x0,0x0}; SetWordType zzerr21[20] = {0x6,0x0,0x0,0x0, 0x4,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x1c,0xf8,0x70,0x3, 0x20,0x0,0x0,0x0}; SetWordType setwd4[157] = {0x0,0xe5,0xda,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0xe5,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0xed,0xe5,0xe7,0x1a,0x0, 0x0,0x0,0x0,0x0,0xc0,0xe5,0xe5,0xe5, 0xe5,0x0,0x0,0x0,0x0,0xe5,0xe5,0xe5, 0x0,0xe5,0x40,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0xe5,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0}; SetWordType zzerr22[20] = {0x6,0x0,0x0,0x0, 0x4,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x3c,0xf8,0x70,0x1, 0x20,0x0,0x0,0x0}; SetWordType zzerr23[20] = {0x6,0x0,0x0,0x0, 0x4,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x1c,0xf8,0x70,0x1, 0x20,0x0,0x0,0x0}; SetWordType zzerr24[20] = {0x2,0x0,0x0,0x0, 0x4,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x1c,0xf8,0x70,0x1, 0x20,0x0,0x0,0x0}; SetWordType zzerr25[20] = {0x2,0x0,0x0,0x0, 0x4,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x1c,0xf8,0x70,0x1, 0x20,0x0,0x0,0x0}; SetWordType zzerr26[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x5, 0x4,0x8,0x8,0x18, 0x20,0x0,0x0,0x0}; SetWordType setwd5[157] = {0x0,0x1f,0xc1,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0xdf,0xc0,0xc0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0xc0,0x0,0xc0,0x0,0x0,0xc0,0xc0,0x0, 0x0,0x0,0x0,0x7f,0x1f,0xdf,0xc0,0xc0, 0x0,0x0,0xc0,0x0,0x67,0x1f,0x1f,0x1f, 0x1f,0x0,0x0,0xc0,0x60,0x1f,0x1f,0x1f, 0x0,0x1f,0x0,0x0,0x40,0xc0,0x0,0x0, 0x0,0x0,0xc0,0xc0,0x0,0x0,0x5f,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0}; SetWordType zzerr27[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x4, 0x0,0x0,0x0,0x10, 0x0,0x0,0x0,0x0}; SetWordType zzerr28[20] = {0x4,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x80,0x2, 0x30,0x0,0x0,0x0, 0x0,0x0,0x0,0x0}; SetWordType zzerr29[20] = {0x4,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x20,0x0,0x0,0x0, 0x0,0x0,0x0,0x0}; SetWordType zzerr30[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0xd, 0x0,0x0,0x80,0x0, 0x20,0x0,0x0,0x0}; SetWordType zzerr31[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0xd, 0x0,0x0,0x0,0x0, 0x20,0x0,0x0,0x0}; SetWordType zzerr32[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x5, 0x4,0x8,0x8,0x18, 0x20,0x0,0x0,0x0}; SetWordType zzerr33[20] = {0x4,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x20,0x0,0x0,0x0, 0x0,0x0,0x0,0x0}; SetWordType setwd6[157] = {0x0,0x0,0xfd,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0xe1,0xe1,0xe1,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0xfd,0x60,0xe9,0x0,0x0,0xe1,0xe1,0x0, 0x0,0x0,0x0,0xe2,0x0,0xfd,0xfd,0xe1, 0x20,0x0,0xe1,0x0,0xe2,0x0,0x0,0x0, 0x0,0x0,0x0,0xe1,0xe2,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0xe2,0xe0,0x20,0x0, 0x0,0x0,0xe1,0xe1,0x0,0x0,0xe2,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0}; SetWordType zzerr34[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0xd, 0x0,0x0,0x80,0x0, 0x20,0x0,0x0,0x0}; SetWordType zzerr35[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0xd, 0x0,0x0,0x0,0x0, 0x20,0x0,0x0,0x0}; SetWordType zzerr36[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x5, 0x4,0x8,0x8,0x18, 0x20,0x0,0x0,0x0}; SetWordType zzerr37[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0xc, 0x0,0x0,0x0,0x0, 0x20,0x0,0x0,0x0}; SetWordType zzerr38[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x4, 0x84,0x9,0x8,0x18, 0x20,0x0,0x0,0x0}; SetWordType zzerr39[20] = {0x0,0x0,0x0,0x0, 0x10,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x1,0x0,0x0, 0x0,0x0,0x0,0x0}; SetWordType zzerr40[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x4, 0x4,0x9,0x8,0x18, 0x20,0x0,0x0,0x0}; SetWordType zzerr41[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x4, 0x4,0x8,0x8,0x18, 0x20,0x0,0x0,0x0}; SetWordType zzerr42[20] = {0x4,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x80,0x0, 0x30,0x0,0x0,0x0, 0x0,0x0,0x0,0x0}; SetWordType setwd7[157] = {0x0,0x0,0xdf,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0xdf,0xdf,0xff,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0xdf,0x3,0xdf,0x0,0x0,0xdf,0xdf,0x0, 0x0,0x0,0x0,0xdf,0x0,0xdf,0xdf,0xdf, 0x1,0x30,0xdf,0x0,0xdf,0x0,0x0,0x0, 0x0,0x0,0x0,0xdf,0xdf,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0xdf,0xdf,0x1,0x0, 0x0,0x0,0xdf,0xdf,0x0,0x0,0xdf,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0}; SetWordType zzerr43[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x4, 0x4,0x8,0x8,0x18, 0x20,0x0,0x0,0x0}; SetWordType zzerr44[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0xc0, 0x1,0x0,0x0,0x0}; SetWordType zzerr45[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x30, 0x40,0x0,0x4,0x0, 0x0,0x0,0x0,0x0}; SetWordType zzerr46[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x30,0x0,0x0,0x0, 0x0,0x0,0x0,0x0}; SetWordType zzerr47[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x20, 0x40,0x0,0x4,0x0, 0x0,0x0,0x0,0x0}; SetWordType zzerr48[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x2,0x0, 0x10,0x0,0x0,0x0}; SetWordType zzerr49[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x4, 0x4,0x8,0x8,0x18, 0x20,0x0,0x0,0x0}; SetWordType zzerr50[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x4, 0x4,0x8,0xa,0x18, 0x30,0x0,0x0,0x0}; SetWordType zzerr51[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x4, 0x4,0x8,0x8,0x18, 0x28,0x0,0x0,0x0}; SetWordType zzerr52[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x40,0x0,0x4,0x0, 0x0,0x0,0x0,0x0}; SetWordType zzerr53[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x4, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0}; SetWordType setwd8[157] = {0x0,0x0,0xe1,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0xe1,0xe1,0xe1,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0xe1,0x0,0xe1,0x0,0x0,0xe3,0xe7,0x0, 0x0,0x0,0x0,0xe1,0x0,0xe1,0xe1,0xef, 0x0,0x0,0xe1,0x0,0xe1,0x0,0x0,0x0, 0x0,0x0,0x10,0xef,0xe1,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0xe1,0xe1,0x0,0x0, 0x0,0x0,0xe1,0xe1,0x0,0x10,0xe1,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0}; SetWordType zzerr54[20] = {0x2,0x0,0x0,0x0, 0x14,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x1c,0xf8,0x78,0x9, 0xe0,0x0,0x0,0x0}; SetWordType zzerr55[20] = {0x2,0x0,0x0,0x0, 0x4,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x1c,0xf8,0x78,0x9, 0x60,0x0,0x0,0x0}; SetWordType zzerr56[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x30,0x0,0x0,0x0, 0x0,0x0,0x0,0x0}; SetWordType zzerr57[20] = {0x2,0x0,0x0,0x0, 0x4,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x1c,0xf8,0x78,0x9, 0xe0,0x0,0x0,0x0}; SetWordType setwd9[157] = {0x0,0x7c,0x1,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x7f,0x1,0x1,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x1,0x0,0x1,0x0,0x0,0x1,0x1,0x0, 0x0,0x0,0x0,0x7f,0x7e,0x7f,0x1,0x1, 0x0,0x0,0x1,0x0,0x7d,0x7e,0x7e,0x7e, 0x7e,0x0,0x0,0x1,0x7d,0x7e,0x7e,0x7e, 0x0,0x7e,0x0,0x0,0x7d,0x1,0x0,0x0, 0x0,0x0,0x1,0x1,0x0,0x0,0x7f,0x64, 0x64,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x80,0x0,0x0,0x0,0x0,0x0,0x80,0x0, 0x80,0x0,0x0,0x0,0x0,0x0}; SetWordType zzerr58[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0xa0,0x0}; SetWordType zzerr59[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x80,0xa0,0x0}; SetWordType zzerr60[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0xa0,0x0}; SetWordType zzerr61[20] = {0x2,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x80,0xa0,0x0}; SetWordType zzerr62[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0xe}; SetWordType zzerr63[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0xe}; SetWordType zzerr64[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0xe}; SetWordType zzerr65[20] = {0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, 0x0,0x0,0x10,0xc}; SetWordType setwd10[157] = {0x0,0xc,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x3,0x0, 0x3,0x0,0x0,0xf0,0xf0,0x0}; SetWordType setwd11[157] = {0x0,0x1,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x1,0x0,0x0,0x0,0x0,0x0}; cdrdao-cdrdao-f00afb2/pccts/antlr/fcache.c000066400000000000000000000055501511453746600205140ustar00rootroot00000000000000/* * fcache.c * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33MR10 * */ #include #include #include "pcctscfg.h" #include "set.h" #include "syn.h" #include "hash.h" #include "generic.h" #ifdef __USE_PROTOS CacheEntry *dumpFcache1(char *prev) #else CacheEntry *dumpFcache1(prev) char *prev; #endif { Entry **table=Fcache; int low=0; int hi=0; CacheEntry *least=NULL; Entry **p; for (p=table; p<&(table[HashTableSize]); p++) { CacheEntry *q =(CacheEntry *) *p; if ( q != NULL && low==0 ) low = p-table; while ( q != NULL ) { if (strcmp(q->str,prev) > 0) { if (least == NULL) { least=q; } else { if (strcmp(q->str,least->str) < 0) { least=q; }; }; }; q = q->next; }; if ( *p != NULL ) hi = p-table; } return least; } #ifdef __USE_PROTOS void reportFcache(CacheEntry *q) #else void reportFcache(q) CacheEntry *q; #endif { char *qstr; fprintf(stdout,"\nrule "); for (qstr=q->str; *qstr != '*' ; qstr++) { fprintf(stdout,"%c",*qstr); }; qstr++; if (*qstr == 'i') fprintf(stdout," First["); if (*qstr == 'o') fprintf(stdout," Follow["); qstr++; fprintf(stdout,"%s]",qstr); if (q->incomplete) fprintf(stdout," *** incomplete ***"); fprintf(stdout,"\n"); MR_dumpTokenSet(stdout,1,q->fset); } void #ifdef __USE_PROTOS DumpFcache(void) #else DumpFcache() #endif { char *prev=""; int n=0; CacheEntry *next; fprintf(stdout,"\n\nDump of First/Follow Cache\n"); for(;;) { next=dumpFcache1(prev); if (next == NULL) break; reportFcache(next); ++n; prev=next->str; }; fprintf(stdout,"\nEnd dump of First/Follow Cache\n"); } cdrdao-cdrdao-f00afb2/pccts/antlr/fset.c000066400000000000000000001506411511453746600202460ustar00rootroot00000000000000/* * fset.c * * Compute FIRST and FOLLOW sets. * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2001 */ #include #include #include "pcctscfg.h" #include "set.h" #include "syn.h" #include "hash.h" #include "generic.h" #include "dlgdef.h" #include "limits.h" #ifdef __USE_PROTOS static void ensure_predicates_cover_ambiguous_lookahead_sequences (Junction *, Junction *, char *, Tree *); #else static void ensure_predicates_cover_ambiguous_lookahead_sequences(); #endif /* * What tokens are k tokens away from junction q? * * Follow both p1 and p2 paths (unless RuleBlk) to collect the tokens k away from this * node. * We lock the junction according to k--the lookahead. If we have been at this * junction before looking for the same, k, number of lookahead tokens, we will * do it again and again...until we blow up the stack. Locks are only used on aLoopBlk, * RuleBlk, aPlusBlk and EndRule junctions to remove/detect infinite recursion from * FIRST and FOLLOW calcs. * * If p->jtype == EndRule we are going to attempt a FOLLOW. (FOLLOWs are really defined * in terms of FIRST's, however). To proceed with the FOLLOW, p->halt cannot be * set. p->halt is set to indicate that a reference to the current rule is in progress * and the FOLLOW is not desirable. * * If we attempt a FOLLOW and find that there is no FOLLOW or REACHing beyond the EndRule * junction yields an empty set, replace the empty set with EOF. No FOLLOW means that * only EOF can follow the current rule. This normally occurs only on the start symbol * since all other rules are referenced by another rule somewhere. * * Normally, both p1 and p2 are followed. However, checking p2 on a RuleBlk node is * the same as checking the next rule which is clearly incorrect. * * Cycles in the FOLLOW sense are possible. e.g. Fo(c) requires Fo(b) which requires * Fo(c). Both Fo(b) and Fo(c) are defined to be Fo(b) union Fo(c). Let's say * Fo(c) is attempted first. It finds all of the FOLLOW symbols and then attempts * to do Fo(b) which finds of its FOLLOW symbols. So, we have: * * Fo(c) * / \ * a set Fo(b) * / \ * a set Fo(c) .....Hmmmm..... Infinite recursion! * * The 2nd Fo(c) is not attempted and Fo(b) is left deficient, but Fo(c) is now * correctly Fo(c) union Fo(b). We wish to pick up where we left off, so the fact * that Fo(b) terminated early means that we lack Fo(c) in the Fo(b) set already * laying around. SOOOOoooo, we track FOLLOW cycles. All FOLLOW computations are * cached in a hash table. After the sequence of FOLLOWs finish, we reconcile all * cycles --> correct all Fo(rule) sets in the cache. * * Confused? Good! Read my MS thesis [Purdue Technical Report TR90-30]. * TJP 8/93 -- can now read PhD thesis from Purdue. * * Also, FIRST sets are cached in the hash table. Keys are (rulename,Fi/Fo,k). * Only FIRST sets, for which the FOLLOW is not included, are stored. * * SPECIAL CASE of (...)+ blocks: * I added an optional alt so that the alts could see what * was behind the (...)+ block--thus using enough lookahead * to branch out rather than just enough to distinguish * between alts in the (...)+. However, when the FIRST("(...)+") is * is needed, must not use this last "optional" alt. This routine * turns off this path by setting a new 'ignore' flag for * the alt and then resetting it afterwards. */ set #ifdef __USE_PROTOS rJunc( Junction *p, int k, set *rk ) #else rJunc( p, k, rk ) Junction *p; int k; set *rk; #endif { set a, b; require(p!=NULL, "rJunc: NULL node"); require(p->ntype==nJunction, "rJunc: not junction"); #ifdef DBG_LL1 if ( p->jtype == RuleBlk ) fprintf(stderr, "FIRST(%s,%d) \n",((Junction *)p)->rname,k); else fprintf(stderr, "rJunc: %s in rule %s\n", decodeJType[p->jtype], ((Junction *)p)->rname); #endif /* if this is one of the added optional alts for (...)+ then return */ /* no need to pop backtrace - hasn't been pushed */ if ( p->ignore ) return empty; if (MR_MaintainBackTrace) MR_pointerStackPush(&MR_BackTraceStack,p); /* MR14 */ if (AlphaBetaTrace && p->alpha_beta_guess_end) { /* MR14 */ warnFL( /* MR14 */ "not possible to compute follow set for alpha in an \"(alpha)? beta\" block. ", /* MR14 */ FileStr[p->file],p->line); /* MR14 */ MR_alphaBetaTraceReport(); /* MR14 */ }; /* MR14 */ if (p->alpha_beta_guess_end) { /* MR14 */ if (MR_MaintainBackTrace) MR_pointerStackPop(&MR_BackTraceStack); /* MR14 */ return empty; /* MR14 */ } /* locks are valid for aLoopBlk,aPlusBlk,RuleBlk,EndRule junctions only */ if ( p->jtype==aLoopBlk || p->jtype==RuleBlk || p->jtype==aPlusBlk || p->jtype==EndRule ) { require(p->lock!=NULL, "rJunc: lock array is NULL"); if ( p->lock[k] ) { if ( p->jtype == EndRule ) /* FOLLOW cycle? */ { #ifdef DBG_LL1 fprintf(stderr, "FOLLOW cycle to %s: panic!\n", p->rname); #endif if (! MR_AmbSourceSearch) RegisterCycle(p->rname, k); } if (MR_MaintainBackTrace) MR_pointerStackPop(&MR_BackTraceStack); return empty; } if ( p->jtype == RuleBlk && p->end->halt && ! MR_AmbSourceSearch) /* check for FIRST cache */ { CacheEntry *q = (CacheEntry *) hash_get(Fcache, Fkey(p->rname,'i',k)); if ( q != NULL ) { set_orin(rk, q->rk); if (MR_MaintainBackTrace) MR_pointerStackPop(&MR_BackTraceStack); return set_dup( q->fset ); } } if ( p->jtype == EndRule && !p->halt && /* MR11 was using cache even when halt set */ ! MR_AmbSourceSearch) /* FOLLOW set cached already? */ { CacheEntry *q = (CacheEntry *) hash_get(Fcache, Fkey(p->rname,'o',k)); if ( q != NULL ) { #ifdef DBG_LL1 fprintf(stderr, "cache for FOLLOW(%s,%d):", p->rname,k); s_fprT(stderr, q->fset); if ( q->incomplete ) fprintf(stderr, " (incomplete)"); fprintf(stderr, "\n"); #endif if ( !q->incomplete ) { if (MR_MaintainBackTrace) MR_pointerStackPop(&MR_BackTraceStack); return set_dup( q->fset ); } } } p->lock[k] = TRUE; /* This rule is busy */ } a = b = empty; if ( p->jtype == EndRule ) { if (p->halt ) /* don't want FOLLOW here? */ /* unless MR10 hoisting */ { p->lock[k] = FALSE; set_orel(k, rk); /* indicate this k value needed */ if (MR_MaintainBackTrace) MR_pointerStackPop(&MR_BackTraceStack); return empty; } if (! MR_AmbSourceSearch) FoPush(p->rname, k); /* Attempting FOLLOW */ if ( p->p1 == NULL ) set_orel((TokenInd!=NULL?TokenInd[EofToken]:EofToken), &a);/* if no FOLLOW assume EOF */ #ifdef DBG_LL1 fprintf(stderr, "-->FOLLOW(%s,%d)\n", p->rname,k); #endif } if ( p->p1 != NULL ) { /* MR14 */ if (p->guess) { /* MR14 */ if (p->guess_analysis_point == NULL) { /* MR14 */ Node * guess_point; /* MR14 */ guess_point=(Node *)analysis_point(p); /* MR14 */ if (guess_point == (Node *)p) { /* MR14 */ guess_point=p->p1; /* MR14 */ } /* MR14 */ p->guess_analysis_point=guess_point; /* MR14 */ } /* MR14 */ REACH(p->guess_analysis_point, k, rk, a); } else { REACH(p->p1, k, rk, a); } } /* C a c h e R e s u l t s */ if ( p->jtype == RuleBlk && p->end->halt && ! MR_AmbSourceSearch) /* can save FIRST set? */ { CacheEntry *q = newCacheEntry( Fkey(p->rname,'i',k) ); /*fprintf(stderr, "Caching %s FIRST %d\n", p->rname, k);*/ hash_add(Fcache, Fkey(p->rname,'i',k), (Entry *)q); q->fset = set_dup( a ); q->rk = set_dup( *rk ); } if ( p->jtype == EndRule && !p->halt && /* MR11 was using cache even with halt set */ ! MR_AmbSourceSearch) /* just completed FOLLOW? */ { /* Cache Follow set */ CacheEntry *q = (CacheEntry *) hash_get(Fcache, Fkey(p->rname,'o',k)); if ( q==NULL ) { q = newCacheEntry( Fkey(p->rname,'o',k) ); hash_add(Fcache, Fkey(p->rname,'o',k), (Entry *)q); } /*fprintf(stderr, "Caching %s FOLLOW %d\n", p->rname, k);*/ if ( set_nil(a) && !q->incomplete ) { /* Don't ever save a nil set as complete. * Turn it into an eof set. */ set_orel(EofToken, &a); } set_orin(&(q->fset), a); FoPop( k ); if ( FoTOS[k] == NULL && Cycles[k] != NULL ) ResolveFoCycles(k); #ifdef DBG_LL1 fprintf(stderr, "saving FOLLOW(%s,%d):", p->rname, k); s_fprT(stderr, q->fset); if ( q->incomplete ) fprintf(stderr, " (incomplete)"); fprintf(stderr, "\n"); #endif } if (p->jtype != RuleBlk && p->p2 != NULL && /* MR14 */ ! p->guess) { REACH(p->p2, k, rk, b); } if ( p->jtype==aLoopBlk || p->jtype==RuleBlk || p->jtype==aPlusBlk || p->jtype==EndRule ) p->lock[k] = FALSE; /* unlock node */ set_orin(&a, b); set_free(b); if (MR_MaintainBackTrace) MR_pointerStackPop(&MR_BackTraceStack); return a; } set #ifdef __USE_PROTOS rRuleRef( RuleRefNode *p, int k, set *rk_out ) #else rRuleRef( p, k, rk_out ) RuleRefNode *p; int k; set *rk_out; #endif { set rk; Junction *r; int k2; set a, rk2, b; int save_halt; RuleEntry *q = (RuleEntry *) hash_get(Rname, p->text); require(p!=NULL, "rRuleRef: NULL node"); require(p->ntype==nRuleRef, "rRuleRef: not rule ref"); #ifdef DBG_LL1 fprintf(stderr, "rRuleRef: %s\n", p->text); #endif if (MR_MaintainBackTrace) MR_pointerStackPush(&MR_BackTraceStack,p); if ( q == NULL ) { warnFL( eMsg1("rule %s not defined",p->text), FileStr[p->file], p->line ); REACH(p->next, k, rk_out, a); if (MR_MaintainBackTrace) MR_pointerStackPop(&MR_BackTraceStack); return a; } rk2 = empty; /* MR9 Problems with rule references in guarded predicates */ /* MR9 Perhaps can use hash table to find rule ? */ /* MR9 */ if (RulePtr == NULL) { /* MR9 */ fatalFL(eMsg2("Rule %s uses rule %s via RulePtr before it has been initialized", /* MR9 */ p->rname,q->str),FileStr[p->file],p->line); /* MR9 */ }; r = RulePtr[q->rulenum]; if ( r->lock[k] ) { errNoFL( eMsg2("infinite left-recursion to rule %s from rule %s", r->rname, p->rname) ); if (MR_MaintainBackTrace) MR_pointerStackPop(&MR_BackTraceStack); return empty; } save_halt = r->end->halt; r->end->halt = TRUE; /* don't let reach fall off end of rule here */ rk = empty; REACH(r, k, &rk, a); r->end->halt = save_halt; while ( !set_nil(rk) ) { k2 = set_int(rk); /* MR11 this messes up the ambiguity search routine */ set_rm(k2, rk); REACH(p->next, k2, &rk2, b); /* MR11 by changing the value of k */ set_orin(&a, b); set_free(b); } set_free(rk); /* this has no members, but free it's memory */ set_orin(rk_out, rk2); /* remember what we couldn't do */ set_free(rk2); if (MR_MaintainBackTrace) MR_pointerStackPop(&MR_BackTraceStack); return a; } /* * Return FIRST sub k ( token_node ) * * TJP 10/11/93 modified this so that token nodes that are actually * ranges (T1..T2) work. */ set #ifdef __USE_PROTOS rToken( TokNode *p, int k, set *rk ) #else rToken( p, k, rk ) TokNode *p; int k; set *rk; #endif { set a; require(p!=NULL, "rToken: NULL node"); require(p->ntype==nToken, "rToken: not token node"); #ifdef DBG_LL1 fprintf(stderr, "rToken: %s\n", (TokenString(p->token)!=NULL)?TokenString(p->token): ExprString(p->token)); #endif if (MR_MaintainBackTrace) MR_pointerStackPush(&MR_BackTraceStack,p); if (MR_AmbSourceSearch && (k-1) == 0) { set localConstrain; set intersection; localConstrain=fset[maxk-k+1]; if (! set_nil(p->tset)) { intersection=set_and(localConstrain,p->tset); if (! set_nil(intersection)) { MR_backTraceReport(); }; set_free(intersection); } else { if (set_el( (unsigned) p->token,localConstrain)) { MR_backTraceReport(); } }; }; if ( k-1 == 0 ) { if (MR_MaintainBackTrace) MR_pointerStackPop(&MR_BackTraceStack); if ( !set_nil(p->tset) ) { return set_dup(p->tset); } else { return set_of(p->token); }; } REACH(p->next, k-1, rk, a); if (MR_MaintainBackTrace) MR_pointerStackPop(&MR_BackTraceStack); return a; } set #ifdef __USE_PROTOS rAction( ActionNode *p, int k, set *rk ) #else rAction( p, k, rk ) ActionNode *p; int k; set *rk; #endif { set a; require(p!=NULL, "rJunc: NULL node"); require(p->ntype==nAction, "rJunc: not action"); /* MR11 */ if (p->is_predicate && p->ampersandPred != NULL) { /* MR11 */ Predicate *pred=p->ampersandPred; /* MR11 */ if (k <= pred->k) { /* MR11 */ REACH(p->guardNodes,k,rk,a); /* MR11 */ return a; /* MR11 */ }; /* MR11 */ }; /* it might be a good idea when doing an MR_AmbSourceSearch to *not* look behind predicates under some circumstances we'll look into that later */ REACH(p->next, k, rk, a); /* ignore actions */ return a; } /* A m b i g u i t y R e s o l u t i o n */ void #ifdef __USE_PROTOS dumpAmbigMsg( set *fset, FILE *f, int want_nls ) #else dumpAmbigMsg( fset, f, want_nls ) set *fset; FILE *f; int want_nls; #endif { int i; set copy; /* MR11 */ if ( want_nls ) fprintf(f, "\n\t"); else fprintf(f, " "); for (i=1; i<=CLL_k; i++) { copy=set_dup(fset[i]); /* MR11 */ if ( i>1 ) { if ( !want_nls ) fprintf(f, ", "); } if ( set_deg(copy) > 3 && elevel == 1 ) { int e,m; fprintf(f, "{"); for (m=1; m<=3; m++) { e=set_int(copy); fprintf(f, " %s", TerminalString(e)); set_rm(e, copy); } fprintf(f, " ... }"); } else s_fprT(f, copy); if ( want_nls ) fprintf(f, "\n\t"); set_free(copy); } fprintf(f, "\n"); } static void #ifdef __USE_PROTOS verify_context(Predicate *predicate) #else verify_context(predicate) Predicate *predicate; #endif { if ( predicate == NULL ) return; if ( predicate->expr == PRED_OR_LIST || predicate->expr == PRED_AND_LIST ) { verify_context(predicate->down); verify_context(predicate->right); /* MR10 */ return; } if ( !predicate->source->ctxwarned && predicate->source->guardpred==NULL && ((predicate->k > 1 && !is_single_tuple(predicate->tcontext)) || ( predicate->k == 1 && set_deg(predicate->scontext[1])>1 )) ) { /* MR9 Suppress annoying messages caused by our own clever(?) fix */ fprintf(stderr, ErrHdr, FileStr[predicate->source->file], predicate->source->line); fprintf(stderr, " warning: predicate applied for >1 lookahead %d-sequences\n", predicate->k); fprintf(stderr, ErrHdr, FileStr[predicate->source->file], predicate->source->line); fprintf(stderr, " predicate text: \"%s\"\n", (predicate->expr == NULL ? "(null)" : predicate->expr) ); fprintf(stderr, ErrHdr, FileStr[predicate->source->file], predicate->source->line); fprintf(stderr, " You may only want one lookahead %d-sequence to apply\n", predicate->k); fprintf(stderr, ErrHdr, FileStr[predicate->source->file], predicate->source->line); fprintf(stderr, " Try using a context guard '(...)? =>'\n"); predicate->source->ctxwarned = 1; } verify_context(predicate->right); /* MR10 */ } /* * If delta is the set of ambiguous lookahead sequences, then make sure that * the predicate(s) for productions alt1,alt2 cover the sequences in delta. * * For example, * a : <>? (A B|A C) * | b * ; * b : <>? A B * | A C * ; * * This should give a warning that (A C) predicts both productions and alt2 * does not have a predicate in the production that generates (A C). * * The warning detection is simple. Let delta = LOOK(alt1) intersection LOOK(alt2). * Now, if ( delta set-difference context(predicates-for-alt1) != empty then * alt1 does not "cover" all ambiguous sequences. * * If ambig is nonempty, then ambig in LL(k) sense -> use tree info; else use fset * info. Actually, sets are used only if k=1 for this grammar. */ static void #ifdef __USE_PROTOS ensure_predicates_cover_ambiguous_lookahead_sequences ( Junction *alt1, Junction *alt2, char *sub, Tree *ambig ) #else ensure_predicates_cover_ambiguous_lookahead_sequences( alt1, alt2, sub, ambig ) Junction *alt1; Junction *alt2; char *sub; Tree *ambig; #endif { if ( !ParseWithPredicates ) return; if ( ambig!=NULL ) { Tree *non_covered = NULL; if ( alt1->predicate!=NULL ) non_covered = tdif(ambig, alt1->predicate, alt1->fset, alt2->fset); if ( (non_covered!=NULL || alt1->predicate==NULL) && WarningLevel>1 ) { fprintf(stderr, ErrHdr, FileStr[alt1->file], alt1->line); fprintf(stderr, " warning: alt %d %shas no predicate to resolve ambiguity", alt1->altnum, sub); if ( alt1->predicate!=NULL && non_covered!=NULL ) { fprintf(stderr, " upon"); preorder(non_covered); } else if ( alt1->predicate==NULL ) { fprintf(stderr, " upon"); preorder(ambig->down); } fprintf(stderr, "\n"); } Tfree(non_covered); non_covered = NULL; if ( alt2->predicate!=NULL ) non_covered = tdif(ambig, alt2->predicate, alt1->fset, alt2->fset); if ( (non_covered!=NULL || alt2->predicate==NULL) && WarningLevel>1 ) { fprintf(stderr, ErrHdr, FileStr[alt2->file], alt2->line); fprintf(stderr, " warning: alt %d %shas no predicate to resolve ambiguity", alt2->altnum, sub); if ( alt2->predicate!=NULL && non_covered!=NULL ) { fprintf(stderr, " upon"); preorder(non_covered); } else if ( alt2->predicate==NULL ) { fprintf(stderr, " upon"); preorder(ambig->down); } fprintf(stderr, "\n"); } Tfree(non_covered); } else if ( !set_nil(alt1->fset[1]) ) { set delta, non_covered; delta = set_and(alt1->fset[1], alt2->fset[1]); non_covered = set_dif(delta, covered_set(alt1->predicate)); if ( set_deg(non_covered)>0 && WarningLevel>1 ) { fprintf(stderr, ErrHdr, FileStr[alt1->file], alt1->line); fprintf(stderr, " warning: alt %d %shas no predicate to resolve ambiguity", alt1->altnum, sub); if ( alt1->predicate!=NULL ) { fprintf(stderr, " upon "); s_fprT(stderr, non_covered); } fprintf(stderr, "\n"); } set_free( non_covered ); non_covered = set_dif(delta, covered_set(alt2->predicate)); if ( set_deg(non_covered)>0 && WarningLevel>1 ) { fprintf(stderr, ErrHdr, FileStr[alt2->file], alt2->line); fprintf(stderr, " warning: alt %d %shas no predicate to resolve ambiguity", alt2->altnum, sub); if ( alt2->predicate!=NULL ) { fprintf(stderr, " upon "); s_fprT(stderr, non_covered); } fprintf(stderr, "\n"); } set_free( non_covered ); set_free( delta ); } else fatal_internal("productions have no lookahead in predicate checking routine"); } #ifdef __USE_PROTOS void MR_doPredicatesHelp(int inGuessBlock,Junction *alt1,Junction *alt2,int jtype,char *sub) #else void MR_doPredicatesHelp(inGuessBlock,alt1,alt2,jtype,sub) int inGuessBlock; Junction *alt1; Junction *alt2; int jtype; char *sub; #endif { Predicate *p1; Predicate *p2; Junction *parentRule=MR_nameToRuleBlk(alt1->rname); if (inGuessBlock && WarningLevel <= 1) return; /* let antlr give the usual error message */ if (alt1->predicate == NULL && alt2->predicate == NULL) return; if ( (jtype == RuleBlk || jtype == aSubBlk) && (alt1->predicate == NULL && alt2->predicate != NULL)) { fprintf(stderr, ErrHdr, FileStr[parentRule->file],parentRule->line); fprintf(stderr," warning: alt %d line %d and alt %d line %d of %s\n%s%s%s", alt1->altnum, alt1->line, alt2->altnum, alt2->line, sub, " These alts have ambig lookahead sequences resolved by a predicate for\n", " the second choice. The second choice may not be reachable.\n", " You may want to use a complementary predicate or rearrange the alts\n" ); return; }; /* first do the easy comparison. then do the hard one */ if (MR_comparePredicates(alt1->predicate,alt2->predicate)) { if (jtype == aLoopBegin || jtype == aPlusBlk ) { /* I'm not sure this code is reachable. Predicates following a (...)+ or (...)* block are probably considered validation predicates and therefore not participate in the predication expression */ fprintf(stderr, ErrHdr,FileStr[parentRule->file],parentRule->line); fprintf(stderr," warning: %s of %s in rule %s\n (file %s alt %d line %d and alt %d line %d)\n%s", "the predicates used to disambiguate optional/exit paths of ", sub, CurRule, FileStr[alt1->file], alt1->altnum, alt1->line, alt2->altnum, alt2->line, " are identical and have no resolving power\n"); } else { fprintf(stderr, ErrHdr, FileStr[parentRule->file], parentRule->line); fprintf(stderr," warning: %s rule %s\n (file %s alt %d line %d and alt %d line %d)\n%s", "the predicates used to disambiguate", CurRule, FileStr[alt1->file], alt1->altnum, alt1->line, alt2->altnum, alt2->line, " are identical and have no resolving power\n"); }; } else { p1=predicate_dup_without_context(alt1->predicate); p1=MR_unfold(p1); MR_clearPredEntry(p1); MR_simplifyInverted(p1,0); p1=MR_predSimplifyALL(p1); p2=predicate_dup_without_context(alt2->predicate); p2=MR_unfold(p2); MR_clearPredEntry(p2); MR_simplifyInverted(p2,0); p2=MR_predSimplifyALL(p2); if (MR_comparePredicates(p1,p2)) { if (jtype == aLoopBegin || jtype == aPlusBlk ) { fprintf(stderr, ErrHdr, FileStr[parentRule->file], parentRule->line); fprintf(stderr," warning: %s of %s in rule %s\n (file %s alt %d line %d and alt %d line %d)\n%s%s", "the predicates used to disambiguate optional/exit paths of ", sub, CurRule, FileStr[alt1->file], alt1->altnum, alt1->line, alt2->altnum, alt2->line, " are identical when compared without context and may have no\n", " resolving power for some lookahead sequences.\n"); } else { fprintf(stderr, ErrHdr, FileStr[parentRule->file], parentRule->line); fprintf(stderr," warning: %s rule %s\n (file %s alt %d line %d and alt %d line %d)\n%s%s", "the predicates used to disambiguate", CurRule, FileStr[alt1->file], alt1->altnum, alt1->line, alt2->altnum, alt2->line, " are identical when compared without context and may have no\n", " resolving power for some lookahead sequences.\n"); }; if (InfoP) { fprintf(output,"\n#if 0\n\n"); fprintf(output,"The following predicates are identical when compared without\n"); fprintf(output," lookahead context information. For some ambiguous lookahead\n"); fprintf(output," sequences they may not have any power to resolve the ambiguity.\n"); fprintf(output,"\n"); fprintf(output,"Choice 1: %s alt %d line %d file %s\n\n", MR_ruleNamePlusOffset( (Node *) alt1), alt1->altnum, alt1->line, FileStr[alt1->file]); fprintf(output," The original predicate for choice 1 with available context information:\n\n"); MR_dumpPred1(2,alt1->predicate,1); fprintf(output," The predicate for choice 1 after expansion (but without context information):\n\n"); MR_dumpPred1(2,p1,0); if (p1 == NULL) { Predicate *phelp; fprintf(output," The predicate for choice 1 after expansion (but before simplification)\n\n"); phelp=predicate_dup_without_context(alt1->predicate); phelp=MR_unfold(phelp); MR_clearPredEntry(phelp); MR_simplifyInverted(phelp,0); phelp=MR_predSimplifyALLX(phelp,1); MR_dumpPred1(2,phelp,0); predicate_free(phelp); }; fprintf(output,"\n"); fprintf(output,"Choice 2: %s alt %d line %d file %s\n\n", MR_ruleNamePlusOffset( (Node *) alt2), alt2->altnum, alt2->line, FileStr[alt2->file]); fprintf(output," The original predicate for choice 2 with available context information:\n\n"); MR_dumpPred1(1,alt2->predicate,1); fprintf(output," The predicate for choice 2 after expansion (but without context information):\n\n"); MR_dumpPred1(1,p2,0); if (p2 == NULL) { Predicate *phelp; fprintf(output," The predicate for choice 2 after expansion (but before simplification)\n\n"); phelp=predicate_dup_without_context(alt2->predicate); phelp=MR_unfold(phelp); MR_clearPredEntry(phelp); MR_simplifyInverted(phelp,0); phelp=MR_predSimplifyALLX(phelp,1); MR_dumpPred1(2,phelp,0); predicate_free(phelp); }; fprintf(output,"\n#endif\n"); }; } else if (MR_secondPredicateUnreachable(p1,p2)) { if (jtype == aLoopBegin || jtype == aPlusBlk ) { fprintf(stderr, ErrHdr, FileStr[parentRule->file], parentRule->line); fprintf(stderr," warning: %s of %s in rule %s\n (file %s alt %d line %d and alt %d line %d)\n%s%s", "the predicate used to disambiguate the first choice of the optional/exit paths of ", sub, CurRule, FileStr[alt1->file], alt1->altnum, alt1->line, alt2->altnum, alt2->line, " appears to \"cover\" the second predicate when compared without context.\n", " The second predicate may have no resolving power for some lookahead sequences.\n"); } else { fprintf(stderr, ErrHdr, FileStr[parentRule->file], parentRule->line); fprintf(stderr," warning: %s rule %s\n (file %s alt %d line %d and alt %d line %d)\n%s%s", "the predicate used to disambiguate the first choice of", CurRule, FileStr[alt1->file], alt1->altnum, alt1->line, alt2->altnum, alt2->line, " appears to \"cover\" the second predicate when compared without context.\n", " The second predicate may have no resolving power for some lookahead sequences.\n"); }; if (InfoP) { fprintf(output,"\n#if 0\n\n"); fprintf(output,"The first predicate appears to \"cover\" the second predicate when they\n"); fprintf(output," are compared without lookahead context information. For some ambiguous\n"); fprintf(output," lookahead sequences the second predicate may not have any power to\n"); fprintf(output," resolve the ambiguity.\n"); fprintf(output,"\n"); fprintf(output,"Choice 1: %s alt %d line %d file %s\n\n", MR_ruleNamePlusOffset( (Node *) alt1), alt1->altnum, alt1->line, FileStr[alt1->file]); fprintf(output," The original predicate for choice 1 with available context information:\n\n"); MR_dumpPred1(2,alt1->predicate,1); fprintf(output," The predicate for choice 1 after expansion (but without context information):\n\n"); MR_dumpPred1(2,p1,0); if (p1 == NULL) { Predicate *phelp; fprintf(output," The predicate for choice 1 after expansion (but before simplification)\n\n"); phelp=predicate_dup_without_context(alt1->predicate); phelp=MR_unfold(phelp); MR_clearPredEntry(phelp); MR_simplifyInverted(phelp,0); phelp=MR_predSimplifyALLX(phelp,1); MR_dumpPred1(2,phelp,0); predicate_free(phelp); }; fprintf(output,"\n"); fprintf(output,"Choice 2: %s alt %d line %d file %s\n\n", MR_ruleNamePlusOffset( (Node *) alt2), alt2->altnum, alt2->line, FileStr[alt2->file]); fprintf(output," The original predicate for choice 2 with available context information:\n\n"); MR_dumpPred1(1,alt2->predicate,1); fprintf(output," The predicate for choice 2 after expansion (but without context information):\n\n"); MR_dumpPred1(1,p2,0); if (p2 == NULL) { Predicate *phelp; fprintf(output," The predicate for choice 2 after expansion (but before simplification)\n\n"); phelp=predicate_dup_without_context(alt2->predicate); phelp=MR_unfold(phelp); MR_clearPredEntry(phelp); MR_simplifyInverted(phelp,0); phelp=MR_predSimplifyALLX(phelp,1); MR_dumpPred1(2,phelp,0); predicate_free(phelp); }; fprintf(output,"\n#endif\n"); }; }; predicate_free(p1); predicate_free(p2); }; } static int totalOverflow=0; /* MR9 */ void #ifdef __USE_PROTOS HandleAmbiguity( Junction *block, Junction *alt1, Junction *alt2, int jtype ) #else HandleAmbiguity( block, alt1, alt2, jtype ) Junction *block; Junction *alt1; Junction *alt2; int jtype; #endif { unsigned **ftbl; set *fset, b; int i, numAmbig,n2; Tree *ambig=NULL, *t, *u; char *sub = ""; long n; int thisOverflow=0; /* MR9 */ long set_deg_value; /* MR10 */ long threshhold; /* MR10 */ require(block!=NULL, "NULL block"); require(block->ntype==nJunction, "invalid block"); /* These sets are used to constrain LL_k set, but are made CLL_k long anyway */ fset = (set *) calloc(CLL_k+1, sizeof(set)); require(fset!=NULL, "cannot allocate fset"); ftbl = (unsigned **) calloc(CLL_k+1, sizeof(unsigned *)); require(ftbl!=NULL, "cannot allocate ftbl"); /* create constraint table and count number of possible ambiguities (use<=LL_k) */ for (n=1,i=1; i<=CLL_k; i++) { b = set_and(alt1->fset[i], alt2->fset[i]); /* MR9 */ set_deg_value = set_deg(b); /* MR10 */ if (n > 0) { /* MR10 */ threshhold = LONG_MAX / n; /* MR10 */ if (set_deg_value <= threshhold) { /* MR10 */ n *= set_deg_value; /* MR10 */ } else { /* MR10 */ n=LONG_MAX; /* MR9 */ if (totalOverflow == 0) { #if 0 /* MR10 comment this out because it just makes users worry */ /* MR9 */ warnNoFL("Overflow in computing number of possible ambiguities in HandleAmbiguity\n"); #endif /* MR9 */ }; /* MR9 */ thisOverflow++; /* MR9 */ totalOverflow++; /* MR9 */ }; /* MR10 */ } else { /* MR10 */ n *= set_deg_value; /* MR9 */ }; fset[i] = set_dup(b); ftbl[i] = set_pdq(b); set_free(b); } switch ( jtype ) { case aSubBlk: sub = "of (..) "; break; case aOptBlk: sub = "of {..} "; break; case aLoopBegin: sub = "of (..)* "; break; case aLoopBlk: sub = "of (..)* "; break; case aPlusBlk: sub = "of (..)+ "; break; case RuleBlk: sub = "of the rule itself "; break; default : sub = ""; break; } /* If the block is marked as a compressed lookahead only block, then * simply return; ambiguity warning is given only at warning level 2. */ if ( block->approx>0 ) { if ( ParseWithPredicates ) { if (alt1->predicate != NULL) predicate_free(alt1->predicate); /* MR12 */ if (alt2->predicate != NULL) predicate_free(alt2->predicate); /* MR12 */ require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty"); alt1->predicate = MR_find_predicates_and_supp((Node *)alt1->p1); require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty"); require (MR_predicate_context_completed(alt1->predicate),"predicate alt 1 not completed"); alt1->predicate=MR_predSimplifyALL(alt1->predicate); require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty"); alt2->predicate = MR_find_predicates_and_supp((Node *)alt2->p1); require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty"); require (MR_predicate_context_completed(alt2->predicate),"predicate alt 2 not completed"); alt2->predicate=MR_predSimplifyALL(alt2->predicate); MR_doPredicatesHelp(0,alt1,alt2,jtype,sub); if ( HoistPredicateContext && (alt1->predicate!=NULL||alt2->predicate!=NULL) ) { verify_context(alt1->predicate); verify_context(alt2->predicate); } if ( HoistPredicateContext && (alt1->predicate!=NULL||alt2->predicate!=NULL) && WarningLevel>1 ) ensure_predicates_cover_ambiguous_lookahead_sequences(alt1, alt2, sub, ambig); } if ( WarningLevel>1 ) { fprintf(stderr, ErrHdr, FileStr[alt1->file], alt1->line); if ( jtype == aLoopBegin || jtype == aPlusBlk ) fprintf(stderr, " warning: optional/exit path and alt(s) %sambiguous upon", sub); else fprintf(stderr, " warning(approx): alts %d and %d %sambiguous upon", alt1->altnum, alt2->altnum, sub); dumpAmbigMsg(fset, stderr, 0); MR_traceAmbSource(fset,alt1,alt2); } for (i=1; i<=CLL_k; i++) set_free( fset[i] ); free((char *)fset); for (i=1; i<=CLL_k; i++) free( (char *)ftbl[i] ); free((char *)ftbl); return; } /* if all sets have degree 1 for k=1 permutation; * don't bother doing full LL(k) analysis. * (This "if" block handles the LL(1) case) */ n2 = 0; for (i=1; ifset[i])+set_deg(alt2->fset[i]); /* here STARTS the special case in which the lookahead sets for alt1 and alt2 all have degree 1 for kp1)!=NULL ) { if ( WarningLevel==1 ) { for (i=1; i<=CLL_k; i++) set_free( fset[i] ); free((char *)fset); for (i=1; i<=CLL_k; i++) free( (char *)ftbl[i] ); free((char *)ftbl); return; } fprintf(stderr, ErrHdr, FileStr[alt1->file], alt1->line); if ( jtype == aLoopBegin || jtype == aPlusBlk ) fprintf(stderr, " warning: optional/exit path and alt(s) %sambiguous upon", sub); else fprintf(stderr, " warning: alts %d and %d %sambiguous upon", alt1->altnum, alt2->altnum, sub); dumpAmbigMsg(fset, stderr, 0); MR_traceAmbSource(fset,alt1,alt2); } ambig = NULL; if ( LL_k>1 ) ambig = make_tree_from_sets(alt1->fset, alt2->fset); if ( ParseWithPredicates ) { if (alt1->predicate != NULL) predicate_free(alt1->predicate); /* MR12 */ if (alt2->predicate != NULL) predicate_free(alt2->predicate); /* MR12 */ require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty"); alt1->predicate = MR_find_predicates_and_supp((Node *)alt1->p1); require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty"); require (MR_predicate_context_completed(alt1->predicate),"predicate alt 1 not completed"); alt1->predicate=MR_predSimplifyALL(alt1->predicate); require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty"); alt2->predicate = MR_find_predicates_and_supp((Node *)alt2->p1); require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty"); require (MR_predicate_context_completed(alt2->predicate),"predicate alt 2 not completed"); alt2->predicate=MR_predSimplifyALL(alt2->predicate); MR_doPredicatesHelp(0,alt1,alt2,jtype,sub); if ( HoistPredicateContext && (alt1->predicate!=NULL||alt2->predicate!=NULL) ) { verify_context(alt1->predicate); verify_context(alt2->predicate); } if (HoistPredicateContext&&(alt1->predicate!=NULL||alt2->predicate!=NULL) && WarningLevel>1) ensure_predicates_cover_ambiguous_lookahead_sequences(alt1, alt2, sub, ambig); if ( WarningLevel == 1 && (alt1->predicate!=NULL||alt2->predicate!=NULL)) { for (i=1; i<=CLL_k; i++) set_free( fset[i] ); free((char *)fset); for (i=1; i<=CLL_k; i++) free( (char *)ftbl[i] ); free((char *)ftbl); Tfree(ambig); return; } } /* end TJP (10/24/93) */ fprintf(stderr, ErrHdr, FileStr[alt1->file], alt1->line); if ( jtype == aLoopBegin || jtype == aPlusBlk ) fprintf(stderr, " warning: optional/exit path and alt(s) %sambiguous upon", sub); else fprintf(stderr, " warning: alts %d and %d %sambiguous upon", alt1->altnum, alt2->altnum, sub); if ( elevel == 3 && LL_k>1 ) { preorder(ambig); fprintf(stderr, "\n"); for (i=1; i<=CLL_k; i++) set_free( fset[i] ); free((char *)fset); for (i=1; i<=CLL_k; i++) free( (char *)ftbl[i] ); free((char *)ftbl); Tfree(ambig); return; }; Tfree(ambig); dumpAmbigMsg(fset, stderr, 0); /* because this is a special case in which both alt1 and alt2 have lookahead sets of degree 1 for kaltnum; CurAmbigAlt2 = alt2->altnum; CurAmbigbtype = sub; CurAmbigfile = alt1->file; CurAmbigline = alt1->line; /* Don't do full LL(n) analysis if (...)? block because the block, by definition, defies LL(n) analysis. If guess (...)? block and ambiguous then don't remove anything from 2nd alt to resolve ambig. Want to predict with LL sup 1 ( n ) decision not LL(n) if guess block since it is much cheaper than LL(n). LL sup 1 ( n ) "covers" the LL(n) lookahead information. Note: LL(n) context cannot be computed for semantic predicates when followed by (..)?. If (..)? then we scream "AAAHHHH! No LL(n) analysis will help" Is 'ambig' always defined if we enter this if? I hope so because the 'ensure...()' func references it. TJP Nov 1993. */ /* THM MR30: Instead of using first_item_is_guss_block we use first_item_is_guess_block_extra which will look inside a loop block for a guess block. In other words ( (...)? )*. It there is an ambiguity in this circumstance then we suppress the normal methods of resolving ambiguities. */ if ( first_item_is_guess_block_extra((Junction *)alt1->p1)!=NULL ) { if ( ParseWithPredicates ) { if (alt1->predicate != NULL) predicate_free(alt1->predicate); /* MR12 */ if (alt2->predicate != NULL) predicate_free(alt2->predicate); /* MR12 */ require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty"); alt1->predicate = MR_find_predicates_and_supp((Node *)alt1->p1); require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty"); require (MR_predicate_context_completed(alt1->predicate),"predicate alt 1 not completed"); alt1->predicate=MR_predSimplifyALL(alt1->predicate); require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty"); alt2->predicate = MR_find_predicates_and_supp((Node *)alt2->p1); require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty"); require (MR_predicate_context_completed(alt2->predicate),"predicate alt 2 not completed"); alt2->predicate=MR_predSimplifyALL(alt2->predicate); MR_doPredicatesHelp(1,alt1,alt2,jtype,sub); if ( HoistPredicateContext && (alt1->predicate!=NULL||alt2->predicate!=NULL) ) { verify_context(alt1->predicate); verify_context(alt2->predicate); } if ( HoistPredicateContext && (alt1->predicate!=NULL||alt2->predicate!=NULL) && WarningLevel>1 ) ensure_predicates_cover_ambiguous_lookahead_sequences(alt1, alt2, sub, ambig); if ( WarningLevel==1 && (alt1->predicate!=NULL||alt2->predicate!=NULL)) { for (i=1; i<=CLL_k; i++) set_free( fset[i] ); free((char *)fset); for (i=1; i<=CLL_k; i++) free( (char *)ftbl[i] ); free((char *)ftbl); return; } } if ( WarningLevel>1 ) { fprintf(stderr, ErrHdr, FileStr[alt1->file], alt1->line); if ( jtype == aLoopBegin || jtype == aPlusBlk ) fprintf(stderr, " warning: optional/exit path and alt(s) %sambiguous upon", sub); else fprintf(stderr, " warning: alts %d and %d %sambiguous upon", alt1->altnum, alt2->altnum, sub); dumpAmbigMsg(fset, stderr, 0); MR_traceAmbSource(fset,alt1,alt2); } for (i=1; i<=CLL_k; i++) set_free( fset[i] ); free((char *)fset); for (i=1; i<=CLL_k; i++) free( (char *)ftbl[i] ); free((char *)ftbl); return; } /* Not resolved with (..)? block. Do full LL(n) analysis */ /* ambig is the set of k-tuples truly in common between alt 1 and alt 2 */ /* MR11 VerifyAmbig once used fset destructively */ ambig = VerifyAmbig(alt1, alt2, ftbl, fset, &t, &u, &numAmbig); /* are all things in intersection really ambigs? */ if (thisOverflow || numAmbig < n ) /* MR9 */ { Tree *v; /* remove ambig permutation from 2nd alternative to resolve ambig; * We want to compute the set of artificial tuples, arising from * LL sup 1 (n) compression, that collide with real tuples from the * 2nd alternative. This is the set of "special case" tuples that * the LL sup 1 (n) decision template maps incorrectly. */ /* when generating code in genExpr() it does * * if ( genExprSets(j->fset) && !genExprTree(j->ftree)) {... * * Sooooo the j->ftree is the tree of alt2 * after removal of conflicts, not alt1 ! */ if ( ambig!=NULL ) { /* at the top of ambig is an ALT node */ for (v=ambig->down; v!=NULL; v=v->right) { u = trm_perm(u, v); /* remove v FROM u */ } /* fprintf(stderr, "after rm alt2:"); preorder(u); fprintf(stderr, "\n");*/ } Tfree( t ); alt1->ftree = tappend(alt1->ftree, u); alt1->ftree = tleft_factor(alt1->ftree); } if ( ambig==NULL ) { for (i=1; i<=CLL_k; i++) set_free( fset[i] ); free((char *)fset); for (i=1; i<=CLL_k; i++) free( (char *)ftbl[i] ); free((char *)ftbl); return; } ambig = tleft_factor(ambig); /* TJP: * At this point, we surely have an LL(k) ambiguity. Check for predicates */ if ( ParseWithPredicates ) { if (alt1->predicate != NULL) predicate_free(alt1->predicate); /* MR12 */ if (alt2->predicate != NULL) predicate_free(alt2->predicate); /* MR12 */ require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty"); alt1->predicate = MR_find_predicates_and_supp((Node *)alt1->p1); require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty"); require (MR_predicate_context_completed(alt1->predicate),"predicate alt 1 not completed"); alt1->predicate=MR_predSimplifyALL(alt1->predicate); require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty"); alt2->predicate = MR_find_predicates_and_supp((Node *)alt2->p1); require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty"); require (MR_predicate_context_completed(alt2->predicate),"predicate alt 2 not completed"); alt2->predicate=MR_predSimplifyALL(alt2->predicate); MR_doPredicatesHelp(0,alt1,alt2,jtype,sub); if ( HoistPredicateContext && (alt1->predicate!=NULL||alt2->predicate!=NULL) ) { verify_context(alt1->predicate); verify_context(alt2->predicate); } if ( HoistPredicateContext && (alt1->predicate!=NULL||alt2->predicate!=NULL) && WarningLevel>1 ) ensure_predicates_cover_ambiguous_lookahead_sequences(alt1, alt2, sub, ambig); if ( WarningLevel==1 && (alt1->predicate!=NULL||alt2->predicate!=NULL)) { /* We found at least one pred for at least one of the alts; * If warnings are low, just return. */ Tfree(ambig); for (i=1; i<=CLL_k; i++) set_free( fset[i] ); free((char *)fset); for (i=1; i<=CLL_k; i++) free( (char *)ftbl[i] ); free((char *)ftbl); return; } /* else we're gonna give a warning */ } /* end TJP addition */ fprintf(stderr, ErrHdr, FileStr[alt1->file], alt1->line); if ( jtype == aLoopBegin || jtype == aPlusBlk ) fprintf(stderr, " warning: optional/exit path and alt(s) %sambiguous upon", sub); else fprintf(stderr, " warning: alts %d and %d %sambiguous upon", alt1->altnum, alt2->altnum, sub); if ( elevel == 3 ) { preorder(ambig->down); /* <===== k>1 ambiguity message data */ fprintf(stderr, "\n"); } else { MR_skipped_e3_report=1; dumpAmbigMsg(fset, stderr, 0); }; MR_traceAmbSourceK(ambig,alt1,alt2); /* <====== k>1 ambiguity aid */ Tfree(ambig); for (i=1; i<=CLL_k; i++) set_free( fset[i] ); free((char *)fset); for (i=1; i<=CLL_k; i++) free( (char *)ftbl[i] ); free((char *)ftbl); } /* Don't analyze alpha block of (alpha)?beta; if (alpha)? then analyze * Return the 1st node of the beta block if present else return j. */ Junction * #ifdef __USE_PROTOS analysis_point( Junction *j ) #else analysis_point( j ) Junction *j; #endif { Junction *gblock; /* MR13b When there was an action/predicate preceding a guess block the guess block became invisible at the analysis_point. first_item_is_guess_block accepts any kind of node, despite the fact that the formal is a junction. But I don't want to have to change it all over the place until I know it works. */ if ( j->ntype != nJunction && j->ntype != nAction) return j; gblock = first_item_is_guess_block((Junction *)j); if ( gblock!=NULL ) { Junction *past = gblock->end; Junction *p; require(past!=NULL, "analysis_point: no end block on (...)? block"); for (p=(Junction *)past->p1; p!=NULL; ) { if ( p->ntype==nAction ) { p=(Junction *)((ActionNode *)p)->next; continue; } if ( p->ntype!=nJunction ) { past->alpha_beta_guess_end=1; /* MR14 */ return (Junction *)past->p1; } if ( p->jtype==EndBlk || p->jtype==EndRule ) { return j; } /* MR6 */ /* MR6 A guess block is of the form "(alpha)? beta" or "(alpha)?". */ /* MR6 When beta is omitted (second form) this means "(alpha)? alpha". */ /* MR6 The program does not store another copy of alpha in this case. */ /* MR6 During analysis when the program needs to know what follows the */ /* MR6 guess clause. It calls this routine. */ /* MR6 */ /* MR6 If it is of the form "(alpha)? beta" it returns a pointer to beta.*/ /* MR6 */ /* MR6 If it is of the form "(alpha)?" it returns a pointer to the guess */ /* MR6 block itself thereby reusing the junction tree. */ /* MR6 */ /* MR6 It works by searching the "next in sequence" chain (skipping actions) */ /* MR6 searching for a RuleRef or Token node. (Those are the only 4 kinds */ /* MR6 of nodes: Junctions, RuleRef, Token, and Action.) */ /* MR6 */ /* MR6 This won't work for the special case "(alpha)? ()" because it has no */ /* MR6 rule references or token nodes. It eventually encounters a */ /* MR6 junction of type EndBlk or EndRule and says to its caller: nothing */ /* MR6 more here to analyze - must be of the form "(alpha)?". */ /* MR6 */ /* MR6 In the case of "(alpha)? ()" it should return a pointer to "()" */ /* MR6 */ /* MR6 I think. */ /* MR6 */ if ( p->jtype!=Generic) { /* MR6 */ past->alpha_beta_guess_end=1; /* MR14 */ return (Junction *)past->p1; /* MR6 */ }; /* MR6 */ p=(Junction *)p->p1; } } return j; } set #ifdef __USE_PROTOS First( Junction *j, int k, int jtype, int *max_k ) #else First( j, k, jtype, max_k ) Junction *j; int k; int jtype; int *max_k; #endif { Junction *alt1, *alt2; set a, rk, fCurBlk; int savek; int p1, p2; int save_maintainBackTrace; require(j->ntype==nJunction, "First: non junction passed"); /* C o m p u t e F I R S T s e t w i t h k l o o k a h e a d */ fCurBlk = rk = empty; for (alt1=j; alt1!=NULL; alt1 = (Junction *)alt1->p2 ) { Junction * p = NULL; Junction * p1junction = NULL; p = analysis_point((Junction *)alt1->p1); p1junction = (Junction *) (alt1->p1); #if 0 if (p != p1junction) { fprintf(stdout,"Analysis point for #%d is #%d", p1junction->seq, p->seq); /* debug */ } #endif REACH(p, k, &rk, alt1->fset[k]); require(set_nil(rk), "rk != nil"); set_free(rk); set_orin(&fCurBlk, alt1->fset[k]); } /* D e t e c t A m b i g u i t i e s */ *max_k = 1; for (p1=1,alt1=j; alt1!=NULL; alt1 = (Junction *)alt1->p2, p1++) { for (p2=1,alt2=(Junction *)alt1->p2; alt2!=NULL; alt2 = (Junction *)alt2->p2, p2++) { savek = k; a = set_and(alt1->fset[k], alt2->fset[k]); while ( !set_nil(a) ) { /* if we have hit the max k requested, just give warning */ if ( j->approx==k ) { } if ( k==CLL_k ) { #ifdef NOT_USED *** int save_LL_k = LL_k; *** int save_CLL_k = CLL_k; *** /* Get new LL_k from interactive feature if enabled */ *** if ( AImode ) *** AmbiguityDialog(j, jtype, alt1, alt2, &CLL_k, &LL_k); #endif *max_k = CLL_k; save_maintainBackTrace=MR_MaintainBackTrace; if (AlphaBetaTrace) MR_MaintainBackTrace=0; HandleAmbiguity(j, alt1, alt2, jtype); MR_MaintainBackTrace=save_maintainBackTrace; break; } else { Junction *p = analysis_point((Junction *)alt1->p1); Junction *q = analysis_point((Junction *)alt2->p1); k++; /* attempt ambig alts again with more lookahead */ REACH(p, k, &rk, alt1->fset[k]); require(set_nil(rk), "rk != nil"); REACH(q, k, &rk, alt2->fset[k]); require(set_nil(rk), "rk != nil"); set_free(a); a = set_and(alt1->fset[k], alt2->fset[k]); if ( k > *max_k ) *max_k = k; } } set_free(a); k = savek; } } return fCurBlk; } cdrdao-cdrdao-f00afb2/pccts/antlr/fset2.c000066400000000000000000001574201511453746600203320ustar00rootroot00000000000000/* * fset2.c * * Compute FIRST sets for full LL(k) * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2001 */ #include #include "pcctscfg.h" #include #ifdef PCCTS_USE_STDARG #include #else #include #endif #include "set.h" #include "syn.h" #include "hash.h" #include "generic.h" #include "dlgdef.h" /* ick! globals. Used by permute() to track which elements of a set have been used */ static int *findex; set *fset; /* MR11 make global */ static unsigned **ftbl; static set *constrain; /* pts into fset. constrains tToken() to 'constrain' */ int ConstrainSearch; int maxk; /* set to initial k upon tree construction request */ /* MR11 make global */ static Tree *FreeList = NULL; #ifdef __USE_PROTOS static int tmember_of_context(Tree *, Predicate *); #else static int tmember_of_context(); #endif #if TREE_DEBUG set set_of_tnodes_in_use; int stop_on_tnode_seq_number=(-1); /* (-1) to disable */ #endif /* Do root * Then each sibling */ void #ifdef __USE_PROTOS preorder( Tree *tree ) #else preorder( tree ) Tree *tree; #endif { if ( tree == NULL ) return; if ( tree->down != NULL ) fprintf(stderr, " ("); if ( tree->token == ALT ) fprintf(stderr, " ALT"); else fprintf(stderr, " %s", TerminalString(tree->token)); if ( tree->token==EpToken ) fprintf(stderr, "(%d)", tree->v.rk); preorder(tree->down); if ( tree->down != NULL ) fprintf(stderr, " )"); preorder(tree->right); } #ifdef __USE_PROTOS int MR_tree_matches_constraints(int k,set * constrain,Tree *t) #else int MR_tree_matches_constraints(k,constrain,t) int k; set * constrain; Tree * t; #endif { int i; Tree *u; if (k == 0) return 1; /* for testing guard predicates: if the guard tree is shorter than the constraint then it is a match. The reason is that a guard of (A B) should be equivalent to a guard of (A B . . .) where "." matches every token. Thus a match which runs out of tree before constraint is a match. */ if (t == NULL) return 1; require (set_deg(constrain[0]) == 1, "MR_tree_matches_constraints: set_deg != 1"); i=set_int(constrain[0]); if (t->token != i) return 0; if (k-1 == 0) return 1; for (u=t->down; u != NULL; u=u->right) { if (MR_tree_matches_constraints(k-1,&constrain[1],u)) { return 1; }; }; return 0; } /* check the depth of each primary sibling to see that it is exactly * k deep. e.g.; * * ALT * | * A ------- B * | | * C -- D E * * Remove all branches <= k deep. * * Added by TJP 9-23-92 to make the LL(k) constraint mechanism to work. */ static int pruneCount=0; static int prunePeak=200; Tree * #ifdef __USE_PROTOS prune( Tree *t, int k ) #else prune( t, k ) Tree *t; int k; #endif { pruneCount++; if (pruneCount > prunePeak+100) { prunePeak=pruneCount; #if 0 *** fprintf(stderr,"pruneCount=%d\n",pruneCount); /*** preorder(t); ***/ *** fprintf(stderr,"\n",pruneCount); #endif }; if ( t == NULL ) { pruneCount--; return NULL; }; if ( t->token == ALT ) fatal_internal("prune: ALT node in FIRST tree"); if ( t->right!=NULL ) t->right = prune(t->right, k); if ( k>1 ) { if ( t->down!=NULL ) t->down = prune(t->down, k-1); if ( t->down == NULL ) { Tree *r = t->right; t->right = NULL; Tfree(t); pruneCount--; return r; } } pruneCount--; return t; } /* build a tree (root child1 child2 ... NULL) */ #ifdef PCCTS_USE_STDARG Tree *tmake(Tree *root, ...) #else Tree *tmake(va_alist) va_dcl #endif { Tree *w; va_list ap; Tree *child, *sibling=NULL, *tail=NULL; #ifndef PCCTS_USE_STDARG Tree *root; #endif #ifdef PCCTS_USE_STDARG va_start(ap, root); #else va_start(ap); root = va_arg(ap, Tree *); #endif child = va_arg(ap, Tree *); while ( child != NULL ) { #ifdef DUM /* added "find end of child" thing TJP March 1994 */ for (w=child; w->right!=NULL; w=w->right) {;} /* find end of child */ #else w = child; #endif if ( sibling == NULL ) {sibling = child; tail = w;} else {tail->right = child; tail = w;} child = va_arg(ap, Tree *); } /* was "root->down = sibling;" */ if ( root==NULL ) root = sibling; else root->down = sibling; va_end(ap); return root; } Tree * #ifdef __USE_PROTOS tnode( int tok ) #else tnode( tok ) int tok; #endif { Tree *p, *newblk; static int n=0; if ( FreeList == NULL ) { /*fprintf(stderr, "tnode: %d more nodes\n", TreeBlockAllocSize);*/ if ( TreeResourceLimit > 0 ) { if ( (n+TreeBlockAllocSize) >= TreeResourceLimit ) { fprintf(stderr, ErrHdr, FileStr[CurAmbigfile], CurAmbigline); fprintf(stderr, " hit analysis resource limit while analyzing alts %d and %d %s\n", CurAmbigAlt1, CurAmbigAlt2, CurAmbigbtype); exit(PCCTS_EXIT_FAILURE); } } newblk = (Tree *)calloc(TreeBlockAllocSize, sizeof(Tree)); if ( newblk == NULL ) { fprintf(stderr, ErrHdr, FileStr[CurAmbigfile], CurAmbigline); fprintf(stderr, " out of memory while analyzing alts %d and %d %s\n", CurAmbigAlt1, CurAmbigAlt2, CurAmbigbtype); exit(PCCTS_EXIT_FAILURE); } n += TreeBlockAllocSize; for (p=newblk; p<&(newblk[TreeBlockAllocSize]); p++) { p->right = FreeList; /* add all new Tree nodes to Free List */ FreeList = p; } } p = FreeList; FreeList = FreeList->right; /* remove a tree node */ p->right = NULL; /* zero out ptrs */ p->down = NULL; p->token = tok; TnodesAllocated++; /* MR10 */ TnodesInUse++; /* MR10 */ if (TnodesInUse > TnodesPeak) TnodesPeak=TnodesInUse; /* MR10 */ #ifdef TREE_DEBUG require(!p->in_use, "tnode: node in use!"); p->in_use = 1; p->seq=TnodesAllocated; set_orel( (unsigned) TnodesAllocated,&set_of_tnodes_in_use); if (stop_on_tnode_seq_number == p->seq) { fprintf(stderr,"\n*** just allocated tnode #%d ***\n", stop_on_tnode_seq_number); }; #endif return p; } static Tree * #ifdef __USE_PROTOS eofnode( int k ) #else eofnode( k ) int k; #endif { Tree *t=NULL; int i; for (i=1; i<=k; i++) { t = tmake(tnode((TokenInd!=NULL?TokenInd[EofToken]:EofToken)), t, NULL); } return t; } void #ifdef __USE_PROTOS _Tfree( Tree *t ) #else _Tfree( t ) Tree *t; #endif { if ( t!=NULL ) { #ifdef TREE_DEBUG if (t->seq == stop_on_tnode_seq_number) { fprintf(stderr,"\n*** just freed tnode #%d ***\n",t->seq); }; require(t->in_use, "_Tfree: node not in use!"); t->in_use = 0; set_rm( (unsigned) t->seq,set_of_tnodes_in_use); #endif t->right = FreeList; FreeList = t; TnodesInUse--; /* MR10 */ } } /* tree duplicate */ Tree * #ifdef __USE_PROTOS tdup( Tree *t ) #else tdup( t ) Tree *t; #endif { Tree *u; if ( t == NULL ) return NULL; u = tnode(t->token); u->v.rk = t->v.rk; u->right = tdup(t->right); u->down = tdup(t->down); return u; } /* tree duplicate (assume tree is a chain downwards) */ Tree * #ifdef __USE_PROTOS tdup_chain( Tree *t ) #else tdup_chain( t ) Tree *t; #endif { Tree *u; if ( t == NULL ) return NULL; u = tnode(t->token); u->v.rk = t->v.rk; u->down = tdup(t->down); return u; } Tree * #ifdef __USE_PROTOS tappend( Tree *t, Tree *u ) #else tappend( t, u ) Tree *t; Tree *u; #endif { Tree *w; /*** fprintf(stderr, "tappend("); *** preorder(t); fprintf(stderr, ","); *** preorder(u); fprintf(stderr, " )\n"); */ if ( t == NULL ) return u; if ( t->token == ALT && t->right == NULL ) return tappend(t->down, u); for (w=t; w->right!=NULL; w=w->right) {;} w->right = u; return t; } /* dealloc all nodes in a tree */ void #ifdef __USE_PROTOS Tfree( Tree *t ) #else Tfree( t ) Tree *t; #endif { if ( t == NULL ) return; Tfree( t->down ); Tfree( t->right ); _Tfree( t ); } /* find all children (alts) of t that require remaining_k nodes to be LL_k * tokens long. * * t-->o * | * a1--a2--...--an <-- LL(1) tokens * | | | * b1 b2 ... bn <-- LL(2) tokens * | | | * . . . * . . . * z1 z2 ... zn <-- LL(LL_k) tokens * * We look for all [Ep] needing remaining_k nodes and replace with u. * u is not destroyed or actually used by the tree (a copy is made). */ Tree * #ifdef __USE_PROTOS tlink( Tree *t, Tree *u, int remaining_k ) #else tlink( t, u, remaining_k ) Tree *t; Tree *u; int remaining_k; #endif { Tree *p; require(remaining_k!=0, "tlink: bad tree"); if ( t==NULL ) return NULL; /*fprintf(stderr, "tlink: u is:"); preorder(u); fprintf(stderr, "\n");*/ if ( t->token == EpToken && t->v.rk == remaining_k ) { require(t->down==NULL, "tlink: invalid tree"); if ( u == NULL ) { /* MR10 */ Tree *tt=t->right; /* MR10 */ _Tfree(t); /* MR10 */ return tt; }; p = tdup( u ); p->right = t->right; _Tfree( t ); return p; } t->down = tlink(t->down, u, remaining_k); t->right = tlink(t->right, u, remaining_k); return t; } /* remove as many ALT nodes as possible while still maintaining semantics */ Tree * #ifdef __USE_PROTOS tshrink( Tree *t ) #else tshrink( t ) Tree *t; #endif { if ( t == NULL ) return NULL; t->down = tshrink( t->down ); t->right = tshrink( t->right ); if ( t->down == NULL ) { if ( t->token == ALT ) { Tree *u = t->right; _Tfree(t); return u; /* remove useless alts */ } return t; } /* (? (ALT (? ...)) s) ==> (? (? ...) s) where s = sibling, ? = match any */ if ( t->token == ALT && t->down->right == NULL) { Tree *u = t->down; u->right = t->right; _Tfree( t ); return u; } /* (? (A (ALT t)) s) ==> (? (A t) s) where A is a token; s,t siblings */ if ( t->token != ALT && t->down->token == ALT && t->down->right == NULL ) { Tree *u = t->down->down; _Tfree( t->down ); t->down = u; return t; } return t; } Tree * #ifdef __USE_PROTOS tflatten( Tree *t ) #else tflatten( t ) Tree *t; #endif { if ( t == NULL ) return NULL; t->down = tflatten( t->down ); t->right = tflatten( t->right ); if ( t->down == NULL ) return t; if ( t->token == ALT ) { Tree *u; /* find tail of children */ for (u=t->down; u->right!=NULL; u=u->right) {;} u->right = t->right; u = t->down; _Tfree( t ); return u; } return t; } Tree * #ifdef __USE_PROTOS tJunc( Junction *p, int k, set *rk ) #else tJunc( p, k, rk ) Junction *p; int k; set *rk; #endif { Tree *t=NULL, *u=NULL; Junction *alt; Tree *tail=NULL, *r; #ifdef DBG_TRAV fprintf(stderr, "tJunc(%d): %s in rule %s\n", k, decodeJType[p->jtype], ((Junction *)p)->rname); #endif /* MR14 */ if (AlphaBetaTrace && p->alpha_beta_guess_end) { /* MR14 */ warnFL( /* MR14 */ "not possible to compute follow set for alpha in an \"(alpha)? beta\" block. ", /* MR14 */ FileStr[p->file],p->line); /* MR14 */ MR_alphaBetaTraceReport(); /* MR14 */ }; /* MR14 */ if (p->alpha_beta_guess_end) { /* MR14 */ return NULL; /* MR14 */ } if ( p->jtype==aLoopBlk || p->jtype==RuleBlk || p->jtype==aPlusBlk || p->jtype==aSubBlk || p->jtype==aOptBlk ) { if ( p->jtype!=aSubBlk && p->jtype!=aOptBlk ) { require(p->lock!=NULL, "rJunc: lock array is NULL"); if ( p->lock[k] ) return NULL; p->lock[k] = TRUE; } /* MR10 */ if (MR_MaintainBackTrace) { /* MR10 */ if (p->jtype != Generic) MR_pointerStackPush(&MR_BackTraceStack,p); /* MR10 */ }; TRAV(p->p1, k, rk, tail); /* MR10 */ if (MR_MaintainBackTrace) { /* MR10 */ if (p->jtype != Generic) MR_pointerStackPop(&MR_BackTraceStack); /* MR10 */ }; if ( p->jtype==RuleBlk ) {p->lock[k] = FALSE; return tail;} r = tmake(tnode(ALT), tail, NULL); for (alt=(Junction *)p->p2; alt!=NULL; alt = (Junction *)alt->p2) { /* if this is one of the added optional alts for (...)+ then break */ if ( alt->ignore ) break; if ( tail==NULL ) {TRAV(alt->p1, k, rk, tail); r->down = tail;} else { /* MR10 */ if (MR_MaintainBackTrace) { /* MR10 */ if (p->jtype != Generic) MR_pointerStackPush(&MR_BackTraceStack,p); /* MR10 */ }; TRAV(alt->p1, k, rk, tail->right); /* MR10 */ if (MR_MaintainBackTrace) { /* MR10 */ if (p->jtype != Generic) MR_pointerStackPop(&MR_BackTraceStack); /* MR10 */ }; if ( tail->right != NULL ) tail = tail->right; } } if ( p->jtype!=aSubBlk && p->jtype!=aOptBlk ) p->lock[k] = FALSE; #ifdef DBG_TREES fprintf(stderr, "blk(%s) returns:",((Junction *)p)->rname); preorder(r); fprintf(stderr, "\n"); #endif if ( r->down == NULL ) {_Tfree(r); return NULL;} return r; } if ( p->jtype==EndRule ) { if ( p->halt ) /* don't want FOLLOW here? */ { /**** if ( ContextGuardTRAV ) return NULL; ****/ set_orel( (unsigned) k, rk); /* indicate this k value needed */ /* MR10 cast */ t = tnode(EpToken); t->v.rk = k; return t; } require(p->lock!=NULL, "rJunc: lock array is NULL"); if ( p->lock[k] ) return NULL; /* if no FOLLOW assume k EOF's */ if ( p->p1 == NULL ) return eofnode(k); p->lock[k] = TRUE; } /* MR14 */ if (p->p1 != NULL && p->guess && p->guess_analysis_point == NULL) { /* MR14 */ Node * guess_point; /* MR14 */ guess_point=(Node *)analysis_point(p); /* MR14 */ if (guess_point == (Node *)p) { /* MR14 */ guess_point=p->p1; /* MR14 */ } /* MR14 */ p->guess_analysis_point=guess_point; /* MR14 */ } if ( p->p2 == NULL ) { /* MR10 */ if (MR_MaintainBackTrace) { /* MR10 */ if (p->jtype != Generic) MR_pointerStackPush(&MR_BackTraceStack,p); /* MR10 */ }; /* M14 */ if (p->guess_analysis_point != NULL) { /* M14 */ TRAV(p->guess_analysis_point, k, rk,t); /* M14 */ } else { TRAV(p->p1, k, rk,t); /* M14 */ } /* MR10 */ if (MR_MaintainBackTrace) { /* MR10 */ if (p->jtype != Generic) MR_pointerStackPop(&MR_BackTraceStack); /* MR10 */ }; if ( p->jtype==EndRule ) p->lock[k]=FALSE; return t; } /* MR10 */ if (MR_MaintainBackTrace) { /* MR10 */ if (p->jtype != Generic) MR_pointerStackPush(&MR_BackTraceStack,p); /* MR10 */ }; /* M14 */ if (p->guess_analysis_point != NULL) { /* M14 */ TRAV(p->guess_analysis_point, k, rk,t); /* M14 */ } else { TRAV(p->p1, k, rk,t); /* M14 */ } /* MR10 */ if (MR_MaintainBackTrace) { /* MR10 */ if (p->jtype != Generic) MR_pointerStackPop(&MR_BackTraceStack); /* MR10 */ }; if ( p->jtype!=RuleBlk && /* MR14 */ !p->guess) TRAV(p->p2, k, rk, u); if ( p->jtype==EndRule ) p->lock[k] = FALSE;/* unlock node */ if ( t==NULL ) return tmake(tnode(ALT), u, NULL); return tmake(tnode(ALT), t, u, NULL); } Tree * #ifdef __USE_PROTOS tRuleRef( RuleRefNode *p, int k, set *rk_out ) #else tRuleRef( p, k, rk_out ) RuleRefNode *p; int k; set *rk_out; #endif { int k2; Tree *t=NULL, *u=NULL; Junction *r; set rk, rk2; int save_halt; RuleEntry *q = (RuleEntry *) hash_get(Rname, p->text); #ifdef DBG_TRAV fprintf(stderr, "tRuleRef: %s\n", p->text); #endif if ( q == NULL ) { TRAV(p->next, k, rk_out, t);/* ignore undefined rules */ return t; } rk = rk2 = empty; if (RulePtr == NULL) fatal("RulePtr==NULL"); r = RulePtr[q->rulenum]; if ( r->lock[k] ) return NULL; save_halt = r->end->halt; r->end->halt = TRUE; /* don't let reach fall off end of rule here */ /* MR10 */ if (MR_MaintainBackTrace) { /* MR10 */ MR_pointerStackPush(&MR_BackTraceStack,p); /* MR10 */ }; TRAV(r, k, &rk, t); /* MR10 */ if (MR_MaintainBackTrace) { /* MR10 */ MR_pointerStackPop(&MR_BackTraceStack); /* MR10 */ }; r->end->halt = save_halt; #ifdef DBG_TREES fprintf(stderr, "after ruleref, t is:"); preorder(t); fprintf(stderr, "\n"); #endif t = tshrink( t ); while ( !set_nil(rk) ) { /* any k left to do? if so, link onto tree */ k2 = set_int(rk); set_rm(k2, rk); /* MR10 */ if (MR_MaintainBackTrace) { /* MR10 */ MR_pointerStackPush(&MR_BackTraceStack,p); /* MR10 */ }; TRAV(p->next, k2, &rk2, u); /* MR10 */ if (MR_MaintainBackTrace) { /* MR10 */ MR_pointerStackPop(&MR_BackTraceStack); /* MR10 */ }; t = tlink(t, u, k2); /* any alts missing k2 toks, add u onto end */ Tfree(u); /* MR10 */ } set_free(rk); /* rk is empty, but free it's memory */ set_orin(rk_out, rk2); /* remember what we couldn't do */ set_free(rk2); return t; } Tree * #ifdef __USE_PROTOS tToken( TokNode *p, int k, set *rk ) #else tToken( p, k, rk ) TokNode *p; int k; set *rk; #endif { Tree *t=NULL, *tset=NULL, *u; if (ConstrainSearch) { if (MR_AmbSourceSearch) { require(constrain>=fset&&constrain<=&(fset[CLL_k]),"tToken: constrain is not a valid set"); } else { require(constrain>=fset&&constrain<=&(fset[LL_k]),"tToken: constrain is not a valid set"); }; constrain = &fset[maxk-k+1]; } #ifdef DBG_TRAV fprintf(stderr, "tToken(%d): %s\n", k, TerminalString(p->token)); if ( ConstrainSearch ) { fprintf(stderr, "constrain is:"); s_fprT(stderr, *constrain); fprintf(stderr, "\n"); } #endif /* is it a meta token (set of tokens)? */ if ( !set_nil(p->tset) ) { unsigned e=0; set a; Tree *n, *tail = NULL; if ( ConstrainSearch ) { a = set_and(p->tset, *constrain); if (set_nil(a)) { /* MR10 */ set_free(a); /* MR11 */ return NULL; /* MR10 */ }; /* MR10 */ } else { a = set_dup(p->tset); }; for (; !set_nil(a); set_rm(e, a)) { e = set_int(a); n = tnode(e); if ( tset==NULL ) { tset = n; tail = n; } else { tail->right = n; tail = n; } } set_free( a ); } else if ( ConstrainSearch && !set_el(p->token, *constrain) ) { /* fprintf(stderr, "ignoring token %s(%d)\n", TerminalString(p->token), k);*/ return NULL; } else { tset = tnode( p->token ); }; /* MR10 */ if (MR_MaintainBackTrace) { /* MR10 */ if (k == 1) { /* MR10 */ MR_pointerStackPush(&MR_BackTraceStack,p); /* MR13 */ if (MR_SuppressSearch) { /* MR13 */ MR_suppressSearchReport(); /* MR13 */ } else { /* MR10 */ MR_backTraceReport(); /* MR13 */ }; /* MR10 */ MR_pointerStackPop(&MR_BackTraceStack); /* MR11 */ Tfree(tset); /* MR11 */ return NULL; /* MR10 */ }; /* MR10 */ }; if ( k == 1 ) return tset; if (MR_MaintainBackTrace) { MR_pointerStackPush(&MR_BackTraceStack,p); }; TRAV(p->next, k-1, rk, t); if (MR_MaintainBackTrace) { Tfree(t); Tfree(tset); MR_pointerStackPop(&MR_BackTraceStack); return NULL; }; /* here, we are positive that, at least, this tree will not contribute * to the LL(2) tree since it will be too shallow, IF t==NULL. * If doing a context guard walk, then don't prune. */ if ( t == NULL && !ContextGuardTRAV ) /* tree will be too shallow */ { if ( tset!=NULL ) Tfree( tset ); return NULL; } #ifdef DBG_TREES fprintf(stderr, "tToken(%d)->next:",k); preorder(t); fprintf(stderr, "\n"); #endif /* if single token root, then just make new tree and return */ /* MR10 - set_nil(p->tset) isn't a good test because of ConstraintSearch */ if (tset->right == NULL) return tmake(tset, t, NULL); /* MR10 */ /* here we must make a copy of t as a child of each element of the tset; * e.g., "T1..T3 A" would yield ( nil ( T1 A ) ( T2 A ) ( T3 A ) ) */ for (u=tset; u!=NULL; u=u->right) { /* make a copy of t and hook it onto bottom of u */ u->down = tdup(t); } Tfree( t ); #ifdef DBG_TREES fprintf(stderr, "range is:"); preorder(tset); fprintf(stderr, "\n"); #endif return tset; } Tree * #ifdef __USE_PROTOS tAction( ActionNode *p, int k, set *rk ) #else tAction( p, k, rk ) ActionNode *p; int k; set *rk; #endif { Tree *t=NULL; set *save_fset=NULL; int i; /* fprintf(stderr, "tAction\n"); */ /* An MR_SuppressSearch is looking for things that can be reached even when the predicate is false. There are three kinds of predicates: plain: r1: <

>? r2 guarded: r1: (A)? => <

>? r2 ampersand style: r1: (A)? && <

>? r2 Of the three kinds of predicates, only a guard predicate has things which are reachable even when the predicate is false. To be reachable the constraint must *not* match the guard. */ if (p->is_predicate && MR_SuppressSearch) { Predicate *pred=p->guardpred; if (pred == NULL) { t=NULL; goto EXIT; }; constrain = &fset[maxk-k+1]; if (pred->k == 1) { set dif; dif=set_dif(*constrain,pred->scontext[1]); if (set_nil(dif)) { set_free(dif); t=NULL; goto EXIT; }; set_free(dif); } else { if (MR_tree_matches_constraints(k,constrain,pred->tcontext)) { t=NULL; goto EXIT; }; } }; /* The ampersand predicate differs from the other predicates because its first set is a subset of the first set behind the predicate r1: (A)? && <

>? r2 ; r2: A | B; In this case first[1] of r1 is A, even though first[1] of r2 is {A B}. */ if (p->is_predicate && p->ampersandPred != NULL) { Predicate *pred=p->ampersandPred; Tree *tAND; Tree *tset; if (k <= pred->k) { if (MR_MaintainBackTrace) MR_pointerStackPush(&MR_BackTraceStack,p); TRAV(p->guardNodes,k,rk,t); if (MR_MaintainBackTrace) MR_pointerStackPop(&MR_BackTraceStack); return t; } else { require (k>1,"tAction for ampersandpred: k <= 1"); if (ConstrainSearch) { if (MR_AmbSourceSearch) { require(constrain>=fset&&constrain<=&(fset[CLL_k]), "tToken: constrain is not a valid set"); } else { require(constrain>=fset&&constrain<=&(fset[LL_k]), "tToken: constrain is not a valid set"); }; save_fset=(set *) calloc (CLL_k+1,sizeof(set)); require (save_fset != NULL,"tAction save_fset alloc"); for (i=1; i <= CLL_k ; i++) { save_fset[i]=set_dup(fset[i]); }; if (pred->k == 1) { constrain = &fset[maxk-k+1]; set_andin(constrain,pred->scontext[1]); if (set_nil(*constrain)) { t=NULL; goto EXIT; }; } else { constrain = &fset[maxk-k+1]; if (! MR_tree_matches_constraints(pred->k,constrain,pred->tcontext)) { t=NULL; goto EXIT; }; /* end loop on i */ }; /* end loop on pred scontext/tcontext */ }; /* end if on k > pred->k */ }; /* end if on constrain search */ TRAV(p->next,k,rk,t); if (t != NULL) { t=tshrink(t); t=tflatten(t); t=tleft_factor(t); if (pred->tcontext != NULL) { tAND=MR_computeTreeAND(t,pred->tcontext); } else { tset=MR_make_tree_from_set(pred->scontext[1]); tAND=MR_computeTreeAND(t,tset); Tfree(tset); }; Tfree(t); t=tAND; }; goto EXIT; }; /* end if on ampersand predicate */ TRAV(p->next,k,rk,t); EXIT: if (save_fset != NULL) { for (i=1 ; i <= CLL_k ; i++) { set_free(fset[i]); fset[i]=save_fset[i]; }; free ( (char *) save_fset); }; return t; } /* see if e exists in s as a possible input permutation (e is always a chain) */ int #ifdef __USE_PROTOS tmember( Tree *e, Tree *s ) #else tmember( e, s ) Tree *e; Tree *s; #endif { if ( e==NULL||s==NULL ) return 0; /** fprintf(stderr, "tmember("); *** preorder(e); fprintf(stderr, ","); *** preorder(s); fprintf(stderr, " )\n"); */ if ( s->token == ALT && s->right == NULL ) return tmember(e, s->down); if ( e->token!=s->token ) { if ( s->right==NULL ) return 0; return tmember(e, s->right); } if ( e->down==NULL && s->down == NULL ) return 1; if ( tmember(e->down, s->down) ) return 1; if ( s->right==NULL ) return 0; return tmember(e, s->right); } /* see if e exists in s as a possible input permutation (e is always a chain); * Only check s to the depth of e. In other words, 'e' can be a shorter * sequence than s. */ int #ifdef __USE_PROTOS tmember_constrained( Tree *e, Tree *s) #else tmember_constrained( e, s ) Tree *e; Tree *s; #endif { if ( e==NULL||s==NULL ) return 0; /** fprintf(stderr, "tmember_constrained("); *** preorder(e); fprintf(stderr, ","); *** preorder(s); fprintf(stderr, " )\n"); **/ if ( s->token == ALT && s->right == NULL ) return tmember_constrained(e, s->down); if ( e->token!=s->token ) { if ( s->right==NULL ) return 0; return tmember_constrained(e, s->right); } if ( e->down == NULL ) return 1; /* if s is matched to depth of e return */ if ( tmember_constrained(e->down, s->down) ) return 1; if ( s->right==NULL ) return 0; return tmember_constrained(e, s->right); } /* combine (? (A t) ... (A u) ...) into (? (A t u)) */ Tree * #ifdef __USE_PROTOS tleft_factor( Tree *t ) #else tleft_factor( t ) Tree *t; #endif { Tree *u, *v, *trail, *w; /* left-factor what is at this level */ if ( t == NULL ) return NULL; for (u=t; u!=NULL; u=u->right) { trail = u; v=u->right; while ( v!=NULL ) { if ( u->token == v->token ) { if ( u->down!=NULL ) { for (w=u->down; w->right!=NULL; w=w->right) {;} w->right = v->down; /* link children together */ } else u->down = v->down; trail->right = v->right; /* unlink factored node */ _Tfree( v ); v = trail->right; } else {trail = v; v=v->right;} } } /* left-factor what is below */ for (u=t; u!=NULL; u=u->right) u->down = tleft_factor( u->down ); return t; } /* remove the permutation p from t if present */ Tree * #ifdef __USE_PROTOS trm_perm( Tree *t, Tree *p ) #else trm_perm( t, p ) Tree *t; Tree *p; #endif { /* fprintf(stderr, "trm_perm("); preorder(t); fprintf(stderr, ","); preorder(p); fprintf(stderr, " )\n"); */ if ( t == NULL || p == NULL ) return NULL; if ( t->token == ALT ) { t->down = trm_perm(t->down, p); if ( t->down == NULL ) /* nothing left below, rm cur node */ { Tree *u = t->right; _Tfree( t ); return trm_perm(u, p); } t->right = trm_perm(t->right, p); /* look for more instances of p */ return t; } if ( p->token != t->token ) /* not found, try a sibling */ { t->right = trm_perm(t->right, p); return t; } t->down = trm_perm(t->down, p->down); if ( t->down == NULL ) /* nothing left below, rm cur node */ { Tree *u = t->right; _Tfree( t ); return trm_perm(u, p); } t->right = trm_perm(t->right, p); /* look for more instances of p */ return t; } /* add the permutation 'perm' to the LL_k sets in 'fset' */ void #ifdef __USE_PROTOS tcvt( set *fset, Tree *perm ) #else tcvt( fset, perm ) set *fset; Tree *perm; #endif { if ( perm==NULL ) return; set_orel(perm->token, fset); tcvt(fset+1, perm->down); } /* for each element of ftbl[k], make it the root of a tree with permute(ftbl[k+1]) * as a child. */ Tree * #ifdef __USE_PROTOS permute( int k, int max_k ) #else permute( k, max_k ) int k, max_k; #endif { Tree *t, *u; if ( k>max_k ) return NULL; if ( ftbl[k][findex[k]] == nil ) return NULL; t = permute(k+1, max_k); if ( t==NULL&&k maxk will have to change. */ Tree * #ifdef __USE_PROTOS VerifyAmbig( Junction *alt1, Junction *alt2, unsigned **ft, set *fs, Tree **t, Tree **u, int *numAmbig ) #else VerifyAmbig( alt1, alt2, ft, fs, t, u, numAmbig ) Junction *alt1; Junction *alt2; unsigned **ft; set *fs; Tree **t; Tree **u; int *numAmbig; #endif { set rk; Tree *perm, *ambig=NULL; Junction *p; int k; int tnodes_at_start=TnodesAllocated; int tnodes_at_end; int tnodes_used; set *save_fs; int j; save_fs=(set *) calloc(CLL_k+1,sizeof(set)); require(save_fs != NULL,"save_fs calloc"); for (j=0; j <= CLL_k ; j++) save_fs[j]=set_dup(fs[j]); maxk = LL_k; /* NOTE: for now, we look for LL_k */ ftbl = ft; fset = fs; constrain = &(fset[1]); findex = (int *) calloc(LL_k+1, sizeof(int)); if ( findex == NULL ) { fprintf(stderr, ErrHdr, FileStr[CurAmbigfile], CurAmbigline); fprintf(stderr, " out of memory while analyzing alts %d and %d of %s\n", CurAmbigAlt1, CurAmbigAlt2, CurAmbigbtype); exit(PCCTS_EXIT_FAILURE); } for (k=1; k<=LL_k; k++) findex[k] = 0; rk = empty; ConstrainSearch = 1; /* consider only tokens in ambig sets */ p = analysis_point((Junction *)alt1->p1); TRAV(p, LL_k, &rk, *t); *t = tshrink( *t ); *t = tflatten( *t ); *t = tleft_factor( *t ); /* MR10 */ *t = prune(*t, LL_k); *t = tleft_factor( *t ); /*** fprintf(stderr, "after shrink&flatten&prune&left_factor:"); preorder(*t); fprintf(stderr, "\n");*/ if ( *t == NULL ) { /*** fprintf(stderr, "TreeIncomplete --> no LL(%d) ambiguity\n", LL_k);*/ Tfree( *t ); /* kill if impossible to have ambig */ *t = NULL; } p = analysis_point((Junction *)alt2->p1); TRAV(p, LL_k, &rk, *u); *u = tshrink( *u ); *u = tflatten( *u ); *t = tleft_factor( *t ); /* MR10 */ *u = prune(*u, LL_k); *u = tleft_factor( *u ); /* fprintf(stderr, "after shrink&flatten&prune&lfactor:"); preorder(*u); fprintf(stderr, "\n");*/ if ( *u == NULL ) { /* fprintf(stderr, "TreeIncomplete --> no LL(%d) ambiguity\n", LL_k);*/ Tfree( *u ); *u = NULL; } for (k=1; k<=LL_k; k++) set_clr( fs[k] ); ambig = tnode(ALT); k = 0; if ( *t!=NULL && *u!=NULL ) { while ( (perm=permute(1,LL_k))!=NULL ) { /* fprintf(stderr, "chk perm:"); preorder(perm); fprintf(stderr, "\n");*/ if ( tmember(perm, *t) && tmember(perm, *u) ) { /* fprintf(stderr, "ambig upon"); preorder(perm); fprintf(stderr, "\n");*/ k++; perm->right = ambig->down; ambig->down = perm; tcvt(&(fs[1]), perm); } else Tfree( perm ); } } for (j=0; j <= CLL_k ; j++) fs[j]=save_fs[j]; free( (char *) save_fs); tnodes_at_end=TnodesAllocated; tnodes_used=tnodes_at_end - tnodes_at_start; if (TnodesReportThreshold > 0 && tnodes_used > TnodesReportThreshold) { fprintf(stdout,"There were %d tuples whose ambiguity could not be resolved by full lookahead\n",k); fprintf(stdout,"There were %d tnodes created to resolve ambiguity between:\n\n",tnodes_used); fprintf(stdout," Choice 1: %s line %d file %s\n", MR_ruleNamePlusOffset( (Node *) alt1),alt1->line,FileStr[alt1->file]); fprintf(stdout," Choice 2: %s line %d file %s\n", MR_ruleNamePlusOffset( (Node *) alt2),alt2->line,FileStr[alt2->file]); for (j=1; j <= CLL_k ; j++) { fprintf(stdout,"\n Intersection of lookahead[%d] sets:\n",j); MR_dumpTokenSet(stdout,2,fs[j]); }; fprintf(stdout,"\n"); }; *numAmbig = k; if ( ambig->down == NULL ) {_Tfree(ambig); ambig = NULL;} free( (char *)findex ); /* fprintf(stderr, "final ambig:"); preorder(ambig); fprintf(stderr, "\n");*/ return ambig; } static Tree * #ifdef __USE_PROTOS bottom_of_chain( Tree *t ) #else bottom_of_chain( t ) Tree *t; #endif { if ( t==NULL ) return NULL; for (; t->down != NULL; t=t->down) {;} return t; } /* * Make a tree from k sets where the degree of the first k-1 sets is 1. */ Tree * #ifdef __USE_PROTOS make_tree_from_sets( set *fset1, set *fset2 ) #else make_tree_from_sets( fset1, fset2 ) set *fset1; set *fset2; #endif { set inter; int i; Tree *t=NULL, *n, *u; unsigned *p,*q; require(LL_k>1, "make_tree_from_sets: LL_k must be > 1"); /* do the degree 1 sets first */ for (i=1; i<=LL_k-1; i++) { inter = set_and(fset1[i], fset2[i]); require(set_deg(inter)==1, "invalid set to tree conversion"); n = tnode(set_int(inter)); if (t==NULL) t=n; else tmake(t, n, NULL); set_free(inter); } /* now add the chain of tokens at depth k */ u = bottom_of_chain(t); inter = set_and(fset1[LL_k], fset2[LL_k]); if ( (q=p=set_pdq(inter)) == NULL ) fatal_internal("Can't alloc space for set_pdq"); /* first one is linked to bottom, then others are sibling linked */ n = tnode(*p++); u->down = n; u = u->down; while ( *p != nil ) { n = tnode(*p); u->right = n; u = u->right; p++; } free((char *)q); return t; } /* create and return the tree of lookahead k-sequences that are in t, but not * in the context of predicates in predicate list p. */ Tree * #ifdef __USE_PROTOS tdif( Tree *ambig_tuples, Predicate *p, set *fset1, set *fset2 ) #else tdif( ambig_tuples, p, fset1, fset2 ) Tree *ambig_tuples; Predicate *p; set *fset1; set *fset2; #endif { unsigned **ft; Tree *dif=NULL; Tree *perm; set b; int i,k; if ( p == NULL ) return tdup(ambig_tuples); ft = (unsigned **) calloc(CLL_k+1, sizeof(unsigned *)); require(ft!=NULL, "cannot allocate ft"); for (i=1; i<=CLL_k; i++) { b = set_and(fset1[i], fset2[i]); ft[i] = set_pdq(b); set_free(b); } findex = (int *) calloc(LL_k+1, sizeof(int)); if ( findex == NULL ) { fatal_internal("out of memory in tdif while checking predicates"); } for (k=1; k<=LL_k; k++) findex[k] = 0; #ifdef DBG_TRAV fprintf(stderr, "tdif_%d[", p->k); preorder(ambig_tuples); fprintf(stderr, ","); preorder(p->tcontext); fprintf(stderr, "] ="); #endif ftbl = ft; while ( (perm=permute(1,p->k))!=NULL ) { #ifdef DBG_TRAV fprintf(stderr, "test perm:"); preorder(perm); fprintf(stderr, "\n"); #endif if ( tmember_constrained(perm, ambig_tuples) && !tmember_of_context(perm, p) ) { #ifdef DBG_TRAV fprintf(stderr, "satisfied upon"); preorder(perm); fprintf(stderr, "\n"); #endif k++; if ( dif==NULL ) dif = perm; else { perm->right = dif; dif = perm; } } else Tfree( perm ); } #ifdef DBG_TRAV preorder(dif); fprintf(stderr, "\n"); #endif for (i=1; i<=CLL_k; i++) free( (char *)ft[i] ); free((char *)ft); free((char *)findex); return dif; } /* is lookahead sequence t a member of any context tree for any * predicate in p? */ static int #ifdef __USE_PROTOS tmember_of_context( Tree *t, Predicate *p ) #else tmember_of_context( t, p ) Tree *t; Predicate *p; #endif { for (; p!=NULL; p=p->right) { if ( p->expr==PRED_AND_LIST || p->expr==PRED_OR_LIST ) return tmember_of_context(t, p->down); if ( tmember_constrained(t, p->tcontext) ) return 1; if ( tmember_of_context(t, p->down) ) return 1; } return 0; } int #ifdef __USE_PROTOS is_single_tuple( Tree *t ) #else is_single_tuple( t ) Tree *t; #endif { if ( t == NULL ) return 0; if ( t->right != NULL ) return 0; if ( t->down == NULL ) return 1; return is_single_tuple(t->down); } /* MR10 Check that a context guard contains only allowed things */ /* MR10 (mainly token references). */ #ifdef __USE_PROTOS int contextGuardOK(Node *p,int h,int *hmax) #else int contextGuardOK(p,h,hmax) Node *p; int h; int *hmax; #endif { Junction *j; TokNode *tn; if (p == NULL) return 1; if (p->ntype == nToken) { h++; if (h > *hmax) *hmax=h; tn=(TokNode *)p; if (tn->el_label != NULL) { warnFL(eMsg1("a label (\"%s\") for a context guard element is meaningless",tn->el_label), FileStr[p->file],p->line); }; return contextGuardOK( ( (TokNode *) p)->next,h,hmax); } else if (p->ntype == nAction) { goto Fail; } else if (p->ntype == nRuleRef) { goto Fail; } else { require (p->ntype == nJunction,"Unexpected ntype"); j=(Junction *) p; if (j->jtype != Generic && j->jtype != aSubBlk && /* pretty sure this one is allowed */ /**** j->jtype != aOptBlk && ****/ /* pretty sure this one is allowed */ /* MR11 not any more ! */ j->jtype != EndBlk) { errFL("A context guard may not contain an option block: {...} or looping block: (...)* or (...)+", FileStr[p->file],p->line); contextGuardOK(j->p1,h,hmax); return 0; }; /* do both p1 and p2 so use | rather than || */ return contextGuardOK(j->p2,h,hmax) | contextGuardOK(j->p1,h,hmax); }; Fail: errFL("A context guard may contain only Token references - guard will be ignored", FileStr[p->file],p->line); contextGuardOK( ( (ActionNode *) p)->next,h,hmax); return 0; } /* * Look at a (...)? generalized-predicate context-guard and compute * either a lookahead set (k==1) or a lookahead tree for k>1. The * k level is determined by the guard itself rather than the LL_k * variable. For example, ( A B )? is an LL(2) guard and ( ID )? * is an LL(1) guard. For the moment, you can only have a single * tuple in the guard. Physically, the block must look like this * --o-->TOKEN-->o-->o-->TOKEN-->o-- ... -->o-->TOKEN-->o-- * An error is printed for any other type. */ Predicate * #ifdef __USE_PROTOS computePredFromContextGuard(Graph blk,int *msgDone) /* MR10 */ #else computePredFromContextGuard(blk,msgDone) /* MR10 */ Graph blk; int *msgDone; /* MR10 */ #endif { Junction *junc = (Junction *)blk.left, *p; Tree *t=NULL; Predicate *pred = NULL; set scontext, rk; int ok; int hmax=0; require(junc!=NULL && junc->ntype == nJunction, "bad context guard"); /* MR10 Check for anything other than Tokens and generic junctions */ *msgDone=0; /* MR10 */ ok=contextGuardOK( (Node *)junc,0,&hmax); /* MR10 */ if (! ok) { /* MR10 */ *msgDone=1; /* MR10 */ return NULL; /* MR10 */ }; /* MR10 */ if (hmax == 0) { errFL("guard is 0 tokens long",FileStr[junc->file],junc->line); /* MR11 */ *msgDone=1; return NULL; }; if (hmax > CLL_k) { /* MR10 */ errFL(eMsgd2("guard is %d tokens long - lookahead is limited to max(k,ck)==%d", /* MR10 */ hmax,CLL_k), /* MR10 */ FileStr[junc->file],junc->line); /* MR10 */ *msgDone=1; /* MR10 */ return NULL; /* MR10 */ }; /* MR10 */ rk = empty; p = junc; pred = new_pred(); pred->k = hmax; /* MR10 should be CLL_k, not LLK ? */ if (hmax > 1 ) /* MR10 was LL_k */ { ConstrainSearch = 0; ContextGuardTRAV = 1; TRAV(p, hmax, &rk, t); /* MR10 was LL_k */ ContextGuardTRAV = 0; set_free(rk); t = tshrink( t ); t = tflatten( t ); t = tleft_factor( t ); /* fprintf(stderr, "ctx guard:"); preorder(t); fprintf(stderr, "\n"); */ pred->tcontext = t; } else { REACH(p, 1, &rk, scontext); require(set_nil(rk), "rk != nil"); set_free(rk); /* fprintf(stderr, "LL(1) ctx guard is:"); s_fprT(stderr, scontext); fprintf(stderr, "\n"); */ pred->scontext[1] = scontext; } list_add(&ContextGuardPredicateList,pred); /* MR13 */ return pred; } /* MR13 When the context guard is originally computed the meta-tokens are not known. */ #ifdef __USE_PROTOS void recomputeContextGuard(Predicate *pred) #else void recomputeContextGuard(pred) Predicate *pred; #endif { Tree * t=NULL; set scontext; set rk; ActionNode * actionNode; Junction * p; actionNode=pred->source; require (actionNode != NULL,"context predicate's source == NULL"); p=actionNode->guardNodes; require (p != NULL,"context predicate's guardNodes == NULL"); rk = empty; if (pred->k > 1 ) { ConstrainSearch = 0; ContextGuardTRAV = 1; TRAV(p, pred->k, &rk, t); ContextGuardTRAV = 0; set_free(rk); t = tshrink( t ); t = tflatten( t ); t = tleft_factor( t ); Tfree(pred->tcontext); pred->tcontext = t; } else { REACH(p, 1, &rk, scontext); require(set_nil(rk), "rk != nil"); set_free(rk); set_free(pred->scontext[1]); pred->scontext[1] = scontext; } } /* MR11 - had enough of flags yet ? */ int MR_AmbSourceSearch=0; int MR_AmbSourceSearchGroup=0; int MR_AmbSourceSearchChoice=0; int MR_AmbSourceSearchLimit=0; int MR_matched_AmbAidRule=0; static set *matchSets[2]={NULL,NULL}; static int *tokensInChain=NULL; static Junction *MR_AmbSourceSearchJ[2]; void MR_traceAmbSourceKclient() { int i; set *save_fset; int save_ConstrainSearch; set incomplete; Tree *t; if (matchSets[0] == NULL) { matchSets[0]=(set *) calloc (CLL_k+1,sizeof(set)); require (matchSets[0] != NULL,"matchSets[0] alloc"); matchSets[1]=(set *) calloc (CLL_k+1,sizeof(set)); require (matchSets[1] != NULL,"matchSets[1] alloc"); }; for (i=1 ; i <= MR_AmbSourceSearchLimit ; i++) { set_clr(matchSets[0][i]); set_orel( (unsigned) tokensInChain[i], &matchSets[0][i]); set_clr(matchSets[1][i]); set_orel( (unsigned) tokensInChain[i], &matchSets[1][i]); }; save_fset=fset; save_ConstrainSearch=ConstrainSearch; for (i=0 ; i < 2 ; i++) { #if 0 ** fprintf(stdout," Choice:%d Depth:%d ",i+1,MR_AmbSourceSearchLimit); ** fprintf(stdout,"("); ** for (j=1 ; j <= MR_AmbSourceSearchLimit ; j++) { ** if (j != 1) fprintf(stdout," "); ** fprintf(stdout,"%s",TerminalString(tokensInChain[j])); ** }; ** fprintf(stdout,")\n\n"); #endif fset=matchSets[i]; MR_AmbSourceSearch=1; MR_MaintainBackTrace=1; MR_AmbSourceSearchChoice=i; ConstrainSearch=1; maxk = MR_AmbSourceSearchLimit; incomplete=empty; t=NULL; constrain = &(fset[1]); MR_pointerStackReset(&MR_BackTraceStack); TRAV(MR_AmbSourceSearchJ[i],maxk,&incomplete,t); Tfree(t); require (set_nil(incomplete),"MR_traceAmbSourceK TRAV incomplete"); require (MR_BackTraceStack.count == 0,"K: MR_BackTraceStack.count != 0"); set_free(incomplete); }; ConstrainSearch=save_ConstrainSearch; fset=save_fset; MR_AmbSourceSearch=0; MR_MaintainBackTrace=0; MR_AmbSourceSearchChoice=0; } #ifdef __USE_PROTOS Tree *tTrunc(Tree *t,int depth) #else Tree *tTrunc(t,depth) Tree *t; #endif { Tree *u; require ( ! (t == NULL && depth > 0),"tree too short"); if (depth == 0) return NULL; if (t->token == ALT) { u=tTrunc(t->down,depth); } else { u=tnode(t->token); u->down=tTrunc(t->down,depth-1); }; if (t->right != NULL) u->right=tTrunc(t->right,depth); return u; } #ifdef __USE_PROTOS void MR_iterateOverTree(Tree *t,int chain[]) #else void MR_iterateOverTree(t,chain) Tree *t; int chain[]; #endif { if (t == NULL) return; chain[0]=t->token; if (t->down != NULL) { MR_iterateOverTree(t->down,&chain[1]); } else { MR_traceAmbSourceKclient(); }; MR_iterateOverTree(t->right,&chain[0]); chain[0]=0; } #ifdef __USE_PROTOS void MR_traceAmbSourceK(Tree *t,Junction *alt1,Junction *alt2) #else void MR_traceAmbSourceK(t,alt1,alt2) Tree *t; Junction *alt1; Junction *alt2; #endif { int i; int depth; int maxDepth; Tree *truncatedTree; if (MR_AmbAidRule == NULL) return; if ( ! ( strcmp(MR_AmbAidRule,alt1->rname) == 0 || strcmp(MR_AmbAidRule,alt2->rname) == 0 || MR_AmbAidLine==alt1->line || MR_AmbAidLine==alt2->line ) ) return; MR_matched_AmbAidRule++; /* there are no token sets in trees, only in TokNodes */ MR_AmbSourceSearchJ[0]=analysis_point( (Junction *) alt1->p1); MR_AmbSourceSearchJ[1]=analysis_point( (Junction *) alt2->p1); if (tokensInChain == NULL) { tokensInChain=(int *) calloc (CLL_k+1,sizeof(int)); require (tokensInChain != NULL,"tokensInChain alloc"); }; MR_AmbSourceSearchGroup=0; fprintf(stdout,"\n"); fprintf(stdout," Ambiguity Aid "); fprintf(stdout, (MR_AmbAidDepth <= LL_k ? "(-k %d -aa %s %s -aad %d)\n\n" : "(-k %d -aa %s %s [-k value limits -aad %d])\n\n"), LL_k, MR_AmbAidRule, (MR_AmbAidMultiple ? "-aam" : ""), MR_AmbAidDepth); for (i=0 ; i < 2 ; i++) { fprintf(stdout," Choice %d: %-25s line %d file %s\n", (i+1), MR_ruleNamePlusOffset( (Node *) MR_AmbSourceSearchJ[i]), MR_AmbSourceSearchJ[i]->line, FileStr[MR_AmbSourceSearchJ[i]->file]); }; fprintf(stdout,"\n"); if (MR_AmbAidDepth < LL_k) { maxDepth=MR_AmbAidDepth; } else { maxDepth=LL_k; }; for (depth=1 ; depth <= maxDepth; depth++) { MR_AmbSourceSearchLimit=depth; if (depth < LL_k) { truncatedTree=tTrunc(t,depth); truncatedTree=tleft_factor(truncatedTree); MR_iterateOverTree(truncatedTree,&tokensInChain[1]); /* <===== */ Tfree(truncatedTree); } else { MR_iterateOverTree(t,tokensInChain); /* <===== */ }; fflush(stdout); fflush(stderr); }; fprintf(stdout,"\n"); MR_AmbSourceSearch=0; MR_MaintainBackTrace=0; MR_AmbSourceSearchGroup=0; MR_AmbSourceSearchChoice=0; MR_AmbSourceSearchLimit=0; } /* this if for k=1 grammars only this is approximate only because of the limitations of linear approximation lookahead. Don't want to do a k=3 search when the user only specified a ck=3 grammar */ #ifdef __USE_PROTOS void MR_traceAmbSource(set *matchSets,Junction *alt1, Junction *alt2) #else void MR_traceAmbSource(matchSets,alt1,alt2) set *matchSets; Junction *alt1; Junction *alt2; #endif { set *save_fset; Junction *p[2]; int i; int j; set *dup_matchSets; set intersection; set incomplete; set tokensUsed; int depth; if (MR_AmbAidRule == NULL) return; if ( ! ( strcmp(MR_AmbAidRule,alt1->rname) == 0 || strcmp(MR_AmbAidRule,alt2->rname) == 0 || MR_AmbAidLine==alt1->line || MR_AmbAidLine==alt2->line ) ) return; MR_matched_AmbAidRule++; save_fset=fset; dup_matchSets=(set *) calloc(CLL_k+1,sizeof(set)); require (dup_matchSets != NULL,"Can't allocate dup_matchSets"); p[0]=analysis_point( (Junction *) alt1->p1); p[1]=analysis_point( (Junction *) alt2->p1); fprintf(stdout,"\n"); fprintf(stdout," Ambiguity Aid "); fprintf(stdout, (MR_AmbAidDepth <= CLL_k ? "(-ck %d -aa %s %s -aad %d)\n\n" : "(-ck %d -aa %s %s [-ck value limits -aad %d])\n\n"), CLL_k, MR_AmbAidRule, (MR_AmbAidMultiple ? "-aam" : ""), MR_AmbAidDepth); for (i=0 ; i < 2 ; i++) { fprintf(stdout," Choice %d: %-25s line %d file %s\n", (i+1), MR_ruleNamePlusOffset( (Node *) p[i]), p[i]->line,FileStr[p[i]->file]); }; for (j=1; j <= CLL_k ; j++) { fprintf(stdout,"\n Intersection of lookahead[%d] sets:\n",j); intersection=set_and(alt1->fset[j],alt2->fset[j]); MR_dumpTokenSet(stdout,2,intersection); set_free(intersection); }; fprintf(stdout,"\n"); require (1 <= MR_AmbAidDepth && MR_AmbAidDepth <= CLL_k, "illegal MR_AmbAidDepth"); MR_AmbSourceSearchGroup=0; for (depth=1; depth <= MR_AmbAidDepth; depth++) { MR_AmbSourceSearchLimit=depth; for (i=0 ; i < 2 ; i++) { /*** fprintf(stdout," Choice:%d Depth:%d\n\n",i+1,depth); ***/ for (j=0 ; j <= CLL_k ; j++) { dup_matchSets[j]=set_dup(matchSets[j]); }; fset=dup_matchSets; fflush(output); fflush(stdout); MR_AmbSourceSearch=1; MR_MaintainBackTrace=1; MR_AmbSourceSearchChoice=i; maxk = depth; tokensUsed=empty; incomplete=empty; constrain = &(fset[1]); MR_pointerStackReset(&MR_BackTraceStack); REACH(p[i],depth,&incomplete,tokensUsed); fflush(output); fflush(stdout); require (set_nil(incomplete),"MR_traceAmbSource REACH incomplete"); require (MR_BackTraceStack.count == 0,"1: MR_BackTraceStack.count != 0"); set_free(incomplete); set_free(tokensUsed); for (j=0 ; j <= CLL_k ; j++) { set_free(dup_matchSets[j]); }; }; }; fprintf(stdout,"\n"); MR_AmbSourceSearch=0; MR_MaintainBackTrace=0; MR_AmbSourceSearchGroup=0; MR_AmbSourceSearchChoice=0; MR_AmbSourceSearchLimit=0; fset=save_fset; free ( (char *) dup_matchSets); } static int itemCount; void MR_backTraceDumpItemReset() { itemCount=0; } #ifdef __USE_PROTOS void MR_backTraceDumpItem(FILE *f,int skip,Node *n) #else void MR_backTraceDumpItem(f,skip,n) FILE *f; int skip; Node *n; #endif { TokNode *tn; RuleRefNode *rrn; Junction *j; ActionNode *a; switch (n->ntype) { case nToken: itemCount++; if (skip) goto EXIT; tn=(TokNode *)n; if (set_nil(tn->tset)) { fprintf(f," %2d #token %-23s",itemCount,TerminalString(tn->token)); } else { fprintf(f," %2d #tokclass %-20s",itemCount,TerminalString(tn->token)); }; break; case nRuleRef: itemCount++; if (skip) goto EXIT; rrn=(RuleRefNode *)n; fprintf(f," %2d to %-27s",itemCount,rrn->text); break; case nAction: a=(ActionNode *)n; goto EXIT; case nJunction: j=(Junction *)n; switch (j->jtype) { case aSubBlk: if (j->guess) { itemCount++; if (skip) goto EXIT; fprintf(f," %2d %-30s",itemCount,"in (...)? block at"); break; }; /****** fprintf(f," %2d %-32s",itemCount,"in (...) block at"); *******/ /****** break; *******/ goto EXIT; case aOptBlk: itemCount++; if (skip) goto EXIT; fprintf(f," %2d %-30s",itemCount,"in {...} block"); break; case aLoopBlk: itemCount++; if (skip) goto EXIT; fprintf(f," %2d %-30s",itemCount,"in (...)* block"); break; case EndBlk: if (j->alpha_beta_guess_end) { itemCount++; if (skip) goto EXIT; fprintf(f," %2d %-30s",itemCount,"end (...)? block at"); break; }; goto EXIT; /****** fprintf(f," %2d %-32s",itemCount,"end of a block at"); *****/ /****** break; *****/ case RuleBlk: itemCount++; if (skip) goto EXIT; fprintf(f," %2d %-30s",itemCount,j->rname); break; case Generic: goto EXIT; case EndRule: itemCount++; if (skip) goto EXIT; fprintf (f," %2d end %-26s",itemCount,j->rname); break; case aPlusBlk: itemCount++; if (skip) goto EXIT; fprintf(f," %2d %-30s",itemCount,"in (...)+ block"); break; case aLoopBegin: goto EXIT; }; break; }; fprintf(f," %-23s line %-4d %s\n",MR_ruleNamePlusOffset(n),n->line,FileStr[n->file]); EXIT: return; } static PointerStack previousBackTrace={0,0,NULL}; #ifdef __USE_PROTOS void MR_backTraceReport(void) #else void MR_backTraceReport() #endif { int i; int match = 0; int limitMatch; Node *p; TokNode *tn; set remainder; int depth; /* Even when doing a k=2 search this routine can get called when there is only 1 token on the stack. This is because something like rRuleRef can change the search value of k from 2 to 1 temporarily. It does this because the it wants to know the k=1 first set before it does a k=2 search */ depth=0; for (i=0; i < MR_BackTraceStack.count ; i++) { p=(Node *) MR_BackTraceStack.data[i]; if (p->ntype == nToken) depth++; }; /* MR14 */ if (MR_AmbSourceSearch) { /* MR14 */ require (depth <= MR_AmbSourceSearchLimit,"depth > MR_AmbSourceSearchLimit"); /* MR14 */ } /* MR23 THM - Traceback report was being called at the wrong time for -alpha reports */ /* Reported by Arpad Beszedes (beszedes@inf.u-szeged.hu) */ if (MR_AmbSourceSearchLimit == 0 || depth < MR_AmbSourceSearchLimit) { return; }; MR_backTraceDumpItemReset(); limitMatch=MR_BackTraceStack.count; if (limitMatch > previousBackTrace.count) { limitMatch=previousBackTrace.count; }; for (match=0; match < limitMatch; match++) { if (MR_BackTraceStack.data[match] != previousBackTrace.data[match]) { break; }; }; /* not sure at the moment why there would be duplicates */ if (match != MR_BackTraceStack.count) { fprintf(stdout," Choice:%d Depth:%d Group:%d", (MR_AmbSourceSearchChoice+1), MR_AmbSourceSearchLimit, ++MR_AmbSourceSearchGroup); depth=0; fprintf(stdout," ("); for (i=0; i < MR_BackTraceStack.count ; i++) { p=(Node *) MR_BackTraceStack.data[i]; if (p->ntype != nToken) continue; tn=(TokNode *)p; if (depth != 0) fprintf(stdout," "); fprintf(stdout,"%s",TerminalString(tn->token)); depth++; if (! MR_AmbAidMultiple) { if (set_nil(tn->tset)) { set_rm( (unsigned) tn->token,fset[depth]); } else { remainder=set_dif(fset[depth],tn->tset); set_free(fset[depth]); fset[depth]=remainder; }; }; }; fprintf(stdout,")\n"); for (i=0; i < MR_BackTraceStack.count ; i++) { MR_backTraceDumpItem(stdout, (i #include #include #include "pcctscfg.h" #include "set.h" #include "syn.h" #include "hash.h" #include "generic.h" #include "dlgdef.h" #define NumExprPerLine 4 static int on1line=0; static set tokensRefdInBlock; /* T r a n s l a t i o n T a b l e s */ /* C_Trans[node type] == pointer to function that knows how to translate that node. */ #ifdef __cplusplus void (*C_Trans[NumNodeTypes+1])(...) = { NULL, NULL, /* See next table. Junctions have many types */ (void (*)(...)) genRuleRef, (void (*)(...)) genToken, (void (*)(...)) genAction }; #else void (*C_Trans[NumNodeTypes+1])() = { NULL, NULL, /* See next table. Junctions have many types */ genRuleRef, genToken, genAction }; #endif /* C_JTrans[Junction type] == pointer to function that knows how to translate that * kind of junction node. */ #ifdef __cplusplus void (*C_JTrans[NumJuncTypes+1])(...) = { NULL, (void (*)(...)) genSubBlk, (void (*)(...)) genOptBlk, (void (*)(...)) genLoopBlk, (void (*)(...)) genEndBlk, (void (*)(...)) genRule, (void (*)(...)) genJunction, (void (*)(...)) genEndRule, (void (*)(...)) genPlusBlk, (void (*)(...)) genLoopBegin }; #else void (*C_JTrans[NumJuncTypes+1])() = { NULL, genSubBlk, genOptBlk, genLoopBlk, genEndBlk, genRule, genJunction, genEndRule, genPlusBlk, genLoopBegin }; #endif #define PastWhiteSpace(s) while (*(s) == ' ' || *(s) == '\t') {s++;} static int tabs = 0; /* MR6 Got tired of text running off page when using standard tab stops */ #define TAB { int i; \ if (TabWidth==0) { \ for (i=0; irname);} else gen1("zzTRACEOUT((ANTLRChar *)\"%s\");\n", q->rname); } } static void #ifdef __USE_PROTOS warn_about_using_gk_option(void) #else warn_about_using_gk_option() #endif { static int warned_already=0; if ( !DemandLookahead || warned_already ) return; warned_already = 1; warnNoFL("-gk option could cause trouble for <<...>>? predicates"); } void #ifdef __USE_PROTOS freeBlkFsets( Junction *q ) #else freeBlkFsets( q ) Junction *q; #endif { int i; Junction *alt; require(q!=NULL, "freeBlkFsets: invalid node"); for (alt=q; alt != NULL; alt= (Junction *) alt->p2 ) { for (i=1; i<=CLL_k; i++) set_free(alt->fset[i]); } } /* * Generate a local variable allocation for each token references * in this block. */ static void #ifdef __USE_PROTOS genTokenPointers( Junction *q ) #else genTokenPointers( q ) Junction *q; #endif { /* Rule refs are counted and can be referenced, but their * value is not set to anything useful ever. * * The ptrs are to be named _tij where i is the current level * and j is the element number within an alternative. */ int first=1, t=0; set a; tokensRefdInBlock = q->tokrefs; if ( set_deg(q->tokrefs) == 0 ) return; a = set_dup(q->tokrefs); gen("ANTLRTokenPtr "); for (; !set_nil(a); set_rm(t, a)) { t = set_int(a); if ( first ) first = 0; else _gen(","); if ( !DontCopyTokens ) _gen2("_tv%d%d,", BlkLevel, t); _gen2("_t%d%d", BlkLevel, t); if ( !DontCopyTokens ) {_gen2("= &_tv%d%d", BlkLevel, t);} else _gen("=NULL"); } _gen(";\n"); set_free(a); } static int #ifdef __USE_PROTOS hasDefaultException(ExceptionGroup *eg) #else hasDefaultException(eg) ExceptionGroup *eg; #endif { ListNode *q; for (q = eg->handlers->next; q!=NULL; q=q->next) { ExceptionHandler *eh = (ExceptionHandler *)q->elem; if ( strcmp("default", eh->signalname)==0 ) { return 1; } } return 0; } static void #ifdef __USE_PROTOS dumpException(ExceptionGroup *eg, int no_default_case) #else dumpException(eg, no_default_case) ExceptionGroup *eg; int no_default_case; #endif { char *outerLabel; /* MR7 */ int altHandler=0; /* MR7 */ int namedHandler=0; /* MR7 */ outerLabel=findOuterHandlerLabel(eg); /* MR7 */ if (eg->label != NULL) { /* MR7 */ namedHandler=1; /* MR7 */ } else if (eg->forRule) { /* MR7 */ /* nothing */ /* MR20 */ } else { /* MR7 */ altHandler=1; /* MR7 */ }; /* MR7 */ #if 0 ** if (! eg->used) { /* MR7 */ ** warnFL("exception group never used", /* MR7 */ ** FileStr[eg->altstart->file],eg->altstart->line); /* MR7 */ ** }; /* MR7 */ #endif if (namedHandler) { /* MR7 */ gen1("switch ( _signal ) { /* [%s] */\n",eg->label); /* MR7 */ } else { /* MR7 */ gen("switch ( _signal ) {\n"); /* MR7 */ gen("case NoSignal: break; /* MR7 */\n"); /* MR7 */ }; /* MR7 */ { ListNode *q; for (q = eg->handlers->next; q!=NULL; q=q->next) { ExceptionHandler *eh = (ExceptionHandler *)q->elem; if ( strcmp("default", eh->signalname)==0 ) { gen("default :\n"); tabs++; dumpAction(eh->action, output, tabs, -1, 1, 1); gen("_signal=NoSignal; /* MR7 */\n"); /* MR7 */ gen("break; /* MR7 */\n"); /* MR7 */ tabs--; gen("}\n"); /* copied from later code in dumpException */ /* MR7 */ if (namedHandler) { /* MR7 */ gen("if (_signal != NoSignal)"); /* MR7 */ _gen1(" goto %s_handler; /* MR7 */\n",outerLabel);/* MR7 */ } else if (altHandler) { /* MR7 */ gen1("goto %s_handler; /* MR7 */\n",outerLabel); /* MR7 */ }; return; } gen1("case %s :\n", eh->signalname); tabs++; if ( eh->action != NULL ) { dumpAction(eh->action, output, tabs, -1, 1, 1); gen("break; /* MR7 */\n"); /* MR7 */ } tabs--; } } if ( no_default_case ) return; gen("default :\n"); tabs++; /* MR7 */ gen("break; /* MR7 */\n"); /* MR7 */ tabs--; /* MR7 */ tabs++; /***** gen("*_retsignal = _signal;\n"); *****/ tabs--; gen("}\n"); if (namedHandler) { /* MR7 */ gen("if (_signal != NoSignal)"); /* MR7 */ _gen1(" goto %s_handler; /* MR7 */\n",outerLabel); /* MR7 */ } else if (altHandler) { /* MR7 */ gen1("goto %s_handler; /* MR7 */\n",outerLabel); /* MR7 */ }; } static void #ifdef __USE_PROTOS dumpExceptions(ListNode *list) #else dumpExceptions(list) ListNode *list; #endif { ListNode *p; for (p = list->next; p!=NULL; p=p->next) { ExceptionGroup *eg = (ExceptionGroup *) p->elem; _gen2("%s%s_handler:\n", eg->label==NULL?"":eg->label, eg->altID==NULL?"":eg->altID); if ( eg->altID!=NULL ) dumpException(eg, 0); else { /* This must be the rule exception handler */ dumpException(eg, 1); if ( !hasDefaultException(eg) ) { gen("default :\n"); tabs++; gen("zzdflthandlers(_signal,_retsignal);\n"); tabs--; gen("}\n"); } } } } /* For each element label that is found in a rule, generate a unique * Attribute (and AST pointer if GenAST) variable. */ void #ifdef __USE_PROTOS genElementLabels(ListNode *list) #else genElementLabels(list) ListNode *list; #endif { int first=1; ListNode *p; if ( GenCC ) {gen("ANTLRTokenPtr");} else {gen("Attrib");} for (p = list->next; p!=NULL; p=p->next) { char *ep = (char *)p->elem; if ( first ) first = 0; else _gen(","); if ( GenCC ) {_gen1(" %s=NULL",ep);} else {_gen1(" %s",ep);} } _gen(";\n"); if ( !GenAST ) return; first = 1; gen("AST"); for (p = list->next; p!=NULL; p=p->next) { char *ep = (char *)p->elem; if ( first ) first = 0; else _gen(","); _gen1(" *%s_ast=NULL",ep); } _gen(";\n"); } /* * Generate a local variable allocation for each token or rule reference * in this block. */ static void #ifdef __USE_PROTOS genASTPointers( Junction *q ) #else genASTPointers( q ) Junction *q; #endif { int first=1, t; set a; a = set_or(q->tokrefs, q->rulerefs); if ( set_deg(a) > 0 ) { gen("AST "); for (; !set_nil(a); set_rm(t, a)) { t = set_int(a); if ( first ) first = 0; else _gen(","); _gen2("*_ast%d%d=NULL", BlkLevel, t); } set_free(a); } _gen(";\n"); } static void #ifdef __USE_PROTOS BLOCK_Head( void ) #else BLOCK_Head( ) #endif { gen("{\n"); tabs++; if ( !GenCC ) gen1("zzBLOCK(zztasp%d);\n", BlkLevel); } static void #ifdef __USE_PROTOS BLOCK_Tail( void ) #else BLOCK_Tail( ) #endif { if ( !GenCC ) gen1("zzEXIT(zztasp%d);\n", BlkLevel); if ( !GenCC ) gen("}\n"); tabs--; gen("}\n"); } static void #ifdef __USE_PROTOS BLOCK_Preamble( Junction *q ) #else BLOCK_Preamble( q ) Junction *q; #endif { ActionNode *a; Junction *begin; BLOCK_Head(); if ( GenCC ) genTokenPointers(q); if ( GenCC&&GenAST ) genASTPointers(q); if ( q->jtype == aPlusBlk ) gen("int zzcnt=1;\n"); if ( q->parm != NULL && !q->predparm ) gen1("zzaPush(%s);\n", q->parm) else if ( !GenCC ) gen("zzMake0;\n"); if ( !GenCC ) gen("{\n"); if ( q->jtype == aLoopBegin ) begin = (Junction *) ((Junction *)q->p1); else begin = q; if ( has_guess_block_as_first_item(begin) ) { gen("zzGUESS_BLOCK\n"); } if ( q->jtype == aLoopBegin ) a = findImmedAction( ((Junction *)q->p1)->p1 ); /* look at aLoopBlk */ else a = findImmedAction( q->p1 ); if ( a!=NULL && !a->is_predicate) { /* MR21 */ if (!a->noHoist) dumpActionPlus(a, a->action, output, tabs, a->file, a->line, 1); a->done = 1; /* remove action. We have already handled it */ } } void #ifdef __USE_PROTOS genCombinedPredTreeContextOrig( Predicate *p ) #else genCombinedPredTreeContextOrig( p ) Predicate *p; #endif { static set *ctx=NULL; /* genExprSets() is destructive, make copy*/ require(p!=NULL, "can't make context tree for NULL pred tree"); #ifdef DBG_PRED fprintf(stderr, "enter genCombinedPredTreeContextOrig(%s,0x%x) with sets:\n", p->expr, p); s_fprT(stderr, p->scontext[1]); fprintf(stderr, "\n"); #endif if ( p->down == NULL ) { /*** if ( p->k>1 && p->tcontext!=NULL ) ***/ if ( p->tcontext!=NULL ) { _gen("("); genExprTree(p->tcontext, 1); _gen(")"); } /*** else if ( p->k==1 && set_deg(p->scontext[1])>0 ) ***/ else if ( set_deg(p->scontext[1])>0 ) { if ( ctx==NULL ) ctx = (set *)calloc(CLL_k+1, sizeof(set)); require(ctx!=NULL, "ctx cannot allocate"); ctx[0]=empty; ctx[1]=set_dup(p->scontext[1]); _gen("("); genExprSets(&(ctx[0]), p->k); _gen(")"); set_free(ctx[1]); } else if ( p->expr==PRED_AND_LIST || p->expr==PRED_OR_LIST ) { fatal_internal("pred tree is orphan OR or AND list"); } else { if (! HoistPredicateContext) { _gen(" 1 /* no context: prc is off */ "); } else { fatal_internal("pred tree context is empty"); }; } return; } /* MR10 - make AND just like OR */ if ( p->expr == PRED_AND_LIST ) { Predicate *list = p->down; for (; list!=NULL; list=list->right) { genCombinedPredTreeContextOrig(list); if ( list->right!=NULL ) _gen("|| /* MR10 was wrong */ "); }; return; } if ( p->expr == PRED_OR_LIST ) { Predicate *list = p->down; for (; list!=NULL; list=list->right) { genCombinedPredTreeContextOrig(list); if ( list->right!=NULL ) _gen("||"); }; return; }; fatal("pred tree is really wacked"); } /* [genCombinedPredTreeContext] */ void #ifdef __USE_PROTOS genCombinedPredTreeContext( Predicate *p ) #else genCombinedPredTreeContext( p ) Predicate *p; #endif { Tree *t; int predDepth=0; if (0 && ! MR_usingPredNames && ! MRhoisting) { genCombinedPredTreeContextOrig(p); } else { /* MR13 */ MR_pred_depth(p,&predDepth); /* MR13 */ if (predDepth == 1) { /* MR13 */ /* MR13 */ set scontext[2]; /* MR13 */ scontext[0]=empty; /* MR13 */ scontext[1]=MR_compute_pred_set(p); /* MR13 */ if (set_nil(scontext[1])) { /* MR13 */ _gen(" 1 /* MR12 no context (-prc off) */ "); /* MR13 */ } else { /* MR13 */ _gen("("); /* MR13 */ genExprSets(&scontext[0], 1); /* MR13 */ set_free(scontext[1]); /* MR13 */ _gen(")"); /* MR13 */ }; } else { t=MR_compute_pred_tree_context(p); if (t == NULL) { _gen(" 1 /* MR12 no context (-prc off) */ "); } else { _gen("("); genExprTree(t, 1); Tfree(t); /* MR10 */ _gen(")"); }; }; }; } /* [genPredTreeGate] */ void #ifdef __USE_PROTOS genPredTreeGate( Predicate *p, int in_and_expr ) #else genPredTreeGate( p, in_and_expr ) Predicate *p; int in_and_expr; #endif { if ( in_and_expr ) { _gen("!("); genCombinedPredTreeContext(p); _gen(")||"); if ( p->down!=NULL ) _gen("\n"); } else { _gen("("); genCombinedPredTreeContext(p); _gen(")&&"); if ( p->down!=NULL ) _gen("\n"); } } #ifdef __USE_PROTOS void genPredEntry(Predicate *p,int outer) #else void genPredEntry(p,outer) Predicate *p; int outer; #endif { int inverted=0; Predicate *q; int localOuter=outer; int needRP=0; if (p == NULL) return; if (p->predEntry != NULL && p->predEntry->predLiteral != NULL) { if (p->inverted != p->predEntry->pred->inverted) { _gen("! /* inverted pred */ ("); needRP=1; } else { if (!localOuter) _gen("("); needRP=1; }; dumpAction(p->predEntry->predLiteral,output,0,p->source->file,p->source->line,0); if (needRP) _gen(")"); return; }; inverted=p->inverted; if (inverted) { _gen(" ! /* inverted pred */ ("); localOuter=1; }; if (p->expr == PRED_OR_LIST) { if (!localOuter) _gen("("); for (q=p->down; q != NULL ; q=q->right) { genPredEntry(q,0); if (q->right != NULL) _gen(" || "); }; if (!localOuter) _gen(")"); } else if (p->expr == PRED_AND_LIST) { if (!localOuter) _gen("("); for (q=p->down; q != NULL ; q=q->right) { genPredEntry(q,0); if (q->right != NULL) _gen(" && "); }; if (!localOuter) _gen(")"); } else { if (!localOuter) _gen("("); require (p->source != NULL,"predEntry->source == NULL"); require (p->source->inverted == 0,"dumpPredEntry p->source->inverted != 0"); dumpAction(p->source->action,output,0,p->source->file,p->source->line,0); if (!localOuter) _gen(")"); }; if (inverted) { _gen(")"); } } void #ifdef __USE_PROTOS dumpPredAction(ActionNode *anode, char *s,FILE *output,int tabs,int file,int line,int final_newline) #else dumpPredAction(anode, s,output,tabs,file,line,final_newline) ActionNode *anode; char *s; FILE *output; int tabs; int file; int line; int final_newline; #endif { PredEntry *predEntry=anode->predEntry; int inverted=anode->inverted; Predicate *workPred; if (predEntry == NULL) { /* inline predicate literal */ require(inverted == 0,"dumpPredAction action->inverted"); dumpAction(s,output,tabs,file,line,final_newline); } else { /* a reference to a predicate - possibly with an inverted source */ if (predEntry->predLiteral != NULL) { if (inverted) _gen("! /* inverted pred */ ("); dumpAction(predEntry->predLiteral,output,0,anode->file,anode->line,0); if (inverted) _gen(")"); } else { workPred=predicate_dup(predEntry->pred); if (inverted) workPred->inverted=!workPred->inverted; genPredEntry(workPred,1); predicate_free(workPred); }; }; } /* [genPred] */ void #ifdef __USE_PROTOS genPred(Predicate *p, Node *j,int suppress_sva) #else genPred(p,j,suppress_sva) Predicate *p; Node *j; int suppress_sva; #endif { if ( FoundException && !suppress_sva) {_gen("(_sva=(");} /* MR11 suppress_sva */ else {_gen("(");} if ( GenLineInfo && j->file != -1 ) _gen("\n"); if (p->source != NULL && p->source->ampersandPred != NULL) { if (p->source->ampersandPred->k == 1) { set ctx[2]; ctx[0]=empty; ctx[1]=set_dup(p->source->ampersandPred->scontext[1]); _gen("("); genExprSets(&(ctx[0]), p->k); _gen(") && "); set_free(ctx[1]); } else { _gen("( "); genExprTree(p->source->ampersandPred->tcontext,1); _gen(" ) && "); }; }; dumpPredAction((ActionNode *)p->source, p->expr, output, 0, -1 /*indicates no line info*/, j->line, 0); if ( FoundException && !suppress_sva) /* MR11 suppress_sva */ {_gen("),_sva)");} /* MR10 - get red of "meant ==" messages */ else {_gen(")");} } void #ifdef __USE_PROTOS MR_distinctORcontextOpt(Predicate *p,Node *j,int in_and_expr) #else MR_distinctORcontextOpt(p,j,in_and_expr) Predicate *p; Node *j; int in_and_expr; #endif { Predicate *q; _gen(" /* MR10 Distinct OR context optimization */ \n"); if (in_and_expr) { gen("zzpf=0,\n"); for (q=p->down; q != NULL; q=q->right) { gen("( "); genCombinedPredTreeContext(q); _gen(" && (zzpf=1, "); genPred(q,j,0); _gen(" )) ||\n"); }; gen("!zzpf)"); } else { require (0, "MR_distinctORcontextOpt: can't get here when using MR_predSimplify"); #if 0 ** for (q=p->down; q != NULL; q=q->right) { ** gen("( "); ** genCombinedPredTreeContext(q); ** _gen(" && "); ** genPred(q,j); ** if (q->right != NULL) { ** _gen(" ) ||\n"); ** }; ** }; ** gen(")"); #endif }; } void #ifdef __USE_PROTOS genPredTreeOrig( Predicate *p, Node *j, int in_and_expr ) #else genPredTreeOrig( p, j, in_and_expr ) Predicate *p; Node *j; int in_and_expr; #endif { /* MR10 */ int allHaveContext=1; /* MR10 */ int noneHaveContext=1; /* MR10 */ MR_predContextPresent(p,&allHaveContext,&noneHaveContext); if ( ! noneHaveContext ) /* MR10 context guards ignored when -prc off */ { _gen("("); genPredTreeGate(p, in_and_expr); } /* if leaf node, just gen predicate */ if ( p->down==NULL ) { genPred(p,j,0); if ( ! noneHaveContext ) _gen(")"); /* MR10 context guards ignored when -prc off */ return; } /* if AND list, do both preds (only two possible) */ if ( p->expr == PRED_AND_LIST ) { #if 0 ** _gen("("); ** genPredTreeOrig(p->down, j, 1); ** _gen("&&"); ** genPredTreeOrig(p->down->right, j, 1); ** _gen(")"); ** if ( ! noneHaveContext ) _gen(")"); /* MR10 context guards ignored when -prc off */ ** return; #endif /* MR11 - make it work with AND with more than two children - like OR */ Predicate *list; _gen("("); list = p->down; for (; list!=NULL; list=list->right) { genPredTreeOrig(list, j, 1); if ( list->right!=NULL ) _gen("&&"); } _gen(")"); if ( ! noneHaveContext ) _gen(")"); /* MR10 context guards ignored when -prc off */ return; }; if ( p->expr == PRED_OR_LIST ) { Predicate *list; _gen("("); list = p->down; for (; list!=NULL; list=list->right) { genPredTreeOrig(list, j, 0); if ( list->right!=NULL ) _gen("||"); } _gen(")"); if ( ! noneHaveContext ) _gen(")"); /* MR10 context guards ignored when -prc off */ return; } fatal_internal("genPredTreeOrig: predicate tree is wacked"); } #if 0 ** Predicate member dummyPredDepth is no longer used in MR10 ** but we might need it again in the future ** ** if (MRhoisting) { ** if ( !noneHaveContext && ** ! in_and_expr && ** p->source != NULL && ** p->source->dummyPredicateDepth > 0 && ** p->down == NULL) { ** _gen("("); ** genCombinedPredTreeContext(p); ** _gen(" )\n"); ** return; ** }; ** }; #endif /* [genPredTree] */ /* in_and_expr what to do if the context is wrong what to do if the context is correct but the predicate is false remember: if the context is wrong it's the same as if the predicate is true as far as enabling an alternative Consider (AND p q r) if in an ... && ... expression then you don't want the entire predicate chain to fail just because the context for one component is wrong: so return true Consider (OR p q r) if in an ... || ... expression then you don't want the entire predicate chain to succeed just because the context for one component is correct when the corresponding test is false: so return false when the context is correct but the test is false. */ void #ifdef __USE_PROTOS genPredTree( Predicate *p, Node *j, int in_and_expr, int suppress_sva ) #else genPredTree( p, j, in_and_expr, suppress_sva) Predicate *p; Node *j; int in_and_expr; int suppress_sva; #endif { int allHaveContext=1; int noneHaveContext=1; Tree *groupTree; Tree *oneTree; Predicate *q; int identicalORcontextOptimization=0; int identicalANDcontextOptimization=0; if (0 && !MR_usingPredNames && !MRhoisting) { genPredTreeOrig(p,j,in_and_expr); return; }; MR_predContextPresent(p,&allHaveContext,&noneHaveContext); if ( ! noneHaveContext ) { /* MR10 context guards ignored when -prc off */ _gen("("); /* MR10 optimize OR predicates which are all leaves */ if (p->expr == PRED_OR_LIST && MR_allPredLeaves(p->down)) { groupTree=MR_compute_pred_tree_context(p); for (q=p->down ; q != NULL ; q=q->right) { oneTree=MR_compute_pred_tree_context(q); if (! MR_tree_equ(groupTree,oneTree)) { Tfree(oneTree); break; }; Tfree(oneTree); }; Tfree(groupTree); if (q == NULL) { _gen("/* MR10 individual OR gates suppressed when all predicates are leaves"); _gen(" with identical context */\n"); genPredTreeGate(p,in_and_expr); /* use the parent's in_and_expr for this gate */ identicalORcontextOptimization=1; } else { MR_distinctORcontextOpt(p,j,in_and_expr); return; }; } else if (p->expr == PRED_AND_LIST && MR_allPredLeaves(p->down)) { /* MR12 optimize AND predicates which are all leaves */ groupTree=MR_compute_pred_tree_context(p); for (q=p->down ; q != NULL ; q=q->right) { oneTree=MR_compute_pred_tree_context(q); if (! MR_tree_equ(groupTree,oneTree)) { Tfree(oneTree); break; }; Tfree(oneTree); }; Tfree(groupTree); if (q == NULL) { _gen("/* MR12 individual AND gates suppressed when all predicates are leaves"); _gen(" with identical context */\n"); genPredTreeGate(p,in_and_expr); /* use the parent's in_and_expr for this gate */ identicalANDcontextOptimization=1; } else { genPredTreeGate(p, in_and_expr); }; } else { genPredTreeGate(p, in_and_expr); }; } /* if leaf node, just gen predicate */ if ( p->down==NULL ) { genPred(p,j,suppress_sva); if ( ! noneHaveContext ) _gen(")"); /* MR10 context guards ignored when -prc off */ return; } /* if AND list, do both preds (only two possible) */ /* MR10 not any more ! */ if ( p->expr == PRED_AND_LIST ) { Predicate *list; _gen("("); list = p->down; for (; list != NULL; list=list->right) { if (identicalANDcontextOptimization) { genPred(list, j,suppress_sva); } else { genPredTree(list, j, 1, suppress_sva); /* in and context */ }; if ( list->right!=NULL ) _gen("&&"); }; _gen(")"); if ( ! noneHaveContext ) _gen(")"); /* MR10 context guards ignored when -prc off */ return; } if ( p->expr == PRED_OR_LIST ) { Predicate *list; _gen("("); list = p->down; for (; list!=NULL; list=list->right) { if (identicalORcontextOptimization) { genPred(list, j,suppress_sva); } else { genPredTree(list, j, 0, suppress_sva); }; if ( list->right!=NULL ) _gen("||"); } _gen(")"); if ( ! noneHaveContext ) _gen(")"); /* MR10 context guards ignored when -prc off */ return; } fatal_internal("predicate tree is wacked"); } /* [genPredTreeMainXX] */ Predicate * /* MR10 */ #ifdef __USE_PROTOS genPredTreeMainXX( Predicate *p, Node *j ,int in_and_expr) #else genPredTreeMainXX( p, j ,in_and_expr) Predicate *p; Node *j; int in_and_expr; #endif { int allHaveContext=1; int noneHaveContext=1; #if 0 fprintf(stderr,"Pred before\n"); dumppred(p); fprintf(stderr,"\n"); fprintf(stderr,"Pred after\n"); dumppred(p); fprintf(stderr,"\n"); #endif p=MR_predSimplifyALL(p); /* MR10 */ require (MR_predicate_context_completed(p),"predicate context is not complete"); MR_cleanup_pred_trees(p); /* MR10 */ MR_predContextPresent(p,&allHaveContext,&noneHaveContext); if (!noneHaveContext && !allHaveContext) { warnFL("predicate contains elements both with and without context", FileStr[j->file],j->line); }; if (InfoP) { _gen("\n#if 0\n\n"); MR_dumpPred(p,1); _gen("#endif\n"); }; genPredTree(p,j,in_and_expr,0); return p; } Predicate * /* MR10 */ #ifdef __USE_PROTOS genPredTreeMain( Predicate *p, Node *j) #else genPredTreeMain( p, j) Predicate *p; Node *j; #endif { return genPredTreeMainXX(p,j,1); } static void #ifdef __USE_PROTOS genExprTreeOriginal( Tree *t, int k ) #else genExprTreeOriginal( t, k ) Tree *t; int k; #endif { require(t!=NULL, "genExprTreeOriginal: NULL tree"); if ( t->token == ALT ) { _gen("("); genExprTreeOriginal(t->down, k); _gen(")"); if ( t->right!=NULL ) { _gen("||"); on1line++; if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); } _gen("("); genExprTreeOriginal(t->right, k); _gen(")"); } return; } if ( t->down!=NULL ) _gen("("); _gen1("LA(%d)==",k); if ( TokenString(t->token) == NULL ) _gen1("%d", t->token) else _gen1("%s", TokenString(t->token)); if ( t->down!=NULL ) { _gen("&&"); on1line++; if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); } _gen("("); genExprTreeOriginal(t->down, k+1); _gen(")"); } if ( t->down!=NULL ) _gen(")"); if ( t->right!=NULL ) { _gen("||"); on1line++; if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); } _gen("("); genExprTreeOriginal(t->right, k); _gen(")"); } } #ifdef __USE_PROTOS static void MR_LAtokenString(int k,int token) #else static void MR_LAtokenString(k,token) int k; int token; #endif { char *ts; ts=TokenString(token); if (ts == NULL) { _gen2(" LA(%d)==%d",k,token); } else { _gen2(" LA(%d)==%s",k,ts); }; } #ifdef __USE_PROTOS static int MR_countLeaves(Tree *t) #else static int MR_countLeaves(t) Tree *t; #endif { if (t == NULL) return 0; if (t->token == ALT) { return MR_countLeaves(t->down)+MR_countLeaves(t->right); } else { return 1+MR_countLeaves(t->down)+MR_countLeaves(t->right); }; } #ifdef __USE_PROTOS static void MR_genOneLine(Tree *tree,int k) #else static void MR_genOneLine(tree,k) Tree *tree; int k; #endif { if (tree == NULL) return; if (tree->token == ALT) { MR_genOneLine(tree->down,k); } else { MR_LAtokenString(k,tree->token); if (tree->down != NULL && tree->down->right == NULL) { _gen(" &&"); MR_genOneLine(tree->down,k+1); } else if (tree->down != NULL) { _gen(" && ("); MR_genOneLine(tree->down,k+1); _gen(")"); }; }; if (tree->right != NULL) { _gen(" ||"); MR_genOneLine(tree->right,k); }; } static int across; static int depth; static int lastkonline; #ifdef __USE_PROTOS static void MR_genMultiLine(Tree *tree,int k) #else static void MR_genMultiLine(tree,k) Tree *tree; int k; #endif { int i; if (tree == NULL) return; if (tree->token == ALT) { MR_genMultiLine(tree,k); } else { MR_LAtokenString(k,tree->token); lastkonline=k; across++; if (tree->down != NULL && tree->down->right == NULL) { if (across > 3) { _gen("\n"); across=0; lastkonline=0; for (i=0 ; i < depth+k ; i++) _gen(" "); _gen("&&"); } else { _gen(" &&"); }; MR_genMultiLine(tree->down,k+1); } else if (tree->down != NULL) { _gen("\n"); lastkonline=0; across=0; for (i=0 ; i < depth+k ; i++) _gen(" "); _gen("&& ("); MR_genMultiLine(tree->down,k+1); _gen(")"); }; }; if (tree->right != NULL) { if (k < lastkonline) { _gen("\n"); across=0; lastkonline=0; for (i=0; i < depth+k-1 ; i++) _gen(" "); _gen("||"); } else if (across > 3 ) { _gen("\n"); across=0; lastkonline=0; for (i=0; i < depth+k ; i++) _gen(" "); _gen("||"); } else { _gen(" ||"); }; MR_genMultiLine(tree->right,k); }; } #ifdef __USE_PROTOS static void genExprTree(Tree *tree,int k) #else static void genExprTree(tree,k) Tree *tree; int k; #endif { int count; #if 0 /* MR20 THM This was probably an error. The routine should probably reference that static "across" and this declaration hides it. */ int across; #endif require (tree != NULL,"genExprTree: tree is NULL"); require (k > 0,"genExprTree: k <= 0"); if (0 && !MRhoisting) { /* MR11 make new version standard */ genExprTreeOriginal(tree,k); } else { count=MR_countLeaves(tree); if (count < 5) { MR_genOneLine(tree,k); } else { _gen("\n"); across=0; depth=0; lastkonline=0; MR_genMultiLine(tree,k); _gen("\n"); }; }; } /* * Generate LL(k) type expressions of the form: * * (LA(1) == T1 || LA(1) == T2 || ... || LA(1) == Tn) && * (LA(2) == T1 || LA(2) == T2 || ... || LA(2) == Tn) && * ..... * (LA(k) == T1 || LA(k) == T2 || ... || LA(k) == Tn) * * If GenExprSetsOpt generate: * * (setwdi[LA(1)]&(1<= 1. * * This routine is visible only to this file and cannot answer a TRANS message. * */ /* [genExpr] */ static int #ifdef __USE_PROTOS genExpr( Junction *j ) #else genExpr( j ) Junction *j; #endif { int max_k; /* if full LL(k) is sufficient, then don't use approximate (-ck) lookahead * from CLL_k..LL_k */ { int limit; if ( j->ftree!=NULL ) limit = LL_k; else limit = CLL_k; max_k = genExprSets(j->fset, limit); } /* Do tests for real tuples from other productions that conflict with * artificial tuples generated by compression (using sets of tokens * rather than k-trees). */ if ( j->ftree != NULL ) { _gen(" && !("); genExprTree(j->ftree, 1); _gen(")"); } if ( ParseWithPredicates && j->predicate!=NULL ) { Predicate *p = j->predicate; warn_about_using_gk_option(); _gen("&&"); j->predicate=genPredTreeMain(p, (Node *)j); /* MR10 */ } return max_k; } static int #ifdef __USE_PROTOS genExprSets( set *fset, int limit ) #else genExprSets( fset, limit ) set *fset; int limit; #endif { int k = 1; int max_k = 0; unsigned *e, *g, firstTime=1; if (set_nil(fset[1])) { _gen(" 0 /* MR13 empty set expression - undefined rule ? infinite left recursion ? */ "); MR_BadExprSets++; }; if ( GenExprSetsOpt ) { while ( k <= limit && !set_nil(fset[k]) ) /* MR11 */ { if ( set_deg(fset[k])==1 ) /* too simple for a set? */ { int e; _gen1("(LA(%d)==",k); e = set_int(fset[k]); if ( TokenString(e) == NULL ) _gen1("%d)", e) else _gen1("%s)", TokenString(e)); } else { NewSet(); FillSet( fset[k] ); _gen3("(setwd%d[LA(%d)]&0x%x)", wordnum, k, 1<max_k ) max_k = k; if ( k == CLL_k ) break; k++; if ( k<=limit && !set_nil(fset[k]) ) _gen(" && "); /* MR11 */ on1line++; if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); } } return max_k; } while ( k<= limit && !set_nil(fset[k]) ) /* MR11 */ { if ( (e=g=set_pdq(fset[k])) == NULL ) fatal_internal("genExpr: cannot allocate IF expr pdq set"); for (; *e!=nil; e++) { if ( !firstTime ) _gen(" || ") else { _gen("("); firstTime = 0; } on1line++; if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); } _gen1("LA(%d)==",k); if ( TokenString(*e) == NULL ) _gen1("%d", *e) else _gen1("%s", TokenString(*e)); } free( (char *)g ); _gen(")"); if ( k>max_k ) max_k = k; if ( k == CLL_k ) break; k++; if ( k <= limit && !set_nil(fset[k]) ) { firstTime=1; _gen(" && "); } /* MR11 */ on1line++; if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); } } return max_k; } /* * Generate code for any type of block. If the last alternative in the block is * empty (not even an action) don't bother doing it. This permits us to handle * optional and loop blocks as well. * * Only do this block, return after completing the block. * This routine is visible only to this file and cannot answer a TRANS message. */ static set #ifdef __USE_PROTOS genBlk( Junction *q, int jtype, int *max_k, int *need_right_curly, int * lastAltEmpty /* MR23 */) #else genBlk( q, jtype, max_k, need_right_curly, lastAltEmpty /* MR23 */) Junction *q; int jtype; int *max_k; int *need_right_curly; int *lastAltEmpty; /* MR23 */ #endif { set f; Junction *alt; int a_guess_in_block = 0; require(q!=NULL, "genBlk: invalid node"); require(q->ntype == nJunction, "genBlk: not junction"); *need_right_curly=0; *lastAltEmpty = 0; /* MR23 */ if ( q->p2 == NULL ) /* only one alternative? Then don't need if */ { if (first_item_is_guess_block((Junction *)q->p1)!=NULL ) { if (jtype != aLoopBlk && jtype != aOptBlk && jtype != aPlusBlk) { warnFL("(...)? as only alternative of block is unnecessary", FileStr[q->file], q->line); }; gen("zzGUESS\n"); /* guess anyway to make output code consistent */ /* MR10 disable */ /**** gen("if ( !zzrv )\n"); ****/ /* MR10 */ gen("if ( !zzrv ) {\n"); tabs++; (*need_right_curly)++; }; TRANS(q->p1); return empty; /* no decision to be made-->no error set */ } f = First(q, 1, jtype, max_k); for (alt=q; alt != NULL; alt= (Junction *) alt->p2 ) { if ( alt->p2 == NULL ) /* chk for empty alt */ { Node *p = alt->p1; if ( p->ntype == nJunction ) { /* we have empty alt */ /* MR23 There is a conflict between giving good error information for non-exceptions and making life easy for those using parser exception handling. Consider: r: { A } b; b: B; with input "C" Before MR21 the error message would be "expecting B - found C". After MR21 the error message would be "expcect A, B - found C". This was good, but it caused problems for those using parser exceptions because the reference to B was generated inside the {...} where B really wasn't part of the block. In MR23 this has been changed for the case where exceptions are in use to not generate the extra check in the tail of the {A} block. */ /* MR23 */ if (isEmptyAlt( ((Junction *)p)->p1, (Node *)q->end)) { /* MR23 */ *lastAltEmpty = 1; /* MR23 */ if (FoundException) { /* MR23 */ /* code to restore state if a prev alt didn't follow guess */ /* MR23 */ if ( a_guess_in_block && jtype != aPlusBlk) { /* MR23 */ gen("if ( !zzrv ) zzGUESS_DONE; /* MR28 */\n"); /* MR23 */ } /* MR23 */ break; /* MR23 */ }; /* MR28 */ if (jtype == aPlusBlk) { /* MR28 */ break; /* MR28 */ } /* MR23 */ } } } /* end of for loop on alt */ /* MR10 */ if (alt->p2 == NULL && /* MR10 */ ( q->jtype == aSubBlk || q->jtype == RuleBlk) ) { /* MR10 */ if (first_item_is_guess_block(alt)) { /* MR10 */ warnFL("(...)? as last alternative of block is unnecessary", /* MR10 */ FileStr[alt->file],alt->line); /* MR10 */ }; /* MR10 */ }; if ( alt != q ) gen("else ") else { if ( DemandLookahead ) { if ( !GenCC ) {gen1("LOOK(%d);\n", *max_k);} else gen1("look(%d);\n", *max_k); } } if ( alt!=q ) { _gen("{\n"); tabs++; (*need_right_curly)++; /* code to restore state if a prev alt didn't follow guess */ if ( a_guess_in_block ) gen("if ( !zzrv ) zzGUESS_DONE;\n"); } if ( first_item_is_guess_block((Junction *)alt->p1)!=NULL ) { a_guess_in_block = 1; gen("zzGUESS\n"); } gen("if ( "); if ( first_item_is_guess_block((Junction *)alt->p1)!=NULL ) _gen("!zzrv && "); genExpr(alt); _gen(" ) "); _gen("{\n"); tabs++; TRANS(alt->p1); --tabs; gen("}\n"); /* MR10 */ if (alt->p2 == NULL) { /* MR10 */ if (first_item_is_guess_block(alt)) { /* MR10 */ gen("/* MR10 */ else {\n"); /* MR10 */ tabs++; /* MR10 */ (*need_right_curly)++; /* MR10 */ /* code to restore state if a prev alt didn't follow guess */ /* MR10 */ gen("/* MR10 */ if ( !zzrv ) zzGUESS_DONE;\n"); /* MR10 */ gen("/* MR10 */ if (0) {} /* last alternative of block is guess block */\n"); /* MR10 */ }; /* MR10 */ }; } return f; } static int #ifdef __USE_PROTOS has_guess_block_as_first_item( Junction *q ) #else has_guess_block_as_first_item( q ) Junction *q; #endif { Junction *alt; for (alt=q; alt != NULL; alt= (Junction *) alt->p2 ) { if ( first_item_is_guess_block((Junction *)alt->p1)!=NULL ) return 1; } return 0; } static int #ifdef __USE_PROTOS has_guess_block_as_last_item( Junction *q ) #else has_guess_block_as_last_item( q ) Junction *q; #endif { Junction *alt; if (q == NULL) return 0; for (alt=q; alt->p2 != NULL && !( (Junction *) alt->p2)->ignore; alt= (Junction *) alt->p2 ) {}; return first_item_is_guess_block( (Junction *) alt->p1) != NULL; } /* MR30 See description of first_item_is_guess_block for background */ Junction * #ifdef __USE_PROTOS first_item_is_guess_block_extra(Junction *q ) #else first_item_is_guess_block_extra(q) Junction *q; #endif { while ( q!=NULL && ( ( q->ntype==nAction ) || ( q->ntype==nJunction && (q->jtype==Generic || q->jtype == aLoopBlk) ) ) ) { if ( q->ntype==nJunction ) q = (Junction *)q->p1; else q = (Junction *) ((ActionNode *)q)->next; } if ( q==NULL ) return NULL; if ( q->ntype!=nJunction ) return NULL; if ( q->jtype!=aSubBlk ) return NULL; if ( !q->guess ) return NULL; return q; } /* return NULL if 1st item of alt is NOT (...)? block; else return ptr to aSubBlk node * of (...)?; This function ignores actions and predicates. */ Junction * #ifdef __USE_PROTOS first_item_is_guess_block( Junction *q ) #else first_item_is_guess_block( q ) Junction *q; #endif { Junction * qOriginal = q; /* DEBUG */ /* MR14 Couldn't find aSubBlock which was a guess block when it lay behind aLoopBlk. The aLoopBlk only appear in conjunction with aLoopBegin, but the routine didn't know that. I think. MR14a Added extra parentheses to clarify precedence MR30 This appears to have been a mistake. The First set was then computed incorrectly for: r : ( (A)? B | C )* The routine analysis_point was seeing the guess block when it was still analyzing the loopBegin block. As a consequence, when it looked for the analysis_point it was processing the B, but skipping over the C alternative altogether because it thought it was looking at a guess block, not realizing there was a loop block in front of the loopBegin. loopBegin loopBlk subBlk/guess A G EB G B EB EB EB ER | | | ^ ^ | | | | | +-> G C G ----------------------+ | | | +--- G G G -------------------------------------+ Reported by Arpad Beszedes (beszedes@inf.u-szeged.hu). MR30 This is still more complicated. This fix caused ambiguity messages to be reported for "( (A B)? )* A B" but not for "( (A B)? )+". Why is there a difference when these are outwardly identical ? It is because the start of a (...)* block is represented by two nodes: a loopBegin block followed by a loopBlock whereas the start of a (...)+ block is represented as a single node: a plusBlock. So if first_item_is_guess_block is called when the current node is a loopBegin it starts with the loop block rather than the the sub block which follows the loop block. However, we can't just skip past the loop block because some routines depend on the old implementation. So, we provide a new implementation which does skip the loopBlock. However, which should be called when ? I'm not sure, but my guess is that first_item_is_guess_block_extra (the new one) should only be called for the ambiguity routines. */ while ( q!=NULL && ( ( q->ntype==nAction ) || ( q->ntype==nJunction && (q->jtype==Generic /*** || q->jtype == aLoopBlk ***/ ) /*** MR30 Undo MR14 change ***/ ) ) ) { if ( q->ntype==nJunction ) q = (Junction *)q->p1; else q = (Junction *) ((ActionNode *)q)->next; } if ( q==NULL ) return NULL; if ( q->ntype!=nJunction ) return NULL; if ( q->jtype!=aSubBlk ) return NULL; if ( !q->guess ) return NULL; return q; } /* MR1 */ /* MR1 10-Apr-97 MR1 Routine to stringize failed semantic predicates msgs */ /* MR1 */ #define STRINGIZEBUFSIZE 1024 static char stringizeBuf[STRINGIZEBUFSIZE]; char * #ifdef __USE_PROTOS stringize(char * s) #else stringize(s) char *s; #endif { char *p; char *stop; p=stringizeBuf; stop=&stringizeBuf[1015]; if (s != 0) { while (*s != 0) { if (p >= stop) { goto stringizeStop; } else if (*s == '\n') { *p++='\\'; *p++='n'; *p++='\\'; *p++=*s++; } else if (*s == '\\') { *p++=*s; *p++=*s++; } else if (*s == '\"') { *p++='\\'; *p++=*s++; while (*s != 0) { if (p >= stop) { goto stringizeStop; } else if (*s == '\n') { *p++='\\'; *p++=*s++; } else if (*s == '\\') { *p++=*s++; *p++=*s++; } else if (*s == '\"') { *p++='\\'; *p++=*s++; break; } else { *p++=*s++; }; }; } else if (*s == '\'') { *p++=*s++; while (*s != 0) { if (p >= stop) { goto stringizeStop; } else if (*s == '\'') { *p++=*s++; break; } else if (*s == '\\') { *p++=*s++; *p++=*s++; } else if (*s == '\"') { *p++='\\'; *p++=*s++; break; } else { *p++=*s++; }; }; } else { *p++=*s++; }; }; }; goto stringizeExit; stringizeStop: *p++='.'; *p++='.'; *p++='.'; stringizeExit: *p=0; return stringizeBuf; } #ifdef __USE_PROTOS int isNullAction(char *s) #else int isNullAction(s) char *s; #endif { char *p; for (p=s; *p != '\0' ; p++) { if (*p != ';' && *p !=' ') return 0; }; return 1; } /* MR1 */ /* MR1 End of Routine to stringize code for failed predicates msgs */ /* MR1 */ /* Generate an action. Don't if action is NULL which means that it was already * handled as an init action. */ void #ifdef __USE_PROTOS genAction( ActionNode *p ) #else genAction( p ) ActionNode *p; #endif { require(p!=NULL, "genAction: invalid node and/or rule"); require(p->ntype==nAction, "genAction: not action"); if ( !p->done ) /* MR10 */ /* MR11 */ { if ( p->is_predicate) { if ( p->guardpred != NULL ) { Predicate *guardDup=predicate_dup(p->guardpred); /* MR10 */ gen("if (!"); guardDup=genPredTreeMain(guardDup, (Node *)p); predicate_free(guardDup); } /* MR10 */ else if (p->ampersandPred != NULL) { /* MR10 */ gen("if (!"); /* MR10 */ p->ampersandPred=genPredTreeMain(p->ampersandPred, (Node *)p); /* MR10 */ } else { gen("if (!("); /* make sure that '#line n' is on front of line */ if ( GenLineInfo && p->file != -1 ) _gen("\n"); dumpPredAction(p,p->action, output, 0, p->file, p->line, 0); _gen(")"); } /* MR23 Change failed predicate macro to have three arguments: macro arg 1: The stringized predicate itself macro arg 2: 0 => no user-defined error action 1 => user-defined error action macro arg 3: The user-defined error action This gives the user more control of the error action. */ tabs++; gen3(") {zzfailed_pred(\"%s\",%s, { %s } );}\n", /* MR23 */ stringize(p->action), /* MR23 */ (p->pred_fail == NULL ? /* MR23/MR27 */ "0 /* report */" : "1 /* user action */"), /* MR23/MR27 */ (p->pred_fail == NULL ? /* MR23 */ "0; /* no user action */" : p->pred_fail)); /* MR23 */ tabs--; } else /* not a predicate */ { if (! isNullAction(p->action) && !p->noHoist) { if ( FoundGuessBlk ) { if ( GenCC ) { gen("if ( !guessing ) {\n"); } else { gen("zzNON_GUESS_MODE {\n"); }; }; dumpActionPlus(p, p->action, output, tabs, p->file, p->line, 1); /* MR21 */ if ( FoundGuessBlk ) gen("}\n"); }; } } TRANS(p->next) } /* * if invoking rule has !noAST pass zzSTR to rule ref and zzlink it in * else pass addr of temp root ptr (&_ast) (don't zzlink it in). * * if ! modifies rule-ref, then never link it in and never pass zzSTR. * Always pass address of temp root ptr. */ void #ifdef __USE_PROTOS genRuleRef( RuleRefNode *p ) #else genRuleRef( p ) RuleRefNode *p; #endif { Junction *q; char *handler_id = ""; RuleEntry *r, *r2; char *parm = "", *exsig = ""; int genRuleRef_emittedGuessGuard=0; /* MR10 */ require(p!=NULL, "genRuleRef: invalid node and/or rule"); require(p->ntype==nRuleRef, "genRuleRef: not rule reference"); if ( p->altstart!=NULL && p->altstart->exception_label!=NULL ) handler_id = p->altstart->exception_label; r = (RuleEntry *) hash_get(Rname, p->text); if ( r == NULL ) { warnFL( eMsg1("rule %s not defined", p->text), FileStr[p->file], p->line ); return; } /* MR8 5-Aug-97 Reported by S.Bochnak@microtool.com.pl */ /* Don't do assign when no return values declared */ /* Move definition of q up and use it to guard p->assign */ q = RulePtr[r->rulenum]; /* find definition of ref'd rule */ /* MR8 */ r2 = (RuleEntry *) hash_get(Rname, p->rname); if ( r2 == NULL ) {warnNoFL("Rule hash table is screwed up beyond belief"); return;} OutLineInfo(output,p->line,FileStr[p->file]); if ( GenCC && GenAST ) { gen("_ast = NULL;\n"); } if ( FoundGuessBlk && p->assign!=NULL && q->ret != NULL ) { /* MR8 */ if ( GenCC ) { gen("if ( !guessing ) {\n"); } else { gen("zzNON_GUESS_MODE {\n"); }; tabs++; /* MR11 */ genRuleRef_emittedGuessGuard=1; /* MR11 */ }; if ( FoundException ) exsig = "&_signal"; tab(); if ( GenAST ) { if ( GenCC ) { /**** if ( r2->noAST || p->astnode==ASTexclude ) ****/ { /**** _gen("_ast = NULL;\n"); ****/ parm = "&_ast"; } /*** we always want to set just a pointer now, then set correct pointer after else { _gen("_astp = (_tail==NULL)?(&_sibling):(&(_tail->_right));\n"); parm = "_astp"; } ****/ } else { if ( r2->noAST || p->astnode==ASTexclude ) { _gen("_ast = NULL; "); parm = "&_ast"; } else parm = "zzSTR"; } if ( p->assign!=NULL && q->ret!=NULL ) /* MR8 */ { if ( !hasMultipleOperands(p->assign) ) {_gen1("%s = ",p->assign);} /* MR23 */ else _gen1("{ struct _rv%d _trv; _trv = ", r->rulenum); } if ( FoundException ) { _gen5("%s%s(%s,&_signal%s%s); ", RulePrefix, p->text, parm, (p->parms!=NULL)?",":"", (p->parms!=NULL)?p->parms:""); if ( p->ex_group!=NULL ) { _gen("\n"); gen("if (_signal) {\n"); tabs++; dumpException(p->ex_group, 0); tabs--; gen("}"); } else { _gen1("if (_signal) goto %s_handler;", handler_id); } } else { _gen5("%s%s(%s%s%s);", RulePrefix, p->text, parm, (p->parms!=NULL)?",":"", (p->parms!=NULL)?p->parms:""); } if ( GenCC && (r2->noAST || p->astnode==ASTexclude) ) { /* rule has a ! or element does */ /* still need to assign to #i so we can play with it */ _gen("\n"); gen2("_ast%d%d = (AST *)_ast;", BlkLevel-1, p->elnum); } else if ( !r2->noAST && p->astnode == ASTinclude ) { /* rule doesn't have a ! and neither does element */ /* MR10 */ if (FoundGuessBlk && !genRuleRef_emittedGuessGuard) { /* MR10 */ _gen("\n"); /* MR10 */ if (GenCC) gen ("if (!guessing) { /* MR10 */") /* MR10 */ else gen ("if (!zzguessing) { /* MR10 */\n"); /* MR10 */ tabs++; /* MR10 */ }; if ( GenCC ) { _gen("\n"); gen("if ( _tail==NULL ) _sibling = _ast; else _tail->setRight(_ast);\n"); gen2("_ast%d%d = (AST *)_ast;\n", BlkLevel-1, p->elnum); tab(); } else _gen(" "); if ( GenCC ) { _gen("ASTBase::"); } else _gen("zz"); _gen("link(_root, &_sibling, &_tail);"); /* MR10 */ if (FoundGuessBlk && !genRuleRef_emittedGuessGuard) { /* MR10 */ /* MR10 */ _gen("\n"); /* MR10 */ tabs--; /* MR10 */ if (GenCC) gen ("}; /* MR10 */") /* MR10 */ else gen ("}; /* MR10 */"); /* MR10 */ }; } } else { if ( p->assign!=NULL && q->ret!=NULL ) /* MR8 */ { if ( !hasMultipleOperands(p->assign) ) {_gen1("%s = ",p->assign);} /* MR23 */ else _gen1("{ struct _rv%d _trv; _trv = ", r->rulenum); } if ( FoundException ) { _gen4("%s%s(&_signal%s%s); ", RulePrefix, p->text, (p->parms!=NULL)?",":"", (p->parms!=NULL)?p->parms:""); if ( p->ex_group!=NULL ) { _gen("\n"); gen("if (_signal) {\n"); tabs++; dumpException(p->ex_group, 0); tabs--; gen("}"); } else { _gen1("if (_signal) goto %s_handler;", handler_id); } } else { _gen3("%s%s(%s);", RulePrefix, p->text, (p->parms!=NULL)?p->parms:""); } if ( p->assign!=NULL && q->ret!=NULL ) _gen("\n"); /* MR8 */ } if ( p->assign!=NULL && q->ret!=NULL) { /* MR8 */ if ( hasMultipleOperands(p->assign) ) /* MR23 */ { _gen("\n"); dumpRetValAssign(p->assign, q->ret, p); /* MR30 */ _gen("}"); } } _gen("\n"); /* Handle element labels now */ if ( p->el_label!=NULL ) { if ( GenAST ) { if ( GenCC ) { gen3("%s_ast = _ast%d%d;\n", p->el_label, BlkLevel-1, p->elnum); } else {gen1("%s_ast = zzastCur;\n", p->el_label);} } else if (!GenCC ) { gen1("%s = zzaCur;\n", p->el_label); } } if ( FoundGuessBlk && p->assign!=NULL && q->ret!=NULL ) { /* MR8 */ /* in guessing mode, don't branch to handler upon error */ tabs--; /* MR11 */ gen("} else {\n"); tabs++; /* MR11 */ if ( FoundException ) { gen6("%s%s(%s%s&_signal%s%s);\n", RulePrefix, p->text, parm, (*parm!='\0')?",":"", (p->parms!=NULL)?",":"", (p->parms!=NULL)?p->parms:""); } else { gen5("%s%s(%s%s%s);\n", RulePrefix, p->text, parm, (p->parms!=NULL && *parm!='\0')?",":"", (p->parms!=NULL)?p->parms:""); } tabs--; /* MR11 */ gen("}\n"); } TRANS(p->next) } /* * Generate code to match a token. * * Getting the next token is tricky. We want to ensure that any action * following a token is executed before the next GetToken(); */ void #ifdef __USE_PROTOS genToken( TokNode *p ) #else genToken( p ) TokNode *p; #endif { RuleEntry *r; char *handler_id = ""; ActionNode *a; char *set_name; char *set_nameErrSet; int complement; int ast_label_in_action = 0; /* MR27 */ int pushedCmodeAST = 0; /* MR27 */ require(p!=NULL, "genToken: invalid node and/or rule"); require(p->ntype==nToken, "genToken: not token"); if ( p->altstart!=NULL && p->altstart->exception_label!=NULL ) handler_id = p->altstart->exception_label; r = (RuleEntry *) hash_get(Rname, p->rname); if ( r == NULL ) {warnNoFL("Rule hash table is screwed up beyond belief"); return;} /* * MR27 Has the element label been referenced as an AST (with the # operator) ? * If so, then we'll want to build the AST even though the user has used * the ! operator. */ /* MR27 */ if (GenAST && p->el_label != NULL) { /* MR27 */ ast_label_in_action = list_search_cstring(r->ast_labels_in_actions, /* MR27 */ p->el_label); /* MR27 */ } OutLineInfo(output,p->line,FileStr[p->file]); if ( !set_nil(p->tset) ) /* implies '.', ~Tok, or tokenclass */ { unsigned e; unsigned eErrSet = 0; set b; set bErrSet; /* MR23 */ b = set_dup(p->tset); bErrSet = set_dup(p->tset); /* MR23 */ complement = p->complement; /* MR23 */ if ( p->tclass!=NULL && complement == 0 /* MR23 */) { /* token class not complemented*/ static char buf[MaxRuleName+20]; /* MR23 */ static char bufErrSet[MaxRuleName+20]; /* MR23 */ if ( p->tclass->dumped ) { e = p->tclass->setnum; eErrSet = p->tclass->setnumErrSet; } else { e = DefErrSet(&b, 0, TokenString(p->token)); eErrSet = DefErrSetWithSuffix(0, &bErrSet, 1, TokenString(p->token), "_errset"); p->tclass->dumped = 1; /* indicate set has been created */ p->tclass->setnum = e; p->tclass->setnumErrSet = eErrSet; /* MR23 */ } sprintf(buf, "%s_set", TokenString(p->token)); sprintf(bufErrSet, "%s_errset", TokenString(p->token)); /* MR23 */ set_name = buf; set_nameErrSet = bufErrSet; /* MR23 */ } /* MR23 - Forgot about the case of ~TOKCLASS. */ else if ( p->tclass!=NULL && complement != 0 /* MR23 */) { static char buf[MaxRuleName+20]; /* MR23 */ static char bufErrSet[MaxRuleName+20]; /* MR23 */ if ( p->tclass->dumpedComplement ) { e = p->tclass->setnumComplement; eErrSet = p->tclass->setnumErrSetComplement; } else { e = DefErrSetWithSuffix(0, &b, 0, TokenString(p->token), "_setbar"); eErrSet = DefErrSetWithSuffix(0, &bErrSet, 1, TokenString(p->token), "_errsetbar"); p->tclass->dumpedComplement = 1; /* indicate set has been created */ p->tclass->setnumComplement = e; p->tclass->setnumErrSetComplement = eErrSet; /* MR23 */ } sprintf(buf, "%s_setbar", TokenString(p->token)); sprintf(bufErrSet, "%s_errsetbar", TokenString(p->token)); /* MR23 */ set_name = buf; set_nameErrSet = bufErrSet; /* MR23 */ } else { /* wild card */ static char buf[sizeof("zzerr")+10]; static char bufErrSet[sizeof("zzerr")+10]; int n = DefErrSet( &b, 0, NULL ); int nErrSet = DefErrSetWithSuffix(0, &bErrSet, 1, NULL, "_set"); if ( GenCC ) sprintf(buf, "err%d", n); else sprintf(buf, "zzerr%d", n); if ( GenCC ) sprintf(bufErrSet, "err%d", nErrSet); else sprintf(bufErrSet, "zzerr%d", nErrSet); set_name = buf; set_nameErrSet = bufErrSet; } if ( !FoundException ) { /* MR23 */ gen2("zzsetmatch(%s, %s);", set_name, set_nameErrSet); } else if ( p->ex_group==NULL ) { if ( p->use_def_MT_handler ) gen3("zzsetmatch_wdfltsig(%s,(ANTLRTokenType)%d,%s);", set_name, p->token, tokenFollowSet(p)) else gen2("zzsetmatch_wsig(%s, %s_handler);", set_name, handler_id); } else { gen1("if ( !_setmatch_wsig(%s) ) {\n", set_name); tabs++; /* MR6 */ if (FoundGuessBlk) { /* MR6 */ if ( GenCC ) {gen("if ( guessing ) goto fail;\n");} /* MR6 */ else gen("if ( zzguessing ) goto fail;\n"); /* MR6 */ }; gen("_signal=MismatchedToken;\n"); dumpException(p->ex_group, 0); tabs--; gen("}\n"); } set_free(b); set_free(bErrSet); } else if ( TokenString(p->token)!=NULL ) { if ( FoundException ) { if ( p->use_def_MT_handler ) gen2("zzmatch_wdfltsig(%s,%s);",TokenString(p->token),tokenFollowSet(p)) else if ( p->ex_group==NULL ) { gen2("zzmatch_wsig(%s, %s_handler);", TokenString(p->token), handler_id); } else { /* MR6 */ if (GenCC) { /* MR6 */ gen1("if ( !_match_wsig(%s) ) {\n", TokenString(p->token)); /* MR6 */ } else { /* MR6 */ gen1("if ( !_zzmatch_wsig(%s) ) {\n", TokenString(p->token)); /* MR6 */ }; tabs++; /* MR6 */ if (FoundGuessBlk) { /* MR6 */ if ( GenCC ) {gen("if ( guessing ) goto fail;\n");} /* MR6 */ else gen("if ( zzguessing ) goto fail;\n"); /* MR6 */ }; gen("_signal=MismatchedToken;\n"); dumpException(p->ex_group, 0); tabs--; gen("}\n"); } } else gen1("zzmatch(%s);", TokenString(p->token)); } else { if ( FoundException ) { if ( p->use_def_MT_handler ) gen2("zzmatch_wdfltsig((ANTLRTokenType)%d,%s);", p->token,tokenFollowSet(p)) else gen2("zzmatch_wsig(%d,%s_handler);",p->token,handler_id); } else {gen1("zzmatch(%d);", p->token);} } a = findImmedAction( p->next ); /* generate the token labels */ if ( GenCC && p->elnum>0 ) { /* If building trees in C++, always gen the LT() assigns */ if ( set_el(p->elnum, tokensRefdInBlock) || GenAST ) { /* MR10 */ if ( FoundGuessBlk ) { /* MR10 */ gen("\n"); /* MR10 */ if (p->label_used_in_semantic_pred) { /* MR10 */ gen2(" _t%d%d = (ANTLRTokenPtr)LT(1); /* MR10 */\n", BlkLevel-1, p->elnum); /* MR10 */ } else { /* MR10 */ gen("if ( !guessing ) {\n"); tab(); /* MR10 */ _gen2(" _t%d%d = (ANTLRTokenPtr)LT(1);\n", BlkLevel-1, p->elnum); /* MR10 */ gen("}\n"); /* MR10 */ }; /* MR10 */ } else { /* MR10 */ _gen2(" _t%d%d = (ANTLRTokenPtr)LT(1);", BlkLevel-1, p->elnum); /* MR10 */ }; /* MR10 */ } /* * MR23 labase is never used in the C++ runtime library. * and this code is generated only in C++ mode */ /*** if ( LL_k>1 ) / * MR23 disabled */ /*** if ( !DemandLookahead ) _gen(" labase++;"); / * MR23 disabled */ /*** _gen("\n"); / * MR23 disabled */ /*** tab(); / * MR23 disabled */ } if ( GenAST ) { if ( FoundGuessBlk && (ast_label_in_action || !(p->astnode == ASTexclude || r->noAST)) ) { if ( GenCC ) {_gen("if ( !guessing ) {\n"); tab();} else {_gen("zzNON_GUESS_MODE {\n"); tab();} } /* MR27 addition when labels referenced when operator ! used */ pushedCmodeAST = 0; /* MR27 */ if (ast_label_in_action && (p->astnode == ASTexclude || r->noAST)) { _gen("\n"); if (GenCC) { /* MR13 */ if (NewAST) { /* MR13 */ gen4("_ast%d%d = newAST(_t%d%d); /* MR27 */\n", BlkLevel-1, p->elnum, BlkLevel-1, p->elnum); /* MR13 */ } else { /* MR13 */ gen4("_ast%d%d = new AST(_t%d%d); /* MR27 */\n", BlkLevel-1, p->elnum, BlkLevel-1, p->elnum); /* MR13 */ } } else { pushedCmodeAST = 1; gen("zzastPush(zzmk_ast(zzastnew(),zzaCur)); /* MR27 */"); } } /* end MR27 addition for labels referenced when operator ! used */ if (!r->noAST ) { if (GenCC && !(p->astnode == ASTexclude) ) { _gen("\n"); /* MR13 */ if (NewAST) { /* MR13 */ gen4("_ast%d%d = newAST(_t%d%d);\n", BlkLevel-1, p->elnum, BlkLevel-1, p->elnum); /* MR13 */ } else { /* MR13 */ gen4("_ast%d%d = new AST(_t%d%d);\n", BlkLevel-1, p->elnum, BlkLevel-1, p->elnum); /* MR13 */ } tab(); } if ( GenCC && !(p->astnode == ASTexclude) ) {_gen2("_ast%d%d->", BlkLevel-1, p->elnum);} else _gen(" "); if ( p->astnode==ASTchild ) { if ( !GenCC ) _gen("zz"); _gen("subchild(_root, &_sibling, &_tail);"); } else if ( p->astnode==ASTroot ) { if ( !GenCC ) _gen("zz"); _gen("subroot(_root, &_sibling, &_tail);"); } if ( GenCC && !(p->astnode == ASTexclude) ) { _gen("\n"); tab(); } } else if ( !GenCC ) { if (! pushedCmodeAST) _gen(" zzastDPush;"); } if ( FoundGuessBlk && (ast_label_in_action || !(p->astnode == ASTexclude || r->noAST)) ) {gen("}\n"); tab();} } /* Handle element labels now */ if ( p->el_label!=NULL ) { int done_NON_GUESSMODE=0; _gen("\n"); /* MR10 */ /* do Attrib / Token ptr for token label used in semantic pred */ /* MR10 */ /* for these cases do assign even in guess mode */ /* MR10 */ /* MR10 */ if (p->label_used_in_semantic_pred) { /* MR10 */ if ( GenCC ) { /* MR10 */ if ( set_el(p->elnum, tokensRefdInBlock) || GenAST ) { /* MR10 */ gen3("%s = _t%d%d;", p->el_label, BlkLevel-1, p->elnum); /* MR10 */ } else { /* MR10 */ gen1("%s = (ANTLRTokenPtr)LT(1);\n", p->el_label); /* MR10 */ }; /* MR10 */ } else { /* MR10 */ gen1("%s = zzaCur;", p->el_label); /* MR10 */ }; /* MR10 */ if (FoundGuessBlk) _gen(" /* MR10 */"); /* MR10 */ _gen("\n"); /* MR10 */ }; /* Do Attrib / Token ptr */ /* MR10 */ if (! p->label_used_in_semantic_pred) { /* MR10 */ /* MR10 */ if ( FoundGuessBlk ) { /* MR10 */ if (! done_NON_GUESSMODE) { /* MR10 */ done_NON_GUESSMODE=1; /* MR10 */ if ( GenCC ) {gen("if ( !guessing ) {\n"); tab();} /* MR10 */ else {gen("zzNON_GUESS_MODE {\n"); tab();} /* MR10 */ }; /* MR10 */ }; /* MR10 */ /* MR10 */ if ( GenCC ) { /* MR10 */ if ( set_el(p->elnum, tokensRefdInBlock) || GenAST ) { /* MR10 */ gen3("%s = _t%d%d;\n", p->el_label, BlkLevel-1, p->elnum); /* MR10 */ } else { /* MR10 */ gen1("%s = (ANTLRTokenPtr)LT(1);\n", p->el_label); /* MR10 */ }; /* MR10 */ } else { /* MR10 */ gen1("%s = zzaCur;\n", p->el_label); /* MR10 */ }; /* MR10 */ }; /* Do AST ptr */ if (GenAST && (ast_label_in_action || !(p->astnode == ASTexclude || r->noAST) )) /* MR27 */ { /* MR10 */ if ( FoundGuessBlk ) { /* MR10 */ if (! done_NON_GUESSMODE) { /* MR10 */ done_NON_GUESSMODE=1; /* MR10 */ if ( GenCC ) {gen("if ( !guessing ) {\n"); tab();} /* MR10 */ else {gen("zzNON_GUESS_MODE {\n"); tab();} /* MR10 */ }; /* MR10 */ }; if ( GenCC ) { gen3("%s_ast = _ast%d%d;\n", p->el_label, BlkLevel-1, p->elnum); } else {gen1("%s_ast = zzastCur;\n", p->el_label);} } /* MR10 */ if (done_NON_GUESSMODE) { /* MR10 */ gen("}\n"); tab(); /* MR10 */ }; } /* Handle any actions immediately following action */ if ( a != NULL ) /* MR10 */ /* MR11 */ { /* delay next token fetch until after action */ _gen("\n"); if ( a->is_predicate) { #if 0 /* Disabled in MR30 ************************************************************ And moved into genAction ***************************************************************************** */ gen("if (!("); /* make sure that '#line n' is on front of line */ /* MR14 */ if ( GenLineInfo && p->file != -1 ) _gen("\n"); /* MR14 */ dumpPredAction(a,a->action, output, 0, a->file, a->line, 0); /* MR23 Change failed predicate macro to have three arguments: macro arg 1: The stringized predicate itself macro arg 2: 0 => no user-defined error action 1 => user-defined error action macro arg 3: The user-defined error action This gives the user more control of the error action. */ _gen(")) \n"); tabs++; gen3(" {zzfailed_pred(\"%s\",%s,{ %s } );}\n", /* MR23 */ stringize(a->action), /* MR23 */ (a->pred_fail == NULL ? /* MR23/MR27 */ "0 /* report */" : "1 /* user action */"), /* MR23/MR27 */ (a->pred_fail == NULL ? /* MR23 */ "0; /* no user action */" : a->pred_fail)); /* MR23 */ tabs--; /* Disabled in MR30 ************************************************************ And moved into genAction ***************************************************************************** */ #endif } else /* MR9 a regular action - not a predicate action */ { /* MR23: Search an action which is not a predicate for LT(i), LA(i), or LATEXT(i) in order to warn novice users that it refers to the previous matched token, not the next one. This is different than the case for semantic predicates. */ /* MR23 */ if (GenCC) { /* MR23 */ if (strstr(a->action, "LT(") != NULL) LTinTokenAction = 1; /* MR23 */ } /* MR23 */ else { /* MR23 */ if (strstr(a->action, "LA(") != NULL) LTinTokenAction = 1; /* MR23 */ if (strstr(a->action, "LATEXT(") != NULL) LTinTokenAction = 1; /* MR23 */ } if ( FoundGuessBlk ) { if ( GenCC ) {gen("if ( !guessing ) {\n");} else gen("zzNON_GUESS_MODE {\n"); } dumpActionPlus(a, a->action, output, tabs, a->file, a->line, 1); /* MR21 */ if ( FoundGuessBlk ) gen("}\n"); a->done = 1; /* MR30 */ } /*** a->done = 1; MR30 Moved up into then branch for true actions, but not predicates ***/ if ( !DemandLookahead ) { if ( GenCC ) { if ( FoundException && p->use_def_MT_handler ) gen("if (!_signal)"); _gen(" consume();") if ( FoundException && p->use_def_MT_handler ) _gen(" _signal=NoSignal;"); _gen("\n"); } else { if ( FoundException && p->use_def_MT_handler ) _gen("if (!_signal)"); _gen(" zzCONSUME;\n"); if ( FoundException && p->use_def_MT_handler ) _gen(" _signal=NoSignal;"); _gen("\n"); } } else gen("\n"); if (a->done) { /* MR30 */ TRANS( a->next ); /* MR30 */ } /* MR30 */ else { /* MR30 */ TRANS( p->next ); /* MR30 */ } /* MR30 */ } else { if ( !DemandLookahead ) { if ( GenCC ) { if (FoundException && p->use_def_MT_handler) _gen("if (!_signal)"); _gen(" consume();") if (FoundException&&p->use_def_MT_handler) _gen(" _signal=NoSignal;"); _gen("\n"); } else { if (FoundException && p->use_def_MT_handler) _gen("if (!_signal)"); _gen(" zzCONSUME;"); if ( FoundException && p->use_def_MT_handler ) _gen(" _signal=NoSignal;"); _gen("\n"); } } else _gen("\n"); TRANS(p->next); } } /* MR21 * * There was a bug in the code generation for {...} which causes it * to omit the optional tokens from the error messages. The easiest * way to fix this was to make the opt block look like a sub block: * * { a | b | c } * * becomes (internally): * * ( a | b | c | ) * * The code for genOptBlk is now identical to genSubBlk except for * cosmetic changes. */ void #ifdef __USE_PROTOS genOptBlk( Junction *q ) #else genOptBlk( q ) Junction *q; #endif { int max_k; set f; int need_right_curly; set savetkref; int lastAltEmpty; /* MR23 */ savetkref = tokensRefdInBlock; require(q->ntype == nJunction, "genOptBlk: not junction"); require(q->jtype == aOptBlk, "genOptBlk: not opt block"); OutLineInfo(output,q->line,FileStr[q->file]); BLOCK_Preamble(q); BlkLevel++; BlockPreambleOption(q,q->pFirstSetSymbol); /* MR21 */ f = genBlk(q, aOptBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */); /* MR23 Bypass error clause generation when exceptions are used in {...} block See multi-line note in genBlk near call to isEmptyAlt. */ if (! FoundException) { if ( q->p2 != NULL ) {tab(); makeErrorClause(q,f,max_k,0 /* use plus block bypass ? */ );} } else { gen("/* MR23 skip error clause for {...} when exceptions in use */\n"); } { int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} } freeBlkFsets(q); --BlkLevel; BLOCK_Tail(); if ( q->guess ) { gen("zzGUESS_DONE\n"); } /* must duplicate if (alpha)?; one guesses (validates), the * second pass matches */ if ( q->guess && analysis_point(q)==q ) { OutLineInfo(output,q->line,FileStr[q->file]); BLOCK_Preamble(q); BlkLevel++; f = genBlk(q, aSubBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */); if ( q->p2 != NULL ) {tab(); makeErrorClause(q,f,max_k,0 /* use plus block bypass ? */ );} { int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} } freeBlkFsets(q); --BlkLevel; BLOCK_Tail(); } tokensRefdInBlock = savetkref; if (q->end->p1 != NULL) TRANS(q->end->p1); } /* * Generate code for a loop blk of form: * * |---| * v | * --o-G-o-->o-- */ void #ifdef __USE_PROTOS genLoopBlk( Junction *begin, Junction *q, Junction *start, int max_k ) #else genLoopBlk( begin, q, start, max_k ) Junction *begin; Junction *q; Junction *start; /* where to start generating code from */ int max_k; #endif { set f; int need_right_curly; set savetkref; Junction *guessBlock; /* MR10 */ int singleAlt; /* MR10 */ int lastAltEmpty; /* MR23 */ savetkref = tokensRefdInBlock; require(q->ntype == nJunction, "genLoopBlk: not junction"); require(q->jtype == aLoopBlk, "genLoopBlk: not loop block"); if ( q->visited ) return; q->visited = TRUE; /* first_item_is_guess_block doesn't care what kind of node it is */ guessBlock=first_item_is_guess_block( (Junction *) q->p1); /* MR10 */ singleAlt=q->p2==NULL; /* MR10 */ if (singleAlt && !guessBlock) /* MR10 */ /* only one alternative? */ { if ( DemandLookahead ) { if ( !GenCC ) {gen1("LOOK(%d);\n", max_k);} else gen1("look(%d);\n", max_k); } gen("while ( "); if ( begin!=NULL ) genExpr(begin); else genExpr(q); /* if no predicates have been hoisted for this single alt (..)* * do so now */ require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty"); if ( ParseWithPredicates && begin->predicate==NULL ) { Predicate *a = MR_find_predicates_and_supp((Node *)q->p1); require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty"); if ( a!=NULL ) { _gen("&&"); a=genPredTreeMain(a, (Node *)q); /* MR10 */ } /* MR10 */ if (MRhoisting) { /* MR10 */ predicate_free(a); /* MR10 */ }; } _gen(" ) {\n"); tabs++; TRANS(q->p1); if ( !GenCC ) gen1("zzLOOP(zztasp%d);\n", BlkLevel-1); if ( DemandLookahead ) { if ( !GenCC ) {gen1("LOOK(%d);\n", max_k);} else gen1("look(%d);\n", max_k); } --tabs; gen("}\n"); freeBlkFsets(q); q->visited = FALSE; tokensRefdInBlock = savetkref; return; } gen("for (;;) {\n"); /* MR20 G. Hobbelt */ tabs++; /* MR6 */ /* MR6 "begin" can never be null when called from genLoopBegin */ /* MR6 because q==(Junction *)begin->p1 and we know q is valid */ /* MR6 */ /* MR6 from genLoopBegin: */ /* MR6 */ /* MR6 if ( LL_k>1 && !set_nil(q->fset[2]) ) */ /* MR6 genLoopBlk( q, (Junction *)q->p1, q, max_k ); */ /* MR6 else genLoopBlk( q, (Junction *)q->p1, NULL, max_k ); */ /* MR6 */ if ( begin!=NULL ) { if ( DemandLookahead ) { if ( !GenCC ) {gen1("LOOK(%d);\n", max_k);} else gen1("look(%d);\n", max_k); } /* The bypass arc of the (...)* predicts what to do when you fail, but * ONLY after having tested the loop start expression. To avoid this, * we simply break out of the (...)* loop when we find something that * is not in the prediction of the loop (all alts thereof). */ gen("if ( !("); /*** TJP says: It used to use the prediction expression for the bypass arc of the (...)*. HOWEVER, if a non LL^1(k) decision was found, this thing would miss the ftree stored in the aLoopBegin node and generate an LL^1(k) decision anyway. *** genExpr((Junction *)begin->p2); ***/ genExpr((Junction *)begin); _gen(")) break;\n"); } /* generate code for terminating loop (this is optional branch) */ f = genBlk(q, aLoopBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */); set_free(f); freeBlkFsets(q); /* generate code for terminating loop (this is optional branch) */ /* MR6 */ /* MR6 30-May-97 Bug reported by Manuel Ornato */ /* MR6 A definite bug involving the exit from a loop block */ /* MR6 In 1.23 and later versions (including 1.33) Instead */ /* MR6 exiting the block and reporting a syntax error the */ /* MR6 code loops forever. */ /* MR6 Looking at 1.20 which generates proper code it is not */ /* MR6 clear which of two changes should be undone. */ /* MR6 This is my best guess. */ /* MR6 From earlier MR6 note we know that begin can never be */ /* MR6 null when genLoopBlk called from genLoopBegin */ /* MR6 */ /* MR6 */ if ( begin==NULL) { /* MR6 */ /* code for exiting loop "for sure" */ /* MR6 */ gen("/* Suppressed by MR6 */ /*** else break; ***/\n"); /* MR6 */ }; /* MR10 */if (singleAlt && guessBlock) { /* MR10 */ tabs--; /* MR6 */ gen("} else break; /* MR6 code for exiting loop \"for sure\" */\n"); /* MR10 */ need_right_curly--; /* MR10 */ } else { /* MR6 */ gen("else break; /* MR6 code for exiting loop \"for sure\" */\n"); /* MR10 */ }; { int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} } if ( !GenCC ) gen1("zzLOOP(zztasp%d);\n", BlkLevel-1); --tabs; gen("}\n"); q->visited = FALSE; tokensRefdInBlock = savetkref; } /* * Generate code for a loop blk of form: * * |---| * v | * --o-->o-->o-G-o-->o-- * | ^ * v | * o-----------o * * q->end points to the last node (far right) in the blk. * * Note that q->end->jtype must be 'EndBlk'. * * Generate code roughly of the following form: * * do { * ... code for alternatives ... * } while ( First Set of aLoopBlk ); * * OR if > 1 alternative * * do { * ... code for alternatives ... * else break; * } while ( 1 ); */ void #ifdef __USE_PROTOS genLoopBegin( Junction *q ) #else genLoopBegin( q ) Junction *q; #endif { set f; int i; int max_k; set savetkref; savetkref = tokensRefdInBlock; require(q!=NULL, "genLoopBegin: invalid node and/or rule"); require(q->ntype == nJunction, "genLoopBegin: not junction"); require(q->jtype == aLoopBegin, "genLoopBegin: not loop block"); require(q->p2!=NULL, "genLoopBegin: invalid Loop Graph"); OutLineInfo(output,q->line,FileStr[q->file]); BLOCK_Preamble(q); BlkLevel++; BlockPreambleOption(q,q->pFirstSetSymbol); /* MR21 */ f = First(q, 1, aLoopBegin, &max_k); /* If not simple LL(1), must specify to start at LoopBegin, not LoopBlk */ if ( LL_k>1 && !set_nil(q->fset[2]) ) genLoopBlk( q, (Junction *)q->p1, q, max_k ); else genLoopBlk( q, (Junction *)q->p1, NULL, max_k ); for (i=1; i<=CLL_k; i++) set_free(q->fset[i]); for (i=1; i<=CLL_k; i++) set_free(((Junction *)q->p2)->fset[i]); --BlkLevel; BLOCK_Tail(); set_free(f); tokensRefdInBlock = savetkref; /* MR21 */ if (MR_BlkErr) { /* MR21 */ set f, fArray[2]; /* MR21 */ f = ComputeErrorSet(q,1,0 /* use plus block bypass ? */ ); /* MR21 */ fArray[0]= empty; /* MR21 */ fArray[1]= set_dup(f); /* MR21 */ gen("if ("); /* MR21 */ genExprSets(fArray,1); /* note: destroys set arguments */ /* MR21 */ _gen(") { /* MR21 option -mrblksynerr */\n"); /* MR21 */ tabs++; /* MR21 */ tab(); /* MR21 */ _gen("/* nothing */ }\n"); /* MR21 */ tab(); /* MR21 */ makeErrorClause(q,f,1,0 /* use plus block bypass ? */ ); /* frees set */ /* MR21 */ tabs--; /* MR21 */ }; if (q->end->p1 != NULL) TRANS(q->end->p1); } /* * Generate code for a loop blk of form: * * |---| * v | * --o-G-o-->o-- * * q->end points to the last node (far right) in the blk. * Note that q->end->jtype must be 'EndBlk'. * * Generate code roughly of the following form: * * do { * ... code for alternatives ... * } while ( First Set of aPlusBlk ); * * OR if > 1 alternative * * do { * ... code for alternatives ... * else if not 1st time through, break; * } while ( 1 ); */ void #ifdef __USE_PROTOS genPlusBlk( Junction *q ) #else genPlusBlk( q ) Junction *q; #endif { int max_k; set f; int need_right_curly; int lastAltEmpty; /* MR23 */ set savetkref; Junction *guessBlock; /* MR10 */ int singleAlt; /* MR10 */ savetkref = tokensRefdInBlock; require(q!=NULL, "genPlusBlk: invalid node and/or rule"); require(q->ntype == nJunction, "genPlusBlk: not junction"); require(q->jtype == aPlusBlk, "genPlusBlk: not Plus block"); require(q->p2 != NULL, "genPlusBlk: not a valid Plus block"); if ( q->visited ) return; q->visited = TRUE; OutLineInfo(output,q->line,FileStr[q->file]); BLOCK_Preamble(q); BlkLevel++; BlockPreambleOption((Junction *)q, q->pFirstSetSymbol); /* MR21 */ /* first_item_is_guess_block doesn't care what kind of node it is */ guessBlock=first_item_is_guess_block( (Junction *)q->p1); /* MR10 */ /* if the ignore flag is set on the 2nd alt and that alt is empty, * then it is the implied optional alternative that we added for (...)+ * and, hence, only 1 alt. */ /* MR10 Reported by Pulkkinen Esa (esap@cs.tut.fi) * Outer code for guess blocks ignored when there is only one alt * for a (...)+ block. * Force use of regular code rather than "optimized" code for that case */ singleAlt=( ( (Junction *) q->p2)->p2 == NULL) && ( ( (Junction *) q->p2)->ignore ); /* only one alternative? */ if (singleAlt && !guessBlock) /* MR10 */ { Predicate *a=NULL; /* if the only alt has a semantic predicate, hoist it; must test before * entering loop. */ if ( ParseWithPredicates ) { require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty"); a = MR_find_predicates_and_supp((Node *)q); require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty"); if ( a!=NULL ) { gen("if ("); a=genPredTreeMain(a, (Node *)q); /* MR10 */ _gen(") {\n"); } } gen("do {\n"); tabs++; TRANS(q->p1); if ( !GenCC ) gen1("zzLOOP(zztasp%d);\n", BlkLevel-1); f = First(q, 1, aPlusBlk, &max_k); if ( DemandLookahead ) { if ( !GenCC ) {gen1("LOOK(%d);\n", max_k);} else gen1("look(%d);\n", max_k); } --tabs; gen("} while ( "); if ( q->parm!=NULL && q->predparm ) _gen1("(%s) && ", q->parm); genExpr(q); if ( ParseWithPredicates && a!=NULL ) { if (! MR_comparePredicates(q->predicate,a)) { _gen("&&"); a=genPredTreeMain(a, (Node *)q); /* MR10 */ }; } _gen(" );\n"); if ( ParseWithPredicates && a!=NULL ) gen("}\n"); --BlkLevel; BLOCK_Tail(); q->visited = FALSE; freeBlkFsets(q); set_free(f); tokensRefdInBlock = savetkref; /* MR21 */ if (MR_BlkErr) { /* MR21 */ set f, fArray[2]; /* MR21 */ f = ComputeErrorSet(q,1,1 /* use plus block bypass ? */ ); /* MR21 */ fArray[0]= empty; /* MR21 */ fArray[1]= set_dup(f); /* MR21 */ gen("if ("); /* MR21 */ genExprSets(fArray,1); /* note: destroys set arguments */ /* MR21 */ _gen(") { /* MR21 option -mrblksynerr */\n"); /* MR21 */ tabs++; /* MR21 */ tab(); /* MR21 */ _gen("/* nothing */ }\n"); /* MR21 */ tab(); /* MR21 */ makeErrorClause(q,f,1,1 /* use plus block bypass ? */ ); /* frees set */ /* MR21 */ tabs--; /* MR21 */ }; if (q->end->p1 != NULL) TRANS(q->end->p1); /* MR10 */ if (MRhoisting) { /* MR10 */ predicate_free(a); /* MR10 */ }; return; } gen("do {\n"); tabs++; f = genBlk(q, aPlusBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */); /* MR6 */ /* MR6 Sinan Karasu (sinan@tardis.ds.boeing.com) */ /* MR6 Failed to turn off guess mode when leaving block */ /* MR6 */ /* MR6 */ if ( has_guess_block_as_last_item(q) ) { /* MR10 */ gen("/* MR10 ()+ */ else {\n"); /* MR10 */ tabs++; /* MR10 */ need_right_curly++; /* MR10 */ gen("/* MR10 ()+ */ if ( !zzrv ) zzGUESS_DONE;\n"); /* MR6 */ gen("/* MR10 ()+ */ if ( zzcnt > 1 ) break;\n"); /* MR10 */ } else { /* MR10 */ gen("/* MR10 ()+ */ else {\n"); /* MR10 */ tabs++; /* MR10 */ need_right_curly++; /* MR10 */ gen("if ( zzcnt > 1 ) break;\n"); /* MR10 */ }; /* MR21 */ if (MR_BlkErr && 1 >= max_k) { /* MR21 */ set f; /* MR21 */ f = ComputeErrorSet(q,1,0 /* use plus block bypass ? */ ); /* MR21 */ tabs++; /* MR21 */ tab(); /* MR21 */ makeErrorClause(q,f,1,0 /* use plus block bypass ? */ ); /* frees set */ /* MR21 */ tabs--; /* MR21 */ } /* MR21 */ else { tab(); makeErrorClause(q,f,max_k,1 /* use plus block bypass ? */); /* MR21 I think this generates the wrong set ? */ /* MR21 because it includes the plus block bypass ? */ /* MR21 but I'm afraid to change it without additional checking */ } { int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} } freeBlkFsets(q); gen("zzcnt++;"); if ( !GenCC ) _gen1(" zzLOOP(zztasp%d);", BlkLevel-1); _gen("\n"); if ( DemandLookahead ) { if ( !GenCC ) {gen1("LOOK(%d);\n", max_k);} else gen1("look(%d);\n", max_k); } --tabs; if ( q->parm!=NULL && q->predparm ) {gen1("} while (%s);\n", q->parm);} else gen("} while ( 1 );\n"); --BlkLevel; BLOCK_Tail(); q->visited = FALSE; tokensRefdInBlock = savetkref; /* MR21 */ if (MR_BlkErr) { /* MR21 */ set f, fArray[2]; /* MR21 */ f = ComputeErrorSet(q,1,1 /* use plus block bypass ? */ ); /* MR21 */ fArray[0]= empty; /* MR21 */ fArray[1]= set_dup(f); /* MR21 */ gen("if ("); /* MR21 */ genExprSets(fArray,1); /* note: destroys set arguments */ /* MR21 */ _gen(") { /* MR21 option -mrblksynerr */\n"); /* MR21 */ tabs++; /* MR21 */ tab(); /* MR21 */ _gen("/* nothing */ }\n"); /* MR21 */ tab(); /* MR21 */ makeErrorClause(q,f,1,1 /* use plus block bypass ? */ ); /* frees set */ /* MR21 */ tabs--; /* MR21 */ }; if (q->end->p1 != NULL) TRANS(q->end->p1); } /* * Generate code for a sub blk of alternatives of form: * * --o-G1--o-- * | ^ * v /| * o-G2-o| * | ^ * v | * .......... * | ^ * v / * o-Gn-o * * q points to the 1st junction of blk (upper-left). * q->end points to the last node (far right) in the blk. * Note that q->end->jtype must be 'EndBlk'. * The last node in every alt points to q->end. * * Generate code of the following form: * if ( First(G1) ) { * ...code for G1... * } * else if ( First(G2) ) { * ...code for G2... * } * ... * else { * ...code for Gn... * } */ void #ifdef __USE_PROTOS genSubBlk( Junction *q ) #else genSubBlk( q ) Junction *q; #endif { int max_k; set f; int need_right_curly; int lastAltEmpty; /* MR23 */ set savetkref; savetkref = tokensRefdInBlock; require(q->ntype == nJunction, "genSubBlk: not junction"); require(q->jtype == aSubBlk, "genSubBlk: not subblock"); OutLineInfo(output,q->line,FileStr[q->file]); BLOCK_Preamble(q); BlkLevel++; BlockPreambleOption(q,q->pFirstSetSymbol); /* MR21 */ f = genBlk(q, aSubBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */); /* MR23 Bypass error clause generation when exceptions are used in a sub block in which the last alternative is epsilon. Example: "(A | B | )". See multi-line note in genBlk near call to isEmptyAlt. */ if (FoundException && lastAltEmpty) { gen("/* MR23 skip error clause for (...| epsilon) when exceptions in use */\n"); } else { if ( q->p2 != NULL ) {tab(); makeErrorClause(q,f,max_k,0 /* use plus block bypass ? */ );} } { int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} } freeBlkFsets(q); --BlkLevel; BLOCK_Tail(); if ( q->guess ) { gen("zzGUESS_DONE\n"); } /* must duplicate if (alpha)?; one guesses (validates), the * second pass matches */ if ( q->guess && analysis_point(q)==q ) { OutLineInfo(output,q->line,FileStr[q->file]); BLOCK_Preamble(q); BlkLevel++; f = genBlk(q, aSubBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */); if ( q->p2 != NULL ) {tab(); makeErrorClause(q,f,max_k,0 /* use plus block bypass ? */);} { int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} } freeBlkFsets(q); --BlkLevel; BLOCK_Tail(); } tokensRefdInBlock = savetkref; if (q->end->p1 != NULL) TRANS(q->end->p1); } static int TnodesAllocatedPrevRule=0; /* * Generate code for a rule. * * rule--> o-->o-Alternatives-o-->o * Or, * rule--> o-->o-Alternative-o-->o * * The 1st junction is a RuleBlk. The second can be a SubBlk or just a junction * (one alternative--no block), the last is EndRule. * The second to last is EndBlk if more than one alternative exists in the rule. * * To get to the init-action for a rule, we must bypass the RuleBlk, * and possible SubBlk. * Mark any init-action as generated so genBlk() does not regenerate it. */ void #ifdef __USE_PROTOS genRule( Junction *q ) #else genRule( q ) Junction *q; #endif { const char * returnValueInitializer; do { /* MR10 Change recursion into iteration */ int max_k; set follow, rk, f; ActionNode *a; RuleEntry *r; int lastAltEmpty; /* MR23 */ static int file = -1; int need_right_curly; require(q->ntype == nJunction, "genRule: not junction"); require(q->jtype == RuleBlk, "genRule: not rule"); /* MR14 */ require (MR_BackTraceStack.count == 0,"-alpha MR_BackTraceStack.count != 0"); /* MR14 */ MR_pointerStackReset(&MR_BackTraceStack); /* MR14 */ if (AlphaBetaTrace) MR_MaintainBackTrace=1; CurRule=q->rname; /* MR11 */ r = (RuleEntry *) hash_get(Rname, q->rname); if ( r == NULL ) warnNoFL("Rule hash table is screwed up beyond belief"); if ( q->file != file ) /* open new output file if need to */ { /* MR6 */ /* MR6 Simpler to debug when output goes to stdout rather than a file */ /* MR6 */ /* MR6 */ if (UseStdout) { /* MR6 */ output = stdout; /* MR6 */ } else { /* MR6 */ if ( output != NULL) fclose( output ); /* MR6 */ output = fopen(OutMetaName(outname(FileStr[q->file])), "w"); /* MR6 */ }; require(output != NULL, "genRule: can't open output file"); #ifdef SPECIAL_FOPEN special_fopen_actions(OutMetaName(outname(FileStr[q->file]))); /* MR1 */ #endif if ( file == -1 ) genHdr1(q->file); else genHdr(q->file); file = q->file; } if (InfoM) { fprintf(stderr," rule %s\n",q->rname); fflush(output); }; #if 0 if (strcmp(q->rname,"***debug***") == 0) { fprintf(stderr,"***debug*** %s reached\n",q->rname); MR_break(); }; #endif DumpFuncHeader(q,r); tabs++; /* MR23 If there is a single return value then it can be initialized in the declaration using assignment syntax. If there are multiple return values then antlr creates a struct and initialization takes place element by element for each element of the struct. For multiple elements the initialization is by assignment so we have to wait until all declarations are done before emitting that code - because of restrictions in C which don't exist in C++. In the past (before MR23) the only kind of initialization was the PURIFY macro which was just a memset() of 0. Now we allow the user to specify an initial value. PURIFY is still used in C mode because C does not have constructors. However, PURIFY is not used in C++ mode because it might overwrite information created by elements which have their own ctor. */ if ( q->ret!=NULL ) { if ( hasMultipleOperands(q->ret) ) /* MR23 */ { /* Emit initialization code later. */ gen1("struct _rv%d _retv;\n",r->rulenum); } else { /* Emit initialization code now. */ tab(); DumpType(q->ret, output); returnValueInitializer = getInitializer(q->ret); if (returnValueInitializer == NULL) { /* MR23 */ gen(" _retv;\n"); /* MR1 MR3 */ } /* MR23 */ else { /* MR23 */ gen1(" _retv = %s;\n", returnValueInitializer); /* MR23 */ } /* MR23 */ } } OutLineInfo(output,q->line,FileStr[q->file]); if (InfoM) { fflush(output); }; gen("zzRULE;\n"); if ( FoundException ) { gen("int _sva=1;\n"); } if ( GenCC && GenAST ) gen("ASTBase *_ast = NULL, *_sibling = NULL, *_tail = NULL;\n"); if ( GenCC ) genTokenPointers(q); if ( GenCC&&GenAST ) genASTPointers(q); if ( q->el_labels!=NULL ) genElementLabels(q->el_labels); if ( FoundException ) gen("int _signal=NoSignal;\n"); if ( !GenCC ) gen1("zzBLOCK(zztasp%d);\n", BlkLevel); /* MR10 */ /* move zzTRACEIN to before init action */ /* MR10 */ if ( TraceGen ) { /* MR10 */ if ( GenCC ) {gen1("zzTRACEIN(\"%s\");\n", q->rname);} /* MR10 */ else gen1("zzTRACEIN((ANTLRChar *)\"%s\");\n", q->rname); /* MR10 */ } /* MR7 Moved PURIFY() to after all local variables have been declared */ /* MR7 so that the generated code is valid C as well as C++ */ /* MR7 Jan Mikkelsen 10-June-1997 */ /* MR23 Do the PURIFY macro only for C mode. C++ users should use constructors or initialization expressions. */ if ( q->ret != NULL ) /* MR7 */ { /* MR7 */ if (hasMultipleOperands(q->ret)) { /* MR23 */ if (PURIFY == TRUE) { gen1("PCCTS_PURIFY(_retv,sizeof(struct _rv%d))\n",r->rulenum); /* MR23 */ } } /* MR7 */ else { /* MR7 */ /* MR23 If there were only one return value operand and it had an initializer then it would have been initiailized in the declaration. */ returnValueInitializer = getInitializer(q->ret); /* MR23 */ if (returnValueInitializer == NULL) { /* MR23 */ if (PURIFY == TRUE) { gen("PCCTS_PURIFY(_retv,sizeof("); /* MR23 */ DumpType(q->ret, output); /* MR7 */ gen("))\n"); /* MR7 */ } } /* MR23 */ } /* MR7 */ if (hasMultipleOperands(q->ret)) { /* MR23 */ DumpInitializers(output, r, q->ret); /* MR23 */ } } if ( !GenCC ) gen("zzMake0;\n"); if ( FoundException ) gen("*_retsignal = NoSignal;\n"); if ( !GenCC ) gen("{\n"); if ( has_guess_block_as_first_item((Junction *)q->p1) ) { gen("zzGUESS_BLOCK\n"); } /* L o o k F o r I n i t A c t i o n */ if ( ((Junction *)q->p1)->jtype == aSubBlk ) a = findImmedAction( ((Junction *)q->p1)->p1 ); else a = findImmedAction( q->p1 ); /* only one alternative in rule */ if ( a!=NULL && !a->is_predicate) { /* MR21 */ if (!a->noHoist) dumpActionPlus(a, a->action, output, tabs, a->file, a->line, 1); a->done = 1; /* ignore action. We have already handled it */ } BlkLevel++; q->visited = TRUE; /* mark RULE as visited for FIRST/FOLLOW */ BlockPreambleOption((Junction *)q->p1, NULL); /* MR21 */ f = genBlk((Junction *)q->p1, RuleBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */); if ( q->p1 != NULL ) if ( ((Junction *)q->p1)->p2 != NULL ) {tab(); makeErrorClause((Junction *)q->p1,f,max_k,0 /* use plus block bypass ? */);} { int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} } freeBlkFsets((Junction *)q->p1); q->visited = FALSE; --BlkLevel; if ( !GenCC ) gen1("zzEXIT(zztasp%d);\n", BlkLevel); genTraceOut(q); if ( q->ret!=NULL ) gen("return _retv;\n") else gen("return;\n"); /* E r r o r R e c o v e r y */ NewSet(); rk = empty; /* MR14 */ if (r->dontComputeErrorSet) { /* MR14 */ follow=empty; } else { MR_pointerStackReset(&MR_BackTraceStack); /* MR14 */ MR_ErrorSetComputationActive=1; REACH(q->end, 1, &rk, follow); MR_ErrorSetComputationActive=0; require (MR_BackTraceStack.count == 0,"K: MR_BackTraceStack.count != 0"); } FillSet( follow ); set_free( follow ); /* MR20 G. Hobbelt Isn't it so that "fail:" is ONLY referenced when: !FoundException || FoundGuessBlk ? Therefore add the "if" around this piece of code generation... Should guessing mode also use _handler label instead of "fail" when exception handling is active? gen can automatically put "if (guessing)" there so as to skip all kinds of user code. */ if ( !FoundException || FoundGuessBlk ) /* MR20 G. Hobbelt */ { /* MR20 G. Hobbelt */ _gen("fail:\n"); if ( !GenCC ) gen("zzEXIT(zztasp1);\n"); if ( FoundGuessBlk ) { if ( !GenCC ) {gen("if ( zzguessing ) zzGUESS_FAIL;\n");} else gen("if ( guessing ) zzGUESS_FAIL;\n"); } if ( q->erraction!=NULL ) dumpAction(q->erraction, output, tabs, q->file, q->line, 1); if ( GenCC ) { gen1("syn(zzBadTok, %s, zzMissSet, zzMissTok, zzErrk);\n", r->egroup==NULL?"(ANTLRChar *)\"\"":r->egroup); } else { gen1("zzsyn(zzMissText, zzBadTok, %s, zzMissSet, zzMissTok, zzErrk, zzBadText);\n", r->egroup==NULL?"(ANTLRChar *)\"\"":r->egroup); } gen3("%sresynch(setwd%d, 0x%x);\n", GenCC?"":"zz", wordnum, 1<ret!=NULL ) { genTraceOut(q); gen("return _retv;\n"); } else if ( q->exceptions!=NULL ) { genTraceOut(q); gen("return;\n"); } else if (!FoundException) { /* MR10 */ genTraceOut(q); /* MR10 */ }; } /* MR20 G. Hobbelt */ if ( !GenCC ) gen("}\n"); /* Gen code for exception handlers */ /* make sure each path out contains genTraceOut() */ if ( q->exceptions!=NULL ) { gen("/* exception handlers */\n"); dumpExceptions(q->exceptions); if ( !r->has_rule_exception ) { _gen("_handler:\n"); gen("zzdflthandlers(_signal,_retsignal);\n"); } /* MR20 G. Gobbelt The label "adios" is never referenced */ #if 0 _gen("_adios:\n"); #endif if ( q->ret!=NULL ) { genTraceOut(q); gen("return _retv;\n"); } else { genTraceOut(q); gen("return;\n"); } } else if ( FoundException ) { _gen("_handler:\n"); gen("zzdflthandlers(_signal,_retsignal);\n"); /* MR1 */ /* MR1 7-Apr-97 Fix suggested by: John Bair (jbair@iftime.com) */ /* MR1 */ if ( q->ret != NULL) { /* MR1 */ genTraceOut(q); /* MR10 */ gen("return _retv;\n"); /* MR1 */ } else { /* MR1 */ genTraceOut(q); /* MR10 */ gen("return;\n") ; /* MR1 */ }; /* MR1 */ } tabs--; gen("}\n"); /* MR10 Tired of looking at stacks that are as deep as the number of */ /* MR10 rules. Changes recursion to iteration. */ MR_releaseResourcesUsedInRule( (Node *) q ); /* MR10 */ if (InfoT) { fprintf(output,"\n/* tnodes created for rule %s: %d */\n", q->rname, (TnodesAllocated-TnodesAllocatedPrevRule) ); }; TnodesAllocatedPrevRule=TnodesAllocated; if (q->p2 == NULL) dumpAfterActions( output ); q=(Junction *)q->p2; require(q==NULL || q->jtype==RuleBlk,"RuleBlk p2 does not point to another RuleBlk"); } while (q != NULL); /**** The old code ****/ /**** if ( q->p2 != NULL ) {TRANS(q->p2);} ****/ /* generate code for next rule too */ /**** else dumpAfterActions( output ); ****/ } /* This is for the function definition, not the declaration. */ static void #ifdef __USE_PROTOS DumpFuncHeader( Junction *q, RuleEntry *r ) #else DumpFuncHeader( q, r ) Junction *q; RuleEntry *r; #endif { /* */ /* MR1 10-Apr-97 MR1 Simplify insertion of commas in function header */ /* */ int needComma; /* MR1 */ /* A N S I */ _gen("\n"); if ( q->ret!=NULL ) { if ( hasMultipleOperands(q->ret) ) /* MR23 */ { if (GenCC) gen2("%s::_rv%d\n", CurrentClassName, r->rulenum) else gen1("struct _rv%d\n",r->rulenum); } else { DumpType(q->ret, output); gen("\n"); } } else { _gen("void\n"); } /* MR1 */ /* MR1 10-Apr-97 133MR1 Replace __STDC__ with __USE_PROTOS */ /* MR1 */ if ( !GenCC ) _gen("#ifdef __USE_PROTOS\n"); /* MR1 */ if ( !GenCC ) gen2("%s%s(", RulePrefix, q->rname) else gen3("%s::%s%s(", CurrentClassName, RulePrefix,q->rname); /* If we generate C++ method names, we must hide default arguments */ /* which can appear in the parameter declaration list. */ /* NOTICE: this is done only here, for the method definition, but */ /* not for the method declaration inside the class */ /* definition. This is exactly the behaviour defined in */ /* C++ standard for default paramters. */ DumpANSIFunctionArgDef(output,q, 0 /* emit initializers ? */); _gen("\n"); if ( GenCC ) { gen("{\n"); return; } /* K & R */ gen("#else\n"); gen2("%s%s(", RulePrefix, q->rname); needComma=0; /* MR1 */ if ( GenAST ) /* MR1 */ { /* MR1 */ _gen("_root"); /* MR1 */ needComma=1; /* MR1 */ } /* MR1 */ if ( FoundException ) /* MR1 */ { /* MR1 */ if (needComma) {_gen(",");needComma=0;}; /* MR1 */ _gen("_retsignal"); /* MR1 */ needComma=1; /* MR1 */ } /* MR1 */ /* MR5 Change below by Jan Mikkelsen (janm@zeta.org.au) 26-May-97 MR5 */ DumpListOfParmNames( q->pdecl, output, needComma ); /* MR5 */ gen(")\n"); if ( GenAST ) gen("AST **_root;\n"); if ( FoundException ) gen("int *_retsignal;\n"); DumpOldStyleParms( q->pdecl, output ); gen("#endif\n"); gen("{\n"); } void #ifdef __USE_PROTOS DumpANSIFunctionArgDef(FILE *f, Junction *q, int bInitializer) #else DumpANSIFunctionArgDef(f,q,bInitializer) FILE *f; Junction *q; int bInitializer; #endif { if ( GenAST ) { if ( GenCC ) {fprintf(f,"ASTBase **_root");} else fprintf(f,"AST**_root"); if ( !FoundException && q->pdecl!=NULL ) fprintf(f,","); } if ( FoundException ) { if ( GenAST ) fprintf(f,","); fprintf(f,"int *_retsignal"); if ( q->pdecl!=NULL ) { fprintf(f,","); } } if ( q->pdecl!=NULL ) { DumpFormals(f, q->pdecl, bInitializer); /* MR23 */ } else { if ( !GenAST && !FoundException ) { fprintf(f,"void"); } } fprintf(f,")"); } void #ifdef __USE_PROTOS genJunction( Junction *q ) #else genJunction( q ) Junction *q; #endif { require(q->ntype == nJunction, "genJunction: not junction"); require(q->jtype == Generic, "genJunction: not generic junction"); if ( q->p1 != NULL ) TRANS(q->p1); if ( q->p2 != NULL ) TRANS(q->p2); } void #ifdef __USE_PROTOS genEndBlk( Junction *q ) #else genEndBlk( q ) Junction *q; #endif { } void #ifdef __USE_PROTOS genEndRule( Junction *q ) #else genEndRule( q ) Junction *q; #endif { } void #ifdef __USE_PROTOS genHdr( int file ) #else genHdr( file ) int file; #endif { int i; _gen("/*\n"); _gen(" * A n t l r T r a n s l a t i o n H e a d e r\n"); _gen(" *\n"); _gen(" * Terence Parr, Will Cohen, and Hank Dietz: 1989-2001\n"); _gen(" * Purdue University Electrical Engineering\n"); _gen(" * With AHPCRC, University of Minnesota\n"); _gen1(" * ANTLR Version %s\n", Version); _gen(" *\n"); /* MR10 */ _gen(" * "); /* MR10 */ for (i=0 ; i < Save_argc ; i++) { /* MR10 */ _gen(" "); /* MR10 */ _gen1("%s",Save_argv[i]); /* MR10 */ }; _gen("\n"); _gen(" *\n"); _gen(" */\n\n"); if (FirstAction != NULL ) dumpAction( FirstAction, output, 0, -1, 0, 1); /* MR11 MR15b */ _gen1("#define ANTLR_VERSION %s\n", VersionDef); _gen("#include \"pcctscfg.h\"\n"); _gen("#include \"pccts_stdio.h\"\n"); if ( strcmp(ParserName, DefaultParserName)!=0 ) _gen2("#define %s %s\n", DefaultParserName, ParserName); if ( strcmp(ParserName, DefaultParserName)!=0 ) {_gen1("#include \"%s\"\n", RemapFileName);} OutLineInfo(output,1,FileStr[file]); if ( GenCC ) { if ( UserTokenDefsFile != NULL ) fprintf(output, "#include %s\n", UserTokenDefsFile); else fprintf(output, "#include \"%s\"\n", DefFileName); } if ( HdrAction != NULL ) dumpAction( HdrAction, output, 0, -1, 0, 1); if ( !GenCC && FoundGuessBlk ) { _gen("#define ZZCAN_GUESS\n"); _gen("#include \"pccts_setjmp.h\"\n"); /* MR15 K.J. Cummings (cummings@peritus.com) */ } if ( FoundException ) { _gen("#define EXCEPTION_HANDLING\n"); _gen1("#define NUM_SIGNALS %d\n", NumSignals); } if ( !GenCC && OutputLL_k > 1 ) _gen1("#define LL_K %d\n", OutputLL_k); if ( GenAST&&!GenCC ) _gen("#define GENAST\n\n"); if ( GenAST ) { if ( GenCC ) {_gen1("#include \"%s\"\n\n", ASTBASE_H);} else _gen("#include \"ast.h\"\n\n"); } if ( !GenCC && DemandLookahead ) _gen("#define DEMAND_LOOK\n\n"); #ifdef DUM if ( !GenCC && LexGen ) { _gen1("#define zzEOF_TOKEN %d\n", (TokenInd!=NULL?TokenInd[EofToken]:EofToken)); } #endif /* ###WARNING: This will have to change when SetWordSize changes */ if ( !GenCC ) _gen1("#define zzSET_SIZE %lu\n", NumWords(TokenNum-1)*sizeof(unsigned)); if (TraceGen) { _gen("#ifndef zzTRACE_RULES\n"); /* MR20 */ _gen("#define zzTRACE_RULES\n"); /* MR20 */ _gen("#endif\n"); /* MR22 */ }; if ( !GenCC ) {_gen("#include \"antlr.h\"\n");} else { _gen1("#include \"%s\"\n", APARSER_H); _gen1("#include \"%s.h\"\n", CurrentClassName); } if ( !GenCC ) { if ( UserDefdTokens ) {_gen1("#include %s\n", UserTokenDefsFile);} /* still need this one as it has the func prototypes */ _gen1("#include \"%s\"\n", DefFileName); } /* still need this one as it defines the DLG interface */ if ( !GenCC ) _gen("#include \"dlgdef.h\"\n"); if ( LexGen && GenCC ) _gen1("#include \"%s\"\n", DLEXERBASE_H); if ( GenCC ) _gen1("#include \"%s\"\n", ATOKPTR_H); if ( !GenCC && LexGen ) _gen1("#include \"%s\"\n", ModeFileName); /* MR10 Ofer Ben-Ami (gremlin@cs.huji.ac.il) */ /* MR10 Finally, a definition of the Purify macro */ if (PURIFY == TRUE) { /* MR23 */ _gen("\n/* MR23 In order to remove calls to PURIFY use the antlr"); /* MR23 */ _gen(" -nopurify option */\n\n"); /* MR23 */ _gen("#ifndef PCCTS_PURIFY\n"); _gen("#define PCCTS_PURIFY(r,s) memset((char *) &(r),'\\0',(s));\n"); _gen("#endif\n\n"); } /* MR23 */ } void #ifdef __USE_PROTOS genHdr1( int file ) #else genHdr1( file ) int file; #endif { ListNode *p; genHdr(file); if ( GenAST ) { if ( !GenCC ) { _gen("#include \"ast.c\"\n"); _gen("zzASTgvars\n\n"); } } if ( !GenCC ) _gen("ANTLR_INFO\n"); if ( BeforeActions != NULL ) { for (p = BeforeActions->next; p!=NULL; p=p->next) { UserAction *ua = (UserAction *)p->elem; dumpAction( ua->action, output, 0, ua->file, ua->line, 1); } } if ( !FoundException ) return; if ( GenCC ) { _gen1("\nvoid %s::\n", CurrentClassName); _gen("zzdflthandlers( int _signal, int *_retsignal )\n"); _gen("{\n"); } else { _gen("\nvoid\n"); /* MR1 */ /* MR1 10-Apr-97 133MR1 Replace __STDC__ with __USE_PROTOS */ /* MR1 */ _gen("#ifdef __USE_PROTOS\n"); /* MR1 */ _gen("zzdflthandlers( int _signal, int *_retsignal )\n"); _gen("#else\n"); _gen("zzdflthandlers( _signal, _retsignal )\n"); _gen("int _signal;\n"); _gen("int *_retsignal;\n"); _gen("#endif\n"); _gen("{\n"); } tabs++; if ( DefaultExGroup!=NULL ) { dumpException(DefaultExGroup, 1); if ( !hasDefaultException(DefaultExGroup) ) { gen("default :\n"); tabs++; gen("*_retsignal = _signal;\n"); tabs--; gen("}\n"); } } else { gen("*_retsignal = _signal;\n"); } tabs--; _gen("}\n\n"); } void #ifdef __USE_PROTOS genStdPCCTSIncludeFile( FILE *f,char *gate ) /* MR10 */ #else genStdPCCTSIncludeFile( f , gate) /* MR10 */ FILE *f; char * gate; /* MR10 */ #endif { /* MR10 Ramanathan Santhanam (ps@kumaran.com) */ /* MR10 Same preprocessor symbol use to gate stdpccts.h */ /* MR10 even when two grammars are in use. */ /* MR10 Derive gate symbol from -fh filename */ if (gate == NULL) { fprintf(f,"#ifndef STDPCCTS_H\n"); /* MR10 */ fprintf(f,"#define STDPCCTS_H\n"); /* MR10 */ } else { fprintf(f,"#ifndef STDPCCTS_%s_H\n",gate); /* MR10 */ fprintf(f,"#define STDPCCTS_%s_H\n",gate); /* MR10 */ }; fprintf(f,"/*\n"); if (gate == NULL) { fprintf(f," * %s -- P C C T S I n c l u d e\n", stdpccts); } else { fprintf(f," * Standard PCCTS include file with -fh %s -- P C C T S I n c l u d e\n", stdpccts); } fprintf(f," *\n"); fprintf(f," * Terence Parr, Will Cohen, and Hank Dietz: 1989-2001\n"); fprintf(f," * Purdue University Electrical Engineering\n"); fprintf(f," * With AHPCRC, University of Minnesota\n"); fprintf(f," * ANTLR Version %s\n", Version); fprintf(f," */\n\n"); fprintf(f,"#ifndef ANTLR_VERSION\n"); fprintf(f,"#define ANTLR_VERSION %s\n", VersionDef); fprintf(f,"#endif\n\n"); if (FirstAction != NULL ) dumpAction(FirstAction, f, 0, -1, 0, 1); /* MR11 */ fprintf(f,"#include \"pcctscfg.h\"\n"); fprintf(f,"#include \"pccts_stdio.h\"\n"); if ( GenCC ) { if ( UserDefdTokens ) fprintf(f, "#include %s\n", UserTokenDefsFile); else { fprintf(f, "#include \"%s\"\n", DefFileName); } fprintf(f, "#include \"%s\"\n", ATOKEN_H); if ( HdrAction != NULL ) dumpAction( HdrAction, f, 0, -1, 0, 1); fprintf(f, "#include \"%s\"\n", ATOKENBUFFER_H); if ( OutputLL_k > 1 ) fprintf(f,"static const unsigned LL_K=%d;\n", OutputLL_k); if ( GenAST ) { fprintf(f, "#include \"%s\"\n", ASTBASE_H); } if (TraceGen) { fprintf(f,"#ifndef zzTRACE_RULES\n"); /* MR20 */ fprintf(f,"#define zzTRACE_RULES\n"); /* MR20 */ fprintf(f,"#endif\n"); /* MR22 */ }; fprintf(f,"#include \"%s\"\n", APARSER_H); fprintf(f,"#include \"%s.h\"\n", CurrentClassName); if ( LexGen ) fprintf(f,"#include \"%s\"\n", DLEXERBASE_H); fprintf(f, "#endif\n"); return; } if ( strcmp(ParserName, DefaultParserName)!=0 ) fprintf(f, "#define %s %s\n", DefaultParserName, ParserName); if ( strcmp(ParserName, DefaultParserName)!=0 ) fprintf(f, "#include \"%s\"\n", RemapFileName); if ( UserTokenDefsFile != NULL ) fprintf(f, "#include %s\n", UserTokenDefsFile); if ( HdrAction != NULL ) dumpAction( HdrAction, f, 0, -1, 0, 1); if ( FoundGuessBlk ) { fprintf(f,"#define ZZCAN_GUESS\n"); fprintf(f,"#include \"pccts_setjmp.h\"\n"); } if (TraceGen) { fprintf(f,"#ifndef zzTRACE_RULES\n"); /* MR20 */ fprintf(f,"#define zzTRACE_RULES\n"); /* MR20 */ fprintf(f,"#endif\n"); /* MR22 */ }; if ( OutputLL_k > 1 ) fprintf(f,"#define LL_K %d\n", OutputLL_k); if ( GenAST ) fprintf(f,"#define GENAST\n"); if ( FoundException ) { /* MR1 7-Apr-97 1.33MR1 */ /* MR1 Fix suggested by: */ /* MR1 Francois-Xavier Fontaine (fontaine_f@istvax.ist.lu) */ fprintf(f,"#define EXCEPTION_HANDLING\n"); /* MR1 */ fprintf(f,"#define NUM_SIGNALS %d\n", NumSignals); /* MR1 */ } if ( DemandLookahead ) fprintf(f,"#define DEMAND_LOOK\n"); #ifdef DUM if ( LexGen ) fprintf(f, "#define zzEOF_TOKEN %d\n", (TokenInd!=NULL?TokenInd[EofToken]:EofToken)); #endif /* ###WARNING: This will have to change when SetWordSize changes */ fprintf(f, "#define zzSET_SIZE %lu\n", NumWords(TokenNum-1)*sizeof(unsigned)); if (TraceGen) { fprintf(f,"#ifndef zzTRACE_RULES\n"); /* MR20 */ fprintf(f,"#define zzTRACE_RULES\n"); /* MR20 */ fprintf(f,"#endif\n"); /* MR22 */ }; fprintf(f,"#include \"antlr.h\"\n"); if ( GenAST ) fprintf(f,"#include \"ast.h\"\n"); if ( UserDefdTokens ) fprintf(f, "#include %s\n", UserTokenDefsFile); /* still need this one as it has the func prototypes */ fprintf(f, "#include \"%s\"\n", DefFileName); /* still need this one as it defines the DLG interface */ fprintf(f,"#include \"dlgdef.h\"\n"); /* don't need this one unless DLG is used */ if ( LexGen ) fprintf(f,"#include \"%s\"\n", ModeFileName); fprintf(f,"#endif\n"); } /* dump action 's' to file 'output' starting at "local" tab 'tabs' Dump line information in front of action if GenLineInfo is set If file == -1 then GenLineInfo is ignored. The user may redefine the LineInfoFormatStr to his/her liking most compilers will like the default, however. June '93; changed so that empty lines are left alone so that line information is correct for the compiler/debuggers. */ void #ifdef __USE_PROTOS dumpAction( char *s, FILE *output, int tabs, int file, int line, int final_newline ) #else dumpAction( s, output, tabs, file, line, final_newline ) char *s; FILE *output; int tabs; int file; int line; int final_newline; #endif { int inDQuote, inSQuote; require(s!=NULL, "dumpAction: NULL action"); require(output!=NULL, eMsg1("dumpAction: output FILE is NULL for %s",s)); if ( GenLineInfo && file != -1 ) { OutLineInfo(output,line,FileStr[file]); } PastWhiteSpace( s ); /* don't print a tab if first non-white char is a # (preprocessor command) */ if ( *s!='#' ) {TAB;} inDQuote = inSQuote = FALSE; while ( *s != '\0' ) { if ( *s == '\\' ) { fputc( *s++, output ); /* Avoid '"' Case */ if ( *s == '\0' ) return; if ( *s == '\'' ) fputc( *s++, output ); if ( *s == '\"' ) fputc( *s++, output ); } if ( *s == '\'' ) { if ( !inDQuote ) inSQuote = !inSQuote; } if ( *s == '"' ) { if ( !inSQuote ) inDQuote = !inDQuote; } if ( *s == '\n' ) { fputc('\n', output); s++; PastWhiteSpace( s ); if ( *s == '}' ) { --tabs; TAB; fputc( *s++, output ); continue; } if ( *s == '\0' ) return; if ( *s != '#' ) /* #define, #endif etc.. start at col 1 */ { TAB; } } if ( *s == '}' && !(inSQuote || inDQuote) ) { --tabs; /* Indent one fewer */ } if ( *s == '{' && !(inSQuote || inDQuote) ) { tabs++; /* Indent one more */ } fputc( *s, output ); s++; } if ( final_newline ) fputc('\n', output); } static void #ifdef __USE_PROTOS dumpAfterActions( FILE *output ) #else dumpAfterActions( output ) FILE *output; #endif { ListNode *p; require(output!=NULL, "dumpAfterActions: output file was NULL for some reason"); if ( AfterActions != NULL ) { for (p = AfterActions->next; p!=NULL; p=p->next) { UserAction *ua = (UserAction *)p->elem; dumpAction( ua->action, output, 0, ua->file, ua->line, 1); } } fclose( output ); } /* * Find the next action in the stream of execution. Do not pass * junctions with more than one path leaving them. * Only pass generic junctions. * * Scan forward while (generic junction with p2==NULL) * If we stop on an action, return ptr to the action * else return NULL; */ static ActionNode * #ifdef __USE_PROTOS findImmedAction( Node *q ) #else findImmedAction( q ) Node *q; #endif { Junction *j; require(q!=NULL, "findImmedAction: NULL node"); require(q->ntype>=1 && q->ntype<=NumNodeTypes, "findImmedAction: invalid node"); while ( q->ntype == nJunction ) { j = (Junction *)q; if ( j->jtype != Generic || j->p2 != NULL ) return NULL; q = j->p1; if ( q == NULL ) return NULL; } if ( q->ntype == nAction ) return (ActionNode *)q; return NULL; } static void #ifdef __USE_PROTOS dumpRetValAssign( char *retval, char *ret_def, RuleRefNode * ruleRef /* MR30 */) #else dumpRetValAssign( retval, ret_def, ruleRef /* MR30 */) char *retval; char *ret_def; RuleRefNode *ruleRefNode; #endif { char *q = ret_def; tab(); while ( *retval != '\0' && *q != '\0') { while ( isspace((*retval)) ) retval++; while ( *retval!=',' && *retval!='\0' ) fputc(*retval++, output); fprintf(output, " = _trv."); DumpNextNameInDef(&q, output); while ( isspace(*q) ) q++; fputc(';', output); fputc(' ', output); if ( *retval == ',' ) retval++; } if (*retval == '\0' && *q != '\0') { /* MR30 */ errFL("Fewer output values than output formals for rule reference", /* MR30 */ FileStr[ruleRef->file],ruleRef->line); } if (*retval != '\0' && *q == '\0') { /* MR30 */ errFL("More output actuals than output formals for rule reference", /* MR30 */ FileStr[ruleRef->file],ruleRef->line); } } /* This function computes the set of tokens that can possibly be seen k * tokens in the future from point j */ static set #ifdef __USE_PROTOS ComputeErrorSet( Junction *j, int k, int usePlusBlockBypass) #else ComputeErrorSet( j, k, usePlusBlockBypass ) Junction *j; int k; int usePlusBlockBypass; #endif { Junction *alt1; set a, rk, f; require(j->ntype==nJunction, "ComputeErrorSet: non junction passed"); f = rk = empty; for (alt1=j; alt1!=NULL; alt1 = (Junction *)alt1->p2) { if (alt1->ignore && ! usePlusBlockBypass) continue; /* MR21 - Ignore aPlusBlk forward p2 */ REACH(alt1->p1, k, &rk, a); require(set_nil(rk), "ComputeErrorSet: rk != nil"); set_free(rk); set_orin(&f, a); set_free(a); } return f; } static char * #ifdef __USE_PROTOS tokenFollowSet(TokNode *p) #else tokenFollowSet(p) TokNode *p; #endif { static char buf[100]; set rk, a; int n; rk = empty; REACH(p->next, 1, &rk, a); require(set_nil(rk), "rk != nil"); set_free(rk); n = DefErrSet( &a, 0, NULL ); set_free(a); if ( GenCC ) sprintf(buf, "err%d", n); else sprintf(buf, "zzerr%d", n); return buf; } static void #ifdef __USE_PROTOS makeErrorClause( Junction *q, set f, int max_k, int usePlusBlockBypass ) #else makeErrorClause( q, f, max_k, usePlusBlockBypass ) Junction *q; set f; int max_k; int usePlusBlockBypass; #endif { char * handler_id=""; /* MR7 */ int nilf=0; /* MR13 */ RuleEntry *ruleEntry; /* MR14 */ if ( FoundException ) { _gen("else {\n"); tabs++; if ( FoundGuessBlk ) { if ( GenCC ) {gen("if ( guessing ) goto fail;\n");} else gen("if ( zzguessing ) goto fail;\n"); } gen("if (_sva) _signal=NoViableAlt;\n"); gen("else _signal=NoSemViableAlt;\n"); if (q->outerEG != NULL) { handler_id=q->outerEG->altID; #if 0 } else { printf("q->curAltNum=%d q->exception_label=%s\n",q->curAltNum,q->exception_label); gen("*** DEBUG *** outerEG==NULL\n"); #endif }; gen1("goto %s_handler; /* MR7 */\n",handler_id); /* MR7 */ tabs--; gen("}\n"); return; } if ( max_k == 1 ) { /* MR13 */ nilf=set_nil(f); if ( GenCC ) { _gen1("else {FAIL(1,err%d", DefErrSet1(1,&f,1,NULL)); } else { _gen1("else {zzFAIL(1,zzerr%d", DefErrSet1(1,&f,1,NULL)); }; set_free(f); } else { int i; set_free(f); if ( GenCC ) {_gen1("else {FAIL(%d", max_k);} else _gen1("else {zzFAIL(%d", max_k); ruleEntry = (RuleEntry *) hash_get(Rname,q->rname); for (i=1; i<=max_k; i++) { /* MR14 */ if (ruleEntry->dontComputeErrorSet) { /* MR14 */ f=empty; } else { f = ComputeErrorSet(q, i, usePlusBlockBypass /* use plus block bypass ? */ ); } if ( GenCC ) {_gen1(",err%d", DefErrSet( &f, 1, NULL ));} else _gen1(",zzerr%d", DefErrSet( &f, 1, NULL )); set_free(f); } } _gen(",&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;}\n"); /* MR13 */ if (nilf) { /* MR13 */ errFL("empty error set for alt - probably because of undefined rule or infinite left recursion", /* MR13 */ FileStr[q->file],q->line); /* MR13 */ gen(" /* MR13 empty error set for this alt - undef rule ? infinite left recursion ? */"); /* MR13 */ }; } static /* MR7 */ #ifdef __USE_PROTOS char * findOuterHandlerLabel(ExceptionGroup *eg) /* MR7 */ #else char * findOuterHandlerLabel(eg) /* MR7 */ ExceptionGroup *eg; /* MR7 */ #endif { char *label=NULL; /* MR7 */ ExceptionGroup *outerEG; /* MR7 */ if (eg->forRule == 0) { /* MR7 */ if (eg->labelEntry != NULL) { /* MR7 */ outerEG=eg->labelEntry->outerEG; /* MR7 */ if (outerEG != NULL) { /* MR7 */ label=outerEG->altID; /* MR7 */ outerEG->used=1; /* MR7 */ }; /* MR7 */ } else if (eg->outerEG != NULL) { /* MR7 */ outerEG=eg->outerEG; /* MR7 */ label=outerEG->altID; /* MR7 */ outerEG->used=1; /* MR7 */ }; /* MR7 */ }; /* MR7 */ return (label==NULL ? "" : label); /* MR7 */ } /* MR7 */ /*** debug ***/ #if 0 ** static /* MR7 */ ** #ifdef __USE_PROTOS ** char * findOuterAltHandlerLabel(Junction *startJ) /* MR7 */ ** #else ** char * findOuterAltHandlerLabel(startJ) /* MR7 */ ** Junction *startJ; /* MR7 */ ** #endif ** { /* MR7 */ ** char *label=NULL; /* MR7 */ ** Junction *alt; /* MR7 */ ** /* MR7 */ ** for (alt=startJ; alt != NULL; alt=alt->outerAltstart) { /* MR7 */ ** label=alt->exception_label; /* MR7 */ ** if (label != NULL) break; /* MR7 */ ** }; /* MR7 */ ** return (label==NULL ? "" : label); /* MR7 */ ** } /* MR7 */ #endif #ifdef __USE_PROTOS static void OutLineInfo(FILE *file,int line,char *fileName) #else static void OutLineInfo(file,line,fileName) FILE * file; int line; char * fileName; #endif { static char * prevFileName=NULL; static char * prevFileNameMS=NULL; char * p; char * q; if (! GenLineInfo) return; if (!GenLineInfoMS) { fprintf(file, LineInfoFormatStr,line,fileName); } else { if (fileName == prevFileName) { fprintf(file, LineInfoFormatStr,line,prevFileNameMS); } else { if (prevFileNameMS != NULL) free (prevFileNameMS); prevFileNameMS=(char *)calloc(1,strlen(fileName)+1); require(prevFileNameMS != NULL,"why not do this in calloc wrapper"); q=prevFileNameMS; for (p=fileName; *p != 0; p++) { *q=*p; if (*q == '\\') *q='/'; q++; } } prevFileName=fileName; }; } #if 0 /* MR21 */ #ifdef __USE_PROTOS void OutFirstSetSymbol(Junction *q, char * pSymbol) #else void OutFirstSetSymbol(q, pSymbol) Junction* q; char * pSymbol #endif { set f; if (pSymbol == NULL) return; gen1("/** #FirstSetSymbol(%s) **/\n",pSymbol); f = ComputeErrorSet(q, 1, 0 /* use plus block bypass ? */); DefErrSetWithSuffix (0 /* nil ok */, &f,0 /* no substitute */, pSymbol, ""); set_free(f); } #endif /* MR21 */ #ifdef __USE_PROTOS void BlockPreambleOption(Junction *q, char * pSymbol) #else void BlockPreambleOption(q, pSymbol) Junction* q; char * pSymbol; #endif { set f = empty; if (pSymbol != NULL) { f = ComputeErrorSet(q, 1, 0 /* use plus block bypass ? */); gen1("/** #FirstSetSymbol(%s) **/\n",pSymbol); DefErrSetWithSuffix (0 /* nil ok */, &f,0 /* no substitute */, pSymbol, ""); } set_free(f); } /* MR21 */ void #ifdef __USE_PROTOS dumpActionPlus(ActionNode *a, char *s, FILE *output, int tabs, int file, int line, int final_newline ) #else dumpActionPlus(a, s, output, tabs, file, line, final_newline ) ActionNode *a; char *s; FILE *output; int tabs; int file; int line; int final_newline; #endif { dumpAction(s,output,tabs,file,line,final_newline); } #if 0 ** #ifdef __USE_PROTOS ** void MR_ErrorSets(Junction *q, int max_k, int usePlusBlockBypass) ** #else ** void MR_ErrorSets(q, max_k, usePlusBlockBypass) ** Junction *q; ** int max_k; ** int usePlusBlockBypass; ** #endif ** { ** int k; ** set setResult; ** Junction* alt1; ** Junction* p; ** set rk; ** ** require (max_k <= CLL_k, "k > CLL_k"); ** ** ** for (k = 1; k <= CLL_k; k++) {set_clr(q->fset[k]); } ** ** for (k = 1; k <= max_k; k++) { ** for (alt1=q; alt1 != NULL; alt1 = (Junction *)alt1->p2) ** { ** if (alt1->ignore && ! usePlusBlockBypass) continue; ** p = analysis_point((Junction *)alt1->p1); ** REACH(p, k, &rk, setResult); ** require(set_nil(rk), "rk != nil"); ** set_orin(&q->fset[k], setResult); ** } ** } ** } #endif #ifdef __USE_PROTOS void DumpInitializers(FILE* output, RuleEntry *r, char * pReturn) #else void DumpInitializers(output, r, pReturn) FILE* output; RuleEntry *r; char * pReturn; #endif { char *p = pReturn; char *pDataType; char *pSymbol; char *pEqualSign; char *pValue; char *pSeparator; int nest = 0; char *q; require(pReturn!=NULL, "DumpInitializer: invalid string"); while (*p != 0) { p = endFormal(p, &pDataType, &pSymbol, &pEqualSign, &pValue, &pSeparator, &nest); if (nest != 0) return; if (pValue != NULL) { tab(); q = strBetween(pSymbol, pEqualSign, pSeparator); fprintf(output, "_retv.%s", q); q = strBetween(pValue, NULL, pSeparator); fprintf(output, " = %s;\n", q); } } } #ifdef __USE_PROTOS void DumpFormals(FILE* output, char * pReturn, int bInitializer) #else void DumpFormals(output, pReturn, bInitializer) FILE* output; char * pReturn; int bInitializer; #endif { char *p = pReturn; char *pDataType; char *pSymbol; char *pEqualSign; char *pValue; char *pSeparator; int nest = 0; char *q; int count = 0; require(pReturn!=NULL, "DumpFormals: invalid string"); while (*p != 0) { p = endFormal(p, &pDataType, &pSymbol, &pEqualSign, &pValue, &pSeparator, &nest); if (nest != 0) return; if (count > 0) fprintf(output,","); if (pDataType != NULL && pSymbol != NULL) { q = strBetween(pDataType, pSymbol, pSeparator); fprintf(output, "%s", q); q = strBetween(pSymbol, pEqualSign, pSeparator); fprintf(output," %s",q); if (pValue != NULL) { q = strBetween(pValue, NULL, pSeparator); if (bInitializer != 0) { fprintf(output, " = %s", q); } } } count++; } } /* MR23 Check for empty alt in a more intelligent way. Previously, an empty alt for genBlk had to point directly to the endBlock. This did not work once I changed {...} blocks to look like (...|...| epsilon) since there were intervening generics. This fixes the problem for this particular case. Things like actions or empty blocks of various kinds will still cause problems, but I wasnt't prepared to handle pathological cases like (A|()*). It does handle (A | ()), which is a recommended idiom for epsilon. Actually, this isn't quite correct since it doesn't handle the case of the ignore bit in the plus block bypass, but I'm too tired to figure out the correct fix, and will just work around it. */ #ifdef __USE_PROTOS int isEmptyAlt(Node * alt, Node * endBlock) #else int isEmptyAlt(alt, endBlock) Node * alt; Node * endBlock; #endif { Node * n = alt; Junction * j; while (n != endBlock) { switch (n->ntype) { case nRuleRef: return 0; case nToken: return 0; case nAction: return 0; case nJunction: goto JUNCTION; default: fatal_internal("Invalid node type"); return 0; } JUNCTION: j = (Junction *) n; switch (j->jtype) { case Generic: { n = j->p1; goto NEXT; } case aSubBlk: { n = j->p1; /* MR26 */ goto NEXT; /* MR26 */ } case EndBlk: return 0; case EndRule: return 1; default: return 0; } NEXT: continue; } return 1; } cdrdao-cdrdao-f00afb2/pccts/antlr/generic.h000066400000000000000000000223001511453746600207140ustar00rootroot00000000000000/* * generic.h -- generic include stuff for new PCCTS ANTLR. * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2001 */ #define StrSame 0 #define DefaultParserName "zzparser" /* MR9 JVincent@novell.com Allow user to override default ZZLEXBUFSIZE */ /* MR11 thm Raise antlr's own default ZZLEXBUFSIZE to 8k */ /* MR22 thm Raise antlr's own default ZZLEXBUFSIZE to 32k */ #ifndef ZZLEXBUFSIZE #define ZZLEXBUFSIZE 32000 #endif /* Tree/FIRST/FOLLOW defines -- valid only after all grammar has been read */ #define ALT TokenNum+1 #define SET TokenNum+2 #define TREE_REF TokenNum+3 /* E r r o r M a c r o s */ #define fatal(err) fatalFL(err, __FILE__, __LINE__) #define fatal_internal(err) fatal_intern(err, __FILE__, __LINE__) #define eMsg1(s,a) eMsg3(s,a,NULL,NULL) #define eMsg2(s,a,b) eMsg3(s,a,b,NULL) /* S a n i t y C h e c k i n g */ #ifndef require #define require(expr, err) {if ( !(expr) ) fatal_internal(err);} #endif /* L i s t N o d e s */ typedef struct _ListNode { void *elem; /* pointer to any kind of element */ struct _ListNode *next; } ListNode; /* Define a Cycle node which is used to track lists of cycles for later * reconciliation by ResolveFoCycles(). */ typedef struct _c { int croot; /* cycle root */ set cyclicDep; /* cyclic dependents */ unsigned deg; /* degree of FOLLOW set of croot */ } Cycle; typedef struct _e { int tok; /* error class name == TokenStr[tok] */ ListNode *elist; /* linked list of elements in error set */ set eset; int setdeg; /* how big is the set */ int lexclass; /* which lex class is it in? */ } ECnode; typedef struct _TCnode { int tok; /* token class name */ ListNode *tlist; /* linked list of elements in token set */ set tset; int lexclass; /* which lex class is it in? */ unsigned char dumped; /* this def has been been dumped */ unsigned char dumpedComplement; /* this def has been been dumped */ unsigned setnum; /* which set number is this guy? (if dumped) */ unsigned setnumComplement; /* MR23 */ unsigned setnumErrSet; /* MR23 which set is this #tokclass error set (if dumped) */ unsigned setnumErrSetComplement; /* MR23 */ } TCnode; typedef struct _ft { char *token; /* id of token type to remap */ int tnum; /* move token type to which token position */ } ForcedToken; typedef struct _ContextGuardPredicates { /* MR13 */ Predicate *pred; /* MR13 */ } ContextGuardPredicates; /* MR13 */ #define newListNode (ListNode *) calloc(1, sizeof(ListNode)); #define newCycle (Cycle *) calloc(1, sizeof(Cycle)); #define newECnode (ECnode *) calloc(1, sizeof(ECnode)); #define newTCnode (TCnode *) calloc(1, sizeof(TCnode)); /* H a s h T a b l e E n t r i e s */ typedef struct _t { /* Token name or expression */ char *str; struct _t *next; int token; /* token number */ unsigned char classname; /* is it a err/tok class name or token */ TCnode *tclass; /* ptr to token class */ char *action; char *akaString; } TermEntry; typedef struct _r { /* Rule name and ptr to start of rule */ char *str; struct _t *next; int rulenum; /* RulePtr[rulenum]== ptr to RuleBlk junction */ unsigned char noAST;/* gen AST construction code? (def==gen code) */ char *egroup; /* which error group (err reporting stuff) */ #if 0 /* MR27 This appears to never be used. Delete this code later. */ ListNode *el_labels;/* list of element labels ref in all of rule */ #endif ListNode *ast_labels_in_actions; /* MR27 */ unsigned char has_rule_exception; char dontComputeErrorSet; /* MR14 - don't compute error set special for rule in alpha part of (alpha)? beta block */ } RuleEntry; typedef struct _f { /* cache Fi/Fo set */ char *str; /* key == (rulename, computation, k) */ struct _f *next; set fset; /* First/Follow of rule */ set rk; /* set of k's remaining to be done after ruleref */ int incomplete; /* only w/FOLLOW sets. Use only if complete */ } CacheEntry; typedef struct _LabelEntry { /* element labels */ char *str; struct _f *next; Node *elem; /* which element does it point to? */ ExceptionGroup *ex_group; /* Is there an exception attached to label? */ ExceptionGroup *outerEG; /* MR7 */ /* next EG if ex_group doesn't catch it MR7 */ struct _LabelEntry *pendingLink; /* MR7 */ /* too lazy to use ListNode ? MR7 */ int curAltNum; /* MR7 */ } LabelEntry; typedef struct _SignalEntry { char *str; struct _f *next; int signum; /* unique signal number */ } SignalEntry; typedef struct _PredEntry { /* MR11 predicate name and ptr to string */ char *str; struct _PredEntry *next; int file; int line; Predicate *pred; char *predLiteral; } PredEntry; typedef struct _PointerStack { /* MR10 */ int count; int size; void **data; } PointerStack; #define newTermEntry(s) (TermEntry *) newEntry(s, sizeof(TermEntry)) #define newRuleEntry(s) (RuleEntry *) newEntry(s, sizeof(RuleEntry)) #define newCacheEntry(s) (CacheEntry *) newEntry(s, sizeof(CacheEntry)) #define newLabelEntry(s) (LabelEntry *) newEntry(s, sizeof(LabelEntry)) #define newSignalEntry(s) (SignalEntry *) newEntry(s, sizeof(SignalEntry)) #define newPredEntry(s) (PredEntry *) newEntry(s,sizeof(PredEntry)) typedef struct _UserAction { char *action; int file, line; } UserAction; /* L e x i c a l C l a s s */ /* to switch lex classes, switch ExprStr and Texpr (hash table) */ typedef struct _lc { char *classnum, **exprs; Entry **htable; } LClass; typedef struct _exprOrder { char *expr; int lclass; } Expr; typedef Graph Attrib; /* M a x i m u m s */ /* MR20 Note G. Hobbelt These values are superceded by values in hash.h */ #ifndef HashTableSize #define HashTableSize 253 #endif #ifndef StrTableSize #define StrTableSize 15000 /* all tokens, nonterminals, rexprs stored here */ #endif #define MaxLexClasses 50 /* how many automatons */ /* TokenStart and EofToken are ignored if #tokdefs meta-op is used */ #define TokenStart 2 /* MUST be in 1 + EofToken */ #define EofToken 1 /* Always predefined to be 1 */ #ifndef MaxNumFiles #define MaxNumFiles 99 #endif /**** MR9 JVincent@novell.com Move to pcctscfg.h */ /**** #define MaxFileName 300 ****/ /* MR9 Move to pcctscfg.h */ /* largest file name size */ #define MaxRuleName 100 /* largest rule name size */ #define TSChunk 100 /* how much to expand TokenStr/ExprStr each time */ #define TIChunk TSChunk /* expand TokenInd by same as TokenStr to mirror them */ #define FoStackSize 100 /* deepest FOLLOW recursion possible */ #define MaxClassDeclStuff 256 /* MR10 */ #define NumPredefinedSignals 3 /* S t a n d a r d S i g n a l s */ #define sigNoSignal 0 #define sigMismatchedToken 1 #define sigNoViableAlt 2 #define sigNoSemViableAlt 3 /* AST token types */ #define ASTexclude 0 #define ASTchild 1 #define ASTroot 2 #define ASTinclude 3 /* include subtree made by rule ref */ #define PredictionVariable "zzpr_expr" #define PredictionLexClassSuffix "_zzpred" #define WildCardString "WildCard" #if 0 /* Removed in version 1.33MR19 Don't understand why this never caused problems before */ /********************************************************* #ifndef ANTLRm #define ANTLRm(st, f, _m) zzbufsize = ZZLEXBUFSIZE;\ zzmode(_m); \ zzenterANTLR(f); \ st; ++zzasp; \ zzleaveANTLR(f); #endif *********************************************************/ #endif #include "proto.h" #include "pcctscfg.h" /* MR14 */ #include cdrdao-cdrdao-f00afb2/pccts/antlr/globals.c000066400000000000000000000414621511453746600207300ustar00rootroot00000000000000/* * globals.c -- File containing all variables/tables visible to all files. * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2001 */ #include #include "pcctscfg.h" #include "set.h" #include "syn.h" #include "hash.h" #include "generic.h" char Version[] = "1.33MR32" ; /* PCCTS version number */ /* MRXXX */ char VersionDef[] = "13332"; /* same (except int equiv for preproc symbol) */ /* MRXXX */ char LexStartSymbol[] = "START";/* Name of starting lexical class/automaton */ char *RemapFileName = "remap.h"; char *DlgFileName = "parser.dlg"; char *DefFileName = "tokens.h"; char *ErrFileName = "err.c"; char *ModeFileName = "mode.h"; char *StdMsgName = NULL; char *ParserName = DefaultParserName; /* list of PCCTS supplied support symbols; these are renamed when more than * one ANTLR-generated parsers are linked together to avoid name conflicts. * Can't use '##' ANSIC preprocessor concat operator with K&R and: * #define zzskip zzparser ## skip * will not work for ANSI/C++ as 'zzparserskip' is created w/o zzparser * being substituted--ack!!! */ char *StandardSymbols[] = { /* ANTLR stuff */ "zzStackOvfMsg", "zzasp", "zzaStack", "inf_tokens", "inf_text", "inf_text_buffer", "inf_text_buffer_ptr", "inf_text_buffer_size", "inf_labase", "inf_last", "inf_lap", "zztokenLA", "zztextLA", "zzlap", "zzlabase", "zztoktext", "zztoken", "zzdirty", "zzguessing", "zzguess_start", "zzresynch", "zzinf_tokens", "zzinf_text", "zzinf_text_buffer", "zzinf_labase", "zzinf_last", "zzfill_inf_look", "zzFAIL", "zzsave_antlr_state", "zzrestore_antlr_state", "zzsyn", "zzset_el", "zzset_deg", "zzedecode", "_zzsetmatch", "_zzmatch", "_inf_zzgettok", "zzconsumeUntil", "zzconsumeUntilToken", "_zzmatch_wsig", "_zzsetmatch_wsig", "_zzmatch_wdfltsig", "_zzsetmatch_wdfltsig", "zzdflthandlers", /* DLG stuff */ "zzreal_line", "zzcharfull", "zzerr", "zzlextext", "zzbegexpr", "zzendexpr", "zzbufsize", "zzbegcol", "zzendcol", "zzline", "zzchar", "zzbufovf", "zzrdstream", "zzrdfunc", "zzrdstr", "zzclose_stream", "zzsave_dlg_state", "zzrestore_dlg_state", "zzmode", "zzskip", "zzmore", "zzreplchar", "zzreplstr", "zzgettok", "zzadvance", "zzerrstd", "zzerr_in", "zzconstr_attr", "zzempty_attr", "zzerraction", "zztokens", /* list of token regular expressions */ "dfa", "accepts", "actions", "zzTraceOptionValue", /* MR10 */ "zzTraceGuessOptionValue", /* MR10 */ "zzTraceCurrentRuleName", /* MR10 */ "zzTraceDepth", /* MR10 */ "zzGuessSeq", /* MR10 */ "zzSyntaxErrCount", /* MR11 */ "zzLexErrCount", /* MR11 */ "zzTraceGuessDone", /* MR13 - BJS */ "zzTraceGuessFail", /* MR13 - BJS */ "zzTraceGuessOption", /* MR13 - BJS */ "zzTraceIn", /* MR13 - BJS */ "zzTraceOption", /* MR13 - BJS */ "zzTraceOut", /* MR13 - BJS */ "zzTraceReset", /* MR13 - BJS */ NULL /* must be present */ }; /* list of PCCTS supplied support functions; these are renamed when more than * one ANTLR-generated parsers are linked together to avoid name conflicts. */ char *ASTSymbols[] = { "AST", "zzast_sp", "zzastStack", "zzlink", "zzastnew", "zzsubchild", "zzsubroot", "zzpre_ast", "zzfree_ast", "zztmake", "zzdup_ast", "zztfree", "zzdouble_link", NULL /* must be present */ }; /* Current ambiguity examination information */ int CurAmbigAlt1, CurAmbigAlt2, CurAmbigline, CurAmbigfile; char *CurAmbigbtype; /* M e t h o d T a b l e s */ /* * The following tables are used to fill syntax diagram nodes with the correct * function pointers for computing FIRST sets and printing themselves. */ /* fpTraverse[node type] == pointer to function that calculates trees * representing the FIRST sets for that node (maintains spatial info). * We use 'struct _tree' not 'tree' due to a g++ 2.4.3 bug. */ #ifdef __cplusplus struct _tree *(*fpTraverse[NumNodeTypes+1])(... /* Node *, int, set * */) = { NULL, (struct _tree *(*)(...)) tJunc, (struct _tree *(*)(...)) tRuleRef, (struct _tree *(*)(...)) tToken, (struct _tree *(*)(...)) tAction }; #else Tree *(*fpTraverse[NumNodeTypes+1])() = { NULL, tJunc, tRuleRef, tToken, tAction }; #endif /* fpReach[node type] == pointer to function that calculates FIRST set for * that node. (r stands for reach). We use 'struct _set' not 'set' * due to a g++ 2.4.3 bug. */ #ifdef __cplusplus struct _set (*fpReach[NumNodeTypes+1])(... /* Node *, int, set * */) = { NULL, (struct _set (*)(...)) rJunc, (struct _set (*)(...)) rRuleRef, (struct _set (*)(...)) rToken, (struct _set (*)(...)) rAction }; #else set (*fpReach[NumNodeTypes+1])() = { NULL, rJunc, rRuleRef, rToken, rAction }; #endif /* fpPrint[node type] == pointer to function that knows how to print that node. */ #ifdef __cplusplus void (*fpPrint[NumNodeTypes+1])(... /* Node * */) = { NULL, (void (*)(...)) pJunc, (void (*)(...)) pRuleRef, (void (*)(...)) pToken, (void (*)(...)) pAction }; #else void (*fpPrint[NumNodeTypes+1])() = { NULL, pJunc, pRuleRef, pToken, pAction }; #endif char *decodeJType[] = { "invalid", "aSubBlk", "aOptBlk", "aLoopBlk", "EndBlk", "RuleBlk", "Generic", "EndRule", "aPlusBlk", "aLoopBegin" }; /* H a s h T a b l e s */ Entry **Tname, /* Table of all token names (maps name to tok num)*/ **Texpr, /* Table of all token expressions (maps expr to tok num) */ **Rname, /* Table of all Rules (has ptr to start of rule) */ **Fcache, /* Cache of First/Follow Computations */ **Tcache; /* Tree cache; First/Follow for permute trees */ Entry **Elabel; /* Table of all element label names */ Entry **Sname; /* Signal names */ Entry **Pname; /* symbolic predicate names MR11 */ /* V a r i a b l e s */ int Save_argc; /* MR10 */ char **Save_argv; /* MR10 */ int EpToken=0; /* Imaginary Epsilon token number */ int WildCardToken=0; int CurFile= -1; /* Index into FileStr table */ char *CurPredName=NULL; /* MR11 */ char *CurRule=NULL; /* Pointer to current rule name */ int CurRuleDebug=0; /* MR13 debug flag */ RuleEntry *CurRuleNode=NULL;/* Pointer to current rule node in syntax tree */ char *CurRetDef=NULL; /* Pointer to current return type definition */ char *CurParmDef=NULL; /* Pointer to current parameter definition */ Junction *CurRuleBlk=NULL; /* Pointer to current block node for enclosing block */ ListNode *CurExGroups=NULL; /* Current list of exception groups for rule/alts */ ListNode *CurElementLabels=NULL; ListNode *CurAstLabelsInActions=NULL; /* MR27 */ /* MR10 used by <<>>? to set "label_used_in_semantic_pred" */ /* MR10 this will force LT(i) assignment even in guess mode */ ListNode *CurActionLabels=NULL; /* MR10 Element Labels appearing in last action */ int numericActionLabel=0 ; /* MR10 << ... $1 ... >> or << ... $1 ... >>? */ ListNode *NumericPredLabels=NULL; /* MR10 << ... $1 ... >>? ONLY */ ListNode *ContextGuardPredicateList=NULL; /* MR13 for re-evaluating predicates after meta tokens are defined */ int CurBlockID=0; /* Unique int for each block */ int CurAltNum=0; Junction *CurAltStart = NULL; /* Junction node that starts the alt */ Junction *OuterAltStart = NULL; /* For chaining exception groups MR7 */ int NumRules=0; /* Rules are from 1 to n */ FILE *output=NULL; /* current parser output file */ FILE *input=NULL; /* current grammar input file */ char *FileStr[MaxNumFiles];/* Ptr to array of file names on command-line */ int NumFiles=0; /* current grammar file number */ #ifdef __cplusplus void (**fpTrans)(...), /* array of ptrs to funcs that translate nodes */ (**fpJTrans)(...); /* ... that translate junctions */ #else void (**fpTrans)(), /* array of ptrs to funcs that translate nodes */ (**fpJTrans)(); /* ... that translate junctions */ #endif int **FoStack; /* Array of LL_k ptrs to stacks of rule numbers */ int **FoTOS; /* FOLLOW stack top-of-stack pointers */ Junction *SynDiag = NULL; /* Pointer to start of syntax diagram */ int BlkLevel=1; /* Current block level. Set by antlr.g, used by * scanner to translate $i.j attributes */ set reserved_positions; /* set of token positions reserved by '#token T=i' cmds */ set all_tokens; /* set of all token types */ set imag_tokens; /* set of all imaginary token types (EpToken, errclasses...) */ set tokclasses; /* set of all token class token types */ ListNode *ForcedTokens = 0; /* list of token_id/token_num pairs to remap */ ListNode *MetaTokenNodes=NULL; /* list of meta token refs such as token classes etc... */ int *TokenInd=NULL; /* an indirection level between token num and position * of that token def in TokenStr and ExprStr */ int LastTokenCounted=0; /* ==TokenNum if no token renumbering (same as old TokenNum) */ int TokenNum=TokenStart; char **TokenStr=NULL; /* map token # to token name */ char **ExprStr=NULL; /* map token # to expr */ Junction **RulePtr=NULL; /* map rule # to RuleBlk node of rule */ ListNode *ExprOrder=NULL; /* list of exprs as they are found in grammar */ ListNode *BeforeActions=NULL;/* list of grammar actions before rules */ ListNode *AfterActions=NULL;/* list of grammar actions after rules */ ListNode *LexActions=NULL; /* list of lexical actions */ /* MR1 */ /* MR1 11-Apr-97 Provide mechanism for inserting code into DLG class */ /* MR1 via #lexmember <<....>> */ /* MR1 via #lexprefix <<....>> */ /* MR1 */ ListNode *LexMemberActions=NULL;/* list of lexical header member decl MR1 */ ListNode *LexPrefixActions=NULL;/* list of lexical header #include decl MR1 */ ListNode **Cycles=NULL; /* list of cycles (for each k) found when doing FOLLOWs */ ListNode *eclasses=NULL; /* list of error classes */ ListNode *tclasses=NULL; /* list of token classes */ LClass lclass[MaxLexClasses]; /* array of lex class definitions */ int CurrentLexClass; /* index into lclass */ int NumLexClasses=0; /* in range 1..MaxLexClasses (init 0) */ char *HdrAction=NULL; /* action defined with #header */ char *FirstAction=NULL; /* action defined with #first MR11 */ FILE *ErrFile; /* sets and error recovery stuff */ FILE *DefFile=NULL; /* list of tokens, return value structs, setwd defs */ FILE *MRinfoFile=NULL; /* MR10 information file */ int MRinfo=0; /* MR10 */ int MRinfoSeq=0; /* MR10 */ int InfoP=0; /* MR10 predicates */ int InfoT=0; /* MR10 tnodes */ int InfoF=0; /* MR10 first/follow sets */ int InfoM=0; /* MR10 monitor progress */ int InfoO=0; /* MR12 orphan rules */ int TnodesInUse=0; /* MR10 */ int TnodesPeak=0; /* MR10 */ int TnodesAllocated=0; /* MR10 */ int TnodesReportThreshold=0; /* MR11 */ int PotentialSuppression=0; /* MR10 */ int PotentialDummy=0; /* MR10 */ int CannotContinue=FALSE; int OutputLL_k = 1; /* LL_k for parsing must be power of 2 */ int action_file; /* used to track start of action */ int action_line; int FoundGuessBlk=0; /* there is a (...)? block somewhere in grammar */ int FoundException=0; /* there is an exception somewhere in grammar */ /* MR6 Distinguish between @ operator and real exception */ /* MR6 by keeping separate flags for @ operator and real exceptions */ int FoundAtOperator=0; /* MR6 */ int FoundExceptionGroup=0; /* MR6 */ int pLevel=0; /* print Level */ int pAlt1,pAlt2; /* print "==>" in front of these alts */ /* C++ output stuff */ FILE *Parser_h, /* where subclass of ANTLRParser goes */ *Parser_c; /* where code for subclass of ANTLRParser goes */ char Parser_h_Name[MaxFileName+1] = ""; char Parser_c_Name[MaxFileName+1] = ""; char MRinfoFile_Name[MaxFileName+1] = ""; /* MR10 */ char *ClassDeclStuff=NULL; /* MR10 */ char *BaseClassName=NULL; /* MR22 */ /* list of actions inside the #class {...} defs */ ListNode *class_before_actions=NULL; ListNode *class_after_actions=NULL; char CurrentClassName[MaxRuleName]=""; int no_classes_found=1; char *UserTokenDefsFile; int UserDefdTokens=0; /* found #tokdefs? */ char *OutputDirectory=TopDirectory; ExceptionGroup *DefaultExGroup = NULL; int NumSignals = NumPredefinedSignals; int ContextGuardTRAV=0; char *MR_AmbAidRule=NULL; /* MR11 */ int MR_AmbAidLine=0; /* MR11 */ int MR_AmbAidDepth=0; /* MR11 */ int MR_AmbAidMultiple=0; /* MR11 */ int MR_skipped_e3_report=0; /* MR11 */ int MR_usingPredNames=0; /* MR11 */ int MR_BadExprSets=0; /* MR13 */ int MR_Inhibit_Tokens_h_Gen=0; /* MR13 */ int NewAST=0; /* MR13 */ int tmakeInParser=0; /* MR23 */ int AlphaBetaTrace=0; /* MR14 */ int MR_BlkErr=0; /* MR21 */ int MR_AlphaBetaMessageCount=0; /* MR14 */ int MR_AlphaBetaWarning=0; /* MR14 */ int MR_ErrorSetComputationActive=0; /* MR14 */ int MR_MaintainBackTrace=0; /* MR14 */ set MR_CompromisedRules; /* MR14 */ Junction *MR_RuleBlkWithHalt; /* MR10 */ /* C m d - L i n e O p t i o n s */ int LL_k=1; /* how many tokens of full lookahead */ int CLL_k= -1; /* how many tokens of compressed lookahead */ int PrintOut = FALSE; /* print out the grammar */ int PrintAnnotate = FALSE;/* annotate printout with FIRST sets */ int CodeGen=TRUE; /* Generate output code? */ int LexGen=TRUE; /* Generate lexical files? (tokens.h, parser.dlg) */ int GenAST=FALSE; /* Generate AST's? */ int GenANSI=FALSE; /* Generate ANSI code where necessary */ int GenExprSetsOpt=TRUE;/* use sets not (LA(1)==tok) expression lists */ int GenCR=FALSE; /* Generate cross reference? */ int GenLineInfo=FALSE; /* Generate # line "file" stuff? */ int GenLineInfoMS=FALSE;/* Like -gl but replace "\" with "/" for MS C/C++ systems */ int TraceGen=FALSE; /* Generate code to trace rule invocation */ int elevel=1; /* error level for ambiguity messages */ int GenEClasseForRules=0;/* don't generate eclass for each rule */ int TreeResourceLimit= -1;/* don't limit tree resource */ int DemandLookahead = 0;/* demand/delayed lookahead or not */ char *RulePrefix = ""; /* prefix each generated rule with this */ char *stdpccts = "stdpccts.h";/* where to generate std pccts include file */ int GenStdPccts = 0; /* don't gen stdpccts.h? */ int ParseWithPredicates = 1; int WarningLevel = 1; int UseStdout = 0; /* MR6 */ int TabWidth = 2; /* MR6 */ /* MR27 */ int HoistPredicateContext = 0; int MRhoisting = 0; /* MR9 */ int MRhoistingk = 0; /* MR13 */ int MR_debugGenRule=0; /* MR11 */ int GenCC = 0; /* Generate C++ output */ PointerStack MR_BackTraceStack={0,0,NULL}; /* MR10 */ PointerStack MR_PredRuleRefStack={0,0,NULL}; /* MR10 */ PointerStack MR_RuleBlkWithHaltStack={0,0,NULL}; /* MR10 */ /* DontCopyTokens and Pragma_DupLabeledTokens were a bad idea. I've just turned them off rather than backpatching the code. Who knows? We may need them in the future. */ int DontCopyTokens = 1; /* in C++, don't copy ANTLRToken passed to ANTLR */ /* Remember if LT(i), LA(i), or LATEXT(i) used in an action which is not a predicate. If so, give a warning for novice users. */ int LTinTokenAction = 0; /* MR23 */ int PURIFY = 1; /* MR23 */ int CurBlockID_array[MAX_BLK_LEVEL]; /* MR23 */ int CurAltNum_array[MAX_BLK_LEVEL]; /* MR23 */ cdrdao-cdrdao-f00afb2/pccts/antlr/hash.c000066400000000000000000000125161511453746600202260ustar00rootroot00000000000000/* * hash.c * * Manage hash tables. * * The following functions are visible: * * char *mystrdup(char *); Make space and copy string * Entry **newHashTable(); Create and return initialized hash table * Entry *hash_add(Entry **, char *, Entry *) * Entry *hash_get(Entry **, char *) * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2001 */ #include #include "pcctscfg.h" #include "hash.h" #ifdef __USE_PROTOS #include #else #ifdef VAXC #include #else #include #endif #endif #include #define StrSame 0 #define fatal(err) \ {fprintf(stderr, "%s(%d):", __FILE__, __LINE__); \ fprintf(stderr, " %s\n", err); exit(PCCTS_EXIT_FAILURE);} #define require(expr, err) {if ( !(expr) ) fatal(err);} static unsigned size = HashTableSize; static char *strings = NULL; static char *strp; static unsigned strsize = StrTableSize; /* create the hash table and string table for terminals (string table only once) */ Entry ** #ifdef __USE_PROTOS newHashTable( void ) #else newHashTable( ) #endif { Entry **table; table = (Entry **) calloc(size, sizeof(Entry *)); require( table != NULL, "cannot allocate hash table"); if ( strings == NULL ) { strings = (char *) calloc(strsize, sizeof(char)); require( strings != NULL, "cannot allocate string table"); strp = strings; } return table; } void #ifdef __USE_PROTOS killHashTable( Entry **table ) #else killHashTable( table ) Entry **table; #endif { /* for now, just free table, forget entries */ free( (char *) table ); /* MR10 cast */ } /* Given a table, add 'rec' with key 'key' (add to front of list). return ptr to entry */ Entry * #ifdef __USE_PROTOS hash_add( Entry **table, char *key, Entry *rec ) #else hash_add( table, key, rec ) Entry **table; char *key; Entry *rec; #endif { unsigned h=0; char *p=key; require(table!=NULL && key!=NULL && rec!=NULL, "add: invalid addition"); Hash(p,h,size); rec->next = table[h]; /* Add to singly-linked list */ table[h] = rec; return rec; } /* Return ptr to 1st entry found in table under key (return NULL if none found) */ Entry * #ifdef __USE_PROTOS hash_get( Entry **table, char *key ) #else hash_get( table, key ) Entry **table; char *key; #endif { unsigned h=0; char *p=key; Entry *q; /* require(table!=NULL && key!=NULL, "get: invalid table and/or key");*/ if ( !(table!=NULL && key!=NULL) ) // *((char *) 34) = 3; denis: old orig code, WTF, looks like an assert return( NULL ); Hash(p,h,size); for (q = table[h]; q != NULL; q = q->next) { if ( strcmp(key, q->str) == StrSame ) return( q ); } return( NULL ); } #ifdef DEBUG_HASH void #ifdef __USE_PROTOS hashStat( Entry **table ) #else hashStat( table ) Entry **table; #endif { static unsigned short count[20]; int i,n=0,low=0, hi=0; Entry **p; float avg=0.0; for (i=0; i<20; i++) count[i] = 0; for (p=table; p<&(table[size]); p++) { Entry *q = *p; int len; if ( q != NULL && low==0 ) low = p-table; len = 0; if ( q != NULL ) fprintf(stderr, "[%d]", p-table); while ( q != NULL ) { len++; n++; fprintf(stderr, " %s", q->str); q = q->next; if ( q == NULL ) fprintf(stderr, "\n"); } count[len]++; if ( *p != NULL ) hi = p-table; } fprintf(stderr, "Storing %d recs used %d hash positions out of %d\n", n, size-count[0], size); fprintf(stderr, "%f %% utilization\n", ((float)(size-count[0]))/((float)size)); for (i=0; i<20; i++) { if ( count[i] != 0 ) { avg += (((float)(i*count[i]))/((float)n)) * i; fprintf(stderr, "Bucket len %d == %d (%f %% of recs)\n", i, count[i], ((float)(i*count[i]))/((float)n)); } } fprintf(stderr, "Avg bucket length %f\n", avg); fprintf(stderr, "Range of hash function: %d..%d\n", low, hi); } #endif /* Add a string to the string table and return a pointer to it. * Bump the pointer into the string table to next avail position. */ char * #ifdef __USE_PROTOS mystrdup( char *s ) #else mystrdup( s ) char *s; #endif { char *start=strp; require(s!=NULL, "mystrdup: NULL string"); while ( *s != '\0' ) { require( strp <= &(strings[strsize-2]), "string table overflow\nIncrease StrTableSize in hash.h and recompile hash.c\n"); *strp++ = *s++; } *strp++ = '\0'; return( start ); } cdrdao-cdrdao-f00afb2/pccts/antlr/hash.h000066400000000000000000000041131511453746600202250ustar00rootroot00000000000000/* * hash.h -- define hash table entries, sizes, hash function... * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2001 */ /* H a s h T a b l e S t u f f */ #ifndef HashTableSize #define HashTableSize 553 #endif #ifndef StrTableSize #ifdef PC32 #define StrTableSize 1000000 #endif #endif #ifndef StrTableSize #ifdef PC #define StrTableSize 655200 #endif #endif #ifndef StrTableSize #define StrTableSize 1000000 #endif typedef struct _entry { /* Minimum hash table entry -- superclass */ char *str; struct _entry *next; } Entry; /* Hash 's' using 'size', place into h (s is modified) */ #define Hash(s,h,size) \ {while ( *s != '\0' ) h = (h<<1) + *s++; \ h %= size;} #ifdef __USE_PROTOS Entry *hash_get(Entry **, char *), **newHashTable(void), *hash_add(Entry **, char *, Entry *); void killHashTable(Entry **); #else Entry *hash_get(), **newHashTable(), *hash_add(); void killHashTable(); /* MR9 23-Sep-97 */ #endif cdrdao-cdrdao-f00afb2/pccts/antlr/lex.c000066400000000000000000000547711511453746600201040ustar00rootroot00000000000000/* * lex.c -- Generate all of the lexical type files: parser.dlg tokens.h * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2001 */ #include #include /* MR1 */ /* MR1 10-Apr-97 MR1 Replace use of __STDC__ with __USE_PROTOS */ /* MR1 */ #include "pcctscfg.h" #include "set.h" #include "syn.h" #include "hash.h" #include "generic.h" #define DLGErrorString "invalid token" /* Generate a complete lexical description of the lexemes found in the grammar */ void #ifdef __USE_PROTOS genLexDescr( void ) #else genLexDescr( ) #endif { ListNode *p; FILE *dlgFile = fopen(OutMetaName(DlgFileName), "w"); require(dlgFile!=NULL, eMsg1("genLexFile: cannot open %s", OutMetaName(DlgFileName)) ); #ifdef SPECIAL_FOPEN special_fopen_actions(OutMetaName(DlgFileName)); /* MR1 */ #endif fprintf(dlgFile, "<<\n"); fprintf(dlgFile, "/* %s -- DLG Description of scanner\n", DlgFileName); fprintf(dlgFile, " *\n"); fprintf(dlgFile, " * Generated from:"); {int i; for (i=0; i 1 ) fprintf(dlgFile, "#define LL_K %d\n", OutputLL_k); if ( DemandLookahead ) fprintf(dlgFile, "#define DEMAND_LOOK\n"); if (TraceGen) { fprintf(dlgFile,"#ifndef zzTRACE_RULES\n"); /* MR20 */ fprintf(dlgFile,"#define zzTRACE_RULES\n"); /* MR20 */ fprintf(dlgFile,"#endif\n"); /* MR22 */ }; fprintf(dlgFile, "#include \"antlr.h\"\n"); if ( GenAST ) { fprintf(dlgFile, "#include \"ast.h\"\n"); } if ( UserDefdTokens ) fprintf(dlgFile, "#include %s\n", UserTokenDefsFile); /* still need this one as it has the func prototypes */ fprintf(dlgFile, "#include \"%s\"\n", DefFileName); fprintf(dlgFile, "#include \"dlgdef.h\"\n"); fprintf(dlgFile, "LOOKAHEAD\n"); fprintf(dlgFile, "\n"); fprintf(dlgFile, "void\n"); fprintf(dlgFile, "#ifdef __USE_PROTOS\n"); fprintf(dlgFile, "zzerraction(void)\n"); fprintf(dlgFile, "#else\n"); fprintf(dlgFile, "zzerraction()\n"); fprintf(dlgFile, "#endif\n"); fprintf(dlgFile, "{\n"); fprintf(dlgFile, "\t(*zzerr)(\"%s\");\n", DLGErrorString); fprintf(dlgFile, "\tzzadvance();\n"); fprintf(dlgFile, "\tzzskip();\n"); fprintf(dlgFile, "}\n"); } fprintf(dlgFile, ">>\n\n"); /* dump all actions */ /* MR1 */ /* MR1 11-Apr-97 Provide mechanism for inserting code into DLG class */ /* MR1 via <<%%lexmember ....>> & <<%%lexprefix ...>> */ /* MR1 */ if (LexActions != NULL) { for (p = LexActions->next; p!=NULL; p=p->next) { /* MR1 */ fprintf(dlgFile, "<<%%%%lexaction\n"); dumpAction( (char *)p->elem, dlgFile, 0, -1, 0, 1 ); fprintf(dlgFile, ">>\n\n"); } }; /* MR1 */ if (GenCC) { /* MR1 */ fprintf(dlgFile,"<<%%%%parserclass %s>>\n\n",CurrentClassName); /* MR1 */ }; /* MR1 */ if (LexPrefixActions != NULL) { /* MR1 */ for (p = LexPrefixActions->next; p!=NULL; p=p->next) /* MR1 */ { /* MR1 */ fprintf(dlgFile, "<<%%%%lexprefix\n"); /* MR1 */ dumpAction( (char *)p->elem, dlgFile, 0, -1, 0, 1 ); /* MR1 */ fprintf(dlgFile, ">>\n\n"); /* MR1 */ } /* MR1 */ }; /* MR1 */ if (LexMemberActions != NULL) { /* MR1 */ for (p = LexMemberActions->next; p!=NULL; p=p->next) /* MR1 */ { /* MR1 */ fprintf(dlgFile, "<<%%%%lexmember\n"); /* MR1 */ dumpAction( (char *)p->elem, dlgFile, 0, -1, 0, 1 ); /* MR1 */ fprintf(dlgFile, ">>\n\n"); /* MR1 */ } /* MR1 */ }; /* dump all regular expression rules/actions (skip sentinel node) */ if ( ExprOrder == NULL ) { warnNoFL("no regular expressions found in grammar"); } else dumpLexClasses(dlgFile); fprintf(dlgFile, "%%%%\n"); fclose( dlgFile ); } /* For each lexical class, scan ExprOrder looking for expressions * in that lexical class. Print out only those that match. * Each element of the ExprOrder list has both an expr and an lclass * field. */ void #ifdef __USE_PROTOS dumpLexClasses( FILE *dlgFile ) #else dumpLexClasses( dlgFile ) FILE *dlgFile; #endif { int i; TermEntry *t; ListNode *p; Expr *q; for (i=0; inext; p!=NULL; p=p->next) { q = (Expr *) p->elem; if ( q->lclass != i ) continue; lexmode(i); t = (TermEntry *) hash_get(Texpr, q->expr); require(t!=NULL, eMsg1("genLexDescr: rexpr %s not in hash table",q->expr) ); if ( t->token == EpToken ) continue; fprintf(dlgFile, "%s\n\t<<\n", StripQuotes(q->expr)); /* replace " killed by StripQuotes() */ q->expr[ strlen(q->expr) ] = '"'; if ( !GenCC ) { if ( TokenString(t->token) != NULL ) fprintf(dlgFile, "\t\tNLA = %s;\n", TokenString(t->token)); else fprintf(dlgFile, "\t\tNLA = %d;\n", t->token); } if ( t->action != NULL ) dumpAction( t->action, dlgFile, 2,-1,0,1 ); if ( GenCC ) { if ( TokenString(t->token) != NULL ) fprintf(dlgFile, "\t\treturn %s;\n", TokenString(t->token)); else fprintf(dlgFile, "\t\treturn (ANTLRTokenType)%d;\n", t->token); } fprintf(dlgFile, "\t>>\n\n"); } } } /* Strip the leading path (if any) from a filename */ char * #ifdef __USE_PROTOS StripPath( char *fileName ) #else StripPath( fileName ) char *fileName; #endif { char *p; static char dirSym[2] = DirectorySymbol; if(NULL != (p = strrchr(fileName, dirSym[0]))) p++; else p = fileName; return(p); } /* Generate a list of #defines && list of struct definitions for * aggregate retv's */ void #ifdef __USE_PROTOS genDefFile( void ) #else genDefFile( ) #endif { int i; /* If C++ mode and #tokdef used, then don't need anything in here since * C++ puts all definitions in the class file name. */ if ( GenCC && UserTokenDefsFile ) return; if ( MR_Inhibit_Tokens_h_Gen) return; DefFile = fopen(OutMetaName(DefFileName), "w"); require(DefFile!=NULL, eMsg1("genDefFile: cannot open %s", OutMetaName(DefFileName)) ); #ifdef SPECIAL_FOPEN special_fopen_actions(OutMetaName(DefFileName)); /* MR1 */ #endif fprintf(DefFile, "#ifndef %s\n", StripPath(gate_symbol(DefFileName))); fprintf(DefFile, "#define %s\n", StripPath(gate_symbol(DefFileName))); fprintf(DefFile, "/* %s -- List of labelled tokens and stuff\n", DefFileName); fprintf(DefFile, " *\n"); fprintf(DefFile, " * Generated from:"); for (i=0; i1 ) { int j; /* look in all lexclasses for the reg expr */ /* MR10 Derek Pappas */ /* MR10 A #tokclass doesn't have associated regular expressiones */ /* MR10 so don't warn user about it's omission */ p = (TermEntry *) hash_get(Tname, TokenString(i)); if (p != NULL && ! p->classname) { for (j=0; j=NumLexClasses ) { warnNoFL(eMsg1("token label has no associated rexpr: %s",TokenString(i))); } }; } require((p=(TermEntry *)hash_get(Tname, TokenString(i))) != NULL, "token not in sym tab when it should be"); if ( !p->classname ) { if ( GenCC ) { if ( !first ) fprintf(DefFile, ",\n"); first = 0; fprintf(DefFile, "\t%s=%d", TokenString(i), i); } else fprintf(DefFile, "#define %s %d\n", TokenString(i), i); } } } /* MR1 */ /* MR1 10-Apr-97 133MR1 Prevent use of varying sizes of integer */ /* MR1 for the enum ANTLRTokenType */ /* MR1 */ if ( GenCC ) { /* MR1 */ if ( !first ) fprintf(DefFile, ",\n"); /* MR14 */ fprintf(DefFile, "\tDLGminToken=0"); /* MR1 */ fprintf(DefFile, ",\n\tDLGmaxToken=9999};\n"); /* MR1 */ }; /* MR1 */ } if ( !GenCC ) GenRulePrototypes(DefFile, SynDiag); fprintf(DefFile, "\n#endif\n"); } void #ifdef __USE_PROTOS GenRemapFile( void ) #else GenRemapFile( ) #endif { if ( strcmp(ParserName, DefaultParserName)!=0 ) { FILE *f; int i; f = fopen(OutMetaName(RemapFileName), "w"); require(f!=NULL, eMsg1("GenRemapFile: cannot open %s", OutMetaName(RemapFileName)) ); #ifdef SPECIAL_FOPEN special_fopen_actions(OutMetaName(RemapFileName)); /* MR1 */ #endif fprintf(f, "/* %s -- List of symbols to remap\n", RemapFileName); fprintf(f, " *\n"); fprintf(f, " * Generated from:"); for (i=0; irname, ParserName, p->rname); p = (Junction *)p->p2; } } /* Generate a bunch of #defines that rename all standard symbols to be * "ParserName_symbol". The list of standard symbols to change is in * globals.c. */ void #ifdef __USE_PROTOS GenPredefinedSymbolRedefs( FILE *f ) #else GenPredefinedSymbolRedefs( f ) FILE *f; #endif { char **p; fprintf(f, "\n/* rename PCCTS-supplied symbols to be 'ParserName_symbol' */\n"); for (p = &StandardSymbols[0]; *p!=NULL; p++) { fprintf(f, "#define %s %s_%s\n", *p, ParserName, *p); } } /* Generate a bunch of #defines that rename all AST symbols to be * "ParserName_symbol". The list of AST symbols to change is in * globals.c. */ void #ifdef __USE_PROTOS GenASTSymbolRedefs( FILE *f ) #else GenASTSymbolRedefs( f ) FILE *f; #endif { char **p; fprintf(f, "\n/* rename PCCTS-supplied AST symbols to be 'ParserName_symbol' */\n"); for (p = &ASTSymbols[0]; *p!=NULL; p++) { fprintf(f, "#define %s %s_%s\n", *p, ParserName, *p); } } /* redefine all sets generated by ANTLR; WARNING: 'zzerr', 'setwd' must match * use in bits.c (DumpSetWd() etc...) */ void #ifdef __USE_PROTOS GenSetRedefs( FILE *f ) #else GenSetRedefs( f ) FILE *f; #endif { int i; for (i=1; i<=wordnum; i++) { fprintf(f, "#define setwd%d %s_setwd%d\n", i, ParserName, i); } for (i=1; i<=esetnum; i++) { fprintf(f, "#define zzerr%d %s_err%d\n", i, ParserName, i); } } /* Find all return types/parameters that require structs and def * all rules with ret types. * * This is for the declaration, not the definition. */ void #ifdef __USE_PROTOS GenRulePrototypes( FILE *f, Junction *p ) #else GenRulePrototypes( f, p ) FILE *f; Junction *p; #endif { int i; i = 1; while ( p!=NULL ) { if ( p->ret != NULL ) { /* MR23 */ if ( hasMultipleOperands(p->ret) ) { DumpRetValStruct(f, p->ret, i); } fprintf(f, "\n#ifdef __USE_PROTOS\n"); /* MR23 */ if ( hasMultipleOperands(p->ret) ) { fprintf(f, "extern struct _rv%d", i); } else { fprintf(f, "extern "); DumpType(p->ret, f); } fprintf(f, " %s%s(", RulePrefix, p->rname); DumpANSIFunctionArgDef(f,p,1 /* emit initializers ? */); fprintf(f, ";\n"); fprintf(f, "#else\n"); /* MR23 */ if ( hasMultipleOperands(p->ret) ) { fprintf(f, "extern struct _rv%d", i); } else { fprintf(f, "extern "); DumpType(p->ret, f); } fprintf(f, " %s%s();\n", RulePrefix, p->rname); fprintf(f, "#endif\n"); } else { fprintf(f, "\n#ifdef __USE_PROTOS\n"); fprintf(f, "void %s%s(", RulePrefix, p->rname); DumpANSIFunctionArgDef(f,p, 1 /* emit initializers ? */ ); fprintf(f, ";\n"); #ifdef OLD if ( p->pdecl != NULL || GenAST ) { if ( GenAST ) { fprintf(f, "AST **%s",(p->pdecl!=NULL)?",":""); } if ( p->pdecl!=NULL ) fprintf(f, "%s", p->pdecl); } else fprintf(f, "void"); fprintf(f, ");\n"); #endif fprintf(f, "#else\n"); fprintf(f, "extern void %s%s();\n", RulePrefix, p->rname); fprintf(f, "#endif\n"); } i++; p = (Junction *)p->p2; } } /* Define all rules in the class.h file; generate any required * struct definitions first, however. */ void #ifdef __USE_PROTOS GenRuleMemberDeclarationsForCC( FILE *f, Junction *q ) #else GenRuleMemberDeclarationsForCC( f, q ) FILE *f; Junction *q; #endif { Junction *p = q; int i; fprintf(f, "private:\n"); /* Dump dflt handler declaration */ fprintf(f, "\tvoid zzdflthandlers( int _signal, int *_retsignal );\n\n"); fprintf(f, "public:\n"); /* Dump return value structs */ i = 1; while ( p!=NULL ) { if ( p->ret != NULL ) { /* MR23 */ if ( hasMultipleOperands(p->ret) ) { DumpRetValStruct(f, p->ret, i); } } i++; p = (Junction *)p->p2; } /* Dump member func defs && CONSTRUCTOR */ fprintf(f, "\t%s(ANTLRTokenBuffer *input);\n", CurrentClassName); /* fprintf(f, "\t%s(ANTLRTokenBuffer *input, ANTLRTokenType eof);\n", CurrentClassName); */ i = 1; p = q; while ( p!=NULL ) { if ( p->ret != NULL ) { /* MR23 */ if ( hasMultipleOperands(p->ret) ) { fprintf(f, "\tstruct _rv%d", i); } else { fprintf(f, "\t"); DumpType(p->ret, f); } fprintf(f, " %s%s(",RulePrefix,p->rname); DumpANSIFunctionArgDef(f,p, 1 /* emit initializers ? */ ); fprintf(f, ";\n"); #ifdef OLD if ( p->pdecl != NULL || GenAST ) { if ( GenAST ) fprintf(f, "ASTBase **%s",(p->pdecl!=NULL)?",":""); if ( p->pdecl!=NULL ) fprintf(f, "%s", p->pdecl); } fprintf(f, ");\n"); #endif } else { fprintf(f, "\tvoid %s%s(",RulePrefix,p->rname); DumpANSIFunctionArgDef(f,p, 1 /* emit initializers ? */); fprintf(f, ";\n"); #ifdef OLD if ( p->pdecl != NULL || GenAST ) { if ( GenAST ) fprintf(f, "ASTBase **%s",(p->pdecl!=NULL)?",":""); if ( p->pdecl!=NULL ) fprintf(f, "%s", p->pdecl); } fprintf(f, ");\n"); #endif } i++; p = (Junction *)p->p2; } } /* Given a list of ANSI-style parameter declarations, print out a * comma-separated list of the symbols (w/o types). * Basically, we look for a comma, then work backwards until start of * the symbol name. Then print it out until 1st non-alnum char. Now, * move on to next parameter. * */ /* MR5 Jan Mikkelsen 26-May-97 - added initalComma parameter */ void #ifdef __USE_PROTOS DumpListOfParmNames(char *pdecl, FILE *output, int initialComma) /* MR5 */ #else DumpListOfParmNames(pdecl, output, initialComma) /* MR5 */ char *pdecl; /* MR5 */ FILE *output; /* MR5 */ int initialComma; /* MR5 */ #endif { int firstTime = 1, done = 0; require(output!=NULL, "DumpListOfParmNames: NULL parm"); if ( pdecl == NULL ) return; while ( !done ) { if ( !firstTime || initialComma ) putc(',', output); /* MR5 */ done = DumpNextNameInDef(&pdecl, output); firstTime = 0; } } /* given a list of parameters or return values, dump the next * name to output. Return 1 if last one just printed, 0 if more to go. */ /* MR23 Total rewrite */ int #ifdef __USE_PROTOS DumpNextNameInDef( char **q, FILE *output ) #else DumpNextNameInDef( q, output ) char **q; FILE *output; #endif { char *p; char *t; char *pDataType; char *pSymbol; char *pEqualSign; char *pValue; char *pSeparator; int nest = 0; p = endFormal(*q, &pDataType, &pSymbol, &pEqualSign, &pValue, &pSeparator, &nest); /* MR26 Handle rule arguments such as: IIR_Bool (IIR_Decl::*contstraint)() For this we need to strip off anything which follows the symbol. */ /* MR26 */ t = pSymbol; /* MR26 */ if (t != NULL) { /* MR26 */ for (t = pSymbol; *t != 0; t++) { /* MR26 */ if (! (isalpha(*t) || isdigit(*t) || *t == '_' || *t == '$')) break; /* MR26 */ } /* MR26 */ } /* MR26 */ fprintf(output,"%s",strBetween(pSymbol, t, pSeparator)); *q = p; return (*pSeparator == 0); } /* Given a list of ANSI-style parameter declarations, dump K&R-style * declarations, one per line for each parameter. Basically, convert * comma to semi-colon, newline. */ void #ifdef __USE_PROTOS DumpOldStyleParms( char *pdecl, FILE *output ) #else DumpOldStyleParms( pdecl, output ) char *pdecl; FILE *output; #endif { require(output!=NULL, "DumpOldStyleParms: NULL parm"); if ( pdecl == NULL ) return; while ( *pdecl != '\0' ) { if ( *pdecl == ',' ) { pdecl++; putc(';', output); putc('\n', output); while ( *pdecl==' ' || *pdecl=='\t' || *pdecl=='\n' ) pdecl++; } else {putc(*pdecl, output); pdecl++;} } putc(';', output); putc('\n', output); } /* Take in a type definition (type + symbol) and print out type only */ /* MR23 Total rewrite */ void #ifdef __USE_PROTOS DumpType( char *s, FILE *f ) #else DumpType( s, f ) char *s; FILE *f; #endif { char *p; char *pDataType; char *pSymbol; char *pEqualSign; char *pValue; char *pSeparator; int nest = 0; require(s!=NULL, "DumpType: invalid type string"); p = endFormal(s, &pDataType, &pSymbol, &pEqualSign, &pValue, &pSeparator, &nest); fprintf(f,"%s",strBetween(pDataType, pSymbol, pSeparator)); } /* check to see if string e is a word in string s */ int #ifdef __USE_PROTOS strmember( char *s, char *e ) #else strmember( s, e ) char *s; char *e; #endif { register char *p; require(s!=NULL&&e!=NULL, "strmember: NULL string"); if ( *e=='\0' ) return 1; /* empty string is always member */ do { while ( *s!='\0' && !isalnum(*s) && *s!='_' ) ++s; p = e; while ( *p!='\0' && *p==*s ) {p++; s++;} if ( *p=='\0' ) { if ( *s=='\0' ) return 1; if ( !isalnum (*s) && *s != '_' ) return 1; } while ( isalnum(*s) || *s == '_' ) ++s; } while ( *s!='\0' ); return 0; } #if 0 /* MR23 Replaced by hasMultipleOperands() */ int #ifdef __USE_PROTOS HasComma( char *s ) #else HasComma( s ) char *s; #endif { while (*s!='\0') if ( *s++ == ',' ) return 1; return 0; } #endif /* MR23 Total rewrite */ void #ifdef __USE_PROTOS DumpRetValStruct( FILE *f, char *ret, int i ) #else DumpRetValStruct( f, ret, i ) FILE *f; char *ret; int i; #endif { char *p = ret; char *pDataType; char *pSymbol; char *pEqualSign; char *pValue; char *pSeparator; int nest = 0; fprintf(f, "\nstruct _rv%d {\n", i); while (*p != 0 && nest == 0) { p = endFormal(p, &pDataType, &pSymbol, &pEqualSign, &pValue, &pSeparator, &nest); fprintf(f,"\t"); fprintf(f,"%s",strBetween(pDataType, pSymbol, pSeparator)); fprintf(f," "); fprintf(f,"%s",strBetween(pSymbol, pEqualSign, pSeparator)); fprintf(f,";\n"); } fprintf(f,"};\n"); } /* given "s" yield s -- DESTRUCTIVE (we modify s if starts with " else return s) */ char * #ifdef __USE_PROTOS StripQuotes( char *s ) #else StripQuotes( s ) char *s; #endif { if ( *s == '"' ) { s[ strlen(s)-1 ] = '\0'; /* remove last quote */ return( s+1 ); /* return address past initial quote */ } return( s ); } cdrdao-cdrdao-f00afb2/pccts/antlr/main.c000066400000000000000000001444611511453746600202340ustar00rootroot00000000000000/* * main.c -- main program for PCCTS ANTLR. * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2001 */ /* To set a breakpoint just before exit look for "cleanUp". */ #include #include "pcctscfg.h" #include "stdpccts.h" #define MAX_INT_STACK 50 static int istack[MAX_INT_STACK]; /* Int stack */ static int isp = MAX_INT_STACK; static int DontAcceptFiles = 0; /* if stdin, don't read files */ static int DontAcceptStdin = 0; /* if files seen first, don't accept stdin */ static int tnodes_used_in_guard_predicates_etc; /* MR10 */ /* C m d - L i n e O p t i o n S t r u c t & F u n c s */ typedef struct _Opt { char *option; int arg; #ifdef __cplusplus void (*process)(...); #else void (*process)(); #endif char *descr; } Opt; #ifdef __USE_PROTOS extern void ProcessArgs(int, char **, Opt *); #else extern void ProcessArgs(); #endif #ifdef __USE_PROTOS int ci_strequ(char *a,char *b) #else int ci_strequ(a,b) char *a; char *b; #endif { for ( ;*a != 0 && *b != 0; a++, b++) { if (toupper(*a) != toupper(*b)) return 0; } return (*a == *b); } static void #ifdef __USE_PROTOS pStdin( void ) #else pStdin( ) #endif { if ( DontAcceptStdin ) { warnNoFL("'-' (stdin) ignored as files were specified first"); return; } require(NumFiles 8 ) { /* MR6 */ warnNoFL("tab width must be between 1 and 8"); /* MR6 */ TabWidth=0; /* MR6 */ } /* MR6 */ } /* MR6 */ static int ambAidDepthSpecified=0; /* MR11 */ static void /* MR11 */ #ifdef __USE_PROTOS pAAd( char *s, char *t ) /* MR11 */ #else pAAd( s, t ) /* MR11 */ char *s; /* MR11 */ char *t; /* MR11 */ #endif { /* MR11 */ ambAidDepthSpecified=1; /* MR11 */ MR_AmbAidDepth = atoi(t); /* MR11 */ } /* MR11 */ static void /* MR11 */ #ifdef __USE_PROTOS pTreport( char *s, char *t ) /* MR11 */ #else pTreport( s, t ) /* MR11 */ char *s; /* MR11 */ char *t; /* MR11 */ #endif { /* MR11 */ TnodesReportThreshold = atoi(t); /* MR11 */ } /* MR11 */ #ifdef __USE_PROTOS void chkGTFlag(void) /* 7-Apr-97 MR1 */ #else void chkGTFlag() /* 7-Apr-97 MR1 */ #endif { if ( !GenAST ) warn("#-variable or other AST item referenced w/o -gt option"); } #ifdef __USE_PROTOS static void pInfo(char *s, char *t) /* MR10 */ #else static void pInfo(s,t) /* MR10 */ char *s; char *t; #endif { char *p; int q; for (p=t; *p != 0; p++) { q=tolower(*p); if (q=='t') { InfoT=1; } else if (q=='p') { InfoP=1; } else if (q=='m') { InfoM=1; } else if (q=='o') { InfoO=1; } else if (q=='0') { ; /* nothing */ } else if (q=='f') { InfoF=1; } else { warnNoFL(eMsgd("unrecognized -info option \"%c\"",(int)*p)); }; }; } #ifdef __USE_PROTOS static void pCGen(void) { CodeGen = FALSE; LexGen = FALSE; } static void pLGen(void) { LexGen = FALSE; } static void pXTGen(void){ MR_Inhibit_Tokens_h_Gen = TRUE; } static void pTGen(void) { TraceGen = TRUE; } static void pSGen(void) { GenExprSetsOpt = FALSE; } static void pPrt(void) { PrintOut = TRUE; pCGen(); pLGen(); } static void pPrtA(void) { PrintOut = TRUE; PrintAnnotate = TRUE; pCGen(); pLGen(); } static void pAst(void) { GenAST = TRUE; } static void pANSI(void) { GenANSI = TRUE; } static void pCr(void) { GenCR = TRUE; } static void pNOPURIFY(void) { PURIFY = FALSE; } /*static void pCt(void) { warnNoFL("-ct option is now the default"); }*/ static void pLI(void) { GenLineInfo = TRUE; GenLineInfoMS = FALSE; } /* MR14 */ static void pLIms(void) { GenLineInfo = TRUE; GenLineInfoMS = TRUE; } /* MR14 */ static void pFr(char *s, char *t) {RemapFileName = t;} static void pFe(char *s, char *t) {ErrFileName = t;} static void pFl(char *s, char *t) {DlgFileName = t;} static void pFm(char *s, char *t) {ModeFileName = t;} static void pFt(char *s, char *t) {DefFileName = t;} static void pE1(void) { elevel = 1; } static void pE2(void) { elevel = 2; } static void pE3(void) { elevel = 3; } static void pEGen(void) { GenEClasseForRules = 1; } static void pDL(void) { DemandLookahead = 1; if ( GenCC ) { warnNoFL("-gk does not work currently in C++ mode; -gk turned off"); DemandLookahead = 0; } } static void pAA(char *s,char *t) {MR_AmbAidRule = t;} /* MR11 */ static void pAAm(char *s){MR_AmbAidMultiple = 1;} /* MR11 */ static void pGHdr(void) { GenStdPccts = 1; } static void pFHdr(char *s, char *t) { stdpccts = t; pGHdr(); } static void pW1(void) { WarningLevel = 1; } static void pNewAST(void) { NewAST = 1; } /* MR13 */ static void ptmakeInParser(void) { tmakeInParser = 1; } /* MR23 */ static void pAlpha(void) { AlphaBetaTrace = 1; } /* MR14 */ static void pMR_BlkErr(void) { MR_BlkErr = 1; } /* MR21 */ static void pStdout(void) {UseStdout = 1; } /* MR6 */ static void pW2(void) { WarningLevel = 2; } static void pCC(void) { GenCC = TRUE; } #else static void pCGen() { CodeGen = FALSE; LexGen = FALSE; } static void pLGen() { LexGen = FALSE; } static void pXTGen(){ MR_Inhibit_Tokens_h_Gen = TRUE; } /* MR14 */ static void pTGen() { TraceGen = TRUE; } static void pSGen() { GenExprSetsOpt = FALSE; } static void pPrt() { PrintOut = TRUE; pCGen(); pLGen(); } static void pPrtA() { PrintOut = TRUE; PrintAnnotate = TRUE; pCGen(); pLGen(); } static void pAst() { GenAST = TRUE; } static void pANSI() { GenANSI = TRUE; } static void pCr() { GenCR = TRUE; } static void pNOPURIFY() { PURIFY = FALSE; } /*static void pCt() { warnNoFL("-ct option is now the default"); }*/ static void pLI() { GenLineInfo = TRUE; GenLineInfoMS = FALSE; } /* MR14 */ static void pLIms() { GenLineInfo = TRUE; GenLineInfoMS = TRUE; } /* MR14 */ static void pFr(s,t) char *s, *t; {RemapFileName = t;} static void pFe(s,t) char *s, *t; {ErrFileName = t;} static void pFl(s,t) char *s, *t; {DlgFileName = t;} static void pFm(s,t) char *s, *t; {ModeFileName = t;} static void pFt(s,t) char *s, *t; {DefFileName = t;} static void pE1() { elevel = 1; } static void pE2() { elevel = 2; } static void pE3() { elevel = 3; } static void pEGen() { GenEClasseForRules = 1; } static void pDL() { DemandLookahead = 1; if ( GenCC ) { warnNoFL("-gk does not work currently in C++ mode; -gk turned off"); DemandLookahead = 0; } } static void pAA(s,t) char *s; char *t; {MR_AmbAidRule = t;} /* MR11 BJS 20-Mar-98 */ static void pAAm(s) char *s; {MR_AmbAidMultiple = 1;} /* MR11 BJS 20-Mar-98 */ static void pGHdr() { GenStdPccts = 1; } static void pFHdr(s,t) char *s, *t; { stdpccts = t; pGHdr(); } static void pW1() { WarningLevel = 1; } static void pNewAST() { NewAST = 1; } /* MR13 */ static void ptmakeInParser() { tmakeInParser = 1; } /* MR23 */ static void pAlpha() { AlphaBetaTrace = 1; } /* MR14 */ static void pMR_BlkErr() { MR_BlkErr = 1; } /* MR21 */ static void pStdout() {UseStdout = 1; } /* MR6 */ static void pW2() { WarningLevel = 2; } static void pCC() { GenCC = TRUE; } #endif static void #ifdef __USE_PROTOS pPre( char *s, char *t ) #else pPre( s, t ) char *s; char *t; #endif { RulePrefix = t; } static void #ifdef __USE_PROTOS pOut( char *s, char *t ) #else pOut( s, t ) char *s; char *t; #endif { OutputDirectory = t; } static void #ifdef __USE_PROTOS pPred( void ) #else pPred( ) #endif { warnNoFL("-pr is no longer used (predicates employed if present); see -prc, -mrhoist, -mrhoistk"); /* ** if ( DemandLookahead ) ** warnNoFL("-gk conflicts with -pr; -gk turned off"); ** DemandLookahead = 0; ** HoistPredicateContext = 0; */ } static void #ifdef __USE_PROTOS pPredCtx( char *s, char *t ) #else pPredCtx(s,t) char *s; char *t; #endif { if ( ci_strequ(t,"on")) HoistPredicateContext = 1; else if ( ci_strequ(t,"off")) HoistPredicateContext = 0; if ( DemandLookahead ) { warnNoFL("-gk incompatible with semantic predicate usage; -gk turned off"); DemandLookahead = 0; } } static void #ifdef __USE_PROTOS pMRhoist( char *s, char *t ) #else pMRhoist(s,t) char *s; char *t; #endif { if ( ci_strequ(t,"on")) MRhoisting = 1; else if ( ci_strequ(t,"off")==0 ) MRhoisting = 0; if (MRhoisting) { fprintf(stderr,"Maintenance Release style hoisting enabled for predicates with lookahead depth = 1\n"); fprintf(stderr," No longer considered experimental\n"); fprintf(stderr," Can't consider suppression for predicates with lookahead depth > 1\n"); fprintf(stderr," Implies -prc on but does *not* imply -mrhoistk for k>1 predicates\n"); fprintf(stderr," This is a reminder, not a warning or error.\n"); }; } static void #ifdef __USE_PROTOS pMRhoistk( char *s, char *t ) #else pMRhoistk(s,t) char *s; char *t; #endif { if ( ci_strequ(t,"on")) MRhoistingk = 1; else if ( ci_strequ(t,"off")==0 ) MRhoistingk = 0; if (MRhoistingk) { fprintf(stderr,"EXPERIMENTAL Maintenance Release style hoisting enabled\n"); fprintf(stderr," Applies to predicates with lookahead depth > 1\n"); fprintf(stderr," Implies -prc on and -mrhoist on\n"); }; } static void #ifdef __USE_PROTOS pTRes( char *s, char *t ) #else pTRes( s, t ) char *s; char *t; #endif { TreeResourceLimit = atoi(t); if ( TreeResourceLimit <= 0 ) { warnNoFL("analysis resource limit (# of tree nodes) must be greater than 0"); TreeResourceLimit = -1; /* set to no limit */ } } Opt options[] = { #ifdef __cplusplus { "-CC", 0, (void (*)(...)) pCC, "Generate C++ output (default=FALSE)"}, { "-ck", 1, (void (*)(...)) pCk, "Set compressed lookahead depth; fast approximate lookahead"}, { "-cr", 0, (void (*)(...)) pCr, "Generate cross reference (default=FALSE)"}, { "-e1", 0, (void (*)(...)) pE1, "Ambiguities/errors shown in low detail (default)"}, { "-e2", 0, (void (*)(...)) pE2, "Ambiguities/errors shown in more detail"}, { "-e3", 0, (void (*)(...)) pE3, "Ambiguities for k>1 grammars shown with exact tuples (not lookahead sets)"}, { "-f", 1, (void (*)(...)) pFileList,"Read names of grammar files from specified file"}, /* MR14 */ { "-fe", 1, (void (*)(...)) pFe, "Rename err.c"}, { "-fh", 1, (void (*)(...)) pFHdr, "Rename stdpccts.h header (turns on -gh)"}, { "-fl", 1, (void (*)(...)) pFl, "Rename lexical output--parser.dlg"}, { "-fm", 1, (void (*)(...)) pFm, "Rename mode.h"}, { "-fr", 1, (void (*)(...)) pFr, "Rename remap.h"}, { "-ft", 1, (void (*)(...)) pFt, "Rename tokens.h"}, { "-ga", 0, (void (*)(...)) pANSI, "Generate ANSI-compatible code (default=FALSE)"}, { "-gc", 0, (void (*)(...)) pCGen, "Do not generate output parser code (default=FALSE)"}, { "-gd", 0, (void (*)(...)) pTGen, "Generate code to trace rule invocation (default=FALSE)"}, { "-ge", 0, (void (*)(...)) pEGen, "Generate an error class for each non-terminal (default=FALSE)"}, { "-gh", 0, (void (*)(...)) pGHdr, "Generate stdpccts.h for non-ANTLR-generated-files to include"}, { "-gk", 0, (void (*)(...)) pDL, "Generate parsers that delay lookahead fetches until needed"}, { "-gl", 0, (void (*)(...)) pLI, "Generate line info about grammar actions in parser"}, { "-glms", 0, (void (*)(...)) pLIms,"Like -gl but replace '\\' with '/' in #line filenames for MS C/C++ systems"}, { "-gp", 1, (void (*)(...)) pPre, "Prefix all generated rule functions with a string"}, { "-gs", 0, (void (*)(...)) pSGen, "Do not generate sets for token expression lists (default=FALSE)"}, { "-gt", 0, (void (*)(...)) pAst, "Generate code for Abstract-Syntax-Trees (default=FALSE)"}, { "-gx", 0, (void (*)(...)) pLGen, "Do not generate lexical (dlg-related) files (default=FALSE)"}, { "-gxt",0, (void (*)(...)) pXTGen, "Do not generate tokens.h (default=FALSE)"}, { "-k", 1, (void (*)(...)) pLLK, "Set full LL(k) lookahead depth (default==1)"}, { "-o", 1, (void (*)(...)) pOut, OutputDirectoryOption}, { "-p", 0, (void (*)(...)) pPrt, "Print out the grammar w/o actions (default=no)"}, { "-pa", 0, (void (*)(...)) pPrtA, "Print out the grammar w/o actions & w/FIRST sets (default=no)"}, { "-pr",0, (void (*)(...)) pPred, "no longer used; predicates employed if present"}, { "-prc", 1, (void (*)(...)) pPredCtx,"Turn on/off computation of context for hoisted predicates"}, { "-rl", 1, (void (*)(...)) pTRes, "Limit max # of tree nodes used by grammar analysis"}, { "-stdout",0, (void (*)(...)) pStdout,"Send grammar.c/grammar.cpp to stdout"}, /* MR6 */ { "-tab", 1, (void (*)(...)) pTab, "Width of tabs (1 to 8) for grammar.c/grammar.cpp files"}, /* MR6 */ { "-w1", 0, (void (*)(...)) pW1, "Set the warning level to 1 (default)"}, { "-w2", 0, (void (*)(...)) pW2, "Ambiguities yield warnings even if predicates or (...)? block"}, { "-", 0, (void (*)(...)) pStdin, "Read grammar from stdin" }, { "-mrhoist",1, (void (*)(...)) pMRhoist, /* MR9 */ "Turn on/off k=1 Maintenance Release style hoisting"}, /* MR9 */ { "-mrhoistk",1, (void (*)(...)) pMRhoistk, /* MR9 */ "Turn on/off EXPERIMENTAL k>1 Maintenance Release style hoisting"}, /* MR13 */ { "-aa" , 1, (void (*)(...)) pAA, "Ambiguity aid for a rule (rule name or line number)"}, /* MR11 */ { "-aam" , 0, (void (*)(...)) pAAm, "Lookahead token may appear multiple times in -aa listing"}, /* MR11 */ { "-aad" , 1, (void (*)(...)) pAAd, "Limits exp growth of -aa listing - default=1 (max=ck value)"}, /* MR11 */ { "-info", 1, (void (*)(...)) pInfo, "Extra info: p=pred t=tnodes f=first/follow m=monitor o=orphans 0=noop"}, /* MR12 */ { "-treport",1,(void (*)(...)) pTreport, "Report when tnode usage exceeds value during ambiguity resolution"}, /* MR11 */ { "-newAST", 0, (void (*)(...)) pNewAST, "In C++ mode use \"newAST(...)\" rather than \"new AST(...)\""}, /* MR13 */ { "-tmake", 0, (void (*)(...)) ptmakeInParser, "In C++ mode use parser's tmake method rather than \"ASTBase::tmake(...)\""}, /* MR23 */ { "-alpha",0,(void (*)(...)) pAlpha, "Provide additional information for \"(alpha)? beta\" error messages"}, /* MR14 */ { "-mrblkerr",0,(void (*)(...)) pMR_BlkErr, /* MR21 */ "EXPERIMENTAL change to (...)* and (...)+ syntax error sets"}, /* MR21 */ { "-nopurify",0,(void (*)(...)) pNOPURIFY, "Don't use the notorious PURIFY macro (replaced by MR23 initial value syntax) to zero return arguments of rules"}, /* MR23 */ { "*", 0, (void (*)(...)) pFile, "" }, /* anything else is a file */ #else { "-CC", 0, pCC, "Generate C++ output (default=FALSE)"}, { "-cr", 0, pCr, "Generate cross reference (default=FALSE)"}, { "-ck", 1, pCk, "Set compressed lookahead depth; fast approximate lookahead"}, { "-e1", 0, pE1, "Ambiguities/errors shown in low detail (default)"}, { "-e2", 0, pE2, "Ambiguities/errors shown in more detail"}, { "-e3", 0, pE3, "Ambiguities for k>1 grammars shown with exact tuples (not lookahead sets)"}, { "-f", 1, pFileList,"Read names of grammar files from specified file"}, /* MR14 */ { "-fe", 1, pFe, "Rename err.c"}, { "-fh", 1, pFHdr, "Rename stdpccts.h header (turns on -gh)"}, { "-fl", 1, pFl, "Rename lexical output--parser.dlg"}, { "-fm", 1, pFm, "Rename mode.h"}, { "-fr", 1, pFr, "Rename remap.h"}, { "-ft", 1, pFt, "Rename tokens.h"}, { "-ga", 0, pANSI, "Generate ANSI-compatible code (default=FALSE)"}, { "-gc", 0, pCGen, "Do not generate output parser code (default=FALSE)"}, { "-gd", 0, pTGen, "Generate code to trace rule invocation (default=FALSE)"}, { "-ge", 0, pEGen, "Generate an error class for each non-terminal (default=FALSE)"}, { "-gh", 0, pGHdr, "Generate stdpccts.h for non-ANTLR-generated-files to include"}, { "-gk", 0, pDL, "Generate parsers that delay lookahead fetches until needed"}, { "-gl", 0, pLI, "Generate line info about grammar actions in C parser"}, { "-glms", 0, pLIms,"Like -gl but replace '\\' with '/' in #line filenames for MS C/C++ systems"}, { "-gp", 1, pPre, "Prefix all generated rule functions with a string"}, { "-gs", 0, pSGen, "Do not generate sets for token expression lists (default=FALSE)"}, { "-gt", 0, pAst, "Generate code for Abstract-Syntax-Trees (default=FALSE)"}, { "-gx", 0, pLGen, "Do not generate lexical (dlg-related) files (default=FALSE)"}, { "-gxt",0, pXTGen, "Do not generate tokens.h (default=FALSE)"}, { "-k", 1, pLLK, "Set full LL(k) lookahead depth (default==1)"}, { "-o", 1, pOut, OutputDirectoryOption}, { "-p", 0, pPrt, "Print out the grammar w/o actions (default=no)"}, { "-pa", 0, pPrtA, "Print out the grammar w/o actions & w/FIRST sets (default=no)"}, { "-pr",0, pPred, "no longer used; predicates employed if present"}, { "-prc", 1, pPredCtx,"Turn on/off computation of context for hoisted predicates"}, { "-rl", 1, pTRes, "Limit max # of tree nodes used by grammar analysis"}, { "-stdout",0, pStdout, "Send grammar.c/grammar.cpp to stdout"}, /* MR6 */ { "-tab", 1, pTab, "Width of tabs (1 to 8) for grammar.c/grammar.cpp files"}, /* MR6 */ { "-w1", 0, pW1, "Set the warning level to 1 (default)"}, { "-w2", 0, pW2, "Ambiguities yield warnings even if predicates or (...)? block"}, { "-mrhoist",1,pMRhoist, /* MR9 */ "Turn on/off k=1 Maintenance Release style hoisting"}, /* MR9 */ { "-mrhoistk",1,pMRhoistk, /* MR13 */ "Turn on/off k>1 EXPERIMENTAL Maintenance Release style hoisting"}, /* MR13 */ { "-aa" ,1,pAA, "Ambiguity aid for a rule (rule name or line number)"}, /* MR11 */ { "-aam" ,0,pAAm, "Lookahead token may appear multiple times in -aa listing"}, /* MR11 */ { "-aad" ,1,pAAd, "Limits exp growth of -aa listing - default=1 (max=ck value)"}, /* MR11 */ { "-info",1,pInfo, "Extra info: p=pred t=tnodes f=first/follow m=monitor o=orphans 0=noop"}, /* MR11 */ { "-treport",1,pTreport, "Report when tnode usage exceeds value during ambiguity resolution"}, /* MR11 */ { "-newAST", 0, pNewAST, "In C++ mode use \"newAST(...)\" rather than \"new AST(...)\""}, /* MR13 */ { "-tmake", 0, ptmakeInParser, "In C++ mode use parser's tmake method rather than \"ASTBase::tmake(...)\""}, /* MR23 */ { "-alpha",0, pAlpha, "Provide additional information for \"(alpha)? beta\" error messages"}, /* MR14 */ { "-mrblkerr",0,pMR_BlkErr, /* MR21 */ "EXPERIMENTAL change to (...)* and (...)+ syntax error sets"}, /* MR21 */ { "-nopurify",0,pNOPURIFY, "Don't use the notorious PURIFY macro (replaced by MR23 initial value syntax) to zero return arguments of rules"}, /* MR23 */ { "-", 0, pStdin, "Read grammar from stdin" }, { "*", 0, pFile, "" }, /* anything else is a file */ #endif { NULL, 0, NULL } }; void readDescr(); void cleanUp(); #ifdef __USE_PROTOS static void buildRulePtr( void ); static void help( void ); static void init( void ); static void CompleteTokenSetRefs( void ); static void ensure_no_C_file_collisions(char *); static void CompleteContextGuards(void); #else static void buildRulePtr( ); static void help( ); static void init( ); static void CompleteTokenSetRefs( ); static void ensure_no_C_file_collisions(); static void CompleteContextGuards(); #endif static void #ifdef __USE_PROTOS /* */ report_numericPredLabels(ActionNode *a) #else report_numericPredLabels(a) ActionNode *a; #endif { /* MR10 */ warnFL("numeric references to attributes (e.g. $i or $i.j) in semantic pred will be null during guess mode", /* MR10 */ FileStr[a->file],a->line); /* MR10 */ } /* MR10 */ /* M a i n */ int #ifdef __USE_PROTOS main( int argc, char *argv[] ) #else main( argc, argv ) int argc; char *argv[]; #endif { int i; static char EPSTR[] = "[Ep]"; Save_argc=argc; /* MR10 */ Save_argv=argv; /* MR10 */ /* malloc_debug(8);*/ #ifdef SPECIAL_INITS special_inits(); /* MR1 */ #endif fprintf(stderr, "Antlr parser generator Version %s 1989-2001\n", Version); if ( argc == 1 ) { help(); zzDIE; } ProcessArgs(argc-1, &(argv[1]), options); /* MR14 */ if (MR_AmbAidRule && AlphaBetaTrace) { /* MR14 */ fatal("Can't specify both -aa (ambiguity aid) and -alpha (\"(alpha)? beta\" aid)"); /* MR14 */ } if (MRhoistingk) { /* MR13 */ HoistPredicateContext=1; /* MR13 */ MRhoisting=1; /* MR13 */ }; /* MR13 */ if (MRhoisting && ! HoistPredicateContext) { /*** warnNoFL("Using \"-mrhoist\" forces \"-prc on\""); ***/ HoistPredicateContext=1; }; if (HoistPredicateContext && ! MRhoisting) { warnNoFL("When using predicate context (-prc on) -mrhoist on is recommended"); } /* Fix lookahead depth */ /* Compressed lookahead must always be larger than or equal to full lookahead */ if ( CLL_k < LL_k && CLL_k>0 ) { warnNoFL("must have compressed lookahead >= full LL(k) lookahead (setting -ck to -k)"); CLL_k = LL_k; } if ( CLL_k == -1 ) CLL_k = LL_k; OutputLL_k = CLL_k; if ( ((CLL_k-1)&CLL_k)!=0 ) { /* output ll(k) must be power of 2 */ int n; for(n=1; n 1) { warnNoFL("The -mrblkerr option is designed only for k=1 ck=1 grammars"); } }; if ( ! ambAidDepthSpecified) { MR_AmbAidDepth=1; } else { if (MR_AmbAidDepth > CLL_k || MR_AmbAidDepth <= 0) { warnNoFL(eMsgd( "Ambiguity aid depth (\"-aad ...\") must be a number between 1 and max(k,ck)=%d",CLL_k)); MR_AmbAidDepth=1; }; if (MR_AmbAidDepth == 0) { MR_AmbAidDepth=2; }; }; if (MR_AmbAidRule != NULL) MR_AmbAidLine=atoi(MR_AmbAidRule); fpTrans = &(C_Trans[0]); /* Translate to C Language */ fpJTrans = &(C_JTrans[0]); init(); lexclass(LexStartSymbol); readDescr(); LastTokenCounted = TokenNum; RemapForcedTokens(); if ( CannotContinue ) {cleanUp(); zzDIE;} if ( GenCC && no_classes_found ) fatal("required grammar class not found (exiting...)"); if ( WarningLevel>1 && HdrAction == NULL ) warnNoFL("no #header action was found"); if ( FoundAtOperator && ! FoundExceptionGroup) { warnNoFL("found the exception operator '@' - but no exception group was found"); }; EpToken = addTname(EPSTR); /* add imaginary token epsilon */ set_orel(EpToken, &imag_tokens); /* this won't work for hand-built scanners since EofToken is not * known. Forces EOF to be token type 1. */ set_orel(EofToken, &imag_tokens); set_size(NumWords(TokenNum-1)); /* compute the set of all known token types * It represents the set of tokens from 1 to last_token_num + the * reserved positions above that (if any). Don't include the set of * imaginary tokens such as the token/error classes or EOF. */ { set a; a = set_dup(reserved_positions); for (i=1; inext; p!=NULL; p=p->next) { UserAction *ua = (UserAction *)p->elem; dumpAction( ua->action, Parser_h, 0, ua->file, ua->line, 1); } } GenParser_c_Hdr(); fprintf(Parser_h, "protected:\n"); /* MR20 */ NewSetWd(); TRANS(SynDiag); /* Translate to the target language */ DumpSetWd(); GenRuleMemberDeclarationsForCC(Parser_h, SynDiag); if ( class_after_actions != NULL ) { ListNode *p; for (p = class_after_actions->next; p!=NULL; p=p->next) { UserAction *ua = (UserAction *)p->elem; dumpAction( ua->action, Parser_h, 0, ua->file, ua->line, 1); } } DumpRemainingTokSets(); fprintf(Parser_h, "};\n"); fprintf(Parser_h, "\n#endif /* %s_h */\n", CurrentClassName); fclose( Parser_h ); fclose( Parser_c ); } } MR_orphanRules(stderr); if (LTinTokenAction && WarningLevel >= 2) { if (GenCC) { warnNoFL("At least one <> following a token match contains a reference to LT(...)\n this will reference the immediately preceding token,\n not the one which follows as is the case with semantic predicates."); } warnNoFL("At least one <> following a token match contains a reference to LA(...) or LATEXT(...)\n this will reference the immediately preceding token,\n not the one which follows as is the case with semantic predicates."); } if ( PrintOut ) { if ( SynDiag == NULL ) {warnNoFL("no grammar description recognized");} else PRINT(SynDiag); } #ifdef DBG_LL1 #endif GenRemapFile(); /* create remap.h */ /* MR10 */ if (FoundGuessBlk) { #ifdef __cplusplus__ /* MR10 */ list_apply(NumericPredLabels, (void (*)(void *))report_numericPredLabels); #else #ifdef __USE_PROTOS /* MR10 */ list_apply(NumericPredLabels, (void (*)(void *))report_numericPredLabels); #else /* MR10 */ list_apply(NumericPredLabels,report_numericPredLabels); #endif #endif /* MR10 */ }; if (InfoT && TnodesAllocated > 0) { if (TnodesPeak > 10000) { fprintf(stdout,"\nTree Nodes: peak %dk created %dk lost %d\n", (TnodesPeak/1000), (TnodesAllocated/1000), TnodesInUse-tnodes_used_in_guard_predicates_etc); } else { fprintf(stdout,"\nTree Nodes: peak %d created %d lost %d\n", TnodesPeak, TnodesAllocated, TnodesInUse-tnodes_used_in_guard_predicates_etc); }; }; if (InfoF) { DumpFcache(); }; if (MR_skipped_e3_report) { fprintf(stderr,"note: use -e3 to get exact information on ambiguous tuples\n"); }; if (MR_BadExprSets != 0) { fprintf(stderr,"note: Unreachable C or C++ code was generated for empty expression sets,\n"); fprintf(stderr," probably due to undefined rules or infinite left recursion.\n"); fprintf(stderr," To locate: search the generated code for \"empty set expression\"\n"); }; if (MR_AmbAidRule != NULL && MR_matched_AmbAidRule==0) { RuleEntry *q = (RuleEntry *) hash_get(Rname,MR_AmbAidRule); if (MR_AmbAidLine == 0 && q == NULL) { warnNoFL(eMsg2("there is no rule \"%s\" so \"-aa %s\" will never match", MR_AmbAidRule,MR_AmbAidRule)); } else { warnNoFL(eMsg1("there was no ambiguity that matched \"-aa %s\"",MR_AmbAidRule)); }; }; if (AlphaBetaTrace) { if (MR_AlphaBetaMessageCount == 0) { fprintf(stderr,"note: there were no messages about \"(alpha)? beta\" blocks added to the generated code\n"); } else { fprintf(stderr,"note: there were %d messages about \"(alpha)? beta\" blocks added to the generated code\n", MR_AlphaBetaMessageCount); } if (set_null(MR_CompromisedRules)) { fprintf(stderr,"note: the list of rules with compromised follow sets is empty\n"); } else { fprintf(stderr,"note: the following is a list of rules which *may* have incorrect\n"); fprintf(stderr," follow sets computed as a result of an \"(alpha)? beta\" block\n"); fprintf(stderr,"\n"); MR_dumpRuleSet(MR_CompromisedRules); fprintf(stderr,"\n"); } } cleanUp(); exit(PCCTS_EXIT_SUCCESS); return 0; /* MR11 make compilers happy */ } static void #ifdef __USE_PROTOS init( void ) #else init( ) #endif { SignalEntry *q; Tname = newHashTable(); Rname = newHashTable(); Fcache = newHashTable(); Tcache = newHashTable(); Sname = newHashTable(); Pname = newHashTable(); /* MR11 */ /* Add default signal names */ q = (SignalEntry *)hash_add(Sname, "NoViableAlt", (Entry *)newSignalEntry("NoViableAlt")); require(q!=NULL, "cannot alloc signal entry"); q->signum = sigNoViableAlt; q = (SignalEntry *)hash_add(Sname, "MismatchedToken", (Entry *)newSignalEntry("MismatchedToken")); require(q!=NULL, "cannot alloc signal entry"); q->signum = sigMismatchedToken; q = (SignalEntry *)hash_add(Sname, "NoSemViableAlt", (Entry *)newSignalEntry("NoSemViableAlt")); require(q!=NULL, "cannot alloc signal entry"); q->signum = sigNoSemViableAlt; reserved_positions = empty; all_tokens = empty; imag_tokens = empty; tokclasses = empty; TokenStr = (char **) calloc(TSChunk, sizeof(char *)); require(TokenStr!=NULL, "main: cannot allocate TokenStr"); FoStack = (int **) calloc(CLL_k+1, sizeof(int *)); require(FoStack!=NULL, "main: cannot allocate FoStack"); FoTOS = (int **) calloc(CLL_k+1, sizeof(int *)); require(FoTOS!=NULL, "main: cannot allocate FoTOS"); Cycles = (ListNode **) calloc(CLL_k+1, sizeof(ListNode *)); require(Cycles!=NULL, "main: cannot allocate Cycles List"); MR_CompromisedRules=empty; /* MR14 */ } static void #ifdef __USE_PROTOS help( void ) #else help( ) #endif { Opt *p = options; fprintf(stderr, "antlr [options] f1 f2 ... fn\n"); while ( *(p->option) != '*' ) { fprintf(stderr, " %-9s%s %s\n", p->option, (p->arg)?"___":" ", p->descr); p++; } } /* The RulePtr array is filled in here. RulePtr exists primarily * so that sets of rules can be maintained for the FOLLOW caching * mechanism found in rJunc(). RulePtr maps a rule num from 1 to n * to a pointer to its RuleBlk junction where n is the number of rules. */ static void #ifdef __USE_PROTOS buildRulePtr( void ) #else buildRulePtr( ) #endif { int r=1; Junction *p = SynDiag; RulePtr = (Junction **) calloc(NumRules+1, sizeof(Junction *)); require(RulePtr!=NULL, "cannot allocate RulePtr array"); while ( p!=NULL ) { require(r<=NumRules, "too many rules???"); RulePtr[r++] = p; p = (Junction *)p->p2; } } void #ifdef __USE_PROTOS dlgerror(const char *s) #else dlgerror(s) char *s; #endif { fprintf(stderr, ErrHdr, FileStr[CurFile], zzline); fprintf(stderr, " lexical error: %s (text was '%s')\n", ((s == NULL) ? "Lexical error" : s), zzlextext); } void #ifdef __USE_PROTOS readDescr( void ) #else readDescr( ) #endif { zzerr = dlgerror; input = NextFile(); if ( input==NULL ) fatal("No grammar description found (exiting...)"); ANTLR(grammar(), input); tnodes_used_in_guard_predicates_etc=TnodesInUse; /* MR10 */ } FILE * #ifdef __USE_PROTOS NextFile( void ) #else NextFile( ) #endif { FILE *f; for (;;) { CurFile++; if ( CurFile >= NumFiles ) return(NULL); if ( ci_strequ(FileStr[CurFile],"stdin")) return stdin; f = fopen(FileStr[CurFile], "r"); if ( f == NULL ) { warnNoFL( eMsg1("file %s doesn't exist; ignored", FileStr[CurFile]) ); } else { return(f); } } } /* * Return a string corresponding to the output file name associated * with the input file name passed in. * * Observe the following rules: * * f.e --> f".c" * f --> f".c" * f. --> f".c" * f.e.g --> f.e".c" * * Where f,e,g are arbitrarily long sequences of characters in a file * name. * * In other words, if a ".x" appears on the end of a file name, make it * ".c". If no ".x" appears, append ".c" to the end of the file name. * * C++ mode using .cpp not .c. * * Use malloc() for new string. */ char * #ifdef __USE_PROTOS outname( char *fs ) #else outname( fs ) char *fs; #endif { if ( GenCC) { return outnameX(fs,CPP_FILE_SUFFIX); } else { return outnameX(fs,".c"); }; } char * #ifdef __USE_PROTOS outnameX( char *fs ,char *suffix) #else outnameX( fs , suffix ) char *fs; char *suffix; #endif { static char buf[MaxFileName+1]; char *p; require(fs!=NULL&&*fs!='\0', "outname: NULL filename"); p = buf; strcpy(buf, fs); while ( *p != '\0' ) {p++;} /* Stop on '\0' */ while ( *p != '.' && p != buf ) {--p;} /* Find '.' */ if ( p != buf ) *p = '\0'; /* Found '.' */ require(strlen(buf) + 2 < (size_t)MaxFileName, "outname: filename too big"); strcat(buf,suffix); return( buf ); } void #ifdef __USE_PROTOS fatalFL( char *err_, char *f, int l ) #else fatalFL( err_, f, l ) char *err_; char *f; int l; #endif { fprintf(stderr, ErrHdr, f, l); fprintf(stderr, " %s\n", err_); cleanUp(); exit(PCCTS_EXIT_FAILURE); } void #ifdef __USE_PROTOS fatal_intern( char *err_, char *f, int l ) #else fatal_intern( err_, f, l ) char *err_; char *f; int l; #endif { fprintf(stderr, ErrHdr, f, l); fprintf(stderr, " #$%%*&@# internal error: %s\n", err_); fprintf(stderr, ErrHdr, f, l); fprintf(stderr, " [complain to nearest government official\n"); fprintf(stderr, ErrHdr, f, l); fprintf(stderr, " or send hate-mail to parrt@parr-research.com;\n"); fprintf(stderr, ErrHdr, f, l); fprintf(stderr, " please pray to the ``bug'' gods that there is a trival fix.]\n"); cleanUp(); exit(PCCTS_EXIT_FAILURE); } void #ifdef __USE_PROTOS cleanUp( void ) #else cleanUp( ) #endif { if ( DefFile != NULL) fclose( DefFile ); } /* sprintf up to 3 strings */ char * #ifdef __USE_PROTOS eMsg3( char *s, char *a1, char *a2, char *a3 ) #else eMsg3( s, a1, a2, a3 ) char *s; char *a1; char *a2; char *a3; #endif { static char buf[250]; /* DANGEROUS as hell !!!!!! */ sprintf(buf, s, a1, a2, a3); return( buf ); } /* sprintf a decimal */ char * #ifdef __USE_PROTOS eMsgd( char *s, int d ) #else eMsgd( s, d ) char *s; int d; #endif { static char buf[250]; /* DANGEROUS as hell !!!!!! */ sprintf(buf, s, d); return( buf ); } char * #ifdef __USE_PROTOS eMsgd2( char *s, int d1,int d2) #else eMsgd2( s, d1, d2 ) char *s; int d1; int d2; #endif { static char buf[250]; /* DANGEROUS as hell !!!!!! */ sprintf(buf, s, d1, d2); return( buf ); } void #ifdef __USE_PROTOS s_fprT( FILE *f, set e ) #else s_fprT( f, e ) FILE *f; set e; #endif { register unsigned *p; unsigned *q; if ( set_nil(e) ) return; if ( (q=p=set_pdq(e)) == NULL ) fatal_internal("Can't alloc space for set_pdq"); fprintf(f, "{"); while ( *p != nil ) { fprintf(f, " %s", TerminalString(*p)); p++; } fprintf(f, " }"); free((char *)q); } /* Return the token name or regular expression for a token number. */ char * #ifdef __USE_PROTOS TerminalString( int token ) #else TerminalString( token ) int token; #endif { int j; static char imag_name[20]; /* look in all lexclasses for the token */ if ( TokenString(token) != NULL ) return TokenString(token); for (j=0; j0, "pushint: stack overflow"); istack[--isp] = i; } int #ifdef __USE_PROTOS popint( void ) #else popint( ) #endif { require(isp 0 ) { p = options; while ( p->option != NULL ) { if ( strcmp(p->option, "*") == 0 || ci_strequ(p->option, *argv) == 1 ) { if ( p->arg ) { /* MR9 26-Sep-97 Check for argv valid */ if (argc-- > 0) { (*p->process)( *argv, *(argv+1) ); argv++; } else { fprintf(stderr,"error: required argument for option %s omitted\n",*argv); exit(PCCTS_EXIT_FAILURE); }; } else (*p->process)( *argv ); break; } p++; } argv++; } } static void #ifdef __USE_PROTOS CompleteContextGuards(void) #else CompleteContextGuards() #endif { ListNode * p; Predicate * pred; if (ContextGuardPredicateList == NULL) return; for (p=ContextGuardPredicateList->next; p != NULL; p=p->next) { pred=(Predicate *)p->elem; recomputeContextGuard(pred); } } /* Go back into the syntax diagram and compute all meta tokens; i.e. * turn all '.', ranges, token class refs etc... into actual token sets */ static void #ifdef __USE_PROTOS CompleteTokenSetRefs(void) #else CompleteTokenSetRefs() #endif { ListNode *p; if ( MetaTokenNodes==NULL ) return; for (p = MetaTokenNodes->next; p!=NULL; p=p->next) { set a,b; TokNode *q = (TokNode *)p->elem; if ( q->wild_card ) { q->tset = all_tokens; } else if ( q->tclass!=NULL ) { if ( q->complement ) q->tset = set_dif(all_tokens, q->tclass->tset); else q->tset = q->tclass->tset; } else if ( q->upper_range!=0 ) { /* we have a range on our hands: make a set from q->token .. q->upper_range */ int i; a = empty; for (i=q->token; i<=q->upper_range; i++) { set_orel(i, &a); } /* MR13 */ /* MR13 */ if (q->complement) { /* MR13 */ q->tset = set_dif(all_tokens, a); /* MR13 */ set_free(a); /* MR13 */ } else { /* MR13 */ q->tset = a; /* MR13 */ } } /* at this point, it can only be a complemented single token */ else if ( q->complement ) { a = set_of(q->token); b = set_dif(all_tokens, a); set_free(a); q->tset=b; } else fatal("invalid meta token"); } } /* MR10: Jeff Vincent MR10: Changed to remove directory information from n only if MR10: if OutputDirectory was changed by user (-o option) */ char * #ifdef __USE_PROTOS OutMetaName(char *n) #else OutMetaName(n) char *n; #endif { static char *dir_sym = DirectorySymbol; static char newname[MaxFileName+1]; char *p; /* If OutputDirectory is same as TopDirectory (platform default) then leave n alone. */ if (strcmp(OutputDirectory, TopDirectory) == 0) /* TopDirectory is "." on Unix. */ return n; /* p will point to filename without path information */ if ((p = strrchr(n, *dir_sym)) != NULL) /* Directory symbol is "/" on Unix. */ p++; else p = n; /* Copy new output directory into newname[] */ strcpy(newname, OutputDirectory); /* if new output directory does not have trailing dir_sym, add it! */ if (newname[strlen(newname)-1] != *dir_sym) { strcat(newname, dir_sym); } strcat(newname, p); return newname; } char * #ifdef __USE_PROTOS pcctsBaseName(char *n) /* MR32 */ #else pcctsBaseName(n) char *n; #endif { static char newname[MaxFileName+1]; static char* dir_sym = DirectorySymbol; int count = 0; char *p; p = n; while ( *p != '\0' ) {p++;} /* go to end of string */ while ( (*p != *dir_sym) && (p != n) ) {--p;} /* Find last DirectorySymbol */ while ( *p == *dir_sym) p++; /* step forward if we're on a dir symbol */ while ( *p != '\0' && *p != '.') { newname[count++] = *p; p++; } /* create a new name */ newname[count] = '\0'; return newname; } static void #ifdef __USE_PROTOS ensure_no_C_file_collisions(char *class_c_file) #else ensure_no_C_file_collisions(class_c_file) char *class_c_file; #endif { int i; for (i=0; i= NumFiles && CurFile >= 1 ) CurFile--; fprintf(stderr, ErrHdr, FileStr[CurFile], zzline); fprintf(stderr, " warning: %s\n", err); } void #ifdef __USE_PROTOS warnNoCR( char *err ) #else warnNoCR( err ) char *err; #endif { /* back up the file number if we hit an error at the end of the last file */ if ( CurFile >= NumFiles && CurFile >= 1 ) CurFile--; fprintf(stderr, ErrHdr, FileStr[CurFile], zzline); fprintf(stderr, " warning: %s", err); } void #ifdef __USE_PROTOS errNoFL(char *err) #else errNoFL(err) char *err; #endif { fprintf(stderr, "error: %s\n", err); } void #ifdef __USE_PROTOS errFL(char *err,char *f,int l) #else errFL(err,f,l) char *err; char *f; int l; #endif { fprintf(stderr, ErrHdr, f, l); fprintf(stderr, " error: %s\n", err); } void #ifdef __USE_PROTOS err(char *err) #else err(err) char *err; #endif { /* back up the file number if we hit an error at the end of the last file */ if ( CurFile >= NumFiles && CurFile >= 1 ) CurFile--; fprintf(stderr, ErrHdr, FileStr[CurFile], zzline); fprintf(stderr, " error: %s\n", err); } void #ifdef __USE_PROTOS errNoCR( char *err ) #else errNoCR( err ) char *err; #endif { /* back up the file number if we hit an error at the end of the last file */ if ( CurFile >= NumFiles && CurFile >= 1 ) CurFile--; fprintf(stderr, ErrHdr, FileStr[CurFile], zzline); fprintf(stderr, " error: %s", err); } UserAction * #ifdef __USE_PROTOS newUserAction(char *s) #else newUserAction(s) char *s; #endif { UserAction *ua = (UserAction *) calloc(1, sizeof(UserAction)); require(ua!=NULL, "cannot allocate UserAction"); ua->action = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char)); strcpy(ua->action, s); return ua; } /* Added by TJP September 1994 */ /* Take in file.h and return file_h; names w/o '.'s are left alone */ char * #ifdef __USE_PROTOS gate_symbol(char *name) #else gate_symbol(name) char *name; #endif { static char buf[100]; char *p; sprintf(buf, "%s", name); for (p=buf; *p!='\0'; p++) { if ( *p=='.' ) *p = '_'; } return buf; } char * #ifdef __USE_PROTOS makeAltID(int blockid, int altnum) #else makeAltID(blockid, altnum) int blockid; int altnum; #endif { static char buf[100]; char *p; sprintf(buf, "_blk%d_alt%d", blockid, altnum); p = (char *)malloc(strlen(buf)+1); strcpy(p, buf); return p; } cdrdao-cdrdao-f00afb2/pccts/antlr/misc.c000066400000000000000000001337241511453746600202430ustar00rootroot00000000000000/* * misc.c * * Manage tokens, regular expressions. * Print methods for debugging * Compute follow lists onto tail ends of rules. * * The following functions are visible: * * int addTname(char *); Add token name * int addTexpr(char *); Add token expression * int Tnum(char *); Get number of expr/token * void Tklink(char *, char *); Link a name with an expression * int hasAction(expr); Does expr already have action assigned? * void setHasAction(expr); Indicate that expr now has an action * Entry *newEntry(char *,int); Create new table entry with certain size * void list_add(ListNode **list, char *e) * void list_free(ListNode **list, int freeData); *** MR10 *** * void list_apply(ListNode *list, void (*f)()) * void lexclass(char *m); switch to new/old lexical class * void lexmode(int i); switch to old lexical class i * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2001 */ #include #include "pcctscfg.h" #include "set.h" #include "syn.h" #include "hash.h" #include "generic.h" #include "dlgdef.h" #include static int tsize=TSChunk; /* size of token str arrays */ static void #ifdef __USE_PROTOS RemapForcedTokensInSyntaxDiagram(Node *); #else RemapForcedTokensInSyntaxDiagram(); #endif /* T o k e n M a n i p u l a t i o n */ /* * add token 't' to the TokenStr/Expr array. Make more room if necessary. * 't' is either an expression or a token name. * * There is only one TokenStr array, but multiple ExprStr's. Therefore, * for each lex class (element of lclass) we must extend the ExprStr array. * ExprStr's and TokenStr are always all the same size. * * Also, there is a Texpr hash table for each automaton. */ static void #ifdef __USE_PROTOS Ttrack( char *t ) #else Ttrack( t ) char *t; #endif { if ( TokenNum >= tsize ) /* terminal table overflow? */ { char **p; int i, more, j; more = TSChunk * (1 + ((TokenNum-tsize) / TSChunk)); tsize += more; TokenStr = (char **) realloc((char *)TokenStr, tsize*sizeof(char *)); require(TokenStr != NULL, "Ttrack: can't extend TokenStr"); for (i=0; iexpr = e; p->lclass = CurrentLexClass; return p; } /* switch to lexical class/mode m. This amounts to creating a new * lex mode if one does not already exist and making ExprStr point * to the correct char string array. We must also switch Texpr tables. * * BTW, we need multiple ExprStr arrays because more than one automaton * may have the same label for a token, but with different expressions. * We need to track an expr for each automaton. If we disallowed this * feature, only one ExprStr would be required. */ void #ifdef __USE_PROTOS lexclass( char *m ) #else lexclass( m ) char *m; #endif { int i; TermEntry *p; static char EOFSTR[] = "\"@\""; if ( hash_get(Tname, m) != NULL ) { warn(eMsg1("lexclass name conflicts with token/errclass label '%s'",m)); } /* does m already exist? */ i = LexClassIndex(m); if ( i != -1 ) {lexmode(i); return;} /* must make new one */ NumLexClasses++; CurrentLexClass = NumLexClasses-1; require(NumLexClasses<=MaxLexClasses, "number of allowable lexclasses exceeded\nIncrease MaxLexClasses in generic.h and recompile all C files"); lclass[CurrentLexClass].classnum = m; lclass[CurrentLexClass].exprs = (char **) calloc(tsize, sizeof(char *)); require(lclass[CurrentLexClass].exprs!=NULL, "lexclass: cannot allocate ExprStr"); lclass[CurrentLexClass].htable = newHashTable(); ExprStr = lclass[CurrentLexClass].exprs; Texpr = lclass[CurrentLexClass].htable; /* define EOF for each automaton */ p = newTermEntry( EOFSTR ); p->token = EofToken; /* couldn't have remapped tokens yet, use EofToken */ hash_add(Texpr, EOFSTR, (Entry *)p); list_add(&ExprOrder, (void *)newExpr(EOFSTR)); /* note: we use the actual ExprStr array * here as TokenInd doesn't exist yet */ ExprStr[EofToken] = EOFSTR; } void #ifdef __USE_PROTOS lexmode( int i ) #else lexmode( i ) int i; #endif { require(iaction!=NULL); } void #ifdef __USE_PROTOS setHasAction( char *expr, char *action ) #else setHasAction( expr, action ) char *expr; char *action; #endif { TermEntry *p; require(expr!=NULL, "setHasAction: invalid expr"); p = (TermEntry *) hash_get(Texpr, expr); require(p!=NULL, eMsg1("setHasAction: expr '%s' doesn't exist",expr)); p->action = action; } ForcedToken * #ifdef __USE_PROTOS newForcedToken(char *token, int tnum) #else newForcedToken(token, tnum) char *token; int tnum; #endif { ForcedToken *ft = (ForcedToken *) calloc(1, sizeof(ForcedToken)); require(ft!=NULL, "out of memory"); ft->token = token; ft->tnum = tnum; return ft; } /* * Make a token indirection array that remaps token numbers and then walk * the appropriate symbol tables and SynDiag to change token numbers */ void #ifdef __USE_PROTOS RemapForcedTokens(void) #else RemapForcedTokens() #endif { ListNode *p; ForcedToken *q; int max_token_number=0; /* MR9 23-Sep-97 Removed "unsigned" */ int i; if ( ForcedTokens == NULL ) return; /* find max token num */ for (p = ForcedTokens->next; p!=NULL; p=p->next) { q = (ForcedToken *) p->elem; if ( q->tnum > max_token_number ) max_token_number = q->tnum; } fprintf(stderr, "max token number is %d\n", max_token_number); /* make token indirection array */ TokenInd = (int *) calloc(max_token_number+1, sizeof(int)); LastTokenCounted = TokenNum; TokenNum = max_token_number+1; require(TokenInd!=NULL, "RemapForcedTokens: cannot allocate TokenInd"); /* fill token indirection array and change token id htable ; swap token indices */ for (i=1; inext; p!=NULL; p=p->next) { TermEntry *te; int old_pos, t; q = (ForcedToken *) p->elem; fprintf(stderr, "%s forced to %d\n", q->token, q->tnum); te = (TermEntry *) hash_get(Tname, q->token); require(te!=NULL, "RemapForcedTokens: token not in hash table"); old_pos = te->token; fprintf(stderr, "Before: TokenInd[old_pos==%d] is %d\n", old_pos, TokenInd[old_pos]); fprintf(stderr, "Before: TokenInd[target==%d] is %d\n", q->tnum, TokenInd[q->tnum]); q = (ForcedToken *) p->elem; t = TokenInd[old_pos]; TokenInd[old_pos] = q->tnum; TokenInd[q->tnum] = t; te->token = q->tnum; /* update token type id symbol table */ fprintf(stderr, "After: TokenInd[old_pos==%d] is %d\n", old_pos, TokenInd[old_pos]); fprintf(stderr, "After: TokenInd[target==%d] is %d\n", q->tnum, TokenInd[q->tnum]); /* Change the token number in the sym tab entry for the exprs * at the old position of the token id and the target position */ /* update expr at target (if any) of forced token id */ if ( q->tnum < TokenNum ) /* is it a valid position? */ { for (i=0; itnum]!=NULL ) { /* update the symbol table for this expr */ TermEntry *e = (TermEntry *) hash_get(lclass[i].htable, lclass[i].exprs[q->tnum]); require(e!=NULL, "RemapForcedTokens: expr not in hash table"); e->token = old_pos; fprintf(stderr, "found expr '%s' at target %d in lclass[%d]; changed to %d\n", lclass[i].exprs[q->tnum], q->tnum, i, old_pos); } } } /* update expr at old position (if any) of forced token id */ for (i=0; itoken = q->tnum; fprintf(stderr, "found expr '%s' for id %s in lclass[%d]; changed to %d\n", lclass[i].exprs[old_pos], q->token, i, q->tnum); } } } /* Update SynDiag */ RemapForcedTokensInSyntaxDiagram((Node *)SynDiag); } static void #ifdef __USE_PROTOS RemapForcedTokensInSyntaxDiagram(Node *p) #else RemapForcedTokensInSyntaxDiagram(p) Node *p; #endif { Junction *j = (Junction *) p; RuleRefNode *r = (RuleRefNode *) p; TokNode *t = (TokNode *)p; if ( p==NULL ) return; require(p->ntype>=1 && p->ntype<=NumNodeTypes, "Remap...: invalid diagram node"); switch ( p->ntype ) { case nJunction : if ( j->visited ) return; if ( j->jtype == EndRule ) return; j->visited = TRUE; RemapForcedTokensInSyntaxDiagram( j->p1 ); RemapForcedTokensInSyntaxDiagram( j->p2 ); j->visited = FALSE; return; case nRuleRef : RemapForcedTokensInSyntaxDiagram( r->next ); return; case nToken : if ( t->remapped ) return; /* we've been here before */ t->remapped = 1; fprintf(stderr, "remapping %d to %d\n", t->token, TokenInd[t->token]); t->token = TokenInd[t->token]; RemapForcedTokensInSyntaxDiagram( t->next ); return; case nAction : RemapForcedTokensInSyntaxDiagram( ((ActionNode *)p)->next ); return; default : fatal_internal("invalid node type"); } } /* * Add a token name. Return the token number associated with it. If it already * exists, then return the token number assigned to it. * * Track the order in which tokens are found so that the DLG output maintains * that order. It also lets us map token numbers to strings. */ int #ifdef __USE_PROTOS addTname( char *token ) #else addTname( token ) char *token; #endif { TermEntry *p; require(token!=NULL, "addTname: invalid token name"); if ( (p=(TermEntry *)hash_get(Tname, token)) != NULL ) return p->token; p = newTermEntry( token ); Ttrack( p->str ); p->token = TokenNum++; hash_add(Tname, token, (Entry *)p); return p->token; } /* This is the same as addTname except we force the TokenNum to be tnum. * We don't have to use the Forced token stuff as no tokens will have * been defined with #tokens when this is called. This is only called * when a #tokdefs meta-op is used. */ int #ifdef __USE_PROTOS addForcedTname( char *token, int tnum ) #else addForcedTname( token, tnum ) char *token; int tnum; #endif { TermEntry *p; require(token!=NULL, "addTname: invalid token name"); if ( (p=(TermEntry *)hash_get(Tname, token)) != NULL ) return p->token; p = newTermEntry( token ); Ttrack( p->str ); p->token = tnum; hash_add(Tname, token, (Entry *)p); return p->token; } /* * Add a token expr. Return the token number associated with it. If it already * exists, then return the token number assigned to it. */ int #ifdef __USE_PROTOS addTexpr( char *expr ) #else addTexpr( expr ) char *expr; #endif { TermEntry *p; require(expr!=NULL, "addTexpr: invalid regular expression"); if ( (p=(TermEntry *)hash_get(Texpr, expr)) != NULL ) return p->token; p = newTermEntry( expr ); Ttrack( p->str ); /* track the order in which they occur */ list_add(&ExprOrder, (void *)newExpr(p->str)); p->token = TokenNum++; hash_add(Texpr, expr, (Entry *)p); return p->token; } /* return the token number of 'term'. Return 0 if no 'term' exists */ int #ifdef __USE_PROTOS Tnum( char *term ) #else Tnum( term ) char *term; #endif { TermEntry *p; require(term!=NULL, "Tnum: invalid terminal"); if ( *term=='"' ) p = (TermEntry *) hash_get(Texpr, term); else p = (TermEntry *) hash_get(Tname, term); if ( p == NULL ) return 0; else return p->token; } /* associate a Name with an expr. If both have been already assigned * token numbers, then an error is reported. Add the token or expr * that has not been added if no error. This 'represents' the #token * ANTLR pseudo-op. If both have not been defined, define them both * linked to same token number. */ void #ifdef __USE_PROTOS Tklink( char *token, char *expr ) #else Tklink( token, expr ) char *token; char *expr; #endif { TermEntry *p, *q; require(token!=NULL && expr!=NULL, "Tklink: invalid token name and/or expr"); p = (TermEntry *) hash_get(Tname, token); q = (TermEntry *) hash_get(Texpr, expr); if ( p != NULL && q != NULL ) /* both defined */ { warn( eMsg2("token name %s and rexpr %s already defined; ignored", token, expr) ); return; } if ( p==NULL && q==NULL ) /* both not defined */ { int t = addTname( token ); q = newTermEntry( expr ); hash_add(Texpr, expr, (Entry *)q); q->token = t; /* note: we use the actual ExprStr array * here as TokenInd doesn't exist yet */ ExprStr[t] = q->str; /* track the order in which they occur */ list_add(&ExprOrder, (void *)newExpr(q->str)); return; } if ( p != NULL ) /* one is defined, one is not */ { q = newTermEntry( expr ); hash_add(Texpr, expr, (Entry *)q); q->token = p->token; ExprStr[p->token] = q->str; /* both expr and token str defined now */ list_add(&ExprOrder, (void *)newExpr(q->str)); } else /* trying to associate name with expr here*/ { p = newTermEntry( token ); hash_add(Tname, token, (Entry *)p); p->token = q->token; TokenStr[p->token] = p->str;/* both expr and token str defined now */ } } /* * Given a string, this function allocates and returns a pointer to a * hash table record of size 'sz' whose "str" pointer is reset to a position * in the string table. */ Entry * #ifdef __USE_PROTOS newEntry( char *text, int sz ) #else newEntry( text, sz ) char *text; int sz; #endif { Entry *p; require(text!=NULL, "new: NULL terminal"); if ( (p = (Entry *) calloc(1,sz)) == 0 ) { fatal_internal("newEntry: out of memory for terminals\n"); exit(PCCTS_EXIT_FAILURE); } p->str = mystrdup(text); return(p); } /* * add an element to a list. * * Any non-empty list has a sentinel node whose 'elem' pointer is really * a pointer to the last element. (i.e. length(list) = #elemIn(list)+1). * Elements are appended to the list. */ void #ifdef __USE_PROTOS list_add( ListNode **list, void *e ) #else list_add( list, e ) ListNode **list; void *e; #endif { ListNode *p, *tail; require(e!=NULL, "list_add: attempting to add NULL list element"); p = newListNode; require(p!=NULL, "list_add: cannot alloc new list node"); p->elem = e; if ( *list == NULL ) { ListNode *sentinel = newListNode; require(sentinel!=NULL, "list_add: cannot alloc sentinel node"); *list=sentinel; sentinel->next = p; sentinel->elem = (char *)p; /* set tail pointer */ } else /* find end of list */ { tail = (ListNode *) (*list)->elem; /* get tail pointer */ tail->next = p; (*list)->elem = (char *) p; /* reset tail */ } } /* MR10 list_free() frees the ListNode elements in the list */ /* MR10 if freeData then free the data elements of the list too */ void #ifdef __USE_PROTOS list_free(ListNode **list,int freeData) #else list_free(list,freeData) ListNode **list; int freeData; #endif { ListNode *p; ListNode *next; if (list == NULL) return; if (*list == NULL) return; for (p=*list; p != NULL; p=next) { next=p->next; if (freeData && p->elem != NULL) { free( (char *) p->elem); }; free( (char *) p); }; *list=NULL; } void #ifdef __USE_PROTOS list_apply( ListNode *list, void (*f)(void *) ) #else list_apply( list, f ) ListNode *list; void (*f)(); #endif { ListNode *p; require(f!=NULL, "list_apply: NULL function to apply"); if ( list == NULL ) return; for (p = list->next; p!=NULL; p=p->next) (*f)( p->elem ); } /* MR27 */ #ifdef __USE_PROTOS int list_search_cstring(ListNode *list, char * cstring) #else int list_search_cstring(list, cstring) ListNode * list; char * cstring; #endif { ListNode *p; if (list == NULL ) return 0; for (p = list->next; p!=NULL; p=p->next) { if (p->elem == NULL) continue; if (0 == strcmp((char *) p->elem , cstring)) return 1; } return 0; } /* F O L L O W C y c l e S t u f f */ /* make a key based upon (rulename, computation, k value). * Computation values are 'i'==FIRST, 'o'==FOLLOW. */ /* MR10 Make the key all characters so it can be read easily */ /* MR10 by a simple dump program. Also, separates */ /* MR10 'o' and 'i' from rule name */ char * #ifdef __USE_PROTOS Fkey( char *rule, int computation, int k ) #else Fkey( rule, computation, k ) char *rule; int computation; int k; #endif { static char key[MaxRuleName+2+2+1]; /* MR10 */ int i; if ( k > 99 ) /* MR10 */ fatal("k>99 is too big for this implementation of ANTLR!\n"); /* MR10 */ if ( (i=strlen(rule)) > MaxRuleName ) /* MR10 */ fatal( eMsgd("rule name > max of %d\n", MaxRuleName) ); /* MR10 */ strcpy(key,rule); /* MR10 */ key[i]='*'; /* MR10 */ key[i+1] = (char) computation; /* MR20 G. Hobbelt */ /* MR10 */ if (k < 10) { /* MR10 */ key[i+2] = (char) ( '0' + k); /* MR10 */ key[i+3] = '\0'; /* MR10 */ } else { /* MR10 */ key[i+2] = (char) ( '0' + k/10); /* MR10 */ key[i+3] = (char) ( '0' + k % 10); /* MR10 */ key[i+4] = '\0'; /* MR10 */ }; return key; } /* Push a rule onto the kth FOLLOW stack */ void #ifdef __USE_PROTOS FoPush( char *rule, int k ) #else FoPush( rule, k ) char *rule; int k; #endif { RuleEntry *r; require(rule!=NULL, "FoPush: tried to push NULL rule"); require(k<=CLL_k, "FoPush: tried to access non-existent stack"); /*fprintf(stderr, "FoPush(%s)\n", rule);*/ r = (RuleEntry *) hash_get(Rname, rule); if ( r == NULL ) {fatal_internal( eMsg1("rule %s must be defined but isn't", rule) );} if ( FoStack[k] == NULL ) /* Does the kth stack exist yet? */ { /*fprintf(stderr, "allocating FoStack\n");*/ FoStack[k] = (int *) calloc(FoStackSize, sizeof(int)); require(FoStack[k]!=NULL, "FoPush: cannot allocate FOLLOW stack\n"); } if ( FoTOS[k] == NULL ) { FoTOS[k]=FoStack[k]; *(FoTOS[k]) = r->rulenum; } else { #ifdef MEMCHK require(valid(FoStack[k]), "FoPush: invalid FoStack"); #endif if ( FoTOS[k] >= &(FoStack[k][FoStackSize-1]) ) fatal( eMsgd("exceeded max depth of FOLLOW recursion (%d)\n", FoStackSize) ); require(FoTOS[k]>=FoStack[k], eMsg1("FoPush: FoStack stack-ptr is playing out of its sandbox", rule)); ++(FoTOS[k]); *(FoTOS[k]) = r->rulenum; } { /* **** int *p; **** fprintf(stderr, "FoStack[k=%d]:\n", k); **** for (p=FoStack[k]; p<=FoTOS[k]; p++) **** { **** fprintf(stderr, "\t%s\n", RulePtr[*p]->rname); **** } */ } } /* Pop one rule off of the FOLLOW stack. TOS ptr is NULL if empty. */ void #ifdef __USE_PROTOS FoPop( int k ) #else FoPop( k ) int k; #endif { require(k<=CLL_k, "FoPop: tried to access non-existent stack"); /*fprintf(stderr, "FoPop\n");*/ require(FoTOS[k]>=FoStack[k]&&FoTOS[k]<=&(FoStack[k][FoStackSize-1]), "FoPop: FoStack stack-ptr is playing out of its sandbox"); if ( FoTOS[k] == FoStack[k] ) FoTOS[k] = NULL; else (FoTOS[k])--; } /* Compute FOLLOW cycle. * Mark all FOLLOW sets for rules in cycle as incomplete. * Then, save cycle on the cycle list (Cycles) for later resolution. * The Cycle is stored in the form: * (head of cycle==croot, rest of rules in cycle==cyclicDep) * * e.g. (Fo means "FOLLOW of", "-->" means requires or depends on) * * Fo(x)-->Fo(a)-->Fo(b)-->Fo(c)-->Fo(x) * ^----Infinite recursion (cycle) * * the cycle would be: x -> {a,b,c} or stored as (x,{a,b,c}). Fo(x) depends * on the FOLLOW of a,b, and c. The root of a cycle is always complete after * Fo(x) finishes. Fo(a,b,c) however are not. It turns out that all rules * in a FOLLOW cycle have the same FOLLOW set. */ void #ifdef __USE_PROTOS RegisterCycle( char *rule, int k ) #else RegisterCycle( rule, k ) char *rule; int k; #endif { CacheEntry *f; Cycle *c; int *p; RuleEntry *r; require(rule!=NULL, "RegisterCycle: tried to register NULL rule"); require(k<=CLL_k, "RegisterCycle: tried to access non-existent stack"); /*fprintf(stderr, "RegisterCycle(%s)\n", rule);*/ /* Find cycle start */ r = (RuleEntry *) hash_get(Rname, rule); require(r!=NULL,eMsg1("rule %s must be defined but isn't", rule)); require(FoTOS[k]>=FoStack[k]&&FoTOS[k]<=&(FoStack[k][FoStackSize-1]), eMsg1("RegisterCycle(%s): FoStack stack-ptr is playing out of its sandbox", rule)); /*** if ( FoTOS[k]&(FoStack[k][FoStackSize-1]) ) **** { **** fprintf(stderr, "RegisterCycle(%s): FoStack stack-ptr is playing out of its sandbox\n", **** rule); **** fprintf(stderr, "RegisterCycle: sp==0x%x out of bounds 0x%x...0x%x\n", **** FoTOS[k], FoStack[k], &(FoStack[k][FoStackSize-1])); **** exit(PCCTS_EXIT_FAILURE); **** } ****/ #ifdef MEMCHK require(valid(FoStack[k]), "RegisterCycle: invalid FoStack"); #endif for (p=FoTOS[k]; *p != r->rulenum && p >= FoStack[k]; --p) {;} require(p>=FoStack[k], "RegisterCycle: FoStack is screwed up beyond belief"); if ( p == FoTOS[k] ) return; /* don't worry about cycles to oneself */ /* compute cyclic dependents (rules in cycle except head) */ c = newCycle; require(c!=NULL, "RegisterCycle: couldn't alloc new cycle"); c->cyclicDep = empty; c->croot = *p++; /* record root of cycle */ for (; p<=FoTOS[k]; p++) { /* Mark all dependent rules as incomplete */ f = (CacheEntry *) hash_get(Fcache, Fkey(RulePtr[*p]->rname,'o',k)); if ( f==NULL ) { f = newCacheEntry( Fkey(RulePtr[*p]->rname,'o',k) ); hash_add(Fcache, Fkey(RulePtr[*p]->rname,'o',k), (Entry *)f); } f->incomplete = TRUE; set_orel(*p, &(c->cyclicDep)); /* mark rule as dependent of croot */ } list_add(&(Cycles[k]), (void *)c); } /* make all rules in cycle complete * * while ( some set has changed ) do * for each cycle do * if degree of FOLLOW set for croot > old degree then * update all FOLLOW sets for rules in cyclic dependency * change = TRUE * endif * endfor * endwhile */ void #ifdef __USE_PROTOS ResolveFoCycles( int k ) #else ResolveFoCycles( k ) int k; #endif { ListNode *p, *q; Cycle *c; int changed = 1; CacheEntry *f,*g; int r; /* int i; */ /* MR10 not useful */ unsigned d; unsigned *cursor; /* MR10 */ unsigned *origin; /* MR10 */ /*fprintf(stderr, "Resolving following cycles for %d\n", k);*/ while ( changed ) { changed = 0; /* MR10 i = 0; */ for (p = Cycles[k]->next; p!=NULL; p=p->next) { c = (Cycle *) p->elem; /*fprintf(stderr, "cycle %d: %s -->", i++, RulePtr[c->croot]->rname);*/ /*s_fprT(stderr, c->cyclicDep);*/ /*fprintf(stderr, "\n");*/ f = (CacheEntry *) hash_get(Fcache, Fkey(RulePtr[c->croot]->rname,'o',k)); require(f!=NULL, eMsg1("FOLLOW(%s) must be in cache but isn't", RulePtr[c->croot]->rname) ); if ( (d=set_deg(f->fset)) > c->deg ) { /*fprintf(stderr, "Fo(%s) has changed\n", RulePtr[c->croot]->rname);*/ changed = 1; c->deg = d; /* update cycle FOLLOW set degree */ /* MR10 */ origin=set_pdq(c->cyclicDep); /* MR10 */ for (cursor=origin; *cursor != nil; cursor++) { /* MR10 */ r=*cursor; /******** while ( !set_nil(c->cyclicDep) ) { *****/ /******** r = set_int(c->cyclicDep); *****/ /******** set_rm(r, c->cyclicDep); *****/ /*fprintf(stderr, "updating Fo(%s)\n", RulePtr[r]->rname);*/ g = (CacheEntry *) hash_get(Fcache, Fkey(RulePtr[r]->rname,'o',k)); require(g!=NULL, eMsg1("FOLLOW(%s) must be in cache but isn't", RulePtr[r]->rname) ); set_orin(&(g->fset), f->fset); g->incomplete = FALSE; } /* MR10 */ free( (char *) origin); /* MR10 */ origin=NULL; } } /* MR10 - this if statement appears to be meaningless since i is always 0 */ /* MR10 if ( i == 1 ) changed = 0; */ /* if only 1 cycle, no need to repeat */ } /* kill Cycle list */ for (q = Cycles[k]->next; q != NULL; q=p) { p = q->next; set_free( ((Cycle *)q->elem)->cyclicDep ); free((char *)q); } free( (char *)Cycles[k] ); Cycles[k] = NULL; } /* P r i n t i n g S y n t a x D i a g r a m s */ static void #ifdef __USE_PROTOS pBlk( Junction *q, int btype ) #else pBlk( q, btype ) Junction *q; int btype; #endif { int k,a; Junction *alt, *p; q->end->pvisited = TRUE; if ( btype == aLoopBegin ) { require(q->p2!=NULL, "pBlk: invalid ()* block"); PRINT(q->p1); alt = (Junction *)q->p2; PRINT(alt->p1); if ( PrintAnnotate ) { printf(" /* Opt "); k = 1; while ( !set_nil(alt->fset[k]) ) { s_fprT(stdout, alt->fset[k]); if ( k++ == CLL_k ) break; if ( !set_nil(alt->fset[k]) ) printf(", "); } printf(" */\n"); } return; } for (a=1,alt=q; alt != NULL; alt= (Junction *) alt->p2, a++) { if ( alt->p1 != NULL ) PRINT(alt->p1); if ( PrintAnnotate ) { printf( " /* [%d] ", alt->altnum); k = 1; while ( !set_nil(alt->fset[k]) ) { s_fprT(stdout, alt->fset[k]); if ( k++ == CLL_k ) break; if ( !set_nil(alt->fset[k]) ) printf(", "); } if ( alt->p2 == NULL && btype == aOptBlk ) printf( " (optional branch) */\n"); else printf( " */\n"); } /* ignore implied empty alt of Plus blocks */ if ( alt->p2 != NULL && ((Junction *)alt->p2)->ignore ) break; if ( alt->p2 != NULL && !(((Junction *)alt->p2)->p2==NULL && btype == aOptBlk) ) { if ( pLevel == 1 ) { printf("\n"); if ( a+1==pAlt1 || a+1==pAlt2 ) printf("=>"); printf("\t"); } else printf(" "); printf("|"); if ( pLevel == 1 ) { p = (Junction *) ((Junction *)alt->p2)->p1; while ( p!=NULL ) { if ( p->ntype==nAction ) { p=(Junction *)((ActionNode *)p)->next; continue; } if ( p->ntype!=nJunction ) { break; } if ( p->jtype==EndBlk || p->jtype==EndRule ) { p = NULL; break; } p = (Junction *)p->p1; } if ( p==NULL ) printf("\n\t"); /* Empty alt? */ } } } q->end->pvisited = FALSE; } /* How to print out a junction */ void #ifdef __USE_PROTOS pJunc( Junction *q ) #else pJunc( q ) Junction *q; #endif { int dum_k; int doing_rule; require(q!=NULL, "pJunc: NULL node"); require(q->ntype==nJunction, "pJunc: not junction"); if ( q->pvisited == TRUE ) return; q->pvisited = TRUE; switch ( q->jtype ) { case aSubBlk : if ( PrintAnnotate ) First(q, 1, q->jtype, &dum_k); if ( q->end->p1 != NULL && ((Junction *)q->end->p1)->ntype==nJunction && ((Junction *)q->end->p1)->jtype == EndRule ) doing_rule = 1; else doing_rule = 0; pLevel++; if ( pLevel==1 ) { if ( pAlt1==1 ) printf("=>"); printf("\t"); } else printf(" "); if ( doing_rule ) { if ( pLevel==1 ) printf(" "); pBlk(q,q->jtype); } else { printf("("); if ( pLevel==1 ) printf(" "); pBlk(q,q->jtype); if ( pLevel>1 ) printf(" "); printf(")"); } if ( q->guess ) printf("?"); pLevel--; if ( PrintAnnotate ) freeBlkFsets(q); if ( q->end->p1 != NULL ) PRINT(q->end->p1); break; case aOptBlk : if ( PrintAnnotate ) First(q, 1, q->jtype, &dum_k); pLevel++; if ( pLevel==1 ) { if ( pAlt1==1 ) printf("=>"); printf("\t"); } else printf(" "); printf("{"); if ( pLevel==1 ) printf(" "); pBlk(q,q->jtype); if ( pLevel>1 ) printf(" "); else printf("\n\t"); printf("}"); pLevel--; if ( PrintAnnotate ) freeBlkFsets(q); if ( q->end->p1 != NULL ) PRINT(q->end->p1); break; case aLoopBegin : if ( PrintAnnotate ) First(q, 1, q->jtype, &dum_k); pLevel++; if ( pLevel==1 ) { if ( pAlt1==1 ) printf("=>"); printf("\t"); } else printf(" "); printf("("); if ( pLevel==1 ) printf(" "); pBlk(q,q->jtype); if ( pLevel>1 ) printf(" "); else printf("\n\t"); printf(")*"); pLevel--; if ( PrintAnnotate ) freeBlkFsets(q); if ( q->end->p1 != NULL ) PRINT(q->end->p1); break; case aLoopBlk : if ( PrintAnnotate ) First(q, 1, q->jtype, &dum_k); pBlk(q,q->jtype); if ( PrintAnnotate ) freeBlkFsets(q); break; case aPlusBlk : if ( PrintAnnotate ) First(q, 1, q->jtype, &dum_k); pLevel++; if ( pLevel==1 ) { if ( pAlt1==1 ) printf("=>"); printf("\t"); } else printf(" "); printf("("); if ( pLevel==1 ) printf(" "); pBlk(q,q->jtype); if ( pLevel>1 ) printf(" "); printf(")+"); pLevel--; if ( PrintAnnotate ) freeBlkFsets(q); if ( q->end->p1 != NULL ) PRINT(q->end->p1); break; case EndBlk : break; case RuleBlk : printf( "\n%s :\n", q->rname); PRINT(q->p1); if ( q->p2 != NULL ) PRINT(q->p2); break; case Generic : if ( q->p1 != NULL ) PRINT(q->p1); q->pvisited = FALSE; if ( q->p2 != NULL ) PRINT(q->p2); break; case EndRule : printf( "\n\t;\n"); break; } q->pvisited = FALSE; } /* How to print out a rule reference node */ void #ifdef __USE_PROTOS pRuleRef( RuleRefNode *p ) #else pRuleRef( p ) RuleRefNode *p; #endif { require(p!=NULL, "pRuleRef: NULL node"); require(p->ntype==nRuleRef, "pRuleRef: not rule ref node"); printf( " %s", p->text); PRINT(p->next); } /* How to print out a terminal node */ void #ifdef __USE_PROTOS pToken( TokNode *p ) #else pToken( p ) TokNode *p; #endif { require(p!=NULL, "pToken: NULL node"); require(p->ntype==nToken, "pToken: not token node"); if ( p->wild_card ) printf(" ."); printf( " %s", TerminalString(p->token)); PRINT(p->next); } /* How to print out a terminal node */ void #ifdef __USE_PROTOS pAction( ActionNode *p ) #else pAction( p ) ActionNode *p; #endif { require(p!=NULL, "pAction: NULL node"); require(p->ntype==nAction, "pAction: not action node"); PRINT(p->next); } /* F i l l F o l l o w L i s t s */ /* * Search all rules for all rule reference nodes, q to rule, r. * Add q->next to follow list dangling off of rule r. * i.e. * * r: -o-R-o-->o--> Ptr to node following rule r in another rule * | * o--> Ptr to node following another reference to r. * * This is the data structure employed to avoid FOLLOW set computation. We * simply compute the FIRST (reach) of the EndRule Node which follows the * list found at the end of all rules which are referenced elsewhere. Rules * not invoked by other rules have no follow list (r->end->p1==NULL). * Generally, only start symbols are not invoked by another rule. * * Note that this mechanism also gives a free cross-reference mechanism. * * The entire syntax diagram is layed out like this: * * SynDiag * | * v * o-->R1--o * | * o-->R2--o * | * ... * | * o-->Rn--o * */ void #ifdef __USE_PROTOS FoLink( Node *p ) #else FoLink( p ) Node *p; #endif { RuleEntry *q; Junction *j = (Junction *) p; RuleRefNode *r = (RuleRefNode *) p; if ( p==NULL ) return; require(p->ntype>=1 && p->ntype<=NumNodeTypes, eMsgd("FoLink: invalid diagram node: ntype==%d",p->ntype)); switch ( p->ntype ) { case nJunction : if ( j->fvisited ) return; if ( j->jtype == EndRule ) return; j->fvisited = TRUE; FoLink( j->p1 ); FoLink( j->p2 ); /* MR14 */ /* MR14 */ /* Need to determine whether the guess block is an */ /* MR14 */ /* of the form (alpha)? beta before follow sets are */ /* MR14 */ /* computed. This is necessary to solve problem */ /* MR14 */ /* of doing follow on the alpha of an (alpha)? beta block. */ /* MR14 */ /* MR14 */ /* This is performed by analysis_point as a side-effect. */ /* MR14 */ /* MR14 */ /* MR14 */ if (j->jtype == aSubBlk && j->guess) { /* MR14 */ Junction *ignore; /* MR14 */ ignore=analysis_point(j); /* MR14 */ } /* MR14 */ return; case nRuleRef : if ( r->linked ) return; q = (RuleEntry *) hash_get(Rname, r->text); if ( q == NULL ) { warnFL( eMsg1("rule %s not defined",r->text), FileStr[r->file], r->line ); } else { if ( r->parms!=NULL && RulePtr[q->rulenum]->pdecl==NULL ) { warnFL( eMsg1("rule %s accepts no parameter(s)", r->text), FileStr[r->file], r->line ); } if ( r->parms==NULL && RulePtr[q->rulenum]->pdecl!=NULL ) { warnFL( eMsg1("rule %s requires parameter(s)", r->text), FileStr[r->file], r->line ); } if ( r->assign!=NULL && RulePtr[q->rulenum]->ret==NULL ) { warnFL( eMsg1("rule %s yields no return value(s)", r->text), FileStr[r->file], r->line ); } if ( r->assign==NULL && RulePtr[q->rulenum]->ret!=NULL ) { warnFL( eMsg1("rule %s returns a value(s)", r->text), FileStr[r->file], r->line ); } if ( !r->linked ) { addFoLink( r->next, r->rname, RulePtr[q->rulenum] ); r->linked = TRUE; } } FoLink( r->next ); return; case nToken : FoLink( ((TokNode *)p)->next ); return; case nAction : FoLink( ((ActionNode *)p)->next ); return; default : fatal_internal("invalid node type"); } } /* * Add a reference to the end of a rule. * * 'r' points to the RuleBlk node in a rule. r->end points to the last node * (EndRule jtype) in a rule. * * Initial: * r->end --> o * * After: * r->end --> o-->o--> Ptr to node following rule r in another rule * | * o--> Ptr to node following another reference to r. * * Note that the links are added to the head of the list so that r->end->p1 * always points to the most recently added follow-link. At the end, it should * point to the last reference found in the grammar (starting from the 1st rule). */ void #ifdef __USE_PROTOS addFoLink( Node *p, char *rname, Junction *r ) #else addFoLink( p, rname, r ) Node *p; char *rname; Junction *r; #endif { Junction *j; require(r!=NULL, "addFoLink: incorrect rule graph"); require(r->end!=NULL, "addFoLink: incorrect rule graph"); require(r->end->jtype==EndRule, "addFoLink: incorrect rule graph"); require(p!=NULL, "addFoLink: NULL FOLLOW link"); j = newJunction(); j->rname = rname; /* rname on follow links point to target rule */ j->p1 = p; /* link to other rule */ j->p2 = (Node *) r->end->p1;/* point to head of list */ r->end->p1 = (Node *) j; /* reset head to point to new node */ } void #ifdef __USE_PROTOS GenCrossRef( Junction *p ) #else GenCrossRef( p ) Junction *p; #endif { set a; Junction *j; RuleEntry *q; unsigned e; require(p!=NULL, "GenCrossRef: why are you passing me a null grammar?"); printf("Cross Reference:\n\n"); a = empty; for (; p!=NULL; p = (Junction *)p->p2) { printf("Rule %20s referenced by {", p->rname); /* make a set of rules for uniqueness */ for (j = (Junction *)(p->end)->p1; j!=NULL; j = (Junction *)j->p2) { q = (RuleEntry *) hash_get(Rname, j->rname); require(q!=NULL, "GenCrossRef: FoLinks are screwed up"); set_orel(q->rulenum, &a); } for (; !set_nil(a); set_rm(e, a)) { e = set_int(a); printf(" %s", RulePtr[e]->rname); } printf(" }\n"); } set_free( a ); } /* The single argument is a pointer to the start of an element of a C++ style function prototypet list. Given a pointer to the start of an formal we must locate the comma (or the end of the string) and locate the datatype, formal name, and initial value expression. The function returns a pointer to the character following the comma which terminates the formal declaration, or a pointer to the end of the string if none was found. I thought we were parsing specialists, how come I'm doing this by hand written code ? Examples of input: Foo f, Foo f = Foo(1), Foo f = Foo(1,2), Foo f = &farray[1,2], Foo f = ",", Foo f = ',', TFoo f = TFoo(1,2), A non-zero value for nesting indicates a problem matching '(' and ')', '[' and ']', '<' and '>', '{' and '}', or improperly terminated string or character literal. */ /* * Don't care if it is a valid string literal or not, just find the end * Start with pointer to leading "\"" */ #ifdef __USE_PROTOS char * skipStringLiteral(char *pCurrent) #else char * skipStringLiteral(pCurrent) char *pCurrent; #endif { char *p = pCurrent; if (*p == 0) return p; require (*p == '\"', "skipStringLiteral") p++; for (p = p; *p != 0; p++) { if (*p == '\\') { p++; if (*p == 0) break; p++; } if (*p == '\"') { p++; break; } } return p; } /* * Don't care if it is a valid character literal or not, just find the end * Start with pointer to leading "'" */ #ifdef __USE_PROTOS char * skipCharLiteral(char *pStart) #else char * skipCharLiteral(pStart) char *pStart; #endif { char *p = pStart; if (*p == 0) return p; require (*p == '\'', "skipCharLiteral") p++; for (p = p; *p != 0; p++) { if (*p == '\\') { p++; if (*p == 0) break; p++; } if (*p == '\'') { p++; break; } } return p; } #ifdef __USE_PROTOS char * skipSpaces(char *pStart) #else char * skipSpaces(pStart) char * pStart; #endif { char *p = pStart; while (*p != 0 && isspace(*p)) p++; return p; } #ifdef __USE_PROTOS char * skipToSeparatorOrEqualSign(char *pStart, int *pNest) #else char * skipToSeparatorOrEqualSign(pStart, pNest) char *pStart; int *pNest; #endif { char *p = pStart; int nest = 0; *pNest = (-1); while (*p != 0) { switch (*p) { case '(' : case '[' : case '<' : case '{' : nest++; p++; break; case ')' : case ']' : case '>' : case '}' : nest--; p++; break; case '"' : p = skipStringLiteral(p); break; case '\'' : p = skipCharLiteral(p); break; case '\\': p++; if (*p == 0) goto EXIT; p++; break; case ',': case '=': if (nest == 0) goto EXIT; p++; break; default: p++; } } EXIT: *pNest = nest; return p; } #ifdef __USE_PROTOS char * skipToSeparator(char *pStart, int *pNest) #else char * skipToSeparator(pStart, pNest) char *pStart; int *pNest; #endif { char * p = pStart; for ( ; ; ) { p = skipToSeparatorOrEqualSign(p, pNest); if (*pNest != 0) return p; if (*p == ',') return p; if (*p == 0) return p; p++; } } /* skip to just past the "=" separating the declaration from the initialization value */ #ifdef __USE_PROTOS char * getInitializer(char *pStart) #else char * getInitializer(pStart) char * pStart; #endif { char *p; char *pDataType; char *pSymbol; char *pEqualSign; char *pValue; char *pSeparator; int nest = 0; require(pStart!=NULL, "getInitializer: invalid string"); p = endFormal(pStart, &pDataType, &pSymbol, &pEqualSign, &pValue, &pSeparator, &nest); if (nest != 0) return NULL; if (pEqualSign == NULL) return NULL; if (pValue == NULL) return NULL; return strBetween(pValue, NULL, pSeparator); } /* Examines the string from pStart to pEnd-1. If the string has 0 length or is entirely white space returns 1. Otherwise 0. */ #ifdef __USE_PROTOS int isWhiteString(const char *pStart, const char *pEnd) #else int isWhiteString(pStart, pEnd) const char *pStart; const char *pEnd; #endif { const char *p; for (p = pStart; p < pEnd; p++) { if (! isspace(*p)) return 0; } return 1; } /* This replaces HasComma() which couldn't distinguish foo ["a,b"] from: foo[a,b] */ #ifdef __USE_PROTOS int hasMultipleOperands(char *pStart) #else int hasMultipleOperands(pStart) char *pStart; #endif { char *p = pStart; int nest = 0; p = skipSpaces(p); if (*p == 0) return 0; p = skipToSeparator(p, &nest); if (nest == 0 && *p == ',') return 1; return 0; } #define MAX_STR_BETWEEN_WORK_AREA 1000 static char strBetweenWorkArea[MAX_STR_BETWEEN_WORK_AREA]; /* strBetween(pStart, pNext, pStop) Creates a null terminated string by copying the text between two pointers to a work area. The start of the string is pStart. The end of the string is the character before pNext, or if pNext is null then the character before pStop. Trailing spaces are not included in the copy operation. This is used when a string contains several parts. The pNext part may be optional. The pStop will stop the scan when the optional part is not present (is a null pointer). */ #ifdef __USE_PROTOS char *strBetween(char *pStart, char *pNext, char *pStop) #else char *strBetween(pStart, pNext, pStop) char *pStart; char *pNext; char *pStop; #endif { char *p; char *q = strBetweenWorkArea; const char *pEnd; pEnd = (pNext != NULL) ? pNext : pStop; require (pEnd != NULL, "pEnd == NULL"); require (pEnd >= pStart, "pEnd < pStart"); for (pEnd--; pEnd >= pStart; pEnd--) { /* MR31 */ if (! isspace(*pEnd)) break; } for (p = pStart; p <= pEnd && q < &strBetweenWorkArea[MAX_STR_BETWEEN_WORK_AREA-2]; p++, q++) { *q = *p; } *q = 0; return strBetweenWorkArea; } /* function Returns pointer to character following separator at value which to continue search for next formal. If at the end of the string a pointer to the null byte at the end of the string is returned. pStart Pointer to the starting position of the formal list This may be the middle of a longer string, for example when looking for the end of formal #3 starting from the middle of the complete formal list. ppDataType Returns a pointer to the start of the data type in the formal. Example: pointer to "Foo". ppSymbol Returns a pointer to the start of the formal symbol. Example: pointer to "f". ppEqualSign Returns a pointer to the equal sign separating the formal symbol from the initial value. If there is no "=" then this will be NULL. ppValue Returns a pointer to the initial value part of the formal declaration. Example: pointer to "&farray[1,2]" ppSeparator Returns a pointer to the character which terminated the scan. This should be a pointer to a comma or a null byte which terminates the string. pNest Returns the nesting level when a separator was found. This is non-zero for any kind of error. This is zero for a successful parse of this portion of the formal list. */ #ifdef __USE_PROTOS char * endFormal(char *pStart, char **ppDataType, char **ppSymbol, char **ppEqualSign, char **ppValue, char **ppSeparator, int *pNest) #else char * endFormal(pStart, ppDataType, ppSymbol, ppEqualSign, ppValue, ppSeparator, pNest) char *pStart; char **ppDataType; char **ppSymbol; char **ppEqualSign; char **ppValue; char **ppSeparator; int *pNest; #endif { char *p = pStart; char *q; *ppDataType = NULL; *ppSymbol = NULL; *ppEqualSign = NULL; *ppValue = NULL; *ppSeparator = NULL; *pNest = 0; /* The first non-blank is the start of the datatype */ p = skipSpaces(p); if (*p == 0) goto EXIT; *ppDataType = p; /* We are not looking for the symbol, we are looking for the separator that follows the symbol. Then we'll back up. Search for the ',' or '=" or null terminator. */ p = skipToSeparatorOrEqualSign(p, pNest); if (*pNest != 0) goto EXIT; /* Work backwards to find start of symbol Skip spaces between the end of symbol and separator Assume that there are no spaces in the formal, but there is a space preceding the formal */ for (q = &p[-1]; q >= *ppDataType; q--) { if (! isspace(*q)) break; } if (q < *ppDataType) goto EXIT; /* MR26 Handle things like: IIR_Bool (IIR_Decl::*constraint)() Backup until we hit the end of a symbol string, then find the start of the symbol string. This wont' work for functions with prototypes, but works for the most common cases. For others, use typedef names. */ /* MR26 */ for (q = q; q >= *ppDataType; q--) { /* MR26 */ if (isalpha(*q) || isdigit(*q) || *q == '_' || *q == '$') break; /* MR26 */ } /* MR26 */ if (q < *ppDataType) goto EXIT; for (q = q; q >= *ppDataType; q--) { if ( ! (isalpha(*q) || isdigit(*q) || *q == '_' || *q == '$')) break; } *ppSymbol = &q[1]; if (*p == ',' || *p == 0) { *ppSeparator = p; goto EXIT; } *ppEqualSign = p; p = skipSpaces(++p); *ppValue = p; if (*p == 0) goto EXIT; while (*p != 0 && *pNest == 0 && *p != ',') { p = skipToSeparator(p, pNest); } if (*pNest == 0) *ppSeparator = p; EXIT: if (*p == ',') p++; return p; } cdrdao-cdrdao-f00afb2/pccts/antlr/mode.h000066400000000000000000000004341511453746600202300ustar00rootroot00000000000000#define START 0 #define STRINGS 1 #define ACTION_STRINGS 2 #define ACTION_CHARS 3 #define ACTION_COMMENTS 4 #define TOK_DEF_COMMENTS 5 #define TOK_DEF_CPP_COMMENTS 6 #define ACTION_CPP_COMMENTS 7 #define CPP_COMMENTS 8 #define COMMENTS 9 #define ACTIONS 10 #define PARSE_ENUM_FILE 11 cdrdao-cdrdao-f00afb2/pccts/antlr/mrhoist.c000066400000000000000000002337061511453746600207760ustar00rootroot00000000000000/* * mrhoist.c * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33MR10 * */ #include #include "pcctscfg.h" #include "set.h" #include "syn.h" #include "hash.h" #include "generic.h" #include "dlgdef.h" #include #ifdef __USE_PROTOS void dumppred(Predicate *); #else void dumppred(); #endif /* Try to determine whether predicate "first" is true for all cases where "second" is true. Comparison takes place without regard to context. Assumes that predicate symbols have been expanded. Assumes that there are no NAND or NOR nodes */ #ifdef __USE_PROTOS int MR_secondPredicateUnreachable(Predicate *first,Predicate *second) #else int MR_secondPredicateUnreachable(first,second) Predicate *first; Predicate *second; #endif { Predicate *f; Predicate *s; if (first == NULL) { return 1; } else if (second == NULL) { return 0; } else if (first->down == NULL && second->down == NULL) { if (first->source == second->source && first->inverted == second->inverted) { return 1; /* look identical - will never reach alt2 */ } else { return 0; /* look different */ }; } else if (first->down == NULL && second->down != NULL) { if (second->expr == PRED_AND_LIST) { /* unreachable if first covers any child of second */ for (s=second->down; s != NULL; s=s->right) { if (MR_secondPredicateUnreachable(first,s)) { return 1; }; }; return 0; } else if (second->expr == PRED_OR_LIST) { /* unreachable if first covers every child of second */ for (s=second->down; s != NULL; s=s->right) { if (!MR_secondPredicateUnreachable(first,s)) { return 0; }; }; return 1; } else { require (0,"Illegal pred->expr"); return 0; /* MR20 Make compiler happy */ }; } else if (first->down != NULL && second->down == NULL) { if (first->expr == PRED_AND_LIST) { /* unreachable if every child of first covers second */ for (f=first->down; f != NULL; f=f->right) { if (!MR_secondPredicateUnreachable(f,second)) { return 0; }; }; return 1; } else if (first->expr == PRED_OR_LIST) { /* unreachable if any child of first covers second */ for (f=first->down; f != NULL; f=f->right) { if (MR_secondPredicateUnreachable(f,second)) { return 1; }; }; return 0; } else { require (0,"Illegal predicate->expr"); return 0; /* MR20 Make compiler happy */ }; } else { if (first->expr == PRED_AND_LIST && second->expr == PRED_AND_LIST) { /* unreachable if each child of first covers at least one child of second */ for (f=first->down; f != NULL ; f=f->right) { for (s=second->down; s != NULL ; s=s->right) { if (MR_secondPredicateUnreachable(f,s)) goto A_next_f; }; return 0; A_next_f: continue; }; return 1; } else if (first->expr == PRED_AND_LIST && second->expr == PRED_OR_LIST) { /* unreachable if each child of first covers ALL of second's children */ for (f=first->down; f != NULL ; f=f->right) { for (s=second->down; s != NULL ; s=s->right) { if (!MR_secondPredicateUnreachable(f,s)) return 0; }; }; return 1; } else if (first->expr == PRED_OR_LIST && second->expr == PRED_AND_LIST) { /* unreachable if any child of second is covered by any child of first */ for (f=first->down; f != NULL ; f=f->right) { for (s=second->down; s != NULL ; s=s->right) { if (MR_secondPredicateUnreachable(f,s)) return 1; }; }; return 0; } else if (first->expr == PRED_OR_LIST && second->expr == PRED_OR_LIST) { /* unreachable if every child of second is covered by some child of first */ for (f=first->down; f != NULL ; f=f->right) { for (s=second->down; s != NULL ; s=s->right) { if (MR_secondPredicateUnreachable(f,s)) goto B_next_f; }; return 0; B_next_f: continue; }; return 1; } else { require (0,"Illegal predicate->expr"); return 0; /* MR20 Make compiler happy */ }; }; return 0; /* MR20 MSVC 5.0 complains about missing return statement */ } #ifdef __USE_PROTOS void MR_xxxIndent(FILE *f,int depth) #else void MR_xxxIndent(f,depth) FILE *f; int depth; #endif { int i; for (i=0; irname,rrn->line,FileStr[rrn->file],rrn->text); }; lastOne=MR_ruleReferenced(rrn); if (lastOne != NULL) { for (j=0; jrname,lastOne->line,FileStr[lastOne->file]); }; } #ifdef __USE_PROTOS void MR_dumpTreeF(FILE *f,int depth,Tree *tree,int across) #else void MR_dumpTreeF(f,depth,tree,across) FILE *f; Tree *tree; int depth; int across; #endif { int newAcross=across; if (tree == NULL ) return; if (tree->down != NULL ) { fprintf(output,"\n"); MR_outputIndent(depth); fprintf(output, "(root ="); }; if (tree->token == ALT ) { fprintf(output," %-16s","Alt"); } else if (tree->token==EpToken ) { fprintf(output,"(%d)%13s",tree->v.rk," "); } else { fprintf(output," %-16s",TerminalString(tree->token)); }; if (tree->down != NULL) { fprintf(output,"\n"); MR_outputIndent(depth+1); MR_dumpTreeF(f,depth+1,tree->down,1); newAcross=0; fprintf(output,"\n"); MR_outputIndent(depth); fprintf(output,")"); }; if (newAcross > 3) { fprintf(output,"\n"); MR_outputIndent(depth); newAcross=0; }; MR_dumpTreeF(f,depth,tree->right,newAcross+1); } #ifdef __USE_PROTOS void MR_dumpTreeX(int depth,Tree *tree,int across) #else void MR_dumpTreeX(depth,tree,across) Tree *tree; int depth; int across; #endif { MR_dumpTreeF(output,depth,tree,across); } #ifdef __USE_PROTOS void MR_dumpTokenSet(FILE *f,int depth,set s) #else void MR_dumpTokenSet(f,depth,s) FILE *f; int depth; set s; #endif { int i; int j; unsigned *pdq; if (set_nil(s)) { fprintf(f,"\n"); MR_xxxIndent(f,depth+1); fprintf(f,"nil\n"); return; }; pdq=set_pdq(s); require(pdq != NULL,"set_pdq failed"); i=0; for (i=0 ; ; i=i+4) { fprintf(f,"\n"); MR_xxxIndent(f,depth+1); for (j=0; j < 4 ; j++) { if (pdq[i+j] == nil) break; fprintf(f," %-16s",TerminalString(pdq[i+j])); }; if (pdq[i+j] == nil) break; }; fprintf(f,"\n"); free( (char *) pdq); } #ifdef __USE_PROTOS void MR_dumpPred1(int depth,Predicate *p,int withContext) #else void MR_dumpPred1(depth,p,withContext) int depth; Predicate *p; int withContext; #endif { unsigned k; if (p == NULL) { MR_outputIndent(depth); fprintf(output,"The predicate is empty (or always true)\n\n"); return; }; if (p->down != NULL) { MR_outputIndent(depth); if (p->inverted) { /* MR14a Left out print expression in fprintf Reported by Manuel Kessler (mlkessle@cip.physik.uni-wuerzburg.de) */ if (p->expr == PRED_AND_LIST) fprintf(output,"%s NAND (not AND) expr\n\n",p->expr); if (p->expr == PRED_OR_LIST) fprintf(output,"%s NOR (not OR) expr\n\n",p->expr); } else { fprintf(output,"%s expr\n\n",p->expr); }; } else { MR_outputIndent(depth); fprintf(output,"pred %s <<%s>>?\n", (p->inverted ? " *not*" : ""), (p->expr == NULL ? "null expr" : p->expr)); MR_outputIndent(depth+1); fprintf(output," "); fprintf(output," depth=k=%d",p->k); if (p->source != NULL && p->source->guardpred) { fprintf(output," (\"=>\" guard)"); } if (p->source != NULL && p->source->ampersandPred != NULL) { fprintf(output," (\"&&\" guard)"); }; k=set_int(p->completionSet); if (k != nil) { fprintf(output," Incomplete Set at k=%d !",k); }; k=set_int(p->completionTree); if (k != nil) { fprintf(output," Incomplete Tree at k=%d !",k); }; if (p->source != NULL) { fprintf(output," rule %s line %d %s", p->source->rname,p->source->line,FileStr[p->source->file]); }; fprintf(output,"\n"); if (withContext && (HoistPredicateContext || ! set_nil(p->scontext[1]) || p->tcontext != NULL)) { if (p->k == 1) { MR_outputIndent(depth+1); fprintf(output,"set context: "); MR_dumpTokenSet(output,depth+1,p->scontext[1]); } if (p->k != 1) { MR_outputIndent(depth+1); fprintf(output,"tree context:"); if (p->tcontext == NULL) { fprintf(output," null"); } else { MR_dumpTreeX(depth+2,p->tcontext,0); }; fprintf(output,"\n"); }; }; fprintf(output,"\n"); }; if (p->down != NULL) { MR_dumpPred1(depth+1,p->down,withContext); }; if (p->right != NULL) { MR_dumpPred1(depth,p->right,withContext); }; } #ifdef __USE_PROTOS void MR_dumpPred(Predicate *p,int withContext) #else void MR_dumpPred(p,withContext) Predicate *p; int withContext; #endif { MR_dumpPred1(0,p,withContext); } #ifdef __USE_PROTOS Tree * MR_make_tree_from_set(set s) #else Tree * MR_make_tree_from_set(s) set s; #endif { Tree *t=NULL; Tree *node; Tree **tp=&t; int i; unsigned *pdq=set_pdq(s); if (pdq != NULL) { for (i=0 ; pdq[i] != nil ; i++) { node=tnode( (int) pdq[i]); *tp=node; tp=&(node->right); }; *tp=NULL; free ( (char *) pdq); }; return t; } #ifdef __USE_PROTOS void MR_check_pred_too_long(Predicate *p,set completion) #else void MR_check_pred_too_long(p,completion) Predicate *p; set completion; #endif { if (p != NULL && p->source != NULL && ! p->source->predTooLong) { if ( !set_nil(completion)) { p->source->predTooLong=1; warnFL("It is unusual (but ok) for a semantic predicate to test context past the end of its own rule", FileStr[p->source->file],p->source->line); }; }; } #ifdef __USE_PROTOS int MR_predicate_context_completed(Predicate *p) #else int MR_predicate_context_completed(p) Predicate *p; #endif { if (p == NULL) return 1; if (p->expr != PRED_AND_LIST && p->expr != PRED_OR_LIST) { if ( ! set_nil(p->completionSet)) return 0; if ( ! set_nil(p->completionTree)) return 0; }; return MR_predicate_context_completed(p->down) & MR_predicate_context_completed(p->right); } #ifdef __USE_PROTOS Node * MR_advance(Node *n) #else Node * MR_advance(n) Node *n; #endif { if (n == NULL) return NULL; switch (n->ntype) { case nJunction: return ((Junction *)n)->p1; case nToken: return ((TokNode *)n)->next; case nRuleRef: return ((RuleRefNode *)n)->next; case nAction: return ((ActionNode *)n)->next; default: return NULL; }; return NULL; /* MSVC 5.0 complains about missing return statement */ } #ifdef __USE_PROTOS Junction * MR_find_endRule(Node *n) #else Junction * MR_find_endRule(n) Node *n; #endif { Node *next; if (n == NULL) return NULL; for (next=n; next != NULL; next=MR_advance(next)) { if (next->ntype == nJunction && ( (Junction *) next)->jtype == EndRule) { break; }; }; return (Junction *)next; } /* Intersection: a branch which is shorter is chosen over one which is longer: (A B C) intersect (A B) yields (A B). AND: a branch which is longer is chosen over the one which is shorter: (A B C) AND (A B) yields (A B C) */ #ifdef __USE_PROTOS Tree *MR_computeTreeIntersection(Tree *l,Tree *r) #else Tree *MR_computeTreeIntersection(l,r) Tree *l; Tree *r; #endif { Tree *result=NULL; Tree **tail; Tree *p; Tree *q; Tree *match; if (l == NULL || r == NULL) return NULL; for (p=l; p != NULL; p=p->right) { require(p->token != EpToken,"MR_computeTreeIntersection: p->EpToken unexpected\n"); require (p->token != ALT,"MR_computeTreeIntersection: p->ALT unexpected\n"); }; for (q=r; q != NULL; q=q->right) { require(q->token != EpToken,"MR_computeTreeIntersection: q->EpToken unexpected\n"); require(q->token != ALT,"MR_computeTreeIntersection: q->ALT unexpected\n"); }; result=tnode(ALT); tail=&(result->down); for (p=l; p != NULL ; p=p->right) { for (q=r; q != NULL ; q=q->right) { if (p->token == q->token) { match=tnode(p->token); match->down=MR_computeTreeIntersection(p->down,q->down); *tail=match; tail=&(match->right); }; }; }; *tail=NULL; result=tshrink(result); result=tflatten( result ); result=tleft_factor( result ); return result; } /* the predicates which are ANDed together have a common context: they must all have common roots. Thus the AND operation is more like an OR operation because branches which are longer are grafted onto shorter branches of the AND tree. For instance combining (A B C) with (A B C D) gives (A B C D). There should never be a case of (A B C) and (A B D) because they have the same context. Actually, this may not be true once one throws in guard predicates which are defined by the user, not the context. */ /* requires input trees to be in "canonical" format */ #ifdef __USE_PROTOS Tree *MR_computeTreeAND(Tree *l,Tree *r) #else Tree *MR_computeTreeAND(l,r) Tree *l; Tree *r; #endif { Tree *result=NULL; Tree **tail; Tree *p; Tree *q; Tree *match; if (l == NULL) return tdup(r); if (r == NULL) return tdup(l); for (p=l; p != NULL; p=p->right) { /**** require(p->token != EpToken,"MR_computeTreeAND: p->EpToken unexpected\n"); ****/ require (p->token != ALT,"MR_computeTreeAND: p->ALT unexpected\n"); }; for (q=r; q != NULL; q=q->right) { /**** require(q->token != EpToken,"MR_computeTreeAND: q->EpToken unexpected\n"); ****/ require(q->token != ALT,"MR_computeTreeAND: q->ALT unexpected\n"); }; result=tnode(ALT); tail=&(result->down); for (p=l; p != NULL ; p=p->right) { for (q=r; q != NULL ; q=q->right) { if (p->token == q->token) { match=tnode(p->token); match->down=MR_computeTreeAND(p->down,q->down); *tail=match; tail=&(match->right); }; }; }; *tail=NULL; result=tshrink(result); result=tflatten( result ); result=tleft_factor( result ); return result; } #ifdef __USE_PROTOS void MR_union_plain_sets1(Predicate *p,set *theUnion) #else void MR_union_plain_sets1(p,theUnion) Predicate *p; set *theUnion; #endif { if (p == NULL) return; MR_union_plain_sets1(p->down,theUnion); MR_union_plain_sets1(p->right,theUnion); set_orin(theUnion,p->plainSet); return; } #ifdef __USE_PROTOS set MR_union_plain_sets(Predicate *p) #else set MR_union_plain_sets(p) Predicate *p; #endif { set theUnion; theUnion=empty; MR_union_plain_sets1(p,&theUnion); return theUnion; } /* does NOT left factor: do not want to merge (A B) with (A) to get (A B) in fact the opposite: (A B) with (A) gives (A) */ #ifdef __USE_PROTOS Tree *MR_compute_pred_tree_ctxXX(Predicate *p) #else Tree *MR_compute_pred_tree_ctxXX(p) Predicate *p; #endif { Tree *result=NULL; Predicate *q; Tree *t; if (p == NULL) return NULL; /* this appears strange: why do we OR the context of and AND predicate ? It is because of the way that predicates are evaluated: if the context is wrong then it's the same as if the predicate was true. That means that even when one leg of an AND has unmatched context, if the other leg has matched context and is true then the predicate succeeds. It's only when all the legs have unmatched context that this one can skip evaluation of the predicates. */ if (p->expr == PRED_OR_LIST || p->expr == PRED_AND_LIST) { for (q=p->down; q != NULL ; q=q->right) { t=MR_compute_pred_tree_ctxXX(q); result=tappend(result,t); t=NULL; }; result=tshrink(result); result=tflatten( result ); /* does NOT left factor: do not want to merge (A B) with (A) to get (A B) in fact the opposite: (A B) with (A) gives (A) */ /**** result=tleft_factor( result ); ****/ return result; }; #if 0 ** if (p->expr == PRED_AND_LIST) { ** ** Predicate *l; ** Predicate *r; ** Tree *l1; ** Tree *r1; ** Tree *prevl1; ** ** l=p->down; ** require (l->right != NULL,"MR_compute_pred_tree - AND has only one child"); ** **/* l1 and r1 should already be in "canonical" format */ ** ** l1=MR_compute_pred_tree(l); ** for (r=l->right; r != NULL; r=r->right) { ** r1=MR_compute_pred_tree(r); ** prevl1=l1; ** l1=MR_computeTreeAND(l1,r1); ** Tfree(r1); ** Tfree(prevl1); ** }; ** **/* result from computeTreeAND should be in "canonical" format */ ** ** result=l1; ** **/* result of MR_computeTreeAND should be in "canonical" format */ ** ** return result; ** }; #endif if (p->k == 1) { result=MR_make_tree_from_set(p->scontext[1]); } else { result=tdup(p->tcontext); result=MR_remove_epsilon_from_tree(result); result=tshrink(result); result=tflatten(result); result=tleft_factor(result); }; return result; } #ifdef __USE_PROTOS void MR_pred_depth(Predicate *p,int *maxDepth) #else void MR_pred_depth(p,maxDepth) Predicate *p; int *maxDepth; #endif { if (p == NULL) return; if (p->expr != PRED_OR_LIST && p->expr != PRED_AND_LIST) { if (p->k > *maxDepth) *maxDepth=p->k; }; MR_pred_depth(p->down,maxDepth); MR_pred_depth(p->right,maxDepth); } /* this computes the OR of all the contexts */ #ifdef __USE_PROTOS set MR_compute_pred_set(Predicate *p) #else set MR_compute_pred_set(p) Predicate *p; #endif { set result; Predicate *q; result=empty; if (p == NULL) return empty; if (p->expr == PRED_OR_LIST || p->expr == PRED_AND_LIST) { /* yes, I do mean PRED_AND_LIST ! */ /* remember: r1: (A)? => <

>? r2; */ /* r2: (B)? => <>? r3; */ set t; t=empty; result=empty; for (q=p->down; q != NULL; q=q->right) { t=MR_compute_pred_set(q); set_orin(&result,t); set_free(t); }; return result; } else if (p->k > 1) { return empty; } else { return set_dup(p->scontext[1]); }; } #ifdef __USE_PROTOS set MR_First(int ck,Junction *j,set *incomplete) #else set MR_First(ck,j,incomplete) int ck; Junction *j; set *incomplete; #endif { Junction *p; set tokensUsed; tokensUsed=empty; require(j->ntype==nJunction, "MR_First: non junction passed"); p = analysis_point((Junction *)j->p1); REACH(p,ck,incomplete,tokensUsed); return tokensUsed; } #ifdef __USE_PROTOS void MR_cleanup_pred_trees(Predicate *p) #else void MR_cleanup_pred_trees(p) Predicate *p; #endif { Tree *t; if (p == NULL) return; if (p->expr != PRED_OR_LIST && p->expr != PRED_AND_LIST) { t=p->tcontext; t=tshrink(t); t=tflatten(t); t=tleft_factor(t); p->tcontext=t; }; MR_cleanup_pred_trees(p->down); MR_cleanup_pred_trees(p->right); } /* does NOT return canonical tree */ #ifdef __USE_PROTOS Tree * MR_remove_epsilon_from_tree(Tree *t) #else Tree * MR_remove_epsilon_from_tree(t) Tree *t; #endif { if (t == NULL) return NULL; /* I think ALT can be ignored as a special case */ if (t->token != EpToken) { t->down=MR_remove_epsilon_from_tree(t->down); t->right=MR_remove_epsilon_from_tree(t->right); return t; } else { Tree *u; u=MR_remove_epsilon_from_tree(t->right); t->right=NULL; Tfree(t); return u; }; } #ifdef __USE_PROTOS void MR_complete_set(int predDepth,set *tokensUsed,set *incomplete) #else void MR_complete_set(predDepth,tokensUsed,incomplete) int predDepth; set *tokensUsed; set *incomplete; #endif { int i; RuleRefNode *ruleRef; set rk2; set b; int k2; Junction *save_MR_RuleBlkWithHalt; if (set_int(*incomplete) > (unsigned) predDepth) { return; }; require(MR_PredRuleRefStack.count == MR_RuleBlkWithHaltStack.count, "RuleRefStack and RuleBlkWithHaltStack not same size"); require(MR_RuleBlkWithHalt == NULL || (MR_RuleBlkWithHalt->jtype == RuleBlk && MR_RuleBlkWithHalt->end->halt == TRUE), "RuleBlkWithHalt has no halt set"); save_MR_RuleBlkWithHalt=MR_RuleBlkWithHalt; if (MR_RuleBlkWithHalt != NULL) { MR_RuleBlkWithHalt->end->halt=FALSE; }; for (i=MR_PredRuleRefStack.count-1; i >= 0 ; i--) { ruleRef=(RuleRefNode *)MR_PredRuleRefStack.data[i]; if (ruleRef == NULL) continue; MR_RuleBlkWithHalt=(Junction *)MR_RuleBlkWithHaltStack.data[i]; if (MR_RuleBlkWithHalt != NULL) MR_RuleBlkWithHalt->end->halt=TRUE; rk2=empty; b=empty; while ( !set_nil(*incomplete) ) { k2=set_int(*incomplete); if (k2 > predDepth) break; /* <=== another exit from loop */ set_rm(k2,*incomplete); REACH(ruleRef->next,k2,&rk2,b); set_orin(tokensUsed,b); set_free(b); }; if (MR_RuleBlkWithHalt != NULL) MR_RuleBlkWithHalt->end->halt=FALSE; set_orin(incomplete,rk2); /* remember what we couldn't do */ set_free(rk2); if (set_int(*incomplete) > (unsigned) predDepth) break; /* <=== another exit from loop */ }; MR_RuleBlkWithHalt=save_MR_RuleBlkWithHalt; if (MR_RuleBlkWithHalt != NULL) { MR_RuleBlkWithHalt->end->halt=TRUE; }; } #ifdef __USE_PROTOS void MR_complete_tree(int predDepth,Tree **t,set *incomplete) #else void MR_complete_tree(predDepth,t,incomplete) int predDepth; Tree **t; set *incomplete; #endif { int i; RuleRefNode *ruleRef; set rk2; Tree *u; unsigned k2; Junction *save_MR_RuleBlkWithHalt; int saveConstrainSearch; if (set_int(*incomplete) > (unsigned) predDepth) { return; }; require(MR_PredRuleRefStack.count == MR_RuleBlkWithHaltStack.count, "RuleRefStack and RuleBlkWithHaltStack not same size"); require(MR_RuleBlkWithHalt == NULL || (MR_RuleBlkWithHalt->jtype == RuleBlk && MR_RuleBlkWithHalt->end->halt == TRUE), "RuleBlkWithHalt has no halt set"); save_MR_RuleBlkWithHalt=MR_RuleBlkWithHalt; saveConstrainSearch=ConstrainSearch; ConstrainSearch=0; if (MR_RuleBlkWithHalt != NULL) { MR_RuleBlkWithHalt->end->halt=FALSE; }; for (i=MR_PredRuleRefStack.count-1; i >= 0 ; i--) { ruleRef=(RuleRefNode *)MR_PredRuleRefStack.data[i]; if (ruleRef == NULL) continue; MR_RuleBlkWithHalt=(Junction *)MR_RuleBlkWithHaltStack.data[i]; if (MR_RuleBlkWithHalt != NULL) MR_RuleBlkWithHalt->end->halt=TRUE; rk2=empty; while ( !set_nil(*incomplete) ) { k2 = set_int(*incomplete); if (k2 > (unsigned) predDepth) break; /* <=== another exit from loop */ set_rm(k2,*incomplete); u = NULL; TRAV(ruleRef->next,k2,&rk2,u); /* any subtrees missing k2 tokens, add u onto end */ *t=tlink(*t,u,k2); Tfree(u); } set_orin(incomplete,rk2); /* remember what we couldn't do */ set_free(rk2); if (MR_RuleBlkWithHalt != NULL) MR_RuleBlkWithHalt->end->halt=FALSE; if (set_int(*incomplete) > (unsigned) predDepth) break; /* <=== another exit from loop */ }; MR_RuleBlkWithHalt=save_MR_RuleBlkWithHalt; if (MR_RuleBlkWithHalt != NULL) { MR_RuleBlkWithHalt->end->halt=TRUE; }; ConstrainSearch=saveConstrainSearch; } #ifdef __USE_PROTOS void MR_complete_predicates(int predDepth,Predicate *pred) #else void MR_complete_predicates(predDepth,pred) int predDepth; Predicate *pred; #endif { if (pred == NULL) return; if (pred->expr != PRED_AND_LIST && pred->expr != PRED_OR_LIST) { MR_complete_set(predDepth,&(pred->scontext[1]),&(pred->completionSet)); MR_complete_tree(predDepth,&(pred->tcontext),&(pred->completionTree)); }; MR_complete_predicates(predDepth,pred->down); MR_complete_predicates(predDepth,pred->right); } #ifdef __USE_PROTOS Junction * MR_junctionWithoutP2(Junction *j) #else Junction * MR_junctionWithoutP2(j) Junction *j; #endif { Junction *thisAlt; /* don't want to follow p2 to the next alternative of this rule */ /* insert a generic node with null p2 if necessary */ /* however FIRST requires a junction */ thisAlt=j; if (thisAlt->p2 != NULL) { if (thisAlt->p1->ntype == nJunction) { thisAlt=(Junction *) thisAlt->p1; } else { thisAlt=newJunction(); thisAlt->p1=j->p1; thisAlt->rname=j->rname; thisAlt->file=j->file; thisAlt->line=j->line; j->p1=(Node *)thisAlt; }; }; return thisAlt; } #ifdef __USE_PROTOS int MR_tree_equ(Tree *big, Tree *small) { #else int MR_tree_equ(big,small) Tree *big; Tree *small; { #endif Tree *b; Tree *s; int bcount=0; int scount=0; if (small == NULL && big == NULL) return 1; if (small == NULL) return 0; if (big == NULL) return 0; if (small->token == ALT) { require(small->right == NULL, "MR_tree_equ: small: ALT node has siblings"); return MR_tree_equ(big,small->down); }; if (big->token == ALT) { require(big->right == NULL, "MR_tree_equ: big: ALT node has siblings"); return MR_tree_equ(big->down,small); }; for (s=small; s != NULL; s=s->right) { scount++; require(s->token != EpToken,"MR_tree_equ: s->EpToken unexpected\n"); }; for (b=big; b != NULL; b=b->right) { bcount++; require(b->token != EpToken,"MR_tree_equ: b->EpToken unexpected\n"); }; if (bcount != scount) return 0; for (s=small; s != NULL; s=s->right) { for (b=big; b!= NULL; b=b->right) { if (s->token == b->token) { if (MR_tree_equ(b->down,s->down)) goto next_s; }; }; return 0; next_s: continue; }; return 1; } /* this does not compare sources - only contexts ! */ #ifdef __USE_PROTOS int MR_identicalContext(Predicate *p,Predicate *q) #else int MR_identicalContext(p,q) Predicate *p; Predicate *q; #endif { if (p->k != q->k) return 0; require ( (p->tcontext == NULL) == (q->tcontext == NULL), "tcontext inconsistent"); if (p->k == 1) { return set_equ(p->scontext[1],q->scontext[1]); } else { return MR_tree_equ(p->tcontext,q->tcontext); }; } #ifdef __USE_PROTOS void MR_reportSetSuppression(int predDepth, set predSet,set plainSet,Junction *jPred,Junction *jPlain,Predicate *p) #else void MR_reportSetSuppression(predDepth,predSet,plainSet,jPred,jPlain,p) int predDepth; set predSet; set plainSet; Junction *jPred; Junction *jPlain; Predicate *p; #endif { if (InfoP) { fprintf(output,"\n#if 0\n\n"); fprintf(output,"Hoisting of predicate suppressed by alternative without predicate.\n"); fprintf(output,"The alt without the predicate includes all cases where the predicate is false.\n\n"); fprintf(output," WITH predicate: line %d %s\n",jPred->line,FileStr[jPred->file]); if (jPlain != NULL) { fprintf(output," WITHOUT predicate: line %d %s\n",jPlain->line,FileStr[jPlain->file]); } else { fprintf(output," WITHOUT predicate: all alternatives without predicates (combined)\n"); }; if (predDepth == 1) { fprintf(output,"\nThe context set for the predicate:\n"); MR_dumpTokenSet(output,1,predSet); }; fprintf(output,"\nThe lookahead set for the alt WITHOUT the semantic predicate:\n"); MR_dumpTokenSet(output,1,plainSet); fprintf(output,"\nThe predicate:\n\n"); MR_dumpPred1(1,p,1); fprintf(output,"Chain of referenced rules:\n\n"); MR_dumpPredRuleRefStack(output,4); fprintf(output,"\n#endif\n"); }; } #ifdef __USE_PROTOS void MR_reportSetRestriction(int predDepth,set predSet,set plainSet, Junction *jPred,Junction *jPlain,Predicate *origPred,Predicate *newPred) #else void MR_reportSetRestriction(predDepth,predSet,plainSet,jPred,jPlain,origPred,newPred) int predDepth; set predSet; set plainSet; Junction *jPred; Junction *jPlain; Predicate *origPred; Predicate *newPred; #endif { set intersect; intersect=empty; if (! InfoP) return; fprintf(output,"\n#if 0\n\n"); fprintf(output,"Restricting the context of a predicate because of overlap in the lookahead set\n"); fprintf(output," between the alternative with the semantic predicate and one without\n"); fprintf(output,"Without this restriction the alternative without the predicate could not\n"); fprintf(output," be reached when input matched the context of the predicate and the predicate\n"); fprintf(output," was false.\n\n"); fprintf(output," WITH predicate: line %d %s\n",jPred->line,FileStr[jPred->file]); if (jPlain != NULL) { fprintf(output," WITHOUT predicate: line %d %s\n",jPlain->line,FileStr[jPlain->file]); } else { fprintf(output," WITHOUT predicate: all alternatives without predicates (combined)\n"); }; if (predDepth == 1) { fprintf(output,"\nThe original context set for the predicate:\n"); MR_dumpTokenSet(output,1,predSet); }; fprintf(output,"\nThe lookahead set for the alt WITHOUT the semantic predicate:\n"); MR_dumpTokenSet(output,1,plainSet); if (predDepth == 1) { fprintf(output,"\nThe intersection of the two sets\n"); intersect=set_and(predSet,plainSet); MR_dumpTokenSet(output,1,intersect); set_free(intersect); }; fprintf(output,"\nThe original predicate:\n\n"); MR_dumpPred1(1,origPred,1); fprintf(output,"The new (modified) form of the predicate:\n\n"); MR_dumpPred1(1,newPred,1); fprintf(output,"#endif\n"); } /* don't use Pass3 by itself unless you know that inverted is not important */ #ifdef __USE_PROTOS Predicate * MR_removeRedundantPredPass3(Predicate *p) #else Predicate * MR_removeRedundantPredPass3(p) Predicate *p; #endif { Predicate *q; if (p == NULL) return NULL; p->right=MR_removeRedundantPredPass3(p->right); p->down=MR_removeRedundantPredPass3(p->down); if (p->redundant) { q=p->right; p->right=NULL; predicate_free(p); return q; }; if (p->expr == PRED_AND_LIST || p->expr == PRED_OR_LIST) { if (p->down == NULL) { q=p->right; p->right=NULL; predicate_free(p); return q; }; if (p->down != NULL && p->down->right == NULL) { q=p->down; q->right=p->right; p->right=NULL; p->down=NULL; return q; }; }; return p; } #ifdef __USE_PROTOS void MR_removeRedundantPredPass2(Predicate *p) #else void MR_removeRedundantPredPass2(p) Predicate *p; #endif { Predicate *q; if (p == NULL) return; if (p->expr == PRED_AND_LIST) { for (q=p->down ; q != NULL ; q=q->right) { MR_removeRedundantPredPass2(q); if (q->isConst) { if (q->constValue == 0) { p->isConst=1; p->constValue=0; return; } else { q->redundant=1; }; }; }; }; if (p->expr == PRED_OR_LIST) { for (q=p->down ; q != NULL ; q=q->right) { MR_removeRedundantPredPass2(q); if (q->isConst) { if (q->constValue == 0) { q->redundant=1; } else { p->isConst=1; p->constValue=1; return; }; }; }; }; return; } #if 0 this totally ignores the implications of guarded predicates in which the part after the guard could possibly cover a predicate. that would be much harder: rule : (A)? => <

>? sub1; /* 1 */ | (B)? => <>? sub2 /* 2 */ sub1 : (A)? => <>? A B /* 3 */ | B /* 4 - suppresses line 2 */ ; #endif #ifdef __USE_PROTOS void MR_apply_restriction1(Predicate *pred,set *plainSet,int *changed) #else void MR_apply_restriction1(pred,plainSet,changed) Predicate *pred; set *plainSet; int *changed; #endif { if (pred == NULL) return; MR_apply_restriction1(pred->right,plainSet,changed); if (pred->down != NULL) { MR_apply_restriction1(pred->down,plainSet,changed); } else { set t; if (pred->k == 1) { t=set_dif(pred->scontext[1],*plainSet); if (*changed == 0 && !set_equ(t,pred->scontext[1])) { *changed=1; }; if (set_nil(t)) { pred->redundant=1; }; set_free(pred->scontext[1]); pred->scontext[1]=t; }; }; } #ifdef __USE_PROTOS void MR_orin_plainSet(Predicate *p,set plainSet) #else void MR_orin_plainSet(p,plainSet) Predicate *p; set plainSet; #endif { if (p == NULL) return; MR_orin_plainSet(p->down,plainSet); MR_orin_plainSet(p->right,plainSet); set_orin(&p->plainSet,plainSet); } Predicate *PRED_SUPPRESS; #ifdef __USE_PROTOS Predicate * MR_find_in_aSubBlk(Junction *alt) #else Predicate * MR_find_in_aSubBlk(alt) Junction *alt; #endif { Predicate *root=NULL; Predicate **tail=NULL; Junction *p; int nAlts=0; Junction **jList; Predicate **predList; int *matchList; set predSet; int i; int j; int m; int predDepth; set incomplete; set union_plainSet; set setChange; int changed; Predicate *newPred; set setDif; Predicate *origPred; int depth1=1; /* const int */ set *plainContext; set plainSet; predSet=empty; incomplete=empty; union_plainSet=empty; setChange=empty; setDif=empty; plainSet=empty; if (PRED_SUPPRESS == NULL) { PRED_SUPPRESS=new_pred(); PRED_SUPPRESS->expr="Predicate Suppressed"; }; /* this section just counts the number of "interesting" alternatives */ /* in order to allocate arrays */ for (p=alt; p!=NULL; p=(Junction *)p->p2) { /* ignore empty alts */ if ( p->p1->ntype != nJunction || ((Junction *)p->p1)->jtype != EndBlk ) { nAlts++; }; }; /* if this is a (...)+ block then don't count the last alt because it can't be taken until at least one time through the block. In other words it isn't a real choice until the (...)+ is entered at which point the hoisting issue is moot. Maybe look at "ignore" instead ? */ if (alt->jtype == aPlusBlk) { nAlts--; }; jList=(Junction **)calloc(nAlts,sizeof(Junction *)); require(jList!=NULL,"cannot allocate MR_find_in_aSubBlk jList"); plainContext=(set *)calloc(nAlts,sizeof(set)); require(plainContext!=NULL,"cannot allocate MR_find_in_aSubBlk plainContext"); for (m=0; m < nAlts; m++) plainContext[m]=empty; predList=(Predicate **)calloc(nAlts,sizeof(Predicate *)); require(predList!=NULL,"cannot allocate MR_find_in_aSubBlk predList"); matchList=(int *)calloc(nAlts,sizeof(int)); require(matchList!=NULL,"cannot allocate MR_find_in_aSubBlk matchList"); /* this section just fills in the arrays previously allocated */ /* the most interesting one is matchList[] */ /* */ /* bit 0 => this alt has a semantic pred which is "covered" */ /* by an alt without a semantic pred. Don't hoist. */ for (i=0,p=alt; p!=NULL && ip2) { /* ignore empty alts */ if ( p->p1->ntype != nJunction || ((Junction *)p->p1)->jtype != EndBlk ) { jList[i]=MR_junctionWithoutP2(p); predList[i]=find_predicates(p->p1); /* should be jList ????? */ if (predList[i] != NULL) { MR_cleanup_pred_trees(predList[i]); /* flatten & left factor */ plainContext[i]=MR_union_plain_sets(predList[i]); } else { MR_set_reuse(&plainSet); MR_set_reuse(&incomplete); plainSet=MR_First(depth1,jList[i],&incomplete); MR_complete_set(depth1,&plainSet,&incomplete); require(set_nil(incomplete),"couldn't complete k=1"); plainContext[i]=plainSet; plainSet=empty; }; set_orin(&union_plainSet,plainContext[i]); }; }; if (nAlts == 1) { goto EXIT_SIMPLE; }; /* * Looking for cases where alt i has a semantic pred and alt j does not. * Don't care about cases where lookahead for semantic predicates overlap * because normal predicate hoisting does the correct thing automatically. * Don't care about cases where lookahead for alts without semantic predicates * overlap because normal prediction does the correct thing automatically. * * When we find such a case check for one of three subcases: * * 1. if lookahead for alt i is contained in the lookahead for any * alt j then ignore semantic predicate of alt i * 2. if lookahead for alt i is not contained in the lookahead for * any alt j then add add predicate i to the OR list to be hoisted * 3. if lookahead for alt i overlaps the lookahead for some alt j then * add a dummy semantic predicate for alt j * * There is an implicit assumption that the context of all alternatives following * the rule being processed here are identical (but may vary from hoist to * hoist depending on the place where the rule was invoked that led to hoisting * these predicates. In othere words in the fragment: * * ( <>? a1 a2 a3 | <>? b1 b2 b3 ) * * both a3 and b3 have the same follow sets because they are both at the end of * alternatives in the same block. */ for (i=0; i < nAlts; i++) { if (jList[i] == NULL) continue; if (predList[i] == NULL) continue; /* if the predicate depth turns out to be one token only */ /* then it is can be easily represented as a set and */ /* compared to the junction set create by MR_First() */ predDepth=0; MR_pred_depth(predList[i],&predDepth); require (predDepth >= 1,"MR_find_in_aSubBlk: pred depth < 1"); require (predDepth <= CLL_k,"MR_find_in_aSubBlk: predDepth > CLL_k"); /* complete predicates to predDepth If completed to depth=1 then the context would be incomplete. The context would be truncated and the predicate simplify routine would have incomplete information. It would lead to either false matches of failure to find true matches. */ MR_complete_predicates(predDepth,predList[i]); if (predList[i] != NULL) { MR_cleanup_pred_trees(predList[i]); /* flatten & left factor */ }; /* If the predicate depth is 1 then it is possible to suppress a predicate completely using a single plain alt. Check for suppression by a single plain alt first because it gives better messages. If that fails try the union of all the plain alts. */ if (predDepth == 1) { MR_set_reuse(&predSet); predSet=MR_compute_pred_set(predList[i]); /* ignores k>1 predicates */ for (j=0; j < nAlts; j++) { if (jList[j] == NULL) continue; if (j == i) continue; MR_set_reuse(&setDif); setDif=set_dif(predSet,plainContext[j]); if (set_nil(setDif)) { matchList[i] |= 1; MR_reportSetSuppression(predDepth,predSet,plainContext[j],jList[i],jList[j],predList[i]); predicate_free(predList[i]); predList[i]=PRED_SUPPRESS; goto next_i; }; }; /* end loop on j */ changed=0; /* predicate_dup is only to give good error messages */ /* remember to do a predicate_free() */ origPred=predicate_dup(predList[i]); MR_apply_restriction1(predList[i],&union_plainSet,&changed); if (changed) { /* don't use Pass3 by itself unless you know that inverted is not important */ newPred=MR_removeRedundantPredPass3(predList[i]); newPred=MR_predSimplifyALL(newPred); if (newPred == NULL) { matchList[i] |= 1; MR_reportSetSuppression(predDepth,predSet,union_plainSet,jList[i], NULL,origPred); predList[i]=PRED_SUPPRESS; } else { MR_reportSetRestriction(predDepth,predSet,union_plainSet,jList[i], NULL,origPred,newPred); predList[i]=newPred; }; }; predicate_free(origPred); origPred=NULL; }; /* If the predicate depth is > 1 then it can't be suppressed completely because the code doesn't support inspection of such things. They're much messier than k=1 sets. */ if (predDepth > 1 ) { changed=0; /* predicate_dup is only to give good error messages */ /* remember to do a predicate_free() */ origPred=predicate_dup(predList[i]); MR_apply_restriction1(predList[i],&union_plainSet,&changed); if (changed) { newPred=MR_removeRedundantPredPass3(predList[i]); newPred=MR_predSimplifyALL(newPred); if (newPred == NULL) { matchList[i] |= 1; MR_reportSetSuppression(predDepth,predSet,union_plainSet,jList[i], NULL,origPred); predList[i]=PRED_SUPPRESS; } else { MR_reportSetRestriction(predDepth,predSet,union_plainSet,jList[i], NULL,origPred,newPred); predList[i]=newPred; }; }; predicate_free(origPred); origPred=NULL; }; next_i: continue; }; EXIT_SIMPLE: root = new_pred(); root->expr=PRED_OR_LIST; tail = &(root->down); for (i=0 ; i< nAlts ; i++) { if (jList[i] == NULL) continue; if (predList[i] == NULL) { continue; } else if ( (matchList[i] & 1) != 0) { if (predList[i] != PRED_SUPPRESS) { predicate_free(predList[i]); }; continue; }; /* make an OR list of predicates */ *tail=predList[i]; tail=&(predList[i]->right); }; /* if just one pred, remove OR root */ if (root->down == NULL) { predicate_free(root); root=NULL; } else if (root->down->right == NULL) { Predicate *p=root->down; root->down=NULL; predicate_free(root); root=p; } root=MR_predSimplifyALL(root); MR_orin_plainSet(root,union_plainSet); set_free(predSet); set_free(union_plainSet); set_free(incomplete); set_free(setChange); set_free(setDif); for (m=0; m < nAlts; m++) set_free(plainContext[m]); free ( (char *) jList); free ( (char *) predList); free ( (char *) matchList); free ( (char *) plainContext); return root; } #ifdef __USE_PROTOS void MR_predContextPresent(Predicate *p,int *allHaveContext,int *noneHaveContext) #else void MR_predContextPresent(p,allHaveContext,noneHaveContext) Predicate *p; int *allHaveContext; int *noneHaveContext; #endif { if (p == NULL) return; MR_predContextPresent(p->right,allHaveContext,noneHaveContext); if (p->expr != PRED_AND_LIST && p->expr != PRED_OR_LIST) { if (set_nil(p->scontext[1]) == 0 || (p->tcontext != NULL)) { *noneHaveContext=0; } else { *allHaveContext=0; }; }; MR_predContextPresent(p->down,allHaveContext,noneHaveContext); } #ifdef __USE_PROTOS int MR_pointerStackPush(PointerStack *ps,void *dataPointer) #else int MR_pointerStackPush(ps,dataPointer) PointerStack *ps; void *dataPointer; #endif { void **newStack; int newSize; int i; if (ps->count == ps->size) { newSize=20+ps->size*2; newStack=(void **)calloc(newSize,sizeof(void *)); require (newStack != NULL,"cannot allocate PointerStack"); for (i=0; i < ps->size; i++) { newStack[i]=ps->data[i]; }; if (ps->data != NULL) free( (char *) ps->data); ps->data=newStack; ps->size=newSize; }; ps->data[ps->count]=dataPointer; ps->count++; return ps->count-1; } #ifdef __USE_PROTOS void * MR_pointerStackPop(PointerStack *ps) #else void * MR_pointerStackPop(ps) PointerStack *ps; #endif { void *dataPointer; require(ps->count > 0,"MR_pointerStackPop underflow"); dataPointer=ps->data[ps->count-1]; ps->data[ps->count-1]=NULL; (ps->count)--; return dataPointer; } #ifdef __USE_PROTOS void * MR_pointerStackTop(PointerStack *ps) #else void * MR_pointerStackTop(ps) PointerStack *ps; #endif { require(ps->count > 0,"MR_pointerStackTop underflow"); return ps->data[ps->count-1]; } #ifdef __USE_PROTOS void MR_pointerStackReset(PointerStack *ps) #else void MR_pointerStackReset(ps) PointerStack *ps; #endif { int i; if (ps->data != NULL) { for (i=0; i < ps->count ; i++) { ps->data[i]=NULL; }; }; ps->count=0; } #ifdef __USE_PROTOS Junction *MR_nameToRuleBlk(char *name) #else Junction *MR_nameToRuleBlk(name) char *name; #endif { RuleEntry *q; require (RulePtr != NULL,"MR_nameToRule: RulePtr not initialized"); if (name == NULL) return NULL; q = (RuleEntry *) hash_get(Rname,name); if ( q == NULL ) { return NULL; } else { return RulePtr[q->rulenum]; }; } #ifdef __USE_PROTOS Junction * MR_ruleReferenced(RuleRefNode *rrn) #else Junction * MR_ruleReferenced(rrn) RuleRefNode *rrn; #endif { return MR_nameToRuleBlk(rrn->text); } #ifdef __USE_PROTOS void MR_comparePredLeaves(Predicate *me,Predicate *myParent,Predicate *him,Predicate *hisParent) #else void MR_comparePredLeaves(me,myParent,him,hisParent) Predicate *me; Predicate *myParent; Predicate *him; Predicate *hisParent; #endif { if (me == NULL) return; if (me == him) { MR_comparePredLeaves(me->right,myParent,him,hisParent); return; } else if (me->expr == PRED_AND_LIST || me->expr == PRED_OR_LIST) { MR_comparePredLeaves(me->down,me,him,hisParent); MR_comparePredLeaves(me->right,myParent,him,hisParent); return; } else { if (me->source != NULL) { /* predicate->invert can be set only in the predEntry predicates */ /* thus they are only visible after the predEntry predicates have been "unfolded" */ int sameSource=(me->source == him->source); int sameInvert=1 & (1 + me->inverted + him->inverted + me->source->inverted + him->source->inverted); int samePredEntry=(me->source->predEntry != NULL && him->source->predEntry != NULL && me->source->predEntry == him->source->predEntry); if (sameInvert && (sameSource || samePredEntry)) { if (MR_identicalContext(me,him)) { /* identical predicates */ if (hisParent->expr == PRED_OR_LIST && myParent->expr == PRED_OR_LIST) { me->redundant=1; } else if (hisParent->expr == PRED_AND_LIST && myParent->expr == PRED_AND_LIST) { me->redundant=1; } else if ( (hisParent->expr == PRED_OR_LIST && myParent->expr == PRED_AND_LIST) || (hisParent->expr == PRED_AND_LIST && myParent->expr == PRED_OR_LIST) ) { myParent->redundant=1; } else { require (0,"MR_comparePredLeaves: not both PRED_LIST"); }; }; }; /* end same source or same predEntrr with same invert sense */ /* same predEntry but opposite invert sense */ if (!sameInvert && (sameSource || samePredEntry)) { if (MR_identicalContext(me,him)) { if (hisParent->expr == PRED_OR_LIST && myParent->expr == PRED_OR_LIST) { myParent->isConst=1; myParent->constValue=1; } else if (hisParent->expr == PRED_AND_LIST && myParent->expr == PRED_AND_LIST) { myParent->isConst=1; myParent->constValue=0; } else if ( (hisParent->expr == PRED_OR_LIST && myParent->expr == PRED_AND_LIST) || (hisParent->expr == PRED_AND_LIST && myParent->expr == PRED_OR_LIST) ) { me->redundant=1; } else { require (0,"MR_comparePredLeaves: not both PRED_LIST"); }; }; }; /* end same predEntry with opposite invert sense */ }; MR_comparePredLeaves(me->right,myParent,him,hisParent); return; }; } #ifdef __USE_PROTOS void MR_removeRedundantPredPass1(Predicate *me,Predicate *myParent) #else void MR_removeRedundantPredPass1(me,myParent) Predicate *me; Predicate *myParent; #endif { if (me == NULL) return; if (me->redundant) { MR_removeRedundantPredPass1(me->right,myParent); return; }; if (me->expr == PRED_AND_LIST || me->expr == PRED_OR_LIST) { MR_removeRedundantPredPass1(me->down,me); MR_removeRedundantPredPass1(me->right,myParent); } else { require (me->source != NULL,"me->source == NULL"); if (myParent != NULL) { MR_comparePredLeaves(myParent->down,myParent,me,myParent); }; MR_removeRedundantPredPass1(me->right,myParent); }; } /* pretty much ignores things with the inverted bit set */ #ifdef __USE_PROTOS Predicate *MR_predFlatten(Predicate *p) #else Predicate *MR_predFlatten(p) Predicate *p; #endif { if (p == NULL) return NULL; if (p->expr == PRED_OR_LIST || p->expr == PRED_AND_LIST) { Predicate *child; Predicate *gchild; Predicate **tail; Predicate *next; char *PRED_XXX_LIST=p->expr; require (p->down != NULL,"MR_predFlatten AND/OR no child"); p->down=MR_predFlatten(p->down); p->right=MR_predFlatten(p->right); child=p->down; if (child->right == NULL) { child->right=p->right; p->right=NULL; p->down=NULL; if (p->inverted) child->inverted=!child->inverted; predicate_free(p); return child; }; /* make a single list of all children and grandchildren */ tail=&(p->down); for (child=p->down; child != NULL; child=next) { if (child->expr != PRED_XXX_LIST || child->inverted || child->predEntry != NULL) { *tail=child; tail=&(child->right); next=child->right; } else { for (gchild=child->down; gchild != NULL; gchild=gchild->right) { *tail=gchild; tail=&(gchild->right); }; next=child->right; child->right=NULL; child->down=NULL; predicate_free(child); }; }; *tail=NULL; return p; } else { p->right=MR_predFlatten(p->right); return p; }; } static char *alwaysFalseWarning=NULL; #ifdef __USE_PROTOS Predicate *checkPredicateConflict(Predicate *p) #else Predicate *checkPredicateConflict(p) Predicate *p; #endif { if (p->isConst) { if (p->constValue == 1) { predicate_free(p); return NULL; } else { if (InfoP && !p->conflictReported) { p->conflictReported=1; fprintf(output,"\n#if 0\n\n"); fprintf(output,"The following predicate expression will always be false:\n\n"); MR_dumpPred1(1,p,1); fprintf(output,"\n#endif\n"); }; if (alwaysFalseWarning != CurRule) { alwaysFalseWarning=CurRule; if (InfoP) { warnNoFL(eMsg1("one (or more) predicate expression hoisted into rule \"%s\" are always false \ - see output file for more information",CurRule)); } else { warnNoFL(eMsg1("one (or more) predicate expressions hoisted into rule \"%s\" are always false \ - use \"-info p\" for more information",CurRule)); }; }; }; }; return p; } #ifdef __USE_PROTOS int MR_countPredNodes(Predicate *p) #else int MR_countPredNodes(p) Predicate *p; #endif { if (p == NULL) return 0; return 1 + MR_countPredNodes(p->down) + MR_countPredNodes(p->right); } #ifdef __USE_PROTOS Predicate *MR_predSimplifyALLX(Predicate *p,int skipPass3) #else Predicate *MR_predSimplifyALLX(p,skipPass3) Predicate *p; int skipPass3; #endif { int countBefore; int countAfter; countAfter=MR_countPredNodes(p); do { if (p == NULL) return NULL; if (p->right == NULL && p->down == NULL) return p; countBefore=countAfter; MR_simplifyInverted(p,0); p=MR_predFlatten(p); MR_removeRedundantPredPass1(p,NULL); MR_removeRedundantPredPass2(p); if (! skipPass3) { p=checkPredicateConflict(p); p=MR_removeRedundantPredPass3(p); }; countAfter=MR_countPredNodes(p); } while (countBefore != countAfter); return p; } #ifdef __USE_PROTOS Predicate *MR_predSimplifyALL(Predicate *p) #else Predicate *MR_predSimplifyALL(p) Predicate *p; #endif { return MR_predSimplifyALLX(p,0); } #ifdef __USE_PROTOS void MR_releaseResourcesUsedInRule(Node *n) #else void MR_releaseResourcesUsedInRule(n) Node *n; #endif { Node *next; Junction *j; int i; if (n == NULL) return; if (n->ntype == nJunction) { j=(Junction *) n; if (j->predicate != NULL) { predicate_free(j->predicate); j->predicate=NULL; }; for (i=0; i< CLL_k; i++) { set_free(j->fset[i]); j->fset[i]=empty; }; if (j->ftree != NULL) { Tfree(j->ftree); j->ftree=NULL; }; if (j->jtype == EndRule) return; if (j->jtype != RuleBlk && j->jtype != EndBlk) { if (j->p2 != NULL && !j->ignore) { /* MR11 */ MR_releaseResourcesUsedInRule(j->p2); }; }; }; next=MR_advance(n); MR_releaseResourcesUsedInRule(next); } #ifdef __USE_PROTOS int MR_allPredLeaves(Predicate *p) #else int MR_allPredLeaves(p) Predicate *p; #endif { Predicate *q; if (p == NULL) return 1; for (q=p; q != NULL; q=q->right) { if (q->down != NULL) return 0; }; return 1; } /* make sure it works for the last rule in a file */ #ifdef __USE_PROTOS int MR_offsetFromRule(Node *n) #else int MR_offsetFromRule(n) Node *n; #endif { Junction *j; int offset=(-1); for (j=SynDiag; j != NULL; j=(Junction *)j->p2) { require (j->ntype == nJunction && j->jtype == RuleBlk,"Not a rule block"); if (n->file < j->file) { return offset; }; if (n->file == j->file) { if (n->line < j->line) { return (offset < 0) ? 0 : offset; } else { offset=n->line - j->line; if (offset == 0) return 0; }; }; }; return offset; } #define ruleNameMax 50 static char ruleNameStatic1[ruleNameMax]; static char ruleNameStatic2[ruleNameMax+10]; #ifdef __USE_PROTOS char * MR_ruleNamePlusOffset(Node *n) #else char * MR_ruleNamePlusOffset(n) Node *n; #endif { int offset=MR_offsetFromRule(n); strncpy(ruleNameStatic1,n->rname,ruleNameMax); if (offset < 0) { sprintf(ruleNameStatic2,"%s/?",ruleNameStatic1); } else { sprintf(ruleNameStatic2,"%s/%d",ruleNameStatic1,offset+1); }; return ruleNameStatic2; } #ifdef __USE_PROTOS int MR_max_height_of_tree(Tree *t) #else int MR_max_height_of_tree(t) Tree *t; #endif { int h; int height=0; Tree *u; if (t == NULL) return 0; require (t->token != ALT && t->token != EpToken,"MR_max_height_of_tree ALT or EpToken"); for (u=t; u != NULL; u=u->right) { h=MR_max_height_of_tree(u->down)+1; if (h > height) height=h; }; return height; } #ifdef __USE_PROTOS int MR_all_leaves_same_height(Tree *t,int depth) #else int MR_all_leaves_same_height(t,depth) Tree *t; int depth; #endif { if (t == NULL) { return (depth==0); }; require (t->token != ALT && t->token != EpToken,"MR_all_leaves_same_height ALT or EpToken"); if (depth == 0) { return 0; } else { if ( ! MR_all_leaves_same_height(t->down,depth-1)) { return 0; }; if (t->right == NULL) { return 1; } else { return MR_all_leaves_same_height(t->right,depth); }; }; } #ifdef __USE_PROTOS void MR_projectTreeOntoSet(Tree *tree,int ck,set *ckset) #else void MR_projectTreeOntoSet(tree,ck,ckset) Tree *tree; int ck; set *ckset; #endif { if (tree == NULL) return; require(tree->token != EpToken,"MR_projectTreeOntoSet: EpToken unexpected\n"); MR_projectTreeOntoSet(tree->right,ck,ckset); if (tree->token == ALT) { MR_projectTreeOntoSet(tree->down,ck,ckset); } else { if (ck > 1) { MR_projectTreeOntoSet(tree->down,ck-1,ckset); } else { set_orel(tree->token,ckset); }; }; } #ifdef __USE_PROTOS int MR_comparePredicates(Predicate *a,Predicate *b) #else int MR_comparePredicates(a,b) Predicate *a; Predicate *b; #endif { Predicate *p; Predicate *q; if (a == b) return 1; if (a == NULL || b == NULL ) return 0; if (a->down == NULL && b->down == NULL) { /* predicate->invert can be set only in the predEntry predicates */ /* thus they are only visible after the predEntry predicates have been "unfolded" */ int sameSource=(a->source == b->source); int sameInvert= 1 & (1 +a->inverted + b->inverted + a->source->inverted + b->source->inverted); int samePredEntry=(a->source->predEntry != NULL && b->source->predEntry != NULL && a->source->predEntry == b->source->predEntry); if (sameInvert && (sameSource || samePredEntry)) { if (MR_identicalContext(a,b)) { return 1; }; }; return 0; }; if (a->down == NULL || b->down == NULL) return 0; if (a->expr != b->expr) return 0; for (p=a->down; p != NULL; p=p->right) { for (q=b->down; q != NULL; q=q->right) { if (MR_comparePredicates(p,q)) goto NEXT_P; }; return 0; NEXT_P: continue; }; return 1; } /* * action->inverted can be set only when a predicate symbol appears in * a rule: "rule : <>? X". It cannot be set under any * other circumstances. In particular it cannot be set by * "#pred NotA !A" or by "#pred Nota <>?". The first case * creates a predEntry and the predicate expression of that predEntry * has inverted set. In the second case, the code for handling "!" * is only present in buildAction, which is not called by the #pred * semantic routines, only when a <<...>>? is recognized as part of * a rule definition. * * predicate->inverted can only be set by a predicate created by a #pred * expression, such as "#pred NotA !A" or "#pred NotXY ! (X && Y) or * "#pred XbarY !(X && Y)". In particular, it cannot be set by any * predicate expression occurring under any other circumstances. * The #pred predicate expresssions are stored with in predEntry->pred * and do not normally appear anywhere else until the predicates are * "unfolded" in order to recognize redundancies, conflicts, and * tautologies. * * The unfold routine expands all references to #pred expressions. * * The simplifyInvert goes through and propagates the invert bit so that * all OR and AND nodes are un-inverted. * * Note that !(A and B) => (!A or !B) * !(A or B) => (!A and !B) * * MR_unfold() is called to expand predicate symbols by replacing predicates * that reference predicate entries with the copies of the predicate entries. * Each reference receives a duplicate of the original. This is necessary * because the next phase involves simplification and removal of redundant * predicate nodes. Anyway, the point I'm making is that predicate->invert * should not be set in any predicate until it has been expanded. * * This is a recursive structure, but there is no need for "recursive expansion" * by which I mean a predicate symbol refers to other predicate symbols which * must also be expanded. * * Recursive expansion is *not* performed by this routine because it is not * necessary. Expansion of references is performed by predPrimary when * a new predicate symbol is created by referring to others in the pred expr. */ #ifdef __USE_PROTOS Predicate *MR_unfold(Predicate *pred) #else Predicate *MR_unfold(pred) Predicate *pred; #endif { Predicate *result; if (pred == NULL) return NULL; pred->right=MR_unfold(pred->right); if (pred->down == NULL) { if (pred->source->predEntry != NULL) { if (pred->source->predEntry->pred == NULL) { ; /* do nothing */ /* a reference to a literal #pred (perhaps with "!" */ } else { result=predicate_dup_without_context(pred->source->predEntry->pred); if (pred->inverted) { result->inverted=!result->inverted; }; if (pred->source->inverted) { result->inverted=!result->inverted; }; result->right=pred->right; pred->right=NULL; predicate_free(pred); /*** result=MR_unfold(result); *** not necessary */ /* recursive expansion */ return result; }; } else { ; /* do nothing */ /* an inline literal predicate */ }; } else { pred->down=MR_unfold(pred->down); }; return pred; } /* this should be called immediately after MR_unfold() and at no other times */ #ifdef __USE_PROTOS void MR_simplifyInverted(Predicate *pred,int inverted) #else void MR_simplifyInverted(pred,inverted) Predicate *pred; int inverted; #endif { int newInverted; if (pred == NULL) return; MR_simplifyInverted(pred->right,inverted); newInverted= 1 & (inverted + pred->inverted); if (pred->down == NULL) { pred->inverted=newInverted; } else { if (newInverted != 0) { if (pred->expr == PRED_AND_LIST) { pred->expr=PRED_OR_LIST; } else { pred->expr=PRED_AND_LIST; }; }; pred->inverted=0; MR_simplifyInverted(pred->down,newInverted); }; } /* only remove it from AND and OR nodes, not leaves */ #ifdef __USE_PROTOS void MR_clearPredEntry(Predicate *p) #else void MR_clearPredEntry(p) Predicate *p; #endif { if (p == NULL) return; MR_clearPredEntry(p->down); MR_clearPredEntry(p->right); if (p->down != NULL) p->predEntry=NULL; } #ifdef __USE_PROTOS void MR_orphanRules(FILE *f) #else void MR_orphanRules(f) FILE *f; #endif { set a; Junction *p; unsigned e; RuleEntry *re; a=empty; if (! InfoO) return; for (p=SynDiag; p!=NULL; p = (Junction *)p->p2) { if ( (Junction *) (p->end)->p1 == NULL) { re=(RuleEntry *) hash_get(Rname,p->rname); require (re != NULL,"RuleEntry == NULL"); set_orel(re->rulenum, &a); } } if (set_deg(a) > 1) { fprintf(f,"note: Start rules: {"); for (; !set_nil(a); set_rm(e,a)) { e=set_int(a); fprintf(f," %s",RulePtr[e]->rname); }; fprintf(f," }\n"); }; set_free( a ); } /* merge (X Y) and (X) to create (X) */ static int *mergeChain; static Tree *mergeTree; #ifdef __USE_PROTOS Tree *MR_merge_tree_contexts_client(Tree *t,int chain[]) #else Tree *MR_merge_tree_contexts_client(t,chain) Tree *t; int chain[]; #endif { if (t == NULL) return NULL; if (chain[0] == 0) { Tree *u=t->right; t->right=NULL; Tfree(t); return MR_merge_tree_contexts_client(u,&chain[0]); } if (chain[0] == t->token) { t->down=MR_merge_tree_contexts_client(t->down,&chain[1]); }; t->right=MR_merge_tree_contexts_client(t->right,&chain[0]); return t; } #ifdef __USE_PROTOS void MR_iterateOverTreeContexts(Tree *t,int chain[]) #else void MR_iterateOverTreeContexts(t,chain) Tree *t; int chain[]; #endif { if (t == NULL) return; chain[0]=t->token; if (t->down != NULL) { MR_iterateOverTreeContexts(t->down,&chain[1]); } else { MR_merge_tree_contexts_client(mergeTree,mergeChain); }; MR_iterateOverTreeContexts(t->right,&chain[0]); chain[0]=0; } #ifdef __USE_PROTOS Tree *MR_merge_tree_contexts(Tree *t) #else Tree *MR_merge_tree_contexts(t) Tree *t; #endif { int h=MR_max_height_of_tree(t); mergeTree=t; mergeChain=(int *) calloc(h+1,sizeof(int)); require (mergeChain != NULL,"MR_merge_tree_contexts: can't alloc chain"); MR_iterateOverTreeContexts(t,mergeChain); t=tshrink(t); t=tflatten(t); t=tleft_factor(t); free ( (char *) mergeChain); mergeChain=NULL; return t; } #ifdef __USE_PROTOS Tree *MR_compute_pred_tree_context(Predicate *p) #else Tree *MR_compute_pred_tree_context(p) Predicate *p; #endif { Tree *t; t=MR_compute_pred_tree_ctxXX(p); MR_merge_tree_contexts(t); return t; } #ifdef __USE_PROTOS void MR_guardPred_plainSet(ActionNode *anode,Predicate *pred) #else void MR_guardPred_plainSet(anode,pred) ActionNode *anode; Predicate *pred; #endif { Junction *j; Predicate *workPred; set maskSet; maskSet=empty; if (!MRhoisting) return; /* it doesn't really matter whether the predicate has depth k=1 or k>1 because we're not really looking at the predicate itself, just the stuff "behind" the predicate. */ /* shouldn't have to worry about REACHing off the end of the rule containing the predicate because the Rule->end->halt should have been set already by the the code which handles RuleRef nodes. We don't want to REACH off the end of the rule because this would give the "global" follow context rather than the "local" context. r1a : (A)? => <

>? r2 (A|B) r1b : (A)? => <

>? r2 (A|C) r2 : (); For r1a we want follow of predicate = {A B} we want plainSet = {B} For r1b we want follow of predicate = {A C} we want plainSet = {C} */ require (anode->next->ntype == nJunction,"MR_guardpred_plainSet not Junction"); j=(Junction *)(anode->next); workPred=predicate_dup_without_context(pred); workPred->k=1; workPred->scontext[1]=MR_First(1,j, &(workPred->completionSet) ); MR_complete_predicates(1,workPred); if (pred->k == 1) { maskSet=pred->scontext[1]; } else { MR_projectTreeOntoSet(pred->tcontext,1,&maskSet); } pred->plainSet=set_dif(workPred->scontext[1],maskSet); predicate_free(workPred); } /*******************************************************************************/ static Tree * suppressTree; static int * suppressChain; /* element 0 not used */ static set * suppressSets; static Node * suppressNode; static int suppressChainLength; int MR_SuppressSearch=0; static int suppressSucceeded; static Predicate * suppressPredicate; #ifdef __USE_PROTOS int MR_isChain(Tree *t) #else int MR_isChain(t) Tree *t; #endif { Tree *u; for (u=t; u != NULL; u=u->down) { if (u->right != NULL) return 0; } return 1; } #ifdef __USE_PROTOS int MR_suppressK_client(Tree *tree,int tokensInChain[]) #else int MR_suppressK_client(tree,tokensInChain) Tree *tree; int tokensInChain[]; #endif { int i; set *save_fset; int save_ConstrainSearch; set incomplete; Tree *t; suppressSucceeded=0; /* volatile */ if (suppressSets == NULL) { suppressSets=(set *) calloc (CLL_k+1,sizeof(set)); require (suppressSets != NULL,"MR_suppressK_client: suppressSets alloc"); }; for (suppressChainLength=1; tokensInChain[suppressChainLength+1] != 0; suppressChainLength++) {}; require (suppressChainLength != 0,"MR_suppressK_client: chain empty"); for (i=1 ; i <= suppressChainLength ; i++) { set_clr(suppressSets[i]); set_orel( (unsigned) tokensInChain[i], &suppressSets[i]); }; save_fset=fset; save_ConstrainSearch=ConstrainSearch; fset=suppressSets; MR_SuppressSearch=1; MR_AmbSourceSearch=1; MR_MaintainBackTrace=1; ConstrainSearch=1; maxk = suppressChainLength; incomplete=empty; t=NULL; /*** constrain = &(fset[1]); ***/ MR_setConstrainPointer(&(fset[1])); /* MR18 */ MR_pointerStackReset(&MR_BackTraceStack); TRAV(suppressNode,maxk,&incomplete,t); Tfree(t); require (set_nil(incomplete),"MR_suppressK_client TRAV incomplete"); require (MR_BackTraceStack.count == 0, "MR_suppressK_client: MR_BackTraceStack.count != 0"); set_free(incomplete); ConstrainSearch=save_ConstrainSearch; fset=save_fset; MR_AmbSourceSearch=0; MR_MaintainBackTrace=0; MR_SuppressSearch=0; return suppressSucceeded; } #ifdef __USE_PROTOS Tree * MR_iterateOverTreeSuppressK(Tree *t,int chain[]) #else Tree * MR_iterateOverTreeSuppressK(t,chain) Tree *t; int chain[]; #endif { if (t == NULL) return NULL; t->right=MR_iterateOverTreeSuppressK(t->right,&chain[0]); chain[0]=t->token; if (t->down != NULL) { t->down=MR_iterateOverTreeSuppressK(t->down,&chain[1]); if (t->down == NULL) { Tree *u=t->right; t->right=NULL; Tfree(t); chain[0]=0; return u; }; } else { MR_suppressK_client(suppressTree,suppressChain); if (suppressSucceeded) { Tree *u=t->right; t->right=NULL; Tfree(t); chain[0]=0; return u; }; }; chain[0]=0; return t; } /* @@@ */ #ifdef __USE_PROTOS Predicate * MR_suppressK(Node *j,Predicate *p) #else Predicate * MR_suppressK(j,p) Node *j; Predicate *p; #endif { Predicate *result; int guardPred=0; int ampersandPred=0; Node *nodePrime; if (! MRhoistingk) { return p; } if (! MRhoisting) return p; if (CLL_k == 1) return p; if (suppressChain == NULL) { suppressChain=(int *) calloc(CLL_k+2,sizeof(int)); require (suppressChain != NULL,"MR_suppressK: can't allocate chain"); } if (p == NULL) return NULL; if (j->ntype == nJunction) { nodePrime=(Node *) MR_junctionWithoutP2( (Junction *) j); } else { nodePrime=j; }; p->down=MR_suppressK(j,p->down); p->right=MR_suppressK(j,p->right); if (p->down != NULL) { result=p; goto EXIT; }; if (p->k == 1) { result=p; goto EXIT; }; if (p->source != NULL) { if (p->source->guardpred != NULL) guardPred=1; if (p->source->ampersandPred != NULL) ampersandPred=1; } suppressPredicate=p; suppressNode=nodePrime; /* was j*/ suppressTree=p->tcontext; if (guardPred || ampersandPred) { p->tcontext=MR_iterateOverTreeSuppressK(suppressTree,&suppressChain[1]); if (p->tcontext == NULL) { predicate_free(p); result=NULL; goto EXIT; }; } else { if (MR_isChain(p->tcontext)) { p->tcontext=MR_iterateOverTreeSuppressK(suppressTree,&suppressChain[1]); if (p->tcontext == NULL) { predicate_free(p); result=NULL; goto EXIT; }; } } result=p; EXIT: return result; } #ifdef __USE_PROTOS void MR_suppressSearchReport(void) #else void MR_suppressSearchReport() #endif { int i; Node *p; TokNode *tn; int depth; set setAnd; /* number of tokens in back trace stack matches length of chain */ depth=0; for (i=0; i < MR_BackTraceStack.count ; i++) { p=(Node *) MR_BackTraceStack.data[i]; if (p->ntype == nToken) depth++; }; require (depth == suppressChainLength,"depth > suppressChainLength"); /* token codes match chain */ depth=0; for (i=0; i < MR_BackTraceStack.count ; i++) { p=(Node *) MR_BackTraceStack.data[i]; if (p->ntype != nToken) continue; tn=(TokNode *) p; depth++; if (set_nil(tn->tset)) { require(set_el( (unsigned) tn->token,fset[depth]), "MR_suppressSearchReport: no match to #token in chain"); } else { setAnd=set_and(fset[depth],tn->tset); require(!set_nil(setAnd), "MR_suppressSearchReport: no match to #token set in chain"); set_free(setAnd); }; }; /* have a match - now remove it from the predicate */ suppressSucceeded=1; if (suppressSucceeded) { fprintf(output,"\n"); fprintf(output,"#if 0\n"); fprintf(output,"\n"); fprintf(output,"Part (or all) of predicate with depth > 1 suppressed by "); fprintf(output,"alternative without predicate\n\n"); MR_dumpPred(suppressPredicate,1); fprintf(output,"The token sequence which is suppressed:"); fprintf(output," ("); for (i=1; i <= suppressChainLength; i++) { fprintf(output," %s",TerminalString(suppressChain[i])); }; fprintf(output," )\n"); fprintf(output,"The sequence of references which generate that sequence of tokens:\n\n"); MR_backTraceDumpItemReset(); for (i=0; i < MR_BackTraceStack.count ; i++) { MR_backTraceDumpItem(output,0,(Node *) MR_BackTraceStack.data[i]); }; fprintf(output,"\n"); fprintf(output,"#endif\n"); } } #ifdef __USE_PROTOS void MR_markCompromisedRule(Node *n) #else void MR_markCompromisedRule(n) Node *n; #endif { RuleEntry *q; Node *mark=NULL; Junction *j; if (n->ntype == nRuleRef) { mark=(Node *) MR_ruleReferenced( (RuleRefNode *) n); } else if (n->ntype == nToken) { mark=n; } else if (n->ntype == nJunction) { j=(Junction *)n; switch (j->jtype) { case aOptBlk: case aLoopBlk: case RuleBlk: case EndRule: case aPlusBlk: case aLoopBegin: mark=n; break; default: break; }; } if (mark == NULL) return; require (RulePtr != NULL,"RulePtr not initialized"); q = (RuleEntry *) hash_get(Rname,mark->rname); require (q != NULL,"RuleEntry not found"); set_orel(q->rulenum,&MR_CompromisedRules); } #ifdef __USE_PROTOS void MR_alphaBetaTraceReport(void) #else void MR_alphaBetaTraceReport() #endif { int i; if (! AlphaBetaTrace) return; MR_AlphaBetaMessageCount++; fprintf(output,"\n"); fprintf(output,"#if 0\n"); fprintf(output,"\n"); fprintf(output,"Trace of references leading to attempt to compute the follow set of\n"); fprintf(output,"alpha in an \"(alpha)? beta\" block. It is not possible for antlr to\n"); fprintf(output,"compute this follow set because it is not known what part of beta has\n"); fprintf(output,"already been matched by alpha and what part remains to be matched.\n"); fprintf(output,"\n"); fprintf(output,"Rules which make use of the incorrect follow set will also be incorrect\n"); fprintf(output,"\n"); MR_backTraceDumpItemReset(); for (i=0; i < MR_BackTraceStack.count ; i++) { MR_backTraceDumpItem(output,0,(Node *) MR_BackTraceStack.data[i]); if (i < MR_BackTraceStack.count-1) { MR_markCompromisedRule( (Node *) MR_BackTraceStack.data[i]); }; }; fprintf(output,"\n"); fprintf(output,"#endif\n"); } #ifdef __USE_PROTOS void MR_dumpRuleSet(set s) #else void MR_dumpRuleSet(s) set s; #endif { unsigned *cursor; unsigned *origin=set_pdq(s); require(origin != NULL,"set_pdq failed"); if (RulePtr == NULL) { fprintf(stderr,"RulePtr[] not yet initialized"); } else { for (cursor=origin; *cursor != nil ; cursor++) { /**** if (cursor != origin) fprintf(stderr,","); ****/ fprintf(stderr," %s",RulePtr[*cursor]->rname); fprintf(stderr,"\n"); }; free( (char *) origin); }; } cdrdao-cdrdao-f00afb2/pccts/antlr/pred.c000066400000000000000000000465321511453746600202420ustar00rootroot00000000000000/* * pred.c -- source for predicate detection, manipulation * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2001 */ #include #include "pcctscfg.h" #include "set.h" #include "syn.h" #include "hash.h" #include "generic.h" #include "dlgdef.h" #include #ifdef __USE_PROTOS static void complete_context_sets(RuleRefNode *, Predicate *); static void complete_context_trees(RuleRefNode *, Predicate *); #else static void complete_context_sets(); static void complete_context_trees(); #endif char *PRED_AND_LIST = "AND"; char *PRED_OR_LIST = "OR"; /* * In C mode, return the largest constant integer found as the * sole argument to LATEXT(i). * * In C++ mode, return the largest constant integer found as the * sole argument to LT(i) given that the char before is nonalpha. */ int #ifdef __USE_PROTOS predicateLookaheadDepth(ActionNode *a) #else predicateLookaheadDepth(a) ActionNode *a; #endif { int max_k=0; if (a->predEntry != NULL) { MR_pred_depth(a->predEntry->pred,&max_k); goto PREDENTRY_EXIT; } if ( GenCC ) { /* scan for LT(i) */ int k = 0; char *p = a->action; while ( p!=NULL ) { p = strstr(p, "LT("); if ( p!=NULL ) { if ( p>=a->action && !isalpha(*(p-1)) ) { k = atoi(p+strlen("LT(")); if ( k>max_k ) max_k=k; } p += strlen("LT("); } } } else { /* scan for LATEXT(i) */ int k = 0; char *p = a->action; while ( p!=NULL ) { p = strstr(p, "LATEXT("); if ( p!=NULL ) { p += strlen("LATEXT("); k = atoi(p); if ( k>max_k ) max_k=k; } } } if ( max_k==0 && CLL_k > 1) /* MR27 Don't warn if max(k,ck) == 1 */ { if ( !a->frmwarned ) { a->frmwarned = 1; warnFL(eMsg1("predicate: %s missing, bad, or with i=0; assuming i=1", GenCC?"LT(i)":"LATEXT(i)"), FileStr[a->file], a->line); } max_k = 1; } /* MR10 */ if ( max_k > CLL_k) { /* MR10 */ if ( !a->frmwarned ) /* MR10 */ { /* MR10 */ a->frmwarned = 1; /* MR11 */ errFL(eMsgd2("predicate refers to lookahead token %d. Semantic lookahead is limited to max(k,ck)==%d", /* MR10 */ max_k,CLL_k), /* MR10 */ FileStr[a->file],a->line); /* MR10 */ if (max_k >= OutputLL_k) { /* MR10 */ if (!GenCC) { /* MR10 */ errFL(eMsgd(" the lookahead buffer size in C mode is %d token(s) (including the one just recognized)", /* MR10 */ OutputLL_k), /* MR10 */ FileStr[a->file],a->line); /* MR10 */ }; /* MR10 */ }; /* MR10 */ }; /* MR10 */ max_k= CLL_k; /* MR10 */ }; PREDENTRY_EXIT: return max_k; } /* Find all predicates in a block of alternatives. DO NOT find predicates * behind the block because that predicate could depend on things set in * one of the nonoptional blocks */ Predicate * #ifdef __USE_PROTOS find_in_aSubBlk( Junction *alt ) #else find_in_aSubBlk( alt ) Junction *alt; #endif { Predicate *a, *head=NULL, *tail=NULL, *root=NULL; Junction *p = alt; if (MRhoisting) { return MR_find_in_aSubBlk(alt); }; for (; p!=NULL; p=(Junction *)p->p2) { /* ignore empty alts */ if ( p->p1->ntype != nJunction || ((Junction *)p->p1)->jtype != EndBlk ) { a = find_predicates(p->p1); /* get preds for this alt */ if ( a==NULL ) continue; /* make an OR list of predicates */ if ( head==NULL ) { root = new_pred(); root->expr = PRED_OR_LIST; head = tail = a; root->down = head; } else { tail->right = a; a->left = tail; a->up = tail->up; tail = a; } } } /* if just one pred, remove OR root */ if ( root!=NULL && root->down->right == NULL ) { Predicate *d = root->down; free( (char *) root); return d; } return root; } Predicate * #ifdef __USE_PROTOS find_in_aOptBlk( Junction *alt ) #else find_in_aOptBlk( alt ) Junction *alt; #endif { return find_in_aSubBlk( alt ); } Predicate * #ifdef __USE_PROTOS find_in_aLoopBegin( Junction *alt ) #else find_in_aLoopBegin( alt ) Junction *alt; #endif { return find_in_aSubBlk( (Junction *) alt->p1 ); /* get preds in alts */ } Predicate * #ifdef __USE_PROTOS find_in_aPlusBlk( Junction *alt ) #else find_in_aPlusBlk( alt ) Junction *alt; #endif { require(alt!=NULL&&alt->p2!=NULL, "invalid aPlusBlk"); return find_in_aSubBlk( alt ); } /* Look for a predicate; * * Do not pass anything but Junction nodes; no Actions, Tokens, RuleRefs. * This means that a "hoisting distance" of zero is the only distance * allowable. Init actions are ignored. * * WARNING: * Assumes no (..)? block after predicate for the moment. * Does not check to see if pred is in production that can generate * a sequence contained in the set of ambiguous tuples. * * Return the predicate found if any. */ Predicate * #ifdef __USE_PROTOS find_predicates( Node *alt ) #else find_predicates( alt ) Node *alt; #endif { #ifdef DBG_PRED Junction *j; RuleRefNode *r; TokNode *t; #endif Predicate *pred; if ( alt==NULL ) return NULL; #ifdef DBG_PRED switch ( alt->ntype ) { case nJunction : j = (Junction *) alt; fprintf(stderr, "Junction(in %s)", j->rname); switch ( j->jtype ) { case aSubBlk : fprintf(stderr,"aSubBlk\n"); break; case aOptBlk : fprintf(stderr,"aOptBlk\n"); break; case aLoopBegin : fprintf(stderr,"aLoopBeginBlk\n"); break; case aLoopBlk : fprintf(stderr,"aLoopBlk\n"); break; case aPlusBlk : fprintf(stderr,"aPlusBlk\n"); break; case EndBlk : fprintf(stderr,"EndBlk\n"); break; case RuleBlk : fprintf(stderr,"RuleBlk\n"); break; case Generic : fprintf(stderr,"Generic\n"); break; case EndRule : fprintf(stderr,"EndRule\n"); break; } break; case nRuleRef : r = (RuleRefNode *) alt; fprintf(stderr, "RuleRef(in %s)\n", r->rname); break; case nToken : t = (TokNode *) alt; fprintf(stderr, "TokenNode(in %s)%s\n", t->rname, TokenString(t->token)); break; case nAction : fprintf(stderr, "Action\n"); break; } #endif switch ( alt->ntype ) { case nJunction : { Predicate *a, *b; Junction *p = (Junction *) alt; /* lock nodes */ if ( p->jtype==aLoopBlk || p->jtype==RuleBlk || p->jtype==aPlusBlk || p->jtype==EndRule ) { require(p->pred_lock!=NULL, "rJunc: lock array is NULL"); if ( p->pred_lock[1] ) { return NULL; } p->pred_lock[1] = TRUE; } switch ( p->jtype ) { case aSubBlk : a = find_in_aSubBlk(p); return a; /* nothing is visible past this guy */ case aOptBlk : a = find_in_aOptBlk(p); return a; case aLoopBegin : a = find_in_aLoopBegin(p); return a; case aLoopBlk : a = find_in_aSubBlk(p); p->pred_lock[1] = FALSE; return a; case aPlusBlk : a = find_in_aPlusBlk(p); p->pred_lock[1] = FALSE; return a; /* nothing is visible past this guy */ case RuleBlk : a = find_predicates(p->p1); p->pred_lock[1] = FALSE; return a; case Generic : a = find_predicates(p->p1); b = find_predicates(p->p2); if ( p->pred_lock!=NULL ) p->pred_lock[1] = FALSE; if ( a==NULL ) return b; if ( b==NULL ) return a; /* otherwise OR the two preds together */ { fatal_internal("hit unknown situation during predicate hoisting"); } case EndBlk : case EndRule : /* Find no predicates after a rule ref */ return NULL; default: fatal_internal("this cannot be printed\n"); break; } } case nAction : { ActionNode *p = (ActionNode *) alt; if ( p->noHoist) return NULL; /* MR12c */ if ( p->init_action ) return find_predicates(p->next); if ( p->is_predicate ) { Tree *t=NULL; #ifdef DBG_PRED fprintf(stderr, "predicate: <<%s>>?\n", p->action); #endif if ( p->guardpred!=NULL ) { pred = predicate_dup(p->guardpred); MR_guardPred_plainSet(p,pred); /* MR12c */ } else { pred = new_pred(); pred->k = predicateLookaheadDepth(p); pred->source = p; pred->expr = p->action; if ( HoistPredicateContext && pred->k > 1 ) { /* MR30 No need to use first_item_is_guess_block_extra since we know this is an action, not a (...)* or (...)+ block. */ if ( first_item_is_guess_block((Junction *)p->next) ) { warnFL("cannot compute context of predicate in front of (..)? block", FileStr[p->file], p->line); } else { ConstrainSearch = 0; /* MR11 */ if (p->ampersandPred != NULL) { /* MR11 */ TRAV(p, /* MR11 */ pred->k, /* MR11 */ &(pred->completionTree), t); /* MR11 */ } else { TRAV(p->next, pred->k, &(pred->completionTree), t); }; pred->tcontext = t; MR_check_pred_too_long(pred,pred->completionTree); #ifdef DBG_PRED fprintf(stderr, "LL(%d) context:", pred->k); preorder(t); fprintf(stderr, "\n"); #endif } } else if ( HoistPredicateContext && pred->k == 1 ) { pred->scontext[1] = empty; /* MR30 No need to use first_item_is_guess_block_extra since we know this is an action. */ if ( first_item_is_guess_block((Junction *)p->next) ) { warnFL("cannot compute context of predicate in front of (..)? block", FileStr[p->file], p->line); } else { REACH((Junction *)p->next, 1, &(pred->completionSet), pred->scontext[1]); MR_check_pred_too_long(pred,pred->completionSet); #ifdef DBG_PRED fprintf(stderr, "LL(1) context:"); s_fprT(stderr, pred->scontext[1]); fprintf(stderr, "\n"); #endif } } } { Predicate *d = find_predicates(p->next); Predicate *root; /* Warning: Doesn't seem like the up pointers will all be set correctly; * TJP: that's ok, we're not using them now. */ if ( d!=NULL ) { root = new_pred(); root->expr = PRED_AND_LIST; root->down = pred; pred->right = d; pred->up = root; d->left = pred; d->up = pred->up; return root; } } return pred; } return NULL; } case nRuleRef : { Predicate *a; RuleRefNode *p = (RuleRefNode *) alt; Junction *r; Junction *save_MR_RuleBlkWithHalt; RuleEntry *q = (RuleEntry *) hash_get(Rname, p->text); if ( q == NULL ) { warnFL( eMsg1("rule %s not defined",p->text), FileStr[p->file], p->line ); return NULL; } r = RulePtr[q->rulenum]; if ( r->pred_lock[1] ) { /* infinite left-recursion; ignore 'cause LL sup 1 (k) analysis * must have seen it earlier. */ return NULL; } /* MR10 There should only be one halt set at a time. */ /* MR10 Life would have been easier with a global variable */ /* MR10 (at least for this particular need) */ /* MR10 Unset the old one and set the new one, later undo. */ require(r->end->halt == FALSE,"should only have one halt at a time"); /* MR10 */ require(MR_RuleBlkWithHalt == NULL || /* MR10 */ (MR_RuleBlkWithHalt->jtype == RuleBlk && MR_RuleBlkWithHalt->end->halt == TRUE), /* MR10 */ "RuleBlkWithHalt->end not RuleBlk or does not have halt set"); /* MR10 */ if (MR_RuleBlkWithHalt != NULL) { /* MR10 */ MR_RuleBlkWithHalt->end->halt=FALSE; /* MR10 */ }; /*** fprintf(stderr,"\nSetting halt on junction #%d\n",r->end->seq); ***/ require(r->end->halt == FALSE,"rule->end->halt already set"); save_MR_RuleBlkWithHalt=MR_RuleBlkWithHalt; /* MR10 */ MR_pointerStackPush(&MR_RuleBlkWithHaltStack,MR_RuleBlkWithHalt); /* MR10 */ MR_pointerStackPush(&MR_PredRuleRefStack,p); r->end->halt = TRUE; /* MR10 */ MR_RuleBlkWithHalt=r; a = find_predicates((Node *)r); require(r->end->halt == TRUE,"rule->end->halt not set"); r->end->halt = FALSE; /* MR10 */ MR_pointerStackPop(&MR_PredRuleRefStack); /* MR10 */ MR_RuleBlkWithHalt=(Junction *) MR_pointerStackPop(&MR_RuleBlkWithHaltStack); require (MR_RuleBlkWithHalt==save_MR_RuleBlkWithHalt, "RuleBlkWithHaltStack not consistent"); /* MR10 */ require(MR_RuleBlkWithHalt == NULL || /* MR10 */ (MR_RuleBlkWithHalt->jtype == RuleBlk && MR_RuleBlkWithHalt->end->halt == FALSE), /* MR10 */ "RuleBlkWithHalt->end not RuleBlk or has no halt set"); /* MR10 */ if (MR_RuleBlkWithHalt != NULL) { /* MR10 */ MR_RuleBlkWithHalt->end->halt=TRUE; /* MR10 */ }; /*** fprintf(stderr,"\nRestoring halt on junction #%d\n",r->end->seq); ***/ if ( a==NULL ) return NULL; /* attempt to compute the "local" FOLLOW just like in normal lookahead * computation if needed */ complete_context_sets(p,a); complete_context_trees(p,a); /* MR10 */ MR_cleanup_pred_trees(a); return a; } case nToken : break; } return NULL; } #ifdef __USE_PROTOS Predicate *MR_find_predicates_and_supp(Node *alt) #else Predicate *MR_find_predicates_and_supp(alt) Node *alt; #endif { Predicate *p; p=find_predicates(alt); p=MR_suppressK(alt,p); return p; } Predicate * #ifdef __USE_PROTOS new_pred( void ) #else new_pred( ) #endif { Predicate *p = (Predicate *) calloc(1,sizeof(Predicate)); /* MR10 */ require(p!=NULL, "new_pred: cannot alloc predicate"); p->scontext[0]=empty; p->scontext[1]=empty; p->completionTree=empty; p->completionSet=empty; p->plainSet=empty; return p; } static void #ifdef __USE_PROTOS complete_context_sets( RuleRefNode *p, Predicate *a ) #else complete_context_sets( p, a ) RuleRefNode *p; Predicate *a; #endif { set rk2, b; int k2; #ifdef DBG_PRED fprintf(stderr, "enter complete_context_sets\n"); #endif for (; a!=NULL; a=a->right) { if ( a->expr == PRED_AND_LIST || a->expr == PRED_OR_LIST ) { complete_context_sets(p,a->down); continue; } rk2 = b = empty; while ( !set_nil(a->completionSet) ) { k2 = set_int(a->completionSet); set_rm(k2, a->completionSet); REACH(p->next, k2, &rk2, b); set_orin(&(a->scontext[1]), b); set_free(b); } set_orin(&(a->completionSet), rk2);/* remember what we couldn't do */ set_free(rk2); #ifdef DBG_PRED fprintf(stderr, "LL(1) context for %s(addr 0x%x) after ruleref:", a->expr, a); s_fprT(stderr, a->scontext[1]); fprintf(stderr, "\n"); #endif /* complete_context_sets(p, a->down);*/ } #ifdef DBG_PRED fprintf(stderr, "exit complete_context_sets\n"); #endif } static void #ifdef __USE_PROTOS complete_context_trees( RuleRefNode *p, Predicate *a ) #else complete_context_trees( p, a ) RuleRefNode *p; Predicate *a; #endif { set rk2; int k2; Tree *u; #ifdef DBG_PRED fprintf(stderr, "enter complete_context_trees\n"); #endif for (; a!=NULL; a=a->right) { if ( a->expr == PRED_AND_LIST || a->expr == PRED_OR_LIST ) { complete_context_trees(p, a->down); continue; } rk2 = empty; /* any k left to do? if so, link onto tree */ while ( !set_nil(a->completionTree) ) { k2 = set_int(a->completionTree); set_rm(k2, a->completionTree); u = NULL; TRAV(p->next, k2, &rk2, u); /* any subtrees missing k2 tokens, add u onto end */ a->tcontext = tlink(a->tcontext, u, k2); Tfree(u); /* MR10 */ } set_orin(&(a->completionTree), rk2);/* remember what we couldn't do */ set_free(rk2); #ifdef DBG_PRED fprintf(stderr, "LL(i<%d) context after ruleref:", LL_k); preorder(a->tcontext); fprintf(stderr, "\n"); #endif /* complete_context_trees(p, a->down);*/ } #ifdef DBG_PRED fprintf(stderr, "exit complete_context_trees\n"); #endif } /* Walk a list of predicates and return the set of all tokens in scontext[1]'s */ set #ifdef __USE_PROTOS covered_set( Predicate *p ) #else covered_set( p ) Predicate *p; #endif { set a; a = empty; for (; p!=NULL; p=p->right) { if ( p->expr == PRED_AND_LIST || p->expr == PRED_OR_LIST ) { set_orin(&a, covered_set(p->down)); continue; } set_orin(&a, p->scontext[1]); set_orin(&a, covered_set(p->down)); } return a; } /* MR10 predicate_free() MR10 Don't free the leaf nodes since they are part of the action node */ #ifdef __USE_PROTOS void predicate_free(Predicate *p) #else void predicate_free(p) Predicate *p; #endif { if (p == NULL) return; predicate_free(p->right); predicate_free(p->down); if (p->cloned || p->source == NULL || p->source->guardpred == NULL || p->expr == PRED_AND_LIST || p->expr == PRED_OR_LIST) { set_free(p->scontext[1]); set_free(p->completionSet); set_free(p->completionTree); set_free(p->plainSet); Tfree(p->tcontext); free( (char *) p); } else { p->right=NULL; p->down=NULL; /* MR13 *** debug */ }; } /* MR10 predicate_dup() */ #ifdef __USE_PROTOS Predicate * predicate_dup_xxx(Predicate *p,int contextToo) #else Predicate * predicate_dup_xxx(p,contextToo) Predicate *p; int contextToo; #endif { Predicate *q; if (p == NULL) return NULL; q=new_pred(); q->down=predicate_dup(p->down); q->right=predicate_dup(p->right); /* don't replicate expr - it is read-only and address comparison is used to look for identical predicates. */ q->expr=p->expr; q->k=p->k; q->source=p->source; q->cloned=1; q->ampersandStyle=p->ampersandStyle; q->inverted=p->inverted; q->predEntry=p->predEntry; q->plainSet=set_dup(p->plainSet); if (contextToo) { q->tcontext=tdup(p->tcontext); q->scontext[0]=set_dup(p->scontext[0]); q->scontext[1]=set_dup(p->scontext[1]); q->completionTree=set_dup(p->completionTree); q->completionSet=set_dup(p->completionSet); }; /* don't need to dup "redundant" */ return q; } #ifdef __USE_PROTOS Predicate * predicate_dup_without_context(Predicate *p) #else Predicate * predicate_dup_without_context(p) Predicate *p; #endif { return predicate_dup_xxx(p,0); } #ifdef __USE_PROTOS Predicate * predicate_dup(Predicate *p) #else Predicate * predicate_dup(p) Predicate *p; #endif { return predicate_dup_xxx(p,1); } cdrdao-cdrdao-f00afb2/pccts/antlr/proto.h000066400000000000000000001127641511453746600204610ustar00rootroot00000000000000/* * proto.h -- function prototypes * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2001 */ /* V a r i a b l e s */ extern int tp; extern Junction *SynDiag; extern char Version[]; extern char VersionDef[]; #ifdef __cplusplus extern void (*fpPrint[])(...); #else extern void (*fpPrint[])(); #endif #ifdef __cplusplus extern struct _set (*fpReach[])(...); #else extern struct _set (*fpReach[])(); #endif #ifdef __cplusplus extern struct _tree *(*fpTraverse[])(...); #else extern struct _tree *(*fpTraverse[])(); #endif #ifdef __cplusplus extern void (**fpTrans)(...); #else extern void (**fpTrans)(); #endif #ifdef __cplusplus extern void (**fpJTrans)(...); #else extern void (**fpJTrans)(); #endif #ifdef __cplusplus extern void (*C_Trans[NumNodeTypes+1])(...); #else extern void (*C_Trans[])(); #endif #ifdef __cplusplus extern void (*C_JTrans[NumJuncTypes+1])(...); #else extern void (*C_JTrans[])(); #endif extern int BlkLevel; extern int CurFile; extern char *CurPredName; extern char *CurRule; extern int CurRuleDebug; /* MR13 */ extern Junction *CurRuleBlk; extern RuleEntry *CurRuleNode; extern ListNode *CurElementLabels; extern ListNode *CurAstLabelsInActions; /* MR27 */ extern ListNode *ContextGuardPredicateList; /* MR13 */ extern ListNode *CurActionLabels; extern int numericActionLabel; /* MR10 << ... $1 ... >> or << ... $1 ... >>? */ extern ListNode *NumericPredLabels; /* MR10 << ... $1 ... >>? ONLY */ extern char *FileStr[]; extern int NumFiles; extern int EpToken; extern int WildCardToken; extern Entry **Tname, **Texpr, **Rname, **Fcache, **Tcache, **Elabel, **Sname, **Pname; /* MR11 */ extern ListNode *ExprOrder; extern ListNode **Cycles; extern int TokenNum; extern int LastTokenCounted; extern ListNode *BeforeActions, *AfterActions, *LexActions; /* MR1 */ /* MR1 11-Apr-97 Provide mechanism for inserting code into DLG class */ /* MR1 via #lexmember <<....>> & #lexprefix <<...>> */ /* MR1 */ extern ListNode *LexMemberActions; /* MR1 */ extern ListNode *LexPrefixActions; /* MR1 */ extern set *fset; /* for constrained search */ /* MR11 */ extern int maxk; /* for constrained search */ /* MR11 */ extern int Save_argc; /* MR10 */ extern char **Save_argv; /* MR10 */ extern ListNode *eclasses, *tclasses; extern char *HdrAction; extern char *FirstAction; /* MR11 */ extern FILE *ErrFile; extern char *RemapFileName; extern char *ErrFileName; extern char *DlgFileName; extern char *DefFileName; extern char *ModeFileName; extern char *StdMsgName; extern int NumRules; extern Junction **RulePtr; extern int LL_k; extern int CLL_k; extern char *decodeJType[]; extern int PrintOut; extern int PrintAnnotate; extern int CodeGen; extern int LexGen; extern int esetnum; extern int setnum; extern int wordnum; extern int GenAST; extern int GenANSI; extern int **FoStack; extern int **FoTOS; extern int GenExprSetsOpt; extern FILE *DefFile; extern int CannotContinue; extern int GenCR; extern int GenLineInfo; extern int GenLineInfoMS; extern int action_file, action_line; extern int TraceGen; extern int CurAmbigAlt1, CurAmbigAlt2, CurAmbigline, CurAmbigfile; extern char *CurAmbigbtype; extern int elevel; extern int GenEClasseForRules; extern FILE *input, *output; extern char **TokenStr, **ExprStr; extern int CurrentLexClass, NumLexClasses; extern LClass lclass[]; extern char LexStartSymbol[]; extern char *CurRetDef; extern char *CurParmDef; extern int OutputLL_k; extern int TreeResourceLimit; extern int DemandLookahead; extern char *RulePrefix; extern int GenStdPccts; extern char *stdpccts; extern int ParseWithPredicates; extern int ConstrainSearch; extern int PURIFY; /* MR23 */ extern set MR_CompromisedRules; /* MR14 */ extern int MR_AmbSourceSearch; /* MR11 */ extern int MR_SuppressSearch; /* MR13 */ extern int MR_AmbSourceSearchGroup; /* MR11 */ extern int MR_AmbSourceSearchChoice; /* MR11 */ extern int MR_AmbSourceSearchLimit; /* MR11 */ extern int MR_usingPredNames; /* MR11 */ extern int MR_ErrorSetComputationActive; /* MR14 */ extern char *MR_AmbAidRule; /* MR11 */ extern int MR_AmbAidLine; /* MR11 */ extern int MR_AmbAidMultiple; /* MR11 */ extern int MR_AmbAidDepth; /* MR11 */ extern int MR_skipped_e3_report; /* MR11 */ extern int MR_matched_AmbAidRule; /* MR11 */ extern int MR_Inhibit_Tokens_h_Gen; /* MR13 */ extern int NewAST; /* MR13 */ extern int tmakeInParser; /* MR23 */ extern int AlphaBetaTrace; /* MR14 */ extern int MR_BlkErr; /* MR21 */ extern int MR_AlphaBetaWarning; /* MR14 */ extern int MR_AlphaBetaMessageCount; /* MR14 */ extern int MR_MaintainBackTrace; /* MR14 */ extern int MR_BadExprSets; /* MR13 */ extern int FoundGuessBlk; extern int FoundException; extern int FoundAtOperator; /* MR6 */ extern int FoundExceptionGroup; /* MR6 */ extern int WarningLevel; extern int UseStdout; /* MR6 */ extern int TabWidth; /* MR6 */ extern int pLevel; extern int pAlt1; extern int pAlt2; extern int AImode; extern int HoistPredicateContext; extern int MRhoisting; /* MR9 */ extern int MRhoistingk; /* MR13 */ extern int MR_debugGenRule; /* MR11 */ extern int GenCC; extern char *ParserName; extern char *StandardSymbols[]; extern char *ASTSymbols[]; extern set reserved_positions; extern set all_tokens; extern set imag_tokens; extern set tokclasses; extern ListNode *ForcedTokens; extern int *TokenInd; extern FILE *Parser_h, *Parser_c; extern char CurrentClassName[]; extern int no_classes_found; extern char Parser_h_Name[]; extern char Parser_c_Name[]; extern char MRinfoFile_Name[]; /* MR10 */ extern FILE *MRinfoFile; /* MR10 */ extern int MRinfo; /* MR10 */ extern int MRinfoSeq; /* MR10 */ extern int InfoP; /* MR10 */ extern int InfoT; /* MR10 */ extern int InfoF; /* MR10 */ extern int InfoM; /* MR10 */ extern int InfoO; /* MR12 */ extern int PotentialSuppression; /* MR10 */ extern int PotentialDummy; /* MR10 */ extern int TnodesInUse; /* MR10 */ extern int TnodesPeak; /* MR10 */ extern int TnodesReportThreshold; /* MR11 */ extern int TnodesAllocated; /* MR10 */ extern char *ClassDeclStuff; /* MR10 */ extern char *BaseClassName; /* MR22 */ extern ListNode *class_before_actions, *class_after_actions; extern char *UserTokenDefsFile; extern int UserDefdTokens; extern ListNode *MetaTokenNodes; extern char *OutputDirectory; extern int DontCopyTokens; extern int LTinTokenAction; /* MR23 */ extern set AST_nodes_refd_in_actions; extern ListNode *CurExGroups; extern int CurBlockID; extern int CurAltNum; extern Junction *CurAltStart; extern Junction *OuterAltStart; /* chain exception groups MR7 */ extern ExceptionGroup *DefaultExGroup; extern int NumSignals; extern int ContextGuardTRAV; extern Junction *MR_RuleBlkWithHalt; /* MR10 */ extern PointerStack MR_BackTraceStack; /* MR10 */ extern PointerStack MR_PredRuleRefStack; /* MR10 */ extern PointerStack MR_RuleBlkWithHaltStack; /* MR10 */ /* */ /* MR1 10-Apr-97 MR1 Previously unable to put right shift operator */ /* MR1 in DLG action */ /* */ extern int tokenActionActive; /* MR1 */ extern char *PRED_OR_LIST; /* MR10 */ extern char *PRED_AND_LIST; /* MR10 */ #ifdef __VMS #define STRICMP strcasecmp /* MR21 */ #else #define STRICMP stricmp /* MR21 */ #endif /* MR26 */ #ifdef PCCTS_USE_STDARG extern Tree *tmake(Tree *root, ...); #else extern Tree *tmake(); #endif #ifdef __USE_PROTOS extern int STRICMP(const char*, const char*); extern void istackreset(void); extern int istacksize(void); extern void pushint(int); extern int popint( void ); extern int istackempty( void ); extern int topint( void ); extern void NewSetWd( void ); extern void DumpSetWd( void ); extern void DumpSetWdForC( void ); extern void DumpSetWdForCC( void ); extern void NewSet( void ); extern void FillSet( set ); extern void ComputeErrorSets( void ); extern void ComputeTokSets( void ); extern void SubstErrorClass( set * ); extern int DefErrSet( set *, int, char * ); extern int DefErrSetForC( set *, int, char * ); extern int DefErrSetForCC( set *, int, char * ); extern int DefErrSet1(int, set *, int, char *); /* MR21 */ extern int DefErrSetForC1(int, set *, int, char *, const char* ); /* MR21 */ extern int DefErrSetForCC1(int, set *, int, char *, const char* ); /* MR21 */ extern int DefErrSetWithSuffix(int, set *, int, char *, const char *); /* MR21 */ extern void GenErrHdr( void ); extern void dumpExpr( FILE *, char * ); extern void addParm( Node *, char * ); extern Graph buildAction( char *, int, int, int ); extern Graph buildToken( char * ); extern Graph buildWildCard( char * ); extern Graph buildRuleRef( char * ); extern Graph Or( Graph, Graph ); extern Graph Cat( Graph, Graph ); extern Graph makeOpt( Graph, int, char *); extern Graph makeBlk( Graph, int, char *); extern Graph makeLoop( Graph, int, char *); extern Graph makePlus( Graph, int, char *); extern Graph emptyAlt( void ); extern Graph emptyAlt3( void ); extern TokNode * newTokNode( void ); extern RuleRefNode * newRNode( void ); extern Junction * newJunction( void ); extern ActionNode * newActionNode( void ); extern char * makelocks( void ); extern void preorder( Tree * ); extern Tree * tnode( int ); extern void _Tfree( Tree * ); extern Tree * tdup( Tree * ); extern int is_single_tuple( Tree * ); extern Tree * tappend( Tree *, Tree * ); extern void Tfree( Tree * ); extern Tree * tlink( Tree *, Tree *, int ); extern Tree * tshrink( Tree * ); extern Tree * tflatten( Tree * ); extern Tree * tJunc( Junction *, int, set * ); extern Tree * tRuleRef( RuleRefNode *, int, set * ); extern Tree * tToken( TokNode *, int, set * ); extern Tree * tAction( ActionNode *, int, set * ); extern int tmember( Tree *, Tree * ); extern int tmember_constrained( Tree *, Tree * ); extern Tree * tleft_factor( Tree * ); extern Tree * trm_perm( Tree *, Tree * ); extern void tcvt( set *, Tree * ); extern Tree * permute( int, int ); extern Tree * VerifyAmbig( Junction *, Junction *, unsigned **, set *, Tree **, Tree **, int * ); extern set rJunc( Junction *, int, set * ); extern set rRuleRef( RuleRefNode *, int, set * ); extern set rToken( TokNode *, int, set * ); extern set rAction( ActionNode *, int, set * ); extern void HandleAmbiguity( Junction *, Junction *, Junction *, int ); extern set First( Junction *, int, int, int * ); extern void freeBlkFsets( Junction * ); extern void genAction( ActionNode * ); extern void genRuleRef( RuleRefNode * ); extern void genToken( TokNode * ); extern void genOptBlk( Junction * ); extern void genLoopBlk( Junction *, Junction *, Junction *, int ); extern void genLoopBegin( Junction * ); extern void genPlusBlk( Junction * ); extern void genSubBlk( Junction * ); extern void genRule( Junction * ); extern void genJunction( Junction * ); extern void genEndBlk( Junction * ); extern void genEndRule( Junction * ); extern void genHdr( int ); extern void genHdr1( int ); extern void dumpAction( char *, FILE *, int, int, int, int ); extern void dumpActionPlus(ActionNode*, char *, FILE *, int, int, int, int ); /* MR21 */ extern Entry ** newHashTable( void ); extern Entry * hash_add( Entry **, char *, Entry * ); extern Entry * hash_get( Entry **, char * ); extern void hashStat( Entry ** ); extern char * mystrdup( char * ); extern void genLexDescr( void ); extern void dumpLexClasses( FILE * ); extern void genDefFile( void ); extern void DumpListOfParmNames( char *, FILE *, int ); /* MR5 janm 26-May-97 */ extern int DumpNextNameInDef( char **, FILE * ); extern void DumpOldStyleParms( char *, FILE * ); extern void DumpType( char *, FILE * ); extern int strmember( char *, char * ); /* extern int HasComma( char * ); MR23 Replaced by hasMultipleOperands() */ extern void DumpRetValStruct( FILE *, char *, int ); extern char * StripQuotes( char * ); extern int main( int, char *[] ); extern void readDescr( void ); extern FILE * NextFile( void ); extern char * outnameX( char *, char *); extern char * outname( char * ); extern void fatalFL( char *, char *, int ); extern void fatal_intern( char *, char *, int ); extern void cleanUp( void ); extern char * eMsg3( char *, char *, char *, char * ); extern char * eMsgd( char *, int ); extern char * eMsgd2( char *, int, int ); extern void s_fprT( FILE *, set ); extern char * TerminalString( int ); extern void lexclass( char * ); extern void lexmode( int ); extern int LexClassIndex( char * ); extern int hasAction( char * ); extern void setHasAction( char *, char * ); extern int addTname( char * ); extern int addTexpr( char * ); extern int Tnum( char * ); extern void Tklink( char *, char * ); extern Entry * newEntry( char *, int ); extern void list_add( ListNode **, void * ); extern void list_free( ListNode **, int freeData ); /* MR10 */ extern void list_apply( ListNode *, void (*)(void *) ); extern int list_search_cstring (ListNode *, char *); /* MR27 */ extern char * Fkey( char *, int, int ); extern void FoPush( char *, int ); extern void FoPop( int ); extern void RegisterCycle( char *, int ); extern void ResolveFoCycles( int ); extern void pJunc( Junction * ); extern void pRuleRef( RuleRefNode * ); extern void pToken( TokNode * ); extern void pAction( ActionNode * ); extern void FoLink( Node * ); extern void addFoLink( Node *, char *, Junction * ); extern void GenCrossRef( Junction * ); extern void defErr( char *, long, long, long, long, long, long ); extern void genStdPCCTSIncludeFile(FILE *,char *); /* MR10 */ extern char * pcctsBaseName(char *); /* MR32 */ extern Predicate *find_predicates(Node *); /* MR10 */ extern Predicate *MR_find_predicates_and_supp(Node *); /* MR13 */ extern int predicateLookaheadDepth(ActionNode *); /* MR10 */ extern void predicate_free(Predicate *); /* MR10 */ extern Predicate * predicate_dup(Predicate *); /* MR10 */ extern Predicate * predicate_dup_without_context(Predicate *); /* MR11 */ extern void GenRulePrototypes(FILE *, Junction *); extern Junction *first_item_is_guess_block(Junction *); extern Junction *first_item_is_guess_block_extra(Junction * q); /* MR30 */ extern Junction *analysis_point(Junction *); extern Tree *make_tree_from_sets(set *, set *); extern Tree *tdup_chain(Tree *); extern Tree *tdif(Tree *, Predicate *, set *, set *); extern set covered_set(Predicate *); extern void AmbiguityDialog(Junction *, int, Junction *, Junction *, int *, int *); extern void dumpAmbigMsg(set *, FILE *, int); extern void GenRuleFuncRedefs(FILE *, Junction *); extern void GenPredefinedSymbolRedefs(FILE *); extern void GenASTSymbolRedefs(FILE *); extern void GenRemapFile(void); extern void GenSetRedefs(FILE *); extern ForcedToken *newForcedToken(char *, int); extern void RemapForcedTokens(void); extern char *TokenOrExpr(int); extern void setUpperRange(TokNode *, char *); extern void GenParser_c_Hdr(void); extern void GenParser_h_Hdr(void); extern void GenRuleMemberDeclarationsForCC(FILE *, Junction *); extern int addForcedTname( char *, int ); extern char *OutMetaName(char *); extern void OutFirstSetSymbol(Junction *q, char *); /* MR21 */ extern void warnNoFL(char *err); extern void warnFL(char *err,char *f,int l); extern void warn(char *err); extern void warnNoCR( char *err ); extern void errNoFL(char *err); extern void errFL(char *err,char *f,int l); extern void err(char *err); extern void errNoCR( char *err ); extern void genPredTree( Predicate *p, Node *j, int ,int); extern UserAction *newUserAction(char *); extern char *gate_symbol(char *name); extern char *makeAltID(int blockid, int altnum); extern void DumpRemainingTokSets(void); extern void DumpANSIFunctionArgDef(FILE *f, Junction *q, int bInit); /* MR23 */ extern void DumpFormals(FILE *, char *, int bInit); /* MR23 */ extern char* hideDefaultArgs(const char* pdecl); /* MR22 VHS */ extern Predicate *computePredFromContextGuard(Graph,int *msgDone); /* MR21 */ extern void recomputeContextGuard(Predicate *); /* MR13 */ extern Predicate *new_pred(void); extern void chkGTFlag(void); extern void leAdd(LabelEntry *); /* MR7 */ extern void leFixup(void); /* MR7 */ extern void egAdd(ExceptionGroup *); /* MR7 */ extern void egFixup(void); /* MR7 */ extern void altAdd(Junction *); /* MR7 */ extern void altFixup(void); /* MR7 */ extern Predicate * MR_find_in_aSubBlk(Junction *alt); /* MR10 */ extern Predicate * MR_predFlatten(Predicate *p); /* MR10 */ extern Predicate * MR_predSimplifyALL(Predicate *p); /* MR10 */ extern Predicate * MR_predSimplifyALLX(Predicate *p,int skipPass3); /* MR10 */ extern int MR_allPredLeaves(Predicate *p); /* MR10 */ extern void MR_cleanup_pred_trees(Predicate *p); /* MR10 */ extern int MR_predicate_context_completed(Predicate *p); /* MR10 */ extern void MR_check_pred_too_long(Predicate *p,set completion); /* MR10 */ extern Tree * MR_remove_epsilon_from_tree(Tree *t); /* MR10 */ extern Tree * MR_computeTreeAND(Tree *l,Tree *r); /* MR10 */ extern int MR_tree_equ(Tree *big, Tree *small); /* MR10 */ extern set MR_First(int ck,Junction *j,set *incomplete); /* MR10 */ extern set MR_compute_pred_set(Predicate *p); /* MR10 */ extern Tree * MR_compute_pred_tree_context(Predicate *p); /* MR10 */ extern int MR_pointerStackPush(PointerStack *,void *); /* MR10 */ extern void * MR_pointerStackPop(PointerStack *); /* MR10 */ extern void * MR_pointerStackTop(PointerStack *); /* MR10 */ extern void MR_pointerStackReset(PointerStack *); /* MR10 */ extern void MR_backTraceReport(void); /* MR10 */ extern void MR_alphaBetaTraceReport(void); /* MR14 */ extern void MR_dumpRuleSet(set); /* MR14 */ extern void MR_predContextPresent(Predicate *p,int *,int *); /* MR10 */ extern void MR_dumpPred(Predicate *p,int withContext); /* MR10 */ extern void MR_dumpPred1(int,Predicate *p,int withContext); /* MR10 */ extern void MR_xxxIndent(FILE *f,int depth); /* MR11 */ extern void MR_outputIndent(int depth); /* MR11 */ extern void MR_stderrIndent(int depth); /* MR11 */ extern Junction * MR_ruleReferenced(RuleRefNode *rrn); /* MR10 */ extern Junction * MR_nameToRuleBlk(char *); /* MR10 */ extern void MR_releaseResourcesUsedInRule(Node *); /* MR10 */ extern void MR_dumpTreeX(int depth,Tree *t,int across); /* MR10 */ extern void MR_dumpTreeF(FILE *f,int depth,Tree *t,int across); /* MR10 */ extern void DumpFcache(void); /* MR10 */ extern void MR_dumpTokenSet(FILE *f,int depth,set s); /* MR10 */ extern void MR_traceAmbSource(set *,Junction *,Junction *); /* MR11 */ extern void MR_traceAmbSourceK(Tree *,Junction *a1,Junction *a2); /* MR11 */ extern void MR_traceAmbSourceKclient(void); /* MR20 */ extern Node *MR_advance(Node *); /* MR11 */ extern int MR_offsetFromRule(Node *); /* MR11 */ extern char *MR_ruleNamePlusOffset(Node *); /* MR11 */ extern int MR_max_height_of_tree(Tree *); /* MR11 */ extern int MR_all_leaves_same_height(Tree *,int); /* MR11 */ extern void MR_projectTreeOntoSet(Tree *t,int k,set *); /* MR11 */ extern Tree *MR_make_tree_from_set(set); /* MR11 */ extern Predicate *MR_removeRedundantPredPass3(Predicate *); /* MR11 */ extern void MR_pred_depth(Predicate *,int *); /* MR11 */ extern int MR_comparePredicates(Predicate *,Predicate *); /* MR11 */ extern Predicate * MR_unfold(Predicate *); /* MR11 */ extern void MR_simplifyInverted(Predicate *,int); /* MR11 */ extern int MR_secondPredicateUnreachable /* MR11 */ (Predicate *first,Predicate *second); /* MR11 */ extern void MR_clearPredEntry(Predicate *); /* MR11 */ extern void MR_orphanRules(FILE *); /* MR12 */ extern void MR_merge_contexts(Tree *); /* MR12 */ extern int ci_strequ(char *,char *); /* MR12 */ extern void MR_guardPred_plainSet(ActionNode *anode,Predicate *); /* MR12c */ extern void MR_suppressSearchReport(void); /* MR12c */ extern Predicate * MR_suppressK(Node *,Predicate *); /* MR13 */ extern void MR_backTraceDumpItem(FILE *,int skip,Node *n); /* MR13 */ extern void MR_backTraceDumpItemReset(void); /* MR13 */ extern Junction * MR_junctionWithoutP2(Junction *); /* MR13 */ extern void MR_setConstrainPointer(set *); /* MR18 */ extern void BlockPreambleOption(Junction *q, char * pSymbol); /* MR23 */ extern char* getInitializer(char *); /* MR23 */ extern char *endFormal(char *pStart, /* MR23 */ char **ppDataType, /* MR23 */ char **ppSymbol, /* MR23 */ char **ppEqualSign, /* MR23 */ char **ppValue, /* MR23 */ char **ppSeparator, /* MR23 */ int *pNext); /* MR23 */ extern char *strBetween(char *pStart, /* MR23 */ char *pNext, /* MR23 */ char *pStop); /* MR23 */ extern int hasMultipleOperands(char *); /* MR23 */ extern void DumpInitializers(FILE*, RuleEntry*, char*); /* MR23 */ extern int isTermEntryTokClass(TermEntry *); /* MR23 */ extern int isEmptyAlt(Node *, Node *); /* MR23 */ #else extern int STRICMP(); extern void istackreset(); extern int istacksize(); extern void pushint(); extern int popint(); extern int istackempty(); extern int topint(); extern void NewSetWd(); extern void DumpSetWd(); extern void DumpSetWdForC(); extern void DumpSetWdForCC(); extern void NewSet(); extern void FillSet(); extern void ComputeErrorSets(); extern void ComputeTokSets(); extern void SubstErrorClass(); extern int DefErrSet(); extern int DefErrSetForC(); extern int DefErrSetForCC(); extern int DefErrSet1(); extern int DefErrSetForC1(); extern int DefErrSetForCC1(); extern int DefErrSetWithSuffix(); /* MR21 */ extern void GenErrHdr(); extern void dumpExpr(); extern void addParm(); extern Graph buildAction(); extern Graph buildToken(); extern Graph buildWildCard(); extern Graph buildRuleRef(); extern Graph Or(); extern Graph Cat(); extern Graph makeOpt(); extern Graph makeBlk(); extern Graph makeLoop(); extern Graph makePlus(); extern Graph emptyAlt(); extern Graph emptyAlt3(); extern TokNode * newTokNode(); extern RuleRefNode * newRNode(); extern Junction * newJunction(); extern ActionNode * newActionNode(); extern char * makelocks(); extern void preorder(); extern Tree * tnode(); extern void _Tfree(); extern Tree * tdup(); extern int is_single_tuple(); extern Tree * tappend(); extern void Tfree(); extern Tree * tlink(); extern Tree * tshrink(); extern Tree * tflatten(); extern Tree * tJunc(); extern Tree * tRuleRef(); extern Tree * tToken(); extern Tree * tAction(); extern int tmember(); extern int tmember_constrained(); extern Tree * tleft_factor(); extern Tree * trm_perm(); extern void tcvt(); extern Tree * permute(); extern Tree * VerifyAmbig(); extern set rJunc(); extern set rRuleRef(); extern set rToken(); extern set rAction(); extern void HandleAmbiguity(); extern set First(); extern void freeBlkFsets(); extern void genAction(); extern void genRuleRef(); extern void genToken(); extern void genOptBlk(); extern void genLoopBlk(); extern void genLoopBegin(); extern void genPlusBlk(); extern void genSubBlk(); extern void genRule(); extern void genJunction(); extern void genEndBlk(); extern void genEndRule(); extern void genHdr(); extern void genHdr1(); extern void dumpAction(); extern void dumpActionPlus(); /* MR21 */ extern Entry ** newHashTable(); extern Entry * hash_add(); extern Entry * hash_get(); extern void hashStat(); extern char * mystrdup(); extern void genLexDescr(); extern void dumpLexClasses(); extern void genDefFile(); extern void DumpListOfParmNames(); /* MR5 janm 26-May-97 */ extern int DumpNextNameInDef(); extern void DumpOldStyleParms(); extern void DumpType(); extern int strmember(); /* extern int HasComma(); MR23 Replaced by hasMultipleOperands() */ extern void DumpRetValStruct(); extern char * StripQuotes(); extern int main(); extern void readDescr(); extern FILE * NextFile(); extern char * outnameX(); extern char * outname(); extern void fatalFL(); extern void fatal_intern(); extern void cleanUp(); extern char * eMsg3(); extern char * eMsgd(); extern char * eMsgd2(); extern void s_fprT(); extern char * TerminalString(); extern void lexclass(); extern void lexmode(); extern int LexClassIndex(); extern int hasAction(); extern void setHasAction(); extern int addTname(); extern int addTexpr(); extern int Tnum(); extern void Tklink(); extern Entry * newEntry(); extern void list_add(); extern void list_free(); /* MR10 */ extern void list_apply(); extern int list_search_cstring (); /* MR27 */ extern char * Fkey(); extern void FoPush(); extern void FoPop(); extern void RegisterCycle(); extern void ResolveFoCycles(); extern void pJunc(); extern void pRuleRef(); extern void pToken(); extern void pAction(); extern void FoLink(); extern void addFoLink(); extern void GenCrossRef(); extern void defErr(); extern void genStdPCCTSIncludeFile(); extern char * pcctsBaseName(); /* MR32 */ extern Predicate *find_predicates(); extern Predicate *MR_find_predicates_and_supp(); /* MR13 */ extern int predicateLookaheadDepth(); /* MR10 */ extern void predicate_free(); /* MR10 */ extern Predicate * predicate_dup(); /* MR10 */ extern Predicate * predicate_dup_without_context(); /* MR11 */ extern void GenRulePrototypes(); extern Junction *first_item_is_guess_block(); extern Junction *first_item_is_guess_block_extra(); /* MR30 */ extern Junction *analysis_point(); extern Tree *make_tree_from_sets(); extern Tree *tdup_chain(); extern Tree *tdif(); extern set covered_set(); extern void AmbiguityDialog(); extern void dumpAmbigMsg(); extern void GenRuleFuncRedefs(); extern void GenPredefinedSymbolRedefs(); extern void GenASTSymbolRedefs(); extern void GenRemapFile(); extern void GenSetRedefs(); extern ForcedToken *newForcedToken(); extern void RemapForcedTokens(); extern char *TokenOrExpr(); extern void setUpperRange(); extern void GenParser_c_Hdr(); extern void GenParser_h_Hdr(); extern void GenRuleMemberDeclarationsForCC(); extern int addForcedTname(); extern char *OutMetaName(); extern void OutFirstSetSymbol(); /* MR21 */ extern void warnNoFL(); extern void warnFL(); extern void warn(); extern void warnNoCR(); extern void errNoFL(); extern void errFL(); extern void err(); extern void errNoCR(); extern void genPredTree(); extern UserAction *newUserAction(); extern char *gate_symbol(); extern char *makeAltID(); extern void DumpRemainingTokSets(); extern void DumpANSIFunctionArgDef(); extern void DumpFormals(); /* MR23 */ extern char* hideDefaultArgs(); /* MR22 VHS */ extern Predicate *computePredFromContextGuard(); extern void recomputeContextGuard(); /* MR13 */ extern Predicate *new_pred(); extern void chkGTFlag(); extern void leAdd(); /* MR7 */ extern void leFixup(); /* MR7 */ extern void egAdd(); /* MR7 */ extern void egFixup(); /* MR7 */ extern void altAdd(); /* MR7 */ extern void altFixup(); /* MR7 */ extern Predicate * MR_find_in_aSubBlk(); /* MR10 */ extern Predicate * MR_predFlatten(); /* MR10 */ extern Predicate * MR_predSimplifyALL(); /* MR10 */ extern Predicate * MR_predSimplifyALLX(); /* MR10 */ extern void MR_cleanup_pred_trees(); /* MR10 */ extern int MR_allPredLeaves(); /* MR10 */ extern int MR_predicate_context_completed(); /* MR10 */ extern void MR_check_pred_too_long(); /* MR10 */ extern Tree * MR_remove_epsilon_from_tree(); /* MR10 */ extern Tree * MR_computeTreeAND(); /* MR10 */ extern int MR_tree_equ(); /* MR10 */ extern set MR_First(); /* MR10 */ extern set MR_compute_pred_set(); /* MR10 */ extern Tree * MR_compute_pred_tree_context(); /* MR10 */ extern int MR_pointerStackPush(); /* MR10 */ extern void * MR_pointerStackPop(); /* MR10 */ extern void * MR_pointerStackTop(); /* MR10 */ extern void MR_pointerStackReset(); /* MR10 */ extern void MR_backTraceReport(); /* MR10 */ extern void MR_alphaBetaTraceReport(); /* MR14 */ extern void MR_dumpRuleSet(); /* MR14 */ extern void MR_predContextPresent(); /* MR10 */ extern void MR_dumpPred(); /* MR10 */ extern void MR_dumpPred1(); /* MR10 */ extern void MR_xxxIndent(); /* MR11 */ extern void MR_stderrIndent(); /* MR11 */ extern void MR_outputIndent(); /* MR11 */ extern Junction * MR_ruleReferenced(); /* MR10 */ extern void MR_releaseResourcesUsedInRule(); /* MR10 */ extern void MR_dumpTreeX(); /* MR10 */ extern void MR_dumpTreeF(); /* MR10 */ extern void DumpFcache(); /* MR10 */ extern void MR_dumpTokenSet(); /* MR10 */ extern void MR_traceAmbSource(); /* MR11 */ extern Node *MR_advance(); /* MR11 */ extern int MR_offsetFromRule(); /* MR11 */ extern char *MR_ruleNamePlusOffset(); /* MR11 */ extern void MR_traceAmbSourceK(); /* MR11 */ extern void MR_traceAmbSourceKclient(); /* [i_a] added */ extern int MR_max_height_of_tree(); /* MR11 */ extern int MR_all_leaves_same_height(); /* MR11 */ extern void MR_projectTreeOntoSet(); /* MR11 */ extern Tree *MR_make_tree_from_set(); /* MR11 */ extern Predicate *MR_removeRedundantPredPass3(); /* MR11 */ extern void MR_pred_depth(); /* MR11 */ extern int MR_comparePredicates(); /* MR11 */ extern Predicate * MR_unfold(); /* MR11 */ extern void MR_simplifyInverted(); /* MR11 */ extern int MR_secondPredicateUnreachable(); /* MR11 */ extern Junction * MR_nameToRuleBlk(); /* MR10 */ extern void MR_clearPredEntry(); /* MR11 */ extern void MR_orphanRules(); /* MR12 */ extern void MR_merge_contexts(); /* MR12 */ extern int ci_strequ(); /* MR12 */ extern void MR_guardPred_plainSet(); /* MR12c */ extern void MR_suppressSearchReport(); /* MR12c */ extern Predicate * MR_suppressK(); /* MR13 */ extern void MR_backTraceDumpItem(); /* MR13 */ extern void MR_backTraceDumpItemReset(); /* MR13 */ extern Junction * MR_junctionWithoutP2(); /* MR13 */ extern void MR_setConstrainPointer(); /* MR18 */ extern void BlockPreambleOption(); /* MR23 */ extern char* getInitializer(); /* MR23 */ extern int hasMultipleOperands(); /* MR23 */ extern char *endFormal(); /* MR23 */ extern char *strBetween(); /* MR23 */ extern void DumpInitializers(); /* MR23 */ extern int isTermEntryTokClass(); /* MR23 */ extern int isEmptyAlt(); #endif #ifdef __USE_PROTOS #include #endif /* MR20 G. Hobbelt Create proper externs for dlg variables */ extern set attribsRefdFromAction; extern int inAlt; extern int UsedOldStyleAttrib; extern int UsedNewStyleLabel; #define MAX_BLK_LEVEL 100 /* MR23 */ extern int CurBlockID_array[MAX_BLK_LEVEL]; /* MR23 */ extern int CurAltNum_array[MAX_BLK_LEVEL]; /* MR23 */ cdrdao-cdrdao-f00afb2/pccts/antlr/scan.c000066400000000000000000004331541511453746600202340ustar00rootroot00000000000000 /* parser.dlg -- DLG Description of scanner * * Generated from: antlr.g * * Terence Parr, Will Cohen, and Hank Dietz: 1989-2001 * Purdue University Electrical Engineering * With AHPCRC, University of Minnesota * ANTLR Version 1.33MR32 */ #define ANTLR_VERSION 13332 #include "pcctscfg.h" #include "pccts_stdio.h" #include "pcctscfg.h" #include "set.h" #include #include "syn.h" #include "hash.h" #include "generic.h" #define zzcr_attr(attr,tok,t) #include "antlr.h" #include "tokens.h" #include "dlgdef.h" LOOKAHEAD void #ifdef __USE_PROTOS zzerraction(void) #else zzerraction() #endif { (*zzerr)("invalid token"); zzadvance(); zzskip(); } /* * D L G tables * * Generated from: parser.dlg * * 1989-2001 by Will Cohen, Terence Parr, and Hank Dietz * Purdue University Electrical Engineering * DLG Version 1.33MR32 */ #include "mode.h" /* maintained, but not used for now */ set AST_nodes_refd_in_actions = set_init; int inAlt = 0; set attribsRefdFromAction = set_init; /* MR20 */ int UsedOldStyleAttrib = 0; int UsedNewStyleLabel = 0; #ifdef __USE_PROTOS char *inline_set(char *); #else char *inline_set(); #endif /* MR1 10-Apr-97 MR1 Previously unable to put right shift operator */ /* MR1 in DLG action */ int tokenActionActive=0; /* MR1 */ static char * #ifdef __USE_PROTOS getFileNameFromTheLineInfo(char *toStr, char *fromStr) #else getFileNameFromTheLineInfo(toStr, fromStr) char *toStr, *fromStr; #endif { int i, j, k; if (!fromStr || !toStr) return toStr; /* find the first " */ for (i=0; (ielem->ntype == nToken,"mark_label_used... ntype != nToken"); tn=(TokNode *)le->elem; require (tn->label != 0,"mark_label_used... TokNode has no label"); tn->label_used_in_semantic_pred=1; } static void act1() { NLA = Eof; /* L o o k F o r A n o t h e r F i l e */ { FILE *new_input; new_input = NextFile(); if ( new_input == NULL ) { NLA=Eof; return; } fclose( input ); input = new_input; zzrdstream( input ); zzskip(); /* Skip the Eof (@) char i.e continue */ } } static void act2() { NLA = 76; zzskip(); } static void act3() { NLA = 77; zzline++; zzskip(); } static void act4() { NLA = 78; zzmode(ACTIONS); zzmore(); istackreset(); pushint(']'); } static void act5() { NLA = 79; action_file=CurFile; action_line=zzline; zzmode(ACTIONS); zzmore(); list_free(&CurActionLabels,0); /* MR10 */ numericActionLabel=0; /* MR10 */ istackreset(); pushint('>'); } static void act6() { NLA = 80; zzmode(STRINGS); zzmore(); } static void act7() { NLA = 81; zzmode(COMMENTS); zzskip(); } static void act8() { NLA = 82; warn("Missing /*; found dangling */"); zzskip(); } static void act9() { NLA = 83; zzmode(CPP_COMMENTS); zzskip(); } static void act10() { NLA = 84; zzline = atoi(zzbegexpr+5) - 1; zzline++; zzmore(); getFileNameFromTheLineInfo(FileStr[CurFile], zzbegexpr); } static void act11() { NLA = 85; zzline++; zzmore(); } static void act12() { NLA = 86; warn("Missing <<; found dangling >>"); zzskip(); } static void act13() { NLA = WildCard; } static void act14() { NLA = 88; FoundException = 1; /* MR6 */ FoundAtOperator = 1; } static void act15() { NLA = Pragma; } static void act16() { NLA = FirstSetSymbol; } static void act17() { NLA = 94; } static void act18() { NLA = 95; } static void act19() { NLA = 96; } static void act20() { NLA = 97; } static void act21() { NLA = 98; } static void act22() { NLA = 99; } static void act23() { NLA = 102; } static void act24() { NLA = 103; } static void act25() { NLA = 104; } static void act26() { NLA = 105; } static void act27() { NLA = 106; } static void act28() { NLA = 107; } static void act29() { NLA = 108; } static void act30() { NLA = 109; } static void act31() { NLA = 110; } static void act32() { NLA = 111; } static void act33() { NLA = 112; } static void act34() { NLA = 113; } static void act35() { NLA = 114; } static void act36() { NLA = 115; } static void act37() { NLA = 116; } static void act38() { NLA = 117; } static void act39() { NLA = 118; } static void act40() { NLA = 119; } static void act41() { NLA = 120; } static void act42() { NLA = 121; } static void act43() { NLA = 122; } static void act44() { NLA = 123; } static void act45() { NLA = 124; } static void act46() { NLA = 125; } static void act47() { NLA = 126; } static void act48() { NLA = 127; } static void act49() { NLA = 128; } static void act50() { NLA = 129; } static void act51() { NLA = 130; } static void act52() { NLA = 131; } static void act53() { NLA = 132; } static void act54() { NLA = 133; } static void act55() { NLA = 134; } static void act56() { NLA = 135; } static void act57() { NLA = NonTerminal; while ( zzchar==' ' || zzchar=='\t' ) { zzadvance(); } if ( zzchar == ':' && inAlt ) NLA = LABEL; } static void act58() { NLA = TokenTerm; while ( zzchar==' ' || zzchar=='\t' ) { zzadvance(); } if ( zzchar == ':' && inAlt ) NLA = LABEL; } static void act59() { NLA = 136; warn(eMsg1("unknown meta-op: %s",LATEXT(1))); zzskip(); } static unsigned char shift0[257] = { 0, 58, 58, 58, 58, 58, 58, 58, 58, 58, 1, 2, 58, 58, 3, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 1, 40, 6, 9, 58, 58, 45, 58, 46, 47, 8, 52, 58, 58, 18, 7, 16, 14, 15, 16, 16, 16, 16, 16, 16, 16, 41, 42, 5, 48, 17, 53, 19, 56, 56, 56, 56, 56, 26, 56, 56, 56, 56, 56, 51, 56, 56, 56, 56, 56, 56, 29, 56, 56, 56, 56, 56, 56, 56, 4, 20, 58, 50, 57, 58, 23, 31, 38, 34, 13, 35, 24, 33, 11, 55, 36, 10, 25, 12, 32, 21, 55, 22, 27, 28, 54, 55, 55, 43, 30, 55, 39, 44, 37, 49, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58 }; static void act60() { NLA = Eof; } static void act61() { NLA = QuotedTerm; zzmode(START); } static void act62() { NLA = 3; zzline++; warn("eoln found in string"); zzskip(); } static void act63() { NLA = 4; zzline++; zzmore(); } static void act64() { NLA = 5; zzmore(); } static void act65() { NLA = 6; zzmore(); } static unsigned char shift1[257] = { 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 5, 5, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }; static void act66() { NLA = Eof; } static void act67() { NLA = 7; zzmode(ACTIONS); zzmore(); } static void act68() { NLA = 8; zzline++; warn("eoln found in string (in user action)"); zzskip(); } static void act69() { NLA = 9; zzline++; zzmore(); } static void act70() { NLA = 10; zzmore(); } static void act71() { NLA = 11; zzmore(); } static unsigned char shift2[257] = { 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 5, 5, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }; static void act72() { NLA = Eof; } static void act73() { NLA = 12; zzmode(ACTIONS); zzmore(); } static void act74() { NLA = 13; zzline++; warn("eoln found in char literal (in user action)"); zzskip(); } static void act75() { NLA = 14; zzmore(); } static void act76() { NLA = 15; zzmore(); } static unsigned char shift3[257] = { 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 5, 5, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }; static void act77() { NLA = Eof; } static void act78() { NLA = 16; zzmode(ACTIONS); zzmore(); } static void act79() { NLA = 17; zzmore(); } static void act80() { NLA = 18; zzline++; zzmore(); DAWDLE; } static void act81() { NLA = 19; zzmore(); } static unsigned char shift4[257] = { 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 5, 5, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }; static void act82() { NLA = Eof; } static void act83() { NLA = 20; zzmode(PARSE_ENUM_FILE); zzmore(); } static void act84() { NLA = 21; zzmore(); } static void act85() { NLA = 22; zzline++; zzmore(); DAWDLE; } static void act86() { NLA = 23; zzmore(); } static unsigned char shift5[257] = { 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 5, 5, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }; static void act87() { NLA = Eof; } static void act88() { NLA = 24; zzline++; zzmode(PARSE_ENUM_FILE); zzskip(); DAWDLE; } static void act89() { NLA = 25; zzskip(); } static unsigned char shift6[257] = { 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }; static void act90() { NLA = Eof; } static void act91() { NLA = 26; zzline++; zzmode(ACTIONS); zzmore(); DAWDLE; } static void act92() { NLA = 27; zzmore(); } static unsigned char shift7[257] = { 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }; static void act93() { NLA = Eof; } static void act94() { NLA = 28; zzline++; zzmode(START); zzskip(); DAWDLE; } static void act95() { NLA = 29; zzskip(); } static unsigned char shift8[257] = { 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }; static void act96() { NLA = Eof; } static void act97() { NLA = 30; zzmode(START); zzskip(); } static void act98() { NLA = 31; zzskip(); } static void act99() { NLA = 32; zzline++; zzskip(); DAWDLE; } static void act100() { NLA = 33; zzskip(); } static unsigned char shift9[257] = { 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 5, 5, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }; static void act101() { NLA = Eof; } static void act102() { NLA = Action; /* these do not nest */ zzmode(START); NLATEXT[0] = ' '; NLATEXT[1] = ' '; zzbegexpr[0] = ' '; zzbegexpr[1] = ' '; if ( zzbufovf ) { err( eMsgd("action buffer overflow; size %d",ZZLEXBUFSIZE)); } /* MR1 10-Apr-97 MR1 Previously unable to put right shift operator */ /* MR1 in DLG action */ /* MR1 Doesn't matter what kind of action it is - reset*/ tokenActionActive=0; /* MR1 */ } static void act103() { NLA = Pred; /* these do not nest */ zzmode(START); NLATEXT[0] = ' '; NLATEXT[1] = ' '; zzbegexpr[0] = '\0'; if ( zzbufovf ) { err( eMsgd("predicate buffer overflow; size %d",ZZLEXBUFSIZE)); }; #ifdef __cplusplus__ /* MR10 */ list_apply(CurActionLabels, (void (*)(void *))mark_label_used_in_sem_pred); #else #ifdef __STDC__ /* MR10 */ list_apply(CurActionLabels, (void (*)(void *))mark_label_used_in_sem_pred); #else #ifdef __USE_PROTOS /* MRxx */ list_apply(CurActionLabels, (void (*)(void *))mark_label_used_in_sem_pred); #else /* MR10 */ list_apply(CurActionLabels,mark_label_used_in_sem_pred); #endif #endif #endif } static void act104() { NLA = PassAction; if ( topint() == ']' ) { popint(); if ( istackempty() ) /* terminate action */ { zzmode(START); NLATEXT[0] = ' '; zzbegexpr[0] = ' '; if ( zzbufovf ) { err( eMsgd("parameter buffer overflow; size %d",ZZLEXBUFSIZE)); } } else { /* terminate $[..] and #[..] */ if ( GenCC ) zzreplstr("))"); else zzreplstr(")"); zzmore(); } } else if ( topint() == '|' ) { /* end of simple [...] */ popint(); zzmore(); } else zzmore(); } static void act105() { NLA = 37; zzmore(); zzreplstr(inline_set(zzbegexpr+ strlen("consumeUntil("))); } static void act106() { NLA = 38; zzmore(); } static void act107() { NLA = 39; zzline++; zzmore(); DAWDLE; } static void act108() { NLA = 40; zzmore(); } static void act109() { NLA = 41; zzmore(); } static void act110() { NLA = 42; if ( !GenCC ) {zzreplstr("zzaRet"); zzmore();} else err("$$ use invalid in C++ mode"); } static void act111() { NLA = 43; if ( !GenCC ) {zzreplstr("zzempty_attr"); zzmore();} else err("$[] use invalid in C++ mode"); } static void act112() { NLA = 44; pushint(']'); if ( !GenCC ) zzreplstr("zzconstr_attr("); else err("$[..] use invalid in C++ mode"); zzmore(); } static void act113() { NLA = 45; { static char buf[100]; numericActionLabel=1; /* MR10 */ if ( strlen(zzbegexpr)>(size_t)85 ) fatal("$i attrib ref too big"); set_orel(atoi(zzbegexpr+1), &attribsRefdFromAction); if ( !GenCC ) sprintf(buf,"zzaArg(zztasp%d,%s)", BlkLevel-1,zzbegexpr+1); else sprintf(buf,"_t%d%s", BlkLevel-1,zzbegexpr+1); zzreplstr(buf); zzmore(); UsedOldStyleAttrib = 1; if ( UsedNewStyleLabel ) err("cannot mix old-style $i with new-style labels"); } } static void act114() { NLA = 46; { static char buf[100]; numericActionLabel=1; /* MR10 */ if ( strlen(zzbegexpr)>(size_t)85 ) fatal("$i.field attrib ref too big"); zzbegexpr[strlen(zzbegexpr)-1] = ' '; set_orel(atoi(zzbegexpr+1), &attribsRefdFromAction); if ( !GenCC ) sprintf(buf,"zzaArg(zztasp%d,%s).", BlkLevel-1,zzbegexpr+1); else sprintf(buf,"_t%d%s.", BlkLevel-1,zzbegexpr+1); zzreplstr(buf); zzmore(); UsedOldStyleAttrib = 1; if ( UsedNewStyleLabel ) err("cannot mix old-style $i with new-style labels"); } } static void act115() { NLA = 47; { static char buf[100]; static char i[20], j[20]; char *p,*q; numericActionLabel=1; /* MR10 */ if (strlen(zzbegexpr)>(size_t)85) fatal("$i.j attrib ref too big"); for (p=zzbegexpr+1,q= &i[0]; *p!='.'; p++) { if ( q == &i[20] ) fatalFL("i of $i.j attrib ref too big", FileStr[CurFile], zzline ); *q++ = *p; } *q = '\0'; for (p++, q= &j[0]; *p!='\0'; p++) { if ( q == &j[20] ) fatalFL("j of $i.j attrib ref too big", FileStr[CurFile], zzline ); *q++ = *p; } *q = '\0'; if ( !GenCC ) sprintf(buf,"zzaArg(zztasp%s,%s)",i,j); else sprintf(buf,"_t%s%s",i,j); zzreplstr(buf); zzmore(); UsedOldStyleAttrib = 1; if ( UsedNewStyleLabel ) err("cannot mix old-style $i with new-style labels"); } } static void act116() { NLA = 48; { static char buf[300]; LabelEntry *el; zzbegexpr[0] = ' '; if ( CurRule != NULL && strcmp(CurRule, &zzbegexpr[1])==0 ) { if ( !GenCC ) zzreplstr("zzaRet"); } else if ( CurRetDef != NULL && strmember(CurRetDef, &zzbegexpr[1])) { if ( hasMultipleOperands( CurRetDef ) ) { require (strlen(zzbegexpr)<=(size_t)285, "$retval attrib ref too big"); sprintf(buf,"_retv.%s",&zzbegexpr[1]); zzreplstr(buf); } else zzreplstr("_retv"); } else if ( CurParmDef != NULL && strmember(CurParmDef, &zzbegexpr[1])) { ; } else if ( Elabel==NULL ) { { err("$-variables in actions outside of rules are not allowed"); } } else if ( (el=(LabelEntry *)hash_get(Elabel, &zzbegexpr[1]))!=NULL ) { /* MR10 */ /* MR10 */ /* element labels might exist without an elem when */ /* MR10 */ /* it is a forward reference (to a rule) */ /* MR10 */ /* MR10 */ if ( GenCC && (el->elem == NULL || el->elem->ntype==nRuleRef) ) /* MR10 */ { err(eMsg1("There are no token ptrs for rule references: '$%s'",&zzbegexpr[1])); } /* MR10 */ /* MR10 */ if ( !GenCC && (el->elem == NULL || el->elem->ntype==nRuleRef) && GenAST) { /* MR10 */ err("You can no longer use attributes returned by rules when also using ASTs"); /* MR10 */ err(" Use upward inheritance (\"rule >[Attrib a] : ... <<$a=...>>\")"); /* MR10 */ }; /* MR10 */ /* MR10 */ /* keep track of <<... $label ...>> for semantic predicates in guess mode */ /* MR10 */ /* element labels contain pointer to the owners node */ /* MR10 */ /* MR10 */ if (el->elem != NULL && el->elem->ntype == nToken) { /* MR10 */ list_add(&CurActionLabels,el); /* MR10 */ }; } else warn(eMsg1("$%s not parameter, return value, (defined) element label",&zzbegexpr[1])); } zzmore(); } static void act117() { NLA = 49; zzreplstr("(*_root)"); zzmore(); chkGTFlag(); } static void act118() { NLA = 50; if ( GenCC ) { if (NewAST) zzreplstr("(newAST)"); else zzreplstr("(new AST)");} else {zzreplstr("zzastnew()");} zzmore(); chkGTFlag(); } static void act119() { NLA = 51; zzreplstr("NULL"); zzmore(); chkGTFlag(); } static void act120() { NLA = 52; { static char buf[100]; if ( strlen(zzbegexpr)>(size_t)85 ) fatal("#i AST ref too big"); if ( GenCC ) sprintf(buf,"_ast%d%s",BlkLevel-1,zzbegexpr+1); else sprintf(buf,"zzastArg(%s)",zzbegexpr+1); zzreplstr(buf); zzmore(); set_orel(atoi(zzbegexpr+1), &AST_nodes_refd_in_actions); chkGTFlag(); } } static void act121() { NLA = 53; zzline = atoi(zzbegexpr+5) - 1; zzline++; zzmore(); getFileNameFromTheLineInfo(FileStr[CurFile], zzbegexpr); } static void act122() { NLA = 54; zzline++; zzmore(); } static void act123() { NLA = 55; if ( !(strcmp(zzbegexpr, "#ifdef")==0 || strcmp(zzbegexpr, "#if")==0 || strcmp(zzbegexpr, "#else")==0 || strcmp(zzbegexpr, "#endif")==0 || strcmp(zzbegexpr, "#ifndef")==0 || strcmp(zzbegexpr, "#define")==0 || strcmp(zzbegexpr, "#pragma")==0 || strcmp(zzbegexpr, "#undef")==0 || strcmp(zzbegexpr, "#import")==0 || strcmp(zzbegexpr, "#line")==0 || strcmp(zzbegexpr, "#include")==0 || strcmp(zzbegexpr, "#error")==0) ) { static char buf[100]; sprintf(buf, "%s_ast", zzbegexpr+1); /* MR27 */ list_add(&CurAstLabelsInActions, mystrdup(zzbegexpr+1)); zzreplstr(buf); chkGTFlag(); } zzmore(); } static void act124() { NLA = 56; pushint(']'); if ( GenCC ) { if (NewAST) zzreplstr("(newAST("); else zzreplstr("(new AST("); } else zzreplstr("zzmk_ast(zzastnew(),"); zzmore(); chkGTFlag(); } static void act125() { NLA = 57; pushint('}'); if ( GenCC ) { if (tmakeInParser) { zzreplstr("tmake("); } else { zzreplstr("ASTBase::tmake("); } } else { zzreplstr("zztmake("); } zzmore(); chkGTFlag(); } static void act126() { NLA = 58; zzmore(); } static void act127() { NLA = 59; if ( istackempty() ) zzmore(); else if ( topint()==')' ) { popint(); } else if ( topint()=='}' ) { popint(); /* terminate #(..) */ zzreplstr(", NULL)"); } zzmore(); } static void act128() { NLA = 60; pushint('|'); /* look for '|' to terminate simple [...] */ zzmore(); } static void act129() { NLA = 61; pushint(')'); zzmore(); } static void act130() { NLA = 62; zzreplstr("]"); zzmore(); } static void act131() { NLA = 63; zzreplstr(")"); zzmore(); } static void act132() { NLA = 64; if (! tokenActionActive) zzreplstr(">"); /* MR1 */ zzmore(); /* MR1 */ } static void act133() { NLA = 65; zzmode(ACTION_CHARS); zzmore(); } static void act134() { NLA = 66; zzmode(ACTION_STRINGS); zzmore(); } static void act135() { NLA = 67; zzreplstr("$"); zzmore(); } static void act136() { NLA = 68; zzreplstr("#"); zzmore(); } static void act137() { NLA = 69; zzline++; zzmore(); } static void act138() { NLA = 70; zzmore(); } static void act139() { NLA = 71; zzmore(); } static void act140() { NLA = 72; zzmode(ACTION_COMMENTS); zzmore(); } static void act141() { NLA = 73; warn("Missing /*; found dangling */ in action"); zzmore(); } static void act142() { NLA = 74; zzmode(ACTION_CPP_COMMENTS); zzmore(); } static void act143() { NLA = 75; zzmore(); } static unsigned char shift10[257] = { 0, 33, 33, 33, 33, 33, 33, 33, 33, 33, 16, 19, 33, 33, 20, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 16, 33, 28, 27, 21, 33, 33, 30, 15, 18, 32, 33, 33, 33, 25, 31, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 33, 33, 33, 33, 1, 2, 33, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 11, 26, 26, 26, 26, 26, 22, 29, 3, 33, 26, 33, 26, 26, 4, 26, 10, 26, 26, 26, 13, 26, 26, 14, 9, 6, 5, 26, 26, 26, 7, 12, 8, 26, 26, 26, 26, 26, 17, 33, 34, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33 }; static void act144() { NLA = Eof; ; } static void act145() { NLA = 137; zzskip(); } static void act146() { NLA = 138; zzline++; zzskip(); } static void act147() { NLA = 139; zzmode(TOK_DEF_CPP_COMMENTS); zzmore(); } static void act148() { NLA = 140; zzmode(TOK_DEF_COMMENTS); zzskip(); } static void act149() { NLA = 141; zzmode(TOK_DEF_CPP_COMMENTS); zzskip(); } static void act150() { NLA = 142; zzmode(TOK_DEF_CPP_COMMENTS); zzskip(); } static void act151() { NLA = 143; ; } static void act152() { NLA = 144; zzmode(TOK_DEF_CPP_COMMENTS); zzskip(); } static void act153() { NLA = 145; zzmode(TOK_DEF_CPP_COMMENTS); zzskip(); } static void act154() { NLA = 146; zzmode(TOK_DEF_CPP_COMMENTS); zzskip(); } static void act155() { NLA = 147; zzmode(TOK_DEF_CPP_COMMENTS); zzskip(); } static void act156() { NLA = 149; } static void act157() { NLA = 151; } static void act158() { NLA = 152; } static void act159() { NLA = 153; } static void act160() { NLA = 154; } static void act161() { NLA = 155; } static void act162() { NLA = 156; } static void act163() { NLA = INT; } static void act164() { NLA = ID; } static unsigned char shift11[257] = { 0, 27, 27, 27, 27, 27, 27, 27, 27, 27, 1, 2, 27, 27, 3, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 1, 27, 27, 6, 27, 27, 27, 27, 27, 27, 5, 27, 22, 27, 27, 4, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 27, 24, 27, 21, 27, 27, 27, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 26, 27, 26, 26, 26, 9, 10, 8, 26, 26, 7, 26, 26, 12, 15, 11, 17, 16, 26, 18, 13, 19, 14, 26, 26, 26, 26, 26, 20, 27, 23, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27 }; #define DfaStates 436 typedef unsigned short DfaState; static DfaState st0[60] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 13, 14, 15, 16, 17, 11, 11, 18, 11, 11, 19, 11, 11, 19, 11, 11, 11, 11, 20, 11, 11, 21, 22, 23, 24, 25, 26, 11, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 11, 11, 19, 436, 436, 436 }; static DfaState st1[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st2[60] = { 436, 2, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st3[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st4[60] = { 436, 436, 37, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st5[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st6[60] = { 436, 436, 436, 436, 436, 38, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st7[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st8[60] = { 436, 436, 436, 436, 436, 436, 436, 39, 40, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st9[60] = { 436, 436, 436, 436, 436, 436, 436, 41, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st10[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 42, 43, 43, 44, 43, 43, 43, 436, 436, 436, 436, 45, 43, 43, 43, 43, 46, 43, 47, 43, 43, 43, 43, 48, 43, 49, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st11[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st12[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 51, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st13[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 13, 13, 13, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st14[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 52, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st15[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 53, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st16[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st17[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 54, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st18[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 55, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st19[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 56, 56, 56, 56, 56, 56, 56, 436, 436, 436, 436, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 436, 56, 436, 436, 436, 436, 56, 436, 436, 436, 436, 436, 436, 436, 56, 436, 436, 56, 56, 56, 56, 436, 436 }; static DfaState st20[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 57, 50, 50, 50, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st21[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st22[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 58, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 50, 50, 59, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st23[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st24[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st25[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st26[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st27[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 60, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st28[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 61, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st29[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st30[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st31[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 62, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st32[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st33[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st34[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 56, 56, 56, 56, 56, 56, 56, 436, 436, 436, 436, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 436, 56, 436, 436, 436, 436, 56, 436, 436, 436, 436, 436, 436, 436, 63, 436, 436, 56, 56, 56, 56, 436, 436 }; static DfaState st35[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st36[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st37[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st38[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st39[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st40[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st41[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st42[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 64, 43, 65, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st43[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st44[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 66, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st45[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 67, 68, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st46[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 69, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st47[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 70, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st48[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 71, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st49[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 72, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st50[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st51[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 436, 73, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st52[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st53[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st54[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 74, 43, 43, 44, 43, 43, 43, 436, 436, 436, 436, 45, 43, 43, 43, 43, 46, 43, 47, 43, 43, 43, 43, 48, 43, 49, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st55[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 75, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st56[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 56, 56, 56, 56, 56, 56, 56, 436, 436, 436, 436, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 436, 56, 436, 436, 436, 436, 56, 436, 436, 436, 436, 436, 436, 436, 56, 436, 436, 56, 56, 56, 56, 436, 436 }; static DfaState st57[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 76, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st58[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 50, 50, 77, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st59[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 78, 50, 50, 50, 50, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st60[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st61[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st62[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st63[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 56, 56, 56, 56, 56, 56, 56, 436, 436, 436, 436, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 436, 56, 436, 436, 436, 436, 56, 436, 436, 79, 436, 436, 436, 436, 56, 436, 436, 56, 56, 56, 56, 436, 436 }; static DfaState st64[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 80, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st65[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 81, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st66[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 82, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st67[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 83, 43, 43, 43, 436, 436, 436, 436, 43, 43, 84, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st68[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 85, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st69[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 86, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st70[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 87, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st71[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 88, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st72[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 89, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st73[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 90, 50, 50, 50, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st74[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 65, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st75[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 50, 91, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st76[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 50, 50, 92, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st77[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 93, 50, 50, 50, 50, 50, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st78[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 436, 94, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st79[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 95, 96, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st80[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 97, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st81[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 98, 43, 99, 43, 100, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 101, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st82[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 102, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st83[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 103, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st84[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 104, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st85[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 105, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st86[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 106, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st87[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 107, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 108, 43, 43, 436, 109, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st88[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 110, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st89[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 111, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st90[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 112, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st91[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 113, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st92[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 114, 50, 50, 50, 436, 436 }; static DfaState st93[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 115, 50, 50, 50, 50, 50, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st94[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 116, 50, 50, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st95[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 117, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st96[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 118, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st97[60] = { 436, 119, 120, 121, 122, 122, 122, 122, 122, 122, 123, 123, 123, 123, 124, 124, 124, 122, 122, 122, 122, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 122, 123, 122, 122, 122, 122, 123, 122, 122, 122, 122, 122, 122, 122, 123, 122, 122, 123, 123, 123, 123, 122, 436 }; static DfaState st98[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 125, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st99[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 126, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st100[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 127, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st101[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 128, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st102[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 129, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st103[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st104[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 130, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st105[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 131, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st106[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 132, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st107[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 133, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st108[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 134, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st109[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 135, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st110[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 136, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st111[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 137, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st112[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 138, 50, 50, 50, 50, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st113[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 139, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st114[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 140, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st115[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st116[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st117[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st118[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st119[60] = { 436, 119, 120, 121, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 141, 141, 141, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 436 }; static DfaState st120[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st121[60] = { 436, 436, 142, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st122[60] = { 436, 122, 120, 121, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 436 }; static DfaState st123[60] = { 436, 122, 120, 121, 122, 122, 122, 122, 122, 122, 123, 123, 123, 123, 123, 123, 123, 122, 122, 122, 122, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 122, 123, 122, 122, 122, 122, 123, 122, 122, 122, 122, 122, 122, 122, 123, 122, 122, 123, 123, 123, 123, 122, 436 }; static DfaState st124[60] = { 436, 143, 144, 145, 122, 122, 146, 122, 122, 122, 123, 123, 123, 123, 124, 124, 124, 122, 122, 122, 122, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 122, 123, 122, 122, 122, 122, 123, 122, 122, 122, 122, 122, 122, 122, 123, 122, 122, 123, 123, 123, 123, 122, 436 }; static DfaState st125[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 147, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st126[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 148, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st127[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 149, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st128[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 150, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st129[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 151, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st130[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 152, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st131[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 153, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st132[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 154, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st133[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st134[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 155, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st135[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 156, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st136[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 157, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st137[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st138[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 158, 50, 50, 50, 50, 50, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st139[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st140[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 159, 50, 50, 50, 50, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st141[60] = { 436, 143, 144, 145, 122, 122, 146, 122, 122, 122, 122, 122, 122, 122, 141, 141, 141, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 436 }; static DfaState st142[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st143[60] = { 436, 143, 120, 121, 122, 122, 146, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 436 }; static DfaState st144[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st145[60] = { 436, 436, 160, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st146[60] = { 436, 161, 162, 163, 161, 161, 122, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 436 }; static DfaState st147[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 164, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st148[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 165, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st149[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 166, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st150[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 167, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st151[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 168, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st152[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st153[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st154[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 169, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st155[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 170, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st156[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 171, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st157[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st158[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 172, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st159[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st160[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st161[60] = { 436, 161, 162, 163, 161, 161, 173, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 436 }; static DfaState st162[60] = { 436, 174, 174, 174, 174, 174, 175, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 436 }; static DfaState st163[60] = { 436, 174, 176, 174, 174, 174, 175, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 436 }; static DfaState st164[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 177, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st165[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 178, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st166[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 179, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st167[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 180, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st168[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 181, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st169[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 182, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st170[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st171[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 183, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st172[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 184, 50, 50, 50, 50, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st173[60] = { 436, 185, 144, 145, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 186, 186, 186, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 436 }; static DfaState st174[60] = { 436, 174, 174, 174, 174, 174, 175, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 436 }; static DfaState st175[60] = { 436, 187, 188, 189, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 190, 190, 190, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st176[60] = { 436, 174, 174, 174, 174, 174, 175, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 436 }; static DfaState st177[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 191, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st178[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 192, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st179[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 193, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st180[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st181[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st182[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 194, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st183[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st184[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 436, 436, 436, 436, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 436, 50, 436, 436, 436, 436, 50, 436, 436, 436, 436, 436, 436, 436, 50, 436, 436, 50, 50, 50, 50, 436, 436 }; static DfaState st185[60] = { 436, 185, 144, 145, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 186, 186, 186, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 436 }; static DfaState st186[60] = { 436, 185, 144, 145, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 186, 186, 186, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 436 }; static DfaState st187[60] = { 436, 187, 188, 189, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 190, 190, 190, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st188[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st189[60] = { 436, 436, 195, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st190[60] = { 436, 187, 188, 189, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 190, 190, 190, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st191[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st192[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st193[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st194[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 196, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st195[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st196[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 197, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st197[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 198, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st198[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 199, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st199[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 200, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st200[60] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 436, 436, 436, 436, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 436, 43, 436, 436, 436, 436, 43, 436, 436, 436, 436, 436, 436, 436, 43, 436, 436, 43, 43, 43, 43, 436, 436 }; static DfaState st201[7] = { 202, 203, 204, 205, 206, 207, 436 }; static DfaState st202[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st203[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st204[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st205[7] = { 436, 436, 208, 436, 436, 436, 436 }; static DfaState st206[7] = { 436, 209, 210, 211, 209, 209, 436 }; static DfaState st207[7] = { 436, 436, 436, 436, 436, 207, 436 }; static DfaState st208[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st209[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st210[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st211[7] = { 436, 436, 212, 436, 436, 436, 436 }; static DfaState st212[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st213[7] = { 214, 215, 216, 217, 218, 219, 436 }; static DfaState st214[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st215[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st216[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st217[7] = { 436, 436, 220, 436, 436, 436, 436 }; static DfaState st218[7] = { 436, 221, 222, 223, 221, 221, 436 }; static DfaState st219[7] = { 436, 436, 436, 436, 436, 219, 436 }; static DfaState st220[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st221[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st222[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st223[7] = { 436, 436, 224, 436, 436, 436, 436 }; static DfaState st224[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st225[7] = { 226, 227, 228, 229, 230, 231, 436 }; static DfaState st226[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st227[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st228[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st229[7] = { 436, 436, 232, 436, 436, 436, 436 }; static DfaState st230[7] = { 436, 233, 233, 233, 233, 233, 436 }; static DfaState st231[7] = { 436, 436, 436, 436, 436, 231, 436 }; static DfaState st232[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st233[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st234[7] = { 235, 236, 237, 238, 239, 237, 436 }; static DfaState st235[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st236[7] = { 436, 436, 240, 436, 436, 436, 436 }; static DfaState st237[7] = { 436, 436, 237, 436, 436, 237, 436 }; static DfaState st238[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st239[7] = { 436, 436, 436, 241, 436, 436, 436 }; static DfaState st240[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st241[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st242[7] = { 243, 244, 245, 246, 247, 245, 436 }; static DfaState st243[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st244[7] = { 436, 436, 248, 436, 436, 436, 436 }; static DfaState st245[7] = { 436, 436, 245, 436, 436, 245, 436 }; static DfaState st246[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st247[7] = { 436, 436, 436, 249, 436, 436, 436 }; static DfaState st248[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st249[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st250[5] = { 251, 252, 253, 254, 436 }; static DfaState st251[5] = { 436, 436, 436, 436, 436 }; static DfaState st252[5] = { 436, 436, 436, 436, 436 }; static DfaState st253[5] = { 436, 255, 436, 436, 436 }; static DfaState st254[5] = { 436, 436, 436, 254, 436 }; static DfaState st255[5] = { 436, 436, 436, 436, 436 }; static DfaState st256[5] = { 257, 258, 259, 260, 436 }; static DfaState st257[5] = { 436, 436, 436, 436, 436 }; static DfaState st258[5] = { 436, 436, 436, 436, 436 }; static DfaState st259[5] = { 436, 261, 436, 436, 436 }; static DfaState st260[5] = { 436, 436, 436, 260, 436 }; static DfaState st261[5] = { 436, 436, 436, 436, 436 }; static DfaState st262[5] = { 263, 264, 265, 266, 436 }; static DfaState st263[5] = { 436, 436, 436, 436, 436 }; static DfaState st264[5] = { 436, 436, 436, 436, 436 }; static DfaState st265[5] = { 436, 267, 436, 436, 436 }; static DfaState st266[5] = { 436, 436, 436, 266, 436 }; static DfaState st267[5] = { 436, 436, 436, 436, 436 }; static DfaState st268[7] = { 269, 270, 271, 272, 273, 271, 436 }; static DfaState st269[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st270[7] = { 436, 436, 274, 436, 436, 436, 436 }; static DfaState st271[7] = { 436, 436, 271, 436, 436, 271, 436 }; static DfaState st272[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st273[7] = { 436, 436, 436, 275, 436, 436, 436 }; static DfaState st274[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st275[7] = { 436, 436, 436, 436, 436, 436, 436 }; static DfaState st276[36] = { 277, 278, 279, 280, 281, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 282, 279, 279, 283, 284, 285, 286, 287, 279, 279, 279, 279, 288, 289, 290, 291, 292, 293, 279, 279, 436 }; static DfaState st277[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st278[36] = { 436, 294, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st279[36] = { 436, 436, 279, 436, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 436, 279, 279, 436, 436, 436, 436, 436, 279, 279, 279, 279, 436, 436, 436, 436, 436, 279, 279, 279, 436 }; static DfaState st280[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st281[36] = { 436, 436, 279, 436, 279, 295, 279, 279, 279, 279, 279, 279, 279, 279, 279, 436, 279, 279, 436, 436, 436, 436, 436, 279, 279, 279, 279, 436, 436, 436, 436, 436, 279, 279, 279, 436 }; static DfaState st282[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st283[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st284[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st285[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 296, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st286[36] = { 436, 436, 436, 436, 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, 436, 436, 436, 436, 436, 436, 298, 299, 300, 300, 436, 297, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st287[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st288[36] = { 436, 436, 436, 436, 301, 301, 301, 301, 301, 301, 301, 301, 301, 301, 302, 303, 436, 436, 436, 436, 436, 436, 304, 305, 306, 436, 301, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st289[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st290[36] = { 436, 307, 308, 309, 308, 308, 308, 308, 308, 308, 308, 308, 308, 308, 308, 308, 308, 308, 310, 311, 312, 313, 308, 308, 308, 308, 308, 314, 308, 308, 308, 308, 308, 308, 308, 436 }; static DfaState st291[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st292[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 315, 316, 436, 436, 436 }; static DfaState st293[36] = { 436, 436, 279, 436, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 436, 279, 279, 436, 436, 436, 436, 436, 279, 279, 279, 279, 436, 436, 436, 436, 317, 279, 279, 279, 436 }; static DfaState st294[36] = { 436, 436, 318, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st295[36] = { 436, 436, 279, 436, 279, 279, 319, 279, 279, 279, 279, 279, 279, 279, 279, 436, 279, 279, 436, 436, 436, 436, 436, 279, 279, 279, 279, 436, 436, 436, 436, 436, 279, 279, 279, 436 }; static DfaState st296[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st297[36] = { 436, 436, 436, 436, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 436, 436, 436, 436, 436, 436, 436, 436, 320, 320, 436, 320, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st298[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st299[36] = { 436, 436, 436, 321, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st300[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 300, 300, 322, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st301[36] = { 436, 436, 436, 436, 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, 436, 436, 436, 436, 436, 436, 436, 436, 323, 323, 436, 323, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st302[36] = { 436, 436, 436, 436, 323, 323, 323, 323, 323, 323, 323, 323, 323, 324, 323, 436, 436, 436, 436, 436, 436, 436, 436, 323, 323, 436, 323, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st303[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 325, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st304[36] = { 436, 436, 436, 326, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st305[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 306, 306, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st306[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 306, 306, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st307[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st308[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st309[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st310[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st311[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st312[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 327, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st313[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st314[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st315[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st316[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st317[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st318[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st319[36] = { 436, 436, 279, 436, 279, 279, 279, 328, 279, 279, 279, 279, 279, 279, 279, 436, 279, 279, 436, 436, 436, 436, 436, 279, 279, 279, 279, 436, 436, 436, 436, 436, 279, 279, 279, 436 }; static DfaState st320[36] = { 436, 436, 436, 436, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 436, 436, 436, 436, 436, 436, 436, 436, 320, 320, 436, 320, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st321[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st322[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 329, 329, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st323[36] = { 436, 436, 436, 436, 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, 436, 436, 436, 436, 436, 436, 436, 436, 323, 323, 436, 323, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st324[36] = { 436, 436, 436, 436, 323, 323, 330, 323, 323, 323, 323, 323, 323, 323, 323, 436, 436, 436, 436, 436, 436, 436, 436, 323, 323, 436, 323, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st325[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st326[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st327[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st328[36] = { 436, 436, 279, 436, 279, 279, 279, 279, 331, 279, 279, 279, 279, 279, 279, 436, 279, 279, 436, 436, 436, 436, 436, 279, 279, 279, 279, 436, 436, 436, 436, 436, 279, 279, 279, 436 }; static DfaState st329[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 329, 329, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st330[36] = { 436, 436, 436, 436, 323, 323, 323, 323, 323, 323, 332, 323, 323, 323, 323, 436, 436, 436, 436, 436, 436, 436, 436, 323, 323, 436, 323, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st331[36] = { 436, 436, 279, 436, 279, 279, 279, 279, 279, 333, 279, 279, 279, 279, 279, 436, 279, 279, 436, 436, 436, 436, 436, 279, 279, 279, 279, 436, 436, 436, 436, 436, 279, 279, 279, 436 }; static DfaState st332[36] = { 436, 334, 334, 334, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 334, 336, 334, 334, 337, 338, 334, 334, 339, 339, 334, 335, 334, 334, 334, 334, 334, 334, 334, 334, 436 }; static DfaState st333[36] = { 436, 436, 279, 436, 279, 279, 279, 279, 279, 279, 340, 279, 279, 279, 279, 436, 279, 279, 436, 436, 436, 436, 436, 279, 279, 279, 279, 436, 436, 436, 436, 436, 279, 279, 279, 436 }; static DfaState st334[36] = { 436, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 337, 338, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 436 }; static DfaState st335[36] = { 436, 334, 334, 334, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 334, 334, 334, 334, 337, 338, 334, 334, 335, 335, 334, 335, 334, 334, 334, 334, 334, 334, 334, 334, 436 }; static DfaState st336[36] = { 436, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 336, 334, 334, 337, 338, 334, 334, 341, 341, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 436 }; static DfaState st337[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st338[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 342, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st339[36] = { 436, 334, 334, 334, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 334, 343, 334, 334, 344, 345, 334, 334, 339, 339, 334, 335, 334, 346, 334, 334, 334, 334, 334, 334, 436 }; static DfaState st340[36] = { 436, 436, 279, 436, 279, 279, 279, 279, 279, 279, 279, 347, 279, 279, 279, 436, 279, 279, 436, 436, 436, 436, 436, 279, 279, 279, 279, 436, 436, 436, 436, 436, 279, 279, 279, 436 }; static DfaState st341[36] = { 436, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 343, 334, 334, 344, 345, 334, 334, 341, 341, 334, 334, 334, 346, 334, 334, 334, 334, 334, 334, 436 }; static DfaState st342[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st343[36] = { 436, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 343, 334, 334, 337, 338, 334, 334, 334, 334, 334, 334, 334, 346, 334, 334, 334, 334, 334, 334, 436 }; static DfaState st344[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st345[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 348, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st346[36] = { 436, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 350, 351, 349, 349, 349, 349, 349, 349, 349, 334, 349, 349, 349, 349, 349, 349, 436 }; static DfaState st347[36] = { 436, 436, 279, 436, 279, 279, 352, 279, 279, 279, 279, 279, 279, 279, 279, 436, 279, 279, 436, 436, 436, 436, 436, 279, 279, 279, 279, 436, 436, 436, 436, 436, 279, 279, 279, 436 }; static DfaState st348[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st349[36] = { 436, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 349, 350, 351, 349, 349, 349, 349, 349, 349, 349, 353, 349, 349, 349, 349, 349, 349, 436 }; static DfaState st350[36] = { 436, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 355, 354, 354, 354, 354, 354, 354, 436 }; static DfaState st351[36] = { 436, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 356, 354, 354, 354, 354, 354, 354, 354, 354, 355, 354, 354, 354, 354, 354, 354, 436 }; static DfaState st352[36] = { 436, 436, 279, 436, 279, 279, 279, 279, 279, 279, 279, 279, 357, 279, 279, 436, 279, 279, 436, 436, 436, 436, 436, 279, 279, 279, 279, 436, 436, 436, 436, 436, 279, 279, 279, 436 }; static DfaState st353[36] = { 436, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 358, 334, 334, 344, 345, 334, 334, 359, 359, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 436 }; static DfaState st354[36] = { 436, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 355, 354, 354, 354, 354, 354, 354, 436 }; static DfaState st355[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 360, 436, 436, 361, 362, 436, 436, 363, 363, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st356[36] = { 436, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 354, 355, 354, 354, 354, 354, 354, 354, 436 }; static DfaState st357[36] = { 436, 436, 279, 436, 279, 279, 279, 279, 279, 279, 279, 279, 279, 364, 279, 436, 279, 279, 436, 436, 436, 436, 436, 279, 279, 279, 279, 436, 436, 436, 436, 436, 279, 279, 279, 436 }; static DfaState st358[36] = { 436, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 358, 334, 334, 344, 345, 334, 334, 359, 359, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 436 }; static DfaState st359[36] = { 436, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 358, 334, 334, 344, 345, 334, 334, 359, 359, 334, 334, 334, 334, 334, 334, 334, 334, 334, 334, 436 }; static DfaState st360[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 360, 436, 436, 361, 362, 436, 436, 363, 363, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st361[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st362[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 365, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st363[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 360, 436, 436, 361, 362, 436, 436, 363, 363, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st364[36] = { 436, 436, 279, 436, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 366, 436, 279, 279, 436, 436, 436, 436, 436, 279, 279, 279, 279, 436, 436, 436, 436, 436, 279, 279, 279, 436 }; static DfaState st365[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st366[36] = { 436, 436, 279, 436, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 367, 279, 279, 436, 436, 436, 436, 436, 279, 279, 279, 279, 436, 436, 436, 436, 436, 279, 279, 279, 436 }; static DfaState st367[36] = { 436, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 369, 370, 436, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 436 }; static DfaState st368[36] = { 436, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 371, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 436 }; static DfaState st369[36] = { 436, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 369, 370, 371, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 436 }; static DfaState st370[36] = { 436, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 373, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 368, 436 }; static DfaState st371[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st372[36] = { 436, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 373, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 374, 436 }; static DfaState st373[36] = { 436, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 376, 436 }; static DfaState st374[36] = { 436, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 377, 368, 378, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 436 }; static DfaState st375[36] = { 436, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 375, 376, 436 }; static DfaState st376[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 379, 436, 380, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st377[36] = { 436, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 377, 368, 378, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 436 }; static DfaState st378[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st379[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 379, 436, 380, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st380[36] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st381[28] = { 382, 383, 384, 385, 386, 436, 387, 388, 388, 388, 389, 388, 388, 388, 388, 388, 388, 388, 388, 388, 390, 391, 392, 393, 394, 395, 388, 436 }; static DfaState st382[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st383[28] = { 436, 383, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st384[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st385[28] = { 436, 436, 396, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st386[28] = { 436, 436, 436, 436, 397, 398, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st387[28] = { 436, 436, 436, 436, 436, 436, 436, 399, 436, 400, 401, 436, 436, 436, 402, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st388[28] = { 436, 436, 436, 436, 436, 436, 436, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 436, 436, 436, 436, 436, 403, 403, 436 }; static DfaState st389[28] = { 436, 436, 436, 436, 436, 436, 436, 403, 403, 403, 403, 404, 403, 403, 403, 403, 403, 403, 403, 403, 436, 436, 436, 436, 436, 403, 403, 436 }; static DfaState st390[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st391[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st392[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st393[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st394[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st395[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 395, 436, 436 }; static DfaState st396[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st397[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st398[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st399[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 405, 436, 436, 436, 436, 436, 436, 406, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st400[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 407, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st401[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 408, 409, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st402[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 410, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st403[28] = { 436, 436, 436, 436, 436, 436, 436, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 436, 436, 436, 436, 436, 403, 403, 436 }; static DfaState st404[28] = { 436, 436, 436, 436, 436, 436, 436, 403, 403, 403, 403, 403, 403, 403, 411, 403, 403, 403, 403, 403, 436, 436, 436, 436, 436, 403, 403, 436 }; static DfaState st405[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 412, 436, 413, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st406[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 414, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st407[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 415, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st408[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 416, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st409[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 417, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st410[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 418, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st411[28] = { 436, 436, 436, 436, 436, 436, 436, 403, 403, 403, 403, 403, 403, 403, 403, 419, 403, 403, 403, 403, 436, 436, 436, 436, 436, 403, 403, 436 }; static DfaState st412[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 420, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st413[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 421, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st414[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 422, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st415[28] = { 436, 436, 436, 436, 436, 436, 436, 423, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st416[28] = { 436, 436, 436, 436, 436, 436, 436, 424, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st417[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 425, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st418[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 426, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st419[28] = { 436, 436, 436, 436, 436, 436, 436, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, 436, 436, 436, 436, 436, 403, 403, 436 }; static DfaState st420[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 427, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st421[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 428, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st422[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 429, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st423[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 430, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st424[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 431, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st425[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st426[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 432, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st427[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st428[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 433, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st429[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 434, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st430[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 435, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st431[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st432[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st433[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st434[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; static DfaState st435[28] = { 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 }; DfaState *dfa[436] = { st0, st1, st2, st3, st4, st5, st6, st7, st8, st9, st10, st11, st12, st13, st14, st15, st16, st17, st18, st19, st20, st21, st22, st23, st24, st25, st26, st27, st28, st29, st30, st31, st32, st33, st34, st35, st36, st37, st38, st39, st40, st41, st42, st43, st44, st45, st46, st47, st48, st49, st50, st51, st52, st53, st54, st55, st56, st57, st58, st59, st60, st61, st62, st63, st64, st65, st66, st67, st68, st69, st70, st71, st72, st73, st74, st75, st76, st77, st78, st79, st80, st81, st82, st83, st84, st85, st86, st87, st88, st89, st90, st91, st92, st93, st94, st95, st96, st97, st98, st99, st100, st101, st102, st103, st104, st105, st106, st107, st108, st109, st110, st111, st112, st113, st114, st115, st116, st117, st118, st119, st120, st121, st122, st123, st124, st125, st126, st127, st128, st129, st130, st131, st132, st133, st134, st135, st136, st137, st138, st139, st140, st141, st142, st143, st144, st145, st146, st147, st148, st149, st150, st151, st152, st153, st154, st155, st156, st157, st158, st159, st160, st161, st162, st163, st164, st165, st166, st167, st168, st169, st170, st171, st172, st173, st174, st175, st176, st177, st178, st179, st180, st181, st182, st183, st184, st185, st186, st187, st188, st189, st190, st191, st192, st193, st194, st195, st196, st197, st198, st199, st200, st201, st202, st203, st204, st205, st206, st207, st208, st209, st210, st211, st212, st213, st214, st215, st216, st217, st218, st219, st220, st221, st222, st223, st224, st225, st226, st227, st228, st229, st230, st231, st232, st233, st234, st235, st236, st237, st238, st239, st240, st241, st242, st243, st244, st245, st246, st247, st248, st249, st250, st251, st252, st253, st254, st255, st256, st257, st258, st259, st260, st261, st262, st263, st264, st265, st266, st267, st268, st269, st270, st271, st272, st273, st274, st275, st276, st277, st278, st279, st280, st281, st282, st283, st284, st285, st286, st287, st288, st289, st290, st291, st292, st293, st294, st295, st296, st297, st298, st299, st300, st301, st302, st303, st304, st305, st306, st307, st308, st309, st310, st311, st312, st313, st314, st315, st316, st317, st318, st319, st320, st321, st322, st323, st324, st325, st326, st327, st328, st329, st330, st331, st332, st333, st334, st335, st336, st337, st338, st339, st340, st341, st342, st343, st344, st345, st346, st347, st348, st349, st350, st351, st352, st353, st354, st355, st356, st357, st358, st359, st360, st361, st362, st363, st364, st365, st366, st367, st368, st369, st370, st371, st372, st373, st374, st375, st376, st377, st378, st379, st380, st381, st382, st383, st384, st385, st386, st387, st388, st389, st390, st391, st392, st393, st394, st395, st396, st397, st398, st399, st400, st401, st402, st403, st404, st405, st406, st407, st408, st409, st410, st411, st412, st413, st414, st415, st416, st417, st418, st419, st420, st421, st422, st423, st424, st425, st426, st427, st428, st429, st430, st431, st432, st433, st434, st435 }; DfaState accepts[437] = { 0, 1, 2, 3, 3, 4, 25, 6, 0, 50, 59, 57, 57, 43, 26, 13, 14, 0, 57, 58, 57, 21, 57, 23, 24, 27, 28, 44, 0, 35, 36, 42, 45, 46, 58, 51, 52, 3, 5, 9, 7, 8, 59, 59, 59, 59, 59, 59, 59, 59, 57, 57, 12, 40, 59, 57, 58, 57, 57, 57, 33, 34, 53, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 57, 59, 57, 57, 57, 57, 0, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 57, 57, 57, 57, 57, 0, 0, 59, 59, 59, 59, 59, 59, 32, 59, 59, 59, 59, 59, 59, 59, 59, 57, 57, 57, 22, 56, 48, 49, 0, 11, 11, 0, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 41, 59, 59, 59, 18, 57, 47, 57, 0, 11, 0, 10, 10, 0, 59, 59, 59, 59, 59, 15, 19, 59, 59, 59, 17, 57, 55, 10, 0, 11, 11, 59, 59, 59, 59, 59, 59, 20, 59, 57, 0, 0, 0, 11, 59, 59, 59, 37, 38, 59, 39, 54, 0, 0, 0, 10, 10, 0, 31, 29, 30, 59, 10, 59, 59, 59, 59, 16, 0, 60, 61, 62, 62, 0, 65, 62, 64, 63, 63, 63, 0, 66, 67, 68, 68, 0, 71, 68, 70, 69, 69, 69, 0, 72, 73, 74, 74, 0, 76, 74, 75, 0, 77, 79, 81, 80, 80, 78, 80, 0, 82, 84, 86, 85, 85, 83, 85, 0, 87, 88, 88, 89, 88, 0, 90, 91, 91, 92, 91, 0, 93, 94, 94, 95, 94, 0, 96, 98, 100, 99, 99, 97, 99, 0, 101, 108, 143, 104, 143, 129, 127, 107, 107, 109, 128, 126, 134, 0, 133, 139, 143, 102, 143, 107, 116, 110, 112, 113, 123, 123, 125, 124, 117, 120, 132, 138, 130, 131, 137, 137, 135, 136, 142, 140, 141, 103, 143, 116, 111, 114, 123, 123, 119, 118, 137, 143, 115, 123, 143, 123, 143, 0, 123, 0, 122, 122, 123, 143, 0, 122, 0, 121, 121, 0, 143, 121, 0, 122, 122, 143, 0, 0, 0, 122, 143, 0, 0, 0, 121, 121, 0, 143, 121, 143, 0, 0, 0, 0, 106, 0, 106, 0, 0, 0, 0, 105, 0, 105, 0, 144, 145, 146, 146, 0, 0, 164, 164, 158, 159, 160, 161, 162, 163, 146, 147, 148, 0, 0, 0, 0, 164, 164, 150, 0, 0, 0, 0, 0, 164, 0, 0, 0, 0, 0, 0, 0, 157, 0, 0, 0, 0, 0, 152, 0, 149, 0, 0, 0, 153, 154, 151, 155, 156, 0 }; void (*actions[165])() = { zzerraction, act1, act2, act3, act4, act5, act6, act7, act8, act9, act10, act11, act12, act13, act14, act15, act16, act17, act18, act19, act20, act21, act22, act23, act24, act25, act26, act27, act28, act29, act30, act31, act32, act33, act34, act35, act36, act37, act38, act39, act40, act41, act42, act43, act44, act45, act46, act47, act48, act49, act50, act51, act52, act53, act54, act55, act56, act57, act58, act59, act60, act61, act62, act63, act64, act65, act66, act67, act68, act69, act70, act71, act72, act73, act74, act75, act76, act77, act78, act79, act80, act81, act82, act83, act84, act85, act86, act87, act88, act89, act90, act91, act92, act93, act94, act95, act96, act97, act98, act99, act100, act101, act102, act103, act104, act105, act106, act107, act108, act109, act110, act111, act112, act113, act114, act115, act116, act117, act118, act119, act120, act121, act122, act123, act124, act125, act126, act127, act128, act129, act130, act131, act132, act133, act134, act135, act136, act137, act138, act139, act140, act141, act142, act143, act144, act145, act146, act147, act148, act149, act150, act151, act152, act153, act154, act155, act156, act157, act158, act159, act160, act161, act162, act163, act164 }; static DfaState dfa_base[] = { 0, 201, 213, 225, 234, 242, 250, 256, 262, 268, 276, 381 }; static unsigned char *b_class_no[] = { shift0, shift1, shift2, shift3, shift4, shift5, shift6, shift7, shift8, shift9, shift10, shift11 }; #define ZZSHIFT(c) (b_class_no[zzauto][1+c]) #define MAX_MODE 12 #include "dlgauto.h" cdrdao-cdrdao-f00afb2/pccts/antlr/set.c000066400000000000000000000365101511453746600200760ustar00rootroot00000000000000/* set.c The following is a general-purpose set library originally developed by Hank Dietz and enhanced by Terence Parr to allow dynamic sets. Sets are now structs containing the #words in the set and a pointer to the actual set words. Generally, sets need not be explicitly allocated. They are created/extended/shrunk when appropriate (e.g. in set_of()). HOWEVER, sets need to be destroyed (free()ed) when they go out of scope or are otherwise no longer needed. A routine is provided to free a set. Sets can be explicitly created with set_new(s, max_elem). Sets can be declared to have minimum size to reduce realloc traffic. Default minimum size = 1. Sets can be explicitly initialized to have no elements (set.n == 0) by using the 'empty' initializer: Examples: set a = empty; -- set_deg(a) == 0 return( empty ); Example set creation and destruction: set set_of2(e,g) unsigned e,g; { set a,b,c; b = set_of(e); -- Creates space for b and sticks in e set_new(c, g); -- set_new(); set_orel() ==> set_of() set_orel(g, &c); a = set_or(b, c); . . . set_free(b); set_free(c); return( a ); } 1987 by Hank Dietz Modified by: Terence Parr Purdue University October 1989 Made it smell less bad to C++ 7/31/93 -- TJP */ #include #include "pcctscfg.h" #ifdef __STDC__ #include #else #include #endif #include #include "set.h" #define MIN(i,j) ( (i) > (j) ? (j) : (i)) #define MAX(i,j) ( (i) < (j) ? (j) : (i)) /* elems can be a maximum of 32 bits */ static unsigned bitmask[] = { 0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, 0x00000020, 0x00000040, 0x00000080, 0x00000100, 0x00000200, 0x00000400, 0x00000800, 0x00001000, 0x00002000, 0x00004000, 0x00008000, #if !defined(PC) || defined(PC32) 0x00010000, 0x00020000, 0x00040000, 0x00080000, 0x00100000, 0x00200000, 0x00400000, 0x00800000, 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000 #endif }; set empty = set_init; static unsigned min=1; #define StrSize 200 #ifdef MEMCHK #define CHK(a) \ if ( a.setword != NULL ) \ if ( !valid(a.setword) ) \ {fprintf(stderr, "%s(%d): invalid set\n",__FILE__,__LINE__); exit(-1);} #else #define CHK(a) #endif /* * Set the minimum size (in words) of a set to reduce realloc calls */ void #ifdef __USE_PROTOS set_size( unsigned n ) #else set_size( n ) unsigned n; #endif { min = n; } unsigned int #ifdef __USE_PROTOS set_deg( set a ) #else set_deg( a ) set a; #endif { /* Fast compute degree of a set... the number of elements present in the set. Assumes that all word bits are used in the set and that SETSIZE(a) is a multiple of WORDSIZE. */ register unsigned *p = &(a.setword[0]); register unsigned *endp = NULL; /* MR27 Avoid false memory check report */ register unsigned degree = 0; CHK(a); if ( a.n == 0 ) return(0); endp = &(a.setword[a.n]); while ( p < endp ) { register unsigned t = *p; register unsigned *b = &(bitmask[0]); do { if (t & *b) ++degree; } while (++b < &(bitmask[WORDSIZE])); p++; } return(degree); } set #ifdef __USE_PROTOS set_or( set b, set c ) #else set_or( b, c ) set b; set c; #endif { /* Fast set union operation */ /* resultant set size is max(b, c); */ set *big; set t; unsigned int m,n; register unsigned *r, *p, *q, *endp; CHK(b); CHK(c); t = empty; if (b.n > c.n) {big= &b; m=b.n; n=c.n;} else {big= &c; m=c.n; n=b.n;} set_ext(&t, m); r = t.setword; /* Or b,c until max of smaller set */ q = c.setword; p = b.setword; endp = &(b.setword[n]); while ( p < endp ) *r++ = *p++ | *q++; /* Copy rest of bigger set into result */ p = &(big->setword[n]); endp = &(big->setword[m]); while ( p < endp ) *r++ = *p++; return(t); } set #ifdef __USE_PROTOS set_and( set b, set c ) #else set_and( b, c ) set b; set c; #endif { /* Fast set intersection operation */ /* resultant set size is min(b, c); */ set t; unsigned int n; register unsigned *r, *p, *q, *endp; CHK(b); CHK(c); t = empty; n = (b.n > c.n) ? c.n : b.n; if ( n == 0 ) return t; /* TJP 4-27-92 fixed for empty set */ set_ext(&t, n); r = t.setword; /* & b,c until max of smaller set */ q = c.setword; p = b.setword; endp = &(b.setword[n]); while ( p < endp ) *r++ = *p++ & *q++; return(t); } set #ifdef __USE_PROTOS set_dif( set b, set c ) #else set_dif( b, c ) set b; set c; #endif { /* Fast set difference operation b - c */ /* resultant set size is size(b) */ set t; unsigned int n; register unsigned *r, *p, *q, *endp; CHK(b); CHK(c); t = empty; n = (b.n <= c.n) ? b.n : c.n ; if ( b.n == 0 ) return t; /* TJP 4-27-92 fixed for empty set */ /* WEC 12-1-92 fixed for c.n = 0 */ set_ext(&t, b.n); r = t.setword; /* Dif b,c until smaller set size */ q = c.setword; p = b.setword; endp = &(b.setword[n]); while ( p < endp ) *r++ = *p++ & (~ *q++); /* Copy rest of b into result if size(b) > c */ if ( b.n > n ) { p = &(b.setword[n]); endp = &(b.setword[b.n]); while ( p < endp ) *r++ = *p++; } return(t); } set #ifdef __USE_PROTOS set_of( unsigned b ) #else set_of( b ) unsigned b; #endif { /* Fast singleton set constructor operation */ static set a; if ( b == nil ) return( empty ); set_new(a, (long unsigned int) b); a.setword[DIVWORD(b)] = bitmask[MODWORD(b)]; return(a); } /* * Extend (or shrink) the set passed in to have n words. * * if n is smaller than the minimum, boost n to have the minimum. * if the new set size is the same as the old one, do nothing. * * TJP 4-27-92 Fixed so won't try to alloc 0 bytes */ void #ifdef __USE_PROTOS set_ext( set *a, unsigned int n ) #else set_ext( a, n ) set *a; unsigned int n; #endif { register unsigned *p; register unsigned *endp; unsigned int size; CHK((*a)); if ( a->n == 0 ) { if ( n == 0 ) return; if (a->setword != NULL) { free (a->setword); /* MR20 */ } a->setword = (unsigned *) calloc(n, BytesPerWord); if ( a->setword == NULL ) { fprintf(stderr, "set_ext(%d words): cannot allocate set\n", n); exit(-1); } a->n = n; return; } if ( n < min ) n = min; if ( a->n == n || n == 0 ) return; size = a->n; a->n = n; a->setword = (unsigned *) realloc( (char *)a->setword, (n*BytesPerWord) ); if ( a->setword == NULL ) { fprintf(stderr, "set_ext(%d words): cannot allocate set\n", n); exit(-1); } p = &(a->setword[size]); /* clear from old size to new size */ endp = &(a->setword[a->n]); do { *p++ = 0; } while ( p < endp ); } set #ifdef __USE_PROTOS set_not( set a ) #else set_not( a ) set a; #endif { /* Fast not of set a (assumes all bits used) */ /* size of resultant set is size(a) */ /* ~empty = empty cause we don't know how bit to make set */ set t; register unsigned *r; register unsigned *p = a.setword; register unsigned *endp = &(a.setword[a.n]); CHK(a); t = empty; if ( a.n == 0 ) return( empty ); set_ext(&t, a.n); r = t.setword; do { *r++ = (~ *p++); } while ( p < endp ); return(t); } int #ifdef __USE_PROTOS set_equ( set a, set b ) #else set_equ( a, b ) set a; set b; #endif { /* 8-Nov-97 Make it work with sets of different sizes */ /* Easy to understand, too. Probably faster. */ /* Check for a equal to b */ unsigned int count; /* MR11 */ unsigned int i; /* MR11 */ CHK(a); CHK(b); count=MIN(a.n,b.n); if (count == 0) return 1; for (i=0; i < count; i++) { if (a.setword[i] != b.setword[i]) return 0; }; if (a.n < b.n) { for (i=count; i < b.n; i++) { if (b.setword[i] != 0) return 0; } return 1; } else if (a.n > b.n) { for (i=count; i < a.n; i++) { if (a.setword[i] != 0) return 0; } return 1; } else { return 1; }; } int #ifdef __USE_PROTOS set_sub( set a, set b ) #else set_sub( a, b ) set a; set b; #endif { /* 8-Nov-97 Make it work with sets of different sizes */ /* Easy to understand, too. Probably faster. */ /* Check for a is a PROPER subset of b */ unsigned int count; unsigned int i; CHK(a); CHK(b); if (a.n == 0) return 1; count=MIN(a.n,b.n); for (i=0; i < count; i++) { if (a.setword[i] & ~b.setword[i]) return 0; }; if (a.n <= b.n) { return 1; } else { for (i=count; i a.n ) return(0); /* Otherwise, we have to check */ return( a.setword[DIVWORD(b)] & bitmask[MODWORD(b)] ); } int #ifdef __USE_PROTOS set_nil( set a ) #else set_nil( a ) set a; #endif { /* Fast check for nil set */ register unsigned *p = a.setword; register unsigned *endp; CHK(a); if ( a.n == 0 ) return(1); endp = &(a.setword[a.n]); /* The set is not empty if any word used to store the set is non-zero. This means one must be a bit careful about doing things like negation. */ do { if (*p) return(0); } while (++p < endp); return(1); } char * #ifdef __USE_PROTOS set_str( set a ) #else set_str( a ) set a; #endif { /* Fast convert set a into ASCII char string... assumes that all word bits are used in the set and that SETSIZE is a multiple of WORDSIZE. Trailing 0 bits are removed from the string. if no bits are on or set is empty, "" is returned. */ register unsigned *p = a.setword; register unsigned *endp = &(a.setword[a.n]); static char str_tmp[StrSize+1]; register char *q = &(str_tmp[0]); CHK(a); if ( a.n==0 ) {*q=0; return( &(str_tmp[0]) );} do { register unsigned t = *p; register unsigned *b = &(bitmask[0]); do { *(q++) = (char) ((t & *b) ? '1' : '0'); } while (++b < &(bitmask[WORDSIZE])); } while (++p < endp); /* Trim trailing 0s & NULL terminate the string */ while ((q > &(str_tmp[0])) && (*(q-1) != '1')) --q; *q = 0; return(&(str_tmp[0])); } set #ifdef __USE_PROTOS set_val( register char *s ) #else set_val( s ) register char *s; #endif { /* Fast convert set ASCII char string into a set. If the string ends early, the remaining set bits are all made zero. The resulting set size is just big enough to hold all elements. */ static set a; register unsigned *p, *endp; set_new(a, strlen(s)); p = a.setword; endp = &(a.setword[a.n]); do { register unsigned *b = &(bitmask[0]); /* Start with a word with no bits on */ *p = 0; do { if (*s) { if (*s == '1') { /* Turn-on this bit */ *p |= *b; } ++s; } } while (++b < &(bitmask[WORDSIZE])); } while (++p < endp); return(a); } /* * Or element e into set a. a can be empty. */ void #ifdef __USE_PROTOS set_orel( unsigned e, set *a ) #else set_orel( e, a ) unsigned e; set *a; #endif { CHK((*a)); if ( e == nil ) return; if ( NumWords(e) > a->n ) set_ext(a, NumWords(e)); a->setword[DIVWORD(e)] |= bitmask[MODWORD(e)]; } /* * Or set b into set a. a can be empty. does nothing if b empty. */ void #ifdef __USE_PROTOS set_orin( set *a, set b ) #else set_orin( a, b ) set *a; set b; #endif { /* Fast set union operation */ /* size(a) is max(a, b); */ unsigned int m; register unsigned *p, *q = b.setword, *endq; /* MR20 */ CHK((*a)); CHK(b); if ( b.n == 0 ) return; endq = &(b.setword[b.n]); /* MR20 */ m = (a->n > b.n) ? a->n : b.n; set_ext(a, m); p = a->setword; do { *p++ |= *q++; } while ( q < endq ); } /* * And set b into set a. a can be empty. does nothing if b empty. */ void #ifdef __USE_PROTOS set_andin( set *a, set b ) #else set_andin( a, b ) set *a; set b; #endif { /* Fast set intersection operation */ /* size(a) is max(a, b); */ unsigned int m; register unsigned *p, *q = b.setword, *endq = &(b.setword[b.n]); CHK((*a)); CHK(b); if ( b.n == 0 ) return; m = (a->n > b.n) ? a->n : b.n; set_ext(a, m); p = a->setword; do { *p++ &= *q++; } while ( q < endq ); } void #ifdef __USE_PROTOS set_rm( unsigned e, set a ) #else set_rm( e, a ) unsigned e; set a; #endif { /* Does not effect size of set */ CHK(a); if ( (e == nil) || (NumWords(e) > a.n) ) return; a.setword[DIVWORD(e)] ^= (a.setword[DIVWORD(e)]&bitmask[MODWORD(e)]); } void #ifdef __USE_PROTOS set_clr( set a ) #else set_clr( a ) set a; #endif { /* Does not effect size of set */ register unsigned *p = a.setword; register unsigned *endp; CHK(a); if ( a.n == 0 ) return; endp = &(a.setword[a.n]); do { *p++ = 0; } while ( p < endp ); } set #ifdef __USE_PROTOS set_dup( set a ) #else set_dup( a ) set a; #endif { set b; register unsigned *p, *q = a.setword, *endq; /* MR20 */ CHK(a); b = empty; if ( a.n == 0 ) return( empty ); endq = &(a.setword[a.n]); /* MR20 */ set_ext(&b, a.n); p = b.setword; do { *p++ = *q++; } while ( q < endq ); return(b); } /* * Return a nil terminated list of unsigned ints that represents all * "on" bits in the bit set. * * e.g. {011011} --> {1, 2, 4, 5, nil} * * _set_pdq and set_pdq are useful when an operation is required on each element * of a set. Normally, the sequence is: * * while ( set_deg(a) > 0 ) { * e = set_int(a); * set_rm(e, a); * ...process e... * } * Now, * * t = e = set_pdq(a); * while ( *e != nil ) { * ...process *e... * e++; * } * free( t ); * * We have saved many set calls and have not destroyed set a. */ void #ifdef __USE_PROTOS _set_pdq( set a, register unsigned *q ) #else _set_pdq( a, q ) set a; register unsigned *q; #endif { register unsigned *p = a.setword, *endp = &(a.setword[a.n]); register unsigned e=0; CHK(a); /* are there any space (possibility of elements)? */ if ( a.n == 0 ) return; do { register unsigned t = *p; register unsigned *b = &(bitmask[0]); do { if ( t & *b ) *q++ = e; ++e; } while (++b < &(bitmask[WORDSIZE])); } while (++p < endp); *q = nil; } /* * Same as _set_pdq except allocate memory. set_pdq is the natural function * to use. */ unsigned * #ifdef __USE_PROTOS set_pdq( set a ) #else set_pdq( a ) set a; #endif { unsigned *q; int max_deg; CHK(a); max_deg = WORDSIZE*a.n; /* assume a.n!=0 & no elements is rare, but still ok */ if ( a.n == 0 ) return(NULL); q = (unsigned *) malloc((max_deg+1)*BytesPerWord); if ( q == NULL ) return( NULL ); _set_pdq(a, q); return( q ); } /* a function that produces a hash number for the set */ unsigned int #ifdef __USE_PROTOS set_hash( set a, register unsigned int mod ) #else set_hash( a, mod ) set a; register unsigned int mod; #endif { /* Fast hash of set a (assumes all bits used) */ register unsigned *p = &(a.setword[0]); register unsigned *endp = &(a.setword[a.n]); register unsigned i = 0; CHK(a); while (p #include "syn.h" #include "hash.h" #include "generic.h" #define zzcr_attr(attr,tok,t) #define zzSET_SIZE 20 #include "antlr.h" #include "tokens.h" #include "dlgdef.h" #include "mode.h" #endif cdrdao-cdrdao-f00afb2/pccts/antlr/syn.h000066400000000000000000000333001511453746600201130ustar00rootroot00000000000000/* * syn.h * * This file includes definitions and macros associated with syntax diagrams * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2001 */ #include "set.h" #define NumNodeTypes 4 #define NumJuncTypes 9 /* List the different node types */ #define nJunction 1 #define nRuleRef 2 #define nToken 3 #define nAction 4 /* Different types of junctions */ #define aSubBlk 1 #define aOptBlk 2 #define aLoopBlk 3 #define EndBlk 4 #define RuleBlk 5 #define Generic 6 /* just a junction--no unusual characteristics */ #define EndRule 7 #define aPlusBlk 8 #define aLoopBegin 9 typedef int NodeType; #define TreeBlockAllocSize 500 #define JunctionBlockAllocSize 200 #define ActionBlockAllocSize 50 #define RRefBlockAllocSize 100 #define TokenBlockAllocSize 100 #ifdef __cplusplus class ActionNode; class Junction; #endif /* note that 'right' is used by the tree node allocator as a ptr for linked list */ typedef struct _tree { struct _tree *down, *right; int token; union { int rk; /* if token==EpToken, => how many more tokens req'd */ struct _tree *tref; /* if token==TREE_REF */ set sref; /* if token==SET */ } v; #ifdef TREE_DEBUG int in_use; int seq; #endif } Tree; /* a predicate is defined to be a predicate action and a token tree with * context info (if used); later, this struct may include the * "hoisting distance" when we hoist past tokens. * * A tree is used to indicate && vs || * * p * | * q--r * * indicates p && (q||r). * * If expr is PRED_AND_LIST or PRED_OR_LIST, then it's an operation node * and indicates the start of an && or || list. */ typedef struct _Predicate { struct _Predicate *down, *right; /* these have to be first */ struct _Predicate *up, *left; /* doubly-link me */ char *expr; Tree *tcontext; /* used if lookahead depth of > one is needed (tree) */ int k; /* lookahead depth for this tcontext */ set scontext[2];/* used if lookahead depth of one is needed (set) */ /* scontext[0] is not used; only needed so genExprSets() routine works (it expects an array) */ set completionTree; /* which lookahead depths are required to complete tcontext? */ set completionSet; /* MR10 separate completion set for sets and trees */ struct _PredEntry *predEntry; /* MR11 */ #ifdef __cplusplus ActionNode *source; /* where did this predicate come from? */ #else struct _anode *source; /* where did this predicate come from? */ #endif char cloned; /* MR10 don't want to free original guard pred */ char redundant; /* MR10 predicate tree simplification */ char ampersandStyle; /* MR10 (g)? && <

>? */ char inverted; /* MR11 ! predName */ char isConst; /* MR11 */ char constValue; /* MR11 */ char conflictReported; /* MR11 */ set plainSet; /* MR12b */ /*** remember to change new_predicate() and predicate_dup() when changing this ***/ } Predicate; typedef struct _ExceptionHandler { char *signalname; char *action; } ExceptionHandler; typedef struct _ExceptionGroup { struct _ListNode *handlers; /* list of ExceptionHandler's */ char *label; /* label==""; implies not attached to any * particular rule ref. */ char *altID; /* which alt did it come from (blk#:alt#) */ struct _ExceptionGroup *pendingLink; /* for alternative EG MR7 */ struct _ExceptionGroup *outerEG; /* for alternative EG MR7 */ struct _LabelEntry *labelEntry; /* for alternative EG MR7 */ int forRule; /* MR7 */ int used; /* MR7 */ } ExceptionGroup ; #define TokenString(_i) ((TokenInd!=NULL)?TokenStr[TokenInd[_i]]:TokenStr[_i]) #define ExprString(_i) ((TokenInd!=NULL)?ExprStr[TokenInd[_i]]:ExprStr[_i]) /* M e s s a g e P a s s i n g T o N o d e s */ /* * assumes a 'Junction *r' exists. This macro calls a function with * the pointer to the node to operate on and a pointer to the rule * in which it is enclosed. */ #define TRANS(p) {if ( (p)==NULL ) fatal("TRANS: NULL object"); \ if ( (p)->ntype == nJunction ) (*(fpJTrans[((Junction *)(p))->jtype]))( p );\ else (*(fpTrans[(p)->ntype]))( p );} #define PRINT(p) {if ( (p)==NULL ) fatal("PRINT: NULL object");\ (*(fpPrint[(p)->ntype]))( p );} #define REACH(p,k,rk,a) {if ( (p)==NULL ) fatal("REACH: NULL object");\ (a) = (*(fpReach[(p)->ntype]))( p, k, rk );} #define TRAV(p,k,rk,a) {if ( (p)==NULL ) {\ if ( ContextGuardTRAV ) (a)=NULL; \ else fatal("TRAV: NULL object");\ } \ else (a) = (*(fpTraverse[(p)->ntype]))( p, k, rk );} /** *** #define TRAV(p,k,rk,a) {if ( (p)==NULL ) fatal("TRAV: NULL object");\ *** (a) = (*(fpTraverse[(p)->ntype]))( p, k, rk );} **/ /* All syntax diagram nodes derive from Node -- superclass */ #ifdef __cplusplus class Node { public: NodeType ntype; char *rname; /* what rule does this element live in? */ int file; /* index in FileStr */ int line; /* line number that element occurs on */ }; #else typedef struct _node { NodeType ntype; char *rname; /* what rule does this element live in? */ int file; /* index in FileStr */ int line; /* line number that element occurs on */ } Node; #endif #ifdef __cplusplus class ActionNode : public Node { public: #else typedef struct _anode { NodeType ntype; char *rname; /* what rule does this action live in? */ int file; /* index in FileStr (name of file with action) */ int line; /* line number that action occurs on */ #endif Node *next; char *action; int is_predicate; /* true if action is a <<...>>? predicate action */ int done; /* don't dump if action dumped (used for predicates) */ int init_action; /* is this the 1st action of 1st prod of block? */ char *pred_fail; /* what to do/print when predicate fails */ Predicate *guardpred; /* if '(context)? =>' was present, already done */ unsigned char frmwarned;/* have we dumped a warning for pred yet? */ unsigned char ctxwarned;/* have we dumped a warning for pred yet? */ unsigned char predTooLong; /* MR10 have we dumped warning for pred yet */ unsigned char noHoist; /* MR12 literally "noHoist" */ Predicate *ampersandPred; /* MR10 (g)? && <

>? expr */ #ifdef __cplusplus Junction *guardNodes; /* MR11 */ #else struct _junct *guardNodes; /* MR11 */ #endif struct _PredEntry *predEntry; /* MR11 */ int inverted; /* MR11 <>? */ #ifdef __cplusplus }; #else } ActionNode; #endif #ifdef __cplusplus class TokNode : public Node { public: #else typedef struct _toknode { NodeType ntype; char *rname; /* name of rule it's in */ int file; /* index in FileStr (name of file with rule) */ int line; /* line number that token occurs on */ #endif Node *next; int token; int astnode; /* leaf/root/excluded (used to build AST's) */ unsigned char label;/* token label or expression ? */ unsigned char remapped; /* used if token id's are forced to certain positions; * a function walks the tree reassigning token numbers */ int upper_range; /* MR13 - was char */ /* used only if Token is of type T1..T2; in this case, * use token..upper_range as the range; else * upper_range must be 0 */ unsigned char wild_card; /* indicates that the token is the "." wild-card; * field token is ignored if wild_card is set */ unsigned int elnum; /* element number within the alternative */ #ifdef __cplusplus Junction *altstart; /* pointer to node that starts alt */ #else struct _junct *altstart; /* pointer to node that starts alt */ #endif struct _TCnode *tclass; /* token class if tokclass ref */ set tset; /* set of tokens represented by meta token */ char *el_label; /* el_label:toknode */ unsigned char complement; /* complement the set? */ ExceptionGroup *ex_group; /* any exception[el_label] attached? */ unsigned char use_def_MT_handler; unsigned char label_used_in_semantic_pred; /* MR10 */ #ifdef __cplusplus }; #else } TokNode; #endif #ifdef __cplusplus class RuleRefNode : public Node { public: #else typedef struct _rrnode { NodeType ntype; char *rname; /* name of rule it's in */ int file; /* index in FileStr (name of file with rule) it's in */ int line; /* line number that rule ref occurs on */ #endif Node *next; char *text; /* reference to which rule */ char *parms; /* point to parameters of rule invocation (if present) */ char *assign; /* point to left-hand-side of assignment (if any) */ int linked; /* Has a FoLink already been established? */ int astnode; /* excluded? (used to build AST's) */ unsigned int elnum; /* element number within the alternative */ #ifdef __cplusplus Junction *altstart; #else struct _junct *altstart; #endif char *el_label; /* el_label:rrnode */ ExceptionGroup *ex_group; /* any exception[el_label] attached? */ #ifdef __cplusplus }; #else } RuleRefNode; #endif #ifdef __cplusplus class Junction : public Node { public: #else typedef struct _junct { NodeType ntype; char *rname; /* name of rule junction is in */ int file; /* index in FileStr (name of file with rule) if blk == RuleBlk */ int line; /* line number that rule occurs on */ #endif int seq; /* MR10 sequence number */ char ignore; /* used by FIRST computation to ignore empty alt added for the (...)+ blks */ char visited; /* used by recursive routines to avoid infinite recursion */ char pvisited; /* used by print routines to avoid infinite recursion */ char fvisited; /* used by FoLink() to avoid infinite recursion */ char *lock; /* used by REACH to track infinite recursion */ char *pred_lock; /* used by find_predicates to track infinite recursion */ int altnum; /* used in subblocks. altnum==0 means not an alt of subrule */ int jtype; /* annotation for code-gen/FIRST/FOLLOW. Junction type */ #ifdef __cplusplus Junction *end; /* pointer to node with EndBlk in it if blk == a block type */ #else struct _junct *end; /* pointer to node with EndBlk in it if blk == a block type */ #endif Node *p1, *p2; char halt; /* never move past a junction with halt==TRUE */ /* MR10 was int */ char *pdecl; /* point to declaration of parameters on rule (if present) */ char *parm; /* point to parameter of block invocation (if present) */ char predparm; /* indicates that the 'parm' is a predicate * to be used in the while loop generated * for blocks */ /* MR10 was int */ char *ret; /* point to return type of rule (if present) */ char *erraction; /* point to error action (if present) */ int blockid; /* this is a unique ID */ char *exception_label; /* goto label for this alt */ set *fset; /* used for code generation */ Tree *ftree; /* used for code generation */ Predicate *predicate;/* predicate that can be used to disambiguate */ char guess; /* true if (...)? block */ char alpha_beta_guess_end; /* MR14 1 => end block of guess sub block */ Node *guess_analysis_point; /* MR14 */ char approx; /* limit block to use linear approx lookahead? */ set tokrefs; /* if ith element of alt is tokref then i is member */ set rulerefs; /* if ith element of alt is rule ref then i is member */ struct _ListNode *exceptions; /* list of exceptions groups for rule */ struct _ListNode *el_labels; /* list of element labels for rule */ ExceptionGroup *outerEG; /* MR7 */ int curAltNum; /* MR7 */ char* pFirstSetSymbol; /* #pragma FirstSetSymbol(Foo) MR21 */ #ifdef __cplusplus Junction *pendingLink; /* MR7 */ #else struct _junct *pendingLink; /* MR7 */ #endif char overlap_warning; /* MR10 */ #ifdef __cplusplus }; #else } Junction; #endif typedef struct { Node *left, *right;} Graph; cdrdao-cdrdao-f00afb2/pccts/antlr/tokens.h000066400000000000000000000116211511453746600206070ustar00rootroot00000000000000#ifndef tokens_h #define tokens_h /* tokens.h -- List of labelled tokens and stuff * * Generated from: antlr.g * * Terence Parr, Will Cohen, and Hank Dietz: 1989-2001 * Purdue University Electrical Engineering * ANTLR Version 1.33MR32 */ #define zzEOF_TOKEN 1 #define Eof 1 #define QuotedTerm 2 #define Action 34 #define Pred 35 #define PassAction 36 #define WildCard 87 #define LABEL 89 #define Pragma 92 #define FirstSetSymbol 93 #define NonTerminal 100 #define TokenTerm 101 #define ID 148 #define INT 150 #ifdef __USE_PROTOS void grammar(void); #else extern void grammar(); #endif #ifdef __USE_PROTOS void class_def(void); #else extern void class_def(); #endif #ifdef __USE_PROTOS void rule(void); #else extern void rule(); #endif #ifdef __USE_PROTOS void laction(void); #else extern void laction(); #endif #ifdef __USE_PROTOS void lmember(void); #else extern void lmember(); #endif #ifdef __USE_PROTOS void lprefix(void); #else extern void lprefix(); #endif #ifdef __USE_PROTOS void aPred(void); #else extern void aPred(); #endif #ifdef __USE_PROTOS extern Predicate * predOrExpr(void); #else extern Predicate * predOrExpr(); #endif #ifdef __USE_PROTOS extern Predicate * predAndExpr(void); #else extern Predicate * predAndExpr(); #endif #ifdef __USE_PROTOS extern Predicate * predPrimary(void); #else extern Predicate * predPrimary(); #endif #ifdef __USE_PROTOS void aLexclass(void); #else extern void aLexclass(); #endif #ifdef __USE_PROTOS void error(void); #else extern void error(); #endif #ifdef __USE_PROTOS void tclass(void); #else extern void tclass(); #endif #ifdef __USE_PROTOS void token(void); #else extern void token(); #endif #ifdef __USE_PROTOS void block(set * toksrefd,set * rulesrefd); #else extern void block(); #endif #ifdef __USE_PROTOS void alt(set * toksrefd,set * rulesrefd); #else extern void alt(); #endif #ifdef __USE_PROTOS extern LabelEntry * element_label(void); #else extern LabelEntry * element_label(); #endif #ifdef __USE_PROTOS extern Node * element(int old_not,int first_on_line,int use_def_MT_handler); #else extern Node * element(); #endif #ifdef __USE_PROTOS void default_exception_handler(void); #else extern void default_exception_handler(); #endif #ifdef __USE_PROTOS extern ExceptionGroup * exception_group(void); #else extern ExceptionGroup * exception_group(); #endif #ifdef __USE_PROTOS extern ExceptionHandler * exception_handler(void); #else extern ExceptionHandler * exception_handler(); #endif #ifdef __USE_PROTOS void enum_file(char * fname); #else extern void enum_file(); #endif #ifdef __USE_PROTOS void defines(char * fname); #else extern void defines(); #endif #ifdef __USE_PROTOS void enum_def(char * fname); #else extern void enum_def(); #endif #endif extern SetWordType zzerr1[]; extern SetWordType zzerr2[]; extern SetWordType zzerr3[]; extern SetWordType zzerr4[]; extern SetWordType setwd1[]; extern SetWordType zzerr5[]; extern SetWordType zzerr6[]; extern SetWordType zzerr7[]; extern SetWordType zzerr8[]; extern SetWordType zzerr9[]; extern SetWordType setwd2[]; extern SetWordType zzerr10[]; extern SetWordType zzerr11[]; extern SetWordType zzerr12[]; extern SetWordType zzerr13[]; extern SetWordType setwd3[]; extern SetWordType zzerr14[]; extern SetWordType zzerr15[]; extern SetWordType zzerr16[]; extern SetWordType zzerr17[]; extern SetWordType zzerr18[]; extern SetWordType zzerr19[]; extern SetWordType zzerr20[]; extern SetWordType zzerr21[]; extern SetWordType setwd4[]; extern SetWordType zzerr22[]; extern SetWordType zzerr23[]; extern SetWordType zzerr24[]; extern SetWordType zzerr25[]; extern SetWordType zzerr26[]; extern SetWordType setwd5[]; extern SetWordType zzerr27[]; extern SetWordType zzerr28[]; extern SetWordType zzerr29[]; extern SetWordType zzerr30[]; extern SetWordType zzerr31[]; extern SetWordType zzerr32[]; extern SetWordType zzerr33[]; extern SetWordType setwd6[]; extern SetWordType zzerr34[]; extern SetWordType zzerr35[]; extern SetWordType zzerr36[]; extern SetWordType zzerr37[]; extern SetWordType zzerr38[]; extern SetWordType zzerr39[]; extern SetWordType zzerr40[]; extern SetWordType zzerr41[]; extern SetWordType zzerr42[]; extern SetWordType setwd7[]; extern SetWordType zzerr43[]; extern SetWordType zzerr44[]; extern SetWordType zzerr45[]; extern SetWordType zzerr46[]; extern SetWordType zzerr47[]; extern SetWordType zzerr48[]; extern SetWordType zzerr49[]; extern SetWordType zzerr50[]; extern SetWordType zzerr51[]; extern SetWordType zzerr52[]; extern SetWordType zzerr53[]; extern SetWordType setwd8[]; extern SetWordType zzerr54[]; extern SetWordType zzerr55[]; extern SetWordType zzerr56[]; extern SetWordType zzerr57[]; extern SetWordType setwd9[]; extern SetWordType zzerr58[]; extern SetWordType zzerr59[]; extern SetWordType zzerr60[]; extern SetWordType zzerr61[]; extern SetWordType zzerr62[]; extern SetWordType zzerr63[]; extern SetWordType zzerr64[]; extern SetWordType zzerr65[]; extern SetWordType setwd10[]; extern SetWordType setwd11[]; cdrdao-cdrdao-f00afb2/pccts/dlg/000077500000000000000000000000001511453746600165605ustar00rootroot00000000000000cdrdao-cdrdao-f00afb2/pccts/dlg/.cvsignore000066400000000000000000000000331511453746600205540ustar00rootroot00000000000000Makefile Makefile.in .deps cdrdao-cdrdao-f00afb2/pccts/dlg/Makefile.am000066400000000000000000000003761511453746600206220ustar00rootroot00000000000000noinst_PROGRAMS = dlg dlg_SOURCES = automata.c dlg_a.c dlg_p.c err.c main.c output.c relabel.c set.c support.c dlg.h mode.h stdpccts.h tokens.h AM_CFLAGS = -std=c9x -Wno-deprecated-non-prototype -DUSER_ZZSYN -DZZLEXBUFSIZE=32000 AM_CPPFLAGS = -I../h cdrdao-cdrdao-f00afb2/pccts/dlg/automata.c000066400000000000000000000176661511453746600205570ustar00rootroot00000000000000/* Automata conversion functions for DLG * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * DLG 1.33 * Will Cohen * With mods by Terence Parr; AHPCRC, University of Minnesota * 1989-2001 */ #include #include "pcctscfg.h" #include "dlg.h" #ifdef MEMCHK #include "trax.h" #else #ifdef __STDC__ #include #else #include #endif /* __STDC__ */ #endif #define hash_list struct _hash_list_ hash_list{ hash_list *next; /* next thing in list */ dfa_node *node; }; int dfa_allocated = 0; /* keeps track of number of dfa nodes */ dfa_node **dfa_array; /* root of binary tree that stores dfa array */ dfa_node *dfa_model_node; hash_list *dfa_hash[HASH_SIZE]; /* used to quickly find */ /* desired dfa node */ void #ifdef __USE_PROTOS make_dfa_model_node(int width) #else make_dfa_model_node(width) int width; #endif { register int i; dfa_model_node = (dfa_node*) malloc(sizeof(dfa_node) + sizeof(int)*width); dfa_model_node->node_no = -1; /* impossible value for real dfa node */ dfa_model_node->dfa_set = 0; dfa_model_node->alternatives = FALSE; dfa_model_node->done = FALSE; dfa_model_node->nfa_states = empty; for(i = 0; itrans[i] = NIL_INDEX; } } /* adds a new nfa to the binary tree and returns a pointer to it */ dfa_node * #ifdef __USE_PROTOS new_dfa_node(set nfa_states) #else new_dfa_node(nfa_states) set nfa_states; #endif { register int j; register dfa_node *t; static int dfa_size=0; /* elements dfa_array[] can hold */ ++dfa_allocated; if (dfa_size<=dfa_allocated){ /* need to redo array */ if (!dfa_array){ /* need some to do inital allocation */ dfa_size=dfa_allocated+DFA_MIN; dfa_array=(dfa_node **) malloc(sizeof(dfa_node*)* dfa_size); }else{ /* need more space */ dfa_size=2*(dfa_allocated+1); dfa_array=(dfa_node **) realloc(dfa_array, sizeof(dfa_node*)*dfa_size); } } /* fill out entry in array */ t = (dfa_node*) malloc(sizeof(nfa_node)+sizeof(int)*class_no); *t = *dfa_model_node; for (j=0; jtrans[j] = NIL_INDEX; t->node_no = dfa_allocated; t->nfa_states = set_dup(nfa_states); dfa_array[dfa_allocated] = t; return t; } /* past a pointer to the start start of the nfa graph * nfa_to_dfa convers this graph to dfa. The function returns * a pointer to the first dfa state. * NOTE: The function that prints out the table will have to figure out how * to find the other dfa states given the first dfa_state and the number of dfa * nodes allocated */ dfa_node ** #ifdef __USE_PROTOS nfa_to_dfa(nfa_node *start) #else nfa_to_dfa(start) nfa_node *start; #endif { register dfa_node *d_state, *trans_d_state; register int a; set t; int last_done; unsigned *nfa_list; unsigned *reach_list; reach_list = (unsigned *) malloc((2+nfa_allocated)*sizeof(unsigned)); if (!start) return NULL; t = set_of(NFA_NO(start)); _set_pdq(t,reach_list); closure(&t,reach_list); /* Make t a dfa state */ d_state = dfastate(t); last_done = DFA_NO(d_state); do { /* Mark dfa state x as "done" */ d_state->done = TRUE; nfa_list = set_pdq(d_state->nfa_states); for (a = 0; at, labeled with a */ d_state->trans[a] = DFA_NO(trans_d_state); d_state->alternatives = TRUE; } } free(nfa_list); ++last_done; /* move forward in queue */ /* And so forth until nothing isn't done */ d_state = DFA(last_done); } while (last_done<=dfa_allocated); free(reach_list); set_free(t); /* returns pointer to the array that holds the automaton */ return dfa_array; } void #ifdef __USE_PROTOS clear_hash(void) #else clear_hash() #endif { register int i; for(i=0; inext; } total+=j; fprintf(f,"bin[%d] has %d\n",i,j); } fprintf(f,"total = %d\n",total); } #endif /* Returns a pointer to a dfa node that has the same nfa nodes in it. * This may or maynot be a newly created node. */ dfa_node * #ifdef __USE_PROTOS dfastate(set nfa_states) #else dfastate(nfa_states) set nfa_states; #endif { register hash_list *p; int bin; /* hash using set and see if it exists */ bin = set_hash(nfa_states,HASH_SIZE); p = dfa_hash[bin]; while(p && !set_equ(nfa_states,(p->node)->nfa_states)){ p = p->next; } if(!p){ /* next state to add to hash table */ p = (hash_list*)malloc(sizeof(hash_list)); p->node = new_dfa_node(nfa_states); p->next = dfa_hash[bin]; dfa_hash[bin] = p; } return (p->node); } /* this reach assumes the closure has been done already on set */ int #ifdef __USE_PROTOS reach(unsigned *nfa_list, register int a, unsigned *reach_list) #else reach(nfa_list, a, reach_list) unsigned *nfa_list; register int a; unsigned *reach_list; #endif { register unsigned *e; register nfa_node *node; int t=0; e = nfa_list; if (e){ while (*e != nil){ node = NFA(*e); if (set_el(a,node->label)){ t=1; *reach_list=NFA_NO(node->trans[0]); ++reach_list; } ++e; } } *reach_list=nil; return t; } /* finds all the nodes that can be reached by epsilon transitions from the set of a nodes and returns puts them back in set b */ set #ifdef __USE_PROTOS closure(set *b, unsigned *reach_list) #else closure(b, reach_list) set *b; unsigned *reach_list; #endif { register nfa_node *node,*n; /* current node being examined */ register unsigned *e; ++operation_no; #if 0 t = e = set_pdq(*b); #else e=reach_list; #endif while (*e != nil){ node = NFA(*e); set_orel(NFA_NO(node),b); /* mark it done */ node->nfa_set = operation_no; if ((n=node->trans[0]) != NIL_INDEX && set_nil(node->label) && (n->nfa_set != operation_no)){ /* put in b */ set_orel(NFA_NO(n),b); close1(n,operation_no,b); } if ((n=node->trans[1]) != NIL_INDEX && (n->nfa_set != operation_no)){ /* put in b */ set_orel(NFA_NO(node->trans[1]),b); close1(n,operation_no,b); } ++e; } #if 0 free(t); #endif return *b; } #ifdef __USE_PROTOS void close1(nfa_node *node, int o, set *b) #else void close1(node,o,b) nfa_node *node; int o; /* marker to avoid cycles */ set *b; #endif { register nfa_node *n; /* current node being examined */ /* mark it done */ node->nfa_set = o; if ((n=node->trans[0]) != NIL_INDEX && set_nil(node->label) && (n->nfa_set != o)){ /* put in b */ set_orel(NFA_NO(n),b); close1(n,o,b); } if ((n=node->trans[1]) != NIL_INDEX && (n->nfa_set != o)){ /* put in b */ set_orel(NFA_NO(node->trans[1]),b); close1(n,o,b); } } cdrdao-cdrdao-f00afb2/pccts/dlg/dlg.h000066400000000000000000000221441511453746600175020ustar00rootroot00000000000000/* dlg header file * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * DLG 1.33 * Will Cohen * With mods by Terence Parr; AHPCRC, University of Minnesota * 1989-2001 */ /* MR1 Move pcctscfg.h to top of file */ #include "pcctscfg.h" /* turn off warnings for unreferenced labels */ #ifdef _MSC_VER #pragma warning(disable:4102) #endif #include "set.h" #define TRUE 1 #define FALSE 0 /***** output related stuff *******************/ #define IN input_stream #define OUT output_stream #define MAX_MODES 50 /* number of %%names allowed */ #define MAX_ON_LINE 10 #define NFA_MIN 64 /* minimum nfa_array size */ #define DFA_MIN 64 /* minimum dfa_array size */ #define DEFAULT_CLASSNAME "DLGLexer" /* these macros allow the size of the character set to be easily changed */ /* NOTE: do NOT change MIN_CHAR since EOF is the lowest char, -1 */ #define MIN_CHAR (-1) /* lowest possible character possible on input */ #define MAX_CHAR 255 /* highest possible character possible on input */ #define CHAR_RANGE (1+(MAX_CHAR) - (MIN_CHAR)) /* indicates that the not an "array" reference */ #define NIL_INDEX 0 /* size of hash table used to find dfa_states quickly */ #define HASH_SIZE 211 #define nfa_node struct _nfa_node nfa_node { int node_no; int nfa_set; int accept; /* what case to use */ nfa_node *trans[2]; set label; /* one arc always labelled with epsilon */ }; #define dfa_node struct _dfa_node dfa_node { int node_no; int dfa_set; int alternatives; /* used for interactive mode */ /* are more characters needed */ int done; set nfa_states; int trans[1];/* size of transition table depends on * number of classes required for automata. */ }; /******** macros for accessing the NFA and DFA nodes ****/ #define NFA(x) (nfa_array[x]) #define DFA(x) (dfa_array[x]) #define DFA_NO(x) ( (x) ? (x)->node_no : NIL_INDEX) #define NFA_NO(x) ( (x) ? (x)->node_no : NIL_INDEX) /******** wrapper for memory checking ***/ /*#define malloc(x) dlg_malloc((x),__FILE__,__LINE__)*/ /*#define calloc(x,y) dlg_calloc((x),(y),__FILE__,__LINE__)*/ /******** antlr attributes *************/ typedef struct { unsigned char letter; nfa_node *l,*r; set label; } Attrib; #define zzcr_attr(attr, token, text) { \ (attr)->letter = text[0]; (attr)->l = NULL; \ (attr)->r = NULL; (attr)->label = empty; \ } #define zzd_attr(a) set_free((a)->label); /******************** Variable ******************************/ extern char program[]; /* tells what program this is */ extern char version[]; /* tells what version this is */ extern char *file_str[]; /* file names being used */ extern int err_found; /* flag to indicate error occured */ extern int action_no; /* last action function printed */ extern int func_action; /* should actions be turned into functions?*/ extern set used_chars; /* used to label trans. arcs */ extern set used_classes; /* classes or chars used to label trans. arcs */ extern int class_no; /* number of classes used */ extern set class_sets[]; /* shows char. in each class */ extern set normal_chars; /* mask off unused portion of set */ extern int comp_level; /* what compression level to use */ extern int interactive; /* interactive scanner (avoid lookahead)*/ extern int mode_counter; /* keeps track of the number of %%name */ extern int dfa_basep[]; /* start of each group of dfa */ extern int dfa_class_nop[];/* number of transistion arcs in */ /* each dfa in each mode */ extern int nfa_allocated; extern int dfa_allocated; extern nfa_node **nfa_array; /* start of nfa "array" */ extern dfa_node **dfa_array; /* start of dfa "array" */ extern int operation_no; /* unique number for each operation */ extern FILE *input_stream; /* where description read from */ extern FILE *output_stream; /* where to put the output */ extern FILE *mode_stream; /* where to put the mode output */ extern FILE *class_stream; extern char *mode_file; /* name of file for mode output */ extern int gen_ansi; /* produce ansi compatible code */ extern int case_insensitive;/* ignore case of input spec. */ extern int warn_ambig; /* show if regular expressions ambiguous */ extern int gen_cpp; extern char *cl_file_str; extern int firstLexMember; /* MR1 */ extern char *OutputDirectory; extern char *class_name; /******************** Functions ******************************/ #ifdef __USE_PROTOS extern char *dlg_malloc(int, char *, int); /* wrapper malloc */ extern char *dlg_calloc(int, int, char *, int); /* wrapper calloc */ extern int reach(unsigned *, register int, unsigned *); extern set closure(set *, unsigned *); extern dfa_node *new_dfa_node(set); extern nfa_node *new_nfa_node(void); extern dfa_node *dfastate(set); extern dfa_node **nfa_to_dfa(nfa_node *); extern void internal_error(char *, char *, int); /* MR9 23-Sep-97 */ extern FILE *read_stream(char *); /* opens file for reading */ extern FILE *write_stream(char *); /* opens file for writing */ extern void make_nfa_model_node(void); extern void make_dfa_model_node(int); extern char *ClassName(char *); extern char *OutMetaName(char *); extern void error(char*, int); extern void warning(char*, int); extern void p_head(void); extern void p_class_hdr(void); extern void p_includes(void); extern void p_tables(void); extern void p_tail(void); /* MR1 */ extern void p_class_def1(void); /* MR1 */ extern void new_automaton_mode(void); /* MR1 */ extern int relabel(nfa_node *,int); /* MR1 */ extern void p_shift_table(int); /* MR1 */ extern void p_bshift_table(void); /* MR1 */ extern void p_class_table(void); /* MR1 */ extern void p_mode_def(char *,int); /* MR1 */ extern void init(void); /* MR1 */ extern void p_class_def2(void); /* MR1 */ extern void clear_hash(void); /* MR1 */ extern void p_alternative_table(void); /* MR1 */ extern void p_node_table(void); /* MR1 */ extern void p_dfa_table(void); /* MR1 */ extern void p_accept_table(void); /* MR1 */ extern void p_action_table(void); /* MR1 */ extern void p_base_table(void); /* MR1 */ extern void p_single_node(int,int); /* MR1 */ extern char * minsize(int); /* MR1 */ extern void close1(nfa_node *,int,set *); /* MR1 */ extern void partition(nfa_node *,int); /* MR1 */ extern void intersect_nfa_labels(nfa_node *,set *); /* MR1 */ extern void r_intersect(nfa_node *,set *); /* MR1 */ extern void label_node(nfa_node *); /* MR1 */ extern void label_with_classes(nfa_node *); /* MR1 */ #else extern char *dlg_malloc(); /* wrapper malloc */ extern char *dlg_calloc(); /* wrapper calloc */ extern int reach(); extern set closure(); extern dfa_node *new_dfa_node(); extern nfa_node *new_nfa_node(); extern dfa_node *dfastate(); extern dfa_node **nfa_to_dfa(); extern void internal_error(); /* MR9 23-Sep-97 */ extern FILE *read_stream(); /* opens file for reading */ extern FILE *write_stream(); /* opens file for writing */ extern void make_nfa_model_node(); extern void make_dfa_model_node(); extern char *ClassName(); extern char *OutMetaName(); extern void error(); extern void warning(); extern void p_head(); /* MR9 */ extern void p_class_hdr(); /* MR9 */ extern void p_includes(); /* MR9 */ extern void p_tables(); /* MR9 */ extern void p_tail(); /* MR1 */ extern void p_class_def1(); /* MR1 */ extern void new_automaton_mode(); /* MR1 */ extern int relabel(); /* MR1 */ extern void p_shift_table(); /* MR1 */ extern void p_bshift_table(); /* MR1 */ extern void p_class_table(); /* MR1 */ extern void p_mode_def(); /* MR1 */ extern void init(); /* MR1 */ extern void p_class_def2(); /* MR1 */ extern void clear_hash(); /* MR1 */ extern void p_alternative_table(); /* MR1 */ extern void p_node_table(); /* MR1 */ extern void p_dfa_table(); /* MR1 */ extern void p_accept_table(); /* MR1 */ extern void p_action_table(); /* MR1 */ extern void p_base_table(); /* MR1 */ extern void p_single_node(); /* MR1 */ extern char * minsize(); /* MR1 */ extern void close1(); /* MR1 */ extern void partition(); /* MR1 */ extern void intersect_nfa_labels(); /* MR1 */ extern void r_intersect(); /* MR1 */ extern void label_node(); /* MR1 */ extern void label_with_classes(); /* MR1 */ #endif cdrdao-cdrdao-f00afb2/pccts/dlg/dlg_a.c000066400000000000000000000706321511453746600200020ustar00rootroot00000000000000 /* parser.dlg -- DLG Description of scanner * * Generated from: dlg_p.g * * Terence Parr, Will Cohen, and Hank Dietz: 1989-2001 * Purdue University Electrical Engineering * With AHPCRC, University of Minnesota * ANTLR Version 1.33MR32 */ #define ANTLR_VERSION 13332 #include "pcctscfg.h" #include "pccts_stdio.h" #include #include "dlg.h" #include "antlr.h" #include "tokens.h" #include "dlgdef.h" LOOKAHEAD void #ifdef __USE_PROTOS zzerraction(void) #else zzerraction() #endif { (*zzerr)("invalid token"); zzadvance(); zzskip(); } /* * D L G tables * * Generated from: parser.dlg * * 1989-2001 by Will Cohen, Terence Parr, and Hank Dietz * Purdue University Electrical Engineering * DLG Version 1.33MR32 */ #include "mode.h" int func_action; /* should actions be turned into functions?*/ int lex_mode_counter = 0; /* keeps track of the number of %%names */ /* MR1 */ /* MR1 11-Apr-97 Provide mechanism for inserting code into DLG class */ /* MR1 via <<%%lexmember...>> */ /* MR1 */ int lexMember = 0; /* <<%%lexmemeber ...>> MR1 */ int lexAction = 0; /* <<%%lexaction ...>> MR1 */ int parserClass = 0; /* <<%%parserclass ...>> MR1 */ int lexPrefix = 0; /* <<%%lexprefix ...>> MR1 */ char theClassName[100]; /* MR11 */ char *pClassName=theClassName; /* MR11 */ int firstLexMember=1; /* MR1 */ #ifdef __USE_PROTOS void xxputc(int c) { /* MR1 */ #else void xxputc(c) /* MR1 */ int c; /* MR1 */ { /* MR1 */ #endif if (parserClass) { /* MR1 */ *pClassName++=c; /* MR1 */ *pClassName=0; /* MR1 */ } else if (lexMember || lexPrefix) { /* MR1 */ if (class_stream != NULL) fputc(c,class_stream); /* MR1 */ } else { /* MR1 */ fputc(c,OUT); /* MR1 */ }; /* MR1 */ } /* MR1 */ #ifdef __USE_PROTOS void xxprintf(char *format,char *string) { /* MR1 */ #else void xxprintf(format,string) /* MR1 */ char *format; /* MR1 */ char *string; /* MR1 */ { /* MR1 */ #endif if (lexMember || lexPrefix || parserClass) { /* MR1 */ if (class_stream != NULL) /* MR1 */ fprintf(class_stream,format,string); /* MR1 */ } else { /* MR1 */ fprintf(OUT,format,string); /* MR1 */ }; /* MR1 */ } /* MR1 */ static void act1() { NLA = 1; } static void act2() { NLA = 2; zzskip(); } static void act3() { NLA = 3; zzline++; zzskip(); DAWDLE; } static void act4() { NLA = L_EOF; } static void act5() { NLA = PER_PER; } static void act6() { NLA = NAME_PER_PER; p_mode_def(&zzlextext[2],lex_mode_counter++); } static void act7() { NLA = LEXMEMBER; lexMember=1; /* MR1 */ if (firstLexMember != 0) { /* MR1 */ firstLexMember=0; /* MR1 */ p_class_def1(); /* MR1 */ }; /* MR1 */ zzmode(ACT); /* MR1 */ } static void act8() { NLA = LEXACTION; lexAction=1;zzmode(ACT); } static void act9() { NLA = PARSERCLASS; parserClass=1; /* MR1 */ zzmode(ACT); /* MR1 */ } static void act10() { NLA = LEXPREFIX; lexPrefix=1;zzmode(ACT); } static void act11() { NLA = ACTION; if (func_action) fprintf(OUT,"\n%s %sact%d()\n{ ", gen_cpp?"ANTLRTokenType":"static void", gen_cpp?ClassName("::"):"", ++action_no); zzmode(ACT); zzskip(); } static void act12() { NLA = GREAT_GREAT; } static void act13() { NLA = L_BRACE; } static void act14() { NLA = R_BRACE; } static void act15() { NLA = L_PAR; } static void act16() { NLA = R_PAR; } static void act17() { NLA = L_BRACK; } static void act18() { NLA = R_BRACK; } static void act19() { NLA = ZERO_MORE; } static void act20() { NLA = ONE_MORE; } static void act21() { NLA = OR; } static void act22() { NLA = RANGE; } static void act23() { NLA = NOT; } static void act24() { NLA = OCTAL_VALUE; {int t; sscanf(&zzlextext[1],"%o",&t); zzlextext[0] = t;} } static void act25() { NLA = HEX_VALUE; {int t; sscanf(&zzlextext[3],"%x",&t); zzlextext[0] = t;} } static void act26() { NLA = DEC_VALUE; {int t; sscanf(&zzlextext[1],"%d",&t); zzlextext[0] = t;} } static void act27() { NLA = TAB; zzlextext[0] = '\t'; } static void act28() { NLA = NL; zzlextext[0] = '\n'; } static void act29() { NLA = CR; zzlextext[0] = '\r'; } static void act30() { NLA = BS; zzlextext[0] = '\b'; } static void act31() { NLA = CONTINUATION; zzline++; zzskip(); } static void act32() { NLA = LIT; zzlextext[0] = zzlextext[1]; } static void act33() { NLA = REGCHAR; } static unsigned char shift0[257] = { 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 1, 2, 40, 40, 1, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 1, 40, 40, 40, 40, 4, 40, 40, 30, 31, 34, 35, 40, 37, 40, 40, 23, 24, 24, 24, 24, 24, 24, 24, 25, 25, 40, 40, 26, 40, 27, 40, 3, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 20, 22, 22, 32, 39, 33, 40, 22, 40, 11, 9, 12, 21, 6, 19, 22, 22, 14, 22, 22, 5, 8, 16, 15, 17, 22, 10, 18, 13, 22, 22, 22, 7, 22, 22, 28, 36, 29, 38, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40 }; static void act34() { NLA = 1; error("unterminated action", zzline); zzmode(START); } static void act35() { NLA = ACTION; if (func_action) fprintf(OUT,"}\n\n"); zzmode(START); /* MR1 */ /* MR1 11-Apr-97 Provide mechanism for inserting code into DLG class */ /* MR1 via <<%%lexmember ...>> */ /* MR1 This is a consequence of not saving actions */ /* MR1 */ /* MR1 */ parserClass=0; /* MR1 */ lexPrefix=0; /* MR1 */ lexAction=0; /* MR1 */ lexMember=0; } static void act36() { NLA = 34; xxputc(zzlextext[0]); zzskip(); } static void act37() { NLA = 35; xxputc('>'); zzskip(); } static void act38() { NLA = 36; xxputc('\\'); zzskip(); } static void act39() { NLA = 37; xxputc(zzlextext[0]); ++zzline; zzskip(); } static void act40() { NLA = 38; zzmode(ACTION_COMMENTS); /* MR1 */ xxprintf("%s", &(zzlextext[0])); zzskip(); /* MR1 */ } static void act41() { NLA = 39; zzmode(ACTION_CPP_COMMENTS); /* MR1 */ xxprintf("%s", &(zzlextext[0])); zzskip(); /* MR1 */ } static void act42() { NLA = 40; xxputc(zzlextext[0]); zzskip(); } static unsigned char shift1[257] = { 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 6, 6, 6, 6, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }; static void act43() { NLA = 1; } static void act44() { NLA = 41; zzmode(ACT); /* MR1 */ xxprintf("%s", &(zzlextext[0])); zzskip(); /* MR1 */ } static void act45() { NLA = 42; zzline++; xxputc(zzlextext[0]); zzskip(); } static void act46() { NLA = 43; xxputc(zzlextext[0]); zzskip(); } static unsigned char shift2[257] = { 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 4, 4, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 4, 4, 4, 4, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }; static void act47() { NLA = 1; } static void act48() { NLA = 44; zzmode(ACT); zzline++; /* MR1 */ xxprintf("%s", &(zzlextext[0])); zzskip(); /* MR1 */ } static void act49() { NLA = 45; xxputc(zzlextext[0]); zzskip(); } static unsigned char shift3[257] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }; #define DfaStates 94 typedef unsigned char DfaState; static DfaState st0[42] = { 1, 2, 3, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 6, 94 }; static DfaState st1[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st2[42] = { 94, 21, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st3[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st4[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st5[42] = { 94, 94, 94, 94, 22, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st6[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st7[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 23, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st8[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 24, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st9[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st10[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st11[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st12[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st13[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st14[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st15[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st16[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st17[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st18[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st19[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st20[42] = { 94, 25, 26, 25, 25, 25, 25, 25, 25, 27, 28, 25, 25, 29, 25, 25, 30, 25, 25, 25, 25, 25, 25, 31, 32, 32, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 94 }; static DfaState st21[42] = { 94, 21, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st22[42] = { 94, 94, 94, 94, 94, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st23[42] = { 94, 94, 94, 94, 34, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st24[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st25[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st26[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st27[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st28[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st29[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st30[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st31[42] = { 94, 94, 94, 94, 94, 94, 94, 35, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 35, 94, 94, 36, 36, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st32[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 37, 37, 37, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st33[42] = { 94, 94, 94, 94, 94, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st34[42] = { 94, 94, 94, 94, 39, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st35[42] = { 94, 94, 94, 94, 94, 94, 40, 94, 94, 40, 94, 40, 40, 94, 94, 94, 94, 94, 94, 40, 94, 40, 94, 40, 40, 40, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st36[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 36, 36, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st37[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 37, 37, 37, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st38[42] = { 94, 94, 94, 94, 94, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st39[42] = { 94, 94, 94, 94, 94, 41, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 42, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st40[42] = { 94, 94, 94, 94, 94, 94, 40, 94, 94, 40, 94, 40, 40, 94, 94, 94, 94, 94, 94, 40, 94, 40, 94, 40, 40, 40, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st41[42] = { 94, 94, 94, 94, 94, 94, 43, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st42[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 44, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st43[42] = { 94, 94, 94, 94, 94, 94, 94, 45, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st44[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 46, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st45[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 47, 94, 94, 48, 94, 94, 94, 94, 94, 49, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st46[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 50, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st47[42] = { 94, 94, 94, 94, 94, 94, 51, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st48[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 52, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st49[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 53, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st50[42] = { 94, 94, 94, 94, 94, 94, 54, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st51[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 55, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st52[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 56, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st53[42] = { 94, 94, 94, 94, 94, 94, 57, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st54[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 58, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st55[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 59, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st56[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 60, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st57[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 61, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st58[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 62, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st59[42] = { 94, 94, 94, 94, 94, 94, 63, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st60[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 64, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st61[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 65, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st62[42] = { 94, 94, 94, 94, 94, 66, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st63[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 67, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st64[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 68, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st65[42] = { 94, 94, 94, 94, 94, 94, 94, 69, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st66[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 70, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st67[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st68[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st69[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st70[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 71, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st71[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 72, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st72[42] = { 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st73[8] = { 74, 75, 76, 77, 78, 79, 79, 94 }; static DfaState st74[8] = { 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st75[8] = { 94, 80, 94, 94, 94, 94, 94, 94 }; static DfaState st76[8] = { 94, 81, 94, 94, 94, 94, 94, 94 }; static DfaState st77[8] = { 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st78[8] = { 94, 94, 94, 94, 82, 83, 94, 94 }; static DfaState st79[8] = { 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st80[8] = { 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st81[8] = { 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st82[8] = { 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st83[8] = { 94, 94, 94, 94, 94, 94, 94, 94 }; static DfaState st84[6] = { 85, 86, 87, 88, 87, 94 }; static DfaState st85[6] = { 94, 94, 94, 94, 94, 94 }; static DfaState st86[6] = { 94, 94, 89, 94, 94, 94 }; static DfaState st87[6] = { 94, 94, 94, 94, 94, 94 }; static DfaState st88[6] = { 94, 94, 94, 94, 94, 94 }; static DfaState st89[6] = { 94, 94, 94, 94, 94, 94 }; static DfaState st90[4] = { 91, 92, 93, 94 }; static DfaState st91[4] = { 94, 94, 94, 94 }; static DfaState st92[4] = { 94, 94, 94, 94 }; static DfaState st93[4] = { 94, 94, 94, 94 }; DfaState *dfa[94] = { st0, st1, st2, st3, st4, st5, st6, st7, st8, st9, st10, st11, st12, st13, st14, st15, st16, st17, st18, st19, st20, st21, st22, st23, st24, st25, st26, st27, st28, st29, st30, st31, st32, st33, st34, st35, st36, st37, st38, st39, st40, st41, st42, st43, st44, st45, st46, st47, st48, st49, st50, st51, st52, st53, st54, st55, st56, st57, st58, st59, st60, st61, st62, st63, st64, st65, st66, st67, st68, st69, st70, st71, st72, st73, st74, st75, st76, st77, st78, st79, st80, st81, st82, st83, st84, st85, st86, st87, st88, st89, st90, st91, st92, st93 }; DfaState accepts[95] = { 0, 1, 2, 3, 4, 33, 33, 33, 33, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 0, 2, 5, 11, 12, 32, 31, 30, 29, 27, 28, 24, 26, 6, 0, 0, 24, 26, 6, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 10, 0, 0, 9, 0, 34, 36, 38, 39, 42, 42, 35, 37, 41, 40, 0, 43, 46, 46, 45, 44, 0, 47, 48, 49, 0 }; void (*actions[50])() = { zzerraction, act1, act2, act3, act4, act5, act6, act7, act8, act9, act10, act11, act12, act13, act14, act15, act16, act17, act18, act19, act20, act21, act22, act23, act24, act25, act26, act27, act28, act29, act30, act31, act32, act33, act34, act35, act36, act37, act38, act39, act40, act41, act42, act43, act44, act45, act46, act47, act48, act49 }; static DfaState dfa_base[] = { 0, 73, 84, 90 }; static unsigned char *b_class_no[] = { shift0, shift1, shift2, shift3 }; #define ZZSHIFT(c) (b_class_no[zzauto][1+c]) #define MAX_MODE 4 #include "dlgauto.h" cdrdao-cdrdao-f00afb2/pccts/dlg/dlg_p.c000066400000000000000000000503431511453746600200160ustar00rootroot00000000000000/* * A n t l r T r a n s l a t i o n H e a d e r * * Terence Parr, Will Cohen, and Hank Dietz: 1989-2001 * Purdue University Electrical Engineering * With AHPCRC, University of Minnesota * ANTLR Version 1.33MR32 * * ..\bin\antlr dlg_p.g -gh * */ #define ANTLR_VERSION 13332 #include "pcctscfg.h" #include "pccts_stdio.h" #include #include "dlg.h" #define zzSET_SIZE 8 #include "antlr.h" #include "tokens.h" #include "dlgdef.h" #include "mode.h" /* MR23 In order to remove calls to PURIFY use the antlr -nopurify option */ #ifndef PCCTS_PURIFY #define PCCTS_PURIFY(r,s) memset((char *) &(r),'\0',(s)); #endif ANTLR_INFO /* MR20 G. Hobbelt Fix for Borland C++ 4.x & 5.x compiling with ALL warnings enabled */ #ifdef __TURBOC__ #pragma warn -aus /* unused assignment of 'xxx' */ #endif int action_no = 0; /* keep track of actions outputed */ int nfa_allocated = 0; /* keeps track of number of nfa nodes */ nfa_node **nfa_array = NULL;/* root of binary tree that stores nfa array */ nfa_node nfa_model_node; /* model to initialize new nodes */ set used_chars; /* used to label trans. arcs */ set used_classes; /* classes or chars used to label trans. arcs */ set normal_chars; /* mask to get rid elements that aren't used in set */ int flag_paren = FALSE; int flag_brace = FALSE; int mode_counter = 0; /* keep track of number of %%names */ void #ifdef __USE_PROTOS grammar(void) #else grammar() #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { p_head(); p_class_hdr(); func_action = FALSE; { zzBLOCK(zztasp2); zzMake0; { while ( (setwd1[LA(1)]&0x1) ) { { zzBLOCK(zztasp3); zzMake0; { if ( (LA(1)==LEXACTION) ) { zzmatch(LEXACTION); zzCONSUME; } else { if ( (LA(1)==LEXMEMBER) ) { zzmatch(LEXMEMBER); zzCONSUME; } else { if ( (LA(1)==LEXPREFIX) ) { zzmatch(LEXPREFIX); zzCONSUME; } else { if ( (LA(1)==PARSERCLASS) ) { zzmatch(PARSERCLASS); zzCONSUME; } else { if ( (LA(1)==ACTION) ) { } else {zzFAIL(1,zzerr1,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } } } } zzEXIT(zztasp3); } } zzmatch(ACTION); zzCONSUME; zzLOOP(zztasp2); } zzEXIT(zztasp2); } } if ( gen_cpp ) p_includes(); start_states(); func_action = FALSE; p_tables(); p_tail(); { zzBLOCK(zztasp2); zzMake0; { while ( (LA(1)==ACTION) ) { zzmatch(ACTION); zzCONSUME; zzLOOP(zztasp2); } zzEXIT(zztasp2); } } zzmatch(1); if (firstLexMember != 0) p_class_def1(); zzCONSUME; zzEXIT(zztasp1); return; fail: zzEXIT(zztasp1); zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd1, 0x2); } } void #ifdef __USE_PROTOS start_states(void) #else start_states() #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { { zzBLOCK(zztasp2); zzMake0; { if ( (LA(1)==PER_PER) ) { zzmatch(PER_PER); zzCONSUME; do_conversion(); } else { if ( (LA(1)==NAME_PER_PER) ) { zzmatch(NAME_PER_PER); zzCONSUME; do_conversion(); { zzBLOCK(zztasp3); zzMake0; { while ( (LA(1)==NAME_PER_PER) ) { zzmatch(NAME_PER_PER); zzCONSUME; do_conversion(); zzLOOP(zztasp3); } zzEXIT(zztasp3); } } } else {zzFAIL(1,zzerr2,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } zzmatch(PER_PER); zzCONSUME; zzEXIT(zztasp1); return; fail: zzEXIT(zztasp1); zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd1, 0x4); } } void #ifdef __USE_PROTOS do_conversion(void) #else do_conversion() #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { new_automaton_mode(); func_action = TRUE; rule_list(); dfa_class_nop[mode_counter] = relabel(zzaArg(zztasp1,1 ).l,comp_level); if (comp_level) p_shift_table(mode_counter); dfa_basep[mode_counter] = dfa_allocated+1; make_dfa_model_node(dfa_class_nop[mode_counter]); nfa_to_dfa(zzaArg(zztasp1,1 ).l); ++mode_counter; func_action = FALSE; #ifdef HASH_STAT fprint_hash_stats(stderr); #endif zzEXIT(zztasp1); return; } } void #ifdef __USE_PROTOS rule_list(void) #else rule_list() #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { if ( (setwd1[LA(1)]&0x10) ) { rule(); zzaRet.l=zzaArg(zztasp1,1 ).l; zzaRet.r=zzaArg(zztasp1,1 ).r; { zzBLOCK(zztasp2); zzMake0; { while ( (setwd1[LA(1)]&0x20) ) { rule(); {nfa_node *t1; t1 = new_nfa_node(); (t1)->trans[0]=zzaRet.l; (t1)->trans[1]=zzaArg(zztasp2,1 ).l; /* all accept nodes "dead ends" */ zzaRet.l=t1; zzaRet.r=NULL; } zzLOOP(zztasp2); } zzEXIT(zztasp2); } } } else { if ( (setwd1[LA(1)]&0x40) ) { zzaRet.l = new_nfa_node(); zzaRet.r = NULL; warning("no regular expressions", zzline); } else {zzFAIL(1,zzerr3,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp1); return; fail: zzEXIT(zztasp1); zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd1, 0x80); } } void #ifdef __USE_PROTOS rule(void) #else rule() #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { if ( (setwd2[LA(1)]&0x1) ) { reg_expr(); zzmatch(ACTION); if (zzaArg(zztasp1,1 ).r != NULL) { zzaRet.l=zzaArg(zztasp1,1 ).l; zzaRet.r=zzaArg(zztasp1,1 ).r; (zzaArg(zztasp1,1 ).r)->accept=action_no; } zzCONSUME; } else { if ( (LA(1)==ACTION) ) { zzmatch(ACTION); zzaRet.l = NULL; zzaRet.r = NULL; error("no expression for action ", zzline); zzCONSUME; } else {zzFAIL(1,zzerr4,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp1); return; fail: zzEXIT(zztasp1); zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd2, 0x2); } } void #ifdef __USE_PROTOS reg_expr(void) #else reg_expr() #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { and_expr(); zzaRet.l=zzaArg(zztasp1,1 ).l; zzaRet.r=zzaArg(zztasp1,1 ).r; { zzBLOCK(zztasp2); zzMake0; { while ( (LA(1)==OR) ) { zzmatch(OR); zzCONSUME; and_expr(); {nfa_node *t1, *t2; t1 = new_nfa_node(); t2 = new_nfa_node(); (t1)->trans[0]=zzaRet.l; (t1)->trans[1]=zzaArg(zztasp2,2 ).l; /* MR23 */ if (zzaRet.r != NULL) (zzaRet.r)->trans[1]=t2; if (zzaArg(zztasp2,2 ).r) { (zzaArg(zztasp2,2 ).r)->trans[1]=t2; /* MR20 */ } zzaRet.l=t1; zzaRet.r=t2; } zzLOOP(zztasp2); } zzEXIT(zztasp2); } } zzEXIT(zztasp1); return; fail: zzEXIT(zztasp1); zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd2, 0x4); } } void #ifdef __USE_PROTOS and_expr(void) #else and_expr() #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { repeat_expr(); zzaRet.l=zzaArg(zztasp1,1 ).l; zzaRet.r=zzaArg(zztasp1,1 ).r; { zzBLOCK(zztasp2); zzMake0; { while ( (setwd2[LA(1)]&0x8) ) { repeat_expr(); if (zzaRet.r != NULL) { (zzaRet.r)->trans[1]=zzaArg(zztasp2,1 ).l; zzaRet.r=zzaArg(zztasp2,1 ).r; } zzLOOP(zztasp2); } zzEXIT(zztasp2); } } zzEXIT(zztasp1); return; } } void #ifdef __USE_PROTOS repeat_expr(void) #else repeat_expr() #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { if ( (setwd2[LA(1)]&0x20) ) { expr(); zzaRet.l=zzaArg(zztasp1,1 ).l; zzaRet.r=zzaArg(zztasp1,1 ).r; { zzBLOCK(zztasp2); zzMake0; { if ( (LA(1)==ZERO_MORE) ) { zzmatch(ZERO_MORE); { nfa_node *t1,*t2; /* MR23 */ if (zzaRet.r != NULL) (zzaRet.r)->trans[0] = zzaRet.l; t1 = new_nfa_node(); t2 = new_nfa_node(); t1->trans[0]=zzaRet.l; t1->trans[1]=t2; /* MR23 */ if (zzaRet.r != NULL) (zzaRet.r)->trans[1]=t2; zzaRet.l=t1;zzaRet.r=t2; } zzCONSUME; } else { if ( (LA(1)==ONE_MORE) ) { zzmatch(ONE_MORE); if (zzaRet.r != NULL) (zzaRet.r)->trans[0] = zzaRet.l; zzCONSUME; } else { if ( (setwd2[LA(1)]&0x40) ) { } else {zzFAIL(1,zzerr5,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } } zzEXIT(zztasp2); } } } else { if ( (LA(1)==ZERO_MORE) ) { zzmatch(ZERO_MORE); error("no expression for *", zzline); zzCONSUME; } else { if ( (LA(1)==ONE_MORE) ) { zzmatch(ONE_MORE); error("no expression for +", zzline); zzCONSUME; } else {zzFAIL(1,zzerr6,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } } zzEXIT(zztasp1); return; fail: zzEXIT(zztasp1); zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd2, 0x80); } } void #ifdef __USE_PROTOS expr(void) #else expr() #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { zzaRet.l = new_nfa_node(); zzaRet.r = new_nfa_node(); if ( (LA(1)==L_BRACK) ) { zzmatch(L_BRACK); zzCONSUME; atom_list(); zzmatch(R_BRACK); /* MR23 */ if (zzaRet.l != NULL) { (zzaRet.l)->trans[0] = zzaRet.r; (zzaRet.l)->label = set_dup(zzaArg(zztasp1,2 ).label); set_orin(&used_chars,(zzaRet.l)->label); } zzCONSUME; } else { if ( (LA(1)==NOT) ) { zzmatch(NOT); zzCONSUME; zzmatch(L_BRACK); zzCONSUME; atom_list(); zzmatch(R_BRACK); /* MR23 */ if (zzaRet.l != NULL) { (zzaRet.l)->trans[0] = zzaRet.r; (zzaRet.l)->label = set_dif(normal_chars,zzaArg(zztasp1,3 ).label); set_orin(&used_chars,(zzaRet.l)->label); } zzCONSUME; } else { if ( (LA(1)==L_PAR) ) { zzmatch(L_PAR); zzCONSUME; reg_expr(); zzmatch(R_PAR); /* MR23 */ if (zzaRet.l != NULL) { (zzaRet.l)->trans[0] = zzaArg(zztasp1,2 ).l; if (zzaArg(zztasp1,2 ).r) { (zzaArg(zztasp1,2 ).r)->trans[1] = zzaRet.r; /* MR20 */ } } zzCONSUME; } else { if ( (LA(1)==L_BRACE) ) { zzmatch(L_BRACE); zzCONSUME; reg_expr(); zzmatch(R_BRACE); /* MR23 */ if (zzaRet.l != NULL) { (zzaRet.l)->trans[0] = zzaArg(zztasp1,2 ).l; (zzaRet.l)->trans[1] = zzaRet.r; if (zzaArg(zztasp1,2 ).r) { (zzaArg(zztasp1,2 ).r)->trans[1] = zzaRet.r; /* MR20 */ } } zzCONSUME; } else { if ( (setwd3[LA(1)]&0x1) ) { atom(); /* MR23 */ if (zzaRet.l != NULL) { (zzaRet.l)->trans[0] = zzaRet.r; (zzaRet.l)->label = set_dup(zzaArg(zztasp1,1 ).label); set_orin(&used_chars,(zzaRet.l)->label); } } else {zzFAIL(1,zzerr7,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } } } } zzEXIT(zztasp1); return; fail: zzEXIT(zztasp1); zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd3, 0x2); } } void #ifdef __USE_PROTOS atom_list(void) #else atom_list() #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { set_free(zzaRet.label); { zzBLOCK(zztasp2); zzMake0; { while ( (setwd3[LA(1)]&0x4) ) { near_atom(); set_orin(&(zzaRet.label),zzaArg(zztasp2,1 ).label); zzLOOP(zztasp2); } zzEXIT(zztasp2); } } zzEXIT(zztasp1); return; } } void #ifdef __USE_PROTOS near_atom(void) #else near_atom() #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { register int i; register int i_prime; anychar(); zzaRet.letter=zzaArg(zztasp1,1 ).letter; zzaRet.label=set_of(zzaArg(zztasp1,1 ).letter); i_prime = zzaArg(zztasp1,1 ).letter + MIN_CHAR; if (case_insensitive && islower(i_prime)) set_orel(toupper(i_prime)-MIN_CHAR, &(zzaRet.label)); if (case_insensitive && isupper(i_prime)) set_orel(tolower(i_prime)-MIN_CHAR, &(zzaRet.label)); { zzBLOCK(zztasp2); zzMake0; { if ( (LA(1)==RANGE) ) { zzmatch(RANGE); zzCONSUME; anychar(); if (case_insensitive){ i_prime = zzaRet.letter+MIN_CHAR; zzaRet.letter = (islower(i_prime) ? toupper(i_prime) : i_prime)-MIN_CHAR; i_prime = zzaArg(zztasp2,2 ).letter+MIN_CHAR; zzaArg(zztasp2,2 ).letter = (islower(i_prime) ? toupper(i_prime) : i_prime)-MIN_CHAR; } /* check to see if range okay */ { int debugLetter1 = zzaRet.letter; int debugLetter2 = zzaArg(zztasp2,2 ).letter; } if (zzaRet.letter > zzaArg(zztasp2,2 ).letter && zzaArg(zztasp2,2 ).letter != 0xff){ /* MR16 */ error("invalid range ", zzline); } for (i=zzaRet.letter; i<= (int)zzaArg(zztasp2,2 ).letter; ++i){ set_orel(i,&(zzaRet.label)); i_prime = i+MIN_CHAR; if (case_insensitive && islower(i_prime)) set_orel(toupper(i_prime)-MIN_CHAR, &(zzaRet.label)); if (case_insensitive && isupper(i_prime)) set_orel(tolower(i_prime)-MIN_CHAR, &(zzaRet.label)); } } else { if ( (setwd3[LA(1)]&0x10) ) { } else {zzFAIL(1,zzerr8,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } zzEXIT(zztasp2); } } zzEXIT(zztasp1); return; fail: zzEXIT(zztasp1); zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd3, 0x20); } } void #ifdef __USE_PROTOS atom(void) #else atom() #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { register int i_prime; anychar(); zzaRet.label = set_of(zzaArg(zztasp1,1 ).letter); i_prime = zzaArg(zztasp1,1 ).letter + MIN_CHAR; if (case_insensitive && islower(i_prime)) set_orel(toupper(i_prime)-MIN_CHAR, &(zzaRet.label)); if (case_insensitive && isupper(i_prime)) set_orel(tolower(i_prime)-MIN_CHAR, &(zzaRet.label)); zzEXIT(zztasp1); return; } } void #ifdef __USE_PROTOS anychar(void) #else anychar() #endif { zzRULE; zzBLOCK(zztasp1); zzMake0; { if ( (LA(1)==REGCHAR) ) { zzmatch(REGCHAR); zzaRet.letter = zzaArg(zztasp1,1 ).letter - MIN_CHAR; zzCONSUME; } else { if ( (LA(1)==OCTAL_VALUE) ) { zzmatch(OCTAL_VALUE); zzaRet.letter = zzaArg(zztasp1,1 ).letter - MIN_CHAR; zzCONSUME; } else { if ( (LA(1)==HEX_VALUE) ) { zzmatch(HEX_VALUE); zzaRet.letter = zzaArg(zztasp1,1 ).letter - MIN_CHAR; zzCONSUME; } else { if ( (LA(1)==DEC_VALUE) ) { zzmatch(DEC_VALUE); zzaRet.letter = zzaArg(zztasp1,1 ).letter - MIN_CHAR; zzCONSUME; } else { if ( (LA(1)==TAB) ) { zzmatch(TAB); zzaRet.letter = zzaArg(zztasp1,1 ).letter - MIN_CHAR; zzCONSUME; } else { if ( (LA(1)==NL) ) { zzmatch(NL); zzaRet.letter = zzaArg(zztasp1,1 ).letter - MIN_CHAR; zzCONSUME; } else { if ( (LA(1)==CR) ) { zzmatch(CR); zzaRet.letter = zzaArg(zztasp1,1 ).letter - MIN_CHAR; zzCONSUME; } else { if ( (LA(1)==BS) ) { zzmatch(BS); zzaRet.letter = zzaArg(zztasp1,1 ).letter - MIN_CHAR; zzCONSUME; } else { if ( (LA(1)==LIT) ) { zzmatch(LIT); zzaRet.letter = zzaArg(zztasp1,1 ).letter - MIN_CHAR; zzCONSUME; } else { if ( (LA(1)==L_EOF) ) { zzmatch(L_EOF); zzaRet.letter = 0; zzCONSUME; } else {zzFAIL(1,zzerr9,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;} } } } } } } } } } zzEXIT(zztasp1); return; fail: zzEXIT(zztasp1); /* empty action */ zzsyn(zzMissText, zzBadTok, (ANTLRChar *)"", zzMissSet, zzMissTok, zzErrk, zzBadText); zzresynch(setwd3, 0x80); } } /* adds a new nfa to the binary tree and returns a pointer to it */ nfa_node * #ifdef __USE_PROTOS new_nfa_node(void) #else new_nfa_node() #endif { register nfa_node *t; static int nfa_size=0; /* elements nfa_array[] can hold */ ++nfa_allocated; if (nfa_size<=nfa_allocated){ /* need to redo array */ if (!nfa_array){ /* need some to do inital allocation */ nfa_size=nfa_allocated+NFA_MIN; nfa_array=(nfa_node **) malloc(sizeof(nfa_node*)* nfa_size); }else{ /* need more space */ nfa_size=2*(nfa_allocated+1); nfa_array=(nfa_node **) realloc(nfa_array, sizeof(nfa_node*)*nfa_size); } } /* fill out entry in array */ t = (nfa_node*) malloc(sizeof(nfa_node)); nfa_array[nfa_allocated] = t; *t = nfa_model_node; t->node_no = nfa_allocated; return t; } /* initialize the model node used to fill in newly made nfa_nodes */ void #ifdef __USE_PROTOS make_nfa_model_node(void) #else make_nfa_model_node() #endif { nfa_model_node.node_no = -1; /* impossible value for real nfa node */ nfa_model_node.nfa_set = 0; nfa_model_node.accept = 0; /* error state default*/ nfa_model_node.trans[0] = NULL; nfa_model_node.trans[1] = NULL; nfa_model_node.label = empty; } #if defined(DEBUG) || defined(_DEBUG) /* print out the pointer value and the node_number */ void #ifdef __USE_PROTOS fprint_dfa_pair(FILE *f, nfa_node *p) #else fprint_dfa_pair(f, p) FILE *f; nfa_node *p; #endif { if (p){ fprintf(f, "%x (%d)", p, p->node_no); }else{ fprintf(f, "(nil)"); } } /* print out interest information on a set */ void #ifdef __USE_PROTOS fprint_set(FILE *f, set s) #else fprint_set(f,s) FILE *f; set s; #endif { unsigned int *x; fprintf(f, "n = %d,", s.n); if (s.setword){ fprintf(f, "setword = %x, ", s.setword); /* print out all the elements in the set */ x = set_pdq(s); while (*x!=nil){ fprintf(f, "%d ", *x); ++x; } }else{ fprintf(f, "setword = (nil)"); } } /* code to be able to dump out the nfas return 0 if okay dump return 1 if screwed up */ int #ifdef __USE_PROTOS dump_nfas(int first_node, int last_node) #else dump_nfas(first_node, last_node) int first_node; int last_node; #endif { register int i; nfa_node *t; for (i=first_node; i<=last_node; ++i){ t = NFA(i); if (!t) break; fprintf(stderr, "nfa_node %d {\n", t->node_no); fprintf(stderr, "\n\tnfa_set = %d\n", t->nfa_set); fprintf(stderr, "\taccept\t=\t%d\n", t->accept); fprintf(stderr, "\ttrans\t=\t("); fprint_dfa_pair(stderr, t->trans[0]); fprintf(stderr, ","); fprint_dfa_pair(stderr, t->trans[1]); fprintf(stderr, ")\n"); fprintf(stderr, "\tlabel\t=\t{ "); fprint_set(stderr, t->label); fprintf(stderr, "\t}\n"); fprintf(stderr, "}\n\n"); } return 0; } #endif /* DLG-specific syntax error message generator * (define USER_ZZSYN when compiling so don't get 2 definitions) */ void #ifdef __USE_PROTOS zzsyn(char *text, int tok, char *egroup, SetWordType *eset, int etok, int k, char *bad_text) #else zzsyn(text, tok, egroup, eset, etok, k, bad_text) char *text, *egroup, *bad_text; int tok; int etok; int k; SetWordType *eset; #endif { fprintf(stderr, ErrHdr, file_str[0]!=NULL?file_str[0]:"stdin", zzline); fprintf(stderr, " syntax error at \"%s\"", (tok==zzEOF_TOKEN)?"EOF":text); if ( !etok && !eset ) {fprintf(stderr, "\n"); return;} if ( k==1 ) fprintf(stderr, " missing"); else { fprintf(stderr, "; \"%s\" not", bad_text); if ( zzset_deg(eset)>1 ) fprintf(stderr, " in"); } if ( zzset_deg(eset)>0 ) zzedecode(eset); else fprintf(stderr, " %s", zztokens[etok]); if ( strlen(egroup) > (size_t)0 ) fprintf(stderr, " in %s", egroup); fprintf(stderr, "\n"); } cdrdao-cdrdao-f00afb2/pccts/dlg/err.c000066400000000000000000000053121511453746600175150ustar00rootroot00000000000000/* * A n t l r S e t s / E r r o r F i l e H e a d e r * * Generated from: dlg_p.g * * Terence Parr, Russell Quong, Will Cohen, and Hank Dietz: 1989-2001 * Parr Research Corporation * with Purdue University Electrical Engineering * With AHPCRC, University of Minnesota * ANTLR Version 1.33MR32 */ #define ANTLR_VERSION 13332 #include "pcctscfg.h" #include "pccts_stdio.h" #include #include "dlg.h" #define zzSET_SIZE 8 #include "antlr.h" #include "tokens.h" #include "dlgdef.h" #include "err.h" ANTLRChar *zztokens[46]={ /* 00 */ "Invalid", /* 01 */ "@", /* 02 */ "[\\r\\t\\ ]+", /* 03 */ "\\n", /* 04 */ "L_EOF", /* 05 */ "PER_PER", /* 06 */ "NAME_PER_PER", /* 07 */ "LEXMEMBER", /* 08 */ "LEXACTION", /* 09 */ "PARSERCLASS", /* 10 */ "LEXPREFIX", /* 11 */ "ACTION", /* 12 */ "GREAT_GREAT", /* 13 */ "L_BRACE", /* 14 */ "R_BRACE", /* 15 */ "L_PAR", /* 16 */ "R_PAR", /* 17 */ "L_BRACK", /* 18 */ "R_BRACK", /* 19 */ "ZERO_MORE", /* 20 */ "ONE_MORE", /* 21 */ "OR", /* 22 */ "RANGE", /* 23 */ "NOT", /* 24 */ "OCTAL_VALUE", /* 25 */ "HEX_VALUE", /* 26 */ "DEC_VALUE", /* 27 */ "TAB", /* 28 */ "NL", /* 29 */ "CR", /* 30 */ "BS", /* 31 */ "CONTINUATION", /* 32 */ "LIT", /* 33 */ "REGCHAR", /* 34 */ "\\>", /* 35 */ "\\\\>", /* 36 */ "\\", /* 37 */ "\\n", /* 38 */ "/\\*", /* 39 */ "//", /* 40 */ "~[]", /* 41 */ "\\*/", /* 42 */ "[\\n\\r]", /* 43 */ "~[]", /* 44 */ "[\\n\\r]", /* 45 */ "~[]" }; SetWordType zzerr1[8] = {0x80,0xf,0x0,0x0, 0x0,0x0,0x0,0x0}; SetWordType zzerr2[8] = {0x60,0x0,0x0,0x0, 0x0,0x0,0x0,0x0}; SetWordType zzerr3[8] = {0x70,0xa8,0x9a,0x7f, 0x3,0x0,0x0,0x0}; SetWordType setwd1[46] = {0x0,0x6,0x0,0x0,0x30,0xc8,0xc8, 0x1,0x1,0x1,0x1,0x35,0x0,0x30,0x0, 0x30,0x0,0x30,0x0,0x30,0x30,0x0,0x0, 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, 0x0,0x30,0x30,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0}; SetWordType zzerr4[8] = {0x10,0xa8,0x9a,0x7f, 0x3,0x0,0x0,0x0}; SetWordType zzerr5[8] = {0x10,0xe8,0xbb,0x7f, 0x3,0x0,0x0,0x0}; SetWordType zzerr6[8] = {0x10,0xa0,0x9a,0x7f, 0x3,0x0,0x0,0x0}; SetWordType setwd2[46] = {0x0,0x0,0x0,0x0,0xeb,0x2,0x2, 0x0,0x0,0x0,0x0,0xd6,0x0,0xeb,0xd4, 0xeb,0xd4,0xeb,0x0,0xcb,0xcb,0xd0,0x0, 0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb,0xeb, 0x0,0xeb,0xeb,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0}; SetWordType zzerr7[8] = {0x10,0xa0,0x82,0x7f, 0x3,0x0,0x0,0x0}; SetWordType zzerr8[8] = {0x10,0x0,0x44,0x7f, 0x3,0x0,0x0,0x0}; SetWordType zzerr9[8] = {0x10,0x0,0x0,0x7f, 0x3,0x0,0x0,0x0}; SetWordType setwd3[46] = {0x0,0x0,0x0,0x0,0xf7,0x0,0x0, 0x0,0x0,0x0,0x0,0xc2,0x0,0xc2,0xc2, 0xc2,0xc2,0xc2,0xb8,0xc2,0xc2,0xc2,0x80, 0xc2,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7, 0x0,0xf7,0xf7,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0}; cdrdao-cdrdao-f00afb2/pccts/dlg/main.c000066400000000000000000000170301511453746600176510ustar00rootroot00000000000000/* Main function for dlg version * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * DLG 1.33 * Will Cohen * With mods by Terence Parr; AHPCRC, University of Minnesota * 1989-2001 */ #include #include "stdpccts.h" char program[] = "dlg"; char version[] = "1.33MR32"; /* MRXXX */ int numfiles = 0; char *file_str[2] = {NULL, NULL}; char *mode_file = "mode.h"; char *class_name = DEFAULT_CLASSNAME; char *OutputDirectory = TopDirectory; /* Option variables */ int comp_level = 0; int interactive = FALSE; int case_insensitive = FALSE; int warn_ambig = FALSE; int gen_cpp = FALSE; #ifdef __USE_PROTOS static int ci_strequ(char *a,char *b) #else static int ci_strequ(a,b) char *a; char *b; #endif { for ( ;*a != 0 && *b != 0; a++, b++) { if (toupper(*a) != toupper(*b)) return 0; } return (*a == *b); } /* Option List Stuff */ #ifdef __USE_PROTOS void p_comp0(void) {comp_level = 0;} void p_comp1(void) {comp_level = 1;} void p_comp2(void) {comp_level = 2;} void p_stdio(void) { file_str[numfiles++] = NULL;} void p_file(char *s) { file_str[numfiles++] = s;} void p_cl_name(char *s, char *t) { if ( gen_cpp ) { class_name = t; } else { warning("-cl only valid in C++ mode; -cl ignored...",0); } } void p_mode_file(char *s, char *t){mode_file=t;} void p_outdir(char *s,char *t) {OutputDirectory=t;} void p_ansi(void) {gen_ansi = TRUE;} void p_interactive(void) {interactive = TRUE;} void p_case_s(void) { case_insensitive = FALSE; } void p_case_i(void) { case_insensitive = TRUE; } void p_warn_ambig(void) { warn_ambig = TRUE; } void p_cpp(void) { gen_cpp = TRUE; } #else void p_comp0() {comp_level = 0;} void p_comp1() {comp_level = 1;} void p_comp2() {comp_level = 2;} void p_stdio() { file_str[numfiles++] = NULL;} void p_file(s) char *s; { file_str[numfiles++] = s;} void p_cl_name(s,t) char *s, *t; { if ( gen_cpp ) { class_name = t; } else { warning("-cl only valid in C++ mode; -cl ignored...",0); } } void p_mode_file(s,t) char *s,*t;{mode_file=t;} void p_outdir(s,t) char *s,*t;{OutputDirectory=t;} void p_ansi() {gen_ansi = TRUE;} void p_interactive() {interactive = TRUE;} void p_case_s() { case_insensitive = FALSE; } void p_case_i() { case_insensitive = TRUE; } void p_warn_ambig() { warn_ambig = TRUE; } void p_cpp() { gen_cpp = TRUE; } #endif #ifdef __cplusplus typedef void (*WildFunc)(...); #else typedef void (*WildFunc)(); #endif typedef struct { char *option; int arg; WildFunc process; char *descr; } Opt; Opt options[] = { { "-CC", 0, (WildFunc)p_cpp, "Generate C++ output" }, { "-C0", 0, (WildFunc)p_comp0, "No compression (default)" }, { "-C1", 0, (WildFunc)p_comp1, "Compression level 1" }, { "-C2", 0, (WildFunc)p_comp2, "Compression level 2" }, { "-ga", 0, (WildFunc)p_ansi, "Generate ansi C"}, { "-Wambiguity", 0, (WildFunc)p_warn_ambig, "Warn if expressions ambiguous"}, { "-m", 1, (WildFunc)p_mode_file, "Rename lexical mode output file"}, { "-i", 0, (WildFunc)p_interactive, "Build interactive scanner (not valid for C++ mode)"}, { "-ci", 0, (WildFunc)p_case_i, "Make lexical analyzer case insensitive"}, { "-cl", 1, (WildFunc)p_cl_name, "Rename lexer class (DLGLexer); only used for -CC"}, { "-cs", 0, (WildFunc)p_case_s, "Make lexical analyzer case sensitive (default)"}, { "-o", 1, (WildFunc)p_outdir, OutputDirectoryOption}, { "-", 0, (WildFunc)p_stdio, "Use standard i/o rather than file"}, { "*", 0, (WildFunc)p_file, ""}, /* anything else is a file */ { NULL, 0, NULL } }; #ifdef __USE_PROTOS void ProcessArgs(int argc, char **argv, Opt *options) #else void ProcessArgs(argc, argv, options) int argc; char **argv; Opt *options; #endif { Opt *p; while ( argc-- > 0 ) { p = options; while ( p->option != NULL ) { if ( strcmp(p->option, "*") == 0 || ci_strequ(p->option,*argv) ) { if ( p->arg ) { (*p->process)( *argv, *(argv+1) ); argv++; argc--; } else (*p->process)( *argv ); break; } p++; } argv++; } } #ifdef __USE_PROTOS int main(int argc, char *argv[]) #else int main(argc, argv) int argc; char *argv[]; #endif { init(); fprintf(stderr, "%s Version %s 1989-2001\n", &(program[0]), &(version[0])); if ( argc == 1 ) { Opt *p = options; fprintf(stderr, "%s [options] f1 f2 ... fn\n",argv[0]); while ( *(p->option) != '*' ) { fprintf(stderr, "\t%s %s\t%s\n", p->option, (p->arg)?"___":" ", p->descr); p++; } }else{ ProcessArgs(argc-1, &(argv[1]), options); if (interactive && gen_cpp) { fprintf(stderr,"\n"); /*** MR21a This statement is wrong ! ***/ #if 0 *** fprintf(stderr,"Interactive lexer option (\"-i\") has no effect when in C++ mode\n"); *** fprintf(stderr,"because of extra buffering provided by ANTLRTokenBuffer class.\n"); *** fprintf(stderr,"\n"); #endif } input_stream = read_stream(file_str[0]); if (input_stream) { /* don't overwrite unless input okay */ if ( gen_cpp ) { output_stream = write_stream(ClassName(CPP_FILE_SUFFIX)); if ( file_str[1]!=NULL ) { warning("output file implicit in C++ mode; ignored...",0); } class_stream = write_stream(ClassName(".h")); mode_stream = class_stream; } else { output_stream = write_stream(file_str[1]); mode_stream = write_stream(mode_file); } } /* make sure that error reporting routines in grammar know what the file really is */ /* make sure that reading and writing somewhere */ if (input_stream && output_stream && mode_stream){ ANTLR(grammar(), input_stream); } p_class_def2(); /* MR1 */ } if ( output_stream!=NULL ) fclose(output_stream); if ( !gen_cpp && mode_stream!=NULL ) fclose(mode_stream); if ( class_stream!=NULL ) fclose(class_stream); exit(PCCTS_EXIT_SUCCESS); return 0; /* get rid of warning message MR1 */ } /* initialize all the variables */ void #ifdef __USE_PROTOS init(void) #else init() #endif { register int i; #ifdef SPECIAL_INITS special_inits(); /* MR1 */ #endif used_chars = empty; used_classes = empty; /* make the valid character set */ normal_chars = empty; /* NOTE: MIN_CHAR is EOF */ /* NOTE: EOF is not quite a valid char, it is special. Skip it*/ for (i = 1; i #include #include "dlg.h" #ifdef MEMCHK #include "trax.h" #else #ifdef __STDC__ #include #else #include #endif /* __STDC__ */ #endif static char *mode_name[MAX_MODES]; static int mode_number[MAX_MODES]; static int cur_mode=0; int operation_no = 0; /* used to mark nodes so that infinite loops avoided */ int dfa_basep[MAX_MODES]; /* start of each group of states */ int dfa_class_nop[MAX_MODES]; /* number of elements in each group of states*/ int gen_ansi = FALSE; /* allows ansi code to be generated */ FILE *input_stream; /* where to read description from */ FILE *output_stream; /* where to put the output */ FILE *mode_stream; /* where to put the mode.h stuff */ FILE *class_stream; /* where to put the scan.h stuff (if gen_cpp) */ /* NOTE: This section is MACHINE DEPENDENT */ #define DIF_SIZE 4 #if defined(PC) && !defined(PC32) unsigned long typesize[DIF_SIZE] = { 0x7f, 0x7fff, 0x7ffful, 0x7ffffffful }; /* MR20 */ char t0[] = "unsigned char"; char t1[] = "unsigned short"; char t2[] = "unsigned int"; char t3[] = "unsigned long"; char *typevar[DIF_SIZE] = { t0, t1, t2, t3}; #else unsigned long typesize[DIF_SIZE] = { 0x7f, 0x7fff, 0x7ffffffful, 0x7ffffffful }; /* MR20 */ char t0[] = "unsigned char"; char t1[] = "unsigned short"; char t2[] = "unsigned int"; char t3[] = "unsigned long"; char *typevar[DIF_SIZE] = { t0, t1, t2, t3}; #endif /* Added by TJP August 1994 */ /* Take in MyLexer and return MyLexer_h */ static char * #ifdef __USE_PROTOS gate_symbol(char *name) #else gate_symbol(name) char *name; #endif { static char buf[100]; sprintf(buf, "%s_h", name); return buf; } /* Added by TJP August 1994 */ static char * #ifdef __USE_PROTOS mystrdup(char *s) #else mystrdup(s) char *s; #endif { char *p = (char *)malloc(strlen(s)+1); strcpy(p, s); return p; } #ifdef __USE_PROTOS void p_class_hdr(void) #else void p_class_hdr() #endif { if ( class_stream == NULL ) return; fprintf(class_stream, "#ifndef %s\n", gate_symbol(ClassName(""))); fprintf(class_stream, "#define %s\n", gate_symbol(ClassName(""))); fprintf(class_stream, "/*\n"); fprintf(class_stream, " * D L G L e x e r C l a s s D e f i n i t i o n\n"); fprintf(class_stream, " *\n"); fprintf(class_stream, " * Generated from:"); fprintf(class_stream, " %s", file_str[0]); fprintf(class_stream, "\n"); fprintf(class_stream, " *\n"); fprintf(class_stream, " * 1989-2001 by Will Cohen, Terence Parr, and Hank Dietz\n"); fprintf(class_stream, " * Purdue University Electrical Engineering\n"); fprintf(class_stream, " * DLG Version %s\n", version); fprintf(class_stream, " */\n\n"); fprintf(class_stream, "\n"); fprintf(class_stream, "#include \"%s\"\n", DLEXERBASE_H); } /* MR1 */ /* MR1 16-Apr-97 Split printing of class header up into several parts */ /* MR1 so that #lexprefix <<...>>and #lexmember <<...>> */ /* MR1 can be inserted in the appropriate spots */ /* MR1 */ #ifdef __USE_PROTOS void p_class_def1(void) #else void p_class_def1() #endif { if ( class_stream == NULL ) return; fprintf(class_stream, "\nclass %s : public DLGLexerBase {\n", ClassName("")); fprintf(class_stream, "public:\n"); } #ifdef __USE_PROTOS void p_class_def2(void) #else void p_class_def2() #endif { int i, m; if ( class_stream == NULL ) return; fprintf(class_stream, "public:\n"); fprintf(class_stream, "\tstatic const int MAX_MODE;\n"); fprintf(class_stream, "\tstatic const int DfaStates;\n"); for (i=0; i> */ /* MR1 */ /* MR1 */ fprintf(class_stream,"//\n"); /* MR1 */ fprintf(class_stream, /* MR1 */ "// 133MR1 Deprecated feature to allow inclusion of "); /* MR1 */ fprintf(class_stream, /* MR1 */ "user-defined code in DLG class header\n"); /* MR1 */ fprintf(class_stream,"//\n"); /* MR1 */ /* MR1 */ fprintf(class_stream,"#ifdef DLGLexerIncludeFile\n"); /* MR1 */ fprintf(class_stream,"#include DLGLexerIncludeFile\n"); /* MR1 */ fprintf(class_stream,"#endif\n"); fprintf(class_stream, "};\n"); fprintf(class_stream, "typedef ANTLRTokenType (%s::*Ptr%sMemberFunc)();\n", ClassName(""), ClassName("")); fprintf(class_stream, "#endif\n"); } /* generate required header on output */ #ifdef __USE_PROTOS void p_head(void) #else void p_head() #endif { fprintf(OUT, "/*\n"); fprintf(OUT, " * D L G tables\n"); fprintf(OUT, " *\n"); fprintf(OUT, " * Generated from:"); fprintf(OUT, " %s", file_str[0]); fprintf(OUT, "\n"); fprintf(OUT, " *\n"); fprintf(OUT, " * 1989-2001 by Will Cohen, Terence Parr, and Hank Dietz\n"); fprintf(OUT, " * Purdue University Electrical Engineering\n"); fprintf(OUT, " * DLG Version %s\n", version); fprintf(OUT, " */\n\n"); if ( gen_cpp) fprintf(OUT, "#include \"pcctscfg.h\"\n"); if ( gen_cpp ) fprintf(OUT, "#include \"pccts_stdio.h\"\n"); if ( !gen_cpp ) fprintf(OUT, "#include \"%s\"\n\n", mode_file); fprintf(OUT,"\n"); } #ifdef __USE_PROTOS void p_includes(void) #else void p_includes() #endif { fprintf(OUT, "#include \"%s\"\n", APARSER_H); fprintf(OUT, "#include \"%s\"\n", DLEXERBASE_H); fprintf(OUT, "#include \"%s\"\n", ClassName(".h")); } /* generate code to tie up any loose ends */ #ifdef __USE_PROTOS void p_tail(void) /* MR1 */ #else void p_tail() /* MR1 */ #endif { if ( gen_cpp ) { if ( strcmp(ClassName(""), DEFAULT_CLASSNAME)!=0 ) fprintf(OUT, "#define DLGLexer %s\n", ClassName("")); fprintf(OUT, "#include \"%s\"\n", DLEXER_H); /* MR23 Rename DLexer.cpp to DLexer.h */ return; } fprintf(OUT, "\n"); fprintf(OUT, "\n"); if (comp_level) fprintf(OUT, "#define ZZSHIFT(c) (b_class_no[zzauto][1+c])\n"); else fprintf(OUT, "#define ZZSHIFT(c) (1+c)\n"); if ( !gen_cpp ) fprintf(OUT, "#define MAX_MODE %d\n",mode_counter); fprintf(OUT, "#include \"dlgauto.h\"\n"); } /* output the table of DFA for general use */ #ifdef __USE_PROTOS void p_tables() #else void p_tables() #endif { if ( !gen_cpp ) { fprintf(OUT, "#define DfaStates\t%d\n", dfa_allocated); fprintf(OUT, "typedef %s DfaState;\n\n", minsize(dfa_allocated)); } if ( gen_cpp ) { int i; fprintf(OUT, "\n"); fprintf(OUT, "const int %s::MAX_MODE=%d;\n", ClassName(""), mode_counter); fprintf(OUT, "const int %s::DfaStates=%d;\n", ClassName(""), dfa_allocated); for (i=0; i typesize[i]) /* MR20 */ ++i; return typevar[i]; } #ifdef __USE_PROTOS void p_node_table(void) #else void p_node_table() #endif { register int i; register int m = 0; for(m=0; m<(mode_counter-1); ++m){ for(i=dfa_basep[m]; itrans[j]; if (trans == NIL_INDEX) trans = dfa_allocated+1; /* all of DFA moved down one in array */ fprintf(OUT, "%d", trans-1); fprintf(OUT, ", "); if (!(--items_on_line)){ fprintf(OUT, "\n "); items_on_line = MAX_ON_LINE; } } #if 1 /* put in jump to error state */ fprintf(OUT, "%d\n};\n\n", dfa_allocated); #else fprintf(OUT, "\n};\n\n"); #endif } #ifdef __USE_PROTOS void p_dfa_table(void) #else void p_dfa_table() #endif { register int i; fprintf(OUT, "\n%sDfaState *%sdfa[%d] = {\n", gen_cpp?ClassName("::"):"",gen_cpp?ClassName("::"):"", dfa_allocated); for (i=0; i<(dfa_allocated-1); ++i){ fprintf(OUT, "\tst%d,\n", i); } fprintf(OUT, "\tst%d\n", i); fprintf(OUT, "};\n\n"); } #ifdef __USE_PROTOS void p_accept_table(void) #else void p_accept_table() #endif { register int i = 1; register int items_on_line = 0; int true_interactive = TRUE; /* make sure element for one past (zzerraction) -WEC 12/16/92 */ fprintf(OUT,"\n%sDfaState %saccepts[%d] = {\n ", gen_cpp?ClassName("::"):"", gen_cpp?ClassName("::"):"", dfa_allocated+1); /* don't do anything if no dfa nodes */ if (i>dfa_allocated) goto skip_accepts; for (;;) { int accept=0; /* MR14a - Manuel Kessler (mlkessle@cip.physik.uni-wuerzburg.de) */ set accept_set; set nfa_states; unsigned int *t, *nfa_i; unsigned int *q, *regular_expr; accept_set = empty; nfa_states = DFA(i)->nfa_states; t = nfa_i = set_pdq(nfa_states); /* NOTE: picks lowest accept because accepts monotonic */ /* with respect to nfa node numbers and set_pdq */ /* returns in that order */ while((*nfa_i != nil) && (!(accept = NFA(*nfa_i)->accept))){ nfa_i++; } /* figure out if more than one accept state there */ if (warn_ambig ){ set_orel(accept, &accept_set); while(*nfa_i != nil){ set_orel(NFA(*nfa_i)->accept, &accept_set); nfa_i++; } /* remove error action from consideration */ set_rm(0, accept_set); if( set_deg(accept_set)>1){ fprintf(stderr, "dlg warning: ambiguous regular expression "); q = regular_expr = set_pdq(accept_set); while(*regular_expr != nil){ fprintf(stderr," %d ", *regular_expr); ++regular_expr; } fprintf(stderr, "\n"); free(q); } } if ((DFA(i)->alternatives) && (accept != 0)){ true_interactive = FALSE; } fprintf(OUT, "%d, ", accept); /* free up memory before we "break" below -ATG 4/6/95 */ free(t); set_free(accept_set); if ((++i)>dfa_allocated) break; if ((++items_on_line)>=MAX_ON_LINE){ fprintf(OUT,"\n "); items_on_line = 0; } /* free(t); set_free(accept_set); */ } /* make sure element for one past (zzerraction) -WEC 12/16/92 */ skip_accepts: fprintf(OUT, "0\n};\n\n"); } #ifdef __USE_PROTOS void p_action_table(void) #else void p_action_table() #endif { register int i; char* theClassName = ClassName(""); if ( gen_cpp ) fprintf(OUT, "Ptr%sMemberFunc %s::actions[%d] = {\n", theClassName, theClassName, action_no+1); else fprintf(OUT, "void (*actions[%d])() = {\n", action_no+1); if ( gen_cpp ) /* fprintf(OUT, "\t(Ptr%sMemberFunc)&%s::erraction,\n", theClassName, theClassName);*/ fprintf(OUT, "\t&%s::erraction,\n", theClassName); else fprintf(OUT, "\tzzerraction,\n"); for (i=1; i=CHAR_RANGE) break; fprintf(OUT,", "); if ((++items_on_line)>=MAX_ON_LINE){ fprintf(OUT,"\n "); items_on_line = 0; } } fprintf(OUT, "\n};\n\n"); } #ifdef __USE_PROTOS void p_base_table(void) #else void p_base_table() #endif { register int m; fprintf(OUT, "%sDfaState %sdfa_base[] = {\n", gen_cpp?ClassName("::"):"static ", gen_cpp?ClassName("::"):""); for(m=0; m<(mode_counter-1); ++m) fprintf(OUT, "\t%d,\n", dfa_basep[m]-1); fprintf(OUT, "\t%d\n};\n\n", dfa_basep[m]-1); } #ifdef __USE_PROTOS void p_class_table(void) /* MR1 */ #else void p_class_table() /* MR1 */ #endif { #if 0 register int m; fprintf(OUT,"%s int %sdfa_class_no[] = {\n", gen_cpp?"":"static", gen_cpp?ClassName("::"):""); for(m=0; m<(mode_counter-1); ++m) fprintf(OUT,"\t%d,\n", dfa_class_nop[m]); fprintf(OUT,"\t%d\n};\n\n", dfa_class_nop[m]); #endif } #ifdef __USE_PROTOS void p_bshift_table(void) /* MR1 */ #else void p_bshift_table() /* MR1 */ #endif { register int m; fprintf(OUT,"%s unsigned char *%sb_class_no[] = {\n", gen_cpp?"":"static", gen_cpp?ClassName("::"):""); for(m=0; m<(mode_counter-1); ++m) fprintf(OUT, "\tshift%d,\n", m); fprintf(OUT, "\tshift%d\n};\n\n", m); } #ifdef __USE_PROTOS void p_alternative_table(void) /* MR1 */ #else void p_alternative_table() /* MR1 */ #endif { register int i; if ( !gen_cpp ) fprintf(OUT, "#define ZZINTERACTIVE\n\n"); if ( gen_cpp ) fprintf(OUT, "DLGChar %salternatives[%d] = {\n", /* mr23 vhs %sDfaStates+1 */ ClassName("::"), dfa_allocated+1); /* vhs ClassName("::")); */ else fprintf(OUT, "static %s zzalternatives[DfaStates+1] = {\n", minsize(dfa_allocated)); for(i=1; i<=dfa_allocated; ++i) fprintf(OUT, "\t%d,\n", DFA(i)->alternatives); fprintf(OUT, "/* must have 0 for zzalternatives[DfaStates] */\n"); fprintf(OUT, "\t0\n};\n\n"); } #ifdef __USE_PROTOS void p_mode_def(char *s,int m) /* MR1 */ #else void p_mode_def(s,m) /* MR1 */ char *s; int m; #endif { if ( gen_cpp ) { mode_name[cur_mode] = mystrdup(s); mode_number[cur_mode] = m; cur_mode++; } else fprintf(mode_stream, "#define %s %d\n", s, m); } #ifdef __USE_PROTOS char * ClassName(char *suffix) #else char * ClassName(suffix) char *suffix; #endif { static char buf[200]; extern char *class_name; sprintf(buf, "%s%s", class_name, suffix); return buf; } #ifdef DEBUG /* print out a particular nfa node that is pointed to by p */ #ifdef __USE_PROTOS void p_nfa_node(nfa_node *p) #else void p_nfa_node(p) nfa_node *p; #endif { register nfa_node *t; if (p != NIL_INDEX){ printf("NFA state : %d\naccept state : %d\n", NFA_NO(p),p->accept); if (p->trans[0] != NIL_INDEX){ printf("trans[0] => %d on ", NFA_NO(p->trans[0])); p_set(p->label); printf("\n"); } else printf("trans[0] => nil\n"); if (p->trans[1] != NIL_INDEX) printf("trans[1] => %d on epsilon\n", NFA_NO(p->trans[1])); else printf("trans[1] => nil\n"); printf("\n"); } } #endif #ifdef DEBUG /* code to print out special structures when using a debugger */ #ifdef __USE_PROTOS void p_nfa(p) #else void p_nfa(nfa_node *p) nfa_node *p; /* state number also index into array */ #endif { /* each node has a marker on it so it only gets printed once */ operation_no++; /* get new number */ s_p_nfa(p); } #ifdef __USE_PROTOS void s_p_nfa(nfa_node *p) #else void s_p_nfa(p) nfa_node *p; /* state number also index into array */ #endif { if ((p != NIL_INDEX) && (p->nfa_set != operation_no)){ /* so it is only printed once */ p->nfa_set = operation_no; p_nfa_node(p); s_p_nfa(p->trans[0]); s_p_nfa(p->trans[1]); } } #ifdef __USE_PROTOS void p_dfa_node(dfa_node *p) #else void p_dfa_node(p) dfa_node *p; #endif { int i; if (p != NIL_INDEX){ printf("DFA state :%d\n",NFA_NO(p)); if (p->done) printf("done\n"); else printf("undone\n"); printf("from nfa states : "); p_set(p->nfa_states); printf("\n"); /* NOTE: trans arcs stored as ints rather than pointer*/ for (i=0; itrans[i]); } printf("\n\n"); } } #ifdef __USE_PROTOS void p_dfa(void) #else void p_dfa() #endif { /* prints out all the dfa nodes actually allocated */ int i; for (i = 1; i<=dfa_allocated; i++) p_dfa_node(NFA(i)); } /* print out numbers in the set label */ #ifdef __USE_PROTOS void p_set(set label) #else void p_set(label) set label; #endif { unsigned *t, *e; if (set_nil(label)){ printf("epsilon\n"); }else{ t = e = set_pdq(label); while(*e != nil){ printf("%d ", (*e+MIN_CHAR)); e++; } printf("\n"); free(t); } } #endif cdrdao-cdrdao-f00afb2/pccts/dlg/relabel.c000066400000000000000000000131251511453746600203340ustar00rootroot00000000000000/* This group of functions does the character class compression. It goes over the dfa and relabels the arcs with the partitions of characters in the NFA. The partitions are stored in the array class. * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * DLG 1.33 * Will Cohen * With mods by Terence Parr; AHPCRC, University of Minnesota * 1989-2001 */ #include #include "dlg.h" #ifdef MEMCHK #include "trax.h" #else #ifdef __STDC__ #include #else #include #endif /* __STDC__ */ #endif int class_no = CHAR_RANGE; /* number of classes for labels */ int first_el[CHAR_RANGE]; /* first element in each class partition */ set class_sets[CHAR_RANGE]; /* array holds partitions from class */ /* compression */ /* goes through labels on NFA graph and partitions the characters into * character classes. This reduces the amount of space required for each * dfa node, since only one arc is required each class instead of one arc * for each character * level: * 0 no compression done * 1 remove unused characters from classes * 2 compress equivalent characters into same class * * returns the number of character classes required */ #ifdef __USE_PROTOS int relabel(nfa_node* start,int level) #else int relabel(start,level) int level; nfa_node *start; #endif { if (level){ set_free(used_classes); partition(start,level); label_with_classes(start); }else{ /* classes equivalent to all characters in alphabet */ class_no = CHAR_RANGE; } return class_no; } /* makes character class sets for new labels */ #ifdef __USE_PROTOS void partition(nfa_node* start,int level) #else void partition(start,level) nfa_node *start; /* beginning of nfa graph */ int level; /* compression level to uses */ #endif { set current_class; set unpart_chars; set temp; unpart_chars = set_dup(used_chars); #if 0 /* EOF (-1+1) alway in class 0 */ class_sets[0] = set_of(0); first_el[0] = 0; used_classes = set_of(0); temp = set_dif(unpart_chars, class_sets[0]); set_free(unpart_chars); unpart_chars = temp; class_no = 1; #else class_no = 0; #endif while (!set_nil(unpart_chars)){ /* don't look for equivalent labels if c <= 1 */ if (level <= 1){ current_class = set_of(set_int(unpart_chars)); }else{ current_class = set_dup(unpart_chars); intersect_nfa_labels(start,¤t_class); } set_orel(class_no,&used_classes); first_el[class_no] = set_int(current_class); class_sets[class_no] = current_class; temp = set_dif(unpart_chars,current_class); set_free(unpart_chars); unpart_chars = temp; ++class_no; } /* free unpart_chars -ATG 5/6/95 */ set_free(unpart_chars); #if 0 /* group all the other unused characters into a class */ set_orel(class_no,&used_classes); first_el[class_no] = set_int(current_class); class_sets[class_no] = set_dif(normal_chars,used_chars); ++class_no; #endif } /* given pointer to beginning of graph and recursively walks it trying * to find a maximal partition. This partion in returned in maximal_class */ #ifdef __USE_PROTOS void intersect_nfa_labels(nfa_node* start,set* maximal_class) #else void intersect_nfa_labels(start,maximal_class) nfa_node *start; set *maximal_class; #endif { /* pick a new operation number */ ++operation_no; r_intersect(start,maximal_class); } #ifdef __USE_PROTOS void r_intersect(nfa_node* start,set* maximal_class) #else void r_intersect(start,maximal_class) nfa_node *start; set * maximal_class; #endif { set temp; if(start && start->nfa_set != operation_no) { start->nfa_set = operation_no; temp = set_and(*maximal_class,start->label); if (!set_nil(temp)) { set_free(*maximal_class); *maximal_class = temp; }else{ set_free(temp); } r_intersect(start->trans[0],maximal_class); r_intersect(start->trans[1],maximal_class); } } /* puts class labels in place of old character labels */ #ifdef __USE_PROTOS void label_with_classes(nfa_node* start) #else void label_with_classes(start) nfa_node *start; #endif { ++operation_no; label_node(start); } #ifdef __USE_PROTOS void label_node(nfa_node *start) #else void label_node(start) nfa_node *start; #endif { set new_label; register int i; /* only do node if it hasn't been done before */ if (start && start->nfa_set != operation_no){ start->nfa_set = operation_no; new_label = empty; for (i = 0; ilabel)) set_orel(i,&new_label); } set_free(start->label); start->label = new_label; /* do any nodes that can be reached from this one */ label_node(start->trans[0]); label_node(start->trans[1]); } } cdrdao-cdrdao-f00afb2/pccts/dlg/set.c000066400000000000000000000365101511453746600175240ustar00rootroot00000000000000/* set.c The following is a general-purpose set library originally developed by Hank Dietz and enhanced by Terence Parr to allow dynamic sets. Sets are now structs containing the #words in the set and a pointer to the actual set words. Generally, sets need not be explicitly allocated. They are created/extended/shrunk when appropriate (e.g. in set_of()). HOWEVER, sets need to be destroyed (free()ed) when they go out of scope or are otherwise no longer needed. A routine is provided to free a set. Sets can be explicitly created with set_new(s, max_elem). Sets can be declared to have minimum size to reduce realloc traffic. Default minimum size = 1. Sets can be explicitly initialized to have no elements (set.n == 0) by using the 'empty' initializer: Examples: set a = empty; -- set_deg(a) == 0 return( empty ); Example set creation and destruction: set set_of2(e,g) unsigned e,g; { set a,b,c; b = set_of(e); -- Creates space for b and sticks in e set_new(c, g); -- set_new(); set_orel() ==> set_of() set_orel(g, &c); a = set_or(b, c); . . . set_free(b); set_free(c); return( a ); } 1987 by Hank Dietz Modified by: Terence Parr Purdue University October 1989 Made it smell less bad to C++ 7/31/93 -- TJP */ #include #include "pcctscfg.h" #ifdef __STDC__ #include #else #include #endif #include #include "set.h" #define MIN(i,j) ( (i) > (j) ? (j) : (i)) #define MAX(i,j) ( (i) < (j) ? (j) : (i)) /* elems can be a maximum of 32 bits */ static unsigned bitmask[] = { 0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, 0x00000020, 0x00000040, 0x00000080, 0x00000100, 0x00000200, 0x00000400, 0x00000800, 0x00001000, 0x00002000, 0x00004000, 0x00008000, #if !defined(PC) || defined(PC32) 0x00010000, 0x00020000, 0x00040000, 0x00080000, 0x00100000, 0x00200000, 0x00400000, 0x00800000, 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000 #endif }; set empty = set_init; static unsigned min=1; #define StrSize 200 #ifdef MEMCHK #define CHK(a) \ if ( a.setword != NULL ) \ if ( !valid(a.setword) ) \ {fprintf(stderr, "%s(%d): invalid set\n",__FILE__,__LINE__); exit(-1);} #else #define CHK(a) #endif /* * Set the minimum size (in words) of a set to reduce realloc calls */ void #ifdef __USE_PROTOS set_size( unsigned n ) #else set_size( n ) unsigned n; #endif { min = n; } unsigned int #ifdef __USE_PROTOS set_deg( set a ) #else set_deg( a ) set a; #endif { /* Fast compute degree of a set... the number of elements present in the set. Assumes that all word bits are used in the set and that SETSIZE(a) is a multiple of WORDSIZE. */ register unsigned *p = &(a.setword[0]); register unsigned *endp = NULL; /* MR27 Avoid false memory check report */ register unsigned degree = 0; CHK(a); if ( a.n == 0 ) return(0); endp = &(a.setword[a.n]); while ( p < endp ) { register unsigned t = *p; register unsigned *b = &(bitmask[0]); do { if (t & *b) ++degree; } while (++b < &(bitmask[WORDSIZE])); p++; } return(degree); } set #ifdef __USE_PROTOS set_or( set b, set c ) #else set_or( b, c ) set b; set c; #endif { /* Fast set union operation */ /* resultant set size is max(b, c); */ set *big; set t; unsigned int m,n; register unsigned *r, *p, *q, *endp; CHK(b); CHK(c); t = empty; if (b.n > c.n) {big= &b; m=b.n; n=c.n;} else {big= &c; m=c.n; n=b.n;} set_ext(&t, m); r = t.setword; /* Or b,c until max of smaller set */ q = c.setword; p = b.setword; endp = &(b.setword[n]); while ( p < endp ) *r++ = *p++ | *q++; /* Copy rest of bigger set into result */ p = &(big->setword[n]); endp = &(big->setword[m]); while ( p < endp ) *r++ = *p++; return(t); } set #ifdef __USE_PROTOS set_and( set b, set c ) #else set_and( b, c ) set b; set c; #endif { /* Fast set intersection operation */ /* resultant set size is min(b, c); */ set t; unsigned int n; register unsigned *r, *p, *q, *endp; CHK(b); CHK(c); t = empty; n = (b.n > c.n) ? c.n : b.n; if ( n == 0 ) return t; /* TJP 4-27-92 fixed for empty set */ set_ext(&t, n); r = t.setword; /* & b,c until max of smaller set */ q = c.setword; p = b.setword; endp = &(b.setword[n]); while ( p < endp ) *r++ = *p++ & *q++; return(t); } set #ifdef __USE_PROTOS set_dif( set b, set c ) #else set_dif( b, c ) set b; set c; #endif { /* Fast set difference operation b - c */ /* resultant set size is size(b) */ set t; unsigned int n; register unsigned *r, *p, *q, *endp; CHK(b); CHK(c); t = empty; n = (b.n <= c.n) ? b.n : c.n ; if ( b.n == 0 ) return t; /* TJP 4-27-92 fixed for empty set */ /* WEC 12-1-92 fixed for c.n = 0 */ set_ext(&t, b.n); r = t.setword; /* Dif b,c until smaller set size */ q = c.setword; p = b.setword; endp = &(b.setword[n]); while ( p < endp ) *r++ = *p++ & (~ *q++); /* Copy rest of b into result if size(b) > c */ if ( b.n > n ) { p = &(b.setword[n]); endp = &(b.setword[b.n]); while ( p < endp ) *r++ = *p++; } return(t); } set #ifdef __USE_PROTOS set_of( unsigned b ) #else set_of( b ) unsigned b; #endif { /* Fast singleton set constructor operation */ static set a; if ( b == nil ) return( empty ); set_new(a, (long unsigned int) b); a.setword[DIVWORD(b)] = bitmask[MODWORD(b)]; return(a); } /* * Extend (or shrink) the set passed in to have n words. * * if n is smaller than the minimum, boost n to have the minimum. * if the new set size is the same as the old one, do nothing. * * TJP 4-27-92 Fixed so won't try to alloc 0 bytes */ void #ifdef __USE_PROTOS set_ext( set *a, unsigned int n ) #else set_ext( a, n ) set *a; unsigned int n; #endif { register unsigned *p; register unsigned *endp; unsigned int size; CHK((*a)); if ( a->n == 0 ) { if ( n == 0 ) return; if (a->setword != NULL) { free (a->setword); /* MR20 */ } a->setword = (unsigned *) calloc(n, BytesPerWord); if ( a->setword == NULL ) { fprintf(stderr, "set_ext(%d words): cannot allocate set\n", n); exit(-1); } a->n = n; return; } if ( n < min ) n = min; if ( a->n == n || n == 0 ) return; size = a->n; a->n = n; a->setword = (unsigned *) realloc( (char *)a->setword, (n*BytesPerWord) ); if ( a->setword == NULL ) { fprintf(stderr, "set_ext(%d words): cannot allocate set\n", n); exit(-1); } p = &(a->setword[size]); /* clear from old size to new size */ endp = &(a->setword[a->n]); do { *p++ = 0; } while ( p < endp ); } set #ifdef __USE_PROTOS set_not( set a ) #else set_not( a ) set a; #endif { /* Fast not of set a (assumes all bits used) */ /* size of resultant set is size(a) */ /* ~empty = empty cause we don't know how bit to make set */ set t; register unsigned *r; register unsigned *p = a.setword; register unsigned *endp = &(a.setword[a.n]); CHK(a); t = empty; if ( a.n == 0 ) return( empty ); set_ext(&t, a.n); r = t.setword; do { *r++ = (~ *p++); } while ( p < endp ); return(t); } int #ifdef __USE_PROTOS set_equ( set a, set b ) #else set_equ( a, b ) set a; set b; #endif { /* 8-Nov-97 Make it work with sets of different sizes */ /* Easy to understand, too. Probably faster. */ /* Check for a equal to b */ unsigned int count; /* MR11 */ unsigned int i; /* MR11 */ CHK(a); CHK(b); count=MIN(a.n,b.n); if (count == 0) return 1; for (i=0; i < count; i++) { if (a.setword[i] != b.setword[i]) return 0; }; if (a.n < b.n) { for (i=count; i < b.n; i++) { if (b.setword[i] != 0) return 0; } return 1; } else if (a.n > b.n) { for (i=count; i < a.n; i++) { if (a.setword[i] != 0) return 0; } return 1; } else { return 1; }; } int #ifdef __USE_PROTOS set_sub( set a, set b ) #else set_sub( a, b ) set a; set b; #endif { /* 8-Nov-97 Make it work with sets of different sizes */ /* Easy to understand, too. Probably faster. */ /* Check for a is a PROPER subset of b */ unsigned int count; unsigned int i; CHK(a); CHK(b); if (a.n == 0) return 1; count=MIN(a.n,b.n); for (i=0; i < count; i++) { if (a.setword[i] & ~b.setword[i]) return 0; }; if (a.n <= b.n) { return 1; } else { for (i=count; i a.n ) return(0); /* Otherwise, we have to check */ return( a.setword[DIVWORD(b)] & bitmask[MODWORD(b)] ); } int #ifdef __USE_PROTOS set_nil( set a ) #else set_nil( a ) set a; #endif { /* Fast check for nil set */ register unsigned *p = a.setword; register unsigned *endp; CHK(a); if ( a.n == 0 ) return(1); endp = &(a.setword[a.n]); /* The set is not empty if any word used to store the set is non-zero. This means one must be a bit careful about doing things like negation. */ do { if (*p) return(0); } while (++p < endp); return(1); } char * #ifdef __USE_PROTOS set_str( set a ) #else set_str( a ) set a; #endif { /* Fast convert set a into ASCII char string... assumes that all word bits are used in the set and that SETSIZE is a multiple of WORDSIZE. Trailing 0 bits are removed from the string. if no bits are on or set is empty, "" is returned. */ register unsigned *p = a.setword; register unsigned *endp = &(a.setword[a.n]); static char str_tmp[StrSize+1]; register char *q = &(str_tmp[0]); CHK(a); if ( a.n==0 ) {*q=0; return( &(str_tmp[0]) );} do { register unsigned t = *p; register unsigned *b = &(bitmask[0]); do { *(q++) = (char) ((t & *b) ? '1' : '0'); } while (++b < &(bitmask[WORDSIZE])); } while (++p < endp); /* Trim trailing 0s & NULL terminate the string */ while ((q > &(str_tmp[0])) && (*(q-1) != '1')) --q; *q = 0; return(&(str_tmp[0])); } set #ifdef __USE_PROTOS set_val( register char *s ) #else set_val( s ) register char *s; #endif { /* Fast convert set ASCII char string into a set. If the string ends early, the remaining set bits are all made zero. The resulting set size is just big enough to hold all elements. */ static set a; register unsigned *p, *endp; set_new(a, strlen(s)); p = a.setword; endp = &(a.setword[a.n]); do { register unsigned *b = &(bitmask[0]); /* Start with a word with no bits on */ *p = 0; do { if (*s) { if (*s == '1') { /* Turn-on this bit */ *p |= *b; } ++s; } } while (++b < &(bitmask[WORDSIZE])); } while (++p < endp); return(a); } /* * Or element e into set a. a can be empty. */ void #ifdef __USE_PROTOS set_orel( unsigned e, set *a ) #else set_orel( e, a ) unsigned e; set *a; #endif { CHK((*a)); if ( e == nil ) return; if ( NumWords(e) > a->n ) set_ext(a, NumWords(e)); a->setword[DIVWORD(e)] |= bitmask[MODWORD(e)]; } /* * Or set b into set a. a can be empty. does nothing if b empty. */ void #ifdef __USE_PROTOS set_orin( set *a, set b ) #else set_orin( a, b ) set *a; set b; #endif { /* Fast set union operation */ /* size(a) is max(a, b); */ unsigned int m; register unsigned *p, *q = b.setword, *endq; /* MR20 */ CHK((*a)); CHK(b); if ( b.n == 0 ) return; endq = &(b.setword[b.n]); /* MR20 */ m = (a->n > b.n) ? a->n : b.n; set_ext(a, m); p = a->setword; do { *p++ |= *q++; } while ( q < endq ); } /* * And set b into set a. a can be empty. does nothing if b empty. */ void #ifdef __USE_PROTOS set_andin( set *a, set b ) #else set_andin( a, b ) set *a; set b; #endif { /* Fast set intersection operation */ /* size(a) is max(a, b); */ unsigned int m; register unsigned *p, *q = b.setword, *endq = &(b.setword[b.n]); CHK((*a)); CHK(b); if ( b.n == 0 ) return; m = (a->n > b.n) ? a->n : b.n; set_ext(a, m); p = a->setword; do { *p++ &= *q++; } while ( q < endq ); } void #ifdef __USE_PROTOS set_rm( unsigned e, set a ) #else set_rm( e, a ) unsigned e; set a; #endif { /* Does not effect size of set */ CHK(a); if ( (e == nil) || (NumWords(e) > a.n) ) return; a.setword[DIVWORD(e)] ^= (a.setword[DIVWORD(e)]&bitmask[MODWORD(e)]); } void #ifdef __USE_PROTOS set_clr( set a ) #else set_clr( a ) set a; #endif { /* Does not effect size of set */ register unsigned *p = a.setword; register unsigned *endp; CHK(a); if ( a.n == 0 ) return; endp = &(a.setword[a.n]); do { *p++ = 0; } while ( p < endp ); } set #ifdef __USE_PROTOS set_dup( set a ) #else set_dup( a ) set a; #endif { set b; register unsigned *p, *q = a.setword, *endq; /* MR20 */ CHK(a); b = empty; if ( a.n == 0 ) return( empty ); endq = &(a.setword[a.n]); /* MR20 */ set_ext(&b, a.n); p = b.setword; do { *p++ = *q++; } while ( q < endq ); return(b); } /* * Return a nil terminated list of unsigned ints that represents all * "on" bits in the bit set. * * e.g. {011011} --> {1, 2, 4, 5, nil} * * _set_pdq and set_pdq are useful when an operation is required on each element * of a set. Normally, the sequence is: * * while ( set_deg(a) > 0 ) { * e = set_int(a); * set_rm(e, a); * ...process e... * } * Now, * * t = e = set_pdq(a); * while ( *e != nil ) { * ...process *e... * e++; * } * free( t ); * * We have saved many set calls and have not destroyed set a. */ void #ifdef __USE_PROTOS _set_pdq( set a, register unsigned *q ) #else _set_pdq( a, q ) set a; register unsigned *q; #endif { register unsigned *p = a.setword, *endp = &(a.setword[a.n]); register unsigned e=0; CHK(a); /* are there any space (possibility of elements)? */ if ( a.n == 0 ) return; do { register unsigned t = *p; register unsigned *b = &(bitmask[0]); do { if ( t & *b ) *q++ = e; ++e; } while (++b < &(bitmask[WORDSIZE])); } while (++p < endp); *q = nil; } /* * Same as _set_pdq except allocate memory. set_pdq is the natural function * to use. */ unsigned * #ifdef __USE_PROTOS set_pdq( set a ) #else set_pdq( a ) set a; #endif { unsigned *q; int max_deg; CHK(a); max_deg = WORDSIZE*a.n; /* assume a.n!=0 & no elements is rare, but still ok */ if ( a.n == 0 ) return(NULL); q = (unsigned *) malloc((max_deg+1)*BytesPerWord); if ( q == NULL ) return( NULL ); _set_pdq(a, q); return( q ); } /* a function that produces a hash number for the set */ unsigned int #ifdef __USE_PROTOS set_hash( set a, register unsigned int mod ) #else set_hash( a, mod ) set a; register unsigned int mod; #endif { /* Fast hash of set a (assumes all bits used) */ register unsigned *p = &(a.setword[0]); register unsigned *endp = &(a.setword[a.n]); register unsigned i = 0; CHK(a); while (p #include "dlg.h" #define zzSET_SIZE 8 #include "antlr.h" #include "tokens.h" #include "dlgdef.h" #include "mode.h" #endif cdrdao-cdrdao-f00afb2/pccts/dlg/support.c000066400000000000000000000117661511453746600204530ustar00rootroot00000000000000/* * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * DLG 1.33 * Will Cohen * With mods by Terence Parr; AHPCRC, University of Minnesota * 1989-2001 */ #include #include #include "dlg.h" #ifdef MEMCHK #include "trax.h" #else #ifdef __STDC__ #include #else #include #endif /* __STDC__ */ #endif int err_found = 0; /* indicates whether problem found */ #ifdef __USE_PROTOS void internal_error(char *s, char *file,int line) /* MR9 23-Sep-97 */ #else void internal_error(s,file,line) /* MR9 23-Sep-97 */ char *s,*file; int line; #endif { fprintf(stderr,s,file,line); exit(PCCTS_EXIT_FAILURE); } #ifdef __USE_PROTOS char *dlg_malloc(int bytes,char *file,int line) #else char *dlg_malloc(bytes,file,line) int bytes; char *file; int line; #endif { char *t; t = (char *) malloc(bytes); if (!t){ /* error */ internal_error("%s(%d): unable to allocate memory\n", file,line); } return t; } #ifdef __USE_PROTOS char *dlg_calloc(int n,int bytes,char *file,int line) #else char *dlg_calloc(n,bytes,file,line) int n,bytes; char *file; int line; #endif { char *t; t = (char *) calloc(n,bytes); if (!t){ /* error */ internal_error("%s(%d): unable to allocate memory\n", file,line); } return t; } #ifdef __USE_PROTOS FILE *read_stream(char *name) #else FILE *read_stream(name) char *name; #endif { FILE *f; if (name){ if (name[0] == '-') { fprintf(stderr, "dlg: invalid option: '%s'\n", name); f = NULL; }else{ f = fopen(name, "r"); if (f == NULL){ /* couldn't open file */ fprintf(stderr, "dlg: Warning: Can't read file %s.\n", name); } } }else{ /* open stdin if nothing there */ f = stdin; } return f; } #ifdef __USE_PROTOS FILE *write_stream(char *name) #else FILE *write_stream(name) char *name; #endif { FILE *f; if (name){ if (name[0] == '-') { fprintf(stderr, "dlg: invalid option: '%s'\n", name); f = NULL; }else{ f = fopen(OutMetaName(name), "w"); if (f == NULL){ /* couldn't open file */ fprintf(stderr, "dlg: Warning: Can't write to file %s.\n", name); } else #ifdef SPECIAL_FOPEN special_fopen_actions(OutMetaName(name)); /* MR1 */ #else ; /* MR1 */ #endif } }else{ /* open stdout if nothing there */ f = stdout; } return f; } #ifdef __USE_PROTOS void fatal(char *message,int line_no) #else void fatal(message,line_no) char *message; int line_no; #endif { fprintf(stderr,ErrHdr, (file_str[0] ? file_str[0] : "stdin"), line_no); fprintf(stderr, " Fatal: %s\n", message); exit(PCCTS_EXIT_FAILURE); } #ifdef __USE_PROTOS void error(char *message,int line_no) #else void error(message,line_no) char *message; int line_no; #endif { fprintf(stderr,ErrHdr, (file_str[0] ? file_str[0] : "stdin"), line_no); fprintf(stderr, " Error: %s\n", message); err_found = 1; } #ifdef __USE_PROTOS void warning(char *message,int line_no) #else void warning(message,line_no) char *message; int line_no; #endif { fprintf(stderr,ErrHdr, (file_str[0] ? file_str[0] : "stdin"), line_no); fprintf(stderr, " Warning: %s\n", message); } /* MR10: Jeff Vincent MR10: Changed to remove directory information from n only if MR10: if OutputDirectory was changed by user (-o option) */ #ifdef __USE_PROTOS char *OutMetaName(char *n) #else char *OutMetaName(n) char *n; #endif { static char *dir_sym = DirectorySymbol; static char newname[MaxFileName+1]; char *p; /* If OutputDirectory is same as TopDirectory (platform default) then leave n alone. */ if (strcmp(OutputDirectory, TopDirectory) == 0) return n; /* p will point to filename without path information */ if ((p = strrchr(n, *dir_sym)) != NULL) p++; else p = n; /* Copy new output directory into newname[] */ strcpy(newname, OutputDirectory); /* if new output directory does not have trailing dir_sym, add it! */ if (newname[strlen(newname)-1] != *dir_sym) strcat(newname, dir_sym); /* contatenate FILE NAME ONLY to new output directory */ strcat(newname, p); return newname; } cdrdao-cdrdao-f00afb2/pccts/dlg/tokens.h000066400000000000000000000042421511453746600202360ustar00rootroot00000000000000#ifndef tokens_h #define tokens_h /* tokens.h -- List of labelled tokens and stuff * * Generated from: dlg_p.g * * Terence Parr, Will Cohen, and Hank Dietz: 1989-2001 * Purdue University Electrical Engineering * ANTLR Version 1.33MR32 */ #define zzEOF_TOKEN 1 #define L_EOF 4 #define PER_PER 5 #define NAME_PER_PER 6 #define LEXMEMBER 7 #define LEXACTION 8 #define PARSERCLASS 9 #define LEXPREFIX 10 #define ACTION 11 #define GREAT_GREAT 12 #define L_BRACE 13 #define R_BRACE 14 #define L_PAR 15 #define R_PAR 16 #define L_BRACK 17 #define R_BRACK 18 #define ZERO_MORE 19 #define ONE_MORE 20 #define OR 21 #define RANGE 22 #define NOT 23 #define OCTAL_VALUE 24 #define HEX_VALUE 25 #define DEC_VALUE 26 #define TAB 27 #define NL 28 #define CR 29 #define BS 30 #define CONTINUATION 31 #define LIT 32 #define REGCHAR 33 #ifdef __USE_PROTOS void grammar(void); #else extern void grammar(); #endif #ifdef __USE_PROTOS void start_states(void); #else extern void start_states(); #endif #ifdef __USE_PROTOS void do_conversion(void); #else extern void do_conversion(); #endif #ifdef __USE_PROTOS void rule_list(void); #else extern void rule_list(); #endif #ifdef __USE_PROTOS void rule(void); #else extern void rule(); #endif #ifdef __USE_PROTOS void reg_expr(void); #else extern void reg_expr(); #endif #ifdef __USE_PROTOS void and_expr(void); #else extern void and_expr(); #endif #ifdef __USE_PROTOS void repeat_expr(void); #else extern void repeat_expr(); #endif #ifdef __USE_PROTOS void expr(void); #else extern void expr(); #endif #ifdef __USE_PROTOS void atom_list(void); #else extern void atom_list(); #endif #ifdef __USE_PROTOS void near_atom(void); #else extern void near_atom(); #endif #ifdef __USE_PROTOS void atom(void); #else extern void atom(); #endif #ifdef __USE_PROTOS void anychar(void); #else extern void anychar(); #endif #endif extern SetWordType zzerr1[]; extern SetWordType zzerr2[]; extern SetWordType zzerr3[]; extern SetWordType setwd1[]; extern SetWordType zzerr4[]; extern SetWordType zzerr5[]; extern SetWordType zzerr6[]; extern SetWordType setwd2[]; extern SetWordType zzerr7[]; extern SetWordType zzerr8[]; extern SetWordType zzerr9[]; extern SetWordType setwd3[]; cdrdao-cdrdao-f00afb2/pccts/h/000077500000000000000000000000001511453746600162415ustar00rootroot00000000000000cdrdao-cdrdao-f00afb2/pccts/h/AParser.cpp000066400000000000000000000573221511453746600203130ustar00rootroot00000000000000/* ANTLRParser.C * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2000 */ #include "pcctscfg.h" #include "pccts_stdlib.h" #include "pccts_stdarg.h" #include "pccts_string.h" #include "pccts_stdio.h" PCCTS_NAMESPACE_STD /* I have to put this here due to C++ limitation * that you can't have a 'forward' decl for enums. * I hate C++!!!!!!!!!!!!!!! * Of course, if I could use real templates, this would go away. */ // MR1 // MR1 10-Apr-97 133MR1 Prevent use of varying sizes for the // MR1 ANTLRTokenType enum // MR1 enum ANTLRTokenType { TER_HATES_CPP=0, ITS_TOO_COMPLICATED=9999}; // MR1 #define ANTLR_SUPPORT_CODE #include ATOKEN_H #include ATOKENBUFFER_H #include APARSER_H static const int zzINF_DEF_TOKEN_BUFFER_SIZE = 2000; /* MR14 */ static const int zzINF_BUFFER_TOKEN_CHUNK_SIZE = 1000; /* MR14 */ /* L o o k a h e a d M a c r o s */ /* maximum of 32 bits/unsigned int and must be 8 bits/byte; * we only use 8 bits of it. */ SetWordType ANTLRParser::bitmask[sizeof(SetWordType)*8] = { 0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, 0x00000020, 0x00000040, 0x00000080 }; #define EMSGBUFFER_SIZE 500 char ANTLRParser::eMsgBuffer[EMSGBUFFER_SIZE] = ""; ANTLRParser:: ~ANTLRParser() { delete [] token_type; delete [] zzFAILtext; // MR16 Manfred Kogler } ANTLRParser:: ANTLRParser(ANTLRTokenBuffer *_inputTokens, int k, int use_inf_look, int dlook, int ssize) { LLk = k; can_use_inf_look = use_inf_look; /* MR14 */ if (dlook != 0) { /* MR14 */ panic("ANTLRParser::ANTLRParser - Demand lookahead not supported in C++ mode"); /* MR14 */ /* MR14 */ }; demand_look = 0; /* demand_look = dlook; */ bsetsize = ssize; guessing = 0; token_tbl = NULL; eofToken = (ANTLRTokenType)1; // allocate lookahead buffer token_type = new ANTLRTokenType[LLk]; lap = 0; labase = 0; #ifdef ZZDEFER_FETCH stillToFetch = 0; // MR19 #endif dirty = 0; inf_labase = 0; // MR7 inf_last = 0; // MR7 /* prime lookahead buffer, point to inputTokens */ this->inputTokens = _inputTokens; this->inputTokens->setMinTokens(k); _inputTokens->setParser(this); // MR1 resynchConsumed=1; // MR8 zzFAILtext=NULL; // MR9 traceOptionValueDefault=0; // MR10 traceReset(); // MR10 zzGuessSeq=0; // MR10 syntaxErrCount=0; // MR11 } void ANTLRParser::init() { prime_lookahead(); resynchConsumed=1; // MR8 traceReset(); // MR10 } void ANTLRParser::traceReset() { traceOptionValue=traceOptionValueDefault; traceGuessOptionValue=1; traceCurrentRuleName=NULL; traceDepth=0; } #ifdef _MSC_VER // MR23 //Turn off warning: //interaction between '_setjmp' and C++ object destruction is non-portable #pragma warning(disable : 4611) #endif int ANTLRParser:: guess(ANTLRParserState *st) { saveState(st); guessing = 1; return setjmp(guess_start.state); } #ifdef _MSC_VER // MR23 #pragma warning(default: 4611) #endif void ANTLRParser:: saveState(ANTLRParserState *buf) { buf->guess_start = guess_start; buf->guessing = guessing; buf->inf_labase = inf_labase; buf->inf_last = inf_last; buf->dirty = dirty; buf->traceOptionValue=traceOptionValue; /* MR10 */ buf->traceGuessOptionValue=traceGuessOptionValue; /* MR10 */ buf->traceCurrentRuleName=traceCurrentRuleName; /* MR10 */ buf->traceDepth=traceDepth; /* MR10 */ } void ANTLRParser:: restoreState(ANTLRParserState *buf) { int i; int prevTraceOptionValue; guess_start = buf->guess_start; guessing = buf->guessing; inf_labase = buf->inf_labase; inf_last = buf->inf_last; dirty = buf->dirty; // restore lookahead buffer from k tokens before restored TokenBuffer position // if demand_look, then I guess we don't look backwards for these tokens. for (i=1; i<=LLk; i++) token_type[i-1] = inputTokens->bufferedToken(i-LLk)->getType(); lap = 0; labase = 0; /* MR10 */ prevTraceOptionValue=traceOptionValue; traceOptionValue=buf->traceOptionValue; if ( (prevTraceOptionValue > 0) != (traceOptionValue > 0)) { if (traceCurrentRuleName != NULL) { /* MR21 */ if (traceOptionValue > 0) { /* MR23 */ printMessage(stderr, "trace enable restored in rule %s depth %d\n", traceCurrentRuleName, traceDepth); }; if (traceOptionValue <= 0) { /* MR23 */ printMessage(stderr, "trace disable restored in rule %s depth %d\n", traceCurrentRuleName, /* MR21 */ traceDepth); }; } }; traceGuessOptionValue=buf->traceGuessOptionValue; traceCurrentRuleName=buf->traceCurrentRuleName; traceDepth=buf->traceDepth; traceGuessDone(buf); } /* Get the next symbol from the input stream; put it into lookahead buffer; * fill token_type[] fast reference cache also. NLA is the next place where * a lookahead ANTLRAbstractToken should go. */ void ANTLRParser:: consume() { #ifdef ZZDEBUG_CONSUME_ACTION zzdebug_consume_action(); #endif // MR19 V.H. Simonis // Defer Fetch feature // Moves action of consume() into LA() function #ifdef ZZDEFER_FETCH stillToFetch++; #else NLA = inputTokens->getToken()->getType(); dirty--; lap = (lap+1)&(LLk-1); #endif } _ANTLRTokenPtr ANTLRParser:: LT(int i) { // MR19 V.H. Simonis // Defer Fetch feature // Moves action of consume() into LA() function #ifdef ZZDEFER_FETCH undeferFetch(); #endif #ifdef DEBUG_TOKENBUFFER if ( i >= inputTokens->bufferSize() || inputTokens->minTokens() < LLk ) /* MR20 Was "<=" */ { char buf[2000]; /* MR20 Was "static" */ sprintf(buf, sizeof(buf), "The minimum number of tokens you requested that the\nANTLRTokenBuffer buffer is not enough to satisfy your\nLT(%d) request; increase 'k' argument to constructor for ANTLRTokenBuffer\n", i); panic(buf); } #endif return inputTokens->bufferedToken(i-LLk); } void ANTLRParser:: look(int k) { int i, c = k - (LLk-dirty); for (i=1; i<=c; i++) consume(); } /* fill the lookahead buffer up with k symbols (even if DEMAND_LOOK); */ void ANTLRParser:: prime_lookahead() { int i; for(i=1;i<=LLk; i++) consume(); dirty=0; // lap = 0; // MR14 Sinan Karasu (sinan.karasu@boeing.com) // labase = 0; // MR14 labase=lap; // MR14 } /* check to see if the current input symbol matches '_t'. * During NON demand lookahead mode, dirty will always be 0 and * hence the extra code for consuming tokens in _match is never * executed; the same routine can be used for both modes. */ int ANTLRParser:: _match(ANTLRTokenType _t, ANTLRChar **MissText, ANTLRTokenType *MissTok, _ANTLRTokenPtr *BadTok, SetWordType **MissSet) { if ( dirty==LLk ) { consume(); } if ( LA(1)!=_t ) { *MissText=NULL; *MissTok= _t; *BadTok = LT(1); *MissSet=NULL; return 0; } dirty++; labase = (labase+1)&(LLk-1); // labase maintained even if !demand look return 1; } /* check to see if the current input symbol matches '_t'. * Used during exception handling. */ int ANTLRParser:: _match_wsig(ANTLRTokenType _t) { if ( dirty==LLk ) { consume(); } if ( LA(1)!=_t ) return 0; dirty++; labase = (labase+1)&(LLk-1); // labase maintained even if !demand look return 1; } /* check to see if the current input symbol matches any token in a set. * During NON demand lookahead mode, dirty will always be 0 and * hence the extra code for consuming tokens in _match is never * executed; the same routine can be used for both modes. */ int ANTLRParser:: _setmatch(SetWordType *tset, ANTLRChar **MissText, ANTLRTokenType *MissTok, _ANTLRTokenPtr *BadTok, SetWordType **MissSet, SetWordType *tokclassErrset) { if ( dirty==LLk ) { consume(); } if ( !set_el(LA(1), tset) ) { *MissText=NULL; /* MR23 */ *MissTok=(ANTLRTokenType) 0; /* MR23 */ *BadTok=LT(1); /* MR23 */ *MissSet=tokclassErrset; /* MR23 */ return 0; } dirty++; labase = (labase+1)&(LLk-1); // labase maintained even if !demand look return 1; } int ANTLRParser:: _setmatch_wsig(SetWordType *tset) { if ( dirty==LLk ) { consume(); } if ( !set_el(LA(1), tset) ) return 0; dirty++; labase = (labase+1)&(LLk-1); // labase maintained even if !demand look return 1; } /* Exception handling routines */ // // 7-Apr-97 133MR1 // Change suggested by Eli Sternheim (eli@interhdl.com) // void ANTLRParser:: consumeUntil(SetWordType *st) { ANTLRTokenType tmp; // MR1 const int Eof=1; // MR1 while ( !set_el( (tmp=LA(1)), st) && tmp!=Eof) { consume(); } // MR1 } // // 7-Apr-97 133MR1 // Change suggested by Eli Sternheim (eli@interhdl.com) // void ANTLRParser:: consumeUntilToken(int t) { int tmp; // MR1 const int Eof=1; // MR1 while ( (tmp=LA(1)) !=t && tmp!=Eof) { consume(); } // MR1 } /* Old error stuff */ void ANTLRParser:: resynch(SetWordType *wd,SetWordType mask) { /* MR8 S.Bochnak@microtool.com.pl */ /* MR8 Change file scope static "consumed" to instance var */ /* if you enter here without having consumed a token from last resynch * force a token consumption. */ /* MR8 */ if ( !resynchConsumed ) {consume(); resynchConsumed=1; return;} /* if current token is in resynch set, we've got what we wanted */ /* MR8 */ if ( wd[LA(1)]&mask || LA(1) == eofToken ) {resynchConsumed=0; return;} /* scan until we find something in the resynch set */ while ( !(wd[LA(1)]&mask) && LA(1) != eofToken ) {consume();} /* MR8 */ resynchConsumed=1; } /* standard error reporting function that assumes DLG-based scanners; * you should redefine in subclass to change it or if you use your * own scanner. */ /* MR23 THM There appears to be a parameter "badText" passed to syn() which is not present in the parameter list. This may be because in C mode there is no attribute function which returns the text, so the text representation of the token must be passed explicitly. I think. */ void ANTLRParser:: syn(_ANTLRTokenPtr /*tok MR23*/, ANTLRChar *egroup, SetWordType *eset, ANTLRTokenType etok, int k) { int line; line = LT(1)->getLine(); syntaxErrCount++; /* MR11 */ /* MR23 If the token is not an EOF token, then use the ->getText() value. If the token is the EOF token the text returned by ->getText() may be garbage. If the text from the token table is "@" use "" instead, because end-users don't know what "@" means. If the text is not "@" then use that text, which must have been supplied by the grammar writer. */ const char * errorAt = LT(1)->getText(); if (LA(1) == eofToken) { errorAt = parserTokenName(LA(1)); if (errorAt[0] == '@') errorAt = ""; } /* MR23 */ printMessage(stderr, "line %d: syntax error at \"%s\"", line, errorAt); if ( !etok && !eset ) {/* MR23 */ printMessage(stderr, "\n"); return;} if ( k==1 ) /* MR23 */ printMessage(stderr, " missing"); else { /* MR23 */ printMessage(stderr, "; \"%s\" not", LT(k)->getText()); // MR23 use LT(k) since k>1 if ( set_deg(eset)>1 ) /* MR23 */ printMessage(stderr, " in"); } if ( set_deg(eset)>0 ) edecode(eset); else /* MR23 */ printMessage(stderr, " %s", token_tbl[etok]); if ( strlen(egroup) > 0 ) /* MR23 */ printMessage(stderr, " in %s", egroup); /* MR23 */ printMessage(stderr, "\n"); } /* is b an element of set p? */ int ANTLRParser:: set_el(ANTLRTokenType b, SetWordType *p) { return( p[DIVWORD(b)] & bitmask[MODWORD(b)] ); } int ANTLRParser:: set_deg(SetWordType *a) { /* Fast compute degree of a set... the number of elements present in the set. Assumes that all word bits are used in the set */ SetWordType *p = a; SetWordType *endp = &(a[bsetsize]); int degree = 0; if ( a == NULL ) return 0; while ( p < endp ) { SetWordType t = *p; SetWordType *b = &(bitmask[0]); do { if (t & *b) ++degree; } while (++b < &(bitmask[sizeof(SetWordType)*8])); p++; } return(degree); } void ANTLRParser:: edecode(SetWordType *a) { SetWordType *p = a; SetWordType *endp = &(p[bsetsize]); unsigned e = 0; if ( set_deg(a)>1 ) /* MR23 */ printMessage(stderr, " {"); do { SetWordType t = *p; SetWordType *b = &(bitmask[0]); do { if ( t & *b ) /* MR23 */ printMessage(stderr, " %s", token_tbl[e]); e++; } while (++b < &(bitmask[sizeof(SetWordType)*8])); } while (++p < endp); if ( set_deg(a)>1 ) /* MR23 */ printMessage(stderr, " }"); } /* input looks like: * zzFAIL(k, e1, e2, ...,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk) * where the zzMiss stuff is set here to the token that did not match * (and which set wasn't it a member of). */ // MR9 29-Sep-97 Stan Bochnak (S.Bochnak@microTool.com.pl) // MR9 Original fix to static allocated text didn't // MR9 work because a pointer to it was passed back // MR9 to caller. Replace with instance variable. const int SETWORDCOUNT=20; void ANTLRParser::FAIL(int k, ...) { // // MR1 10-Apr-97 // if (zzFAILtext == NULL) zzFAILtext=new char [1000]; // MR9 SetWordType **f=new SetWordType *[SETWORDCOUNT]; // MR1 // MR9 SetWordType **miss_set; ANTLRChar **miss_text; _ANTLRTokenPtr *bad_tok; ANTLRChar **bad_text; // // 7-Apr-97 133MR1 // err_k is passed as a "int *", not "unsigned *" // int *err_k; // MR1 int i; va_list ap; va_start(ap, k); zzFAILtext[0] = '\0'; if ( k > SETWORDCOUNT ) panic("FAIL: overflowed buffer"); for (i=1; i<=k; i++) /* collect all lookahead sets */ { f[i-1] = va_arg(ap, SetWordType *); } for (i=1; i<=k; i++) /* look for offending token */ { if ( i>1 ) strcat(zzFAILtext, " "); strcat(zzFAILtext, LT(i)->getText()); if ( !set_el(LA(i), f[i-1]) ) break; } miss_set = va_arg(ap, SetWordType **); miss_text = va_arg(ap, ANTLRChar **); bad_tok = va_arg(ap, _ANTLRTokenPtr *); bad_text = va_arg(ap, ANTLRChar **); err_k = va_arg(ap, int *); // MR1 if ( i>k ) { /* bad; lookahead is permutation that cannot be matched, * but, the ith token of lookahead is valid at the ith position * (The old LL sub 1 (k) versus LL(k) parsing technique) */ *miss_set = NULL; *miss_text = LT(1)->getText(); *bad_tok = LT(1); *bad_text = (*bad_tok)->getText(); *err_k = k; // // MR4 20-May-97 erroneously deleted contents of f[] // MR4 reported by Bruce Guenter (bruceg@qcc.sk.ca) // MR1 10-Apr-97 release temporary storage // delete [] f; // MR1 return; // MR1 } /* MR23 printMessage(stderr, "%s not in %dth set\n", zztokens[LA(i)], i);*/ *miss_set = f[i-1]; *miss_text = zzFAILtext; *bad_tok = LT(i); *bad_text = (*bad_tok)->getText(); if ( i==1 ) *err_k = 1; else *err_k = k; // // MR4 20-May-97 erroneously deleted contents of f[] // MR4 reported by Bruce Guenter (bruceg@qcc.sk.ca) // MR1 10-Apr-97 release temporary storage // delete [] f; // MR1 return; // MR1 } int ANTLRParser:: _match_wdfltsig(ANTLRTokenType tokenWanted, SetWordType *whatFollows) { if ( dirty==LLk ) consume(); if ( LA(1)!=tokenWanted ) { syntaxErrCount++; /* MR11 */ /* MR23 */ printMessage(stderr, "line %d: syntax error at \"%s\" missing %s\n", LT(1)->getLine(), (LA(1)==eofToken && LT(1)->getText()[0] == '@')?"":LT(1)->getText(), /* MR21a */ token_tbl[tokenWanted]); consumeUntil( whatFollows ); return 0; } else { dirty++; labase = (labase+1)&(LLk-1); // labase maintained even if !demand look /* if ( !demand_look ) consume(); */ return 1; } } int ANTLRParser:: _setmatch_wdfltsig(SetWordType *tokensWanted, ANTLRTokenType tokenTypeOfSet, SetWordType *whatFollows) { if ( dirty==LLk ) consume(); if ( !set_el(LA(1), tokensWanted) ) { syntaxErrCount++; /* MR11 */ /* MR23 */ printMessage(stderr, "line %d: syntax error at \"%s\" missing %s\n", LT(1)->getLine(), (LA(1)==eofToken && LT(1)->getText()[0] == '@')?"":LT(1)->getText(), /* MR21a */ token_tbl[tokenTypeOfSet]); consumeUntil( whatFollows ); return 0; } else { dirty++; labase = (labase+1)&(LLk-1); // labase maintained even if !demand look /* if ( !demand_look ) consume(); */ return 1; } } char *ANTLRParser:: eMsgd(char *err,int d) { snprintf(eMsgBuffer, EMSGBUFFER_SIZE, err, d); // dangerous, but I don't care return eMsgBuffer; } char *ANTLRParser:: eMsg(char *err, char *s) { snprintf(eMsgBuffer, EMSGBUFFER_SIZE, err, s); return eMsgBuffer; } char *ANTLRParser:: eMsg2(char *err,char *s, char *t) { snprintf(eMsgBuffer, EMSGBUFFER_SIZE, err, s, t); return eMsgBuffer; } void ANTLRParser:: panic(const char *msg) // MR20 const { /* MR23 */ printMessage(stderr, "ANTLR panic: %s\n", msg); exit(PCCTS_EXIT_FAILURE); // MR1 } const ANTLRChar *ANTLRParser:: // MR1 parserTokenName(int tok) { // MR1 return token_tbl[tok]; // MR1 } // MR1 void ANTLRParser::traceGuessDone(const ANTLRParserState *state) { int doIt=0; if (traceCurrentRuleName == NULL) return; if (traceOptionValue <= 0) { doIt=0; } else if (traceGuessOptionValue <= 0) { doIt=0; } else { doIt=1; }; if (doIt) { /* MR23 */ printMessage(stderr,"guess done - returning to rule %s {\"%s\"} at depth %d", state->traceCurrentRuleName, LT(1)->getType() == eofToken ? "@" : LT(1)->getText(), state->traceDepth); if (state->guessing != 0) { /* MR23 */ printMessage(stderr," (guess mode continues - an enclosing guess is still active)"); } else { /* MR23 */ printMessage(stderr," (guess mode ends)"); }; /* MR23 */ printMessage(stderr,"\n"); }; } void ANTLRParser::traceGuessFail() { int doIt=0; if (traceCurrentRuleName == NULL) return; /* MR21 */ if (traceOptionValue <= 0) { doIt=0; } else if (guessing && traceGuessOptionValue <= 0) { doIt=0; } else { doIt=1; }; if (doIt) { /* MR23 */ printMessage(stderr,"guess failed in %s\n",traceCurrentRuleName); }; } /* traceOption: zero value turns off trace */ void ANTLRParser::tracein(const ANTLRChar * rule) { int doIt=0; traceDepth++; traceCurrentRuleName=rule; if (traceOptionValue <= 0) { doIt=0; } else if (guessing && traceGuessOptionValue <= 0) { doIt=0; } else { doIt=1; }; if (doIt) { /* MR23 */ printMessage(stderr,"enter rule %s {\"%s\"} depth %d", rule, LT(1)->getType() == eofToken ? "@" : LT(1)->getText(), traceDepth); if (guessing) /* MR23 */ printMessage(stderr," guessing"); /* MR23 */ printMessage(stderr,"\n"); }; return; } void ANTLRParser::traceout(const ANTLRChar * rule) { int doIt=0; traceDepth--; if (traceOptionValue <= 0) { doIt=0; } else if (guessing && traceGuessOptionValue <= 0) { doIt=0; } else { doIt=1; }; if (doIt) { /* MR23 */ printMessage(stderr,"exit rule %s {\"%s\"} depth %d", rule, LT(1)->getType() == eofToken ? "@" : LT(1)->getText(), traceDepth+1); if (guessing) /* MR23 */ printMessage(stderr," guessing"); /* MR23 */ printMessage(stderr,"\n"); }; } int ANTLRParser::traceOption(int delta) { int prevValue=traceOptionValue; traceOptionValue=traceOptionValue+delta; if (traceCurrentRuleName != NULL) { if (prevValue <= 0 && traceOptionValue > 0) { /* MR23 */ printMessage(stderr,"trace enabled in rule %s depth %d\n",traceCurrentRuleName,traceDepth); }; if (prevValue > 0 && traceOptionValue <= 0) { /* MR23 */ printMessage(stderr,"trace disabled in rule %s depth %d\n",traceCurrentRuleName,traceDepth); }; }; return prevValue; } int ANTLRParser::traceGuessOption(int delta) { int prevValue=traceGuessOptionValue; traceGuessOptionValue=traceGuessOptionValue+delta; if (traceCurrentRuleName != NULL) { if (prevValue <= 0 && traceGuessOptionValue > 0) { /* MR23 */ printMessage(stderr,"guess trace enabled in rule %s depth %d\n",traceCurrentRuleName,traceDepth); }; if (prevValue > 0 && traceGuessOptionValue <= 0) { /* MR23 */ printMessage(stderr,"guess trace disabled in rule %s depth %d\n",traceCurrentRuleName,traceDepth); }; }; return prevValue; } // MR19 V.H. Simonis Defer Fetch feature void ANTLRParser::undeferFetch() { #ifdef ZZDEFER_FETCH if (stillToFetch) { for (int stillToFetch_x = 0; stillToFetch_x < stillToFetch; ++stillToFetch_x) { NLA = inputTokens->getToken()->getType(); dirty--; lap = (lap+1)&(LLk-1); } stillToFetch = 0; } #else return; #endif } int ANTLRParser::isDeferFetchEnabled() { #ifdef ZZDEFER_FETCH return 1; #else return 0; #endif } //MR23 int ANTLRParser::printMessage(FILE* pFile, const char* pFormat, ...) { va_list marker; va_start( marker, pFormat ); int iRet = printMessageV(pFile, pFormat, marker); va_end( marker ); return iRet; } int ANTLRParser::printMessageV(FILE* pFile, const char* pFormat, va_list arglist) // MR23 { return vfprintf(pFile, pFormat, arglist); } // MR23 Move semantic predicate error handling from macro to virtual function // // Called by the zzfailed_pred void ANTLRParser::failedSemanticPredicate(const char* predicate) { printMessage(stdout,"line %d: semantic error; failed predicate: '%s'\n", LT(1)->getLine(), predicate); } cdrdao-cdrdao-f00afb2/pccts/h/AParser.h000066400000000000000000000325211511453746600177520ustar00rootroot00000000000000/* ANTLRParser.h * * Define the generic ANTLRParser superclass, which is subclassed to * define an actual parser. * * Before entry into this file: ANTLRTokenType must be set. * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2000 */ #ifndef APARSER_H_GATE #define APARSER_H_GATE #include "pcctscfg.h" #include "pccts_stdio.h" #include "pccts_setjmp.h" PCCTS_NAMESPACE_STD #include ATOKEN_H #include ATOKENBUFFER_H #ifdef ZZCAN_GUESS #ifndef ZZINF_LOOK #define ZZINF_LOOK #endif #endif #define NLA (token_type[lap&(LLk-1)])/* --> next LA */ typedef unsigned char SetWordType; /* Define external bit set stuff (for SetWordType) */ #define EXT_WORDSIZE (sizeof(char)*8) #define EXT_LOGWORDSIZE 3 /* s y n t a c t i c p r e d i c a t e s t u f f */ #ifndef zzUSER_GUESS_HOOK #define zzUSER_GUESS_HOOK(seqFrozen,zzrv) #endif #ifndef zzUSER_GUESS_DONE_HOOK #define zzUSER_GUESS_DONE_HOOK(seqFrozen) #endif /* MR14 Add zzUSER_GUESS_FAIL_HOOK and related code */ #define zzUSER_GUESS_FAIL_HOOK_INTERNAL zzUSER_GUESS_FAIL_HOOK(SeqFrozen) #ifndef zzUSER_GUESS_FAIL_HOOK #define zzUSER_GUESS_FAIL_HOOK(zzGuessSeq) #endif typedef struct _zzjmp_buf { jmp_buf state; } zzjmp_buf; /* these need to be macros not member functions */ #define zzGUESS_BLOCK ANTLRParserState zzst; int zzrv; int _marker; int zzGuessSeqFrozen; #define zzNON_GUESS_MODE if ( !guessing ) #define zzGUESS_FAIL guess_fail(); /* Note: zzGUESS_DONE does not execute longjmp() */ #define zzGUESS_DONE {zzrv=1; inputTokens->rewind(_marker); guess_done(&zzst);zzUSER_GUESS_DONE_HOOK(zzGuessSeqFrozen) } #define zzGUESS saveState(&zzst); \ guessing = 1; \ zzGuessSeqFrozen = ++zzGuessSeq; \ _marker = inputTokens->mark(); \ zzrv = setjmp(guess_start.state); \ zzUSER_GUESS_HOOK(zzGuessSeqFrozen,zzrv) \ if ( zzrv ) zzGUESS_DONE #define zzTRACEdata const ANTLRChar *zzTracePrevRuleName = NULL; #ifndef zzTRACEIN #define zzTRACEIN(r) zzTracePrevRuleName=traceCurrentRuleName;tracein(r); #endif #ifndef zzTRACEOUT #define zzTRACEOUT(r) traceout(r);traceCurrentRuleName=zzTracePrevRuleName; #endif /* a n t l r p a r s e r d e f */ struct ANTLRParserState { /* class variables */ zzjmp_buf guess_start; int guessing; int inf_labase; int inf_last; int dirty; int traceOptionValue; // MR10 int traceGuessOptionValue; // MR10 const ANTLRChar *traceCurrentRuleName; // MR10 int traceDepth; // MR10 }; /* notes: * * multiple inheritance is a cool way to include what stuff is needed * in this structure (like guess stuff). however, i'm not convinced that * multiple inheritance works correctly on all platforms. not that * much space is used--just include all possibly useful members. * * the class should also be a template with arguments for the lookahead * depth and so on. that way, more than one parser can be defined (as * each will probably have different lookahead requirements). however, * am i sure that templates work? no, i'm not sure. * * no attributes are maintained and, hence, the 'asp' variable is not * needed. $i can still be referenced, but it refers to the token * associated with that rule element. question: where are the token's * stored if not on the software stack? in local variables created * and assigned to by antlr. */ class ANTLRParser { protected: /* class variables */ static SetWordType bitmask[sizeof(SetWordType)*8]; static char eMsgBuffer[500]; protected: int LLk; // number of lookahead symbols (old LL_K) int demand_look; ANTLRTokenType eofToken; // when do I stop during resynch()s int bsetsize; // size of bitsets created by ANTLR in // units of SetWordType ANTLRTokenBuffer *inputTokens; //place to get input tokens zzjmp_buf guess_start; // where to jump back to upon failure int guessing; // if guessing (using (...)? predicate) // infinite lookahead stuff int can_use_inf_look; // set by subclass (generated by ANTLR) int inf_lap; int inf_labase; int inf_last; int *_inf_line; const ANTLRChar **token_tbl; // pointer to table of token type strings MR20 const int dirty; // used during demand lookahead ANTLRTokenType *token_type; // fast reference cache of token.getType() // ANTLRLightweightToken **token; // the token with all its attributes int lap; int labase; #ifdef ZZDEFER_FETCH int stillToFetch; // MR19 V.H. Simonis #endif private: void fill_inf_look(); protected: virtual void guess_fail() { // MR9 27-Sep-97 make virtual traceGuessFail(); // MR10 longjmp(guess_start.state, 1); } // MR9 virtual void guess_done(ANTLRParserState *st) { // MR9 27-Sep-97 make virtual restoreState(st); } // MR9 virtual int guess(ANTLRParserState *); // MR9 27-Sep-97 make virtual void look(int); int _match(ANTLRTokenType, ANTLRChar **, ANTLRTokenType *, _ANTLRTokenPtr *, SetWordType **); int _setmatch(SetWordType *, ANTLRChar **, ANTLRTokenType *, _ANTLRTokenPtr *, SetWordType **, SetWordType * tokclassErrset /* MR23 */); int _match_wsig(ANTLRTokenType); int _setmatch_wsig(SetWordType *); virtual void consume(); virtual void resynch(SetWordType *wd,SetWordType mask); // MR21 void prime_lookahead(); virtual void tracein(const ANTLRChar *r); // MR10 virtual void traceout(const ANTLRChar *r); // MR10 static unsigned MODWORD(unsigned x) {return x & (EXT_WORDSIZE-1);} // x % EXT_WORDSIZE // MR9 static unsigned DIVWORD(unsigned x) {return x >> EXT_LOGWORDSIZE;} // x / EXT_WORDSIZE // MR9 int set_deg(SetWordType *); int set_el(ANTLRTokenType, SetWordType *); virtual void edecode(SetWordType *); // MR1 virtual void FAIL(int k, ...); // MR1 int traceOptionValue; // MR10 int traceGuessOptionValue; // MR10 const ANTLRChar *traceCurrentRuleName; // MR10 int traceDepth; // MR10 void traceReset(); // MR10 virtual void traceGuessFail(); // MR10 virtual void traceGuessDone(const ANTLRParserState *); // MR10 int zzGuessSeq; // MR10 public: ANTLRParser(ANTLRTokenBuffer *, int k=1, int use_inf_look=0, int demand_look=0, int bsetsize=1); virtual ~ANTLRParser(); virtual void init(); ANTLRTokenType LA(int i) { // // MR14 demand look will always be 0 for C++ mode // //// return demand_look ? token_type[(labase+(i)-1)&(LLk-1)] : //// token_type[(lap+(i)-1)&(LLk-1)]; // MR19 V.H. Simonis Defer fetch feature #ifdef ZZDEFER_FETCH undeferFetch(); #endif return token_type[(lap+(i)-1)&(LLk-1)]; } _ANTLRTokenPtr LT(int i); void setEofToken(ANTLRTokenType t) { eofToken = t; } ANTLRTokenType getEofToken() const { return eofToken; } // MR14 void noGarbageCollectTokens() { inputTokens->noGarbageCollectTokens(); } void garbageCollectTokens() { inputTokens->garbageCollectTokens(); } virtual void syn(_ANTLRTokenPtr tok, ANTLRChar *egroup, SetWordType *eset, ANTLRTokenType etok, int k); virtual void saveState(ANTLRParserState *); // MR9 27-Sep-97 make virtual virtual void restoreState(ANTLRParserState *); // MR9 27-Sep-97 make virtual virtual void panic(const char *msg); // MR20 const static char *eMsgd(char *,int); static char *eMsg(char *,char *); static char *eMsg2(char *,char *,char *); virtual int printMessage(FILE* pFile, const char* pFormat, ...); // MR23 virtual int printMessageV(FILE* pFile, const char* pFormat, va_list arglist); // MR23 void consumeUntil(SetWordType *st); void consumeUntilToken(int t); virtual int _setmatch_wdfltsig(SetWordType *tokensWanted, ANTLRTokenType tokenTypeOfSet, SetWordType *whatFollows); virtual int _match_wdfltsig(ANTLRTokenType tokenWanted, SetWordType *whatFollows); const ANTLRChar * parserTokenName(int tok); // MR1 int traceOptionValueDefault; // MR11 int traceOption(int delta); // MR11 int traceGuessOption(int delta); // MR11 // MR8 5-Aug-97 S.Bochnak@microtool.com.pl // MR8 Move resynch static local variable // MR8 to class instance int syntaxErrCount; // MR12 ANTLRTokenStream *getLexer() const { // MR12 return inputTokens ? inputTokens->getLexer() : 0; } // MR12 protected: // MR8 int resynchConsumed; // MR8 char *zzFAILtext; // workarea required by zzFAIL // MR9 void undeferFetch(); // MR19 V.H. Simonis int isDeferFetchEnabled(); // MR19 V.H. Simonis virtual void failedSemanticPredicate(const char* predicate); /* MR23 */ }; #define zzmatch(_t) \ if ( !_match((ANTLRTokenType)_t, &zzMissText, &zzMissTok, \ (_ANTLRTokenPtr *) &zzBadTok, &zzMissSet) ) goto fail; #define zzmatch_wsig(_t,handler) \ if ( !_match_wsig((ANTLRTokenType)_t) ) if ( guessing ) zzGUESS_FAIL else {_signal=MismatchedToken; goto handler;} #define zzsetmatch(_ts,_tokclassErrset) \ if ( !_setmatch(_ts, &zzMissText, &zzMissTok, \ (_ANTLRTokenPtr *) &zzBadTok, &zzMissSet, _tokclassErrset) ) goto fail; #define zzsetmatch_wsig(_ts, handler) \ if ( !_setmatch_wsig(_ts) ) if ( guessing ) zzGUESS_FAIL else {_signal=MismatchedToken; goto handler;} /* For the dflt signal matchers, a FALSE indicates that an error occurred * just like the other matchers, but in this case, the routine has already * recovered--we do NOT want to consume another token. However, when * the match was successful, we do want to consume hence _signal=0 so that * a token is consumed by the "if (!_signal) consume(); _signal=NoSignal;" * preamble. */ #define zzsetmatch_wdfltsig(tokensWanted, tokenTypeOfSet, whatFollows) \ if ( !_setmatch_wdfltsig(tokensWanted, tokenTypeOfSet, whatFollows) ) \ _signal = MismatchedToken; #define zzmatch_wdfltsig(tokenWanted, whatFollows) \ if ( !_match_wdfltsig(tokenWanted, whatFollows) ) _signal = MismatchedToken; // MR1 10-Apr-97 zzfailed_pred() macro does not backtrack in guess mode. // MR1 Identification and correction due to J. Lilley // // MR23 Call virtual method to report error. // MR23 Provide more control over failed predicate action // without any need for user to worry about guessing internals. #ifndef zzfailed_pred #define zzfailed_pred(_p,_hasuseraction,_useraction) \ if (guessing) { \ zzGUESS_FAIL; \ } else { \ zzfailed_pred_action(_p,_hasuseraction,_useraction) \ } #endif // MR23 Provide more control over failed predicate action // without any need for user to worry about guessing internals. // _hasuseraction == 0 => no user specified error action // _hasuseraction == 1 => user specified error action #ifndef zzfailed_pred_action #define zzfailed_pred_action(_p,_hasuseraction,_useraction) \ if (_hasuseraction) { _useraction } else { failedSemanticPredicate(_p); } #endif #define zzRULE \ SetWordType *zzMissSet=NULL; ANTLRTokenType zzMissTok=(ANTLRTokenType)0; \ _ANTLRTokenPtr zzBadTok=NULL; ANTLRChar *zzBadText=(ANTLRChar *)""; \ int zzErrk=1,zzpf=0; \ zzTRACEdata \ ANTLRChar *zzMissText=(ANTLRChar *)""; #endif /* S t a n d a r d E x c e p t i o n S i g n a l s */ #define NoSignal 0 #define MismatchedToken 1 #define NoViableAlt 2 #define NoSemViableAlt 3 /* MR7 Allow more control over signalling */ /* by adding "Unwind" and "SetSignal" */ #define Unwind 4 #define setSignal(newValue) *_retsignal=_signal=(newValue) #define suppressSignal *_retsignal=_signal=0 #define exportSignal *_retsignal=_signal cdrdao-cdrdao-f00afb2/pccts/h/ASTBase.cpp000066400000000000000000000152341511453746600201740ustar00rootroot00000000000000/* Abstract syntax tree manipulation functions * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2000 */ #include "pcctscfg.h" #include "pccts_stdio.h" #include "pccts_stdarg.h" PCCTS_NAMESPACE_STD #define ANTLR_SUPPORT_CODE #include "ASTBase.h" /* ensure that tree manipulation variables are current after a rule * reference */ void ASTBase::link(ASTBase **_root, ASTBase **_sibling, ASTBase **_tail) { if ( *_sibling == NULL ) return; if ( *_root == NULL ) *_root = *_sibling; else if ( *_root != *_sibling ) (*_root)->_down = *_sibling; if ( *_tail==NULL ) *_tail = *_sibling; while ( (*_tail)->_right != NULL ) *_tail = (*_tail)->_right; } /* add a child node to the current sibling list */ void ASTBase::subchild(ASTBase **_root, ASTBase **_sibling, ASTBase **_tail) { if ( *_tail != NULL ) (*_tail)->_right = this; else { *_sibling = this; if ( *_root != NULL ) (*_root)->_down = *_sibling; } *_tail = this; if ( *_root == NULL ) *_root = *_sibling; } /* make a new AST node. Make the newly-created * node the root for the current sibling list. If a root node already * exists, make the newly-created node the root of the current root. */ void ASTBase::subroot(ASTBase **_root, ASTBase **_sibling, ASTBase **_tail) { if ( *_root != NULL ) if ( (*_root)->_down == *_sibling ) *_sibling = *_tail = *_root; *_root = this; (*_root)->_down = *_sibling; } /* Apply preorder_action(), etc.. to root then each sibling */ // // 7-Apr-97 133MR1 // Fix suggested by Ron House (house@helios.usq.edu.au) // void ASTBase::preorder(void* pData /*= NULL*/ /* MR23 */) { ASTBase *tree = this; while ( tree!= NULL ) { if ( tree->_down != NULL ) { tree->preorder_before_action(pData); // MR1 }; tree->preorder_action(pData); if ( tree->_down!=NULL ) { tree->_down->preorder(pData); tree->preorder_after_action(pData); // MR1 } tree = tree->_right; } } /* free all AST nodes in tree; apply func to each before freeing */ void ASTBase::destroy() { ASTBase* tree = this; while (tree) { if (tree->_down) tree->_down->destroy(); ASTBase* cur = tree; tree = tree->_right; delete cur; } } /* build a tree (root child1 child2 ... NULL) * If root is NULL, simply make the children siblings and return ptr * to 1st sibling (child1). If root is not single node, return NULL. * * Siblings that are actually siblins lists themselves are handled * correctly. For example #( NULL, #( NULL, A, B, C), D) results * in the tree ( NULL A B C D ). * * Requires at least two parameters with the last one being NULL. If * both are NULL, return NULL. */ ASTBase * ASTBase::tmake(ASTBase *root, ...) { va_list ap; register ASTBase *child, *sibling=NULL, *tail=NULL /*MR23*/, *w; va_start(ap, root); if ( root != NULL ) if ( root->_down != NULL ) { root->reportOverwriteOfDownPointer(); /* MR21 Report problem which almost always an error */ return NULL; } child = va_arg(ap, ASTBase *); while ( child != NULL ) { for (w=child; w->_right!=NULL; w=w->_right) {;} /* find end of child */ if ( sibling == NULL ) {sibling = child; tail = w;} else {tail->_right = child; tail = w;} child = va_arg(ap, ASTBase *); } if ( root==NULL ) root = sibling; else root->_down = sibling; va_end(ap); return root; } #ifndef PCCTS_NOT_USING_SOR /* tree duplicate */ // forgot to check for NULL this (TJP July 23,1995) ASTBase * ASTBase::dup() { ASTBase *u, *t=this; if ( t == NULL ) return NULL; /* u = new ASTBase; *u = *t; */ u = (ASTBase *)this->shallowCopy(); if ( t->_right!=NULL ) u->_right = t->_right->dup(); else u->_right = NULL; if ( t->_down!=NULL ) u->_down = t->_down->dup(); else u->_down = NULL; return u; } #endif // // 7-Apr-97 133MR1 // Fix suggested by Asgeir Olafsson (olafsson@cstar.ac.com) // /* tree duplicate */ #ifndef PCCTS_NOT_USING_SOR ASTBase * ASTDoublyLinkedBase::dup() { ASTDoublyLinkedBase *u, *t=this; if ( t == NULL ) return NULL; u = (ASTDoublyLinkedBase *)this->shallowCopy(); u->_up = NULL; /* set by calling invocation */ u->_left = NULL; if (t->_right!=NULL) { // MR1 u->_right=t->_right->dup(); // MR1 ((ASTDoublyLinkedBase *)u->_right)->_left = u; // MR1 } else { // MR1 u->_right = NULL; // MR1 }; // MR1 if (t->_down!=NULL) { // MR1 u->_down = t->_down->dup(); // MR1 ((ASTDoublyLinkedBase *)u->_down)->_up = u; // MR1 } else { // MR1 u->_down = NULL; // MR1 }; // MR1 return u; } #endif /* * Set the 'up', and 'left' pointers of all nodes in 't'. * Initial call is double_link(your_tree, NULL, NULL). */ void ASTDoublyLinkedBase::double_link(ASTBase *left, ASTBase *up) { ASTDoublyLinkedBase *t = this; t->_left = (ASTDoublyLinkedBase *) left; t->_up = (ASTDoublyLinkedBase *) up; if (t->_down != NULL) ((ASTDoublyLinkedBase *)t->_down)->double_link(NULL, t); if (t->_right != NULL) ((ASTDoublyLinkedBase *)t->_right)->double_link(t, up); } // MR21 ASTBase::reportOverwriteOfDownPointer void ASTBase::reportOverwriteOfDownPointer() { panic("Attempt to overwrite down pointer in ASTBase::tmake"); } // MR21 ASTBase::panic void ASTBase::panic(const char *msg) { /* MR23 */ printMessage(stderr,"ASTBase panic: %s\n", msg); exit(PCCTS_EXIT_FAILURE); } #ifdef PCCTS_NOT_USING_SOR //MR23 int ASTBase::printMessage(FILE* pFile, const char* pFormat, ...) { va_list marker; va_start( marker, pFormat ); int iRet = vfprintf(pFile, pFormat, marker); va_end( marker ); return iRet; } #endif cdrdao-cdrdao-f00afb2/pccts/h/ASTBase.h000066400000000000000000000076331511453746600176450ustar00rootroot00000000000000/* Abstract syntax tree * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2000 */ #ifndef ASTBase_H #define ASTBase_H #include "pcctscfg.h" #include "pccts_stdio.h" #include "pccts_stdlib.h" PCCTS_NAMESPACE_STD #ifndef PCCTS_NOT_USING_SOR #include "PCCTSAST.h" #endif /* * Notes: * * To specify a copy constructor, subclass one of these classes and * give the copy constructor. To use dup(), you must define shallowCopy(). * shallowCopy() can use either a copy constructor or just copy the node * itself. */ #ifdef PCCTS_NOT_USING_SOR class DllExportPCCTS ASTBase { #else class DllExportPCCTS ASTBase : public PCCTS_AST { #endif protected: ASTBase *_right, *_down; public: #ifdef PCCTS_NOT_USING_SOR ASTBase *right() { return _right; } ASTBase *down() { return _down; } void setRight(ASTBase *t) { _right = (ASTBase *)t; } void setDown(ASTBase *t) { _down = (ASTBase *)t; } #else PCCTS_AST *right() { return _right; } // define the SORCERER interface PCCTS_AST *down() { return _down; } void setRight(PCCTS_AST *t) { _right = (ASTBase *)t; } void setDown(PCCTS_AST *t) { _down = (ASTBase *)t; } #endif ASTBase() { _right = _down = NULL; } virtual ~ASTBase() { ; } #ifndef PCCTS_NOT_USING_SOR virtual ASTBase *dup(); #endif void destroy(); void preorder(void* pData = NULL /* MR23 */); static ASTBase *tmake(ASTBase *, ...); static void link(ASTBase **, ASTBase **, ASTBase **); void subchild(ASTBase **, ASTBase **, ASTBase **); void subroot(ASTBase **, ASTBase **, ASTBase **); virtual void preorder_action(void* /*pData*/ = NULL /* MR23 */) { ; } virtual void preorder_before_action(void* /*pData*/ = NULL /* MR23 */) { /* MR23 */ printMessage(stdout, " ("); } virtual void preorder_after_action(void* /*pData*/ = NULL /* MR23 */) { /* MR23 */ printMessage(stdout, " )"); } virtual void panic(const char *msg); /* MR21 */ virtual void reportOverwriteOfDownPointer(); /* MR21 */ #ifdef PCCTS_NOT_USING_SOR virtual int printMessage(FILE* pFile, const char* pFormat, ...); // MR23 #endif }; class DllExportPCCTS ASTDoublyLinkedBase : public ASTBase { protected: ASTDoublyLinkedBase *_left, *_up; public: void double_link(ASTBase *left, ASTBase *up); #ifndef PCCTS_NOT_USING_SOR virtual ASTBase *dup(); #endif #ifdef PCCTS_NOT_USING_SOR ASTBase *left() { return _left; } ASTBase *up() { return _up; } void setLeft(ASTBase *t) { _left = (ASTDoublyLinkedBase *)t; } // MR6 void setUp(ASTBase *t) { _up = (ASTDoublyLinkedBase *)t; } // MR6 #else PCCTS_AST *left() { return _left; } PCCTS_AST *up() { return _up; } void setLeft(PCCTS_AST *t) { _left = (ASTDoublyLinkedBase *)t; } // MR6 void setUp(PCCTS_AST *t) { _up = (ASTDoublyLinkedBase *)t; } // MR6 #endif }; class AST; // announce that this class will be coming along shortly #endif cdrdao-cdrdao-f00afb2/pccts/h/ATokPtr.h000066400000000000000000000057601511453746600177460ustar00rootroot00000000000000/* ATokPtr.h * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Written by Russell Quong June 30, 1995 * Adapted by Terence Parr to ANTLR stuff * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2000 */ #ifndef ATokPtr_h #define ATokPtr_h #include "pcctscfg.h" #include "pccts_stdio.h" PCCTS_NAMESPACE_STD // pointer to a reference counted object // robust in that an unused ANTLRTokenPtr can point to NULL. class ANTLRAbstractToken; class DllExportPCCTS ANTLRTokenPtr { public: ANTLRTokenPtr(ANTLRAbstractToken *addr=NULL){ptr_ = addr; ref();} ANTLRTokenPtr(const ANTLRTokenPtr &lhs) {ptr_ = lhs.ptr_; lhs.ref();} ~ANTLRTokenPtr(); // use ANTLRTokenPtr as a pointer to ANTLRToken // // 8-Apr-97 MR1 Make operator -> a const member function // as well as some other member functions // ANTLRAbstractToken *operator-> () const { return ptr_; } // MR1 // // 7-Apr-97 133MR1 // Fix suggested by Andreas Magnusson // (Andreas.Magnusson@mailbox.swipnet.se) void operator = (const ANTLRTokenPtr & lhs); // MR1 void operator = (ANTLRAbstractToken *addr); int operator != (const ANTLRTokenPtr &q) const // MR1 // MR11 unsigned -> int { return this->ptr_ != q.ptr_; } int operator == (const ANTLRTokenPtr &q) const // MR1 // MR11 unsigned -> int { return this->ptr_ == q.ptr_; } int operator == (const ANTLRAbstractToken *addr) const // MR11 { return this->ptr_ == addr; } int operator != (const ANTLRAbstractToken *addr) const // MR11 { return this->ptr_ != addr; } void ref() const; void deref(); protected: ANTLRAbstractToken *ptr_; }; //typedef ANTLRTokenPtr _ANTLRTokenPtr; /* * Since you cannot redefine operator->() to return one of the user's * token object types, we must down cast. This is a drag. Here's * a macro that helps. template: "mytoken(a-smart-ptr)->myfield". */ #define mytoken(tk) ((ANTLRToken *)(tk.operator->())) #endif cdrdao-cdrdao-f00afb2/pccts/h/ATokPtrImpl.h000066400000000000000000000044161511453746600205650ustar00rootroot00000000000000/* * ATokPtrImpl.h (formerly ATokPtr.cpp) * * This is #included in ATokBuffer.cpp for historical reasons. * It has been renamed because of problems with the .cpp extension * when used with IDE. * * * ANTLRToken MUST be defined before entry to this file. * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Written by Russell Quong June 30, 1995 * Adapted by Terence Parr to ANTLR stuff * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2000 */ #include "pcctscfg.h" PCCTS_NAMESPACE_STD #include "ATokPtr.h" void ANTLRTokenPtr::ref() const { if (ptr_ != NULL) { ptr_->ref(); } } void ANTLRTokenPtr::deref() { if (ptr_ != NULL) { ptr_->deref(); if ( ptr_->nref()==0 ) { delete ptr_; ptr_ = NULL; } } } ANTLRTokenPtr::~ANTLRTokenPtr() { deref(); } // // 8-Apr-97 MR1 Make operator -> a const member function // as weall as some other member functions // void ANTLRTokenPtr::operator = (const ANTLRTokenPtr & lhs) // MR1 { lhs.ref(); // protect against "xp = xp"; ie same underlying object deref(); ptr_ = lhs.ptr_; } void ANTLRTokenPtr::operator = (ANTLRAbstractToken *addr) { if (addr != NULL) { addr->ref(); } deref(); ptr_ = addr; } cdrdao-cdrdao-f00afb2/pccts/h/AToken.h000066400000000000000000000232571511453746600176040ustar00rootroot00000000000000/* ANTLRToken.h * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2000 */ #ifndef ATOKEN_H_GATE #define ATOKEN_H_GATE #include "pcctscfg.h" #include "pccts_string.h" #include "pccts_stdio.h" #include "pccts_stdlib.h" #include "pccts_stdarg.h" // MR23 PCCTS_NAMESPACE_STD // MR9 RJV (JVincent@novell.com) Not needed for variable length strings //// MR9 #ifndef ANTLRCommonTokenTEXTSIZE //// MR9 #define ANTLRCommonTokenTEXTSIZE 100 //// MR9 #endif /* must define what a char looks like; can make this a class too */ typedef char ANTLRChar; /* D E F I N E S M A R T P O I N T E R S */ //#include ATOKPTR_H not tested yet, leave out class ANTLRAbstractToken; typedef ANTLRAbstractToken *_ANTLRTokenPtr; class ANTLRAbstractToken { public: virtual ~ANTLRAbstractToken() {;} virtual ANTLRTokenType getType() const = 0; virtual void setType(ANTLRTokenType t) = 0; virtual int getLine() const = 0; virtual void setLine(int line) = 0; virtual ANTLRChar *getText() const = 0; virtual void setText(const ANTLRChar *) = 0; /* This function will disappear when I can use templates */ virtual ANTLRAbstractToken *makeToken(ANTLRTokenType tt, ANTLRChar *text, int line) = 0; /* define to satisfy ANTLRTokenBuffer's need to determine whether or not a token object can be destroyed. If nref()==0, no one has a reference, and the object may be destroyed. This function defaults to 1, hence, if you use deleteTokens() message with a token object not derived from ANTLRCommonRefCountToken, the parser will compile but will not delete objects after they leave the token buffer. */ virtual unsigned nref() const { return 1; } // MR11 virtual void ref() {;} virtual void deref() {;} virtual void panic(const char *msg) // MR20 const { /* MR23 */ printMessage(stderr, "ANTLRAbstractToken panic: %s\n", msg); exit(PCCTS_EXIT_FAILURE); } virtual int printMessage(FILE* pFile, const char* pFormat, ...) // MR23 { va_list marker; va_start( marker, pFormat ); int iRet = vfprintf(pFile, pFormat, marker); va_end( marker ); return iRet; } }; /* This class should be subclassed. It cannot store token type or text */ class ANTLRRefCountToken : public ANTLRAbstractToken { public: #ifdef DBG_REFCOUNTTOKEN static int ctor; static int dtor; #endif protected: unsigned refcnt_; #ifdef DBG_REFCOUNTTOKEN char object[200]; #endif public: // MR23 - No matter what you do, you're hammered. // Don't give names to formals something breaks. // Give names to formals and don't use them it breaks. #ifndef DBG_REFCOUNTTOKEN ANTLRRefCountToken(ANTLRTokenType /* t MR23 */, const ANTLRChar * /* s MR23 */) #else ANTLRRefCountToken(ANTLRTokenType t, const ANTLRChar * s) #endif #ifndef DBG_REFCOUNTTOKEN { refcnt_ = 0; } #else { ctor++; refcnt_ = 0; if ( t==1 ) sprintf(object,"tok_EOF"); else sprintf(object,"tok_%s",s); /* MR23 */ printMessage(stderr, "ctor %s #%d\n",object,ctor); } #endif ANTLRRefCountToken() #ifndef DBG_REFCOUNTTOKEN { refcnt_ = 0; } #else { ctor++; refcnt_ = 0; sprintf(object,"tok_blank"); /* MR23 */ printMessage(stderr, "ctor %s #%d\n",object,ctor); } virtual ~ANTLRRefCountToken() { dtor++; if ( dtor>ctor ) /* MR23 */ printMessage(stderr, "WARNING: dtor>ctor\n"); /* MR23 */ printMessage(stderr, "dtor %s #%d\n", object, dtor); object[0]='\0'; } #endif // reference counting stuff needed by ANTLRTokenPtr. // User should not access these; for C++ language reasons, we had // to make these public. Yuck. void ref() { refcnt_++; } void deref() { refcnt_--; } unsigned nref() const { return refcnt_; } // MR11 virtual ANTLRAbstractToken *makeToken(ANTLRTokenType /*tt MR23*/, ANTLRChar * /*txt MR23*/, int /*line MR23*/) { panic("call to ANTLRRefCountToken::makeToken()\n"); return NULL; } }; class ANTLRCommonNoRefCountToken : public ANTLRAbstractToken { protected: ANTLRTokenType _type; int _line; ANTLRChar *_text; // MR9 RJV public: ANTLRCommonNoRefCountToken(ANTLRTokenType t, const ANTLRChar *s) { setType(t); _line = 0; _text = NULL; setText(s); } ANTLRCommonNoRefCountToken() { setType((ANTLRTokenType)0); _line = 0; _text = NULL; setText(""); } ~ANTLRCommonNoRefCountToken() { if (_text) delete [] _text; } // MR9 RJV: Added Destructor to remove string ANTLRTokenType getType() const { return _type; } void setType(ANTLRTokenType t) { _type = t; } virtual int getLine() const { return _line; } void setLine(int line) { _line = line; } ANTLRChar *getText() const { return _text; } int getLength() const { return strlen(getText()); } // MR11 // MR9 RJV: Added code for variable length strings to setText() void setText(const ANTLRChar *s) { if (s != _text) { if (_text) delete [] _text; if (s != NULL) { _text = new ANTLRChar[strlen(s)+1]; if (_text == NULL) panic("ANTLRCommonNoRefCountToken::setText new failed"); strcpy(_text,s); } else { _text = new ANTLRChar[1]; if (_text == NULL) panic("ANTLRCommonNoRefCountToken::setText new failed"); strcpy(_text,""); }; }; } virtual ANTLRAbstractToken *makeToken(ANTLRTokenType tt, ANTLRChar *txt, int line) { ANTLRAbstractToken *t = new ANTLRCommonNoRefCountToken; t->setType(tt); t->setText(txt); t->setLine(line); return t; } // MR9 THM Copy constructor required when heap allocated string is used with copy semantics ANTLRCommonNoRefCountToken (const ANTLRCommonNoRefCountToken& from) : ANTLRAbstractToken(from) { setType(from._type); setLine(from._line); _text=NULL; setText(from._text); }; // MR9 THM operator =() required when heap allocated string is used with copy semantics virtual ANTLRCommonNoRefCountToken& operator =(const ANTLRCommonNoRefCountToken& rhs) { ////// MR15 WatCom can't hack use of operator =() ////// Use this: *( (ANTRLAbstractToken *) this)=rhs; *( (ANTLRAbstractToken *) this ) = rhs; setType(rhs._type); setLine(rhs._line); setText(rhs._text); return *this; }; }; class ANTLRCommonToken : public ANTLRRefCountToken { protected: ANTLRTokenType _type; int _line; ANTLRChar *_text; // MR9 RJV:Added public: ANTLRCommonToken(ANTLRTokenType t, const ANTLRChar *s) : ANTLRRefCountToken(t,s) { setType(t); _line = 0; _text = NULL; setText(s); } // MR9 ANTLRCommonToken() { setType((ANTLRTokenType)0); _line = 0; _text = NULL; setText(""); } // MR9 virtual ~ANTLRCommonToken() { if (_text) delete [] _text; } // MR9 RJV: Added Destructor to remove string ANTLRTokenType getType() const { return _type; } void setType(ANTLRTokenType t) { _type = t; } virtual int getLine() const { return _line; } void setLine(int line) { _line = line; } ANTLRChar *getText() const { return _text; } int getLength() const { return strlen(getText()); } // MR11 // MR9 RJV: Added code for variable length strings to setText() void setText(const ANTLRChar *s) { if (s != _text) { if (_text) delete [] _text; if (s != NULL) { _text = new ANTLRChar[strlen(s)+1]; if (_text == NULL) panic("ANTLRCommonToken::setText new failed"); strcpy(_text,s); } else { _text = new ANTLRChar[1]; if (_text == NULL) panic("ANTLRCommonToken::setText new failed"); strcpy(_text,""); }; }; } virtual ANTLRAbstractToken *makeToken(ANTLRTokenType tt, ANTLRChar *txt, int line) { ANTLRAbstractToken *t = new ANTLRCommonToken(tt,txt); t->setLine(line); return t; } // MR9 THM Copy constructor required when heap allocated string is used with copy semantics ANTLRCommonToken (const ANTLRCommonToken& from) : ANTLRRefCountToken(from) { setType(from._type); setLine(from._line); _text=NULL; setText(from._text); }; // MR9 THM operator =() required when heap allocated string is used with copy semantics virtual ANTLRCommonToken& operator =(const ANTLRCommonToken& rhs) { ////// MR15 WatCom can't hack use of operator =() ////// Use this instead: *( (ANTRLRRefCountToken *) this)=rhs; *( (ANTLRRefCountToken *) this) = rhs; setType(rhs._type); setLine(rhs._line); setText(rhs._text); return *this; }; }; // used for backward compatibility typedef ANTLRCommonToken ANTLRCommonBacktrackingToken; #endif cdrdao-cdrdao-f00afb2/pccts/h/ATokenBuffer.cpp000066400000000000000000000240531511453746600212640ustar00rootroot00000000000000/* ANTLRTokenBuffer.cpp * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2000 */ typedef int ANTLRTokenType; // fool AToken.h into compiling class ANTLRParser; /* MR1 */ #define ANTLR_SUPPORT_CODE #include "pcctscfg.h" #include ATOKENBUFFER_H #include APARSER_H // MR23 typedef ANTLRAbstractToken *_ANTLRTokenPtr; #if defined(DBG_TBUF)||defined(DBG_TBUF_MARK_REW) static unsigned char test[1000]; #endif #ifdef DBG_REFCOUNTTOKEN int ANTLRRefCountToken::ctor = 0; /* MR23 */ int ANTLRRefCountToken::dtor = 0; /* MR23 */ #endif ANTLRTokenBuffer:: ANTLRTokenBuffer(ANTLRTokenStream *_input, int _k, int _chunk_size_formal) /* MR14 */ { this->input = _input; this->k = _k; buffer_size = chunk_size = _chunk_size_formal; buffer = (_ANTLRTokenPtr *) calloc(chunk_size+1,sizeof(_ANTLRTokenPtr )); if ( buffer == NULL ) { panic("cannot alloc token buffer"); } buffer++; // leave the first elem empty so tp-1 is valid ptr tp = &buffer[0]; last = tp-1; next = &buffer[0]; num_markers = 0; end_of_buffer = &buffer[buffer_size-1]; threshold = &buffer[(int)(buffer_size/2)]; // MR23 - Used to be 1.0/2.0 ! _deleteTokens = 1; // assume we delete tokens parser=NULL; // MR5 - uninitialized reference } static void f() {;} ANTLRTokenBuffer:: ~ANTLRTokenBuffer() { f(); // Delete all remaining tokens (from 0..last inclusive) if ( _deleteTokens ) { _ANTLRTokenPtr *z; for (z=buffer; z<=last; z++) { (*z)->deref(); // z->deref(); #ifdef DBG_REFCOUNTTOKEN /* MR23 */ printMessage(stderr, "##########dtor: deleting token '%s' (ref %d)\n", ((ANTLRCommonToken *)*z)->getText(), (*z)->nref()); #endif if ( (*z)->nref()==0 ) { delete (*z); } } } if ( buffer!=NULL ) free((char *)(buffer-1)); } #if defined(DBG_TBUF)||defined(DBG_TBUF_MARK_REW) #include "pccts_stdio.h" PCCTS_NAMESPACE_STD #endif _ANTLRTokenPtr ANTLRTokenBuffer:: getToken() { if ( tp <= last ) // is there any buffered lookahead still to be read? { return *tp++; // read buffered lookahead } // out of buffered lookahead, get some more "real" // input from getANTLRToken() if ( num_markers==0 ) { if( next > threshold ) { #ifdef DBG_TBUF /* MR23 */ printMessage(stderr,"getToken: next > threshold (high water is %d)\n", threshold-buffer); #endif makeRoom(); } } else { if ( next > end_of_buffer ) { #ifdef DBG_TBUF /* MR23 */ printMessage(stderr,"getToken: next > end_of_buffer (size is %d)\n", buffer_size); #endif extendBuffer(); } } *next = getANTLRToken(); (*next)->ref(); // say we have a copy of this pointer in buffer last = next; next++; tp = last; return *tp++; } void ANTLRTokenBuffer:: rewind(int pos) { #if defined(DBG_TBUF)||defined(DBG_TBUF_MARK_REW) /* MR23 */ printMessage(stderr, "rewind(%d)[nm=%d,from=%d,%d.n=%d]\n", pos, num_markers, tp-buffer,pos,test[pos]); test[pos]--; #endif tp = &buffer[pos]; num_markers--; } /* * This function is used to specify that the token pointers read * by the ANTLRTokenBuffer should be buffered up (to be reused later). */ int ANTLRTokenBuffer:: mark() { #if defined(DBG_TBUF)||defined(DBG_TBUF_MARK_REW) test[tp-buffer]++; /* MR23 */ printMessage(stderr,"mark(%d)[nm=%d,%d.n=%d]\n",tp-buffer,num_markers+1,tp-buffer,test[tp-buffer]); #endif num_markers++; return tp - buffer; } /* * returns the token pointer n positions ahead. * This implies that bufferedToken(1) gets the NEXT symbol of lookahead. * This is used in conjunction with the ANTLRParser lookahead buffer. * * No markers are set or anything. A bunch of input is buffered--that's all. * The tp pointer is left alone as the lookahead has not been advanced * with getToken(). The next call to getToken() will find a token * in the buffer and won't have to call getANTLRToken(). * * If this is called before a consume() is done, how_many_more_i_need is * set to 'n'. */ _ANTLRTokenPtr ANTLRTokenBuffer:: bufferedToken(int n) { // int how_many_more_i_need = (last-tp < 0) ? n : n-(last-tp)-1; int how_many_more_i_need = (tp > last) ? n : n-(last-tp)-1; // Make sure that at least n tokens are available in the buffer #ifdef DBG_TBUF /* MR23 */ printMessage(stderr, "bufferedToken(%d)\n", n); #endif for (int i=1; i<=how_many_more_i_need; i++) { if ( next > end_of_buffer ) // buffer overflow? { extendBuffer(); } *next = getANTLRToken(); (*next)->ref(); // say we have a copy of this pointer in buffer last = next; next++; } return tp[n - 1]; } /* If no markers are set, the none of the input needs to be saved (except * for the lookahead Token pointers). We save only k-1 token pointers as * we are guaranteed to do a getANTLRToken() right after this because otherwise * we wouldn't have needed to extend the buffer. * * If there are markers in the buffer, we need to save things and so * extendBuffer() is called. */ void ANTLRTokenBuffer:: makeRoom() { #ifdef DBG_TBUF /* MR23 */ printMessage(stderr, "in makeRoom.................\n"); /* MR23 */ printMessage(stderr, "num_markers==%d\n", num_markers); #endif /* if ( num_markers == 0 ) { */ #ifdef DBG_TBUF /* MR23 */ printMessage(stderr, "moving lookahead and resetting next\n"); _ANTLRTokenPtr *r; /* MR23 */ printMessage(stderr, "tbuf = ["); for (r=buffer; r<=last; r++) { if ( *r==NULL ) /* MR23 */ printMessage(stderr, " xxx"); else /* MR23 */ printMessage(stderr, " '%s'", ((ANTLRCommonToken *)*r)->getText()); } /* MR23 */ printMessage(stderr, " ]\n"); /* MR23 */ printMessage(stderr, "before: tp=%d, last=%d, next=%d, threshold=%d\n",tp-buffer,last-buffer,next-buffer,threshold-buffer); #endif // Delete all tokens from 0..last-(k-1) inclusive if ( _deleteTokens ) { _ANTLRTokenPtr *z; for (z=buffer; z<=last-(k-1); z++) { (*z)->deref(); // z->deref(); #ifdef DBG_REFCOUNTTOKEN /* MR23 */ printMessage(stderr, "##########makeRoom: deleting token '%s' (ref %d)\n", ((ANTLRCommonToken *)*z)->getText(), (*z)->nref()); #endif if ( (*z)->nref()==0 ) { delete (*z); } } } // reset the buffer to initial conditions, but move k-1 symbols // to the beginning of buffer and put new input symbol at k _ANTLRTokenPtr *p = buffer, *q = last-(k-1)+1; // ANTLRAbstractToken **p = buffer, **q = end_of_buffer-(k-1)+1; #ifdef DBG_TBUF /* MR23 */ printMessage(stderr, "lookahead buffer = ["); #endif for (int i=1; i<=(k-1); i++) { *p++ = *q++; #ifdef DBG_TBUF /* MR23 */ printMessage(stderr, " '%s'", ((ANTLRCommonToken *)buffer[i-1])->getText()); #endif } #ifdef DBG_TBUF /* MR23 */ printMessage(stderr, " ]\n"); #endif next = &buffer[k-1]; tp = &buffer[k-1]; // tp points to what will be filled in next last = tp-1; #ifdef DBG_TBUF /* MR23 */ printMessage(stderr, "after: tp=%d, last=%d, next=%d\n", tp-buffer, last-buffer, next-buffer); #endif /* } else { extendBuffer(); } */ } /* This function extends 'buffer' by chunk_size and returns with all * pointers at the same relative positions in the buffer (the buffer base * address could have changed in realloc()) except that 'next' comes * back set to where the next token should be stored. All other pointers * are untouched. */ void ANTLRTokenBuffer:: extendBuffer() { int save_last = last-buffer, save_tp = tp-buffer, save_next = next-buffer; #ifdef DBG_TBUF /* MR23 */ printMessage(stderr, "extending physical buffer\n"); #endif buffer_size += chunk_size; buffer = (_ANTLRTokenPtr *) realloc((char *)(buffer-1), (buffer_size+1)*sizeof(_ANTLRTokenPtr )); if ( buffer == NULL ) { panic("cannot alloc token buffer"); } buffer++; // leave the first elem empty so tp-1 is valid ptr tp = buffer + save_tp; // put the pointers back to same relative position last = buffer + save_last; next = buffer + save_next; end_of_buffer = &buffer[buffer_size-1]; threshold = &buffer[(int)(buffer_size*(1.0/2.0))]; /* // zero out new token ptrs so we'll know if something to delete in buffer ANTLRAbstractToken **p = end_of_buffer-chunk_size+1; for (; p<=end_of_buffer; p++) *p = NULL; */ } ANTLRParser * ANTLRTokenBuffer:: // MR1 setParser(ANTLRParser *p) { // MR1 ANTLRParser *old=parser; // MR1 parser=p; // MR1 input->setParser(p); // MR1 return old; // MR1 } // MR1 // MR1 ANTLRParser * ANTLRTokenBuffer:: // MR1 getParser() { // MR1 return parser; // MR1 } // MR1 void ANTLRTokenBuffer::panic(const char *msg) // MR23 { if (parser) //MR23 parser->panic(msg); //MR23 else //MR23 exit(PCCTS_EXIT_FAILURE); } //MR23 int ANTLRTokenBuffer::printMessage(FILE* pFile, const char* pFormat, ...) { va_list marker; va_start( marker, pFormat ); int iRet = 0; if (parser) parser->printMessageV(pFile, pFormat, marker); else iRet = vfprintf(pFile, pFormat, marker); va_end( marker ); return iRet; } /* to avoid having to link in another file just for the smart token ptr * stuff, we include it here. Ugh. * * MR23 This causes nothing but problems for IDEs. * Change from .cpp to .h * */ #include ATOKPTR_IMPL_H cdrdao-cdrdao-f00afb2/pccts/h/ATokenBuffer.h000066400000000000000000000076361511453746600207410ustar00rootroot00000000000000/* ANTLRTokenBuffer.h * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2000 */ #ifndef ATOKENBUFFER_H_GATE #define ATOKENBUFFER_H_GATE #include "pcctscfg.h" #include "pccts_stdlib.h" PCCTS_NAMESPACE_STD #include ATOKEN_H #include ATOKENSTREAM_H /* * The parser is "attached" to an ANTLRTokenBuffer via interface * functions: getToken() and bufferedToken(). The object that actually * consumes characters and constructs tokens is connected to the * ANTLRTokenBuffer via interface function ANTLRTokenStream::getToken(); * where ANTLRTokenStream is really just a behavior (class with no data). * C++ does not have this abstraction and hence we simply have come up * with a fancy name for "void *". See the note in ANTLRTokenStream.h on * the "behavior" of ANTLRTokenStream. */ class ANTLRParser; // MR1 class DllExportPCCTS ANTLRTokenBuffer { protected: ANTLRTokenStream *input; // where do I get tokens int buffer_size; int chunk_size; int num_markers; int k; // Need at least this many tokens in buffer _ANTLRTokenPtr *buffer; // buffer used for arbitrary lookahead _ANTLRTokenPtr *tp; // pts into buffer; current token ptr _ANTLRTokenPtr *last; // pts to last valid token in buffer _ANTLRTokenPtr *next; // place to put token from getANTLRToken() _ANTLRTokenPtr *end_of_buffer; /* when you try to write a token past this and there are no markers set, then move k-1 tokens back to the beginning of the buffer. We want to stay away from the end of the buffer because we have to extend it if a marker is set and we reach the end (we cannot move tokens to the beginning of the buffer in this case). */ _ANTLRTokenPtr *threshold; unsigned char _deleteTokens; // This function is filled in by the subclass; it initiates fetch of input virtual _ANTLRTokenPtr getANTLRToken() { return input->getToken(); } void makeRoom(); void extendBuffer(); public: ANTLRTokenBuffer(ANTLRTokenStream *in, int k=1, int chksz=50); virtual ~ANTLRTokenBuffer(); virtual _ANTLRTokenPtr getToken(); virtual void rewind(int pos); virtual int mark(); virtual _ANTLRTokenPtr bufferedToken(int i); void noGarbageCollectTokens() { _deleteTokens=0; } void garbageCollectTokens() { _deleteTokens=1; } virtual int bufferSize() { return buffer_size; } virtual int minTokens() { return k; } virtual void setMinTokens(int k_new) { k = k_new; } virtual void panic(const char *msg); /* MR20 const */ virtual int printMessage(FILE* pFile, const char* pFormat, ...); // MR23 protected: // MR1 ANTLRParser *parser; // MR1 public: // MR1 ANTLRParser *setParser(ANTLRParser *p); // MR1 ANTLRParser *getParser(); // MR1 ANTLRTokenStream *getLexer() const { // MR12 return input;} // MR12 }; #endif cdrdao-cdrdao-f00afb2/pccts/h/ATokenStream.h000066400000000000000000000037451511453746600207600ustar00rootroot00000000000000/* ANTLRTokenStream.h * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2000 */ #ifndef ATOKENSTREAM_H_GATE #define ATOKENSTREAM_H_GATE #include "pcctscfg.h" /* This is really a behavior or protocol; it merely indicates the behavior * required of the input and output of an ANTLRTokenBuffer. You could * subclass it, but you can also just pass any old pointer to ANTLRTokenBuffer * with a type cast (in which case, your getANTLRToken() would have to * explicitly cast the input pointer to your REAL type (typically your lexer)). */ class ANTLRParser; // MR1 class DllExportPCCTS ANTLRTokenStream { public: virtual _ANTLRTokenPtr getToken() = 0; virtual ~ANTLRTokenStream() {} virtual ANTLRParser * setParser(ANTLRParser * /*p MR23*/) {return 0; }; // MR12 virtual ANTLRParser * getParser() { return 0; }; // MR12 }; #endif cdrdao-cdrdao-f00afb2/pccts/h/BufFileInput.cpp000066400000000000000000000037321511453746600213060ustar00rootroot00000000000000// FILE: BufFileInput.cpp // AUTHOR: Alexey Demakov (AVD) demakov@kazbek.ispras.ru // CREATION: 26-JAN-1998 // DESCRIPTION: File Input Stream with lookahead for Scanner. // See file BufFileInput.h for details // Change History: // // 22-Jun-1998 assert.h -> PCCTS_ASSERT_H // string.h -> PCCTS_STRING_H // // 28-May-1998 Add virtual destructor to release buffer. // // Add dummy definition for ANTLRTokenType // to allow compilation without knowing // token type codes. // // Manfred Kogler (km@cast.uni-linz.ac.at) // (1.33MR14) // // 20-Jul-1998 MR14a - Reorder initialization list for ctor. // enum ANTLRTokenType {TER_HATES_CPP=0, SO_DO_OTHERS=9999 }; #include "pcctscfg.h" #include "pccts_assert.h" #include "pccts_string.h" PCCTS_NAMESPACE_STD #include "BufFileInput.h" BufFileInput::BufFileInput( FILE *f, int buf_size ) : input( f ), buf( new int[buf_size] ), size( buf_size ), start( 0 ), len( 0 ) { } BufFileInput::~BufFileInput() { delete [] buf; } int BufFileInput::nextChar( void ) { if( len > 0 ) { // get char from buffer int c = buf[start]; if( c != EOF ) { start++; start %= size; len--; } return c; } else { // get char from file int c = getc( input ); if( c == EOF ) { // if EOF - put it in the buffer as indicator buf[start] = EOF; len++; } return c; } } int BufFileInput::lookahead( char* s ) { int l = strlen( s ); assert( 0 < l && l <= size ); while( len < l ) { int c = getc( input ); buf[ (start+len) % size ] = c; len++; if( c == EOF ) return 0; } for( int i = 0; i < l; i++ ) { if( s[i] != buf[ (start+i) % size ] ) return 0; } return 1; } // End of file BufFileInput.cpp cdrdao-cdrdao-f00afb2/pccts/h/BufFileInput.h000066400000000000000000000023731511453746600207530ustar00rootroot00000000000000// FILE: BufFileInput.h // AUTHOR: Alexey Demakov (AVD) demakov@kazbek.ispras.ru // CREATION: 26-JAN-1998 // DESCRIPTION: File Input Stream with lookahead for Scanner // Tested under Win32 with ANTLR 1.33 MR10 and MSVC 5.0 // Change History: // // 28-May-1998 Add virtual destructor to release buffer // Manfred Kogler (km@cast.uni-linz.ac.at) // (1.33MR14) #ifndef BufFileInput_h #define BufFileInput_h #include "pcctscfg.h" #include "pccts_stdio.h" PCCTS_NAMESPACE_STD #include "DLexerBase.h" class DllExportPCCTS BufFileInput : public DLGInputStream { public: // constructor // f - input stream // buf_size - size of buffer (maximal length for string in is_in) BufFileInput(FILE *f, int buf_size = 8 ); virtual ~BufFileInput(); // gets next char from stream virtual int nextChar( void ); // looks in stream and compares next l characters with s // returns the result of comparision int lookahead( char* s ); private: FILE *input; // input stream; int* buf; // buffer int size; // size of buffer int start; // position of the first symbol in buffer int len; // count of characters in buffers }; #endif // end of file BufFileInput.h cdrdao-cdrdao-f00afb2/pccts/h/DLG_stream_input.h000066400000000000000000000035431511453746600216170ustar00rootroot00000000000000 /************************************************************/ /* */ /* Predefined char stream: Input from (c++) stream. */ /* */ /* By Hubert Holin (Hubert.Holin@Bigfoot.com), 1998. */ /* */ /* This is completely free stuff, do whatever you want with */ /* it (but then, I will take no responsability for whatever */ /* may happen if you do either... caveat emptor!). */ /* */ /************************************************************/ #ifndef _DLG_STREAM_INPUT_H #define _DLG_STREAM_INPUT_H #include "pccts_istream.h" PCCTS_NAMESPACE_STD #ifndef DLGX_H #include "DLexerBase.h" #endif // NOTES: The semantics of the copy constructor // and the affectation operator may be unwaranted... // and the stream may not be reset. // // It would have been so much nicer for nextChar() // to throw (of for the DLGInputStream to change status) // upon hiting EOF than to return an "int"... template < class E, class T = ::std::char_traits > class DLG_stream_input : public DLGInputStream { public: DLG_stream_input(::std::basic_istream * p_input_stream) : input(p_input_stream) { // nothing to do! }; DLG_stream_input(const DLG_stream_input & a_recopier) : input(a_recopier.input) { // nothing to do! }; virtual ~DLG_stream_input() { this->purge(); // bloody templarized lookup... }; DLG_stream_input operator = (const DLG_stream_input & a_affecter) { if (this != &a_affecter) { input = a_affecter.input; } return(*this); }; virtual int nextChar() { E extracted_stuff; input->get(extracted_stuff); if (*input) { return(int(extracted_stuff)); } else { return(EOF); } }; protected: ::std::basic_istream * input; private: void purge() { // nothing to do! }; }; #endif /* _DLG_STREAM_INPUT_H */ cdrdao-cdrdao-f00afb2/pccts/h/DLexer.h000066400000000000000000000116141511453746600176000ustar00rootroot00000000000000/* DLexer.h (formerly DLexer.cpp) * * This was renamed because the use of the .cpp extension caused problems * with IDEs. * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2000 */ #define ZZINC {if ( track_columns ) (++_endcol);} #define ZZGETC {ch = input->nextChar(); cl = ZZSHIFT(ch);} #define ZZNEWSTATE (newstate = dfa[state][cl]) #ifndef ZZCOPY #define ZZCOPY \ /* Truncate matching buffer to size (not an error) */ \ if (nextpos < lastpos){ \ *(nextpos++) = ch; \ }else{ \ bufovf = 1; \ } #endif void DLGLexer:: mode( int m ) { /* points to base of dfa table */ if (m*actions[accepts[state]])(); // MR1 // MR1 11-Apr-97 Help for tracking DLG results // MR1 #ifdef DEBUG_LEXER /* MR1 */ if (debugLexerFlag) { /* MR1 */ if (parser != NULL) { /* MR1 */ /* MR23 */ printMessage(stdout, "\ntoken name=%s",parser->parserTokenName(tk)); /* MR1 */ } else { /* MR1 */ /* MR23 */ printMessage(stdout, "\ntoken nnumber=%d",tk); /* MR1 */ }; /* MR1 */ /* MR23 */ printMessage(stdout, " lextext=(%s) mode=%d", /* MR1 */ (_lextext[0]=='\n' && _lextext[1]==0) ? /* MR1 */ "newline" : _lextext, /* MR1 */ automaton); /* MR1 */ if (interactive && !charfull) { /* MR1 */ /* MR23 */ printMessage(stdout, " char=empty"); /* MR1 */ } else { /* MR1 */ if (ch=='\n') { /* MR1 */ /* MR23 */ printMessage(stdout, " char=newline"); /* MR1 */ } else { /* MR1 */ /* MR23 */ printMessage(stdout, " char=(%c)",ch); /* MR1 */ }; /* MR1 */ }; /* MR1 */ /* MR23 */ printMessage(stdout, " %s\n", /* MR1 */ (add_erase==1 ? "skip()" : /* MR1 */ add_erase==2 ? "more()" : /* MR1 */ "")); /* MR1 */ }; #endif switch (add_erase) { case 1: goto skip; case 2: goto more; } return tk; } void DLGLexer:: advance() { if ( input==NULL ) err_in(); ZZGETC; charfull = 1; ZZINC; } cdrdao-cdrdao-f00afb2/pccts/h/DLexerBase.cpp000066400000000000000000000162741511453746600207350ustar00rootroot00000000000000/* DLGLexerBase.c * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2000 */ #include "pcctscfg.h" #include "pccts_stdio.h" #include "pccts_stdlib.h" PCCTS_NAMESPACE_STD /* I have to put this here due to C++ limitation * that you can't have a 'forward' decl for enums. * I hate C++!!!!!!!!!!!!!!! */ // MR1 // MR1 10-Apr-97 133MR1 Prevent use of varying sizes for the // MR1 ANTLRTokenType enum // MR1 enum ANTLRTokenType { TER_HATES_CPP=0, ITS_UTTER_GARBAGE, // MR1 WITH_SOME_GOOD_IDEAS=9999}; // MR1 #define ANTLR_SUPPORT_CODE #include "pcctscfg.h" #include DLEXERBASE_H #include APARSER_H // MR23 DLGLexerBase:: DLGLexerBase(DLGInputStream *in, unsigned bufsize, int _interactive, int _track_columns) { this->_bufsize = bufsize; this->_lextext = new DLGChar[_bufsize]; if ( this->_lextext==NULL ) { panic("text buffer is NULL"); } this->_begexpr = this->_endexpr = NULL; this->ch = this->bufovf = 0; this->nextpos = NULL; this->cl = 0; this->add_erase = 0; this->input = in; this->_begcol = 0; this->_endcol = 0; this->_line = 1; this->charfull = 0; this->automaton = 0; this->token_to_fill = NULL; this->interactive = _interactive; this->track_columns = _track_columns; this->debugLexerFlag = 0; // MR1 this->parser = NULL; // MR1 this->lexErrCount=0; // MR11 } // MR19 THM void DLGLexerBase::reset() { this->charfull = 0; this->_begcol = 0; this->_endcol = 0; this->automaton = 0; this->_line=1; this->lexErrCount=0; } void DLGLexerBase:: setInputStream( DLGInputStream *in ) { this->input = in; _line = 1; charfull = 0; } /* saves dlg state, but not what feeds dlg (such as file position) */ void DLGLexerBase:: saveState(DLGState *state) { state->input = input; state->interactive = interactive; state->track_columns = track_columns; state->auto_num = automaton; state->add_erase = add_erase; state->lookc = ch; state->char_full = charfull; state->begcol = _begcol; state->endcol = _endcol; state->line = _line; state->lextext = _lextext; state->begexpr = _begexpr; state->endexpr = _endexpr; state->bufsize = _bufsize; state->bufovf = bufovf; state->nextpos = nextpos; state->class_num = cl; state->debugLexerFlag = debugLexerFlag; // MR1 state->parser = parser; // MR1 } void DLGLexerBase:: restoreState(DLGState *state) { input = state->input; interactive = state->interactive; track_columns = state->track_columns; automaton = state->auto_num; add_erase = state->add_erase; ch = state->lookc; charfull = state->char_full; _begcol = state->begcol; _endcol = state->endcol; _line = state->line; _lextext = state->lextext; _begexpr = state->begexpr; _endexpr = state->endexpr; _bufsize = state->bufsize; bufovf = state->bufovf; nextpos = state->nextpos; cl = state->class_num; debugLexerFlag = state->debugLexerFlag; // MR1 parser = state->parser; // MR1 } /* erase what is currently in the buffer, and get a new reg. expr */ void DLGLexerBase:: skip() { add_erase = 1; } /* don't erase what is in the lextext buffer, add on to it */ void DLGLexerBase:: more() { add_erase = 2; } /* substitute c for the reg. expr last matched and is in the buffer */ void DLGLexerBase:: replchar(DLGChar c) { /* can't allow overwriting null at end of string */ if (_begexpr < &_lextext[_bufsize-1]){ *_begexpr = c; *(_begexpr+1) = '\0'; } _endexpr = _begexpr; if (c != '\0') { nextpos = _begexpr + 1; } else { nextpos = _begexpr; /* MR30 Zero terminates string. */ } } /* replace the string s for the reg. expr last matched and in the buffer */ #ifdef _MSC_VER // MR23 //Turn off "assignment within conditional expression" warning #pragma warning(disable : 4706) #endif void DLGLexerBase:: replstr(const DLGChar *s) /* MR20 const */ { DLGChar *l= &_lextext[_bufsize -1]; nextpos = _begexpr; if (s){ while ((nextpos <= l) && (*(nextpos++) = *(s++))){ /* empty */ } /* correct for NULL at end of string */ nextpos--; } if ((nextpos <= l) && (*(--s) == 0)){ bufovf = 0; }else{ bufovf = 1; } *(nextpos) = '\0'; _endexpr = nextpos - 1; } #ifdef _MSC_VER // MR23 #pragma warning(default: 4706) #endif void DLGLexerBase:: errstd(const char *s) /* MR20 const */ { lexErrCount++; /* MR11 */ /* MR23 */ printMessage(stderr, "%s near line %d (text was '%s')\n", ((s == NULL) ? "Lexical error" : s), _line,_lextext); } int DLGLexerBase:: err_in() { /* MR23 */ printMessage(stderr,"No input stream, function, or string\n"); /* return eof to get out gracefully */ return EOF; } ANTLRTokenType DLGLexerBase:: erraction() { errstd("invalid token"); advance(); skip(); return (ANTLRTokenType) 0; // bogus, but satisfies compiler } _ANTLRTokenPtr DLGLexerBase:: getToken() { if ( token_to_fill==NULL ) panic("NULL token_to_fill"); ANTLRTokenType tt = nextTokenType(); _ANTLRTokenPtr tk = token_to_fill->makeToken(tt, _lextext,_line); return tk; } void DLGLexerBase:: panic(const char *msg) /* MR20 const */ { if (parser) //MR23 parser->panic(msg); //MR23 else //MR23 { /* MR23 */ printMessage(stderr, "DLG panic: %s\n", msg); // // 7-Apr-97 133MR1 // exit(PCCTS_EXIT_FAILURE); // MR1 } } ANTLRParser * DLGLexerBase:: // MR1 setParser(ANTLRParser *p) { // MR1 ANTLRParser *oldValue=parser; // MR1 parser=p; // MR1 return oldValue; // MR1 } // MR1 // MR1 ANTLRParser * DLGLexerBase:: // MR1 getParser() { // MR1 return parser; // MR1 } // MR1 // MR1 int DLGLexerBase:: // MR1 debugLexer(int newValue) { // MR1 int oldValue=debugLexerFlag; // MR1 debugLexerFlag=newValue; // MR1 return oldValue; // MR1 } // MR1 //MR23 int DLGLexerBase::printMessage(FILE* pFile, const char* pFormat, ...) { va_list marker; va_start( marker, pFormat ); int iRet = 0; if (parser) parser->printMessageV(pFile, pFormat, marker); else iRet = vfprintf(pFile, pFormat, marker); va_end( marker ); return iRet; } cdrdao-cdrdao-f00afb2/pccts/h/DLexerBase.h000066400000000000000000000140601511453746600203710ustar00rootroot00000000000000/* DLGLexerBase.h * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2000 */ #ifndef DLGX_H #define DLGX_H #include "pcctscfg.h" #include "pccts_stdio.h" PCCTS_NAMESPACE_STD #include ATOKEN_H #include ATOKENSTREAM_H class ANTLRParser; // MR1 /* must define what a char looks like; can make this a class too */ typedef char DLGChar; /* Can have it as a class too: (ack this looks weird; is it right?) class DllExportPCCTS DLGChar { private: int c; public: DLGChar(int ch) { c = ch; } int atom() { return c; } }; */ /* user must subclass this */ class DllExportPCCTS DLGInputStream { public: virtual ~DLGInputStream() {} virtual int nextChar() = 0; }; /* Predefined char stream: Input from FILE */ class DllExportPCCTS DLGFileInput : public DLGInputStream { private: int found_eof; FILE *input; public: DLGFileInput(FILE *f) { input = f; found_eof = 0; } virtual ~DLGFileInput() {} int nextChar() { int c; if ( found_eof ) return EOF; else { c=getc(input); if ( c==EOF ) found_eof = 1; return c; } } void DLGFileReset(FILE *f) {input=f; found_eof = 0; }; // MR11 }; // MR9 Suggested by Bruce Guenter (bruceg@qcc.sk.ca) // MR9 Make DLGStringInput const correct /* Predefined char stream: Input from string */ class DllExportPCCTS DLGStringInput : public DLGInputStream { private: const DLGChar *input; // MR9 const DLGChar *p; // MR9 public: DLGStringInput(const DLGChar *s) { input = s; p = &input[0];} // MR9 ~DLGStringInput() {} int nextChar() { if (*p) return (int) (unsigned char) *p++; // MR14 else return EOF; } void DLGStringReset(const DLGChar *s) {input=s; p= &input[0]; }; // MR11 // MR16 }; class DllExportPCCTS DLGState { public: DLGInputStream *input; int interactive; int track_columns; int auto_num; int add_erase; int lookc; int char_full; int begcol, endcol; int line; DLGChar *lextext, *begexpr, *endexpr; int bufsize; int bufovf; DLGChar *nextpos; int class_num; int debugLexerFlag; // MR1 ANTLRParser *parser; // MR1 }; /* user must subclass this */ class DllExportPCCTS DLGLexerBase : public ANTLRTokenStream { public: virtual ANTLRTokenType erraction(); protected: DLGInputStream *input; int interactive; int track_columns; DLGChar *_lextext; /* text of most recently matched token */ DLGChar *_begexpr; /* beginning of last reg expr recogn. */ DLGChar *_endexpr; /* beginning of last reg expr recogn. */ int _bufsize; /* number of characters in lextext */ int _begcol; /* column that first character of token is in*/ int _endcol; /* column that last character of token is in */ int _line; /* line current token is on */ int ch; /* character to determine next state */ int bufovf; /* indicates that buffer too small for text */ int charfull; DLGChar *nextpos; /* points to next available position in lextext*/ int cl; int automaton; int add_erase; DLGChar ebuf[70]; _ANTLRTokenPtr token_to_fill; int debugLexerFlag; // MR1 ANTLRParser *parser; // MR1 public: virtual _ANTLRTokenPtr getToken(); // MR12 public virtual void advance(void) = 0; void skip(void); /* erase lextext, look for antoher token */ void more(void); /* keep lextext, look for another token */ void mode(int k); /* switch to automaton 'k' */ void saveState(DLGState *); void restoreState(DLGState *); virtual ANTLRTokenType nextTokenType(void)=0;/* get next token */ void replchar(DLGChar c); /* replace last recognized reg. expr. with a character */ void replstr(const DLGChar *s); /* replace last recognized reg. expr. with a string */ /* MR20 const */ virtual int err_in(); // MR1 virtual void errstd(const char *); // MR1 MR20 const int line() { return _line; } void set_line(int newValue) { _line=newValue; }; // MR1 virtual void newline() { _line++; } DLGChar *lextext() { return _lextext; } int begcol() { return _begcol; } int endcol() { return _endcol; } void set_begcol(int a) { _begcol=a; } void set_endcol(int a) { _endcol=a; } DLGChar *begexpr() { return _begexpr; } DLGChar *endexpr() { return _endexpr; } int bufsize() { return _bufsize; } void setToken(ANTLRAbstractToken *t) { token_to_fill = t; } void setInputStream(DLGInputStream *); DLGLexerBase(DLGInputStream *in, unsigned bufsize=2000, int interactive=0, int track_columns=0); void reset(); // MR19 virtual ~DLGLexerBase() { delete [] _lextext; } virtual void panic(const char *msg); // MR1 MR20 const void trackColumns() { track_columns = 1; this->_begcol = 0; this->_endcol = 0; }; virtual ANTLRParser *setParser(ANTLRParser *p); // MR1 virtual ANTLRParser *getParser(); // MR1 virtual int debugLexer(int value); // MR1 int lexErrCount; // MR12 virtual int printMessage(FILE* pFile, const char* pFormat, ...); // MR23 }; #endif cdrdao-cdrdao-f00afb2/pccts/h/PBlackBox.h000066400000000000000000000065111511453746600202220ustar00rootroot00000000000000#ifndef PBLACKBOX_H #define PBLACKBOX_H /* * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2000 */ /* Completely rewritten by Chris Uzdavinis (chris@atdesk.com) for MR23 */ #include "pcctscfg.h" #include "pccts_iostream.h" PCCTS_NAMESPACE_STD // MR20 Added #include for "DLexerBase.h" #include "DLexerBase.h" // // The default buffer size of the lexer is given by the // second argument of the lexer's ctor. It is optional // and defaults to 2000 // template class DllExportPCCTS ParserBlackBox { private: // no copy construction allowed ParserBlackBox(ParserBlackBox const &); // no copy assignment allowed ParserBlackBox & operator=(ParserBlackBox const &); protected: DLGFileInput *in; Lexer *scan; _ANTLRTokenPtr tok; ANTLRTokenBuffer *pipe; Parser *_parser; FILE *file; int openByBlackBox; /* MR21 Don't close what we haven't opened */ public: ParserBlackBox(FILE *f) : in(0) , scan(0) , tok(0) , pipe(0) , _parser(0) , file(0) , openByBlackBox(0) { if (f == NULL) { cerr << "invalid file pointer\n"; } else { openByBlackBox = 0; /* MR21a */ file = f; in = new DLGFileInput(f); scan = new Lexer(in); pipe = new ANTLRTokenBuffer(scan); tok = new Token; scan->setToken(tok); _parser = new Parser(pipe); _parser->init(); } } ParserBlackBox(char *fname) : in(0) , scan(0) , tok(0) , pipe(0) , _parser(0) , file(0) , openByBlackBox(0) { FILE *f = fopen(fname, "r"); if ( f==NULL ) { openByBlackBox = 0; cerr << "cannot open " << fname << "\n"; return; } else { openByBlackBox = 1; file = f; in = new DLGFileInput(f); scan = new Lexer(in); pipe = new ANTLRTokenBuffer(scan); tok = new Token; scan->setToken(tok); _parser = new Parser(pipe); _parser->init(); } } ~ParserBlackBox() { delete in; delete scan; delete pipe; delete _parser; delete tok; if (1 == openByBlackBox) { fclose(file); } } Parser *parser() { return _parser; } Lexer *getLexer() { return scan; } }; #endif cdrdao-cdrdao-f00afb2/pccts/h/PCCTSAST.cpp000066400000000000000000000405041511453746600201740ustar00rootroot00000000000000/* * PCCTSAST.C * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to SORCERER -- SORCERER is in the public * domain. An individual or company may do whatever they wish with * source code distributed with SORCERER or the code generated by * SORCERER, including the incorporation of SORCERER, or its output, into * commerical software. * * We encourage users to develop software with SORCERER. However, we do * ask that credit is given to us for developing SORCERER. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like SORCERER and have developed a nice tool with the * output, please mention that you developed it using SORCERER. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * SORCERER 1.00B14 and ANTLR 1.33 * Terence Parr * Parr Research Corporation * AHPCRC, University of Minnesota * 1992-2000 */ #define ANTLR_SUPPORT_CODE #include "pcctscfg.h" #include "PCCTSAST.h" #include "pccts_stdarg.h" PCCTS_NAMESPACE_STD #include //#include "SList.h" /* String Scanning/Parsing Stuff */ const char *PCCTS_AST::scan_token_tbl[] = { /* MR20 const */ "invalid", /* 0 */ "LPAREN", /* 1 */ "RPAREN", /* 2 */ "PERCENT", /* 3 */ "INT", /* 4 */ "COLON", /* 5 */ "POUND", /* 6 */ "PERIOD", /* 7 */ }; void PCCTS_AST:: addChild(PCCTS_AST *t) { if ( t==NULL ) return; PCCTS_AST *s = down(); if ( s!=NULL ) { while ( s->right()!=NULL ) s = s->right(); s->setRight(t); } else this->setDown(t); } void PCCTS_AST:: lisp(FILE *f) { if ( down() != NULL ) /* MR23 */ printMessage(f," ("); lisp_action(f); if ( down()!=NULL ) down()->lisp(f); if ( down() != NULL ) /* MR23 */ printMessage(f," )"); if ( right()!=NULL ) right()->lisp(f); } /* build a tree (root child1 child2 ... NULL) * If root is NULL, simply make the children siblings and return ptr * to 1st sibling (child1). If root is not single node, return NULL. * * Siblings that are actually sibling lists themselves are handled * correctly. For example #( NULL, #( NULL, A, B, C), D) results * in the tree ( NULL A B C D ). * * Requires at least two parameters with the last one being NULL. If * both are NULL, return NULL. * * The down() and right() down/right pointers are used to make the tree. */ PCCTS_AST *PCCTS_AST:: make(PCCTS_AST *rt, ...) { va_list ap; register PCCTS_AST *child, *sibling=NULL, *tail=NULL /*MR23*/, *w; PCCTS_AST *root; va_start(ap, rt); root = rt; if ( root != NULL ) if ( root->down() != NULL ) return NULL; child = va_arg(ap, PCCTS_AST *); while ( child != NULL ) { /* find end of child */ for (w=child; w->right()!=NULL; w=w->right()) {;} if ( sibling == NULL ) {sibling = child; tail = w;} else {tail->setRight(child); tail = w;} child = va_arg(ap, PCCTS_AST *); } if ( root==NULL ) root = sibling; else root->setDown(sibling); va_end(ap); return root; } /* The following push and pop routines are only used by ast_find_all() */ void PCCTS_AST:: _push(PCCTS_AST **st, int *sp, PCCTS_AST *e) { (*sp)--; require((*sp)>=0, "stack overflow"); st[(*sp)] = e; } PCCTS_AST *PCCTS_AST:: _pop(PCCTS_AST **st, int *sp) { PCCTS_AST *e = st[*sp]; (*sp)++; require((*sp)<=MaxTreeStackDepth, "stack underflow"); return e; } /* Find all occurrences of u in t. * 'cursor' must be initialized to 't'. It eventually * returns NULL when no more occurrences of 'u' are found. */ PCCTS_AST *PCCTS_AST:: ast_find_all(PCCTS_AST *u, PCCTS_AST **cursor) { PCCTS_AST *sib; /*** static ***/ PCCTS_AST *template_stack[MaxTreeStackDepth]; /* MR23 Remove "static" */ /*** static ***/ int tsp = MaxTreeStackDepth; /* MR23 Remove "static" */ ////static int nesting = 0; /* MR23 Not referenced */ if ( *cursor == NULL ) return NULL; if ( *cursor!=this ) sib = *cursor; else { /* else, first time--start at top of template 't' */ tsp = MaxTreeStackDepth; sib = this; /* bottom of stack is always a NULL--"cookie" indicates "done" */ _push(template_stack, &tsp, NULL); } keep_looking: if ( sib==NULL ) /* hit end of sibling list */ { sib = _pop(template_stack, &tsp); if ( sib == NULL ) { *cursor = NULL; return NULL; } } if ( sib->type() != u->type() ) { /* look for another match */ if ( sib->down()!=NULL ) { if ( sib->right()!=NULL ) _push(template_stack, &tsp, sib->right()); sib=sib->down(); goto keep_looking; } /* nothing below to try, try next sibling */ sib=sib->right(); goto keep_looking; } /* found a matching root node, try to match what's below */ if ( match_partial(sib, u) ) { /* record sibling cursor so we can pick up next from there */ if ( sib->down()!=NULL ) { if ( sib->right()!=NULL ) _push(template_stack, &tsp, sib->right()); *cursor = sib->down(); } else if ( sib->right()!=NULL ) *cursor = sib->right(); else *cursor = _pop(template_stack, &tsp); return sib; } /* no match, keep searching */ if ( sib->down()!=NULL ) { if ( sib->right()!=NULL ) _push(template_stack, &tsp, sib->right()); sib=sib->down(); } else sib = sib->right(); /* else, try to right if zip below */ goto keep_looking; } /* are two trees exactly alike? */ int PCCTS_AST:: match(PCCTS_AST *u) { PCCTS_AST *t = this; PCCTS_AST *sib; if ( u==NULL ) return 0; for (sib=t; sib!=NULL&&u!=NULL; sib=sib->right(), u=u->right()) { if ( sib->type() != u->type() ) return 0; if ( sib->down()!=NULL ) if ( !sib->down()->match(u->down()) ) return 0; } return 1; } /* Is 'u' a subtree of 't' beginning at the root? */ int PCCTS_AST:: match_partial(PCCTS_AST *t, PCCTS_AST *u) { PCCTS_AST *sib; if ( u==NULL ) return 1; if ( t==NULL ) return 0; /* MR23 removed unreachable code */ for (sib=t; sib!=NULL&&u!=NULL; sib=sib->right(), u=u->right()) { if ( sib->type() != u->type() ) return 0; if ( sib->down()!=NULL ) if ( !match_partial(sib->down(), u->down()) ) return 0; } return 1; } #ifdef _MSC_VER // MR23 //Turn off "unreachable code" warning #pragma warning(disable : 4702) #endif /* Walk the template tree 't' (matching against 'this'), filling in the * 'labels' array, and setting 'n' according to how many labels were matched. */ int PCCTS_AST:: scanmatch(ScanAST *t, PCCTS_AST **labels[], int *n) { ScanAST *sib; PCCTS_AST *u = this; if ( u==NULL ) return 0; for (sib=t; sib!=NULL&&u!=NULL; sib=sib->right(), u=u->right()) { /* make sure tokens match; token of '0' means wildcard match */ if ( sib->type() != u->type() && sib->type()!=0 ) return 0; /* we have a matched token here; set label pointers if exists */ if ( sib->label_num>0 ) { require(labels!=NULL, "label found in template, but no array of labels"); (*n)++; *(labels[sib->label_num-1]) = u; } /* match what's below if something there and current node is not wildcard */ if ( sib->down()!=NULL && sib->type()!=0 ) { if ( sib->down()==NULL ) { if ( u->down()!=NULL ) return 0; else return 1; } if ( !u->down()->scanmatch(sib->down(), labels, n) ) return 0; } } return 1; } #ifdef _MSC_VER // MR23 #pragma warning(default : 4702) #endif void PCCTS_AST:: insert_after(PCCTS_AST *b) { PCCTS_AST *end; if ( b==NULL ) return; /* find end of b's child list */ for (end=b; end->right()!=NULL; end=end->right()) {;} end->setRight(this->right()); this->setRight(b); } void PCCTS_AST:: append(PCCTS_AST *b) { PCCTS_AST *end; require(b!=NULL, "append: NULL input tree"); /* find end of child list */ for (end=this; end->right()!=NULL; end=end->right()) {;} end->setRight(b); } PCCTS_AST *PCCTS_AST:: tail() { PCCTS_AST *end; /* find end of child list */ for (end=this; end->right()!=NULL; end=end->right()) {;} return end; } PCCTS_AST *PCCTS_AST:: bottom() { PCCTS_AST *end; /* find end of child list */ for (end=this; end->down()!=NULL; end=end->down()) {;} return end; } PCCTS_AST *PCCTS_AST:: cut_between(PCCTS_AST *a, PCCTS_AST *b) { PCCTS_AST *end, *ret; if (a==NULL||b==NULL) return NULL; /* find node pointing to b */ for (end=a; end->right()!=NULL&&end->right()!=b; end=end->right()) {;} if (end->right()==NULL) return NULL; //ast_cut_between: a,b not connected end->setRight(NULL); /* don't want it point to 'b' anymore */ ret = a->right(); a->setRight(b); return ret; } #ifdef NOT_YET SList *PCCTS_AST:: to_slist() { SList *list = new SList; PCCTS_AST *p; for (p=this; p!=NULL; p=p->right()) { list->add(p); } return list; } #endif void PCCTS_AST:: tfree() { PCCTS_AST *t = this; if ( t->down()!=NULL ) t->down()->tfree(); if ( t->right()!=NULL ) t->right()->tfree(); delete t; } int PCCTS_AST:: nsiblings() { PCCTS_AST *t = this; int n=0; while ( t!=NULL ) { n++; t = t->right(); } return n; } PCCTS_AST *PCCTS_AST:: sibling_index(int i) { PCCTS_AST *t = this; int j=1; require(i>0, "sibling_index: i<=0"); while ( t!=NULL ) { if ( j==i ) return t; j++; t = t->right(); } return NULL; } /* Assume this is a root node of a tree-- * duplicate that node and what's below; ignore siblings of root node. */ // MR9 23-Sep-97 RJV // MR9 // MR9 RJV: Original version only duplicated the node and down elements. // MR9 Made copies of the pointers to sibling. // MR9 Changed call "down()->deepCopy()" to "down()->deepCopyBushy()" // MR9 PCCTS_AST *PCCTS_AST:: deepCopy() { PCCTS_AST *u = this->shallowCopy(); if ( down()!=NULL ) u->setDown(down()->deepCopyBushy()); u->setRight(NULL); return u; } /* Copy all nodes including siblings of root. */ PCCTS_AST *PCCTS_AST:: deepCopyBushy() { PCCTS_AST *u = this->shallowCopy(); /* copy the rest of the tree */ if ( down()!=NULL ) u->setDown(down()->deepCopyBushy()); if ( right()!=NULL ) u->setRight(right()->deepCopyBushy()); return u; } void PCCTS_AST:: scanast_free(ScanAST *t) { if ( t == NULL ) return; scanast_free( t->down() ); scanast_free( t->right() ); free( (char *) t ); // MR1 } /* * scan * * This function is like scanf(): it attempts to match a template * against an input tree. A variable number of tree pointers * may be set according to the '%i' labels in the template string. * For example: * * t->ast_scan("#( 6 #(5 %1:4 %2:3) #(1 %3:3 %4:3) )", * &w, &x, &y, &z); * * Naturally, you'd want this converted from * * t->ast_scan("#( RangeOp #(Minus %1:IConst %2:Var) #(Plus %3:Var %4Var) )", * &w, &x, &y, &z); * * by SORCERER. * * This function call must be done withing a SORCERER file because SORCERER * must convert the token references to the associated token number. * * This functions parses the template and creates trees which are then * matched against the input tree. The labels are set as they are * encountered; hence, partial matches may leave some pointers set * and some NULL. This routines initializes all argument pointers to NULL * at the beginning. * * This function returns the number of labels matched. */ int PCCTS_AST:: ast_scan(char *templ, ...) { va_list ap; ScanAST *tmpl; int n, i, found=0; PCCTS_AST ***label_ptrs=NULL; va_start(ap, templ); /* make a ScanAST tree out of the template */ tmpl = stringparser_parse_scanast(templ, &n); /* make an array out of the labels */ if ( n>0 ) { label_ptrs = (PCCTS_AST ***) calloc(n, sizeof(PCCTS_AST **)); require(label_ptrs!=NULL, "scan: out of memory"); for (i=1; i<=n; i++) { label_ptrs[i-1] = va_arg(ap, PCCTS_AST **); *(label_ptrs[i-1]) = NULL; } } /* match the input tree against the template */ scanmatch(tmpl, label_ptrs, &found); scanast_free(tmpl); free( (char *) label_ptrs); // MR1 return found; } ScanAST *PCCTS_AST:: new_scanast(int tok) { ScanAST *p = (ScanAST *) calloc(1, sizeof(ScanAST)); // // 7-Apr-97 133MR1 // if ( p == NULL ) panic("out of memory\n"); // MR23 p->_token = tok; return p; } ScanAST *PCCTS_AST:: stringparser_parse_scanast(char *templ, int *num_labels) { StringLexer lex; StringParser parser; ScanAST *t; stringlexer_init(&lex, templ); stringparser_init(&parser, &lex); t = stringparser_parse_tree(&parser); *num_labels = parser.num_labels; return t; } void PCCTS_AST:: stringparser_match(StringParser *parser, int token) { if ( parser->token != token ) panic("bad tree in scan()"); } /* * Match a tree of the form: * (root child1 child2 ... childn) * or, * node * * where the elements are integers or labeled integers. */ ScanAST *PCCTS_AST:: stringparser_parse_tree(StringParser *parser) { ScanAST *t=NULL, *root, *child, *last=NULL /*MR23*/; if ( parser->token != __POUND ) { return stringparser_parse_element(parser); } stringparser_match(parser,__POUND); parser->token = stringscan_gettok(parser->lexer); stringparser_match(parser,__LPAREN); parser->token = stringscan_gettok(parser->lexer); root = stringparser_parse_element(parser); while ( parser->token != __RPAREN ) { child = stringparser_parse_element(parser); if ( t==NULL ) { t = child; last = t; } else { last->_right = child; last = child; } } stringparser_match(parser,__RPAREN); parser->token = stringscan_gettok(parser->lexer); root->_down = t; return root; } ScanAST *PCCTS_AST:: stringparser_parse_element(StringParser *parser) { char ebuf[100]; int label = 0; if ( parser->token == __POUND ) { return stringparser_parse_tree(parser); } if ( parser->token == __PERCENT ) { parser->token = stringscan_gettok(parser->lexer); stringparser_match(parser,__INT); label = atoi(parser->lexer->text); parser->num_labels++; if ( label==0 ) panic("%%0 is an invalid label"); parser->token = stringscan_gettok(parser->lexer); stringparser_match(parser,__COLON); parser->token = stringscan_gettok(parser->lexer); /* can label tokens and wildcards */ if ( parser->token != __INT && parser->token != __PERIOD ) panic("can only label tokens"); } if ( parser->token == __INT ) { ScanAST *p = new_scanast(atoi(parser->lexer->text)); parser->token = stringscan_gettok(parser->lexer); p->label_num = label; return p; } if ( parser->token == __PERIOD ) { ScanAST *p = new_scanast(0); /* token of 0 is wildcard */ parser->token = stringscan_gettok(parser->lexer); p->label_num = label; return p; } sprintf(ebuf, "mismatch token in scan(): %s", scan_token_str(parser->token)); panic(ebuf); return NULL; } void PCCTS_AST:: stringparser_init(StringParser *parser, StringLexer *input) { parser->lexer = input; parser->token = stringscan_gettok(parser->lexer); parser->num_labels = 0; } void PCCTS_AST:: stringlexer_init(StringLexer *scanner, char *input) { scanner->text[0]='\0'; scanner->input = input; scanner->p = input; stringscan_advance(scanner); } void PCCTS_AST:: stringscan_advance(StringLexer *scanner) { if ( *(scanner->p) == '\0' ) scanner->c = __StringScanEOF; scanner->c = *(scanner->p)++; } int PCCTS_AST:: stringscan_gettok(StringLexer *scanner) { char *index = &scanner->text[0]; char ebuf[100]; /* MR23 Remove static */ while ( isspace(scanner->c) ) { stringscan_advance(scanner); } if ( isdigit(scanner->c) ) { int tok = __INT; while ( isdigit(scanner->c) ) { *index++ = (char) /* static_cast */ (scanner->c); // MR23 stringscan_advance(scanner); } *index = '\0'; return tok; } switch ( scanner->c ) { case '#' : stringscan_advance(scanner); return __POUND; case '(' : stringscan_advance(scanner); return __LPAREN; case ')' : stringscan_advance(scanner); return __RPAREN; case '%' : stringscan_advance(scanner); return __PERCENT; case ':' : stringscan_advance(scanner); return __COLON; case '.' : stringscan_advance(scanner); return __PERIOD; case '\0' : return __StringScanEOF; case __StringScanEOF : return __StringScanEOF; default : sprintf(ebuf, "invalid char in scan: '%c'", scanner->c); panic(ebuf); } return __StringScanEOF; // never reached } const char *PCCTS_AST:: /* MR20 const */ scan_token_str(int t) { if ( VALID_SCAN_TOKEN(t) ) return scan_token_tbl[t]; else if ( t==__StringScanEOF ) return ""; else return ""; } //MR23 int PCCTS_AST::printMessage(FILE* pFile, const char* pFormat, ...) { va_list marker; va_start( marker, pFormat ); int iRet = vfprintf(pFile, pFormat, marker); va_end( marker ); return iRet; } cdrdao-cdrdao-f00afb2/pccts/h/PCCTSAST.h000066400000000000000000000111311511453746600176330ustar00rootroot00000000000000/* Abstract syntax tree * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2000 */ #ifndef PCCTSAST_H #define PCCTSAST_H #include "pcctscfg.h" #include "pccts_stdio.h" #include "pccts_stdlib.h" PCCTS_NAMESPACE_STD //class SList; #define StringScanMaxText 50 #define MaxTreeStackDepth 400 // // 7-Apr-97 133MR1 signed int not accepted by AT&T cfront // typedef struct stringlexer { int c; // MR1 char *input; char *p; char text[StringScanMaxText]; } StringLexer; /* Define the structures needed for ast_scan() */ typedef struct stringparser { int token; StringLexer *lexer; int num_labels; } StringParser; typedef struct _scanast { struct _scanast *_right, *_down; int _token; int label_num; int type() { return _token; } struct _scanast *right() { return _right; } struct _scanast *down() { return _down; } } ScanAST; #define VALID_SCAN_TOKEN(t) (t>=__LPAREN && t<=__PERIOD) class DllExportPCCTS PCCTS_AST { protected: static const char *scan_token_tbl[]; /* MR20 const */ enum { __LPAREN=1, __RPAREN=2, __PERCENT=3, __INT=4, __COLON=5, __POUND=6, __PERIOD=7, __StringScanEOF=-1}; protected: const char *scan_token_str(int t); /* MR20 const */ void stringlexer_init(StringLexer *scanner, char *input); void stringparser_init(StringParser *, StringLexer *); ScanAST *stringparser_parse_scanast(char *templ, int *n); ScanAST *stringparser_parse_tree(StringParser *parser); ScanAST *stringparser_parse_element(StringParser *parser); void stringscan_advance(StringLexer *scanner); int stringscan_gettok(StringLexer *scanner); void _push(PCCTS_AST **st, int *sp, PCCTS_AST *e); PCCTS_AST *_pop(PCCTS_AST **st, int *sp); int match_partial(PCCTS_AST *t, PCCTS_AST *u); int scanmatch(ScanAST *t, PCCTS_AST **labels[], int *n); void scanast_free(ScanAST *t); ScanAST *new_scanast(int tok); void stringparser_match(StringParser *parser, int type); virtual PCCTS_AST *deepCopyBushy(); public: PCCTS_AST() {;} virtual ~PCCTS_AST() {;} /* This group must be defined for SORCERER to work correctly */ virtual PCCTS_AST *right() = 0; virtual PCCTS_AST *down() = 0; virtual void setRight(PCCTS_AST *t) = 0; virtual void setDown(PCCTS_AST *t) = 0; // we define these so ANTLR doesn't have to virtual int type() { return 0; } virtual void setType(int /*t MR23 */) {;} virtual PCCTS_AST *shallowCopy() {panic("no shallowCopy() defined"); return NULL;} /* These are not needed by ANTLR, but are support functions */ virtual PCCTS_AST *deepCopy(); // used by SORCERER in transform mode virtual void addChild(PCCTS_AST *t); virtual void lisp_action(FILE * /*f MR23 */) {;} virtual void lisp(FILE *f); static PCCTS_AST *make(PCCTS_AST *rt, ...); virtual PCCTS_AST *ast_find_all(PCCTS_AST *u, PCCTS_AST **cursor); virtual int match(PCCTS_AST *u); virtual void insert_after(PCCTS_AST *b); virtual void append(PCCTS_AST *b); virtual PCCTS_AST *tail(); virtual PCCTS_AST *bottom(); static PCCTS_AST *cut_between(PCCTS_AST *a, PCCTS_AST *b); // virtual SList *to_slist(); virtual void tfree(); int ast_scan(char *templ, ...); virtual int nsiblings(); virtual PCCTS_AST *sibling_index(int i); void require(int e,const char *err){ if ( !e ) panic(err); } /* MR20 const */ virtual void panic(const char *err) // MR20 const { /* MR23 */ printMessage(stderr, "PCCTS_AST: %s\n", err); exit(PCCTS_EXIT_FAILURE); } virtual int printMessage(FILE* pFile, const char* pFormat, ...); // MR23 }; #endif /* PCCTSAST_H */ cdrdao-cdrdao-f00afb2/pccts/h/SList.h000066400000000000000000000042741511453746600174570ustar00rootroot00000000000000#ifndef SList_h #define SList_h /* * SList.h * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to SORCERER -- SORCERER is in the public * domain. An individual or company may do whatever they wish with * source code distributed with SORCERER or the code generated by * SORCERER, including the incorporation of SORCERER, or its output, into * commerical software. * * We encourage users to develop software with SORCERER. However, we do * ask that credit is given to us for developing SORCERER. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like SORCERER and have developed a nice tool with the * output, please mention that you developed it using SORCERER. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * PCCTS 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1992-2000 */ #include "pcctscfg.h" #include "pccts_stdio.h" #include "pccts_stdlib.h" PCCTS_NAMESPACE_STD #include "PCCTSAST.h" class PCCTS_AST; class SListNode { protected: void *_elem; /* pointer to any kind of element */ SListNode *_next; public: SListNode() {_elem=_next=NULL;} virtual ~SListNode() {_elem=_next=NULL;} void *elem() { return _elem; } void setElem(void *e) { _elem = e; } void setNext(SListNode *t) { _next = t; } SListNode *next() { return _next; } }; class SList { SListNode *head, *tail; public: SList() {head=tail=NULL;} virtual ~SList() {head=tail=NULL;} virtual void *iterate(SListNode **); virtual void add(void *e); virtual void lfree(); virtual PCCTS_AST *to_ast(SList list); virtual void require(int e,char *err){ if ( !e ) panic(err); } virtual void panic(char *err){ /* MR23 */ printMessage(stderr, "SList panic: %s\n", err); exit(PCCTS_EXIT_FAILURE); } virtual int printMessage(FILE* pFile, const char* pFormat, ...); // MR23 }; #endif cdrdao-cdrdao-f00afb2/pccts/h/antlr.h000066400000000000000000000601121511453746600175320ustar00rootroot00000000000000/* antlr.h * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2000 */ #ifndef ANTLR_H #define ANTLR_H #include "pcctscfg.h" #include "pccts_stdio.h" /* turn off warnings for unreferenced labels */ #ifdef _MSC_VER #pragma warning(disable:4102) #endif /* * Define all of the stack setup and manipulation of $i, #i variables. * * Notes: * The type 'Attrib' must be defined before entry into this .h file. */ #ifdef __USE_PROTOS #include "pccts_stdlib.h" #else #ifdef VAXC #include #else #include #endif #endif #include "pccts_string.h" #if 0 #include "set.h" #endif typedef int ANTLRTokenType; typedef unsigned char SetWordType; typedef char ANTLRChar; /* G u e s s S t u f f */ #ifdef ZZCAN_GUESS #ifndef ZZINF_LOOK #define ZZINF_LOOK #endif #endif #ifdef ZZCAN_GUESS typedef struct _zzjmp_buf { jmp_buf state; } zzjmp_buf; #endif /* can make this a power of 2 for more efficient lookup */ #ifndef ZZLEXBUFSIZE #define ZZLEXBUFSIZE 8000 /* MR22 raise from 2k to 8k */ #endif #define zzOvfChk \ if ( zzasp <= 0 ) \ { \ fprintf(stderr, zzStackOvfMsg, __FILE__, __LINE__); \ exit(PCCTS_EXIT_FAILURE); \ } #ifndef ZZA_STACKSIZE #define ZZA_STACKSIZE 400 #endif #ifndef ZZAST_STACKSIZE #define ZZAST_STACKSIZE 400 #endif #ifndef zzfailed_pred #ifdef ZZCAN_GUESS #define zzfailed_pred(_p,_hasuseraction,_useraction) \ if (zzguessing) { \ zzGUESS_FAIL; \ } else { \ zzfailed_pred_action(_p,_hasuseraction,_useraction); \ } #else #define zzfailed_pred(_p,_hasuseraction,_useraction) \ zzfailed_pred_action(_p,_hasuseraction,_useraction); #endif #endif /* MR23 Provide more control over failed predicate action without any need for user to worry about guessing internals. _hasuseraction == 0 => no user specified error action _hasuseraction == 1 => user specified error action */ #ifndef zzfailed_pred_action #define zzfailed_pred_action(_p,_hasuseraction,_useraction) \ if (_hasuseraction) { _useraction } \ else { fprintf(stderr, "semantic error; failed predicate: '%s'\n",_p); } #endif /* MR19 zzchar_t additions */ #ifdef LL_K #define LOOKAHEAD \ int zztokenLA[LL_K]; \ zzchar_t zztextLA[LL_K][ZZLEXBUFSIZE]; \ int zzlap = 0, zzlabase=0; /* labase only used for DEMAND_LOOK */ #else #define LOOKAHEAD \ int zztoken; #endif #ifndef zzcr_ast #define zzcr_ast(ast,attr,tok,text) #endif #ifdef DEMAND_LOOK #define DemandLookData int zzdirty=1; #else #define DemandLookData #endif #ifndef zzUSER_GUESS_HOOK #define zzUSER_GUESS_HOOK(seqFrozen,zzrv) #endif #ifndef zzUSER_GUESS_DONE_HOOK #define zzUSER_GUESS_DONE_HOOK(seqFrozen) #endif /* S t a t e S t u f f */ #ifdef ZZCAN_GUESS #define zzGUESS_BLOCK zzantlr_state zzst; int zzrv; int zzGuessSeqFrozen; /* MR10 change zzGUESS: do zzGUESS_DONE when zzrv==1 after longjmp as in C++ mode */ #define zzGUESS zzsave_antlr_state(&zzst); \ zzguessing = 1; \ zzGuessSeqFrozen=++zzGuessSeq; \ zzrv = setjmp(zzguess_start.state); \ zzUSER_GUESS_HOOK(zzGuessSeqFrozen,zzrv) \ if (zzrv) zzGUESS_DONE; #ifdef zzTRACE_RULES #define zzGUESS_FAIL { zzTraceGuessFail(); longjmp(zzguess_start.state, 1); } #else #define zzGUESS_FAIL longjmp(zzguess_start.state, 1) #endif /* MR10 change zzGUESS_DONE: zzrv=1 to simulate longjmp() return value as in C++ mode */ #define zzGUESS_DONE { zzrestore_antlr_state(&zzst); zzrv=1; zzUSER_GUESS_DONE_HOOK(zzGuessSeqFrozen) } #define zzNON_GUESS_MODE if ( !zzguessing ) #define zzGuessData \ zzjmp_buf zzguess_start; \ int zzguessing; #else #define zzGUESS_BLOCK #define zzGUESS #define zzGUESS_FAIL #define zzGUESS_DONE #define zzNON_GUESS_MODE #define zzGuessData #endif typedef struct _zzantlr_state { #ifdef ZZCAN_GUESS zzjmp_buf guess_start; int guessing; #endif int asp; int ast_sp; #ifdef ZZINF_LOOK int inf_lap; /* not sure we need to save this one */ int inf_labase; int inf_last; /* MR6 Gunnar Rxnning (gunnar@candleweb.no) */ /* MR6 Additional state needs to be saved/restored */ /* MR6 Matching changes in err.h */ int *inf_tokens; /* MR6 */ char **inf_text; /* MR6 */ char *inf_text_buffer; /* MR6 */ int *inf_line; /* MR6 */ #endif #ifdef DEMAND_LOOK int dirty; #endif #ifdef LL_K int tokenLA[LL_K]; char textLA[LL_K][ZZLEXBUFSIZE]; int lap; int labase; #else int token; char text[ZZLEXBUFSIZE]; #endif #ifdef zzTRACE_RULES int traceOptionValue; /* MR10 */ int traceGuessOptionValue; /* MR10 */ char *traceCurrentRuleName; /* MR10 */ int traceDepth; /* MR10 */ #endif } zzantlr_state; #ifdef zzTRACE_RULES extern int zzTraceOptionValueDefault; extern int zzTraceOptionValue; extern int zzTraceGuessOptionValue; extern char *zzTraceCurrentRuleName; extern int zzTraceDepth; #endif extern int zzGuessSeq; /* MR10 */ extern int zzSyntaxErrCount; /* MR11 */ extern int zzLexErrCount; /* MR11 */ /* I n f i n i t e L o o k a h e a d */ #ifdef ZZINF_LOOK #define InfLookData \ int *zzinf_tokens; \ char **zzinf_text; \ char *zzinf_text_buffer; \ int *zzinf_line; \ int zzinf_labase; \ int zzinf_last; #else #define InfLookData #endif #ifdef ZZINF_LOOK #ifndef ZZINF_DEF_TEXT_BUFFER_SIZE #define ZZINF_DEF_TEXT_BUFFER_SIZE 20000 #endif #ifndef ZZINF_DEF_TOKEN_BUFFER_SIZE #define ZZINF_DEF_TOKEN_BUFFER_SIZE 2000 #endif /* WARNING!!!!!! * ZZINF_BUFFER_TEXT_CHUNK_SIZE must be > sizeof(text) largest possible token. */ #ifndef ZZINF_BUFFER_TEXT_CHUNK_SIZE #define ZZINF_BUFFER_TEXT_CHUNK_SIZE 5000 #endif #ifndef ZZINF_BUFFER_TOKEN_CHUNK_SIZE #define ZZINF_BUFFER_TOKEN_CHUNK_SIZE 1000 #endif #if ZZLEXBUFSIZE > ZZINF_BUFFER_TEXT_CHUNK_SIZE #define ZZINF_BUFFER_TEXT_CHUNK_SIZE ZZLEXBUFSIZE+5 #endif /* make inf_look user-access macros */ #ifdef LL_K #define ZZINF_LA_VALID(i) (((zzinf_labase+i-1)-LL_K+1) <= zzinf_last) #define ZZINF_LA(i) zzinf_tokens[(zzinf_labase+i-1)-LL_K+1] #define ZZINF_LATEXT(i) zzinf_text[(zzinf_labase+i-1)-LL_K+1] /* MR6 In 1.33 vanilla the #define ZZINF_LINE(i) is was commented out */ #define ZZINF_LINE(i) zzinf_line[(zzinf_labase+i-1)-LL_K+1] #else #define ZZINF_LA_VALID(i) (((zzinf_labase+i-1)) <= zzinf_last) #define ZZINF_LA(i) zzinf_tokens[(zzinf_labase+i-1)] #define ZZINF_LATEXT(i) zzinf_text[(zzinf_labase+i-1)] #endif #define inf_zzgettok _inf_zzgettok() extern void _inf_zzgettok(); #endif /* ZZINF_LOOK */ #ifdef LL_K #ifdef __USE_PROTOS #define ANTLR_INFO \ Attrib zzempty_attr(void) {static Attrib a; return a;} \ Attrib zzconstr_attr(int _tok, char *_text) \ {Attrib a; zzcr_attr((&a),_tok,_text); return a;} \ int zzasp=ZZA_STACKSIZE; \ char zzStackOvfMsg[]="fatal: attrib/AST stack overflow %s(%d)!\n"; \ Attrib zzaStack[ZZA_STACKSIZE]; DemandLookData \ InfLookData \ zzGuessData #else #define ANTLR_INFO \ Attrib zzempty_attr() {static Attrib a; return a;} \ Attrib zzconstr_attr(_tok, _text) int _tok; char *_text; \ {Attrib a; zzcr_attr((&a),_tok,_text); return a;} \ int zzasp=ZZA_STACKSIZE; \ char zzStackOvfMsg[]="fatal: attrib/AST stack overflow %s(%d)!\n"; \ Attrib zzaStack[ZZA_STACKSIZE]; DemandLookData \ InfLookData \ zzGuessData #endif #else #ifdef __USE_PROTOS #define ANTLR_INFO \ Attrib zzempty_attr(void) {static Attrib a; return a;} \ Attrib zzconstr_attr(int _tok, char *_text) \ {Attrib a={0,0}; zzcr_attr((&a),_tok,_text); return a;} \ int zzasp=ZZA_STACKSIZE; \ char zzStackOvfMsg[]="fatal: attrib/AST stack overflow %s(%d)!\n"; \ Attrib zzaStack[ZZA_STACKSIZE]; DemandLookData \ InfLookData \ zzGuessData #else #define ANTLR_INFO \ Attrib zzempty_attr() {static Attrib a; return a;} \ Attrib zzconstr_attr(_tok, _text) int _tok; char *_text; \ {Attrib a; zzcr_attr((&a),_tok,_text); return a;} \ int zzasp=ZZA_STACKSIZE; \ char zzStackOvfMsg[]="fatal: attrib/AST stack overflow %s(%d)!\n"; \ Attrib zzaStack[ZZA_STACKSIZE]; DemandLookData \ InfLookData \ zzGuessData #endif #endif /* LL_k */ #ifdef ZZINF_LOOK #ifdef LL_K #ifdef DEMAND_LOOK #define zzPrimeLookAhead {zzdirty=LL_K; zzlap = zzlabase = 0;} #else #define zzPrimeLookAhead {zzlap = zzlabase = 0; zzfill_inf_look();\ {int _i; for(_i=1;_i<=LL_K; _i++) \ {zzCONSUME;} zzlap = zzlabase = 0;}} #endif #else /* LL_K */ #ifdef DEMAND_LOOK #define zzPrimeLookAhead zzfill_inf_look(); zzdirty=1 #else #define zzPrimeLookAhead zzfill_inf_look(); inf_zzgettok #endif #endif /* LL_K */ #else /* ZZINF_LOOK */ #ifdef LL_K #ifdef DEMAND_LOOK #define zzPrimeLookAhead {zzdirty=LL_K; zzlap = zzlabase = 0;} #else #define zzPrimeLookAhead {int _i; zzlap = 0; for(_i=1;_i<=LL_K; _i++) \ {zzCONSUME;} zzlap = 0;} #endif #else #ifdef DEMAND_LOOK #define zzPrimeLookAhead zzdirty=1 #else #define zzPrimeLookAhead zzgettok() #endif #endif /* LL_K */ #endif /* ZZINF_LOOK */ #ifdef LL_K #define zzenterANTLRs(s) \ zzlextext = &(zztextLA[0][0]); zzrdstr( s ); zzPrimeLookAhead; #define zzenterANTLRf(f) \ zzlextext = &(zztextLA[0][0]); zzrdfunc( f ); zzPrimeLookAhead; #define zzenterANTLR(f) \ zzlextext = &(zztextLA[0][0]); zzrdstream( f ); zzPrimeLookAhead; #ifdef ZZINF_LOOK #define zzleaveANTLR(f) free(zzinf_text_buffer); free(zzinf_text); free(zzinf_tokens); free(zzinf_line); #define zzleaveANTLRf(f) free(zzinf_text_buffer); free(zzinf_text); free(zzinf_tokens); free(zzinf_line); #define zzleaveANTLRs(f) free(zzinf_text_buffer); free(zzinf_text); free(zzinf_tokens); free(zzinf_line); #else #define zzleaveANTLR(f) #define zzleaveANTLRf(f) #define zzleaveANTLRs(f) #endif #else #define zzenterANTLRs(s) \ {static char zztoktext[ZZLEXBUFSIZE]; \ zzlextext = zztoktext; zzrdstr( s ); zzPrimeLookAhead;} #define zzenterANTLRf(f) \ {static char zztoktext[ZZLEXBUFSIZE]; \ zzlextext = zztoktext; zzrdfunc( f ); zzPrimeLookAhead;} #define zzenterANTLR(f) \ {static char zztoktext[ZZLEXBUFSIZE]; \ zzlextext = zztoktext; zzrdstream( f ); zzPrimeLookAhead;} #ifdef ZZINF_LOOK #define zzleaveANTLR(f) free(zzinf_text_buffer); free(zzinf_text); free(zzinf_tokens); free(zzinf_line); #define zzleaveANTLRf(f) free(zzinf_text_buffer); free(zzinf_text); free(zzinf_tokens); free(zzinf_line); #define zzleaveANTLRs(f) free(zzinf_text_buffer); free(zzinf_text); free(zzinf_tokens); free(zzinf_line); #else #define zzleaveANTLR(f) #define zzleaveANTLRf(f) #define zzleaveANTLRs(f) #endif #endif /* MR19 Paul D. Smith (psmith@baynetworks.com) Need to adjust AST stack pointer at exit. Referenced in ANTLRx macros. */ #ifdef GENAST #define ZZAST_ADJUST ++zzast_sp; #else #define ZZAST_ADJUST #endif #define ANTLR(st, f) zzbufsize = ZZLEXBUFSIZE; \ zzenterANTLR(f); \ { \ zzBLOCK(zztasp1); \ st; /* ++zzasp; Removed MR20 G. Hobbelt */ \ /* ZZAST_ADJUST Removed MR20 G. Hobbelt */ \ /* MR20 G. Hobbelt. Kill the top' attribute (+AST stack corr.) */ \ zzEXIT_ANTLR(zztasp1 + 1); \ } \ zzleaveANTLR(f); #define ANTLRm(st, f, _m) zzbufsize = ZZLEXBUFSIZE; \ zzmode(_m); \ zzenterANTLR(f); \ { \ zzBLOCK(zztasp1); \ st; /* ++zzasp; Removed MR20 G. Hobbelt */ \ /* ZZAST_ADJUST Removed MR20 G. Hobbelt */ \ /* MR20 G. Hobbelt. Kill the top' attribute (+AST stack corr.) */ \ zzEXIT_ANTLR(zztasp1 + 1); \ } \ zzleaveANTLR(f); #define ANTLRf(st, f) zzbufsize = ZZLEXBUFSIZE; \ zzenterANTLRf(f); \ { \ zzBLOCK(zztasp1); \ st; /* ++zzasp; Removed MR20 G. Hobbelt */ \ /* ZZAST_ADJUST Removed MR20 G. Hobbelt */ \ /* MR20 G. Hobbelt. Kill the top' attribute (+AST stack corr.) */ \ zzEXIT_ANTLR(zztasp1 + 1); \ } \ zzleaveANTLRf(f); #define ANTLRs(st, s) zzbufsize = ZZLEXBUFSIZE; \ zzenterANTLRs(s); \ { \ zzBLOCK(zztasp1); \ st; /* ++zzasp; Removed MR20 G. Hobbelt */ \ /* ZZAST_ADJUST Removed MR20 G. Hobbelt */ \ /* MR20 G. Hobbelt. Kill the top' attribute (+AST stack corr.) */ \ zzEXIT_ANTLR(zztasp1 + 1); \ } \ zzleaveANTLRs(s); #ifdef LL_K #define zztext (&(zztextLA[zzlap][0])) #else #define zztext zzlextext #endif /* A r g u m e n t A c c e s s */ #define zzaCur (zzaStack[zzasp]) #define zzaRet (*zzaRetPtr) #define zzaArg(v,n) zzaStack[v-n] #define zzMakeAttr { zzNON_GUESS_MODE {zzOvfChk; --zzasp; zzcr_attr(&(zzaStack[zzasp]),LA(1),LATEXT(1));}} #ifdef zzdef0 #define zzMake0 { zzOvfChk; --zzasp; zzdef0(&(zzaStack[zzasp]));} #else #define zzMake0 { zzOvfChk; --zzasp;} #endif #define zzaPush(_v) { zzOvfChk; zzaStack[--zzasp] = _v;} #ifndef zzd_attr #define zzREL(t) zzasp=(t); /* Restore state of stack */ #else #define zzREL(t) for (; zzasp<(t); zzasp++) \ { zzd_attr(&(zzaStack[zzasp])); } #endif #define zzsetmatch(_es,_tokclassErrset) \ if ( !_zzsetmatch(_es, &zzBadText, &zzMissText, &zzMissTok, &zzBadTok, &zzMissSet, _tokclassErrset) ) goto fail; /* MR23 */ #ifdef ZZCAN_GUESS #define zzsetmatch_wsig(_es, handler) \ if ( !_zzsetmatch_wsig(_es) ) if (zzguessing) { zzGUESS_FAIL; } else {_signal=MismatchedToken; goto handler;} #else #define zzsetmatch_wsig(_es, handler) \ if ( !_zzsetmatch_wsig(_es) ) {_signal=MismatchedToken; goto handler;} #endif #ifdef __USE_PROTOS extern int _zzsetmatch(SetWordType *, char **, char **, int *, int *, SetWordType **, SetWordType * /* MR23 */); extern int _zzsetmatch_wsig(SetWordType *); #else extern int _zzsetmatch(); extern int _zzsetmatch_wsig(); #endif #define zzmatch(_t) \ if ( !_zzmatch(_t, &zzBadText, &zzMissText, &zzMissTok, &zzBadTok, &zzMissSet) ) goto fail; #ifdef ZZCAN_GUESS #define zzmatch_wsig(_t,handler) \ if ( !_zzmatch_wsig(_t) ) if (zzguessing) { zzGUESS_FAIL; } else {_signal=MismatchedToken; goto handler;} #else #define zzmatch_wsig(_t,handler) \ if ( !_zzmatch_wsig(_t) ) {_signal=MismatchedToken; goto handler;} #endif #ifdef __USE_PROTOS extern int _zzmatch(int, char **, char **, int *, int *, SetWordType **); extern int _zzmatch_wsig(int); #else extern int _zzmatch(); extern int _zzmatch_wsig(); #endif #define zzmatch_wdfltsig(_t,_f) \ if ( !_zzmatch_wdfltsig(_t,_f) ) _signal=MismatchedToken; #define zzsetmatch_wdfltsig(tw,tt,wf) \ if ( !_zzsetmatch_wdfltsig(tw,tt,wf) ) _signal=MismatchedToken; #ifdef __USE_PROTOS extern int _zzmatch_wdfltsig(int, SetWordType *); extern int _zzsetmatch_wdfltsig(SetWordType *tokensWanted, int tokenTypeOfSet, SetWordType *whatFollows); #else extern int _zzmatch_wdfltsig(); extern int _zzsetmatch_wdfltsig(); #endif #ifdef GENAST #define zzRULE Attrib *zzaRetPtr = &(zzaStack[zzasp-1]); \ SetWordType *zzMissSet=NULL; int zzMissTok=0; \ int zzBadTok=0; char *zzBadText=""; \ int zzErrk=1,zzpf=0; \ zzTRACEdata \ char *zzMissText=""; zzASTVars #else #define zzRULE Attrib *zzaRetPtr = &(zzaStack[zzasp-1]); \ int zzBadTok=0; char *zzBadText=""; \ int zzErrk=1,zzpf=0; \ zzTRACEdata \ SetWordType *zzMissSet=NULL; int zzMissTok=0; char *zzMissText="" #endif #ifdef GENAST #define zzBLOCK(i) int i = zzasp - 1; int zztsp = zzast_sp #define zzEXIT(i) zzREL(i); zzastREL; zzNON_GUESS_MODE { zzastPush(*_root); } #define zzEXIT_ANTLR(i) zzREL(i); zzastREL /* [i_a] added as we want this for the ANTLRx() macros */ #define zzLOOP(i) zzREL(i); zzastREL #else #define zzBLOCK(i) int i = zzasp - 1 #define zzEXIT(i) zzREL(i) #define zzEXIT_ANTLR(i) zzREL(i) /* [i_a] added as we want this for the ANTLRx() macros */ #define zzLOOP(i) zzREL(i) #endif #ifdef LL_K #ifdef DEMAND_LOOK #define LOOK(_k) {int i,stop=_k-(LL_K-zzdirty); for (i=1; i<=stop; i++) \ zzCONSUME;} #define zzCONSUME {zzgettok(); zzdirty--; \ zzlap = (zzlap+1)&(LL_K-1); \ zzlextext = &(zztextLA[zzlap][0]);} #else #ifdef ZZINF_LOOK #define zzCONSUME {inf_zzgettok; \ zzlap = (zzlap+1)&(LL_K-1); \ zzlextext = &(zztextLA[zzlap][0]); \ } #else #define zzCONSUME {zzgettok(); \ zzlap = (zzlap+1)&(LL_K-1); \ zzlextext = &(zztextLA[zzlap][0]);} #endif /* ZZINF_LOOK */ #endif /* DEMAND_LOOK */ #else /* LL_K */ #ifdef DEMAND_LOOK #define LOOK(_k) if ( zzdirty) zzCONSUME; #ifdef ZZINF_LOOK #define zzCONSUME inf_zzgettok; zzdirty=0; #else #define zzCONSUME zzgettok(); zzdirty=0; #endif /* ZZINF_LOOK */ #else /* DEMAND_LOOK */ #ifdef ZZINF_LOOK #define zzCONSUME inf_zzgettok #else #define zzCONSUME zzgettok(); #endif #endif /* DEMAND_LOOK */ #endif /* LL_K */ #ifdef LL_K #define NLA zztokenLA[zzlap&(LL_K-1)] /* --> next LA */ #define NLATEXT zztextLA[zzlap&(LL_K-1)] /* --> next text of LA */ #ifdef DEMAND_LOOK #define LA(i) zztokenLA[(zzlabase+(i)-1)&(LL_K-1)] #define LATEXT(i) (&(zztextLA[(zzlabase+(i)-1)&(LL_K-1)][0])) #else #define LA(i) zztokenLA[(zzlap+(i)-1)&(LL_K-1)] #define LATEXT(i) (&(zztextLA[(zzlap+(i)-1)&(LL_K-1)][0])) #endif #else #define NLA zztoken #define NLATEXT zztext #define LA(i) zztoken #define LATEXT(i) zztext #endif /* S t a n d a r d S i g n a l s */ #define NoSignal 0 #define MismatchedToken 1 #define NoViableAlt 2 #define NoSemViableAlt 3 /* MR7 Allow more control over signalling */ /* by adding "Unwind" and "zzsetSignal" */ #define Unwind 4 #define zzsetSignal(newValue) *_retsignal=_signal=(newValue) #define zzsuppressSignal *_retsignal=_signal=0 #define zzexportSignal *_retsignal=_signal /* F u n c t i o n T r a c i n g */ #ifndef zzTRACE_RULES #define zzTRACEdata #else #ifndef zzTRACEdata #define zzTRACEdata ANTLRChar *zzTracePrevRuleName = NULL; #endif #endif #ifndef zzTRACEIN #define zzTRACEIN(r) zzTracePrevRuleName=zzTraceCurrentRuleName;zzTraceIn(r); #endif #ifndef zzTRACEOUT #define zzTRACEOUT(r) zzTraceOut(r);zzTraceCurrentRuleName=zzTracePrevRuleName; #endif /* MR19 zzchar_t additions */ #ifndef zzchar_t #ifdef ZZWCHAR_T #define zzchar_t wchar_t #else #define zzchar_t char #endif #endif /* MR26 */ #ifdef PCCTS_USE_STDARG extern void zzFAIL(int k, ...); #else extern void zzFAIL(); #endif /* E x t e r n D e f s */ #ifdef __USE_PROTOS extern Attrib zzempty_attr(void); extern Attrib zzconstr_attr(int, char *); extern void zzsyn(char *, int, char *, SetWordType *, int, int, char *); extern int zzset_el(unsigned, SetWordType *); extern int zzset_deg(SetWordType *); extern void zzedecode(SetWordType *); extern void zzresynch(SetWordType *, SetWordType); extern void zzsave_antlr_state(zzantlr_state *); extern void zzrestore_antlr_state(zzantlr_state *); extern void zzfill_inf_look(void); extern void zzconsumeUntil(SetWordType *st); /* MR7 */ extern void zzconsumeUntilToken(int t); /* MR7 */ extern void zzTraceIn(char * ruleName); /* MR10 */ extern void zzTraceOut(char * ruleName); /* MR10 */ extern int zzTraceOption(int delta); /* MR10 */ extern int zzTraceGuessOption(int delta); /* MR10 */ extern void zzTraceReset(void); /* MR10 */ extern void zzTraceGuessFail(void); /* MR10 */ #ifdef EXCEPTION_HANDLING extern void zzdflthandlers(int, int *); #endif #else extern Attrib zzempty_attr(); extern Attrib zzconstr_attr(); extern void zzsyn(); extern int zzset_el(); extern int zzset_deg(); extern void zzedecode(); extern void zzresynch(); extern void zzsave_antlr_state(); extern void zzrestore_antlr_state(); extern void zzfill_inf_look(); extern void zzconsumeUntil(); /* MR7 */ extern void zzconsumeUntilToken(); /* MR7 */ extern void zzTraceIn(); /* MR10 */ extern void zzTraceOut(); /* MR10 */ extern int zzTraceOption(); /* MR10 */ extern int zzTraceGuessOption(); /* MR10 */ extern void zzTraceReset(); /* MR10 */ extern void zzTraceGuessFail(); /* MR10 */ #ifdef EXCEPTION_HANDLING extern void zzdflthandlers(); #endif #endif /* G l o b a l V a r i a b l e s */ /* Define a parser; user should do a "#parser myname" in their grammar file */ /*extern struct pccts_parser zzparser;*/ extern char *zztokens[]; #ifdef LL_K extern int zztokenLA[]; extern zzchar_t zztextLA[][ZZLEXBUFSIZE]; extern int zzlap; extern int zzlabase; #else extern int zztoken; #endif extern char zzStackOvfMsg[]; extern int zzasp; extern Attrib zzaStack[]; #ifdef ZZINF_LOOK extern int *zzinf_tokens; extern char **zzinf_text; extern char *zzinf_text_buffer; extern int *zzinf_line; extern int zzinf_labase; extern int zzinf_last; #endif #ifdef DEMAND_LOOK extern int zzdirty; #endif #ifdef ZZCAN_GUESS extern int zzguessing; extern zzjmp_buf zzguess_start; #endif /* Define global veriables that refer to values exported by the scanner. * These declarations duplicate those in dlgdef.h, but are needed * if ANTLR is not to generate a .dlg file (-gx); PS, this is a hack. */ extern zzchar_t *zzlextext; /* text of most recently matched token */ extern int zzbufsize; /* how long zzlextext is */ #endif cdrdao-cdrdao-f00afb2/pccts/h/ast.h000066400000000000000000000067601511453746600172120ustar00rootroot00000000000000/* Abstract syntax tree * * Macros, definitions * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2000 */ #ifndef ZZAST_H #define ZZAST_H #define zzastOvfChk \ if ( zzast_sp <= 0 ) \ { \ fprintf(stderr, zzStackOvfMsg, __FILE__, __LINE__); \ exit(PCCTS_EXIT_FAILURE); \ } #ifndef USER_DEFINED_AST #ifndef AST_FIELDS #define AST_FIELDS #endif typedef struct _ast { struct _ast *right, *down; #ifdef zzAST_DOUBLE struct _ast *left, *up; #endif AST_FIELDS } AST; #else #ifdef zzAST_DOUBLE #define AST_REQUIRED_FIELDS struct _ast *right, *down, *left, *up; #else #define AST_REQUIRED_FIELDS struct _ast *right, *down; #endif #endif /* N o d e a c c e s s m a c r o s */ #define zzchild(t) (((t)==NULL)? (AST *) NULL:(t->down)) /* MR19 */ #define zzsibling(t) (((t)==NULL)? (AST *) NULL:(t->right)) /* MR19 */ /* define global variables needed by #i stack */ #define zzASTgvars \ AST *zzastStack[ZZAST_STACKSIZE]; \ int zzast_sp = ZZAST_STACKSIZE; #define zzASTVars AST *_ast = NULL, *_sibling = NULL, *_tail = NULL #define zzSTR ( (_tail==NULL)?(&_sibling):(&(_tail->right)) ) #define zzastCur (zzastStack[zzast_sp]) #define zzastArg(i) (zzastStack[zztsp-i]) #define zzastPush(p) zzastOvfChk; zzastStack[--zzast_sp] = p; #define zzastDPush --zzast_sp #define zzastMARK zztsp=zzast_sp; /* Save state of stack */ #define zzastREL zzast_sp=zztsp; /* Return state of stack */ #define zzrm_ast {zzfree_ast(*_root); _tail = _sibling = (*_root)=NULL;} extern int zzast_sp; extern AST *zzastStack[]; /* MR26 */ #ifdef PCCTS_USE_STDARG AST *zztmake(AST *, ...); #else AST *zztmake(); #endif #ifdef __USE_PROTOS void zzlink(AST **, AST **, AST **); void zzsubchild(AST **, AST **, AST **); void zzsubroot(AST **, AST **, AST **); void zzpre_ast(AST *, void (*)(AST *), void (*)(AST *), void (*)(AST *)); void zzfree_ast(AST *); AST *zzdup_ast(AST *); void zztfree(AST *); void zzdouble_link(AST *, AST *, AST *); AST *zzastnew(void); #else void zzlink(); AST *zzastnew(); void zzsubchild(); void zzsubroot(); void zzpre_ast(); void zzfree_ast(); AST *zzdup_ast(); void zztfree(); void zzdouble_link(); #endif #endif cdrdao-cdrdao-f00afb2/pccts/h/charbuf.h000066400000000000000000000030471511453746600200300ustar00rootroot00000000000000/* ANTLR attribute definition -- constant width text * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2000 */ #ifndef ZZCHARBUF_H #define ZZCHARBUF_H #include "pcctscfg.h" #include "pccts_string.h" #ifndef D_TextSize #define D_TextSize 30 #endif typedef struct { char text[D_TextSize]; } Attrib; #define zzcr_attr(a,tok,t) strncpy((a)->text, t, D_TextSize-1); \ (a)->text[D_TextSize-1] = '\0'; #endif cdrdao-cdrdao-f00afb2/pccts/h/charptr.h000066400000000000000000000033011511453746600200520ustar00rootroot00000000000000/* * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2000 */ /* * WARNING!!!!: charptr.h does NOT make copies and the * memory is freed after the attribute scope exits. */ #ifndef ZZCHARPTR_H #define ZZCHARPTR_H typedef char *Attrib; #define zzdef0(a) {*(a)=NULL;} /* MR8 Jens Tingleff (jensting@imaginet.fr) */ /* Set memory pointer to null after free() */ #define zzd_attr(a) {if ( *(a)!=NULL ) {free(*(a)); *(a)=NULL; }; } #ifdef __STDC__ extern zzcr_attr(Attrib *,int,char *); #endif #endif cdrdao-cdrdao-f00afb2/pccts/h/config.h000066400000000000000000000000261511453746600176550ustar00rootroot00000000000000#include "pcctscfg.h" cdrdao-cdrdao-f00afb2/pccts/h/dlgauto.h000066400000000000000000000252351511453746600200600ustar00rootroot00000000000000/* dlgauto.h automaton * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Will Cohen and Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2000 */ #ifndef ZZDEFAUTO_H #define ZZDEFAUTO_H /* 10-Apr-97 133MR1 Uses __USE_PROTOS show should #include pcctscfg.h */ #include "pcctscfg.h" zzchar_t *zzlextext; /* text of most recently matched token */ zzchar_t *zzbegexpr; /* beginning of last reg expr recogn. */ zzchar_t *zzendexpr; /* beginning of last reg expr recogn. */ int zzbufsize = 0; /* number of characters in zzlextext */ /* MR7 */ int zzbegcol = 0; /* column that first character of token is in*/ int zzendcol = 0; /* column that last character of token is in */ int zzline = 1; /* line current token is on */ int zzreal_line=1; /* line of 1st portion of token that is not skipped */ int zzchar; /* character to determine next state */ int zzbufovf; /* indicates that buffer too small for text */ int zzcharfull = 0; static zzchar_t *zznextpos;/* points to next available position in zzlextext*/ static int zzclass; #ifdef __USE_PROTOS void zzerrstd(const char *); void (*zzerr)(const char *)=zzerrstd;/* pointer to error reporting function */ extern int zzerr_in(void); static int (*zzfunc_in)(void) = zzerr_in; /* MR20 */ #else void zzerrstd(); void (*zzerr)()=zzerrstd; /* pointer to error reporting function */ extern int zzerr_in(); static int (*zzfunc_in)() = zzerr_in; /* MR20 */ #endif static FILE *zzstream_in=0; static zzchar_t *zzstr_in=0; #ifdef USER_ZZMODE_STACK int zzauto = 0; #else static int zzauto = 0; #endif static int zzadd_erase; static char zzebuf[70]; #ifdef ZZCOL #define ZZINC (++zzendcol) #else #define ZZINC #endif #define ZZGETC_STREAM {zzchar = getc(zzstream_in); zzclass = ZZSHIFT(zzchar);} #define ZZGETC_FUNC {zzchar = (*zzfunc_in)(); zzclass = ZZSHIFT(zzchar);} #define ZZGETC_STR { \ if (*zzstr_in){ \ zzchar = *zzstr_in; \ ++zzstr_in; \ }else{ \ zzchar = EOF; \ } \ zzclass = ZZSHIFT(zzchar); \ } #define ZZNEWSTATE (newstate = dfa[state][zzclass]) #ifndef ZZCOPY #define ZZCOPY \ /* Truncate matching buffer to size (not an error) */ \ if (zznextpos < lastpos){ \ *(zznextpos++) = zzchar; \ }else{ \ zzbufovf = 1; \ } #endif void #ifdef __USE_PROTOS zzrdstream( FILE *f ) #else zzrdstream( f ) FILE *f; #endif { /* make sure that it is really set to something, otherwise just leave it be. */ if (f){ /* make sure that there is always someplace to get input before closing zzstream_in */ #if 0 if (zzstream_in && zzstream_in!=stdin) fclose( zzstream_in ); #endif zzline = 1; zzstream_in = f; zzfunc_in = NULL; zzstr_in = 0; zzcharfull = 0; } } void #ifdef __USE_PROTOS zzrdfunc( int (*f)(void) ) #else zzrdfunc( f ) int (*f)(); #endif { /* make sure that it is really set to something, otherwise just leave it be. */ if (f){ /* make sure that there is always someplace to get input before closing zzstream_in */ #if 0 if (zzstream_in && zzstream_in!=stdin) fclose( zzstream_in ); #endif zzline = 1; zzstream_in = NULL; zzfunc_in = f; zzstr_in = 0; zzcharfull = 0; } } void #ifdef __USE_PROTOS zzrdstr( zzchar_t *s ) #else zzrdstr( s ) zzchar_t *s; #endif { /* make sure that it is really set to something, otherwise just leave it be. */ if (s){ /* make sure that there is always someplace to get input before closing zzstream_in */ #if 0 if (zzstream_in && zzstream_in!=stdin) fclose( zzstream_in ); #endif zzline = 1; zzstream_in = NULL; zzfunc_in = 0; zzstr_in = s; zzcharfull = 0; } } #ifdef __USE_PROTOS void zzclose_stream(void) #else void zzclose_stream() #endif { #if 0 fclose( zzstream_in ); zzstream_in = NULL; zzfunc_in = NULL; #endif } /* saves dlg state, but not what feeds dlg (such as file position) */ void #ifdef __USE_PROTOS zzsave_dlg_state(struct zzdlg_state *state) #else zzsave_dlg_state(state) struct zzdlg_state *state; #endif { state->stream = zzstream_in; state->func_ptr = zzfunc_in; state->str = zzstr_in; state->auto_num = zzauto; state->add_erase = zzadd_erase; state->lookc = zzchar; state->char_full = zzcharfull; state->begcol = zzbegcol; state->endcol = zzendcol; state->line = zzline; state->lextext = zzlextext; state->begexpr = zzbegexpr; state->endexpr = zzendexpr; state->bufsize = zzbufsize; state->bufovf = zzbufovf; state->nextpos = zznextpos; state->class_num = zzclass; } void #ifdef __USE_PROTOS zzrestore_dlg_state(struct zzdlg_state *state) #else zzrestore_dlg_state(state) struct zzdlg_state *state; #endif { zzstream_in = state->stream; zzfunc_in = state->func_ptr; zzstr_in = state->str; zzauto = state->auto_num; zzadd_erase = state->add_erase; zzchar = state->lookc; zzcharfull = state->char_full; zzbegcol = state->begcol; zzendcol = state->endcol; zzline = state->line; zzlextext = state->lextext; zzbegexpr = state->begexpr; zzendexpr = state->endexpr; zzbufsize = state->bufsize; zzbufovf = state->bufovf; zznextpos = state->nextpos; zzclass = state->class_num; } void #ifdef __USE_PROTOS zzmode( int m ) #else zzmode( m ) int m; #endif { /* points to base of dfa table */ if (m #include /* */ /* 7-Apr-97 133MR1 */ /* Proper choice of STDC and cplusplus pre-processor symbols (?) */ /* */ #include "pccts_string.h" #ifdef PCCTS_USE_STDARG #include "pccts_stdarg.h" #else #include #endif #ifdef DUM /* Define usable bits per unsigned int word (used for set stuff) */ #ifdef PC #define BSETWORDSIZE 16 #define BSETLOGWORDSIZE 4 #else #define BSETWORDSIZE 32 #define BSETLOGWORDSIZE 5 #endif #endif #define BSETWORDSIZE 8 #define BSETLOGWORDSIZE 3 /* SetWordType is 8bits */ #define BSETMODWORD(x) ((x) & (BSETWORDSIZE-1)) /* x % BSETWORDSIZE */ #define BSETDIVWORD(x) ((x) >> BSETLOGWORDSIZE) /* x / BSETWORDSIZE */ /* This is not put into the global pccts_parser structure because it is * hidden and does not need to be saved during a "save state" operation */ /* maximum of 32 bits/unsigned int and must be 8 bits/byte */ static SetWordType bitmask[] = { 0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, 0x00000020, 0x00000040, 0x00000080 }; #ifdef zzTRACE_RULES int zzTraceOptionValueDefault=1; int zzTraceOptionValue=1; int zzTraceGuessOptionValue=1; char *zzTraceCurrentRuleName=NULL; int zzTraceDepth=0; #endif int zzGuessSeq=0; /* MR10 */ int zzSyntaxErrCount=0; /* MR11 */ int zzLexErrCount=0; /* MR11 */ void #ifdef __USE_PROTOS zzresynch(SetWordType *wd,SetWordType mask) #else zzresynch(wd,mask) SetWordType *wd, mask; #endif { static int consumed = 1; /* if you enter here without having consumed a token from last resynch * force a token consumption. */ if ( !consumed ) {zzCONSUME; consumed=1; return;} /* MR10 */ /* if current token is in resynch set, we've got what we wanted */ if ( wd[LA(1)]&mask || LA(1) == zzEOF_TOKEN ) {consumed=0; return;} /* scan until we find something in the resynch set */ while ( !(wd[LA(1)]&mask) && LA(1) != zzEOF_TOKEN ) {zzCONSUME;} consumed=1; } /* */ /* 7-Apr-97 133MR1 for C++ and MR7 for C */ /* Change suggested by Eli Sternheim (eli@interhdl.com) */ /* */ void #ifdef __USE_PROTOS zzconsumeUntil(SetWordType *st) #else zzconsumeUntil(st) SetWordType *st; #endif { int tmp; /* MR7 */ while ( !zzset_el( (tmp=LA(1)), st) && tmp!=1 /* Eof */) { /* MR7 */ zzCONSUME; } /* MR7 */ } /* */ /* 7-Apr-97 133MR1 for C++ and MR7 for C */ /* Change suggested by Eli Sternheim (eli@interhdl.com) */ /* */ void #ifdef __USE_PROTOS zzconsumeUntilToken(int t) #else zzconsumeUntilToken(t) int t; #endif { int tmp; /* MR7 */ while ( (tmp=LA(1)) !=t && tmp!=1 /* Eof */) { zzCONSUME; } /* MR7 */ } /* input looks like: * zzFAIL(k, e1, e2, ...,&zzMissSet,&zzMissText,&zzBadTok,&zzBadText) * where the zzMiss stuff is set here to the token that did not match * (and which set wasn't it a member of). */ #ifdef PCCTS_USE_STDARG void zzFAIL(int k, ...) #else void zzFAIL(va_alist) va_dcl #endif { #ifdef LL_K static char text[LL_K*ZZLEXBUFSIZE+1]; SetWordType *f[LL_K]; #else static char text[ZZLEXBUFSIZE+1]; SetWordType *f[1]; #endif SetWordType **miss_set; char **miss_text; int *bad_tok; char **bad_text; int *err_k; int i; va_list ap; #ifndef PCCTS_USE_STDARG /* MR20 */ int k; #endif #ifdef PCCTS_USE_STDARG /* MR20 */ va_start(ap, k); #else va_start(ap); k = va_arg(ap, int); /* how many lookahead sets? */ #endif assert(k <= sizeof(f)/sizeof(f[0])); /* MR20 G. Hobbelt */ text[0] = '\0'; for (i=1; i<=k; i++) /* collect all lookahead sets */ { f[i-1] = va_arg(ap, SetWordType *); } for (i=1; i<=k; i++) /* look for offending token */ { if ( i>1 ) strcat(text, " "); strcat(text, LATEXT(i)); if ( !zzset_el((unsigned)LA(i), f[i-1]) ) break; } miss_set = va_arg(ap, SetWordType **); miss_text = va_arg(ap, char **); bad_tok = va_arg(ap, int *); bad_text = va_arg(ap, char **); err_k = va_arg(ap, int *); if ( i>k ) { /* bad; lookahead is permutation that cannot be matched, * but, the ith token of lookahead is valid at the ith position * (The old LL sub 1 (k) versus LL(k) parsing technique) */ *miss_set = NULL; *miss_text = zzlextext; *bad_tok = LA(1); *bad_text = LATEXT(1); *err_k = k; return; } /* fprintf(stderr, "%s not in %dth set\n", zztokens[LA(i)], i);*/ *miss_set = f[i-1]; *miss_text = text; *bad_tok = LA(i); *bad_text = LATEXT(i); if ( i==1 ) *err_k = 1; else *err_k = k; } #ifdef __USE_PROTOS void zzTraceGuessDone(zzantlr_state *state) #else void zzTraceGuessDone(state) zzantlr_state *state; #endif { #ifdef zzTRACE_RULES #ifdef ZZCAN_GUESS int doIt=0; if (zzTraceCurrentRuleName == NULL) return; if (zzTraceOptionValue <= 0) { doIt=0; } else if (zzTraceGuessOptionValue <= 0) { doIt=0; } else { doIt=1; }; if (doIt) { fprintf(stderr,"guess done - returning to rule %s {\"%s\"} at depth %d", state->traceCurrentRuleName, LATEXT(1), state->traceDepth); if (state->guessing != 0) { fprintf(stderr," (guess mode continues - an enclosing guess is still active)"); } else { fprintf(stderr," (guess mode ends)"); }; fprintf(stderr,"\n"); }; #endif #endif } void #ifdef __USE_PROTOS zzsave_antlr_state(zzantlr_state *buf) #else zzsave_antlr_state(buf) zzantlr_state *buf; #endif { #ifdef LL_K int i; #endif #ifdef ZZCAN_GUESS buf->guess_start = zzguess_start; buf->guessing = zzguessing; #endif buf->asp = zzasp; #ifdef GENAST buf->ast_sp = zzast_sp; #endif #ifdef ZZINF_LOOK buf->inf_labase = zzinf_labase; buf->inf_last = zzinf_last; /* MR6 Gunnar Rxnning (gunnar@candleweb.no) */ /* MR6 Additional state needs to be saved/restored */ buf->inf_tokens = zzinf_tokens; /* MR6 */ buf->inf_text = zzinf_text; /* MR6 */ buf->inf_text_buffer = zzinf_text_buffer; /* MR6 */ buf->inf_line = zzinf_line; /* MR6 */ #endif #ifdef DEMAND_LOOK buf->dirty = zzdirty; #endif #ifdef LL_K for (i=0; itokenLA[i] = zztokenLA[i]; for (i=0; itextLA[i], zztextLA[i]); buf->lap = zzlap; buf->labase = zzlabase; #else buf->token = zztoken; strcpy(buf->text, zzlextext); #endif #ifdef zzTRACE_RULES /* MR10 */ buf->traceOptionValue=zzTraceOptionValue; buf->traceGuessOptionValue=zzTraceGuessOptionValue; buf->traceCurrentRuleName=zzTraceCurrentRuleName; buf->traceDepth=zzTraceDepth; #endif } void #ifdef __USE_PROTOS zzrestore_antlr_state(zzantlr_state *buf) #else zzrestore_antlr_state(buf) zzantlr_state *buf; #endif { #ifdef zzTRACE_RULES int prevTraceOptionValue; #endif #ifdef LL_K int i; #endif #ifdef ZZCAN_GUESS zzguess_start = buf->guess_start; zzguessing = buf->guessing; #endif zzasp = buf->asp; #ifdef GENAST zzast_sp = buf->ast_sp; #endif #ifdef ZZINF_LOOK zzinf_labase = buf->inf_labase; zzinf_last = buf->inf_last; /* MR6 Gunnar Rxnning (gunnar@candleweb.no) */ /* MR6 Additional state needs to be saved/restored */ zzinf_tokens = buf->inf_tokens; /* MR6 */ zzinf_text = buf->inf_text; /* MR6 */ zzinf_text_buffer = buf->inf_text_buffer; /* MR6 */ zzinf_line = buf->inf_line; /* MR6 */ #endif #ifdef DEMAND_LOOK zzdirty = buf->dirty; #endif #ifdef LL_K for (i=0; itokenLA[i]; for (i=0; itextLA[i]); zzlap = buf->lap; zzlabase = buf->labase; #else zztoken = buf->token; strcpy(zzlextext, buf->text); #endif #ifdef zzTRACE_RULES prevTraceOptionValue=zzTraceOptionValue; zzTraceOptionValue=buf->traceOptionValue; if ( (prevTraceOptionValue > 0) != (zzTraceOptionValue > 0)) { if (zzTraceOptionValue > 0) { fprintf(stderr,"trace enable restored in rule %s depth %d\n", zzTraceCurrentRuleName,zzTraceDepth); }; if (zzTraceOptionValue <= 0) { fprintf(stderr,"trace disable restored in rule %s depth %d\n", zzTraceCurrentRuleName,zzTraceDepth); }; }; zzTraceOptionValue=buf->traceOptionValue; /* MR10 */ zzTraceGuessOptionValue=buf->traceGuessOptionValue; /* MR10 */ zzTraceCurrentRuleName=buf->traceCurrentRuleName; /* MR10 */ zzTraceDepth=buf->traceDepth; /* MR10 */ zzTraceGuessDone(buf); /* MR10 */ #endif } void #ifdef __USE_PROTOS zzedecode(SetWordType *a) #else zzedecode(a) SetWordType *a; #endif { register SetWordType *p = a; register SetWordType *endp = &(p[zzSET_SIZE]); register unsigned e = 0; if ( zzset_deg(a)>1 ) fprintf(stderr, " {"); do { register SetWordType t = *p; register SetWordType *b = &(bitmask[0]); do { if ( t & *b ) fprintf(stderr, " %s", zztokens[e]); e++; } while (++b < &(bitmask[sizeof(SetWordType)*8])); } while (++p < endp); if ( zzset_deg(a)>1 ) fprintf(stderr, " }"); } #ifndef USER_ZZSYN /* standard error reporting function */ void #ifdef __USE_PROTOS zzsyn(char *text, int tok, char *egroup, SetWordType *eset, int etok, int k, char *bad_text) #else zzsyn(text, tok, egroup, eset, etok, k, bad_text) char *text, *egroup, *bad_text; int tok; int etok; int k; SetWordType *eset; #endif { zzSyntaxErrCount++; /* MR11 */ fprintf(stderr, "line %d: syntax error at \"%s\"", zzline, (tok==zzEOF_TOKEN)?"EOF":bad_text); if ( !etok && !eset ) {fprintf(stderr, "\n"); return;} if ( k==1 ) fprintf(stderr, " missing"); else { fprintf(stderr, "; \"%s\" not", bad_text); if ( zzset_deg(eset)>1 ) fprintf(stderr, " in"); } if ( zzset_deg(eset)>0 ) zzedecode(eset); else fprintf(stderr, " %s", zztokens[etok]); if ( strlen(egroup) > 0 ) fprintf(stderr, " in %s", egroup); fprintf(stderr, "\n"); } #endif /* is b an element of set p? */ int #ifdef __USE_PROTOS zzset_el(unsigned b, SetWordType *p) #else zzset_el(b,p) unsigned b; SetWordType *p; #endif { return( p[BSETDIVWORD(b)] & bitmask[BSETMODWORD(b)] ); } int #ifdef __USE_PROTOS zzset_deg(SetWordType *a) #else zzset_deg(a) SetWordType *a; #endif { /* Fast compute degree of a set... the number of elements present in the set. Assumes that all word bits are used in the set */ register SetWordType *p = a; register SetWordType *endp = &(a[zzSET_SIZE]); register int degree = 0; if ( a == NULL ) return 0; while ( p < endp ) { register SetWordType t = *p; register SetWordType *b = &(bitmask[0]); do { if (t & *b) ++degree; } while (++b < &(bitmask[sizeof(SetWordType)*8])); p++; } return(degree); } #ifdef DEMAND_LOOK #ifdef LL_K int #ifdef __USE_PROTOS _zzmatch(int _t, char **zzBadText, char **zzMissText, int *zzMissTok, int *zzBadTok, SetWordType **zzMissSet) #else _zzmatch(_t, zzBadText, zzMissText, zzMissTok, zzBadTok, zzMissSet) int _t; char **zzBadText; char **zzMissText; int *zzMissTok, *zzBadTok; SetWordType **zzMissSet; #endif { if ( zzdirty==LL_K ) { zzCONSUME; } if ( LA(1)!=_t ) { *zzBadText = *zzMissText=LATEXT(1); *zzMissTok= _t; *zzBadTok=LA(1); *zzMissSet=NULL; return 0; } zzMakeAttr zzdirty++; zzlabase++; return 1; } int #ifdef __USE_PROTOS _zzmatch_wsig(int _t) #else _zzmatch_wsig(_t) int _t; #endif { if ( zzdirty==LL_K ) { zzCONSUME; } if ( LA(1)!=_t ) { return 0; } zzMakeAttr zzdirty++; zzlabase++; return 1; } #else int #ifdef __USE_PROTOS _zzmatch(int _t, char **zzBadText, char **zzMissText, int *zzMissTok, int *zzBadTok, SetWordType **zzMissSet) #else _zzmatch(_t, zzBadText, zzMissText, zzMissTok, zzBadTok, zzMissSet) int _t; char **zzBadText; char **zzMissText; int *zzMissTok, *zzBadTok; SetWordType **zzMissSet; #endif { if ( zzdirty ) {zzCONSUME;} if ( LA(1)!=_t ) { *zzBadText = *zzMissText=LATEXT(1); *zzMissTok= _t; *zzBadTok=LA(1); *zzMissSet=NULL; return 0; } zzdirty = 1; zzMakeAttr return 1; } int #ifdef __USE_PROTOS _zzmatch_wsig(int _t) #else _zzmatch_wsig(_t) int _t; #endif { if ( zzdirty ) {zzCONSUME;} if ( LA(1)!=_t ) { return 0; } zzdirty = 1; zzMakeAttr return 1; } #endif /*LL_K*/ #else int #ifdef __USE_PROTOS _zzmatch(int _t, char **zzBadText, char **zzMissText, int *zzMissTok, int *zzBadTok, SetWordType **zzMissSet) #else _zzmatch(_t, zzBadText, zzMissText, zzMissTok, zzBadTok, zzMissSet) int _t; char **zzBadText; char **zzMissText; int *zzMissTok, *zzBadTok; SetWordType **zzMissSet; #endif { if ( LA(1)!=_t ) { *zzBadText = *zzMissText=LATEXT(1); *zzMissTok= _t; *zzBadTok=LA(1); *zzMissSet=NULL; return 0; } zzMakeAttr return 1; } int #ifdef __USE_PROTOS _zzmatch_wsig(int _t) #else _zzmatch_wsig(_t) int _t; #endif { if ( LA(1)!=_t ) return 0; zzMakeAttr return 1; } #endif /*DEMAND_LOOK*/ #ifdef ZZINF_LOOK void #ifdef __USE_PROTOS _inf_zzgettok(void) #else _inf_zzgettok() #endif { if ( zzinf_labase >= zzinf_last ) {NLA = zzEOF_TOKEN; strcpy(NLATEXT, "");} else { NLA = zzinf_tokens[zzinf_labase]; zzline = zzinf_line[zzinf_labase]; /* wrong in 1.21 */ strcpy(NLATEXT, zzinf_text[zzinf_labase]); zzinf_labase++; } } #endif #ifdef ZZINF_LOOK /* allocate default size text,token and line arrays; * then, read all of the input reallocing the arrays as needed. * Once the number of total tokens is known, the LATEXT(i) array (zzinf_text) * is allocated and it's pointers are set to the tokens in zzinf_text_buffer. */ void #ifdef __USE_PROTOS zzfill_inf_look(void) #else zzfill_inf_look() #endif { int tok, line; int zzinf_token_buffer_size = ZZINF_DEF_TOKEN_BUFFER_SIZE; int zzinf_text_buffer_size = ZZINF_DEF_TEXT_BUFFER_SIZE; int zzinf_text_buffer_index = 0; int zzinf_lap = 0; /* allocate text/token buffers */ zzinf_text_buffer = (char *) malloc(zzinf_text_buffer_size); if ( zzinf_text_buffer == NULL ) { fprintf(stderr, "cannot allocate lookahead text buffer (%d bytes)\n", zzinf_text_buffer_size); exit(PCCTS_EXIT_FAILURE); } zzinf_tokens = (int *) calloc(zzinf_token_buffer_size,sizeof(int)); if ( zzinf_tokens == NULL ) { fprintf(stderr, "cannot allocate token buffer (%d tokens)\n", zzinf_token_buffer_size); exit(PCCTS_EXIT_FAILURE); } zzinf_line = (int *) calloc(zzinf_token_buffer_size,sizeof(int)); if ( zzinf_line == NULL ) { fprintf(stderr, "cannot allocate line buffer (%d ints)\n", zzinf_token_buffer_size); exit(PCCTS_EXIT_FAILURE); } /* get tokens, copying text to text buffer */ zzinf_text_buffer_index = 0; do { zzgettok(); line = zzreal_line; while ( zzinf_lap>=zzinf_token_buffer_size ) { zzinf_token_buffer_size += ZZINF_BUFFER_TOKEN_CHUNK_SIZE; zzinf_tokens = (int *) realloc(zzinf_tokens, zzinf_token_buffer_size*sizeof(int)); if ( zzinf_tokens == NULL ) { fprintf(stderr, "cannot allocate lookahead token buffer (%d tokens)\n", zzinf_token_buffer_size); exit(PCCTS_EXIT_FAILURE); } zzinf_line = (int *) realloc(zzinf_line, zzinf_token_buffer_size*sizeof(int)); if ( zzinf_line == NULL ) { fprintf(stderr, "cannot allocate lookahead line buffer (%d ints)\n", zzinf_token_buffer_size); exit(PCCTS_EXIT_FAILURE); } } while ( (zzinf_text_buffer_index+strlen(NLATEXT)+1) >= zzinf_text_buffer_size ) { zzinf_text_buffer_size += ZZINF_BUFFER_TEXT_CHUNK_SIZE; zzinf_text_buffer = (char *) realloc(zzinf_text_buffer, zzinf_text_buffer_size); if ( zzinf_text_buffer == NULL ) { fprintf(stderr, "cannot allocate lookahead text buffer (%d bytes)\n", zzinf_text_buffer_size); exit(PCCTS_EXIT_FAILURE); } } /* record token and text and line of input symbol */ tok = zzinf_tokens[zzinf_lap] = NLA; strcpy(&zzinf_text_buffer[zzinf_text_buffer_index], NLATEXT); zzinf_text_buffer_index += strlen(NLATEXT)+1; zzinf_line[zzinf_lap] = line; zzinf_lap++; } while (tok!=zzEOF_TOKEN); zzinf_labase = 0; zzinf_last = zzinf_lap-1; /* allocate ptrs to text of ith token */ zzinf_text = (char **) calloc(zzinf_last+1,sizeof(char *)); if ( zzinf_text == NULL ) { fprintf(stderr, "cannot allocate lookahead text buffer (%d)\n", zzinf_text_buffer_size); exit(PCCTS_EXIT_FAILURE); } zzinf_text_buffer_index = 0; zzinf_lap = 0; /* set ptrs so that zzinf_text[i] is the text of the ith token found on input */ while (zzinf_lap<=zzinf_last) { zzinf_text[zzinf_lap++] = &zzinf_text_buffer[zzinf_text_buffer_index]; zzinf_text_buffer_index += strlen(&zzinf_text_buffer[zzinf_text_buffer_index])+1; } } #endif int #ifdef __USE_PROTOS _zzsetmatch(SetWordType *e, char **zzBadText, char **zzMissText, int *zzMissTok, int *zzBadTok, SetWordType **zzMissSet, SetWordType *zzTokclassErrset /* MR23 */) #else _zzsetmatch(e, zzBadText, zzMissText, zzMissTok, zzBadTok, zzMissSet, zzTokclassErrset /* MR23 */) SetWordType *e; char **zzBadText; char **zzMissText; int *zzMissTok, *zzBadTok; SetWordType **zzMissSet; SetWordType *zzTokclassErrset; #endif { #ifdef DEMAND_LOOK #ifdef LL_K if ( zzdirty==LL_K ) {zzCONSUME;} #else if ( zzdirty ) {zzCONSUME;} #endif #endif if ( !zzset_el((unsigned)LA(1), e) ) { *zzBadText = LATEXT(1); *zzMissText=NULL; *zzMissTok= 0; *zzBadTok=LA(1); *zzMissSet=zzTokclassErrset; /* MR23 */ return 0; } zzMakeAttr /* MR14 Ger Hobbelt (hobbelt@axa.nl) */ #ifdef DEMAND_LOOK #ifdef LL_K zzdirty++; zzlabase++; /* MR14 Ger Hobbelt (hobbelt@axa.nl) */ #else zzdirty = 1; #endif #endif return 1; } int #ifdef __USE_PROTOS _zzmatch_wdfltsig(int tokenWanted, SetWordType *whatFollows) #else _zzmatch_wdfltsig(tokenWanted, whatFollows) int tokenWanted; SetWordType *whatFollows; #endif { #ifdef DEMAND_LOOK #ifdef LL_K if ( zzdirty==LL_K ) { zzCONSUME; } #else if ( zzdirty ) {zzCONSUME;} #endif #endif if ( LA(1)!=tokenWanted ) { zzSyntaxErrCount++; /* MR11 */ fprintf(stderr, "line %d: syntax error at \"%s\" missing %s\n", zzline, (LA(1)==zzEOF_TOKEN)?"":(char *)LATEXT(1), zztokens[tokenWanted]); zzconsumeUntil( whatFollows ); return 0; } else { zzMakeAttr #ifdef DEMAND_LOOK #ifdef LL_K zzdirty++; zzlabase++; #else zzdirty = 1; #endif #else /* zzCONSUME; consume if not demand lookahead */ #endif return 1; } } int #ifdef __USE_PROTOS _zzsetmatch_wdfltsig(SetWordType *tokensWanted, int tokenTypeOfSet, SetWordType *whatFollows) #else _zzsetmatch_wdfltsig(tokensWanted, tokenTypeOfSet, whatFollows) SetWordType *tokensWanted; int tokenTypeOfSet; SetWordType *whatFollows; #endif { #ifdef DEMAND_LOOK #ifdef LL_K if ( zzdirty==LL_K ) {zzCONSUME;} #else if ( zzdirty ) {zzCONSUME;} #endif #endif if ( !zzset_el((unsigned)LA(1), tokensWanted) ) { zzSyntaxErrCount++; /* MR11 */ fprintf(stderr, "line %d: syntax error at \"%s\" missing %s\n", zzline, (LA(1)==zzEOF_TOKEN)?"":(char *)LATEXT(1), zztokens[tokenTypeOfSet]); zzconsumeUntil( whatFollows ); return 0; } else { zzMakeAttr #ifdef DEMAND_LOOK #ifdef LL_K zzdirty++; zzlabase++; #else zzdirty = 1; #endif #else /* zzCONSUME; consume if not demand lookahead */ #endif return 1; } } int #ifdef __USE_PROTOS _zzsetmatch_wsig(SetWordType *e) #else _zzsetmatch_wsig(e) SetWordType *e; #endif { #ifdef DEMAND_LOOK #ifdef LL_K if ( zzdirty==LL_K ) {zzCONSUME;} #else if ( zzdirty ) {zzCONSUME;} #endif #endif if ( !zzset_el((unsigned)LA(1), e) ) return 0; zzMakeAttr /* MR14 Ger Hobbelt (hobbelt@axa.nl) */ #ifdef DEMAND_LOOK #ifdef LL_K zzdirty++; zzlabase++; /* MR14 Ger Hobbelt (hobbelt@axa.nl) */ #else zzdirty = 1; #endif #endif return 1; } #ifdef USER_ZZMODE_STACK static int zzmstk[ZZMAXSTK] = { -1 }; static int zzmdep = 0; static char zzmbuf[70]; void #ifdef __USE_PROTOS zzmpush( int m ) #else zzmpush( m ) int m; #endif { if(zzmdep == ZZMAXSTK - 1) { sprintf(zzmbuf, "Mode stack overflow "); zzerr(zzmbuf); } else { zzmstk[zzmdep++] = zzauto; zzmode(m); } } void #ifdef __USE_PROTOS zzmpop( void ) #else zzmpop( ) #endif { if(zzmdep == 0) { sprintf(zzmbuf, "Mode stack underflow "); zzerr(zzmbuf); } else { zzmdep--; zzmode(zzmstk[zzmdep]); } } void #ifdef __USE_PROTOS zzsave_mode_stack( int modeStack[], int *modeLevel ) #else zzsave_mode_stack( modeStack, modeLevel ) int modeStack[]; int *modeLevel; #endif { int i; memcpy(modeStack, zzmstk, sizeof(zzmstk)); *modeLevel = zzmdep; zzmdep = 0; return; } void #ifdef __USE_PROTOS zzrestore_mode_stack( int modeStack[], int *modeLevel ) #else zzrestore_mode_stack( modeStack, modeLevel ) int modeStack[]; int *modeLevel; #endif { int i; memcpy(zzmstk, modeStack, sizeof(zzmstk)); zzmdep = *modeLevel; return; } #endif /* USER_ZZMODE_STACK */ #ifdef __USE_PROTOS void zzTraceReset(void) #else void zzTraceReset() #endif { #ifdef zzTRACE_RULES zzTraceOptionValue=zzTraceOptionValueDefault; zzTraceGuessOptionValue=1; zzTraceCurrentRuleName=NULL; zzTraceDepth=0; #endif } #ifdef __USE_PROTOS void zzTraceGuessFail(void) #else void zzTraceGuessFail() #endif { #ifdef zzTRACE_RULES #ifdef ZZCAN_GUESS int doIt=0; if (zzTraceOptionValue <= 0) { doIt=0; } else if (zzguessing && zzTraceGuessOptionValue <= 0) { doIt=0; } else { doIt=1; }; if (doIt) { fprintf(stderr,"guess failed\n"); }; #endif #endif } /* zzTraceOption: zero value turns off trace */ #ifdef __USE_PROTOS void zzTraceIn(char * rule) #else void zzTraceIn(rule) char *rule; #endif { #ifdef zzTRACE_RULES int doIt=0; zzTraceDepth++; zzTraceCurrentRuleName=rule; if (zzTraceOptionValue <= 0) { doIt=0; #ifdef ZZCAN_GUESS } else if (zzguessing && zzTraceGuessOptionValue <= 0) { doIt=0; #endif } else { doIt=1; }; if (doIt) { fprintf(stderr,"enter rule %s {\"%s\"} depth %d", rule, LA(1)==1 ? "@" : (char *) LATEXT(1), /* MR19 */ zzTraceDepth); #ifdef ZZCAN_GUESS if (zzguessing) fprintf(stderr," guessing"); #endif fprintf(stderr,"\n"); }; #endif return; } #ifdef __USE_PROTOS void zzTraceOut(char * rule) #else void zzTraceOut(rule) char *rule; #endif { #ifdef zzTRACE_RULES int doIt=0; zzTraceDepth--; if (zzTraceOptionValue <= 0) { doIt=0; #ifdef ZZCAN_GUESS } else if (zzguessing && zzTraceGuessOptionValue <= 0) { doIt=0; #endif } else { doIt=1; }; if (doIt) { fprintf(stderr,"exit rule %s {\"%s\"} depth %d", rule, LA(1)==1 ? "@" : (char *) LATEXT(1), /* MR19 */ zzTraceDepth+1); #ifdef ZZCAN_GUESS if (zzguessing) fprintf(stderr," guessing"); #endif fprintf(stderr,"\n"); }; #endif } #ifdef __USE_PROTOS int zzTraceOption(int delta) #else int zzTraceOption(delta) int delta; #endif { #ifdef zzTRACE_RULES int prevValue=zzTraceOptionValue; zzTraceOptionValue=zzTraceOptionValue+delta; if (zzTraceCurrentRuleName != NULL) { if (prevValue <= 0 && zzTraceOptionValue > 0) { fprintf(stderr,"trace enabled in rule %s depth %d\n", zzTraceCurrentRuleName,zzTraceDepth); }; if (prevValue > 0 && zzTraceOptionValue <= 0) { fprintf(stderr,"trace disabled in rule %s depth %d\n", zzTraceCurrentRuleName,zzTraceDepth); }; }; return prevValue; #else return 0; #endif } #ifdef __USE_PROTOS int zzTraceGuessOption(int delta) #else int zzTraceGuessOption(delta) int delta; #endif { #ifdef zzTRACE_RULES #ifdef ZZCAN_GUESS int prevValue=zzTraceGuessOptionValue; zzTraceGuessOptionValue=zzTraceGuessOptionValue+delta; if (zzTraceCurrentRuleName != NULL) { if (prevValue <= 0 && zzTraceGuessOptionValue > 0) { fprintf(stderr,"guess trace enabled in rule %s depth %d\n", zzTraceCurrentRuleName,zzTraceDepth); }; if (prevValue > 0 && zzTraceGuessOptionValue <= 0) { fprintf(stderr,"guess trace disabled in rule %s depth %d\n", zzTraceCurrentRuleName,zzTraceDepth); }; }; return prevValue; #else return 0; #endif #else return 0; #endif } #endif /* ERR_H */ cdrdao-cdrdao-f00afb2/pccts/h/int.h000066400000000000000000000025331511453746600172070ustar00rootroot00000000000000/* ANTLR attribute definition -- long integers * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * ANTLR 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2000 */ #ifndef ZZINT_H #define ZZINT_H typedef long Attrib; #define zzcr_attr(a,tok,t) *(a) = atol(t); #endif cdrdao-cdrdao-f00afb2/pccts/h/pccts_assert.h000066400000000000000000000002221511453746600211030ustar00rootroot00000000000000#ifndef __PCCTS_ASSERT_H__ #define __PCCTS_ASSERT_H__ #ifdef PCCTS_USE_NAMESPACE_STD #include #else #include #endif #endif cdrdao-cdrdao-f00afb2/pccts/h/pccts_iostream.h000066400000000000000000000002311511453746600214250ustar00rootroot00000000000000#ifndef __PCCTS_IOSTREAM_H__ #define __PCCTS_IOSTREAM_H__ #ifdef PCCTS_USE_NAMESPACE_STD #include #else #include #endif #endif cdrdao-cdrdao-f00afb2/pccts/h/pccts_istream.h000066400000000000000000000002251511453746600212510ustar00rootroot00000000000000#ifndef __PCCTS_ISTREAM_H__ #define __PCCTS_ISTREAM_H__ #ifdef PCCTS_USE_NAMESPACE_STD #include #else #include #endif #endif cdrdao-cdrdao-f00afb2/pccts/h/pccts_setjmp.h000066400000000000000000000002221511453746600211040ustar00rootroot00000000000000#ifndef __PCCTS_SETJMP_H__ #define __PCCTS_SETJMP_H__ #ifdef PCCTS_USE_NAMESPACE_STD #include #else #include #endif #endif cdrdao-cdrdao-f00afb2/pccts/h/pccts_stdarg.h000066400000000000000000000002221511453746600210660ustar00rootroot00000000000000#ifndef __PCCTS_STDARG_H__ #define __PCCTS_STDARG_H__ #ifdef PCCTS_USE_NAMESPACE_STD #include #else #include #endif #endif cdrdao-cdrdao-f00afb2/pccts/h/pccts_stdio.h000066400000000000000000000002161511453746600207270ustar00rootroot00000000000000#ifndef __PCCTS_STDIO_H__ #define __PCCTS_STDIO_H__ #ifdef PCCTS_USE_NAMESPACE_STD #include #else #include #endif #endif cdrdao-cdrdao-f00afb2/pccts/h/pccts_stdlib.h000066400000000000000000000002221511453746600210630ustar00rootroot00000000000000#ifndef __PCCTS_STDLIB_H__ #define __PCCTS_STDLIB_H__ #ifdef PCCTS_USE_NAMESPACE_STD #include #else #include #endif #endif cdrdao-cdrdao-f00afb2/pccts/h/pccts_string.h000066400000000000000000000002221511453746600211100ustar00rootroot00000000000000#ifndef __PCCTS_STRING_H__ #define __PCCTS_STRING_H__ #ifdef PCCTS_USE_NAMESPACE_STD #include #else #include #endif #endif cdrdao-cdrdao-f00afb2/pccts/h/pcctscfg.h000066400000000000000000000214521511453746600202120ustar00rootroot00000000000000#ifndef PCCTS_CONFIG_H #define PCCTS_CONFIG_H /* * pcctscfg.h (formerly config.h) (for ANTLR, DLG, and SORCERER) * * This is a simple configuration file that doesn't have config stuff * in it, but it's a start. * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to the Purdue Compiler Construction Tool * Set (PCCTS) -- PCCTS is in the public domain. An individual or * company may do whatever they wish with source code distributed with * PCCTS or the code generated by PCCTS, including the incorporation of * PCCTS, or its output, into commerical software. * * We encourage users to develop software with PCCTS. However, we do ask * that credit is given to us for developing PCCTS. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like PCCTS and have developed a nice tool with the * output, please mention that you developed it using PCCTS. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * Used by PCCTS 1.33 (SORCERER 1.00B11 and up) * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1989-2000 */ /* This file knows about the following ``environments'' UNIX (default) DOS (use #define PC) MAC (use #define MPW; has a few things for THINK C, Metrowerks) MS/C++ (MR14 Microsoft Visual C++ environment uses symbol _MSC_VER) */ /* should test __STDC__ for 1, but some compilers don't set value, just def */ #ifndef __USE_PROTOS #ifdef __STDC__ #define __USE_PROTOS #endif #ifdef __cplusplus #define __USE_PROTOS #endif #endif #ifdef PCCTS_USE_NAMESPACE_STD #define PCCTS_NAMESPACE_STD namespace std {}; using namespace std; #else #define PCCTS_NAMESPACE_STD #endif #include "pccts_stdio.h" #include "pccts_stdlib.h" /* largest file name size */ #ifdef _MAX_PATH #define MaxFileName _MAX_PATH /* MR9 RJV: MAX_PATH defined in stdlib.h (MSVC++ 5.0) */ #else #define MaxFileName 300 #endif /* * Define PC32 if in a 32-bit PC environment (e.g. extended DOS or Win32). * The macros tested here are defined by Watcom, Microsoft, Borland, * and djgpp, respectively, when they are used as 32-bit compilers. * Users of these compilers *must* be sure to define PC in their * makefiles for this to work correctly. */ #ifdef PC # if (defined(__WATCOMC__) || defined(_WIN32) || defined(__WIN32__) || \ defined(__GNUC__) || defined(__GNUG__)) # ifndef PC32 # define PC32 # endif # endif #endif /* MR1 10-Apr-97 Default for PC is short file names */ /* MR1 Default for non-PC is long file names */ /* MR1 Can override via command line option LONGFILENAMES */ #ifndef LONGFILENAMES #ifndef PC #define LONGFILENAMES #endif #endif #ifndef LONGFILENAMES #define ATOKEN_H "AToken.h" #define ATOKPTR_H "ATokPtr.h" #define ATOKPTR_IMPL_H "ATokPtrIm.h" #define ATOKENBUFFER_H "ATokBuf.h" #define ATOKENBUFFER_C "ATokBuf.cpp" #define ATOKENSTREAM_H "ATokStr.h" #define APARSER_H "AParser.h" #define APARSER_C "AParser.cpp" #define ASTBASE_H "ASTBase.h" #define ASTBASE_C "ASTBase.cpp" #define PCCTSAST_C "PCCTSAST.cpp" #define LIST_C "List.cpp" #define DLEXERBASE_H "DLexBase.h" #define DLEXERBASE_C "DLexBase.cpp" #define DLEXER_H "DLexer.h" #define STREESUPPORT_C "STreeSup.C" #else #define ATOKEN_H "AToken.h" #define ATOKPTR_H "ATokPtr.h" #define ATOKPTR_IMPL_H "ATokPtrImpl.h" #define ATOKENBUFFER_H "ATokenBuffer.h" #define ATOKENBUFFER_C "ATokenBuffer.cpp" #define ATOKENSTREAM_H "ATokenStream.h" #define APARSER_H "AParser.h" #define APARSER_C "AParser.cpp" #define ASTBASE_H "ASTBase.h" #define ASTBASE_C "ASTBase.cpp" #define PCCTSAST_C "PCCTSAST.cpp" #define LIST_C "List.cpp" #define DLEXERBASE_H "DLexerBase.h" #define DLEXERBASE_C "DLexerBase.cpp" #define DLEXER_H "DLexer.h" #define STREESUPPORT_C "STreeSupport.cpp" #endif /* SORCERER Stuff */ /* MR8 6-Aug-97 Change from ifdef PC to ifndef LONGFILENAMES */ #ifndef LONGFILENAMES #define STPARSER_H "STreePar.h" #define STPARSER_C "STreePar.C" #else #define STPARSER_H "STreeParser.h" #define STPARSER_C "STreeParser.cpp" #endif #ifdef MPW #define CPP_FILE_SUFFIX ".cp" #define CPP_FILE_SUFFIX_NO_DOT "cp" #define OBJ_FILE_SUFFIX ".o" #else #ifdef PC #define CPP_FILE_SUFFIX ".cpp" #define CPP_FILE_SUFFIX_NO_DOT "cpp" #define OBJ_FILE_SUFFIX ".obj" #else #ifdef __VMS #define CPP_FILE_SUFFIX ".cpp" #define CPP_FILE_SUFFIX_NO_DOT "cpp" #define OBJ_FILE_SUFFIX ".obj" #else #define CPP_FILE_SUFFIX ".cpp" #define CPP_FILE_SUFFIX_NO_DOT "cpp" #define OBJ_FILE_SUFFIX ".o" #endif #endif #endif /* User may redefine how line information looks */ /* make it #line MR7 */ /* MR21 Use #ifndef */ #ifndef LineInfoFormatStr #define LineInfoFormatStr "#line %d \"%s\"\n" #endif #ifdef MPW /* Macintosh Programmer's Workshop */ #define ErrHdr "File \"%s\"; Line %d #" #else #ifdef _MSC_VER /* MR14 Microsoft Visual C++ environment */ #define ErrHdr "%s(%d) :" #else #define ErrHdr "%s, line %d:" /* default */ #endif #endif /* must assume old K&R cpp here, can't use #if defined(..)... */ #ifdef MPW #define TopDirectory ":" #define DirectorySymbol ":" #define OutputDirectoryOption "Directory where all output files should go (default=\":\")" #else #ifdef PC #define TopDirectory "." #define DirectorySymbol "\\" #define OutputDirectoryOption "Directory where all output files should go (default=\".\")" #else #ifdef __VMS #define TopDirectory "[000000]" #define DirectorySymbol "]" #define OutputDirectoryOption "Directory where all output files should go (default=\"[]\")" #else #define TopDirectory "." #define DirectorySymbol "/" #define OutputDirectoryOption "Directory where all output files should go (default=\".\")" #endif #endif #endif #ifdef MPW /* Make sure we have prototypes for all functions under MPW */ #include "pccts_string.h" #include "pccts_stdlib.h" /* MR6 2-Jun-97 Fixes false dependency caused by VC++ #include scanner */ /* MR6 Reported by Brad Schick (schick@interaccess.com) */ #define MPW_CursorCtl_Header #include MPW_CursorCtl_Header #ifdef __cplusplus extern "C" { #endif extern void fsetfileinfo (const char *filename, unsigned long newcreator, unsigned long newtype); #ifdef __cplusplus } #endif /* File creators for various popular development environments */ #define MAC_FILE_CREATOR 'MPS ' /* MPW Text files */ #if 0 #define MAC_FILE_CREATOR 'KAHL' /* THINK C/Symantec C++ Text files */ #endif #if 0 #define MAC_FILE_CREATOR 'CWIE' /* Metrowerks C/C++ Text files */ #endif #endif #ifdef MPW #define DAWDLE SpinCursor(1) #else #define DAWDLE #endif #ifdef MPW #define SPECIAL_INITS #define SPECIAL_FOPEN #endif #ifdef MPW #ifdef __cplusplus inline #else static #endif void special_inits() { InitCursorCtl((acurHandle) 0); } #endif #ifdef MPW #ifdef __cplusplus inline #else static #endif void special_fopen_actions(char * s) { fsetfileinfo (s, MAC_FILE_CREATOR, 'TEXT'); } #endif /* Define usable bits for set.c stuff */ #define BytesPerWord sizeof(unsigned) #define WORDSIZE (sizeof(unsigned)*8) #define LogWordSize (WORDSIZE==16?4:5) #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #if defined(VAXC) || defined(__VMS) #include #define PCCTS_EXIT_SUCCESS 1 #define PCCTS_EXIT_FAILURE SS$_ABORT #define zzDIE return SS$_ABORT; #define zzDONE return 1; #else /* !VAXC and !__VMS */ #define PCCTS_EXIT_SUCCESS 0 #define PCCTS_EXIT_FAILURE 1 #define zzDIE return 1; #define zzDONE return 0; #endif #ifdef USER_ZZMODE_STACK # ifndef ZZSTACK_MAX_MODE # define ZZSTACK_MAX_MODE 32 # endif # define ZZMAXSTK (ZZSTACK_MAX_MODE * 2) #endif #ifndef DllExportPCCTS #define DllExportPCCTS #endif #ifdef PC #ifndef PCCTS_CASE_INSENSITIVE_FILE_NAME #define PCCTS_CASE_INSENSITIVE_FILE_NAME #endif #endif #ifdef PC32 #ifndef PCCTS_CASE_INSENSITIVE_FILE_NAME #define PCCTS_CASE_INSENSITIVE_FILE_NAME #endif #endif #ifdef __VMS #ifndef PCCTS_CASE_INSENSITIVE_FILE_NAME #define PCCTS_CASE_INSENSITIVE_FILE_NAME #endif #endif #ifdef __USE_PROTOS #ifndef PCCTS_USE_STDARG #define PCCTS_USE_STDARG #endif #endif #ifdef __STDC__ #ifndef PCCTS_USE_STDARG #define PCCTS_USE_STDARG #endif #endif #ifdef __cplusplus #ifndef PCCTS_USE_STDARG #define PCCTS_USE_STDARG #endif #endif #ifdef _MSC_VER /*Turn off the warnings for: unreferenced inline/local function has been removed */ #pragma warning(disable : 4514) /* function not expanded */ #pragma warning(disable : 4710) #endif #endif cdrdao-cdrdao-f00afb2/pccts/h/set.h000066400000000000000000000062241511453746600172110ustar00rootroot00000000000000#ifndef __GATE_SET_H #define __GATE_SET_H /* set.h The following is a general-purpose set library originally developed by Hank Dietz and enhanced by Terence Parr to allow dynamic sets. Sets are now structs containing the #words in the set and a pointer to the actual set words. 1987 by Hank Dietz Modified by: Terence Parr Purdue University October 1989 Added ANSI prototyping Dec. 1992 -- TJP */ #include "pcctscfg.h" #ifdef NOT_USED /* SEE config.h */ /* Define usable bits per unsigned int word */ #ifdef PC #define WORDSIZE 16 #define LogWordSize 4 #else #define WORDSIZE 32 #define LogWordSize 5 #endif #define BytesPerWord sizeof(unsigned) #endif #define SETSIZE(a) ((a).n<> LogWordSize) /* x / WORDSIZE */ #define nil (~((unsigned) 0)) /* An impossible set member all bits on (big!) */ typedef struct _set { unsigned int n; /* Number of words in set */ unsigned *setword; } set; #define set_init {0, NULL} #define set_null(a) ((a).setword==NULL) #define NumBytes(x) (((x)>>3)+1) /* Num bytes to hold x */ #define NumWords(x) ((((unsigned)(x))>>LogWordSize)+1) /* Num words to hold x */ /* M a c r o s */ /* make arg1 a set big enough to hold max elem # of arg2 */ #define set_new(a,_max) \ if (((a).setword=(unsigned *)calloc(NumWords(_max),BytesPerWord))==NULL) \ fprintf(stderr, "set_new: Cannot allocate set with max of %lu\n", _max); \ (a).n = NumWords(_max); #define set_free(a) \ {if ( (a).setword != NULL ) free((char *)((a).setword)); \ (a) = empty;} #ifdef __USE_PROTOS extern void set_size( unsigned ); extern unsigned int set_deg( set ); extern set set_or( set, set ); extern set set_and( set, set ); extern set set_dif( set, set ); extern set set_of( unsigned ); extern void set_ext( set *, unsigned int ); extern set set_not( set ); extern int set_equ( set, set ); extern int set_sub( set, set ); extern unsigned set_int( set ); extern int set_el( unsigned, set ); extern int set_nil( set ); extern char * set_str( set ); extern set set_val( register char * ); extern void set_orel( unsigned, set * ); extern void set_orin( set *, set ); extern void set_andin( set *, set ); extern void set_rm( unsigned, set ); extern void set_clr( set ); extern set set_dup( set ); extern void set_PDQ( set, register unsigned * ); extern unsigned *set_pdq( set ); extern void _set_pdq( set a, register unsigned *q ); extern unsigned int set_hash( set, register unsigned int ); #else extern void set_size(); extern unsigned int set_deg(); extern set set_or(); extern set set_and(); extern set set_dif(); extern set set_of(); extern void set_ext(); extern set set_not(); extern int set_equ(); extern int set_sub(); extern unsigned set_int(); extern int set_el(); extern int set_nil(); extern char * set_str(); extern set set_val(); extern void set_orel(); extern void set_orin(); extern void set_andin(); extern void set_rm(); extern void set_clr(); extern set set_dup(); extern void set_PDQ(); extern unsigned *set_pdq(); extern void _set_pdq(); extern unsigned int set_hash(); #endif extern set empty; #endif cdrdao-cdrdao-f00afb2/pccts/h/slist.cpp000066400000000000000000000054511511453746600201100ustar00rootroot00000000000000/* * SList.C * * SOFTWARE RIGHTS * * We reserve no LEGAL rights to SORCERER -- SORCERER is in the public * domain. An individual or company may do whatever they wish with * source code distributed with SORCERER or the code generated by * SORCERER, including the incorporation of SORCERER, or its output, into * commerical software. * * We encourage users to develop software with SORCERER. However, we do * ask that credit is given to us for developing SORCERER. By "credit", * we mean that if you incorporate our source code into one of your * programs (commercial product, research project, or otherwise) that you * acknowledge this fact somewhere in the documentation, research report, * etc... If you like SORCERER and have developed a nice tool with the * output, please mention that you developed it using SORCERER. In * addition, we ask that this header remain intact in our source code. * As long as these guidelines are kept, we expect to continue enhancing * this system and expect to make other tools available as they are * completed. * * PCCTS 1.33 * Terence Parr * Parr Research Corporation * with Purdue University and AHPCRC, University of Minnesota * 1992-2000 */ #define ANTLR_SUPPORT_CODE #include "SList.h" #include "pccts_stdarg.h" // MR23 /* Iterate over a list of elements; returns ptr to a new element * in list upon every call and NULL when no more are left. * Very useful like this: * * cursor = mylist; * while ( (p=mylist->iterate(&cursor)) ) { * // place with element p * } * * The cursor must be initialized to point to the list to iterate over. */ void *SList:: iterate(SListNode **cursor) { void *e; if ( cursor == NULL || *cursor==NULL ) return NULL; if ( head == *cursor ) { *cursor = (*cursor)->next(); } e = (*cursor)->elem(); (*cursor) = (*cursor)->next(); return e; } /* add an element to end of list. */ void SList:: add(void *e) { SListNode *p, *tail=NULL; require(e!=NULL, "slist_add: attempting to add NULL list element"); p = new SListNode; require(p!=NULL, "add: cannot alloc new list node"); p->setElem(e); if ( head == NULL ) { head = tail = p; } else /* find end of list */ { tail->setNext(p); tail = p; } } void SList:: lfree() { SListNode *p,*q; if ( head==NULL ) return; /* empty list */ for (p = head; p!=NULL; p=q) { q = p->next(); free(p); } } PCCTS_AST *SList:: to_ast(SList list) { PCCTS_AST *t=NULL, *last=NULL; SListNode *p; for (p = head; p!=NULL; p=p->next()) { PCCTS_AST *u = (PCCTS_AST *)p->elem(); if ( last==NULL ) last = t = u; else { last->setRight(u); last = u; } } return t; } // MR23 int SList::printMessage(FILE* pFile, const char* pFormat, ...) { va_list marker; va_start( marker, pFormat ); int iRet = vfprintf(pFile, pFormat, marker); va_end( marker ); return iRet; } cdrdao-cdrdao-f00afb2/specs/000077500000000000000000000000001511453746600160135ustar00rootroot00000000000000cdrdao-cdrdao-f00afb2/specs/cdrdao.fedora.spec.in000066400000000000000000000053551511453746600217770ustar00rootroot00000000000000Name: cdrdao Version: @PACKAGE_VERSION@ Release: 1 Epoch: 0 Summary: A Disk-At-Once (DAO) Audio CD writer and GUI editor Group: Applications/Multimedia License: GPL URL: http://cdrdao.sourceforge.net/ BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) Source0: http://dl.sourceforge.net/sourceforge/cdrdao/%{name}-%{version}.tar.gz %description Writes audio CD-Rs in disc-at-once (DAO) mode allowing control over pre-gaps (length down to 0, nonzero audio data) and sub-channel information like ISRC codes. All data that is written to the disc must be specified with a text file. Audio data may be in WAVE or raw format. %package -n gcdmaster Summary: The Gnome2/GTK2 GUI front-end to cdrdao Group: Applications/Multimedia Requires: %{name} = %{epoch}:%{version}-%{release} BuildRequires: gtkmm30-devel BuildRequires: libsigc++20-devel >= 0:1.2 BuildRequires: libvorbis-devel >= 0:1.0 BuildRequires: libao-devel >= 0:0.8 BuildRequires: libmad-devel BuildRequires: GConf2 Requires(pre): GConf2 Requires(post): GConf2 Requires(preun): GConf2 %description -n gcdmaster Gcdmaster is a GNOME2 GUI front-end to cdrdao that makes it easy to visualize and manipulate audio information before burning it onto CD. Its features include: cut/copy/paste of sound samples, track marks edition and silence insertion. %prep %setup -q %build %configure --disable-schemas-compile make %{?_smp_mflags} %install rm -rf $RPM_BUILD_ROOT export GCONF_DISABLE_MAKEFILE_SCHEMA_INSTALL=1 make install DESTDIR=$RPM_BUILD_ROOT find $RPM_BUILD_ROOT -type f -name "*.la" -exec rm -f {} ';' %clean rm -rf $RPM_BUILD_ROOT %pre %gconf_schema_prepare org.gnome.gcdmaster %post %gconf_schema_upgrade org.gnome.gcdmaster %preun %gconf_schema_remove org.gnome.gcdmaster %files %defattr(-, root, root, -) %doc AUTHORS COPYING CREDITS ChangeLog INSTALL README NEWS README.PlexDAE README.Win32 %{_bindir}/cdrdao %{_datadir}/cdrdao %{_bindir}/toc2* %{_bindir}/cue2toc %{_mandir}/man1/cdrdao* %{_mandir}/man1/cue2toc* %files -n gcdmaster %defattr(-, root, root, -) %{_bindir}/gcdmaster %{_datadir}/gcdmaster %{_datadir}/mime-info/gcdmaster* %{_datadir}/mime/packages/gcdmaster.xml %{_datadir}/applications/gcdmaster.desktop %{_datadir}/application-registry/gcdmaster.applications %{_datadir}/glib-2.0/schemas/org.gnome.gcdmaster.gschema.xml %{_datadir}/pixmaps/gcdmaster* %{_mandir}/man1/gcdmaster* %{_mandir}/man1/toc2* %changelog * Fri Apr 15 2022 Denis Leroy - 0:1.2.5-1 - gtk 3.0 port * Mon Jul 20 2004 Denis Leroy - 0:1.1.9pre1-0.fdr.1 - Added Ogg and libao dependencies - Switch to gtkmm 2.4 APIs * Mon Jun 26 2004 Denis Leroy - 0:1.1.9-0.fdr.1 - Initial FC2 spec cdrdao-cdrdao-f00afb2/testtocs/000077500000000000000000000000001511453746600165465ustar00rootroot00000000000000cdrdao-cdrdao-f00afb2/testtocs/3encodings.toc000066400000000000000000000020701511453746600213100ustar00rootroot00000000000000CD_DA CD_TEXT { LANGUAGE_MAP { 0: 9 1: 15 2: 105 } LANGUAGE 0 { ENCODING_ISO_8859_1 TITLE "The Water" PERFORMER "Jeanne Cherhal" } LANGUAGE 1 { TITLE "L'humiditĆ© de l'eau" PERFORMER "Jeannine FranƧaise" } LANGUAGE 2 { ENCODING_MS_JIS TITLE "湿った氓" PERFORMER "ē™½äŗŗć®ćƒ•ćƒ©ćƒ³ć‚¹äŗŗå„³ę€§" } } // Track 1 TRACK AUDIO NO COPY NO PRE_EMPHASIS TWO_CHANNEL_AUDIO ISRC "FR79W0600410" CD_TEXT { LANGUAGE 0 { TITLE "Heat Wave" PERFORMER "Jeanne Cherhal" } LANGUAGE 1 { TITLE "Canicule" PERFORMER "Jeannine FranƧaise" } LANGUAGE 2 { TITLE "熱波" PERFORMER "ē™½äŗŗć®ćƒ•ćƒ©ćƒ³ć‚¹äŗŗå„³ę€§" } } SILENCE 1:0:0 // Track 2 TRACK AUDIO NO COPY NO PRE_EMPHASIS TWO_CHANNEL_AUDIO ISRC "FR79W0600420" CD_TEXT { LANGUAGE 0 { TITLE "I am liquid" PERFORMER "Jeanne Cherhal" } LANGUAGE 1 { TITLE "Je suis liquidĆ©e" PERFORMER "Jeannine FranƧaise" } LANGUAGE 2 { TITLE "私は液体です" PERFORMER "ē™½äŗŗć®ćƒ•ćƒ©ćƒ³ć‚¹äŗŗå„³ę€§" } } SILENCE 1:0:0 cdrdao-cdrdao-f00afb2/testtocs/cdtext.toc000066400000000000000000000017301511453746600205510ustar00rootroot00000000000000CD_DA // global CD-TEXT data CD_TEXT { // Mapping from language number (0..7) used in 'LANGUAGE' statements // to language code. LANGUAGE_MAP { 0 : EN // 9 is the code for ENGLISH, // I don't know any other language code, yet } // Language number should always start with 0 LANGUAGE 0 { // Required fields - at least all CD-TEXT CDs I've seen so far have them. TITLE "CD Title" PERFORMER "Perf\\ormer" DISC_ID "XY12345" UPC_EAN "" // usually empty // Further possible items, all of them are optional ARRANGER "" SONGWRITER "" MESSAGE "" GENRE "" // I'm not sure if this should be really ascii data } } TRACK AUDIO // track specific CD-TEXT data CD_TEXT { LANGUAGE 0 { // if an item is defined for one track it should be defined for all tracks TITLE "Track \"Title\"" PERFORMER "Performer" ISRC "US-XX1-98-01234" ARRANGER "" SONGWRITER "" MESSAGE "" } } SILENCE 1:0:0 cdrdao-cdrdao-f00afb2/testtocs/data1.toc000066400000000000000000000000761511453746600202520ustar00rootroot00000000000000// Just a single MODE1 track. CD_ROM TRACK MODE1 ZERO 1:0:0 cdrdao-cdrdao-f00afb2/testtocs/data2.toc000066400000000000000000000001621511453746600202470ustar00rootroot00000000000000// MODE1 track followed by an AUDIO track CD_ROM TRACK MODE1 ZERO 1:0:0 TRACK AUDIO PREGAP 0:2:0 SILENCE 1:0:0 cdrdao-cdrdao-f00afb2/testtocs/data3.toc000066400000000000000000000003501511453746600202470ustar00rootroot00000000000000// AUDIO track followed by a MODE1 track. // Causes my PlexWriter to hang until a SCSI bus reset occus when the // first sector of the MODE1 track is written. CD_ROM TRACK AUDIO SILENCE 1:0:0 TRACK MODE1 PREGAP 0:2:0 ZERO 1:0:0 cdrdao-cdrdao-f00afb2/testtocs/data4.toc000066400000000000000000000003571511453746600202570ustar00rootroot00000000000000// MODE1 track followed by an AUDIO track followed by a MODE1 track. // This works on my PlexWriter in contrast to 'data3.toc'. CD_ROM TRACK MODE1 ZERO 1:0:0 TRACK AUDIO PREGAP 0:2:0 SILENCE 1:0:0 TRACK MODE1 PREGAP 0:2:0 ZERO 1:0:0 cdrdao-cdrdao-f00afb2/testtocs/data5.toc000066400000000000000000000001431511453746600202510ustar00rootroot00000000000000// XA disk // CD_ROM_XA TRACK MODE2_FORM2 ZERO 1:0:0 TRACK MODE2_FORM1 PREGAP 0:2:0 ZERO 2:0:0 cdrdao-cdrdao-f00afb2/testtocs/data6.toc000066400000000000000000000000631511453746600202530ustar00rootroot00000000000000// MODE2 track // CD_ROM TRACK MODE2 ZERO 1:0:0 cdrdao-cdrdao-f00afb2/testtocs/data7.toc000066400000000000000000000002361511453746600202560ustar00rootroot00000000000000// Video CD // CD_ROM_XA TRACK MODE1 // ISO filesystem ZERO 1:0:0 TRACK MODE2_FORM_MIX // XA track with form 1 and form 2 sectors PREGAP 0:2:0 ZERO 1:0:0 cdrdao-cdrdao-f00afb2/testtocs/gold/000077500000000000000000000000001511453746600174735ustar00rootroot00000000000000cdrdao-cdrdao-f00afb2/testtocs/gold/3encodings.showtoc000066400000000000000000000021161511453746600231370ustar00rootroot00000000000000TOC TYPE: CD_DA TITLE "The Water" PERFORMER "Jeanne Cherhal" TITLE "L'humiditĆ© de l'eau" PERFORMER "Jeannine FranƧaise" TITLE "湿った氓" PERFORMER "ē™½äŗŗć®ćƒ•ćƒ©ćƒ³ć‚¹äŗŗå„³ę€§" TRACK 1 Mode AUDIO: ISRC FR 79W 06 00410 COPY NOT PERMITTED NO PRE-EMPHASIS TWO CHANNEL AUDIO START 00:00:00( 0) END 01:00:00( 4500) TITLE "Heat Wave" PERFORMER "Jeanne Cherhal" TITLE "Canicule" PERFORMER "Jeannine FranƧaise" TITLE "熱波" PERFORMER "ē™½äŗŗć®ćƒ•ćƒ©ćƒ³ć‚¹äŗŗå„³ę€§" TRACK 2 Mode AUDIO: ISRC FR 79W 06 00420 COPY NOT PERMITTED NO PRE-EMPHASIS TWO CHANNEL AUDIO START 01:00:00( 4500) END 02:00:00( 9000) TITLE "I am liquid" PERFORMER "Jeanne Cherhal" TITLE "Je suis liquidĆ©e" PERFORMER "Jeannine FranƧaise" TITLE "私は液体です" PERFORMER "ē™½äŗŗć®ćƒ•ćƒ©ćƒ³ć‚¹äŗŗå„³ę€§" cdrdao-cdrdao-f00afb2/testtocs/gold/cdtext.showtoc000066400000000000000000000005741511453746600224040ustar00rootroot00000000000000TOC TYPE: CD_DA TITLE "CD Title" PERFORMER "Perf\\ormer" DISC_ID "XY12345" TRACK 1 Mode AUDIO: COPY NOT PERMITTED NO PRE-EMPHASIS TWO CHANNEL AUDIO START 00:00:00( 0) END 01:00:00( 4500) TITLE "Track \"Title\"" PERFORMER "Performer" UPC_EAN "US-XX1-98-01234" cdrdao-cdrdao-f00afb2/testtocs/gold/data1.showtoc000066400000000000000000000002101511453746600220660ustar00rootroot00000000000000TOC TYPE: CD_ROM TRACK 1 Mode MODE1: COPY NOT PERMITTED START 00:00:00( 0) END 01:00:00( 4500) cdrdao-cdrdao-f00afb2/testtocs/gold/data2.showtoc000066400000000000000000000005301511453746600220740ustar00rootroot00000000000000TOC TYPE: CD_ROM TRACK 1 Mode MODE1: COPY NOT PERMITTED START 00:00:00( 0) END 01:00:00( 4500) TRACK 2 Mode AUDIO: COPY NOT PERMITTED NO PRE-EMPHASIS TWO CHANNEL AUDIO PREGAP 00:02:00( 150) START 01:02:00( 4650) END 02:02:00( 9150) cdrdao-cdrdao-f00afb2/testtocs/gold/data3.showtoc000066400000000000000000000005301511453746600220750ustar00rootroot00000000000000TOC TYPE: CD_ROM TRACK 1 Mode AUDIO: COPY NOT PERMITTED NO PRE-EMPHASIS TWO CHANNEL AUDIO START 00:00:00( 0) END 01:00:00( 4500) TRACK 2 Mode MODE1: COPY NOT PERMITTED PREGAP 00:02:00( 150) START 01:02:00( 4650) END 02:02:00( 9150) cdrdao-cdrdao-f00afb2/testtocs/gold/data4.showtoc000066400000000000000000000007621511453746600221050ustar00rootroot00000000000000TOC TYPE: CD_ROM TRACK 1 Mode MODE1: COPY NOT PERMITTED START 00:00:00( 0) END 01:00:00( 4500) TRACK 2 Mode AUDIO: COPY NOT PERMITTED NO PRE-EMPHASIS TWO CHANNEL AUDIO PREGAP 00:02:00( 150) START 01:02:00( 4650) END 02:02:00( 9150) TRACK 3 Mode MODE1: COPY NOT PERMITTED PREGAP 00:02:00( 150) START 02:04:00( 9300) END 03:04:00( 13800) cdrdao-cdrdao-f00afb2/testtocs/gold/data5.showtoc000066400000000000000000000004611511453746600221020ustar00rootroot00000000000000TOC TYPE: CD_ROM_XA TRACK 1 Mode MODE2_FORM2: COPY NOT PERMITTED START 00:00:00( 0) END 01:00:00( 4500) TRACK 2 Mode MODE2_FORM1: COPY NOT PERMITTED PREGAP 00:02:00( 150) START 01:02:00( 4650) END 03:02:00( 13650) cdrdao-cdrdao-f00afb2/testtocs/gold/data6.showtoc000066400000000000000000000002101511453746600220730ustar00rootroot00000000000000TOC TYPE: CD_ROM TRACK 1 Mode MODE2: COPY NOT PERMITTED START 00:00:00( 0) END 01:00:00( 4500) cdrdao-cdrdao-f00afb2/testtocs/gold/data7.showtoc000066400000000000000000000004561511453746600221100ustar00rootroot00000000000000TOC TYPE: CD_ROM_XA TRACK 1 Mode MODE1: COPY NOT PERMITTED START 00:00:00( 0) END 01:00:00( 4500) TRACK 2 Mode MODE2_FORM_MIX: COPY NOT PERMITTED PREGAP 00:02:00( 150) START 01:02:00( 4650) END 02:02:00( 9150) cdrdao-cdrdao-f00afb2/testtocs/gold/mode1_rw.showtoc000066400000000000000000000002121511453746600226130ustar00rootroot00000000000000TOC TYPE: CD_DA TRACK 1 Mode MODE1 RW: COPY NOT PERMITTED START 00:00:00( 0) END 10:00:00( 45000) cdrdao-cdrdao-f00afb2/testtocs/gold/mode1_rw_raw.showtoc000066400000000000000000000002161511453746600234700ustar00rootroot00000000000000TOC TYPE: CD_DA TRACK 1 Mode MODE1 RW_RAW: COPY NOT PERMITTED START 00:00:00( 0) END 10:00:00( 45000) cdrdao-cdrdao-f00afb2/testtocs/gold/t1.showtoc000066400000000000000000000002751511453746600214330ustar00rootroot00000000000000TOC TYPE: CD_DA TRACK 1 Mode AUDIO: COPY NOT PERMITTED NO PRE-EMPHASIS TWO CHANNEL AUDIO START 00:00:00( 0) END 01:00:00( 4500) cdrdao-cdrdao-f00afb2/testtocs/gold/t2.showtoc000066400000000000000000000003371511453746600214330ustar00rootroot00000000000000TOC TYPE: CD_DA TRACK 1 Mode AUDIO: COPY NOT PERMITTED NO PRE-EMPHASIS TWO CHANNEL AUDIO PREGAP 00:10:00( 750) START 00:10:00( 750) END 01:00:00( 4500) cdrdao-cdrdao-f00afb2/testtocs/gold/t3.showtoc000066400000000000000000000005531511453746600214340ustar00rootroot00000000000000TOC TYPE: CD_DA TRACK 1 Mode AUDIO: COPY NOT PERMITTED NO PRE-EMPHASIS TWO CHANNEL AUDIO START 00:00:00( 0) END 01:00:00( 4500) TRACK 2 Mode AUDIO: COPY NOT PERMITTED NO PRE-EMPHASIS TWO CHANNEL AUDIO START 01:00:00( 4500) END 02:00:00( 9000) cdrdao-cdrdao-f00afb2/testtocs/gold/t4.showtoc000066400000000000000000000002671511453746600214370ustar00rootroot00000000000000TOC TYPE: CD_DA TRACK 1 Mode AUDIO: COPY PERMITTED PRE-EMPHASIS FOUR CHANNEL AUDIO START 00:00:00( 0) END 01:00:00( 4500) cdrdao-cdrdao-f00afb2/testtocs/gold/t5.showtoc000066400000000000000000000003331511453746600214320ustar00rootroot00000000000000TOC TYPE: CD_DA CATALOG NUMBER: 1234567890123 TRACK 1 Mode AUDIO: COPY NOT PERMITTED NO PRE-EMPHASIS TWO CHANNEL AUDIO START 00:00:00( 0) END 01:00:00( 4500) cdrdao-cdrdao-f00afb2/testtocs/gold/t6.showtoc000066400000000000000000000003341511453746600214340ustar00rootroot00000000000000TOC TYPE: CD_DA TRACK 1 Mode AUDIO: ISRC DE MUA 98 00001 COPY NOT PERMITTED NO PRE-EMPHASIS TWO CHANNEL AUDIO START 00:00:00( 0) END 01:00:00( 4500) cdrdao-cdrdao-f00afb2/testtocs/gold/t7.showtoc000066400000000000000000000006541511453746600214420ustar00rootroot00000000000000TOC TYPE: CD_DA TRACK 1 Mode AUDIO: COPY NOT PERMITTED NO PRE-EMPHASIS TWO CHANNEL AUDIO START 00:00:00( 0) END 01:00:00( 4500) TRACK 2 Mode AUDIO: ISRC DE MUA 98 00001 COPY NOT PERMITTED NO PRE-EMPHASIS TWO CHANNEL AUDIO PREGAP 00:05:00( 375) START 01:05:00( 4875) END 02:00:00( 9000) cdrdao-cdrdao-f00afb2/testtocs/gold/t8.showtoc000066400000000000000000000007251511453746600214420ustar00rootroot00000000000000TOC TYPE: CD_DA TRACK 1 Mode AUDIO: COPY NOT PERMITTED NO PRE-EMPHASIS TWO CHANNEL AUDIO START 00:00:00( 0) INDEX 2 01:00:00( 4500) INDEX 3 02:00:00( 9000) END 03:00:00( 13500) TRACK 2 Mode AUDIO: COPY NOT PERMITTED NO PRE-EMPHASIS TWO CHANNEL AUDIO PREGAP 00:05:00( 375) START 03:05:00( 13875) END 04:00:00( 18000) cdrdao-cdrdao-f00afb2/testtocs/gold/t9.showtoc000066400000000000000000000021601511453746600214360ustar00rootroot00000000000000TOC TYPE: CD_DA CATALOG NUMBER: 0724385356926 TRACK 1 Mode AUDIO: ISRC US EM3 96 00078 COPY PERMITTED NO PRE-EMPHASIS TWO CHANNEL AUDIO PREGAP 00:05:00( 375) START 00:05:00( 375) END 00:10:00( 750) TRACK 2 Mode AUDIO: ISRC US EM3 96 00079 COPY NOT PERMITTED NO PRE-EMPHASIS TWO CHANNEL AUDIO PREGAP 00:02:00( 150) START 00:12:00( 900) END 00:20:00( 1500) TRACK 3 Mode AUDIO: COPY PERMITTED NO PRE-EMPHASIS TWO CHANNEL AUDIO PREGAP 00:01:30( 105) START 00:21:30( 1605) END 00:30:00( 2250) TRACK 4 Mode AUDIO: COPY NOT PERMITTED NO PRE-EMPHASIS TWO CHANNEL AUDIO START 00:30:00( 2250) END 00:40:00( 3000) TRACK 5 Mode AUDIO: ISRC ED UMA 98 92346 COPY NOT PERMITTED NO PRE-EMPHASIS TWO CHANNEL AUDIO PREGAP 00:02:01( 151) START 00:42:01( 3151) END 00:46:01( 3451) cdrdao-cdrdao-f00afb2/testtocs/mode1_rw.toc000066400000000000000000000000421511453746600207660ustar00rootroot00000000000000CD_DA TRACK MODE1 RW ZERO 10:0:0 cdrdao-cdrdao-f00afb2/testtocs/mode1_rw_raw.toc000066400000000000000000000000461511453746600216430ustar00rootroot00000000000000CD_DA TRACK MODE1 RW_RAW ZERO 10:0:0 cdrdao-cdrdao-f00afb2/testtocs/pregap1.toc000066400000000000000000000001211511453746600206060ustar00rootroot00000000000000CD_DA TRACK AUDIO SILENCE 00:10:00 TRACK AUDIO START 00:02:00 SILENCE 00:10:00 cdrdao-cdrdao-f00afb2/testtocs/pregap2.toc000066400000000000000000000001221511453746600206100ustar00rootroot00000000000000CD_DA TRACK AUDIO SILENCE 00:10:00 TRACK AUDIO PREGAP 00:02:00 SILENCE 00:10:00 cdrdao-cdrdao-f00afb2/testtocs/t1.toc000066400000000000000000000001301511453746600175730ustar00rootroot00000000000000// simplest cue sheet TRACK AUDIO NO COPY // so that all CTL flags are 0 SILENCE 1:0:0 cdrdao-cdrdao-f00afb2/testtocs/t2.toc000066400000000000000000000002151511453746600176000ustar00rootroot00000000000000// additional pre-gap for track 1 TRACK AUDIO NO COPY // so that all CTL flags are 0 SILENCE 1:0:0 START 0:10:0 // 10 second pre-gap cdrdao-cdrdao-f00afb2/testtocs/t3.toc000066400000000000000000000002661511453746600176070ustar00rootroot00000000000000// simplest cue sheet for two tracks TRACK AUDIO NO COPY // so that all CTL flags are 0 SILENCE 1:0:0 TRACK AUDIO NO COPY // so that all CTL flags are 0 SILENCE 1:0:0 cdrdao-cdrdao-f00afb2/testtocs/t4.toc000066400000000000000000000001451511453746600176040ustar00rootroot00000000000000// non default CTL flag of track 1 TRACK AUDIO COPY PRE_EMPHASIS FOUR_CHANNEL_AUDIO SILENCE 1:0:0 cdrdao-cdrdao-f00afb2/testtocs/t5.toc000066400000000000000000000001241511453746600176020ustar00rootroot00000000000000// test catalog number CATALOG "1234567890123" TRACK AUDIO NO COPY SILENCE 1:0:0 cdrdao-cdrdao-f00afb2/testtocs/t6.toc000066400000000000000000000001121511453746600176000ustar00rootroot00000000000000// test ISRC code TRACK AUDIO NO COPY ISRC "DEMUA9800001" SILENCE 1:0:0 cdrdao-cdrdao-f00afb2/testtocs/t7.toc000066400000000000000000000002361511453746600176100ustar00rootroot00000000000000// check two tracks with pre-gap and ISRC TRACK AUDIO NO COPY SILENCE 1:0:0 TRACK AUDIO NO COPY ISRC "DEMUA9800001" SILENCE 1:0:0 START 0:5:0 // pre-gap cdrdao-cdrdao-f00afb2/testtocs/t8.toc000066400000000000000000000002231511453746600176050ustar00rootroot00000000000000// check index increments TRACK AUDIO NO COPY SILENCE 3:0:0 INDEX 1:0:0 INDEX 2:0:0 TRACK AUDIO NO COPY SILENCE 1:0:0 START 0:5:0 // pre-gap cdrdao-cdrdao-f00afb2/testtocs/t9.toc000066400000000000000000000005351511453746600176140ustar00rootroot00000000000000CD_DA // check multiple tracks CATALOG "0724385356926" TRACK AUDIO ISRC "USEM39600078" COPY SILENCE 0:10:0 START 0:5:0 TRACK AUDIO NO COPY ISRC "USEM39600079" SILENCE 0:10:0 START 0:2:0 TRACK AUDIO COPY SILENCE 0:10:0 START 0:1:30 TRACK AUDIO NO COPY START 0:0:0 SILENCE 0:10:0 TRACK AUDIO ISRC "EDUMA9892346" NO COPY SILENCE 0:6:1 START 0:2:1 cdrdao-cdrdao-f00afb2/testtocs/test000077500000000000000000000012011511453746600174450ustar00rootroot00000000000000#!/usr/bin/perl use strict; my $cdrdao = "../dao/cdrdao"; if (! -x $cdrdao) { print "Cannot find cdrdao executable\n"; exit 1; } opendir DIRH, "." || die "Could not opendir current dir"; my @all = readdir DIRH; closedir DIRh; foreach my $f (@all) { if ($f =~ /(.+)\.toc/) { my $basename = $1; if ( ! -r "gold/$basename.showtoc") { next; } my $testoutput = `$cdrdao show-toc -v 9 $f 2> /dev/null`; my $goldoutput = `cat gold/$basename.showtoc`; if ($testoutput eq $goldoutput) { print "\033[42mPASS\033[00m: ", $basename, "\n"; } else { print "\033[41mFAIL\033[00m: ", $basename, "\n"; } } } cdrdao-cdrdao-f00afb2/trackdb/000077500000000000000000000000001511453746600163105ustar00rootroot00000000000000cdrdao-cdrdao-f00afb2/trackdb/.cvsignore000066400000000000000000000002121511453746600203030ustar00rootroot00000000000000TocLexer.dlg TocLexerBase.cpp TocLexerBase.h TocParser.cpp TocParserGram.cpp TocParserGram.h TocParserTokens.h Makefile Makefile.in .deps cdrdao-cdrdao-f00afb2/trackdb/.gitignore000066400000000000000000000002331511453746600202760ustar00rootroot00000000000000AParser.cpp ATokenBuffer.cpp DLexerBase.cpp TocLexer.dlg TocLexerBase.cpp TocLexerBase.h TocParser.cpp TocParserGram.cpp TocParserGram.h TocParserTokens.h cdrdao-cdrdao-f00afb2/trackdb/CdTextContainer.cc000066400000000000000000000122541511453746600216610ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller * * 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. */ #include #include #include "CdTextContainer.h" #include "CdTextItem.h" struct LanguageCode { int code; const char *name; }; static LanguageCode LANGUAGE_CODES[] = { { 0x75, "Chinese" }, { 0x06, "Czech" }, { 0x07, "Danish" }, { 0x1d, "Dutch" }, { 0x09, "English" }, { 0x27, "Finnish" }, { 0x0f, "French" }, { 0x08, "German" }, { 0x70, "Greek" }, { 0x1b, "Hungarian" }, { 0x15, "Italian" }, { 0x69, "Japanese" }, { 0x65, "Korean" }, { 0x1e, "Norwegian" }, { 0x20, "Polish" }, { 0x21, "Portuguese" }, { 0x56, "Russian" }, { 0x26, "Slovene" }, { 0x0a, "Spanish" }, { 0x28, "Swedish" } }; static int NOF_LANGUAGE_CODES = sizeof(LANGUAGE_CODES) / sizeof(LanguageCode); CdTextContainer::CdTextContainer() : languages(8, -1), encodings(8, Util::Encoding::UNSET) { } void CdTextContainer::print(int isTrack, std::ostream &out, PrintParams& params) const { int i; int foundLanguageMapping; if (!items_.empty()) { int actBlockNr = (*items_.begin())->blockNr(); out << "CD_TEXT {\n"; if (!isTrack) { foundLanguageMapping = 0; for (i = 0; i < 8; i++) { if (languages[i] >= 0) { foundLanguageMapping = 1; break; } } if (foundLanguageMapping) { out << " LANGUAGE_MAP {\n"; for (i = 0; i < 8; i++) { if (languages[i] >= 0) out << " " << i << ": " << languages[i] << "\n"; } out << " }\n"; } } out << " LANGUAGE " << actBlockNr << " {\n"; for (const auto& item : items_) { if (item->blockNr() != actBlockNr) { actBlockNr = item->blockNr(); out << " }\n LANGUAGE " << actBlockNr << " {\n"; } out << " "; item->print(out, params); out << "\n"; } out << " }\n}\n"; } } void CdTextContainer::add(CdTextItem* item) { remove(item->packType(), item->blockNr()); items_.emplace_back(item); std::sort(items_.begin(), items_.end(), [](std::shared_ptr a, std::shared_ptr b) { if (a->blockNr() != b->blockNr()) return a->blockNr() < b->blockNr(); else return a->packType() < b->packType(); }); } void CdTextContainer::remove(CdTextItem::PackType type, int blockNr) { for (auto it = items_.begin(); it != items_.end(); it++) { if ((*it)->packType() == type && (*it)->blockNr() == blockNr) items_.erase(it--); } } bool CdTextContainer::existBlock(int blockNr) const { for (const auto& item : items_) if (item->blockNr() == blockNr) return true; return false; } const CdTextItem *CdTextContainer::getPack(int blockNr, CdTextItem::PackType type) const { for (const auto& item : items_) if (item->blockNr() == blockNr && item->packType() == type) return item.get(); return nullptr; } void CdTextContainer::language(int blockNr, int lang) { assert(blockNr >= 0 && blockNr <= 7); assert(lang >= -1 && lang <= 255); languages[blockNr] = lang; } int CdTextContainer::language(int blockNr) const { assert(blockNr >= 0 && blockNr <= 7); return languages[blockNr]; } void CdTextContainer::encoding(int blockNr, Util::Encoding enc) { assert(blockNr >= 0 && blockNr <= 7); encodings[blockNr] = enc; } void CdTextContainer::enforceEncoding(CdTextContainer* global) { if (global == this) { for (auto& e : encodings) if (e == Util::Encoding::UNSET) e = Util::Encoding::LATIN; } else { encodings = global->encodings; } for (auto i : items_) i->encoding(encodings[i->blockNr()]); } Util::Encoding CdTextContainer::encoding(int blockNr) const { assert(blockNr >= 0 && blockNr <= 7); return encodings[blockNr]; } const char *CdTextContainer::languageName(int lang) { int i; if (lang < 0) return "Undefined"; for (i = 0; i < NOF_LANGUAGE_CODES; i++) { if (lang == LANGUAGE_CODES[i].code) return LANGUAGE_CODES[i].name; } return "Unknown"; } cdrdao-cdrdao-f00afb2/trackdb/CdTextContainer.h000066400000000000000000000057631511453746600215320ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller * * 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. */ #ifndef __CDTEXTCONTAINER_H__ #define __CDTEXTCONTAINER_H__ #include #include #include #include #include "util.h" #include "CdTextItem.h" class CdTextContainer { public: CdTextContainer(); CdTextContainer(const CdTextContainer &) = default; long count() const { return items_.size(); } void add(CdTextItem*); void remove(CdTextItem::PackType, int blockNr); void print(int isTrack, std::ostream &, PrintParams&) const; // checks if a pack exists for given 'blockNr' (language) bool existBlock(int blockNr) const; // return pack for given 'blockNr' and pack type const CdTextItem *getPack(int blockNr, CdTextItem::PackType) const; // sets/returns language code for block nr void language(int blockNr, int lang); int language(int blockNr) const; // sets/returns character encoding for block nr void encoding(int blockNr, Util::Encoding enc); Util::Encoding encoding(int blockNr) const; void enforceEncoding(CdTextContainer* global); static const char *languageName(int lang); // Allow iteration over CD-TEXT items struct Iterator { using iterator_category = std::forward_iterator_tag; using difference_type = std::ptrdiff_t; using value_type = CdTextItem; using pointer = std::vector>::const_iterator; using reference = CdTextItem&; Iterator(pointer item) : m_ptr(item) {} friend bool operator==(const Iterator& a, const Iterator& b) { return a.m_ptr == b.m_ptr; } friend bool operator!=(const Iterator& a, const Iterator& b) { return a.m_ptr != b.m_ptr; } Iterator& operator++() { m_ptr++; return *this; } reference operator*() const { return *(*m_ptr); } pointer m_ptr; }; Iterator begin() const { return Iterator(items_.begin()); } Iterator end() const { return Iterator(items_.end()); } private: std::vector> items_; std::vector languages; // mapping from block nr to language code std::vector encodings; // mapping from block_nr to encoding void setDefaultLanguageMapping(); }; #endif cdrdao-cdrdao-f00afb2/trackdb/CdTextItem.cc000066400000000000000000000163171511453746600206410ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller * * 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. */ #include #include #include #include #include #include "CdTextItem.h" #include "CdTextContainer.h" #include "util.h" #include "log.h" CdTextItem::CdTextItem(PackType packType, int blockNr) { assert(blockNr >= 0 && blockNr <= 7); packType_ = packType; blockNr_ = blockNr; trackNr_ = 0; encoding_ = Util::Encoding::UNSET; } void CdTextItem::setData(const u8* buffer, size_t buffer_len) { data_.resize(buffer_len); memcpy(data_.data(), buffer, buffer_len); dataType_ = DataType::BINARY; } void CdTextItem::setRawText(const u8* buffer, size_t buffer_len) { setData(buffer, buffer_len); dataType_ = DataType::SBCC; updateEncoding(); } void CdTextItem::setRawText(const std::string& str) { data_.resize(str.size() + 1); auto writer = data_.begin(); for (const auto c : str) *writer++ = c; *writer++ = '\0'; dataType_ = DataType::SBCC; updateEncoding(); } void CdTextItem::setText(const char* utf8_text) { u8text = utf8_text; dataType_ = DataType::SBCC; updateEncoding(); } void CdTextItem::setTextFromToc(const char* text) { if (Util::isValidUTF8(text)) setText(text); else setRawText((u8*)text, strlen(text)); } void CdTextItem::setGenre(u8 genreCode1, u8 genreCode2, const char *description) { dataType_ = DataType::BINARY; data_.push_back(genreCode1); data_.push_back(genreCode2); if (description) { const char* ptr = description; while (*ptr) data_.push_back(*ptr++); data_.push_back(0); } } void CdTextItem::print(std::ostream &out, PrintParams& params) const { char buf[20]; out << packType2String(isTrackPack(), packType_); auto printchar = [&](unsigned char c, bool ascii_only) { if (c == '"') out << "\\\""; else if (c == '\\') out << "\\\\"; else if (ascii_only && (c < 32 || c >= 127)) out << "\\" << std::oct << std::setfill('0') << std::setw(3) << (unsigned int)c; else out << c; }; if (dataType() == DataType::SBCC) { out << " \""; if (params.no_utf8 || u8text.empty()) { for (auto c : data_) { if (c == '\0') break; printchar(c, true); } } else { for (auto c : u8text) printchar(c, false); } out << "\""; } else { long i = 0; out << " {"; for (auto c : data_) { if (i == 0) { snprintf(buf, sizeof(buf), "%2d", c); out << buf; } else { if (i % 12 == 0) out << ",\n "; else out << ", "; snprintf(buf, sizeof(buf), "%2d", c); out << buf; } i++; } out << "}"; } } int CdTextItem::operator==(const CdTextItem &obj) { return !(packType_ != obj.packType_ || blockNr_ != obj.blockNr_ || dataType_ != obj.dataType_ || data_ != obj.data_ || u8text != obj.u8text); } int CdTextItem::operator!=(const CdTextItem &obj) { return (*this == obj) ? 0 : 1; } const char *CdTextItem::packType2String(int isTrack, PackType packType) { const char *ret = "UNKNOWN"; switch (packType) { case PackType::TITLE: ret = "TITLE"; break; case PackType::PERFORMER: ret = "PERFORMER"; break; case PackType::SONGWRITER: ret = "SONGWRITER"; break; case PackType::COMPOSER: ret = "COMPOSER"; break; case PackType::ARRANGER: ret = "ARRANGER"; break; case PackType::MESSAGE: ret = "MESSAGE"; break; case PackType::DISK_ID: ret = "DISC_ID"; break; case PackType::GENRE: ret = "GENRE"; break; case PackType::TOC_INFO1: ret = "TOC_INFO1"; break; case PackType::TOC_INFO2: ret = "TOC_INFO2"; break; case PackType::RES1: ret = "RESERVED1"; break; case PackType::RES2: ret = "RESERVED2"; break; case PackType::RES3: ret = "RESERVED3"; break; case PackType::CLOSED: ret = "CLOSED"; break; case PackType::UPCEAN_ISRC: if (isTrack) ret = "ISRC"; else ret = "UPC_EAN"; break; case PackType::SIZE_INFO: ret = "SIZE_INFO"; break; } return ret; } CdTextItem::PackType CdTextItem::int2PackType(int i) { PackType t = PackType::TITLE; switch (i) { case 0x80: t = PackType::TITLE; break; case 0x81: t = PackType::PERFORMER; break; case 0x82: t = PackType::SONGWRITER; break; case 0x83: t = PackType::COMPOSER; break; case 0x84: t = PackType::ARRANGER; break; case 0x85: t = PackType::MESSAGE; break; case 0x86: t = PackType::DISK_ID; break; case 0x87: t = PackType::GENRE; break; case 0x88: t = PackType::TOC_INFO1; break; case 0x89: t = PackType::TOC_INFO2; break; case 0x8a: t = PackType::RES1; break; case 0x8b: t = PackType::RES2; break; case 0x8c: t = PackType::RES3; break; case 0x8d: t = PackType::CLOSED; break; case 0x8e: t = PackType::UPCEAN_ISRC; break; case 0x8f: t = PackType::SIZE_INFO; break; } return t; } int CdTextItem::isBinaryPack(PackType type) { int ret; switch (type) { case PackType::TOC_INFO1: case PackType::TOC_INFO2: case PackType::SIZE_INFO: case PackType::GENRE: ret = 1; break; default: ret = 0; break; } return ret; } void CdTextItem::encoding(Util::Encoding e) { encoding_ = e; updateEncoding(); } void CdTextItem::updateEncoding() { if (encoding_ != Util::Encoding::UNSET) { if (u8text.empty()) { u8text = Util::to_utf8(data(), dataLen(), encoding_); } else if (data_.empty()) { if (!Util::from_utf8(u8text, data_, encoding_)) log_message(-2, "CD-TEXT: Unable to encode \"%s\" into compatible format"); } } } cdrdao-cdrdao-f00afb2/trackdb/CdTextItem.h000066400000000000000000000067601511453746600205040ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller * * 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. */ #ifndef __CDTEXTITEM_H__ #define __CDTEXTITEM_H__ #include #include #include "util.h" class CdTextItem { public: enum class DataType { SBCC, DBCC, BINARY }; enum class PackType { TITLE = 0x80, PERFORMER = 0x81, SONGWRITER = 0x82, COMPOSER = 0x83, ARRANGER = 0x84, MESSAGE = 0x85, DISK_ID = 0x86, GENRE = 0x87, TOC_INFO1 = 0x88, TOC_INFO2 = 0x89, RES1 = 0x8a, RES2 = 0x8b, RES3 = 0x8c, CLOSED = 0x8d, UPCEAN_ISRC = 0x8e, SIZE_INFO = 0x8f }; CdTextItem(PackType packType, int blockNr); CdTextItem(const CdTextItem &) = default; void setData(const u8* buffer, size_t buffer_len); void setRawText(const u8* buffer, size_t buffer_len); void setRawText(const std::string &buffer); void setText(const char* utf8_text); void setTextFromToc(const char* text); void setGenre(u8 genreCode1, u8 genreCode2, const char *description); DataType dataType() const { return dataType_; } PackType packType() const { return packType_; } int blockNr() const { return blockNr_; } bool isTrackPack() const { return trackNr_ > 0; } void trackNr(int t) { trackNr_ = t; } int trackNr() const { return trackNr_; } void encoding(Util::Encoding e); Util::Encoding encoding() const { return encoding_; } const u8* data() const { return data_.data(); } size_t dataLen() const { return data_.size(); } const std::string& getText() const { return u8text; } void print(std::ostream &, PrintParams& params) const; int operator==(const CdTextItem &); int operator!=(const CdTextItem &); static const char *packType2String(int isTrack, PackType packType); static PackType int2PackType(int); static int isBinaryPack(PackType); private: DataType dataType_; PackType packType_; int blockNr_; // 0 ... 7 Util::Encoding encoding_; // We potentially keep two copies of the CD-TEXT: the data_ vector // represents what will actulally be burned onto the CD, and can // be either binary data or text data, encoded using one of the // officially supported CD encodings (i.e. not UTF-8). The u8text // string, is set, represents the desired textual encoding and // comes from either the TOC file or from the gcdmaster dialog // boxes. That UTF-8 string will get translated into ASCII or // ISO-8859-1 as best as possible. // Raw binary content, or pre-encoded text content std::vector data_; // UTF-8 text content. std::string u8text; // Info fields only, ignored during burn int trackNr_; void updateEncoding(); }; #endif cdrdao-cdrdao-f00afb2/trackdb/Cddb.cc000066400000000000000000000775021511453746600174660ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2000 Andreas Mueller * * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Toc.h" #include "CdTextItem.h" #include "util.h" #include "log.h" #include "Cddb.h" using std::string; using std::vector; #define CDDB_MAX_LINE_LEN 1024 #define CDDB_DEFAULT_PORT_CDDBP 8880 #define CDDB_DEFAULT_PORT_HTTP 80 static int getCode(const char *line, int code[3]); static unsigned int cddbSum(unsigned int n); static void convertEscapeSequences(const char *in, char *out); static int parseQueryResult(char *line, char *category, char *diskId, char *title); static RETSIGTYPE alarmHandler(int sig) { log_message(0, "ALARM"); #if RETSIGTYPE != void return 0; #endif } Cddb::Cddb(Toc *t) { toc_ = t; serverList_ = NULL; selectedServer_ = NULL; fd_ = -1; connected_ = 0; queryResults_ = NULL; cddbEntry_ = NULL; httpCmd_ = NULL; httpData_ = NULL; httpMode_ = 0; timeout_ = 20; } Cddb::~Cddb() { ServerList *snext; shutdown(); clearQueryResults(); clearCddbEntry(); delete[] httpCmd_; httpCmd_ = NULL; delete[] httpData_; httpData_ = NULL; while (serverList_ != NULL) { snext = serverList_->next; delete[] serverList_->server; serverList_->server = NULL; delete[] serverList_->httpCgiBin; serverList_->httpCgiBin = NULL; delete[] serverList_->httpProxyServer; serverList_->httpProxyServer = NULL; delete serverList_; serverList_ = snext; } } void Cddb::timeout(int t) { if (t > 0) timeout_ = t; } void Cddb::localCddbDirectory(const std::string& dir) { const char *homeDir; // replace ~/ by the path to the home directory as indicated by $HOME if (dir[0] == '~' && dir[1] == '/' && (homeDir = getenv("HOME")) != NULL) { localCddbDirectory_ = homeDir; localCddbDirectory_ += dir.substr(1); } else { localCddbDirectory_ = dir; } } void Cddb::appendQueryResult(const char *category, const char *diskId, const char *title, int exactMatch) { QueryResults *run, *ent; for (run = queryResults_; run != NULL && run->next != NULL; run = run->next) ; ent = new QueryResults; ent->category = strdupCC(category); ent->diskId = strdupCC(diskId); ent->title = strdupCC(title); ent->exactMatch = (exactMatch != 0) ? 1 : 0; ent->next = NULL; if (run == NULL) queryResults_ = ent; else run->next = ent; } void Cddb::clearQueryResults() { QueryResults *next; while (queryResults_ != NULL) { next = queryResults_->next; delete[] queryResults_->category; queryResults_->category = NULL; delete[] queryResults_->diskId; queryResults_->diskId = NULL; delete[] queryResults_->title; queryResults_->title = NULL; delete queryResults_; queryResults_ = next; } } void Cddb::clearCddbEntry() { int i; if (cddbEntry_ != NULL) { delete[] cddbEntry_->diskTitle; cddbEntry_->diskTitle = NULL; delete[] cddbEntry_->diskArtist; cddbEntry_->diskArtist = NULL; delete[] cddbEntry_->diskExt; cddbEntry_->diskExt = NULL; for (i = 0; i < cddbEntry_->ntracks; i++) { delete[] cddbEntry_->trackTitles[i]; cddbEntry_->trackTitles[i] = NULL; delete[] cddbEntry_->trackExt[i]; cddbEntry_->trackExt[i] = NULL; } delete[] cddbEntry_->trackTitles; cddbEntry_->trackTitles = NULL; delete[] cddbEntry_->trackExt; cddbEntry_->trackExt = NULL; delete cddbEntry_; cddbEntry_ = NULL; } } /* Appends a CDDB server name to the server list. Format of server strings: * * connect to , default cddbp port, use cddbp protocol * * : * connect to , port , use cddbp protocol * * : * connect to , default http port, use http protocol, * url: * * :: * connect to , port , use http protocol, url: * * ::: * connect to , default http port, use http protocol, * url: http://:/ * * :::: * connect to , port , use http protocol, * url: http://:/ */ void Cddb::appendServer(const char *s) { ServerList *run, *ent; char *name; char *port; char *httpCgiBin = NULL; char *httpProxyServer = NULL; char *httpProxyPort = NULL; unsigned short portNr = CDDB_DEFAULT_PORT_CDDBP; unsigned short httpProxyPortNr = CDDB_DEFAULT_PORT_HTTP; if (s == NULL || *s == 0) return; name = strdupCC(s); if ((port = strchr(name, ':')) != NULL) { *port = 0; port++; if (!isdigit(*port)) { httpCgiBin = port; port = NULL; portNr = CDDB_DEFAULT_PORT_HTTP; } else { if ((httpCgiBin = strchr(port, ':')) != NULL) { *httpCgiBin = 0; httpCgiBin++; } } if (httpCgiBin != NULL && (httpProxyServer = strchr(httpCgiBin, ':')) != NULL) { *httpProxyServer = 0; httpProxyServer++; } if (httpProxyServer != NULL && (httpProxyPort = strchr(httpProxyServer, ':')) != NULL) { *httpProxyPort = 0; httpProxyPort++; } } for (run = serverList_; run != NULL && run->next != NULL; run = run->next) { if (strcmp(run->server, name) == 0) { delete[] name; return; } } if (run != NULL && strcmp(run->server, s) == 0) { delete[] name; return; } if (port != NULL) portNr = (unsigned short)strtoul(port, NULL, 0); if (httpProxyPort != NULL) httpProxyPortNr = (unsigned short)strtoul(httpProxyPort, NULL, 0); ent = new ServerList; ent->server = name; ent->port = portNr; ent->httpCgiBin = (httpCgiBin != NULL) ? strdupCC(httpCgiBin) : NULL; if (httpProxyServer != NULL) { ent->httpProxyServer = strdupCC(httpProxyServer); ent->httpProxyPort = httpProxyPortNr; } else { ent->httpProxyServer = NULL; ent->httpProxyPort = 0; } ent->next = NULL; if (run == NULL) serverList_ = ent; else run->next = ent; } /* Tries to connect to a CDDB server. If no server was previously connected * (selectedServer_ == NULL) all servers from the server list will be tested * and the first successful connected server will be taken. * Return: 0: OK * 1: could not connect to any server */ int Cddb::openConnection() { ServerList *run; struct hostent *hostEnt; struct sockaddr_in sockAddr; const char *server; unsigned short port; struct sigaction newAlarmHandler; struct sigaction oldAlarmHandler; #ifndef HAVE_INET_ATON long inetAddr; #endif if (fd_ >= 0) // already connected return 0; memset(&newAlarmHandler, 0, sizeof(newAlarmHandler)); sigemptyset(&(newAlarmHandler.sa_mask)); #ifdef UNIXWARE newAlarmHandler.sa_handler = (void (*)()) alarmHandler; #else newAlarmHandler.sa_handler = alarmHandler; #endif if (sigaction(SIGALRM, &newAlarmHandler, &oldAlarmHandler) != 0) { log_message(-2, "CDDB: Cannot install alarm signal handler: %s", strerror(errno)); return 1; } alarm(0); for (run = (selectedServer_ != NULL) ? selectedServer_ : serverList_; run != NULL; run = (selectedServer_ != NULL) ? (ServerList*)0 : run->next) { server = run->server; port = run->port; if (run->httpCgiBin != NULL) { if (run->httpProxyServer != NULL) { server = run->httpProxyServer; port = run->httpProxyPort; log_message(1, "CDDB: Connecting to http://%s:%u%s via proxy %s:%u ...", run->server, run->port, run->httpCgiBin, server, port); } else { log_message(1, "CDDB: Connecting to http://%s:%u%s ...", server, port, run->httpCgiBin); } } else { log_message(1, "CDDB: Connecting to cddbp://%s:%u ...", server, port); } #ifdef HAVE_INET_ATON if (!inet_aton(server, &sockAddr.sin_addr)) { #else if ((inetAddr = (long)inet_addr(server)) == -1) { #endif if ((hostEnt = gethostbyname(server)) == NULL || hostEnt->h_addrtype != AF_INET) { alarm(0); log_message(-1, "CDDB: Cannot resolve hostname '%s' - skipping.", server); continue; } else { memcpy((char*) &sockAddr.sin_addr, hostEnt->h_addr, hostEnt->h_length); } } #ifndef HAVE_INET_ATON else { memcpy((char*)&sockAddr.sin_addr, (char*)&inetAddr, sizeof(inetAddr)); } #endif log_message(4, "CDDB: Hostname: %s -> IP: %s", server, inet_ntoa(sockAddr.sin_addr)); if ((fd_ = socket(AF_INET, SOCK_STREAM, 0)) < 0) { log_message(-2, "CDDB: Cannot create socket: %s", strerror(errno)); goto fail; } sockAddr.sin_family = AF_INET; sockAddr.sin_port = htons(port); alarm(timeout_); if (connect(fd_, (struct sockaddr*)&sockAddr, sizeof(sockAddr)) == 0) { alarm(0); log_message(1, "CDDB: Ok."); selectedServer_ = run; break; } else { alarm(0); log_message(-1, "CDDB: Failed to connect to '%s:%u: %s", server, port, strerror(errno)); closeConnection(); } } fail: connected_ = 0; alarm(0); if (sigaction(SIGALRM, &oldAlarmHandler, NULL) != 0) { log_message(-1, "CDDB: Cannot restore alarm signal handler: %s", strerror(errno)); } if (fd_ < 0) return 1; return 0; } /* Closes connection. */ void Cddb::closeConnection() { if (fd_ >= 0) { close(fd_); fd_ = -1; connected_ = 0; } } /* Create some strings that are used for all communications via the http * protocol. */ void Cddb::setupHttpData(const char *userName, const char *hostName, const char *clientName, const char *version) { delete[] httpCmd_; httpCmd_ = strdupvCC("&hello=", userName, "+", hostName, "+", clientName, "+", version, "&proto=6", NULL); delete[] httpData_; httpData_ = strdupvCC("User-Agent: ", clientName, "/", version, "\r\n", "Accept: text/plain\r\n", NULL); } /* Tries to connect to a server of the internal server list and performs the * the client-server handshake. * Return: 0: OK * 1: could not connect to any server * 2: handshake failed */ int Cddb::connectDb(const char *userName, const char *hostName, const char *clientName, const char *version) { int code[3]; const char *response; const char *cmdArgs[6]; if (connected_) return 0; if (openConnection() != 0) return 1; if (selectedServer_->httpCgiBin != NULL) { httpMode_ = 1; setupHttpData(userName, hostName, clientName, version); return 0; } response = getServerResponse(code); if (response == NULL) { log_message(-2, "CDDB: EOF while waiting for server greeting."); closeConnection(); return 2; } if (code[0] != 2) { log_message(-2, "CDDB: Connection to server denied: %s", response); return 2; } log_message(4, "CDDB: Server greeting: %s", response); connected_ = 1; cmdArgs[0] = "cddb"; cmdArgs[1] = "hello"; cmdArgs[2] = userName; cmdArgs[3] = hostName; cmdArgs[4] = clientName; cmdArgs[5] = version; if (sendCommand({"cddb", "hello", userName, hostName, clientName, version}) != 0) { log_message(-2, "CDDB: Failed to send handshake command."); return 2; } response = getServerResponse(code); if (response == NULL) { log_message(-2, "CDDB: EOF while waiting for server handshake response."); return 2; } if (code[0] != 2) { log_message(-2, "CDDB: Server handshake failed: %s", response); return 2; } log_message(4, "CDDB: Handshake response: %s", response); if (sendCommand({"proto", "6"}) != 0) { log_message(-2, "CDDB: Failed to send proto command."); return 2; } response = getServerResponse(code); log_message(4, "CDDB: Handshake response: %s", response); return 0; } /* Print query for current toc */ void Cddb::printDbQuery() { const char *cddbId; int ntracks; const Track *t; Msf start, end; long diskLength; ntracks = toc_->nofTracks(); cddbId = calcCddbId(); printf("%s ", cddbId); printf("%d ", ntracks); TrackIterator itr(toc_); for (t = itr.first(start, end); t != NULL; t = itr.next(start, end)) { long trackStart = start.lba() + 150; printf("%ld ", trackStart); } diskLength = toc_->length().min() * 60 + toc_->length().sec() + 2; printf("%ld\n", diskLength); } bool Cddb::printDbEntry() { if (!cddbEntry_) return false; if (cddbEntry_->diskArtist) printf("Artist: %s\n", cddbEntry_->diskArtist); if (cddbEntry_->diskTitle) printf("Title: %s\n", cddbEntry_->diskTitle); if (cddbEntry_->diskExt) printf("Ext: %s\n", cddbEntry_->diskExt); for (int i = 0; i < cddbEntry_->ntracks; i++) { printf("Track %02d: %s\n", i+1, cddbEntry_->trackTitles[i]); if (cddbEntry_->trackExt && cddbEntry_->trackExt[i]) printf("Trach %02d ext: %s\n", i+1, cddbEntry_->trackExt[i]); } return true; } /* Queries for entries that match the current 'toc_'. * 'results' will be filled with a list of matching diskIds/category/title * triples. 'results' will be NULL if no matching entry is found. * Return: 0: OK * 1: communication error occured */ int Cddb::queryDb(QueryResults **results) { const char *cddbId; vector args; const char *resp; char qtitle[CDDB_MAX_LINE_LEN]; char qcategory[CDDB_MAX_LINE_LEN]; char qdiskId[CDDB_MAX_LINE_LEN]; char respBuf[CDDB_MAX_LINE_LEN]; char *buf; int code[3]; int err = 0; int i; int ntracks; const Track *t; Msf start, end; // clear previous results clearQueryResults(); if (httpMode_) { if (openConnection() != 0) return 1; } ntracks = toc_->nofTracks(); args = { "cddb", "query" }; cddbId = calcCddbId(); args.push_back(cddbId); args.push_back(std::to_string(ntracks)); TrackIterator itr(toc_); for (t = itr.first(start, end); t != NULL; t = itr.next(start, end)) args.push_back(std::to_string(start.lba() + 150)); { long diskLength = toc_->length().min() * 60 + toc_->length().sec() + 2; args.push_back(std::to_string(diskLength)); } if (sendCommand(args) != 0) { log_message(-2, "CDDB: Failed to send QUERY command."); err = 1; goto fail; } if ((resp = getServerResponse(code)) == NULL) { log_message(-2, "CDDB: EOF while waiting for QUERY response."); err = 1; goto fail; } log_message(4, "CDDB: QUERY response: %s", resp); if (code[0] != 2) { log_message(-2, "CDDB: QUERY failed: %s", resp); err = 1; goto fail; } else { if (code[2] == 0) { // found exact match strcpy(respBuf, resp + 3); if (parseQueryResult(respBuf, qcategory, qdiskId, qtitle)) { appendQueryResult(qcategory, qdiskId, qtitle, 1); } else { log_message(-2, "CDDB: Received invalid QUERY response: %s", resp); err = 1; goto fail; } } else if(code[2] == 1) { // found inexact matches while ((resp = readLine()) != NULL && strcmp(resp, ".") != 0) { strcpy(respBuf, resp); log_message(4, "CDDB: Query data: %s", resp); if (parseQueryResult(respBuf, qcategory, qdiskId, qtitle)) { appendQueryResult(qcategory, qdiskId, qtitle, 0); } else { log_message(-2, "CDDB: Received invalid QUERY data: %s", resp); err = 1; goto fail; } } if (resp == NULL) { log_message(-2, "CDDB: EOF while reading QUERY data."); err = 1; goto fail; } } else { // found no match } } fail: if (httpMode_) closeConnection(); *results = queryResults_; return err; } /* Reads CDDB entry for specified category and disk id. 'entry' will be * set to the stucture containing the record data. * Return: 0: OK * 1: communication error or could not retrieve CDDB entry */ int Cddb::readDb(const char *category, const char *diskId, CddbEntry **entry) { int code[3]; const char *resp; int localRecordFd = -1; clearCddbEntry(); if (httpMode_) { if (openConnection() != 0) return 1; } if (sendCommand({"cddb", "read", category, diskId}) != 0) { log_message(-2, "CDDB: Failed to send READ command."); goto fail; } if ((resp = getServerResponse(code)) == NULL) { log_message(-2, "CDDB: EOF while waiting for READ response."); goto fail; } log_message(4, "CDDB: READ response: %s", resp); if (code[0] == 2) { if ((localRecordFd = createLocalCddbFile(category, diskId)) == -2) { log_message(-1, "Existing local CDDB record for %s/%s will not be overwritten.", category, diskId); } if (readDbEntry(localRecordFd) != 0) { log_message(-2, "CDDB: Received invalid database entry."); goto fail; } } else { log_message(-2, "CDDB: READ failed: %s", resp); goto fail; } *entry = cddbEntry_; if (httpMode_) closeConnection(); if (localRecordFd >= 0) close(localRecordFd); return 0; fail: if (httpMode_) closeConnection(); if (localRecordFd >= 0) close(localRecordFd); *entry = NULL; return 1; } /* Shuts down the connection to the CDDB server. */ void Cddb::shutdown() { const char *resp; int code[3]; if (fd_ < 0) return; if (!connected_) { closeConnection(); return; } if (sendCommand({"quit"}) == 0) { if ((resp = getServerResponse(code)) == NULL) { log_message(-1, "CDDB: EOF while waiting for QUIT response."); } else { log_message(4, "CDDB: QUIT response: %s", resp); } } else { log_message(-1, "CDDB: Failed to send QUIT command."); } closeConnection(); } /* Filter characters of given string so that it is suitable as CD-TEXT data. */ static char *cdTextFilter(char *s) { char *p = s; while (*p != 0) { if (*p == '\n' || *p == '\t') *p = ' '; p++; } return s; } /* Adds the data of the retrieved CDDB record stored in 'cddbEntry_' to * the given toc as CD-TEXT data. * Return: 1: CD-TEXT data was added * 0: toc was not modified */ int Cddb::addAsCdText(Toc *toc) { int havePerformer = 0; int haveTitle = 0; int haveMessage = 0; int trun; CdTextItem *item; if (cddbEntry_ == NULL) return 0; if (cddbEntry_->diskTitle != NULL) haveTitle = 1; if (cddbEntry_->diskArtist != NULL) havePerformer = 1; if (cddbEntry_->diskExt != NULL) haveMessage = 1; for (trun = 0; trun < cddbEntry_->ntracks; trun++) { if (cddbEntry_->trackTitles[trun] != NULL) haveTitle = 1; if (cddbEntry_->trackExt[trun] != NULL) haveMessage = 1; } if (!haveTitle && !havePerformer && !haveMessage) return 0; toc->cdTextLanguage(0, 9); if (haveTitle) { item = createItem(CdTextItem::PackType::TITLE, (cddbEntry_->diskTitle != NULL) ? cdTextFilter(cddbEntry_->diskTitle) : ""); toc->addCdTextItem(0, item); } if (havePerformer) { item = createItem(CdTextItem::PackType::PERFORMER, (cddbEntry_->diskArtist != NULL) ? cdTextFilter(cddbEntry_->diskArtist) : ""); toc->addCdTextItem(0, item); } if (haveMessage) { item = createItem(CdTextItem::PackType::MESSAGE, (cddbEntry_->diskExt != NULL) ? cdTextFilter(cddbEntry_->diskExt) : ""); toc->addCdTextItem(0, item); } for (trun = 0; trun < toc->nofTracks(); trun++) { item = nullptr; if (haveTitle) { item = createItem(CdTextItem::PackType::TITLE, (trun < cddbEntry_->ntracks && cddbEntry_->trackTitles[trun] != NULL) ? cdTextFilter(cddbEntry_->trackTitles[trun]) : ""); toc->addCdTextItem(trun + 1, item); } if (havePerformer) { item = createItem(CdTextItem::PackType::PERFORMER, (cddbEntry_->diskArtist != NULL) ? cdTextFilter(cddbEntry_->diskArtist) : ""); toc->addCdTextItem(trun + 1, item); } if (haveMessage) { item = createItem(CdTextItem::PackType::MESSAGE, (trun < cddbEntry_->ntracks && cddbEntry_->trackExt[trun] != NULL) ? cdTextFilter(cddbEntry_->trackExt[trun]) : ""); toc->addCdTextItem(trun + 1, item); } } return 1; } /* Reads a line (until '\n') from 'fd_'. Checks for timeouts. */ const char *Cddb::readLine() { static char buf[CDDB_MAX_LINE_LEN]; int pos = 0; struct timeval tv; fd_set readFds; int ret; char *s; int characterRead = 0; while (pos < CDDB_MAX_LINE_LEN) { FD_ZERO(&readFds); FD_SET(fd_, &readFds); tv.tv_sec = timeout_; tv.tv_usec = 0; ret = select(fd_ + 1, &readFds, NULL, NULL, &tv); if (ret == 0) { log_message(-2, "CDDB: Timeout while reading data."); return NULL; } if (ret < 0) { log_message(-2, "CDDB: Error while waiting for data: %s", strerror(errno)); return NULL; } ret = read(fd_, &(buf[pos]), 1); if (ret == 0) { // end of file break; } if (ret < 0) { log_message(-2, "CDDB: Error while reading data: %s", strerror(errno)); return NULL; } characterRead = 1; if (buf[pos] == '\n') break; pos++; } if (pos >= CDDB_MAX_LINE_LEN) buf[CDDB_MAX_LINE_LEN - 1] = 0; else buf[pos] = 0; if (buf[0] == 0 && !characterRead) { // end of file return NULL; } // skip leading blanks for (s = buf; *s != 0 && isspace(*s); s++) ; // skip trailing blanks for (pos = strlen(s) - 1; pos >= 0 && isspace(s[pos]); pos--) s[pos] = 0; log_message(5, "CDDB: Data read: %s", s); return s; } /* Checks if 'line' contains a cddb server status and sets 'code' to the * server code. * Return: 0: 'line' is not a cddb server status line * 1: 'line' is a cddb server status line, 'code' contains valid data */ static int getCode(const char *line, int code[3]) { if (isdigit(line[0]) && isdigit(line[1]) && isdigit(line[2]) && isspace(line[3])) { code[0] = line[0] - '0'; code[1] = line[1] - '0'; code[2] = line[2] - '0'; return 1; } return 0; } /* Reads lines from 'fd_' until a valid server status line is encountered. * 'code' is set to the server status code on success. * Return: server status line or 'NULL' on timeout or communication error */ const char *Cddb::getServerResponse(int code[3]) { const char *line; while ((line = readLine()) != NULL && !getCode(line, code)) ; return line; } /* Sends command in 'args' to 'fd_'. cdbbp and http protocols are handled. * Return: 0: OK * 1: communication error occured. */ int Cddb::sendCommand(const vector& args) { int err = 0; string cmd; for (const auto& s : args) { if (!cmd.empty()) cmd += (httpMode_ ? "+" : " "); cmd += s; } if (httpMode_) { std::ostringstream ss; if (selectedServer_->httpProxyServer != NULL) { ss << "GET http://" << selectedServer_->server; ss << selectedServer_->port << selectedServer_->httpCgiBin; ss << "?cmd=" << cmd << " HTTP/1.0\r\n"; ss << "Host: " << selectedServer_->server << "\r\n"; ss << httpData_ << "\r\n"; } else { ss << "GET " << selectedServer_->httpCgiBin << "?cmd=" << cmd << " HTTP/1.0\r\n" << "Host: " << selectedServer_->server << "\r\n" << httpData_ << "\r\n"; } cmd = ss.str(); log_message(4, "CDDB: Sending command '%s'...", cmd.c_str()); } else { log_message(4, "CDDB: Sending command '%s'...", cmd.c_str()); cmd += "\n"; } auto ret = ::write(fd_, cmd.c_str(), cmd.size()); if (ret != cmd.size()) { log_message(-2, "CDDB: Failed to send command '%s': %s", cmd.c_str(), strerror(errno)); err = 1; goto fail; } log_message(4, "CDDB: Ok."); fail: return err; } static unsigned int cddbSum(unsigned int n) { unsigned int ret; ret = 0; while (n > 0) { ret += (n % 10); n /= 10; } return ret; } const char *Cddb::calcCddbId() { const Track *t; Msf start, end; unsigned int n = 0; unsigned int o = 0; int tcount = 0; static char buf[20]; unsigned long id; TrackIterator itr(toc_); for (t = itr.first(start, end); t != NULL; t = itr.next(start, end)) { if (t->type() == TrackData::AUDIO) { n += cddbSum(start.min() * 60 + start.sec() + 2/* gap offset */); o = end.min() * 60 + end.sec(); tcount++; } } id = (n % 0xff) << 24 | o << 8 | tcount; snprintf(buf, sizeof(buf), "%08lx", id); return buf; } static void convertEscapeSequences(const char *in, char *out) { while (*in != 0) { if (*in == '\\') { switch (*(in + 1)) { case 'n': *out++ = '\n'; in++; break; case 't': *out++ = '\t'; in++; break; case '\\': *out++ = '\\'; in++; break; default: *out++ = '\\'; break; } } else { *out++ = *in; } in++; } *out = 0; } /* Retrieves the category, disk ID and title from a query response string. * The provided strings 'category', 'diskId' and 'title' must point to * existing buffers with at least the same length as 'line'. * Return: 1 if 'line' was successfully parsed, else 0 */ static int parseQueryResult(char *line, char *category, char *diskId, char *title) { const char *sep = " \t"; char *p; if ((p = strtok(line, sep)) != NULL) { strcpy(category, p); if ((p = strtok(NULL, sep)) != NULL) { strcpy(diskId, p); if ((p = strtok(NULL, "")) != NULL) { // remove leading white space while (*p != 0 && isspace(*p)) p++; convertEscapeSequences(p, title); // remove newline from title string if ((p = strchr(title, '\n')) != NULL) *p = 0; return 1; } } } return 0; } /* Reads a CDDB record from 'fd_' and fills 'cddbEntry_' with the required * data. * Return: 0: OK * 1: communication error occured */ int Cddb::readDbEntry(int localRecordFd) { const char *resp; char buf[CDDB_MAX_LINE_LEN]; char *line; char *p, *s; char *val; int ntracks = toc_->nofTracks(); int i, trackNr; cddbEntry_ = new CddbEntry; cddbEntry_->diskTitle = NULL; cddbEntry_->diskArtist = NULL; cddbEntry_->diskExt = NULL; cddbEntry_->ntracks = ntracks; cddbEntry_->trackTitles = new char*[ntracks]; cddbEntry_->trackExt = new char*[ntracks]; for (i = 0; i < ntracks; i++) { cddbEntry_->trackTitles[i] = NULL; cddbEntry_->trackExt[i] = NULL; } while ((resp = readLine()) != NULL && strcmp(resp, ".") != 0) { log_message(4, "CDDB: READ data: %s", resp); if (localRecordFd >= 0) { // save to local CDDB record file fullWrite(localRecordFd, resp, strlen(resp)); fullWrite(localRecordFd, "\n", 1); } convertEscapeSequences(resp, buf); // remove comments //if ((p = strchr(buf, '#')) != NULL) // *p = 0; if (buf[0] == '#') buf[0] = 0; // xxam! // remove leading blanks for (line = buf; *line != 0 && isspace(*line); line++) ; if ((val = strchr(line, '=')) != NULL) { *val = 0; val++; if (strcmp(line, "DTITLE") == 0) { if (*val != 0) { if (cddbEntry_->diskArtist == NULL) { cddbEntry_->diskArtist = strdupCC(val); } else { s = strdup3CC(cddbEntry_->diskArtist, val, NULL); delete[] cddbEntry_->diskArtist; cddbEntry_->diskArtist = s; } } } else if (strcmp(line, "EXTD") == 0) { if (*val != 0) { if (cddbEntry_->diskExt == NULL) { cddbEntry_->diskExt = strdupCC(val); } else { s = strdup3CC(cddbEntry_->diskExt, val, NULL); delete[] cddbEntry_->diskExt; cddbEntry_->diskExt = s; } } } else if (strncmp(line, "TTITLE", 6) == 0) { if (*val != 0) { trackNr = atoi(line + 6); if (trackNr >= 0 && trackNr < ntracks) { if (cddbEntry_->trackTitles[trackNr] == NULL) { cddbEntry_->trackTitles[trackNr] = strdupCC(val); } else { s = strdup3CC(cddbEntry_->trackTitles[trackNr], val, NULL); delete[] cddbEntry_->trackTitles[trackNr]; cddbEntry_->trackTitles[trackNr] = s; } } } } else if (strncmp(line, "EXTT", 4) == 0) { if (*val != 0) { trackNr = atoi(line + 4); if (trackNr >= 0 && trackNr < ntracks) { if (cddbEntry_->trackExt[trackNr] == NULL) { cddbEntry_->trackExt[trackNr] = strdupCC(val); } else { s = strdup3CC(cddbEntry_->trackExt[trackNr], val, NULL); delete[] cddbEntry_->trackExt[trackNr]; cddbEntry_->trackExt[trackNr] = s; } } } } } } if (resp == NULL) { log_message(-2, "CDDB: EOF while reading database entry."); goto fail; } if (cddbEntry_->diskArtist != NULL) { if ((p = strchr(cddbEntry_->diskArtist, '/')) != NULL) { *p = 0; // remove leading white space of disk title for (s = p + 1; *s != 0 && isspace(*s); s++) ; cddbEntry_->diskTitle = strdupCC(s); // remove trailing white space of disk artist for (p = p - 1; p >= cddbEntry_->diskArtist && isspace(*p); p--) *p = 0; } else { cddbEntry_->diskTitle = strdupCC(cddbEntry_->diskArtist); } } return 0; fail: clearCddbEntry(); return 1; } int Cddb::createLocalCddbFile(const char *category, const char *diskId) { std::string categoryDir; std::string recordFile; struct stat sbuf; int ret; int fd = -1; if (localCddbDirectory_.empty()) return -1; ret = stat(localCddbDirectory_.c_str(), &sbuf); if (ret != 0 && errno == ENOENT) { log_message(-1, "CDDB: Local CDDB directory \"%s\" does not exist.", localCddbDirectory_.c_str()); return -1; } else if (ret == 0) { if (!S_ISDIR(sbuf.st_mode)) { log_message(-2, "CDDB: \"%s\" is not a directory.", localCddbDirectory_.c_str()); return -1; } } else { log_message(-2, "CDDB: stat of \"%s\" failed: %s", localCddbDirectory_.c_str(), strerror(errno)); return -1; } categoryDir = localCddbDirectory_ + "/" + category; ret = stat(categoryDir.c_str(), &sbuf); if (ret != 0 && errno == ENOENT) { if (mkdir(categoryDir.c_str(), 0777) != 0) { log_message(-2, "CDDB: Cannot create directory \"%s\": %s", categoryDir.c_str(), strerror(errno)); goto fail; } } else if (ret == 0) { if (!S_ISDIR(sbuf.st_mode)) { log_message(-2, "CDDB: \"%s\" is not a directory.", categoryDir.c_str()); } } else { log_message(-2, "CDDB: stat of \"%s\" failed: %s", categoryDir.c_str(), strerror(errno)); goto fail; } recordFile = categoryDir + "/" + diskId; ret = stat(recordFile.c_str(), &sbuf); if (ret != 0 && errno == ENOENT) { if ((fd = open(recordFile.c_str(), O_WRONLY|O_CREAT, 0666)) < 0) { log_message(-2, "CDDB: Cannot create CDDB record file \"%s\": %s", recordFile.c_str(), strerror(errno)); fd = -1; goto fail; } } else if (ret == 0) { fd = -2; goto fail; } else { log_message(-2, "CDDB: stat of \"%s\" failed: %s", categoryDir.c_str(), strerror(errno)); goto fail; } fail: return fd; } CdTextItem* Cddb::createItem(CdTextItem::PackType ptype, const char* text) { auto item = new CdTextItem(ptype, 0); item->setText(text); return item; } cdrdao-cdrdao-f00afb2/trackdb/Cddb.h000066400000000000000000000060131511453746600173150ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2000 Andreas Mueller * * 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. */ /* * Retrieve CDDB data for a 'Toc' */ #ifndef __CDDB_H__ #define __CDDB_H__ #include #include class Toc; class Cddb { public: struct QueryResults { char *category; char *diskId; char *title; int exactMatch; struct QueryResults *next; }; struct CddbEntry { char *diskTitle; char *diskArtist; char *diskExt; int ntracks; char **trackTitles; char **trackExt; }; Cddb(Toc *); ~Cddb(); void localCddbDirectory(const std::string&); void appendServer(const char *s); void timeout(int); int connectDb(const char *userName, const char *hostName, const char *clientName, const char *version); int queryDb(QueryResults **); int readDb(const char *category, const char *diskId, CddbEntry **); int addAsCdText(Toc *toc); void printDbQuery(); // Print the found CDDB entry to stdout. Returns false if no entry // available. bool printDbEntry(); private: struct ServerList { char *server; unsigned short port; char *httpCgiBin; char *httpProxyServer; unsigned short httpProxyPort; struct ServerList *next; }; Toc *toc_; ServerList *serverList_; // list of CDDB servers ServerList *selectedServer_; std::string localCddbDirectory_; int fd_; // file descriptor for connection to CDDB server int connected_; // 1 if connection to CDDB server was established, else 0 int timeout_; // timeout in seconds int httpMode_; char *httpCmd_; char *httpData_; QueryResults *queryResults_; CddbEntry *cddbEntry_; static CdTextItem* createItem(CdTextItem::PackType, const char*); int openConnection(); void closeConnection(); void setupHttpData(const char *userName, const char *hostName, const char *clientName, const char *version); void appendQueryResult(const char *category, const char *diskId, const char *title, int exactMatch); void clearQueryResults(); void clearCddbEntry(); const char *readLine(); const char *getServerResponse(int code[3]); int sendCommand(const std::vector& cmds); const char *calcCddbId(); int readDbEntry(int); void shutdown(); int createLocalCddbFile(const char *category, const char *diskId); }; #endif cdrdao-cdrdao-f00afb2/trackdb/Cue2Toc.cc000066400000000000000000000734571511453746600201030ustar00rootroot00000000000000/* cue2toc.c - conversion routines * Copyright (C) 2004 Matthias Czapla * * This file is part of cue2toc. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include "Cue2Toc.h" #include "TrackData.h" #define TCBUFLEN 9 /* Buffer length for timecode strings (HH:MM:SS) */ #define MAXCMDLEN 10 /* Longest command (currently SONGWRITER) */ long tc2fr(const char *); int fr2tc(char *, long fr); /* * Input is divied into tokens that are separated by whitespace, horizantal * tabulator, line feed and carriage return. Tokens can be either commands * from a fixed set or strings. If a string is to contain any of the token * delimiting characters it must be enclosed in double quotes. */ static const char token_delimiter[] = { ' ', '\t', '\n', '\r' }; /* Return true if c is one of token_delimiter */ static int isdelim(int c) { int i; int n = sizeof(token_delimiter); for (i = 0; i < n; i++) if (c == token_delimiter[i]) return 1; return 0; } /* Used as return type for get_command and index into cmds */ enum command { REM, CATALOG, CDTEXTFILE, FILECMD, PERFORMER, SONGWRITER, TITLE, TRACK, FLAGS, DCP, FOURCH, PRE, SCMS, ISRC, PREGAP, INDEX, POSTGAP, BINARY, MOTOROLA, AIFF, WAVE, MP3, OGG, UNKNOWN, END }; /* Except the last two these are the valid CUE commands */ char cmds[][MAXCMDLEN + 1] = { "REM", "CATALOG", "CDTEXTFILE", "FILE", "PERFORMER", "SONGWRITER", "TITLE", "TRACK", "FLAGS", "DCP", "4CH", "PRE", "SCMS", "ISRC", "PREGAP", "INDEX", "POSTGAP", "BINARY", "MOTOROLA", "AIFF", "WAVE", "MP3", "OGG", "UNKNOWN", "END" }; /* These are for error messages */ static const char *fname = "stdin"; static long line; /* current line number */ static long tokenstart; /* line where last token started */ /* To generate meaningful error messages in check_once */ enum scope { CUESHEET, GLOBAL, ONETRACK }; /* Fatal error while processing input file */ static void err_fail(const char *s) { fprintf(stderr, "%s:%ld: %s\n", fname, tokenstart, s); exit(EXIT_FAILURE); } /* Fatal error */ static void err_fail2(const char *s) { fprintf(stderr, "%s\n", s); exit(EXIT_FAILURE); } /* EOF while expecting more */ static void err_earlyend() { fprintf(stderr, "%s:%ld: Premature end of file\n", fname, line); exit(EXIT_FAILURE); } /* Warning. Keep on going. */ static void err_warn(const char *s) { fprintf(stderr, "%s:%ld: Warning, %s\n", fname, tokenstart, s); } /* Get next command from file */ static enum command get_command(FILE *f) { int c; char buf[MAXCMDLEN + 1]; int i = 0; /* eat whitespace */ do { c = getc(f); if (c == '\n') line++; } while (isdelim(c)); if (c == EOF) return END; tokenstart = line; /* get command, transform to upper case */ do { buf[i++] = toupper(c); c = getc(f); } while (!isdelim(c) && c!= EOF && i < MAXCMDLEN); if (!isdelim(c)) return UNKNOWN; /* command longer than MAXCMDLEN */ if (c == EOF) return END; if (c == '\n') line++; buf[i] = '\0'; if (strcmp(buf, cmds[REM]) == 0) return REM; else if (strcmp(buf, cmds[CATALOG]) == 0) return CATALOG; else if (strcmp(buf, cmds[CDTEXTFILE]) == 0) return CDTEXTFILE; else if (strcmp(buf, cmds[FILECMD]) == 0) return FILECMD; else if (strcmp(buf, cmds[PERFORMER]) == 0) return PERFORMER; else if (strcmp(buf, cmds[SONGWRITER]) == 0) return SONGWRITER; else if (strcmp(buf, cmds[TITLE]) == 0) return TITLE; else if (strcmp(buf, cmds[TRACK]) == 0) return TRACK; else if (strcmp(buf, cmds[FLAGS]) == 0) return FLAGS; else if (strcmp(buf, cmds[DCP]) == 0) return DCP; else if (strcmp(buf, cmds[FOURCH]) == 0) return FOURCH; else if (strcmp(buf, cmds[PRE]) == 0) return PRE; else if (strcmp(buf, cmds[SCMS]) == 0) return SCMS; else if (strcmp(buf, cmds[ISRC]) == 0) return ISRC; else if (strcmp(buf, cmds[PREGAP]) == 0) return PREGAP; else if (strcmp(buf, cmds[INDEX]) == 0) return INDEX; else if (strcmp(buf, cmds[POSTGAP]) == 0) return POSTGAP; else if (strcmp(buf, cmds[BINARY]) == 0) return BINARY; else if (strcmp(buf, cmds[MOTOROLA]) == 0) return MOTOROLA; else if (strcmp(buf, cmds[AIFF]) == 0) return AIFF; else if (strcmp(buf, cmds[WAVE]) == 0) return WAVE; else if (strcmp(buf, cmds[MP3]) == 0) return MP3; else if (strcmp(buf, cmds[OGG]) == 0) return OGG; else return UNKNOWN; } /* Skip leading token delimiters then read at most n chars from f into s. * Put terminating Null at the end of s. This implies that s must be * really n + 1. Return number of characters written to s. The only case to * return zero is on EOF before any character was read. * Exit the program indicating failure if string is longer than n. */ static size_t get_string(FILE *f, char *s, size_t n) { int c; size_t i = 0; /* eat whitespace */ do { c = getc(f); if (c == '\n') line++; } while (isdelim(c)); if (c == EOF) return 0; tokenstart = line; if (c == '\"') { c = getc(f); if (c == '\n') line++; while (c != '\"' && c != EOF && i < n) { s[i++] = c; c = getc(f); if (c == '\n') line++; } if (i == n && c != '\"' && c != EOF) err_fail("String too long"); } else { while (!isdelim(c) && c != EOF && i < n) { s[i++] = c; c = getc(f); } if (i == n && !isdelim(c) && c != EOF) err_fail("String too long"); } if (i == 0) err_fail("Empty string"); if (c == '\n') line++; s[i] = '\0'; return i; } /* Return track mode */ static TrackData::Mode get_track_mode(FILE *f) { char buf[] = "MODE1/2048"; char *pbuf = buf; if (get_string(f, buf, sizeof(buf) - 1) < 1) err_fail("Illegal track mode"); /* transform to upper case */ while (*pbuf) { *pbuf = toupper(*pbuf); pbuf++; } if (strcmp(buf, "AUDIO") == 0) return TrackData::AUDIO; if (strcmp(buf, "MODE1/2048") == 0) return TrackData::MODE1; if (strcmp(buf, "MODE1/2352") == 0) return TrackData::MODE1_RAW; if (strcmp(buf, "MODE2/2336") == 0) return TrackData::MODE2; if (strcmp(buf, "MODE2/2352") == 0) return TrackData::MODE2_RAW; err_fail("Unsupported track mode"); return TrackData::AUDIO; } static void check_once(enum command cmd, char *s, enum scope sc); /* Read at most CDTEXTLEN chars into s */ static void get_cdtext(FILE *f, enum command cmd, char *s, enum scope sc) { check_once(cmd, s, sc); if (get_string(f, s, CDTEXTLEN) < 1) err_earlyend(); } /* All strings have their first character initialized to '\0' so if s[0] is not Null the cmd has already been seen in input. In this case print a message end exit program indicating failure. The only purpose of the arguments cmd and sc is to print meaningful error messages. */ static void check_once(enum command cmd, char *s, enum scope sc) { if (s[0] == '\0') return; fprintf(stderr, "%s:%ld: %s allowed only once", fname, line, cmds[cmd]); switch (sc) { case CUESHEET: fprintf(stderr, "\n"); break; case GLOBAL: fprintf(stderr, " in global section\n"); break; case ONETRACK: fprintf(stderr, " per track\n"); break; } exit(EXIT_FAILURE); } /* Allocate, initialize and return new track */ static struct trackspec* new_track(void) { struct trackspec *track; int i; if ((track = (struct trackspec*) malloc(sizeof(struct trackspec))) == NULL) err_fail("Memory allocation error in new_track()"); track->copy = track->pre_emphasis = track->four_channel_audio = track->pregap_data_from_file = 0; track->isrc[0] = track->title[0] = track->performer[0] = track->songwriter[0] = track->filename[0] = '\0'; track->pregap = track->start = track->postgap = -1; for (i = 0; i < NUM_OF_INDEXES; i++) track->indexes[i] = -1; track->next = NULL; return track; } /* Read the cuefile and return a pointer to the cuesheet */ struct cuesheet* read_cue(const char *cuefile, const char *wavefile) { FILE *f; enum command cmd; struct cuesheet *cs = NULL; struct trackspec *track = NULL; size_t n; int c; char file[FILENAMELEN + 1]; char timecode_buffer[TCBUFLEN]; char devnull[FILENAMELEN + 1]; /* just for eating CDTEXTFILE arg */ if (NULL == cuefile) { f = stdin; } else if (NULL == (f = fopen(cuefile, "r"))) { fprintf(stderr, "Could not open file \"%s\" for " "reading: %s\n", cuefile, strerror(errno)); exit(EXIT_FAILURE); } if (cuefile) fname = cuefile; if ((cs = (struct cuesheet*) malloc(sizeof(struct cuesheet))) == NULL) err_fail("Memory allocation error in read_cue()"); cs->catalog[0] = '\0'; cs->type = (session_type)0; cs->title[0] = '\0'; cs->performer[0] = '\0'; cs->songwriter[0] = '\0'; cs->tracklist = NULL; file[0] = '\0'; line = 1; /* global section */ while ((cmd = get_command(f)) != TRACK) { switch (cmd) { case UNKNOWN: err_fail("Unknown command"); case END: err_earlyend(); case REM: c = getc(f); while (c != '\n' && c != EOF) c = getc(f); break; case CDTEXTFILE: err_warn("ignoring CDTEXTFILE..."); if (get_string(f, devnull, FILENAMELEN) == 0) err_warn("Syntactically incorrect " "CDTEXTFILE command. But who " "cares..."); break; case CATALOG: check_once(CATALOG, cs->catalog, CUESHEET); n = get_string(f, cs->catalog, 13); if (n != 13) err_fail("Catalog number must be 13 " "characters long"); break; case TITLE: get_cdtext(f, TITLE, cs->title, GLOBAL); break; case PERFORMER: get_cdtext(f, PERFORMER, cs->performer, GLOBAL); break; case SONGWRITER: get_cdtext(f, SONGWRITER, cs->songwriter, GLOBAL); break; case FILECMD: check_once(FILECMD, file, GLOBAL); if (get_string(f, file, FILENAMELEN) < 1) err_earlyend(); switch (cmd = get_command(f)) { case MOTOROLA: err_warn("big endian binary file"); case BINARY: break; case AIFF: err_warn("AIFF not supported by cdrdao"); case MP3: case OGG: case WAVE: if (wavefile) { strncpy(file, wavefile, FILENAMELEN); file[FILENAMELEN] = '\0'; } break; default: err_fail("Unsupported file type"); } break; default: err_fail("Command not allowed in global section"); break; } } /* leaving global section, entering track specifications */ if (file[0] == '\0') err_fail("TRACK without previous FILE"); while (cmd != END) { switch(cmd) { case UNKNOWN: err_fail("Unknown command"); case REM: c = getc(f); while (c != '\n' && c != EOF) c = getc(f); break; case TRACK: if (track == NULL) /* first track */ cs->tracklist = track = new_track(); else { track = track->next = new_track(); } /* the CUE format is "TRACK nn MODE" but we are not interested in the track number */ while (isdelim(c = getc(f))) if (c == '\n') line++; while (!isdelim(c = getc(f))) ; if (c == '\n') line++; track->mode = get_track_mode(f); /* audio tracks with binary files seem quite common */ /* if (track->mode == AUDIO && filetype == BINARY || track->mode != AUDIO && filetype == WAVE) err_fail("File and track type mismatch"); */ strcpy(track->filename, file); break; case TITLE: get_cdtext(f, TITLE, track->title, ONETRACK); break; case PERFORMER: get_cdtext(f, PERFORMER, track->performer, ONETRACK); break; case SONGWRITER: get_cdtext(f, SONGWRITER, track->songwriter, ONETRACK); break; case ISRC: check_once(ISRC, track->isrc, ONETRACK); if (get_string(f, track->isrc, 12) != 12) err_fail("ISRC must be 12 characters long"); break; case FLAGS: if (track->copy || track->pre_emphasis || track->four_channel_audio) err_fail("FLAGS allowed only once per track"); /* get the flags */ cmd = get_command(f); while (cmd == DCP || cmd == FOURCH || cmd == PRE || cmd == SCMS) { switch (cmd) { case DCP: track->copy = 1; break; case FOURCH: track->four_channel_audio = 1; break; case PRE: track->pre_emphasis = 1; break; case SCMS: err_warn("serial copy management " "system flag not supported " "by cdrdao"); break; default: err_fail("Should not get here"); } cmd = get_command(f); } /* current non-FLAG command is already in cmd, so avoid get_command() call below */ continue; break; case PREGAP: if (track->pregap != -1) err_fail("PREGAP allowed only once per track"); if (get_string(f, timecode_buffer, TCBUFLEN - 1) < 1) err_earlyend(); track->pregap = tc2fr(timecode_buffer); if (track->pregap == -1) err_fail("Timecode out of range"); track->pregap_data_from_file = 0; break; case POSTGAP: if (track->postgap != -1) err_fail("POSTGAP allowed only once per track"); if (get_string(f, timecode_buffer, TCBUFLEN - 1) < 1) err_earlyend(); track->postgap = tc2fr(timecode_buffer); if (track->postgap == -1) err_fail("Timecode out of range"); break; case INDEX: if (get_string(f, timecode_buffer, 2) < 1) err_earlyend(); n = atoi(timecode_buffer); if (n < 0 || n > 99) err_fail("Index out of range"); /* Index 0 is track pregap and Index 1 is start of track. Index 2 to 99 are the true subindexes and only allowed if the preceding one was there before */ switch (n) { case 0: if (track->start != -1) err_fail("Indexes must be sequential"); if (track->pregap != -1) err_fail("PREGAP allowed only once " "per track"); if (get_string(f, timecode_buffer, TCBUFLEN - 1) < 1) err_earlyend(); /* This is only a temporary value until index 01 is read */ track->pregap = tc2fr(timecode_buffer); if (track->pregap == -1) err_fail("Timecode out of range"); track->pregap_data_from_file = 1; break; case 1: if (track->start != -1) err_fail("Each index allowed only " "once per track"); if (get_string(f, timecode_buffer, TCBUFLEN - 1) < 1) err_fail("Missing timecode"); track->start = tc2fr(timecode_buffer); if (track->start == -1) err_fail("Timecode out of range"); /* Fix the pregap value */ if (track->pregap_data_from_file) track->pregap = track->start - track->pregap; break; case 2: if (track->start == -1) err_fail("Indexes must be sequential"); if (track->indexes[n - 2] != -1) err_fail("Each index allowed only " "once per track"); if (get_string(f, timecode_buffer, TCBUFLEN - 1) < 1) err_fail("Missing timecode"); track->indexes[n - 2] = tc2fr(timecode_buffer); if (track->indexes[n - 2] == -1) err_fail("Timecode out of range"); break; default: /* the other 97 indexes */ /* check if previous index is there */ if (track->indexes[n - 3] == -1) err_fail("Indexes must be sequential"); if (track->indexes[n - 2] != -1) err_fail("Each index allowed only " "once per track"); if (get_string(f, timecode_buffer, TCBUFLEN - 1) < 1) err_fail("Missing timecode"); track->indexes[n - 2] = tc2fr(timecode_buffer); if (track->indexes[n - 2] == -1) err_fail("Timecode out of range"); break; } break; case FILECMD: if (get_string(f, file, FILENAMELEN) < 1) err_earlyend(); switch (cmd = get_command(f)) { case MOTOROLA: err_warn("big endian binary file"); case BINARY: break; case AIFF: err_warn("AIFF and MP3 not supported by " "cdrdao"); case MP3: case OGG: case WAVE: if (wavefile) { strncpy(file, wavefile, FILENAMELEN); file[FILENAMELEN] = '\0'; } break; default: err_fail("Unsupported file type"); } break; default: err_fail("Command not allowed in track spec"); break; } cmd = get_command(f); } return cs; } /* Deduce the disc session type from the track modes */ static enum session_type determine_session_type(struct trackspec *list) { struct trackspec *track = list; /* set to true if track of corresponding type is found */ int audio = 0; int mode1 = 0; int mode2 = 0; while (track != NULL) { switch (track->mode) { case TrackData::AUDIO: audio = 1; break; case TrackData::MODE1: case TrackData::MODE1_RAW: mode1 = 1; break; case TrackData::MODE2: case TrackData::MODE2_RAW: mode2 = 1; break; default: /* should never get here */ err_fail2("Don't know how this could happen, but here " "is a track with an unknown mode :|"); } track = track->next; } /* CD_DA only audio * CD_ROM only mode1 with or without audio * CD_ROM_XA only mode2 with or without audio */ if (audio && !mode1 && !mode2) return CD_DA; else if ((audio && mode1 && !mode2) || (!audio && mode1 && !mode2)) return CD_ROM; else if ((audio && !mode1 && mode2) || (!audio && !mode1 && mode2)) return CD_ROM_XA; else return INVALID; } /* Return true if cuesheet contains any CD-Text data */ static int contains_cdtext(struct cuesheet *cs) { struct trackspec *track = cs->tracklist; if (cs->title[0] != '\0' || cs->performer[0] != '\0' || cs->songwriter[0] != '\0') return 1; while (track) { if (track->title[0] != '\0' || track->performer[0] != '\0' || track->songwriter[0] != '\0') return 1; track = track->next; } return 0; } /* fprintf() with indentation. The argument indent is the number of spaces to print per level. E.g. with indent=4 and level=3 there are 12 spaces printed. Every eight spaces are replaced by a single tabulator. The return value is the return value of fprintf(). */ static int ifprintf(std::ostream& o, int indent, int level, const char *format, ...) { static char twolines[161]; va_list ap; int fprintf_return = 0; int tabs = indent * level / 8; int spaces = indent * level % 8; int i; for (i = 0; i < tabs; i++) o << '\t'; for (i = 0; i < spaces; i++) o << ' '; va_start(ap, format); fprintf_return = vsnprintf(twolines, sizeof(twolines), format, ap); va_end(ap); o << twolines; return fprintf_return; } /* Write a track to the file f. The arguments i and l are the indentation amount and level (see ifprintf above). Do not write CD-Text data if cdtext is zero. */ static void write_track(struct trackspec *tr, std::ostream& f, int i, int l, int cdtext) { char timecode_buffer[TCBUFLEN]; long start = 0, len = 0; int j = 0; f << std::endl; ifprintf(f, i, l++, "TRACK "); switch(tr->mode) { case TrackData::AUDIO: f << "AUDIO\n"; break; case TrackData::MODE1: f << "MODE1\n"; break; case TrackData::MODE1_RAW: f << "MODE1_RAW\n"; break; case TrackData::MODE2: f << "MODE2\n"; break; case TrackData::MODE2_RAW: f << "MODE2_RAW\n"; break; default: err_fail2("Unknown track mode"); /* cant get here */ } /* Flags and ISRC */ if (tr->copy) ifprintf(f, i, l, "COPY\n"); if (tr->pre_emphasis) ifprintf(f, i, l, "PRE_EMPHASIS\n"); if (tr->four_channel_audio) ifprintf(f, i, l, "FOUR_CHANNEL_AUDIO\n"); if (tr->isrc[0] != '\0') ifprintf(f, i, l, "ISRC \"%s\"\n", tr->isrc); /* CD-Text data */ if (cdtext && (tr->title[0] != '\0' || tr->performer[0] != '\0' || tr->songwriter[0] != '\0')) { ifprintf(f, i, l++, "CD_TEXT {\n"); ifprintf(f, i, l++, "LANGUAGE 0 {\n"); if (tr->title[0] != '\0') ifprintf(f, i, l, "TITLE \"%s\"\n", tr->title); if (tr->performer[0] != '\0') ifprintf(f, i, l, "PERFORMER \"%s\"\n", tr->performer); if (tr->songwriter[0] != '\0') ifprintf(f, i, l, "SONGWRITER \"%s\"\n", tr->songwriter); ifprintf(f, i, --l, "}\n"); /* LANGUAGE 0 { */ ifprintf(f, i, --l, "}\n"); /* CD_TEXT { */ } /* Pregap with zero data */ if (tr->pregap != -1 && !tr->pregap_data_from_file) { if (fr2tc(timecode_buffer, tr->pregap) == -1) err_fail2("Pregap out of range"); ifprintf(f, i, l, "PREGAP %s\n", timecode_buffer); } /* Specify the file */ start = 0; if (tr->mode == TrackData::AUDIO) { ifprintf(f, i, l, "AUDIOFILE \"%s\" ", tr->filename); if (tr->start != -1) { if (tr->pregap_data_from_file) { start = tr->start - tr->pregap; } else start = tr->start; } if (fr2tc(timecode_buffer, start) == -1) err_fail2("Track start out of range"); f << timecode_buffer; } else { if (tr->start) { long datastart = (tr->pregap_data_from_file ? tr->start - tr->pregap : tr->start); ifprintf(f, i, l, "DATAFILE \"%s\" #%d", tr->filename, datastart * AUDIO_BLOCK_LEN); start = datastart; } else { ifprintf(f, i, l, "DATAFILE \"%s\"", tr->filename); } } /* If next track has the same filename and specified a start value use the difference between start of this and start of the next track as the length of the current track */ if (tr->next && strcmp(tr->filename, tr->next->filename) == 0 && tr->next->start != -1) { if (tr->next->pregap_data_from_file) len = tr->next->start - tr->next->pregap - start; else len = tr->next->start - start; if (fr2tc(timecode_buffer, len) == -1) err_fail2("Track length out of range"); f << ' ' << timecode_buffer << std::endl; } else { f << std::endl; } /* Pregap with data from file */ if (tr->pregap_data_from_file) { if (fr2tc(timecode_buffer, tr->pregap) == -1) err_fail2("Pregap out of range"); ifprintf(f, i, l, "START %s\n", timecode_buffer); } /* Postgap */ if (tr->postgap != -1) { if (fr2tc(timecode_buffer, tr->postgap) == -1) err_fail2("Postgap out of range"); if (tr->mode == TrackData::AUDIO) ifprintf(f, i, l, "SILENCE %s\n", timecode_buffer); else ifprintf(f, i, l, "ZERO %s\n", timecode_buffer); } /* Indexes */ while (tr->indexes[j] != -1 && i < NUM_OF_INDEXES) { if (fr2tc(timecode_buffer, tr->indexes[j++]) == -1) err_fail2("Index out of range"); ifprintf(f, i, l, "INDEX %s\n", timecode_buffer); } } // Write the cuesheet cs to the output stream. Do not write CD-Text // data if cdt is zero. void write_toc(std::ostream& f, struct cuesheet *cs, bool cdt) { int i = 4; /* number of chars for indentation */ int l = 0; /* current leven of indentation */ bool cdtext = contains_cdtext(cs) && cdt; struct trackspec *track = cs->tracklist; if ((cs->type = determine_session_type(cs->tracklist)) == INVALID) err_fail2("Invalid combination of track modes"); ifprintf(f, i, l, "// Generated by cue2toc 0.2\n"); ifprintf(f, i, l, "// Report bugs to \n"); if (cs->catalog[0] != '\0') ifprintf(f, i, l, "CATALOG \"%s\"\n", cs->catalog); switch (cs->type) { case CD_DA: ifprintf(f, i, l, "CD_DA\n"); break; case CD_ROM: ifprintf(f, i, l, "CD_ROM\n"); break; case CD_ROM_XA: ifprintf(f, i, l, "CD_ROM_XA\n"); break; default: err_fail2("Should never get here"); } if (cdtext) { ifprintf(f, i, l++, "CD_TEXT {\n"); ifprintf(f, i, l++, "LANGUAGE_MAP {\n"); ifprintf(f, i, l, "0 : EN\n"); ifprintf(f, i, --l, "}\n"); ifprintf(f, i, l++, "LANGUAGE 0 {\n"); if (cs->title[0] != '\0') ifprintf(f, i, l, "TITLE \"%s\"\n", cs->title); if (cs->performer[0] != '\0') ifprintf(f, i, l, "PERFORMER \"%s\"\n", cs->performer); if (cs->songwriter[0] != '\0') ifprintf(f, i, l, "SONGWRITER \"%s\"\n", cs->songwriter); ifprintf(f, i, --l, "}\n"); ifprintf(f, i, --l, "}\n"); } while (track) { write_track(track, f, i, l, cdtext); track = track->next; } } /* Interpret argument as timecode value ("MM:SS:FF") and return the total number of frames. Tries to work in a way similar to atoi(), ignoring any trailing non-timecode junk. Skips leading whitespace. I want it to be as flexible as possible, recognizing simple values like "0" (interpreted as "00:00:00"), "1:2" ("00:01:02") and so on. Returns -1 on error (argument NULL or some value out of range) */ #define MAXDIGITS 2 #define NUMOFNUMS 3 long tc2fr(const char *tc) { int minutes = 0; int seconds = 0; int frames = 0; long totalframes = 0; char tmp[MAXDIGITS + 1]; int nums[NUMOFNUMS]; int n = 0; int i = 0; int last_was_colon = 0; int stop = 0; if (tc == NULL) return -1; for (i = 0; i <= MAXDIGITS; i++) tmp[i] = '\0'; while (isspace(*tc)) tc++; for (n = 0; n < NUMOFNUMS; n++) { if (n > 0) { if (tc[0] != ':') { --n; break; } else tc++; } for (i = 0; i < MAXDIGITS; i++) { if (isdigit(tc[i])) { tmp[i] = tc[i]; last_was_colon = 0; } else if (tc[i] == ':') { if (i == 0) stop = 1; break; } else { stop = 1; break; } } if (i != 0) { tmp[i] = '\0'; nums[n] = atoi(tmp); tc = &tc[i]; } else --n; if (stop) break; } if (n == NUMOFNUMS) --n; frames = seconds = minutes = 0; switch (n) { case 0: frames = nums[0]; break; case 1: seconds = nums[0]; frames = nums[1]; break; case 2: minutes = nums[0]; seconds = nums[1]; frames = nums[2]; break; } totalframes = ((60 * minutes) + seconds) * 75 + frames; if (seconds > 59 || frames > 74) return -1; return totalframes; } /* Writes formatted timecode string ("MM:SS:FF") into tc, calculated from frame number fr. Returns -1 on error (frames value out of range) */ int fr2tc(char *tc, long fr) { int m; int s; int f; if (fr > 449999 || fr < 0) { /* 99:59:74 */ strcpy(tc, "00:00:00"); return -1; } f = fr % 75; fr -= f; s = (fr / 75) % 60; fr -= s * 75; m = fr / 75 / 60; snprintf(tc, TCBUFLEN, "%02d:%02d:%02d", m, s, f); return 0; } cdrdao-cdrdao-f00afb2/trackdb/Cue2Toc.h000066400000000000000000000044041511453746600177270ustar00rootroot00000000000000/* cue2toc.h - declarations for conversion routines * Copyright (C) 2004 Matthias Czapla * * This file is part of cue2toc. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "Track.h" /* Maximum length of the FILEname */ #define FILENAMELEN 1024 /* Number of characters allowed per CD-Text entry (w/o termin. Null) */ #define CDTEXTLEN 80 /* Index can be 0 to 99, but 0 and 1 are pre-gap and track start respectively, so 98 are left */ #define NUM_OF_INDEXES 98 enum session_type { CD_DA = 1, /* only audio tracks */ CD_ROM, /* mode1 [and audio] */ CD_ROM_XA, /* mode2 form1 or mode2 form2 [and audio] */ INVALID /* invalid mixture of track modes */ }; struct trackspec { TrackData::Mode mode; int copy; /* boolean */ int pre_emphasis; /* boolean */ int four_channel_audio; /* boolean */ char isrc[13]; char title[CDTEXTLEN + 1]; char performer[CDTEXTLEN + 1]; char songwriter[CDTEXTLEN + 1]; char filename[FILENAMELEN + 1];; long pregap; /* Pre-gap in frames */ int pregap_data_from_file; /* boolean */ long start; /* track start in frames */ long postgap; /* Post-gap in frames */ long indexes[NUM_OF_INDEXES]; /* indexes in frames */ struct trackspec *next; }; struct cuesheet { char catalog[14]; enum session_type type; char title[CDTEXTLEN + 1]; char performer[CDTEXTLEN + 1]; char songwriter[CDTEXTLEN + 1]; struct trackspec *tracklist; }; struct cuesheet *read_cue(const char*, const char*); void write_toc(std::ostream&, struct cuesheet*, bool withCdText); cdrdao-cdrdao-f00afb2/trackdb/CueParser.cc000066400000000000000000000024121511453746600205070ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2005 Denis Leroy * * 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. */ #include #include #include #include "Cue2Toc.h" #include "Toc.h" extern Toc *parseToc(const char* , const char *); Toc *parseCue(FILE *fp, const char *filename) { struct cuesheet* cue = read_cue(filename, NULL); std::ostringstream oss(std::ostringstream::out); write_toc(oss, cue, true); std::string ossstr = oss.str(); const char* content = ossstr.c_str(); return parseToc(content, filename); } cdrdao-cdrdao-f00afb2/trackdb/CueParser.h000066400000000000000000000016521511453746600203560ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2005 Denis Leroy * * 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. */ #include #include #include "Toc.h" Toc* parseCue(FILE* fp, const char* filename); cdrdao-cdrdao-f00afb2/trackdb/FormatConverter.cc000066400000000000000000000123311511453746600217370ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2004 Denis Leroy * * 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. */ #include #ifdef HAVE_AO #include #endif #include #include #include "config.h" #include "log.h" #include "FormatConverter.h" #include "TempFileManager.h" #ifdef HAVE_MP3_SUPPORT #include "FormatMp3.h" #endif #ifdef HAVE_OGG_SUPPORT #include "FormatOgg.h" #endif FormatConverter::FormatConverter() { #if defined(HAVE_MP3_SUPPORT) || defined(HAVE_OGG_SUPPORT) ao_initialize(); #endif #ifdef HAVE_MP3_SUPPORT managers_.push_front(new FormatMp3Manager); #endif #ifdef HAVE_OGG_SUPPORT managers_.push_front(new FormatOggManager); #endif } FormatConverter::~FormatConverter() { std::list::iterator i = managers_.begin(); while (i != managers_.end()) { delete *i++; } #if defined(HAVE_MP3_SUPPORT) || defined(HAVE_OGG_SUPPORT) ao_shutdown(); #endif } FormatSupport* FormatConverter::newConverter(const char* fn) { const char* ext = strrchr(fn, '.'); if (!ext) return NULL; ext++; FormatSupport* candidate = NULL; std::list::iterator i = managers_.begin(); while (i != managers_.end()) { FormatSupportManager* mgr = *i++; candidate = mgr->newConverter(ext); if (candidate) break; } return candidate; } FormatSupport* FormatConverter::newConverterStart(const char* src, std::string& dst, FormatSupport::Status* st) { if (st) *st = FormatSupport::FS_SUCCESS; FormatSupport* candidate = newConverter(src); if (candidate) { const char* extension; if (candidate->format() == TrackData::WAVE) extension = "wav"; else extension = "raw"; bool exists = tempFileManager.getTempFile(dst, src, extension); if (exists) { delete candidate; return NULL; } FormatSupport::Status ret = candidate->convertStart(src, dst.c_str()); if (st) *st = ret; if (ret == FormatSupport::FS_SUCCESS) return candidate; else delete candidate; } dst = ""; return NULL; } bool FormatConverter::canConvert(const char* fn) { FormatSupport* c = newConverter(fn); if (!c) return false; delete c; return true; } const char* FormatConverter::convert(const char* fn, FormatSupport::Status* err) { *err = FormatSupport::FS_SUCCESS; FormatSupport* c = newConverter(fn); if (!c) return NULL; std::string* file = new std::string; const char* extension; if (c->format() == TrackData::WAVE) extension = "wav"; else extension = "raw"; bool exists = tempFileManager.getTempFile(*file, fn, extension); if (!exists) { log_message(2, "Decoding file \"%s\"", fn); *err = c->convert(fn, file->c_str()); if (*err != FormatSupport::FS_SUCCESS) return NULL; tempFiles_.push_front(file); } return file->c_str(); } int FormatConverter::supportedExtensions(std::list& list) { int num = 0; std::list::iterator i = managers_.begin(); for (;i != managers_.end(); i++) { num += (*i)->supportedExtensions(list); } return num; } FormatSupport::Status FormatConverter::convert(Toc* toc) { FormatSupport::Status err; std::set set; toc->collectFiles(set); std::set::iterator i = set.begin(); for (; i != set.end(); i++) { const char* dst = convert((*i).c_str(), &err); if (!dst && err != FormatSupport::FS_SUCCESS) return FormatSupport::FS_OTHER_ERROR; if (dst) toc->markFileConversion((*i).c_str(), dst); } return FormatSupport::FS_SUCCESS; } bool parseM3u(const char* m3ufile, std::list& list) { // You'd think STL would be smart enough to NOT have to use a stack // buffer like this. STL is so poorly designed there's no any other // way. char buffer[1024]; std::string dir = m3ufile; dir = dir.substr(0, dir.rfind("/")); dir += "/"; std::ifstream file(m3ufile, std::ios::in); if (!file.is_open()) return false; while (!file.eof()) { file.getline(buffer, 1024); std::string e = buffer; if (!e.empty() && (*(e.begin())) != '#') { if (e[0] != '/') e = dir + e; int n; while ((n = e.find('\r')) >= 0) e.erase(n, 1); while ((n = e.find('\n')) >= 0) e.erase(n, 1); list.push_back(e); } } file.close(); return true; } FormatConverter formatConverter; cdrdao-cdrdao-f00afb2/trackdb/FormatConverter.h000066400000000000000000000076171511453746600216140ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2004 Denis Leroy * * 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. */ #ifndef __FORMATCONVERTER_H__ #define __FORMATCONVERTER_H__ #include #include #include #include "TrackData.h" #include "Toc.h" // Quick abstract class declarations. Format converters should derive // their own FormatSupport and FormatSupportManager. class FormatSupport { public: virtual ~FormatSupport() {} typedef enum { FS_SUCCESS, FS_IN_PROGRESS, FS_WRONG_FORMAT, FS_INPUT_PROBLEM, FS_OUTPUT_PROBLEM, FS_DISK_FULL, FS_DECODE_ERROR, FS_OTHER_ERROR, } Status; // Convert source file to destination WAV or RAW. This is a blocking // call until conversion is finished. // Return values: // 0: success // 1: problem with input file // 2: problem with output file // 3: problem with conversion virtual Status convert(const char* from, const char* to) = 0; // Same as above, but asynchronous interface. Call start, then call // continue in a busy loop until it no longer returns // FS_IN_PROGRESS. virtual Status convertStart(const char* from, const char* to) = 0; virtual Status convertContinue() = 0; virtual void convertAbort() = 0; // Specify what this object converts to. Should only returns either // TrackData::WAVE or TrackData::RAW virtual TrackData::FileType format() = 0; }; class FormatSupportManager { public: virtual ~FormatSupportManager() {} // Acts as virtual constructor. Returns a new converter if this // converter understands the given file extension. virtual FormatSupport* newConverter(const char* extension) = 0; // Add supported file extensions to list. Returns number added. virtual int supportedExtensions(std::list&) = 0; }; // The global format conversion class. A single global instance of // this class exists and manages all format conversions. class FormatConverter { public: FormatConverter(); virtual ~FormatConverter(); // Returns true if the converter understands this format bool canConvert(const char* fn); // Convert file, return tempory file with WAV or RAW data (based on // temp file extension).Returns NULL if conversion failed. const char* convert(const char* src, FormatSupport::Status* st = NULL); // Convert all files contained in a given Toc object, and update the // Toc accordingly. This is a big time blocking call. FormatSupport::Status convert(Toc* toc); // Dynamic allocator. FormatSupport* newConverter(const char* src); // Do it yourself. Returns a converter and starts it. Sets dst to // the converter file name (or clears it if no converter // found). Returns NULL if file can't be converted. FormatSupport* newConverterStart(const char* src, std::string& dst, FormatSupport::Status* status = NULL); // Add all supported extensions to string list. Returns number added. int supportedExtensions(std::list&); private: std::list tempFiles_; std::list managers_; }; extern FormatConverter formatConverter; // Utility for parsing M3U files bool parseM3u(const char* m3ufile, std::list& list); #endif cdrdao-cdrdao-f00afb2/trackdb/FormatMp3.cc000066400000000000000000000166571511453746600204460ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2004 Denis Leroy * * 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. */ // A lot of this code is taken from mpg321 : // mpg321 - a fully free clone of mpg123. // Copyright (C) 2001 Joe Drew #include #include #include #include #include #include #include #include #include "log.h" #include "FormatMp3.h" FormatMp3::FormatMp3() { memset(&dither_, 0, sizeof(dither_)); } FormatSupport::Status FormatMp3::convert(const char* from, const char* to) { src_file_ = from; dst_file_ = to; Status err = madInit(); if (err != FS_SUCCESS) return err; while ((err = madDecodeFrame()) == FS_IN_PROGRESS); madExit(); return err; } FormatSupport::Status FormatMp3::convertStart(const char* from, const char* to) { src_file_ = from; dst_file_ = to; return madInit(); } FormatSupport::Status FormatMp3::convertContinue() { Status err; for (int i = 0; i < 3; i++) { err = madDecodeFrame(); if (err != FS_IN_PROGRESS) break; } if (err != FS_IN_PROGRESS) madExit(); return err; } void FormatMp3::convertAbort() { madExit(); } FormatSupport::Status FormatMp3::madInit() { struct stat st; if (stat(src_file_, &st) != 0) { log_message(-2, "Could not stat input file \"%s\": %s", src_file_, strerror(errno)); return FS_INPUT_PROBLEM; } mapped_fd_ = open(src_file_, O_RDONLY); if (!mapped_fd_) { log_message(-2, "Could not open input file \"%s\": %s", src_file_, strerror(errno)); return FS_INPUT_PROBLEM; } length_ = st.st_size; start_ = mmap(0, st.st_size, PROT_READ, MAP_SHARED, mapped_fd_, 0); if (start_ == MAP_FAILED) { log_message(-2, "Could not map file \"%s\" into memory: %s", src_file_, strerror(errno)); return FS_INPUT_PROBLEM; } // Initialize libao for WAV output; ao_sample_format out_format; bzero(&out_format, sizeof(out_format)); out_format.bits = 16; out_format.rate = 44100; out_format.channels = 2; out_format.byte_format = AO_FMT_NATIVE; out_ = ao_open_file(ao_driver_id("wav"), dst_file_, 1, &out_format, NULL); if (!out_) { log_message(-2, "Could not create output file \"%s\": %s", dst_file_, strerror(errno)); return FS_OUTPUT_PROBLEM; } // Initialize libmad input stream. mad_stream_init(&stream_); mad_frame_init(&frame_); mad_synth_init(&synth_); mad_stream_options(&stream_, 0); mad_stream_buffer(&stream_, (unsigned char*)start_, length_); return FS_SUCCESS; } FormatSupport::Status FormatMp3::madDecodeFrame() { if (mad_frame_decode(&frame_, &stream_) == -1) { if (stream_.error != MAD_ERROR_BUFLEN && stream_.error != MAD_ERROR_LOSTSYNC) { log_message(-1, "Decoding error 0x%04x (%s) at byte offset %u", stream_.error, mad_stream_errorstr(&stream_), stream_.this_frame - (unsigned char*)start_); } if (stream_.error == MAD_ERROR_BUFLEN) return FS_SUCCESS; if (!MAD_RECOVERABLE(stream_.error)) return FS_DECODE_ERROR; } mad_synth_frame(&synth_, &frame_); madOutput(); return FS_IN_PROGRESS; } void FormatMp3::madExit() { mad_synth_finish(&synth_); mad_frame_finish(&frame_); mad_stream_finish(&stream_); munmap(start_, length_); close(mapped_fd_); ao_close(out_); } unsigned long FormatMp3::prng(unsigned long state) { return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL; } signed long FormatMp3::audio_linear_dither(unsigned int bits, mad_fixed_t sample, struct audio_dither *dither) { unsigned int scalebits; mad_fixed_t output, mask, random; enum { MIN = -MAD_F_ONE, MAX = MAD_F_ONE - 1 }; /* noise shape */ sample += dither->error[0] - dither->error[1] + dither->error[2]; dither->error[2] = dither->error[1]; dither->error[1] = dither->error[0] / 2; /* bias */ output = sample + (1L << (MAD_F_FRACBITS + 1 - bits - 1)); scalebits = MAD_F_FRACBITS + 1 - bits; mask = (1L << scalebits) - 1; /* dither */ random = prng(dither->random); output += (random & mask) - (dither->random & mask); dither->random = random; /* clip */ if (output > MAX) { output = MAX; if (sample > MAX) sample = MAX; } else if (output < MIN) { output = MIN; if (sample < MIN) sample = MIN; } /* quantize */ output &= ~mask; /* error feedback */ dither->error[0] = sample - output; /* scale */ return output >> scalebits; } FormatSupport::Status FormatMp3::madOutput() { struct mad_pcm* pcm = &synth_.pcm; int nsamples = pcm->length; mad_fixed_t const *left_ch = pcm->samples[0], *right_ch = pcm->samples[1]; char* ptr = buffer_; signed int sample; mad_fixed_t tempsample; if (pcm->channels == 2) { while (nsamples--) { tempsample = (mad_fixed_t)(*left_ch++); sample = (signed int)audio_linear_dither(16, tempsample,&dither_); #ifndef WORDS_BIGENDIAN *ptr++ = (unsigned char)(sample >> 0); *ptr++ = (unsigned char)(sample >> 8); #else *ptr++ = (unsigned char)(sample >> 8); *ptr++ = (unsigned char)(sample >> 0); #endif tempsample = (mad_fixed_t)(*right_ch++); sample = (signed int)audio_linear_dither(16, tempsample, &dither_); #ifndef WORDS_BIGENDIAN *ptr++ = (unsigned char)(sample >> 0); *ptr++ = (unsigned char)(sample >> 8); #else *ptr++ = (unsigned char)(sample >> 8); *ptr++ = (unsigned char)(sample >> 0); #endif } if (ao_play(out_, buffer_, pcm->length * 4) == 0) return FS_DISK_FULL; } else { while (nsamples--) { tempsample = (mad_fixed_t)((*left_ch++)/MAD_F_ONE); sample = (signed int)audio_linear_dither(16, tempsample, &dither_); /* Just duplicate the sample across both channels. */ #ifndef WORDS_BIGENDIAN *ptr++ = (unsigned char)(sample >> 0); *ptr++ = (unsigned char)(sample >> 8); *ptr++ = (unsigned char)(sample >> 0); *ptr++ = (unsigned char)(sample >> 8); #else *ptr++ = (unsigned char)(sample >> 8); *ptr++ = (unsigned char)(sample >> 0); *ptr++ = (unsigned char)(sample >> 8); *ptr++ = (unsigned char)(sample >> 0); #endif } if (ao_play(out_, buffer_, pcm->length * 4) == 0) return FS_DISK_FULL; } return FS_SUCCESS; } // ---------------------------------------------------------------- // // Manager class // // FormatSupport* FormatMp3Manager::newConverter(const char* extension) { if (strcmp(extension, "mp3") == 0) return new FormatMp3; return NULL; } int FormatMp3Manager::supportedExtensions(std::list& list) { list.push_front("mp3"); return 1; } cdrdao-cdrdao-f00afb2/trackdb/FormatMp3.h000066400000000000000000000044301511453746600202720ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2004 Denis Leroy * * 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. */ #ifndef __FORMATMP3_H__ #define __FORMATMP3_H__ #include #include #include #include "FormatConverter.h" class FormatMp3 : public FormatSupport { public: FormatMp3(); Status convert(const char* from, const char* to); Status convertStart(const char* from, const char* to); Status convertContinue(); void convertAbort(); TrackData::FileType format() { return TrackData::WAVE; } protected: struct audio_dither { mad_fixed_t error[3]; mad_fixed_t random; }; static inline unsigned long prng(unsigned long state); static inline signed long audio_linear_dither(unsigned int bits, mad_fixed_t sample, struct audio_dither* dither); Status madInit(); Status madDecodeFrame(); void madExit(); Status madOutput(); private: const char* src_file_; const char* dst_file_; // 1152 because that's what mad has as a max; *4 because there are 4 // distinct bytes per sample (in 2 channel case). char buffer_[1152*4]; ao_device* out_; int mapped_fd_; void* start_; unsigned length_; struct audio_dither dither_; struct mad_stream stream_; struct mad_frame frame_; struct mad_synth synth_; }; class FormatMp3Manager : public FormatSupportManager { public: FormatSupport* newConverter(const char* extension); int supportedExtensions(std::list&); }; #endif cdrdao-cdrdao-f00afb2/trackdb/FormatOgg.cc000066400000000000000000000061241511453746600205070ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2004 Denis Leroy * * 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. */ #include #include #include "log.h" #include "FormatOgg.h" FormatSupport::Status FormatOgg::convert(const char* from, const char* to) { src_file_ = from; dst_file_ = to; Status err = oggInit(); if (err != FS_SUCCESS) return err; while ((err = oggDecodeFrame()) == FS_IN_PROGRESS); oggExit(); return err; } FormatSupport::Status FormatOgg::convertStart(const char* from, const char* to) { src_file_ = from; dst_file_ = to; return oggInit(); } FormatSupport::Status FormatOgg::convertContinue() { Status err; for (int i = 0; i < 4; i++) { err = oggDecodeFrame(); if (err != FS_IN_PROGRESS) break; } if (err != FS_IN_PROGRESS) oggExit(); return err; } void FormatOgg::convertAbort() { oggExit(); } FormatSupport::Status FormatOgg::oggInit() { fin_ = fopen(src_file_, "r"); if (!fin_) { log_message(-2, "Could not open input file \"%s\": %s", src_file_, strerror(errno)); return FS_INPUT_PROBLEM; } int ovret = ov_open(fin_, &vorbisFile_, NULL, 0); if (ovret != 0) { log_message(-2, "Could not open Ogg Vorbis file \"%s\"", src_file_); return FS_WRONG_FORMAT; } outFormat_.bits = 16; outFormat_.rate = 44100; outFormat_.channels = 2; outFormat_.byte_format = AO_FMT_NATIVE; aoDev_ = ao_open_file(ao_driver_id("wav"), dst_file_, 1, &outFormat_, NULL); if (!aoDev_) { log_message(-2, "Could not create output file \"%s\": %s", dst_file_, strerror(errno)); return FS_OUTPUT_PROBLEM; } return FS_SUCCESS; } FormatSupport::Status FormatOgg::oggDecodeFrame() { int sec; int size = ov_read(&vorbisFile_, buffer_, sizeof(buffer_), 0, 2, 1, &sec); if (!size) return FS_SUCCESS; if (ao_play(aoDev_, buffer_, size) == 0) return FS_DISK_FULL; return FS_IN_PROGRESS; } FormatSupport::Status FormatOgg::oggExit() { ov_clear(&vorbisFile_); ao_close(aoDev_); return FS_SUCCESS; } // ---------------------------------------------------------------- // // Manager class // // FormatSupport* FormatOggManager::newConverter(const char* extension) { if (strcmp(extension, "ogg") == 0) return new FormatOgg; return NULL; } int FormatOggManager::supportedExtensions(std::list& list) { list.push_front("ogg"); return 1; } cdrdao-cdrdao-f00afb2/trackdb/FormatOgg.h000066400000000000000000000033711511453746600203520ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2004 Denis Leroy * * 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. */ #ifndef __FORMATOGG_H__ #define __FORMATOGG_H__ #include #include #include #include "FormatConverter.h" class FormatOgg : public FormatSupport { public: FormatOgg() {}; Status convert(const char* from, const char* to); Status convertStart(const char* from, const char* to); Status convertContinue(); void convertAbort(); TrackData::FileType format() { return TrackData::WAVE; } protected: virtual Status oggInit(); virtual Status oggDecodeFrame(); virtual Status oggExit(); private: const char* src_file_; const char* dst_file_; char buffer_[4096]; FILE* fin_; ao_device* aoDev_; ao_sample_format outFormat_; OggVorbis_File vorbisFile_; }; class FormatOggManager : public FormatSupportManager { public: FormatSupport* newConverter(const char* extension); int supportedExtensions(std::list&); }; #endif cdrdao-cdrdao-f00afb2/trackdb/Makefile.am000066400000000000000000000030261511453746600203450ustar00rootroot00000000000000noinst_LIBRARIES = libtrackdb.a libtrackdb_a_SOURCES = \ Cddb.cc \ lec.cc \ Toc.cc \ TrackDataList.cc \ CdTextContainer.cc \ Msf.cc \ Track.cc \ util.cc \ CdTextItem.cc \ SubTrack.cc \ TrackData.cc \ Cddb.h \ CdTextContainer.h \ CdTextItem.h \ lec.h \ Msf.h \ Sample.h \ SubTrack.h \ Toc.h \ TrackData.h \ TrackDataList.h \ Track.h \ util.h \ TocParser.g \ TempFileManager.cc \ FormatConverter.cc \ TempFileManager.h \ FormatConverter.h \ Cue2Toc.cc \ Cue2Toc.h \ CueParser.h \ CueParser.cc \ log.h \ log.cc PCCTS_GEN_FILES = \ TocParser.cpp \ TocParserGram.cpp \ TocLexerBase.cpp \ TocLexerBase.h \ TocParserGram.h \ TocParserTokens.h \ AParser.cpp \ DLexerBase.cpp \ ATokenBuffer.cpp nodist_libtrackdb_a_SOURCES = ${PCCTS_GEN_FILES} AM_CPPFLAGS = -I@pcctsinc@ ANTLR = @antlr_path@ DLG = @dlg_path@ TocParser.cpp: $(srcdir)/TocParser.g $(ANTLR) -nopurify -k 3 -CC -w2 -fl TocLexer.dlg -ft TocParserTokens.h $(srcdir)/TocParser.g $(DLG) -C2 -CC -cl TocLexerBase TocLexer.dlg TocParserGram.cpp TocLexerBase.cpp: TocParser.cpp AParser.cpp: @pcctsinc@/$@ cp @pcctsinc@/$@ . DLexerBase.cpp: @pcctsinc@/$@ cp @pcctsinc@/$@ . ATokenBuffer.cpp: @pcctsinc@/$@ cp @pcctsinc@/$@ . AM_CXXFLAGS = @AO_CFLAGS@ if COND_MP3 AM_CXXFLAGS += @MAD_CFLAGS@ libtrackdb_a_SOURCES += FormatMp3.cc FormatMp3.h endif if COND_OGG AM_CXXFLAGS += @VORBISFILE_CFLAGS@ libtrackdb_a_SOURCES += FormatOgg.cc FormatOgg.h endif CLEANFILES = ${PCCTS_GEN_FILES} CueLexer.dlg TocLexer.dlg cdrdao-cdrdao-f00afb2/trackdb/Msf.cc000066400000000000000000000032601511453746600173450ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller * * 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. */ #include #include #include #include "Msf.h" Msf::Msf() { min_ = sec_ = frac_ = 0; lba_ = 0; } Msf::Msf(int min, int sec, int frac) { // assert(frac >= 0 && frac < 75); // assert(sec >= 0 && sec < 60); // assert(min >= 0); min_ = min; sec_ = sec; frac_ = frac; lba_ = min_ * 4500 + sec_ * 75 + frac_; } Msf::Msf(long lba) { if (lba < 0) lba = 0; lba_ = lba; lba2Msf(); } void Msf::lba2Msf() { long lba = lba_; min_ = lba / 4500; lba %= 4500; sec_ = lba / 75; lba %= 75; frac_ = lba; } const char *Msf::str() const { static char buf[20]; snprintf(buf, sizeof(buf), "%02d:%02d:%02d", min_, sec_, frac_); return buf; } Msf operator+(const Msf &m1, const Msf &m2) { return Msf(m1.lba() + m2.lba()); } Msf operator-(const Msf &m1, const Msf &m2) { return Msf(m1.lba() - m2.lba()); } cdrdao-cdrdao-f00afb2/trackdb/Msf.h000066400000000000000000000032431511453746600172100ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller * * 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. */ #ifndef __MSF_H__ #define __MSF_H__ #include "Sample.h" #ifdef min /* I stupidly named a member function 'min' which clashes with the macro 'min' * on some operating systems. The macro is simply undefined here since it is * not used in this package anyway. */ #undef min #endif class Msf { private: int min_; // minutes int sec_; // seconds int frac_; // fractions (blocks) long lba_; // logical block address void lba2Msf(); public: Msf(int min, int sec, int frac); Msf(long lba); Msf(); int min() const { return min_; } int sec() const { return sec_; } int frac() const { return frac_; } long lba() const { return lba_; } unsigned long samples() const { return lba_ * SAMPLES_PER_BLOCK; } const char *str() const; }; Msf operator+(const Msf &m1, const Msf &m2); Msf operator-(const Msf &m1, const Msf &m2); #endif cdrdao-cdrdao-f00afb2/trackdb/Sample.h000066400000000000000000000032001511453746600176750ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998 Andreas Mueller * * 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. */ /* * $Log: Sample.h,v $ * Revision 1.1 2000/02/05 01:32:25 llanero * Initial revision * * Revision 1.2 1998/09/22 19:15:49 mueller * Added setting of sample data. * */ #ifndef __SAMPLE_H__ #define __SAMPLE_H__ #define SAMPLES_PER_BLOCK 588 // represents one audio sample struct Sample { unsigned char msbLeft; unsigned char lsbLeft; unsigned char msbRight; unsigned char lsbRight; short left() const { return (msbLeft << 8) | lsbLeft; } short right() const { return (msbRight << 8) | lsbRight; } void left(short d) { msbLeft = d >> 8; lsbLeft = d; } void right(short d) { msbRight = d >> 8; lsbRight = d; } void swap(); }; inline void Sample::swap() { char tmp; tmp = msbLeft; msbLeft = lsbLeft; lsbLeft = tmp; tmp = msbRight; msbRight = lsbRight; lsbRight = tmp; } #endif cdrdao-cdrdao-f00afb2/trackdb/SubTrack.cc000066400000000000000000000025161511453746600203410ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller * * 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. */ #include #include #include "SubTrack.h" SubTrack::SubTrack(Type t, unsigned long start, const TrackData &data) : TrackData(data) { type_ = t; start_ = start; next_ = pred_ = NULL; } SubTrack::SubTrack(Type t, const TrackData &data) : TrackData(data) { type_ = t; start_ = 0; next_ = pred_ = NULL; } SubTrack::SubTrack(const SubTrack &obj) : TrackData(obj) { type_ = obj.type_; start_ = obj.start_; next_ = pred_ = NULL; } SubTrack::~SubTrack() { next_ = pred_ = NULL; } cdrdao-cdrdao-f00afb2/trackdb/SubTrack.h000066400000000000000000000027321511453746600202030ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller * * 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. */ #ifndef __SUBTRACK_H__ #define __SUBTRACK_H__ #include "TrackData.h" class SubTrack : public TrackData { public: enum Type { PAD, DATA }; SubTrack(Type, unsigned long start, const TrackData &); SubTrack(Type, const TrackData &); SubTrack(const SubTrack &); ~SubTrack(); Type type() const { return type_; } unsigned long start() const { return start_; } void start(unsigned long s) { start_ = s; } private: unsigned long start_; // start postion (samples) within containing track Type type_; class SubTrack *next_; class SubTrack *pred_; friend class Track; friend class TrackReader; friend class SubTrackIterator; }; #endif cdrdao-cdrdao-f00afb2/trackdb/TempFileManager.cc000066400000000000000000000061151511453746600216220ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2004 Denis Leroy * * 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. */ #include "TempFileManager.h" #include "log.h" #include #include #include #include #include #include #define DEFAULT_TEMP_PATH "/tmp/" TempFileManager::TempFileManager() { path_ = DEFAULT_TEMP_PATH; keepTemps_ = false; prefix_ = "cdrdao."; } TempFileManager::~TempFileManager() { if (!keepTemps_) { std::map::const_iterator i = map_.begin(); for (;i != map_.end(); i++) { std::string tmpFile = (*i).second; log_message(3, "Removing temp file \"%s\"", tmpFile.c_str()); unlink(tmpFile.c_str()); } } } bool TempFileManager::setTempDirectory(const char* path) { struct stat st; int ret = stat(path, &st); if (ret != 0) { log_message(-2, "Could not find temporary directory %s.", path); return false; } if (!S_ISDIR(st.st_mode) || access(path, W_OK) != 0) { log_message(-2, "No permission for temp directory %s.", path); return false; } path_ = path; if (path[path_.size() - 1] != '/') path_ += '/'; return true; } bool TempFileManager::getTempFile(std::string& tempname, const char* key, const char* extension) { if (!map_[key].empty()) { tempname = map_[key]; return true; } const char* shortname = strrchr(key, '/'); if (shortname) shortname++; else shortname = key; std::string fname = path_; fname += prefix_; fname += shortname; int id = 1; int fd; do { char tmpbuf[12]; std::string uniqnm = fname; snprintf(tmpbuf, sizeof(tmpbuf), ".%d", id); uniqnm += tmpbuf; if (extension) { uniqnm += "."; uniqnm += extension; } fd = open(uniqnm.c_str(), O_CREAT|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); if (fd > 0) { fname = uniqnm; break; } id++; if (id > 100) { log_message(-2, "Unable to create temp file in directory %s.", path_.c_str()); tempname = ""; return false; } } while(1); close(fd); map_[key] = fname; tempname = map_[key]; log_message(3, "Created temp file \"%s\" for file \"%s\"", fname.c_str(), key); return false; } TempFileManager tempFileManager; cdrdao-cdrdao-f00afb2/trackdb/TempFileManager.h000066400000000000000000000034071511453746600214650ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2004 Denis Leroy * * 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. */ #ifndef __TEMPFILEMANAGER_H__ #define __TEMPFILEMANAGER_H__ #include #include class TempFileManager { public: TempFileManager(); // The destructor will delete all temp files (unless keepTemps is // set) that have not expired yet. virtual ~TempFileManager(); bool setTempDirectory(const char* path); void setKeepTemps(bool b) { keepTemps_ = b; } void setPrefix(const char* prefix) { prefix_ = prefix; } // Create a new temporary file, associated with given 'key'. The // given name string is set to the temporaty file. Returns false // is a new file was created, returns true if a temporary file // already exists. bool getTempFile(std::string& name, const char* key, const char* extension = NULL); private: std::string path_; std::string prefix_; std::map map_; bool keepTemps_; }; extern TempFileManager tempFileManager; #endif cdrdao-cdrdao-f00afb2/trackdb/Toc.cc000066400000000000000000001051201511453746600173430ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller * * 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. */ #include #include #include #include #include #include #include #include #include #include #include "Toc.h" #include "util.h" #include "log.h" #include "TrackDataList.h" #include "CdTextItem.h" #include "CueParser.h" #include "FormatConverter.h" using std::string; #ifdef UNIXWARE extern "C" { extern int strcasecmp(const char *, const char *); } #endif extern Toc *parseToc(FILE *fp, const char *filename); Toc::Toc() : length_(0) { tocType_ = Type::CD_DA; nofTracks_ = 0; firstTrackNo_ = 0; tracks_ = lastTrack_ = NULL; catalogValid_ = 0; } // copy constructor Toc::Toc(const Toc &obj) : length_(0), cdtext_(obj.cdtext_) { tocType_ = obj.tocType_; if ((catalogValid_ = obj.catalogValid_)) memcpy(catalog_, obj.catalog_, 13); nofTracks_ = 0; firstTrackNo_ = obj.firstTrackNo_; tracks_ = lastTrack_ = NULL; // copy all tracks for (auto trun = obj.tracks_; trun; trun = trun->next) append(trun->track); } Toc::~Toc() { TrackEntry *run = tracks_; TrackEntry *next; while (run != NULL) { next = run->next; delete run->track; delete run; run = next; } } // appends track // return: 0: OK // 1: first track contains pregap int Toc::append(const Track *t) { if (tracks_ == NULL) { tracks_ = lastTrack_ = new TrackEntry; } else { lastTrack_->next = new TrackEntry; lastTrack_->next->pred = lastTrack_; lastTrack_ = lastTrack_->next; } lastTrack_->track = new Track(*t); nofTracks_ += 1; update(); return 0; } void Toc::update() { TrackEntry *run; long length = 0; // length of disc in blocks long tlength; // length of single track in blocks int tnum; for (run = tracks_, tnum = 1; run != NULL; run = run->next, tnum++) { tlength = run->track->length().lba(); run->absStart = Msf(length); run->start = Msf(length + run->track->start().lba()); run->end = Msf(length + tlength); run->trackNr = tnum; length += tlength; } length_ = Msf(length); } Toc *Toc::read(const string& filename) { FILE *fp; Toc *ret; const char *p; if ((fp = fopen(filename.c_str(), "r")) == NULL) { log_message(-2, "Cannot open toc file '%s' for reading: %s", filename.c_str(), strerror(errno)); return NULL; } if (filename.size() >= 4 && filename.substr(filename.size() - 4, 4) == ".cue") ret = parseCue(fp, filename.c_str()); else ret = parseToc(fp, filename.c_str()); fclose(fp); return ret; } bool Toc::resolveFilenames(const char* filename) { // Resolve all relative filenames to absoluate paths wrt to the toc // file current directory. std::string path = filename; path = path.substr(0, path.rfind('/')); if (path.empty()) path = "."; for (TrackEntry* t = tracks_; t != NULL; t = t->next) if (!t->track->resolveFilename(path.c_str())) return false; return true; } // Writes toc to file with given name. // Return: 0: OK // 1: error occured int Toc::write(const string& filename, bool conversions) const { assert(!filename.empty()); std::ofstream out(filename); if (!out) { log_message(-2, "Cannot open file \"%s\" for writing: %s", filename.c_str(), strerror(errno)); return 1; } PrintParams p; p.conversions = conversions; print(out, p); return 0; } int Toc::check() const { TrackEntry *t; int trackNr; int ret = 0; for (t = tracks_, trackNr = 1; t != NULL; t = t->next, trackNr++) { ret |= t->track->check(trackNr); } return ret; } bool Toc::recomputeLength() { for (TrackEntry* t = tracks_; t; t = t->next) { if (!t->track->recomputeLength()) return false; } update(); return true; } // Sets catalog number. 's' must be a string of 13 digits. // return: 0: OK // 1: illegal catalog string int Toc::catalog(const char *s) { int i; if (s == NULL) { catalogValid_ = 0; return 0; } if (strlen(s) != 13) { return 1; } for (i = 0; i < 13; i++) { if (!isdigit(s[i])) return 1; } for (i = 0; i < 13; i++) catalog_[i] = s[i] - '0'; catalogValid_ = 1; return 0; } const char *Toc::catalog() const { static char buf[14]; int i; if (!catalogValid_) return NULL; for (i = 0; i < 13; i++) buf[i] = catalog_[i] + '0'; buf[13] = 0; return buf; } // writes contents in TOC file syntax void Toc::print(std::ostream &out, PrintParams& params) const { int i; TrackEntry *t; out << tocType2String(tocType()) << "\n\n"; if (catalogValid()) { out << "CATALOG \""; for (i = 0; i < 13; i++) { out << (char)(catalog(i) + '0'); } out << "\"" << std::endl; } cdtext_.print(0, out, params); for (t = tracks_, i = 1; t != NULL; t = t->next, i++) { out << "\n// Track " << i << "\n"; t->track->print(out, params); out << std::endl; } } bool Toc::convertFilesToWav() { FormatSupport::Status status = formatConverter.convert(this); return (status == FormatSupport::FS_SUCCESS); } void Toc::collectFiles(std::set& set) { for (TrackEntry* t = tracks_; t != NULL; t = t->next) t->track->collectFiles(set); } void Toc::markFileConversion(const char* src, const char* dst) { for (TrackEntry* t = tracks_; t != NULL; t = t->next) t->track->markFileConversion(src, dst); } // find track entry that contains given sample number // return: found track entry or 'NULL' if sample is out of range Toc::TrackEntry *Toc::findTrack(unsigned long sample) const { TrackEntry *run; for (run = tracks_; run != NULL; run = run->next) { if (sample < run->end.samples()) return run; } return NULL; } // find track with given number // return: found track entry or 'NULL' if 'trackNr' is out of range Toc::TrackEntry *Toc::findTrackByNumber(int trackNr) const { TrackEntry *run; for (run = tracks_; run != NULL; run = run->next) { if (run->trackNr == trackNr) return run; } return NULL; } Track *Toc::getTrack(int trackNr) { TrackEntry *ent = findTrackByNumber(trackNr); if (ent != NULL) return ent->track; else return NULL; } // Moves specified track/index position to given LBA if possible. // return: 0: OK // 1: Cannot move pre-gap of first track // 2: specified track/index position not found in toc // 3: 'lba' is an illegal position for track/index mark // 4: resulting track length would be short than 4 seconds // 5: cannot cross track/index boundaries // 6: cannot modify data track int Toc::moveTrackMarker(int trackNr, int indexNr, long lba) { TrackEntry *act; if (trackNr == 1 && indexNr == 0) return 1; if ((act = findTrackByNumber(trackNr)) == NULL) { return 2; } if (indexNr <= 1 && (act->track->type() != TrackData::AUDIO || act->track->subChannelType() != TrackData::SUBCHAN_NONE)) return 6; if ((indexNr == 0 || (indexNr == 1 && act->track->start().lba() == 0)) && act->pred != NULL && (act->pred->track->type() != TrackData::AUDIO || act->track->subChannelType() != TrackData::SUBCHAN_NONE)) return 6; if (indexNr == 0 && act->track->start().lba() == 0) return 2; if (indexNr > 1 && indexNr - 2 >= act->track->nofIndices()) return 2; if (lba < 0 || lba >= length().lba()) return 3; if ((indexNr == 1 && (act->track->start().lba() > 0 || trackNr == 1)) || indexNr > 1) { // change track/index position within track if (indexNr == 1) { if (lba > act->end.lba() - 4 * 75) return 4; if (lba <= act->absStart.lba() && trackNr > 1) return 3; } else { if (lba - act->absStart.lba() <= 0) return 3; } switch (act->track->moveIndex(indexNr, lba - act->absStart.lba())) { case 1: return 4; case 2: return 5; } } else { // move track start position, we need to shift audio data from // on track to the other // 'act->pred' is always non NULL in this case because track 1 is // exhaustively handled above TrackDataList *dataList; // audio data that is removed from one track if (lba < act->absStart.lba()) { // move to the left if (lba < act->pred->start.lba() + 4 * 75) return 4; dataList = act->pred->track->removeToEnd(Msf(lba - act->pred->absStart.lba()).samples()); act->track->prependTrackData(dataList); delete dataList; // adjust start of track act->track->start(Msf(act->start.lba() - lba)); if (indexNr == 1) act->track->moveIndex(1, 0); // remove intermediate pre-gap } else if (lba > act->absStart.lba()) { // move to the right if (indexNr == 1) { // introduce an intermediate pre-gap that adjusts the index // increments switch (act->track->moveIndex(1, lba - act->absStart.lba())) { case 1: return 4; case 2: return 5; } // remove intermediate pre-gap act->track->start(Msf(0)); } else { // adjust pre-gap if (lba >= act->start.lba()) return 5; act->track->start(Msf(act->start.lba() - lba)); } dataList = act->track->removeFromStart(Msf(lba - act->absStart.lba()).samples()); act->pred->track->appendTrackData(dataList); delete dataList; } } update(); checkConsistency(); return 0; } void Toc::remove(TrackEntry *ent) { if (ent->pred != NULL) ent->pred->next = ent->next; else tracks_ = ent->next; if (ent->next != NULL) ent->next->pred = ent->pred; else lastTrack_ = ent->pred; ent->pred = ent->next = NULL; ent->track = NULL; delete ent; } // Removes specified track marker. // return: 0: OK // 1: cannot remove first track // 2: specified track/index position not found in toc // 3: cannot modify a data track int Toc::removeTrackMarker(int trackNr, int indexNr) { TrackEntry *act; if (trackNr == 1 && indexNr == 1) return 1; if ((act = findTrackByNumber(trackNr)) == NULL) { return 2; } if ((act->track->type() != TrackData::AUDIO || act->track->subChannelType() != TrackData::SUBCHAN_NONE) && indexNr <= 1) return 3; if (act->pred != NULL && (act->pred->track->type() != TrackData::AUDIO || act->track->subChannelType() != TrackData::SUBCHAN_NONE) && indexNr <= 1) return 3; if (trackNr == 1 && indexNr == 0) { // pre-gap of first track if (act->start.lba() == 0) return 2; // no pre-gap act->track->start(Msf(0)); } else if (indexNr > 1) { // index increment if (act->track->removeIndex(indexNr - 2) != 0) return 2; } else if (indexNr == 0) { // remove pre-gap, audio data of pre-gap is appended to previous track unsigned long len = act->track->start().samples(); if (len == 0) return 2; // track has no pre-gap act->track->start(Msf(0)); TrackDataList *dataList = act->track->removeFromStart(len); act->pred->track->appendTrackData(dataList); delete dataList; } else { // index == 1, remove track completely act->pred->track->appendTrackData(act->track); Track *store = act->track; remove(act); delete store; nofTracks_--; } update(); checkConsistency(); return 0; } // Adds index increment at given LBA. // return: 0: OK // 1: LBA out of range // 2: cannot add index at this position // 3: more than 98 index increments int Toc::addIndexMarker(long lba) { TrackEntry *act = findTrack(Msf(lba).samples()); if (act == NULL) return 1; if (lba <= act->start.lba()) return 2; switch (act->track->addIndex(Msf(lba - act->start.lba()))) { case 1: return 3; case 2: return 2; } return 0; } // Adds a track marker at given LBA. // return: 0: OK // 1: LBA out of range // 2: cannot add track at this position // 3: resulting track would be shorter than 4 seconds // 4: previous track would be short than 4 seconds // 5: cannot modify a data track int Toc::addTrackMarker(long lba) { TrackEntry *act = findTrack(Msf(lba).samples()); if (act == NULL) return 1; if (act->track->type() != TrackData::AUDIO) return 5; if (act->track->subChannelType() != TrackData::SUBCHAN_NONE) return 5; if (lba <= act->start.lba()) return 2; if (lba - act->start.lba() < 4 * 75) return 4; if (act->end.lba() - lba < 4 * 75) return 3; TrackDataList *dataList = act->track->removeToEnd(Msf(lba - act->absStart.lba()).samples()); Track *t = new Track(act->track->type(), act->track->subChannelType()); t->appendTrackData(dataList); delete dataList; TrackEntry *ent = new TrackEntry; ent->track = t; ent->next = act->next; if (ent->next != NULL) ent->next->pred = ent; ent->pred = act; act->next = ent; if (act == lastTrack_) lastTrack_ = ent; nofTracks_++; update(); checkConsistency(); return 0; } // Adds pre-gap add given LBA. // return: 0: OK // 1: LBA out of range // 2: cannot add pre-gap at this point // 3: actual track would be shorter than 4 seconds // 4: cannot modify a data track int Toc::addPregap(long lba) { TrackEntry *act = findTrack(Msf(lba).samples()); if (act == NULL) return 1; if (act->track->type() != TrackData::AUDIO) return 4; if (act->track->subChannelType() != TrackData::SUBCHAN_NONE) return 4; if (act->next == NULL) return 2; // no next track where we could add pre-gap if (act->next->track->type() != act->track->type() || act->next->track->subChannelType() != act->track->subChannelType()) return 4; if (lba <= act->start.lba()) return 2; if (act->next->track->start().lba() != 0) return 2; // track has already a pre-gap if (lba - act->start.lba() < 4 * 75) return 3; TrackDataList *dataList = act->track->removeToEnd(Msf(lba - act->absStart.lba()).samples()); act->next->track->prependTrackData(dataList); delete dataList; act->next->track->start(Msf(act->next->start.lba() - lba)); update(); checkConsistency(); return 0; } void Toc::fixLengths() { TrackEntry* te; int i; for (i = 0 , te = tracks_; te; te = te->next, i++) { printf("%d : Track %d\n", i, te->trackNr); } } void Toc::checkConsistency() { TrackEntry *run, *last = NULL; long cnt = 0; for (run = tracks_; run != NULL; last = run, run = run->next) { cnt++; if (run->pred != last) log_message(-3, "Toc::checkConsistency: wrong pred pointer."); run->track->checkConsistency(); } if (last != lastTrack_) log_message(-3, "Toc::checkConsistency: wrong last pointer."); if (cnt != nofTracks_) log_message(-3, "Toc::checkConsistency: wrong sub track counter."); } // Appends a track with given audio data. 'start' is filled with // first LBA of new track, 'end' is filled with last LBA + 1 of new track. void Toc::appendTrack(const TrackDataList *list, long *start, long *end) { Track t(TrackData::AUDIO, TrackData::SUBCHAN_NONE); const TrackData *run; for (run = list->first(); run != NULL; run = list->next()) t.append(SubTrack(SubTrack::DATA, *run)); // ensure that track lasts at least 4 seconds unsigned long minTime = 4 * 75 * SAMPLES_PER_BLOCK; // 4 seconds unsigned long len = list->length(); if (len < minTime) t.append(SubTrack(SubTrack::DATA, TrackData(minTime - len))); *start = length().lba(); append(&t); checkConsistency(); *end = length().lba(); } // Appends given audio data to last track. If no track exists 'appendTrack' // will be called. 'start' and 'end' is filled with position of modified // region. // Return: 0: OK // 1: cannot modify a data track int Toc::appendTrackData(const TrackDataList *list, long *start, long *end) { const TrackData *run; if (lastTrack_ == NULL) { appendTrack(list, start, end); return 0; } if (lastTrack_->track->type() != TrackData::AUDIO) return 1; if (lastTrack_->track->subChannelType() != TrackData::SUBCHAN_NONE) return 1; *start = length().lba(); for (run = list->first(); run != NULL; run = list->next()) lastTrack_->track->append(SubTrack(SubTrack::DATA, *run)); update(); checkConsistency(); *end = length().lba(); return 0; } // Removes specified range of samples from a single track. // Return: 0: OK // 1: samples range covers more than one track // 2: cannot modify a data track // 3: illegal 'start' position int Toc::removeTrackData(unsigned long start, unsigned long end, TrackDataList **list) { TrackEntry *tent = findTrack(start); if (tent == NULL) return 3; if (tent->track->type() != TrackData::AUDIO) return 2; if (tent->track->subChannelType() != TrackData::SUBCHAN_NONE) return 2; if (tent != findTrack(end)) return 1; *list = tent->track->removeTrackData(start - tent->absStart.samples(), end - tent->absStart.samples()); update(); checkConsistency(); return 0; } // Inserts given track data at specified postion. // Return: 0: OK // 1: cannot modify a data track int Toc::insertTrackData(unsigned long pos, const TrackDataList *list) { TrackEntry *tent = findTrack(pos); if (tent != NULL && tent->track->type() != TrackData::AUDIO) return 1; if (tent != NULL && tent->track->subChannelType() != TrackData::SUBCHAN_NONE) return 1; if (tent != NULL) { tent->track->insertTrackData(pos - tent->absStart.samples(), list); update(); checkConsistency(); return 0; } else { long start, end; return appendTrackData(list, &start, &end); } } // Returns mode that should be used for lead-in. The mode of first track's // first sub-track is used. TrackData::Mode Toc::leadInMode() const { const SubTrack *t; if (tracks_ == NULL || (t = tracks_->track->firstSubTrack()) == NULL) { // no track or track data available - return AUDIO in this case return TrackData::AUDIO; } return t->mode(); } // Returns mode that should be used for lead-out. The mode of last track's // last sub-track is used TrackData::Mode Toc::leadOutMode() const { const SubTrack *t; if (lastTrack_ == NULL || (t = lastTrack_->track->lastSubTrack()) == NULL) { // no track or track data available - return AUDIO in this case return TrackData::AUDIO; } return t->mode(); } const char *Toc::tocType2String(Type t) { const char *ret = NULL; switch (t) { case Type::CD_DA: ret = "CD_DA"; break; case Type::CD_ROM: ret = "CD_ROM"; break; case Type::CD_I: ret = "CD_I"; break; case Type::CD_ROM_XA: ret = "CD_ROM_XA"; break; } return ret; } void Toc::addCdTextItem(int trackNr, CdTextItem *item) { assert(trackNr >= 0 && trackNr <= 99); if (cdtext_.encoding(item->blockNr()) != Util::Encoding::UNSET) item->encoding(cdtext_.encoding(item->blockNr())); if (trackNr == 0) { cdtext_.add(item); } else { item->trackNr(trackNr); TrackEntry *track = findTrackByNumber(trackNr); if (track == NULL) { log_message(-3, "addCdTextItem: Track %d is not available.", trackNr); return; } track->track->addCdTextItem(item); } } void Toc::removeCdTextItem(int trackNr, CdTextItem::PackType type, int blockNr) { assert(trackNr >= 0 && trackNr <= 99); if (trackNr == 0) { cdtext_.remove(type, blockNr); } else { TrackEntry *track = findTrackByNumber(trackNr); if (track == NULL) { log_message(-3, "addCdTextItem: Track %d is not available.", trackNr); return; } track->track->removeCdTextItem(type, blockNr); } } int Toc::existCdTextBlock(int blockNr) const { if (cdtext_.existBlock(blockNr)) return 1; for (auto run = tracks_; run != NULL; run = run->next) { if (run->track->existCdTextBlock(blockNr)) return 1; } return 0; } const CdTextItem *Toc::getCdTextItem(int trackNr, int blockNr, CdTextItem::PackType type) const { if (trackNr == 0) { return cdtext_.getPack(blockNr, type); } TrackEntry *track = findTrackByNumber(trackNr); if (track == NULL) return NULL; return track->track->getCdTextItem(blockNr, type); } void Toc::cdTextLanguage(int blockNr, int lang) { cdtext_.language(blockNr, lang); } int Toc::cdTextLanguage(int blockNr) const { return cdtext_.language(blockNr); } void Toc::cdTextEncoding(int blockNr, Util::Encoding t) { cdtext_.encoding(blockNr, t); } Util::Encoding Toc::cdTextEncoding(int blockNr) const { return cdtext_.encoding(blockNr); } void Toc::enforceTextEncoding() { cdtext_.enforceEncoding(&cdtext_); for (auto run = tracks_; run; run = run ->next) { run->track->cdtext_.enforceEncoding(&cdtext_); } } // Check the consistency of the CD-TEXT data. // Return: 0: OK // 1: at least one warning occured // 2: at least one error occured int Toc::checkCdTextData() const { TrackEntry *trun; int err = 0; int l; int last; int titleCnt, performerCnt, songwriterCnt, composerCnt, arrangerCnt; int messageCnt, isrcCnt, genreCnt; int languageCnt = 0; genreCnt = 0; // Check if language numbers are continuously used starting at 0 for (l = 0, last = -1; l <= 7; l++) { if (cdTextLanguage(l) >= 0) { languageCnt++; if (cdtext_.getPack(l, CdTextItem::PackType::GENRE) != NULL) genreCnt++; if (l - 1 != last) { if (last == -1) log_message(-2, "CD-TEXT: Language number %d: Language numbers must start at 0.", l); else log_message(-2, "CD-TEXT: Language number %d: Language numbers are not continuously used.", l); if (err < 2) err = 2; } last = l; } } if (genreCnt > 0 && genreCnt != languageCnt) { log_message(-1, "CD-TEXT: %s field not defined for all languages.", CdTextItem::packType2String(1, CdTextItem::PackType::GENRE)); if (err < 1) err = 1; } for (l = 0, last = -1; l <= 7; l++) { if (cdTextLanguage(l) < 0) continue; titleCnt = (cdtext_.getPack(l, CdTextItem::PackType::TITLE) != NULL) ? 1 : 0; performerCnt = (cdtext_.getPack(l, CdTextItem::PackType::PERFORMER) != NULL) ? 1 : 0; songwriterCnt = (cdtext_.getPack(l, CdTextItem::PackType::SONGWRITER) != NULL) ? 1 : 0; composerCnt = (cdtext_.getPack(l, CdTextItem::PackType::COMPOSER) != NULL) ? 1 : 0; arrangerCnt = (cdtext_.getPack(l, CdTextItem::PackType::ARRANGER) != NULL) ? 1 : 0; messageCnt = (cdtext_.getPack(l, CdTextItem::PackType::MESSAGE) != NULL) ? 1 : 0; isrcCnt = 0; for (trun = tracks_; trun != NULL; trun = trun->next) { if (trun->track->getCdTextItem(l, CdTextItem::PackType::TITLE) != NULL) titleCnt++; if (trun->track->getCdTextItem(l, CdTextItem::PackType::PERFORMER) != NULL) performerCnt++; if (trun->track->getCdTextItem(l, CdTextItem::PackType::SONGWRITER) != NULL) songwriterCnt++; if (trun->track->getCdTextItem(l, CdTextItem::PackType::COMPOSER) != NULL) composerCnt++; if (trun->track->getCdTextItem(l, CdTextItem::PackType::ARRANGER) != NULL) arrangerCnt++; if (trun->track->getCdTextItem(l, CdTextItem::PackType::MESSAGE) != NULL) messageCnt++; if (trun->track->getCdTextItem(l, CdTextItem::PackType::UPCEAN_ISRC) != NULL) isrcCnt++; } if (titleCnt > 0 && titleCnt != nofTracks_ + 1) { log_message(-2, "CD-TEXT: Language %d: %s field not defined for all tracks or disk.", l, CdTextItem::packType2String(1, CdTextItem::PackType::TITLE)); if (err < 2) err = 2; } else if (titleCnt == 0) { log_message(-1, "CD-TEXT: Language %d: %s field is not defined.", l, CdTextItem::packType2String(1, CdTextItem::PackType::TITLE)); if (err < 1) err = 1; } if (performerCnt > 0 && performerCnt != nofTracks_ + 1) { log_message(-2, "CD-TEXT: Language %d: %s field not defined for all tracks or disk.", l, CdTextItem::packType2String(1, CdTextItem::PackType::PERFORMER)); if (err < 2) err = 2; } else if (performerCnt == 0) { log_message(-1, "CD-TEXT: Language %d: %s field is not defined.", l, CdTextItem::packType2String(1, CdTextItem::PackType::PERFORMER)); if (err < 1) err = 1; } if (songwriterCnt > 0 && songwriterCnt != nofTracks_ + 1) { log_message(-2, "CD-TEXT: Language %d: %s field not defined for all tracks or disk.", l, CdTextItem::packType2String(1, CdTextItem::PackType::SONGWRITER)); if (err < 2) err = 2; } if (composerCnt > 0 && composerCnt != nofTracks_ + 1) { log_message(-2, "CD-TEXT: Language %d: %s field not defined for all tracks or disk.", l, CdTextItem::packType2String(1, CdTextItem::PackType::COMPOSER)); if (err < 2) err = 2; } if (arrangerCnt > 0 && arrangerCnt != nofTracks_ + 1) { log_message(-2, "CD-TEXT: Language %d: %s field not defined for all tracks or disk.", l, CdTextItem::packType2String(1, CdTextItem::PackType::ARRANGER)); if (err < 2) err = 2; } if (messageCnt > 0 && messageCnt != nofTracks_ + 1) { log_message(-2, "CD-TEXT: Language %d: %s field not defined for all tracks or disk.", l, CdTextItem::packType2String(1, CdTextItem::PackType::MESSAGE)); if (err < 2) err = 2; } if ((isrcCnt > 0 && isrcCnt != nofTracks_) || (isrcCnt == 0 && cdtext_.getPack(l, CdTextItem::PackType::UPCEAN_ISRC) != NULL)) { log_message(-2, "CD-TEXT: Language %d: %s field not defined for all tracks.", l, CdTextItem::packType2String(1, CdTextItem::PackType::UPCEAN_ISRC)); if (err < 2) err = 2; } } return err; } void Toc::trackSummary(int *nofAudioTracks, int *nofMode1Tracks, int *nofMode2Tracks) const { TrackEntry *run; if (nofAudioTracks != NULL) *nofAudioTracks = 0; if (nofMode1Tracks != NULL) *nofMode1Tracks = 0; if (nofMode2Tracks != NULL) *nofMode2Tracks = 0; for (run = tracks_; run != NULL; run = run->next) { switch (run->track->type()) { case TrackData::AUDIO: if (nofAudioTracks != NULL) *nofAudioTracks += 1; break; case TrackData::MODE1: case TrackData::MODE1_RAW: if (nofMode1Tracks != NULL) *nofMode1Tracks += 1; break; case TrackData::MODE2: case TrackData::MODE2_FORM1: case TrackData::MODE2_FORM2: case TrackData::MODE2_FORM_MIX: case TrackData::MODE2_RAW: if (nofMode2Tracks != NULL) *nofMode2Tracks += 1; break; case TrackData::MODE0: break; } } } // Class TrackIterator TrackIterator::TrackIterator(const Toc *t) { toc_ = t; iterator_ = NULL; } TrackIterator::~TrackIterator() { toc_ = NULL; iterator_ = NULL; } const Track *TrackIterator::find(int trackNr, Msf &start, Msf &end) { Track *t; iterator_ = toc_->findTrackByNumber(trackNr); if (iterator_ != NULL) { start = iterator_->start; end = iterator_->end; t = iterator_->track; iterator_ = iterator_->next; return t; } return NULL; } const Track *TrackIterator::find(unsigned long sample, Msf &start, Msf &end, int *trackNr) { Track *t; iterator_ = toc_->findTrack(sample); if (iterator_ != NULL) { start = iterator_->start; end = iterator_->end; *trackNr = iterator_->trackNr; t = iterator_->track; iterator_ = iterator_->next; return t; } return NULL; } const Track *TrackIterator::first(Msf &start, Msf &end) { iterator_ = toc_->tracks_; return next(start, end); } const Track *TrackIterator::first() { Msf start, end; return first(start, end); } const Track *TrackIterator::next(Msf &start, Msf &end) { Track *t; if (iterator_ != NULL) { start = iterator_->start; end = iterator_->end; t = iterator_->track; iterator_ = iterator_->next; return t; } else { return NULL; } } const Track *TrackIterator::next() { Msf start, end; return next(start, end); } // Class TocReader TocReader::TocReader(const Toc *t) : reader(NULL) { toc_ = t; readTrack_ = NULL; readPos_ = 0; readPosSample_ = 0; open_ = 0; } TocReader::~TocReader () { if (open_) { closeData(); } toc_ = NULL; readTrack_ = NULL; } void TocReader::init(const Toc *t) { if (open_) { closeData(); } reader.init(NULL); toc_ = t; readTrack_ = NULL; } int TocReader::openData() { int ret = 0; assert(open_ == 0); assert(toc_ != NULL); readTrack_ = toc_->tracks_; readPos_ = 0; readPosSample_ = 0; reader.init(readTrack_->track); if (readTrack_ != NULL) { ret = reader.openData(); } open_ = 1; return ret; } void TocReader::closeData() { if (open_ != 0) { reader.closeData(); readTrack_ = NULL; readPos_ = 0; open_ = 0; readPosSample_ = 0; } } #if 0 long TocReader::readData(long lba, char *buf, long len) { long n; long nread = 0; assert(open_ != 0); if (readPos_ + len > toc_->length_.lba()) { if ((len = toc_->length_.lba() - readPos_) <= 0) { return 0; } } do { n = reader.readData(0, lba, buf + (nread * AUDIO_BLOCK_LEN), len); if (n < 0) { return -1; } lba += n; if (n != len) { // skip to next track readTrack_ = readTrack_->next; assert(readTrack_ != NULL); reader.init(readTrack_->track); if (reader.openData() != 0) { return -1; } } nread += n; len -= n; } while (len > 0); readPos_ += nread; return nread; } #endif // seeks to specified sample (absolute position) // return: 0: OK // 10: sample position out of range // return codes from 'Track::openData()' int TocReader::seekSample(unsigned long sample) { int ret; assert(open_ != 0); // find track that contains 'sample' Toc::TrackEntry *tr = toc_->findTrack(sample); if (tr == NULL) return 10; // open track if necessary if (tr != readTrack_) { readTrack_ = tr; reader.init(readTrack_->track); if ((ret = reader.openData() != 0)) return ret; } assert(sample >= readTrack_->absStart.samples()); unsigned long offset = sample - readTrack_->absStart.samples(); // seek in track if ((ret = reader.seekSample(offset)) != 0) return ret; readPosSample_ = sample; return 0; } long TocReader::readSamples(Sample *buf, long len) { long n; long nread = 0; assert(open_ != 0); if (readPosSample_ + (unsigned long)len > toc_->length_.samples()) { if ((len = toc_->length_.samples() - readPosSample_) <= 0) return 0; } do { n = reader.readSamples(buf + nread , len); if (n < 0) return -1; if (n != len) { // skip to next track readTrack_ = readTrack_->next; reader.init(readTrack_->track); assert(readTrack_ != NULL); if (reader.openData() != 0) { return -1; } } nread += n; len -= n; } while (len > 0); readPosSample_ += nread; return nread; } const char* TocReader::curFilename() { return reader.curFilename(); } cdrdao-cdrdao-f00afb2/trackdb/Toc.h000066400000000000000000000155621511453746600172170ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller * * 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. */ #ifndef __TOC_H__ #define __TOC_H__ #include #include #include #include #include #include "util.h" #include "Track.h" #include "CdTextContainer.h" #include "CdTextItem.h" class Toc { public: Toc(); Toc(const Toc &); ~Toc(); enum class Type { CD_DA, CD_ROM, CD_I, CD_ROM_XA }; // sets/returns toc type void tocType(Type); Type tocType() const; void firstTrackNo(int i) { firstTrackNo_ = i; } int firstTrackNo() const { return firstTrackNo_; } int nofTracks() const { return nofTracks_; } Msf length() const { return length_; } // returns mode that should be used for lead-in and gap TrackData::Mode leadInMode() const; // returns mode that should be used for lead-out TrackData::Mode leadOutMode() const; int append(const Track *); void insert(int, const Track *); void remove(int); Track *getTrack(int trackNr); int moveTrackMarker(int trackNr, int indexNr, long lba); int removeTrackMarker(int trackNr, int indexNr); int addIndexMarker(long lba); int addTrackMarker(long lba); int addPregap(long lba); void appendTrack(const TrackDataList *, long *start, long *end); int appendTrackData(const TrackDataList *, long *start, long *end); int removeTrackData(unsigned long start, unsigned long end, TrackDataList **); int insertTrackData(unsigned long pos, const TrackDataList *list); static Toc *read(const std::string&); int write(const std::string&, bool conversions = false) const; int catalogValid() const { return catalogValid_; } int catalog(const char *); // sets catalog number char catalog(int i) const { return catalog_[i]; } // BCD const char *catalog() const; void addCdTextItem(int trackNr, CdTextItem *); void removeCdTextItem(int trackNr, CdTextItem::PackType, int blockNr); int existCdTextBlock(int blockNr) const; const CdTextItem *getCdTextItem(int trackNr, int blockNr, CdTextItem::PackType) const; int nofCdTextItems() { return cdtext_.count(); } CdTextContainer& globalCdTextItems() { return cdtext_; } void cdTextLanguage(int blockNr, int lang); int cdTextLanguage(int blockNr) const; void cdTextEncoding(int blockNr, Util::Encoding t); Util::Encoding cdTextEncoding(int blockNr) const; void enforceTextEncoding(); void trackSummary(int *nofAudioTracks, int *nofMode1Tracks, int *nofMode2Tracks) const; // Verification methods bool resolveFilenames(const char* tocFilename); int check() const; int checkCdTextData() const; bool convertFilesToWav(); bool recomputeLength(); // if conversions is true, the TOc is printed with the converted WAV // or RAW filenames instead of the original ones. void print(std::ostream &, PrintParams& params) const; void collectFiles(std::set& list); void markFileConversion(const char* src, const char* dst); static const char *tocType2String(Type); private: struct TrackEntry { TrackEntry() : absStart(0), start(0), end(0) { trackNr = 0; track = 0; next = 0; pred = 0; } int trackNr; Track *track; Msf absStart; // absoulte track start (end of last track) Msf start; // logical track start (after pre-gap) Msf end; struct TrackEntry *next; struct TrackEntry *pred; }; public: // Allow iterations over tracks struct Iterator { using iterator_category = std::bidirectional_iterator_tag; using difference_type = std::ptrdiff_t; using value_type = Track; using pointer = TrackEntry*; using reference= Track&; Iterator(pointer item) : m_ptr(item) {} friend bool operator==(const Iterator& a, const Iterator& b) { return a.m_ptr == b.m_ptr; } friend bool operator!=(const Iterator& a, const Iterator& b) { return a.m_ptr != b.m_ptr; } Iterator& operator++() { m_ptr = m_ptr->next; return *this; } Iterator& operator--() { m_ptr = m_ptr->pred; return *this; } reference operator*() const { return *(m_ptr->track); } pointer m_ptr; }; Iterator begin() { return Iterator(tracks_); } Iterator end() { return Iterator(lastTrack_); } private: friend class TocImpl; friend class TocParserGram; friend class TocReader; friend class TrackIterator; void update(); TrackEntry *findTrack(unsigned long sample) const; TrackEntry *findTrackByNumber(int trackNr) const; void remove(TrackEntry *); void fixLengths(); void checkConsistency(); Toc::Type tocType_; // type of TOC int nofTracks_, firstTrackNo_; TrackEntry *tracks_; TrackEntry *lastTrack_; Msf length_; // total length of disc char catalog_[13]; int catalogValid_; CdTextContainer cdtext_; }; class TocReader { public: TocReader(const Toc * = 0); ~TocReader(); void init(const Toc *); int openData(); //long readData(long lba, char *buf, long len); int seekSample(unsigned long sample); long readSamples(Sample *buf, long len); void closeData(); const char* curFilename(); private: const Toc *toc_; TrackReader reader; const Toc::TrackEntry *readTrack_; // actual read track long readPos_; // actual read position (blocks) long readPosSample_; // actual read position (samples) int open_; // != 0 indicates that toc was opened for reading data }; class TrackIterator { public: TrackIterator(const Toc *); ~TrackIterator(); const Track *find(int trackNr, Msf &start, Msf &end); const Track *find(unsigned long sample, Msf &start, Msf &end, int *trackNr); const Track *first(Msf &start, Msf &end); const Track *first(); const Track *next(Msf &start, Msf &end); const Track *next(); private: const Toc *toc_; Toc::TrackEntry *iterator_; }; inline void Toc::tocType(Type t) { tocType_ = t; } inline Toc::Type Toc::tocType() const { return tocType_; } #endif cdrdao-cdrdao-f00afb2/trackdb/TocParser.g000066400000000000000000000660441511453746600203740ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller * * 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. */ #header << #include #include #include #include "Toc.h" #include "util.h" #include "log.h" #include "CdTextItem.h" >> << #include "CdTextContainer.h" #include "TocLexerBase.h" // Maximum length of binary data for CD-TEXT #define MAX_CD_TEXT_DATA_LEN (256 * 12) /* Use 'ANTLRCommonToken' as 'ANTLRToken' to be compatible with some bug * fix releases of PCCTS-1.33. The drawback is that the token length is * limited to 100 characters. This might be a problem for long file names. * Define 'USE_ANTLRCommonToken' to 0 if you want to use the dynamic token * which handles arbitrary token lengths (there'll be still a limitation in * the lexer code but that's more than 100 characters). In this case it might * be necessary to adjust the types of the member functions to the types in * 'ANTLRAbstractToken' defined in PCCTSDIR/h/AToken.h'. */ #define USE_ANTLRCommonToken 0 #if USE_ANTLRCommonToken typedef ANTLRCommonToken ANTLRToken; #else class ANTLRToken : public ANTLRRefCountToken { private: ANTLRTokenType type_; int line_; ANTLRChar *text_; public: ANTLRToken(ANTLRTokenType t, ANTLRChar *s) : ANTLRRefCountToken(t, s) { setType(t); line_ = 0; setText(s); } ANTLRToken() { setType((ANTLRTokenType)0); line_ = 0; setText(""); } virtual ~ANTLRToken() { delete[] text_; } #if 0 // use this for basic PCCTS-1.33 release ANTLRTokenType getType() { return type_; } virtual int getLine() { return line_; } ANTLRChar *getText() { return text_; } void setText(ANTLRChar *s) { text_ = strdupCC(s); } #else // use this for PCCTS-1.33 bug fix releases ANTLRTokenType getType() const { return type_; } virtual int getLine() const { return line_; } ANTLRChar *getText() const { return text_; } void setText(const ANTLRChar *s) { text_ = strdupCC(s); } #endif void setType(ANTLRTokenType t) { type_ = t; } void setLine(int line) { line_ = line; } virtual ANTLRAbstractToken *makeToken(ANTLRTokenType tt, ANTLRChar *txt, int line) { ANTLRAbstractToken *t = new ANTLRToken(tt,txt); t->setLine(line); return t; } }; #endif >> << class TocLexer : public TocLexerBase { public: TocLexer(DLGInputStream *in, unsigned bufsize=2000) : TocLexerBase(in, bufsize) { parser_ = NULL; } virtual ANTLRTokenType erraction(); TocParserGram *parser_; }; >> #lexclass START #token Eof "@" #token "[\t\r\ ]+" << skip(); >> #token Comment "//~[\n@]*" << skip(); >> #token "\n" << newline(); skip(); >> #token BeginString "\"" << mode(STRING); >> #token Integer "[0-9]+" #token TrackDef "TRACK" #token FirstTrackNo "FIRST_TRACK_NO" #token Audio "AUDIO" #token Mode0 "MODE0" #token Mode1 "MODE1" #token Mode1Raw "MODE1_RAW" #token Mode2 "MODE2" #token Mode2Raw "MODE2_RAW" #token Mode2Form1 "MODE2_FORM1" #token Mode2Form2 "MODE2_FORM2" #token Mode2FormMix "MODE2_FORM_MIX" #token SubChanRw "RW" #token SubChanRwRaw "RW_RAW" #token Index "INDEX" #token Catalog "CATALOG" #token Isrc "ISRC" #token No "NO" #token Copy "COPY" #token PreEmphasis "PRE_EMPHASIS" #token TwoChannel "TWO_CHANNEL_AUDIO" #token FourChannel "FOUR_CHANNEL_AUDIO" #tokclass AudioFile { "AUDIOFILE" "FILE" } #token DataFile "DATAFILE" #token Fifo "FIFO" #token Silence "SILENCE" #token Zero "ZERO" #token Pregap "PREGAP" #token Start "START" #token End "END" #token TocTypeCdda "CD_DA" #token TocTypeCdrom "CD_ROM" #token TocTypeCdromXa "CD_ROM_XA" #token TocTypeCdi "CD_I" #token Swap "SWAP" #token CdText "CD_TEXT" #token Language "LANGUAGE" #token LanguageMap "LANGUAGE_MAP" #token Title "TITLE" #token Performer "PERFORMER" #token Songwriter "SONGWRITER" #token Composer "COMPOSER" #token Arranger "ARRANGER" #token Message "MESSAGE" #token DiscId "DISC_ID" #token Genre "GENRE" #token TocInfo1 "TOC_INFO1" #token TocInfo2 "TOC_INFO2" #token Reserved1 "RESERVED1" #token Reserved2 "RESERVED2" #token Reserved3 "RESERVED3" #token Reserved4 "RESERVED4" #token Closed "CLOSED" #token UpcEan "UPC_EAN" #token SizeInfo "SIZE_INFO" #token LangEn "EN" #token EncodingLatin "ENCODING_ISO_8859_1" #token EncodingAscii "ENCODING_ASCII" #token EncodingJis "ENCODING_MS_JIS" #token EncodingKorean "ENCODING_KOREAN" #token EncodingMandarin "ENCODING_MANDARIN" #lexclass STRING #token EndString "\"" << mode(START); >> #token StringQuote "\\\"" #token StringBackslash "\\\\" #token StringOctal "\\[0-9][0-9][0-9]" #token String "[ ]+" #token String "~[\\\n\"\t ]*" #lexclass START class TocParserGram { << public: const char *filename_; int error_; void syn(_ANTLRTokenPtr tok, ANTLRChar *egroup, SetWordType *eset, ANTLRTokenType etok, int k); >> toc > [ Toc *t ] : << $t = new Toc; Track *tr = NULL; int lineNr = 0; std::string catalog; Toc::Type toctype; int firsttrack, firstLine; >> ( Catalog string > [ catalog ] << if (!catalog.empty()) { if ($t->catalog(catalog.c_str()) != 0) { log_message(-2, "%s:%d: Illegal catalog number: %s.\n", filename_, $1->getLine(), catalog.c_str()); error_ = 1; } } >> | tocType > [ toctype ] << $t->tocType(toctype); >> )* { FirstTrackNo integer > [ firsttrack, firstLine ] << if (firsttrack > 0 && firsttrack < 100) { $t->firstTrackNo(firsttrack); } else { log_message(-2, "%s:%d: Illegal track number: %d\n", filename_, firstLine, firsttrack); error_ = 1; } >> } { cdTextGlobal [ $t->cdtext_ ] } ( track > [ tr, lineNr ] << if (tr != NULL) { if ($t->append(tr) != 0) { log_message(-2, "%s:%d: First track must not have a pregap.\n", filename_, lineNr); error_ = 1; } delete tr, tr = NULL; } >> )+ << $t->enforceTextEncoding(); >> Eof ; // fail action << delete $t, $t = NULL; >> track > [ Track *tr, int lineNr ] : << $tr = NULL; $lineNr = 0; SubTrack *st = NULL; std::string isrcCode; TrackData::Mode trackType; TrackData::SubChannelMode subChanType = TrackData::SUBCHAN_NONE; Msf length; Msf indexIncrement; Msf pos; int posGiven = 0; Msf startPos; // end of pre-gap Msf endPos; // start if post-gap int startPosLine = 0; int endPosLine = 0; int lineNr = 0; int flag = 1; >> TrackDef << $lineNr = $1->getLine(); >> trackMode > [ trackType ] { subChannelMode > [ subChanType ] } << $tr = new Track(trackType, subChanType); >> ( Isrc string > [ isrcCode ] << if (!isrcCode.empty()) { if ($tr->isrc(isrcCode.c_str()) != 0) { log_message(-2, "%s:%d: Illegal ISRC code: %s.\n", filename_, $1->getLine(), isrcCode.c_str()); error_ = 1; } } >> | { No << flag = 0; >> } Copy << $tr->copyPermitted(flag); flag = 1; >> | { No << flag = 0; >> } PreEmphasis << $tr->preEmphasis(flag); flag = 1; >> | TwoChannel << $tr->audioType(0); >> | FourChannel << $tr->audioType(1); >> )* { cdTextTrack [ $tr->cdtext_ ] } { Pregap msf > [ length ] << if (length.lba() == 0) { log_message(-2, "%s:%d: Length of pregap is zero.\n", filename_, $1->getLine()); error_ = 1; } else { if (trackType == TrackData::AUDIO) { $tr->append(SubTrack(SubTrack::DATA, TrackData(length.samples()))); } else { $tr->append(SubTrack(SubTrack::DATA, TrackData(trackType, subChanType, length.lba() * TrackData::dataBlockSize(trackType, subChanType)))); } startPos = $tr->length(); startPosLine = $1->getLine(); } >> } ( subTrack [ trackType, subChanType ] > [ st, lineNr ] << if (st != NULL && $tr->append(*st) == 2) { log_message(-2, "%s:%d: Mixing of FILE/AUDIOFILE/SILENCE and DATAFILE/ZERO statements not allowed.", filename_, lineNr); log_message(-2, "%s:%d: PREGAP acts as SILENCE in audio tracks.", filename_, lineNr); error_ = 1; } delete st, st = NULL; >> | Start << posGiven = 0; >> { msf > [ pos ] << posGiven = 1; >> } << if (startPosLine != 0) { log_message(-2, "%s:%d: Track start (end of pre-gap) already defined.\n", filename_, $1->getLine()); error_ = 1; } else { if (!posGiven) { pos = $tr->length(); // retrieve current position } startPos = pos; startPosLine = $1->getLine(); } pos = Msf(0); >> | End << posGiven = 0; >> { msf > [ pos ] << posGiven = 1; >> } << if (endPosLine != 0) { log_message(-2, "%s:%d: Track end (start of post-gap) already defined.\n", filename_, $1->getLine()); error_ = 1; } else { if (!posGiven) { pos = $tr->length(); // retrieve current position } endPos = pos; endPosLine = $1->getLine(); } pos = Msf(0); >> )+ // set track start (end of pre-gap) and check for minimal track length << if (startPosLine != 0 && $tr->start(startPos) != 0) { log_message(-2, "%s:%d: START %s behind or at track end.\n", filename_, startPosLine, startPos.str()); error_ = 1; } >> ( Index msf > [ indexIncrement ] << if ($tr != NULL) { switch ($tr->appendIndex(indexIncrement)) { case 1: log_message(-2, "%s:%d: More than 98 index increments.\n", filename_, $1->getLine()); error_ = 1; break; case 2: log_message(-2, "%s:%d: Index beyond track end.\n", filename_, $1->getLine()); error_ = 1; break; case 3: log_message(-2, "%s:%d: Index at start of track.\n", filename_, $1->getLine()); error_ = 1; break; } } >> )* // set track end (start of post-gap) << if (endPosLine != 0) { switch ($tr->end(endPos)) { case 1: log_message(-2, "%s:%d: END %s behind or at track end.\n", filename_, endPosLine, endPos.str()); error_ = 1; break; case 2: log_message(-2, "%s:%d: END %s within pre-gap.\n", filename_, endPosLine, endPos.str()); error_ = 1; break; case 3: log_message(-2, "%s:%d: END %s: Cannot create index mark for post-gap.\n", filename_, endPosLine, endPos.str()); error_ = 1; break; } } >> ; // fail action << delete $tr, $tr = NULL; >> subTrack < [ TrackData::Mode trackType, TrackData::SubChannelMode subChanType ] > [ SubTrack *st, int lineNr ] : << $st = NULL; $lineNr = 0; std::string filename; unsigned long start = 0; unsigned long len = 0; long offset = 0; TrackData::Mode dMode; int swapSamples = 0; >> ( AudioFile string > [ filename ] { Swap << swapSamples = 1; >> } { "#" sLong > [ offset ] } samples > [start] { samples > [len] } << $st = new SubTrack(SubTrack::DATA, TrackData(filename.c_str(), offset, start, len)); $st->swapSamples(swapSamples); $lineNr = $1->getLine(); if (trackType != TrackData::AUDIO) { log_message(-2, "%s:%d: FILE/AUDIOFILE statements are only allowed for audio tracks.", filename_, $1->getLine()); error_ = 1; } if (subChanType != TrackData::SUBCHAN_NONE) { log_message(-2, "%s:%d: FILE/AUDIOFILE statements are only allowed for audio tracks without sub-channel mode.", filename_, $1->getLine()); error_ = 1; } >> | DataFile string > [ filename ] << dMode = $trackType; >> // { dataMode > [ dMode ] } { "#" sLong > [ offset ] } { dataLength [ dMode, $subChanType ] > [ len ] } << $st = new SubTrack(SubTrack::DATA, TrackData(dMode, $subChanType, filename.c_str(), offset, len)); $lineNr = $1->getLine(); >> | Fifo string > [ filename ] dataLength [$trackType, $subChanType ] > [ len ] << $st = new SubTrack(SubTrack::DATA, TrackData($trackType, $subChanType, filename.c_str(), len)); >> | Silence samples > [len] << $st = new SubTrack(SubTrack::DATA, TrackData(len)); $lineNr = $1->getLine(); if (len == 0) { log_message(-2, "%s:%d: Length of silence is 0.\n", filename_, $lineNr); error_ = 1; } if (trackType != TrackData::AUDIO) { log_message(-2, "%s:%d: SILENCE statements are only allowed for audio tracks.", filename_, $1->getLine()); error_ = 1; } if (subChanType != TrackData::SUBCHAN_NONE) { log_message(-2, "%s:%d: SILENCE statements are only allowed for audio tracks without sub-channel mode.", filename_, $1->getLine()); error_ = 1; } >> | Zero << dMode = $trackType; >> { dataMode > [ dMode ] } { subChannelMode > [ $subChanType ] } dataLength [ dMode, $subChanType ] > [ len ] << $st = new SubTrack(SubTrack::DATA, TrackData(dMode, $subChanType, len)); $lineNr = $1->getLine(); if (len == 0) { log_message(-2, "%s:%d: Length of zero data is 0.\n", filename_, $lineNr); error_ = 1; } >> ) << if ($st != NULL && $st->length() == 0) { // try to determine length if ($st->determineLength() != 0) { log_message(-2, "%s:%d: Cannot determine length of track data specification.", filename_, $lineNr); error_ = 1; } } >> ; // fail action << delete $st, $st = NULL; >> string > [ std::string ret ] : << int linenr = 0; bool is_utf8; >> BeginString << linenr = $1->getLine(); >> ( ( String << $ret += $1->getText(); >> | StringBackslash << $ret += "\\"; >> | StringQuote << $ret += "\""; >> | StringOctal << $ret += $1->getText(); >> ) )+ << if (!Util::processMixedString($ret, is_utf8)) { log_message(-2, "%s:%d: Illegal mixed UTF-8 and binary.", filename_, linenr); error_ = 1; } >> EndString ; stringEmpty > [ std::string ret, bool is_utf8 ] : << int linenr = 0; >> BeginString << linenr = $1->getLine(); >> ( ( String << $ret += $1->getText(); >> | StringBackslash << $ret += "\\"; >> | StringQuote << $ret += "\""; >> | StringOctal << $ret += $1->getText(); >> ) )* << if (!Util::processMixedString($ret, $is_utf8)) { log_message(-2, "%s:%d: Illegal mixed UTF-8 and binary.", filename_, linenr); error_ = 1; } >> EndString ; uLong > [ unsigned long l ] : << $l = 0; >> Integer << $l = strtoul($1->getText(), NULL, 10); >> ; sLong > [ long l ] : << $l = 0; >> Integer << $l = strtol($1->getText(), NULL, 10); >> ; integer > [ int i, int lineNr ] : << $i = 0; >> Integer << $i = atol($1->getText()); $lineNr = $1->getLine(); >> ; msf > [ Msf m ] : << int min = 0; int sec = 0; int frac = 0; int err = 0; int minLine; int secLine; int fracLine; >> integer > [min, minLine] ":" integer > [sec, secLine] ":" integer > [frac, fracLine] << if (min < 0) { log_message(-2, "%s:%d: Illegal minute field: %d\n", filename_, minLine, min); err = error_ = 1; } if (sec < 0 || sec > 59) { log_message(-2, "%s:%d: Illegal second field: %d\n", filename_, secLine, sec); err = error_ = 1; } if (frac < 0 || frac > 74) { log_message(-2, "%s:%d: Illegal fraction field: %d\n", filename_, fracLine, frac); err = error_ = 1; } if (err != 0) { $m = Msf(0); } else { $m = Msf(min, sec, frac); } >> ; samples > [ unsigned long s ] : << Msf m; >> ( msf > [ m ] << $s = m.samples(); >> | uLong > [ $s ] ) ; // fail action << $s = 0; >> dataLength [ TrackData::Mode mode, TrackData::SubChannelMode sm] > [ unsigned long len ] : << Msf m; unsigned long blen; blen = TrackData::dataBlockSize(mode, sm); >> ( msf > [ m] << $len = m.lba() * blen; >> | uLong > [ $len ] ) ; // fail action << $len = 0; >> dataMode > [ TrackData::Mode m ] : ( Audio << $m = TrackData::AUDIO; >> | Mode0 << $m = TrackData::MODE0; >> | Mode1 << $m = TrackData::MODE1; >> | Mode1Raw << $m = TrackData::MODE1_RAW; >> | Mode2 << $m = TrackData::MODE2; >> | Mode2Raw << $m = TrackData::MODE2_RAW; >> | Mode2Form1 << $m = TrackData::MODE2_FORM1; >> | Mode2Form2 << $m = TrackData::MODE2_FORM2; >> | Mode2FormMix << $m = TrackData::MODE2_FORM_MIX; >> ) ; trackMode > [ TrackData::Mode m ] : ( Audio << $m = TrackData::AUDIO; >> | Mode1 << $m = TrackData::MODE1; >> | Mode1Raw << $m = TrackData::MODE1_RAW; >> | Mode2 << $m = TrackData::MODE2; >> | Mode2Raw << $m = TrackData::MODE2_RAW; >> | Mode2Form1 << $m = TrackData::MODE2_FORM1; >> | Mode2Form2 << $m = TrackData::MODE2_FORM2; >> | Mode2FormMix << $m = TrackData::MODE2_FORM_MIX; >> ) ; subChannelMode > [ TrackData::SubChannelMode m ] : ( SubChanRw << $m = TrackData::SUBCHAN_RW; >> | SubChanRwRaw << $m = TrackData::SUBCHAN_RW_RAW; >> ) ; tocType > [ Toc::Type t ] : ( TocTypeCdda << $t = Toc::Type::CD_DA; >> | TocTypeCdrom << $t = Toc::Type::CD_ROM; >> | TocTypeCdromXa << $t = Toc::Type::CD_ROM_XA; >> | TocTypeCdi << $t = Toc::Type::CD_I; >> ) ; packType > [ CdTextItem::PackType t, int lineNr ] : ( Title << $t = CdTextItem::PackType::TITLE; $lineNr = $1->getLine(); >> | Performer << $t = CdTextItem::PackType::PERFORMER; $lineNr = $1->getLine(); >> | Songwriter << $t = CdTextItem::PackType::SONGWRITER; $lineNr = $1->getLine(); >> | Composer << $t = CdTextItem::PackType::COMPOSER; $lineNr = $1->getLine(); >> | Arranger << $t = CdTextItem::PackType::ARRANGER; $lineNr = $1->getLine(); >> | Message << $t = CdTextItem::PackType::MESSAGE; $lineNr = $1->getLine(); >> | DiscId << $t = CdTextItem::PackType::DISK_ID; $lineNr = $1->getLine(); >> | Genre << $t = CdTextItem::PackType::GENRE; $lineNr = $1->getLine(); >> | TocInfo1 << $t = CdTextItem::PackType::TOC_INFO1; $lineNr = $1->getLine(); >> | TocInfo2 << $t = CdTextItem::PackType::TOC_INFO2; $lineNr = $1->getLine(); >> | Reserved1 << $t = CdTextItem::PackType::RES1; $lineNr = $1->getLine(); >> | Reserved2 << $t = CdTextItem::PackType::RES2; $lineNr = $1->getLine(); >> | Reserved3 << $t = CdTextItem::PackType::RES3; $lineNr = $1->getLine(); >> | Reserved4 << $t = CdTextItem::PackType::CLOSED; $lineNr = $1->getLine(); >> | Closed << $t = CdTextItem::PackType::CLOSED; $lineNr = $1->getLine(); >> | UpcEan << $t = CdTextItem::PackType::UPCEAN_ISRC; $lineNr = $1->getLine(); >> | Isrc << $t = CdTextItem::PackType::UPCEAN_ISRC; $lineNr = $1->getLine(); >> | SizeInfo << $t = CdTextItem::PackType::SIZE_INFO; $lineNr = $1->getLine(); >> ) ; binaryData > [ const unsigned char *data, long len ] : << static unsigned char buf[MAX_CD_TEXT_DATA_LEN]; $data = buf; $len = 0; int i; int lineNr; >> "\{" { integer > [ i, lineNr ] << if (i < 0 || i > 255) { log_message(-2, "%s:%d: Illegal binary data: %d", filename_, lineNr, i); error_ = 1; i = 0; } buf[0] = i; $len = 1; >> ( "," integer > [ i, lineNr ] << if (i < 0 || i > 255) { log_message(-2, "%s:%d: Illegal binary data: %d", filename_, lineNr, i); error_ = 1; i = 0; } if ($len >= MAX_CD_TEXT_DATA_LEN) { log_message(-2, "%s:%d: Binary data exceeds maximum length (%d).", filename_, lineNr, MAX_CD_TEXT_DATA_LEN); error_ = 1; } else { buf[$len] = i; $len += 1; } >> )* } "\}" ; // fail action << $len = 0; >> cdTextItem [ int blockNr ] > [ CdTextItem* item, int lineNr ] : << $item = NULL; CdTextItem::PackType type; std::string s; bool is_utf8 = false; const unsigned char *data; long len; >> packType > [ type, $lineNr ] ( stringEmpty > [ s, is_utf8 ] << if (!s.empty()) { $item = new CdTextItem(type, blockNr); if (is_utf8) $item->setText(s.c_str()); else $item->setRawText(s); } >> | binaryData > [ data, len ] << $item = new CdTextItem(type, blockNr); $item->setData(data, len); >> ) ; // fail action << >> cdTextBlock [ CdTextContainer &container, int isTrack ] : << CdTextItem* item = nullptr; int blockNr = 0; int lineNr = 0; >> Language integer > [ blockNr, lineNr ] "\{" << if (blockNr < 0 || blockNr > 7) { log_message(-2, "%s:%d: Invalid block number, allowed range: [0..7].", filename_, lineNr); error_ = 1; blockNr = 0; } >> { EncodingLatin << container.encoding(blockNr, Util::Encoding::LATIN); >> | EncodingAscii << container.encoding(blockNr, Util::Encoding::ASCII); >> | EncodingJis << container.encoding(blockNr, Util::Encoding::MSJIS); >> | EncodingKorean << container.encoding(blockNr, Util::Encoding::KOREAN); >> | EncodingMandarin << container.encoding(blockNr, Util::Encoding::MANDARIN); >> } ( cdTextItem [ blockNr ] > [ item, lineNr ] << if (item) { int type = (int)item->packType(); if (isTrack && ((type > 0x86 && type <= 0x89) || type == 0x8f)) { log_message(-2, "%s:%d: Invalid CD-TEXT item for a track.", filename_, lineNr); error_ = 1; } else { container.add(item); } } >> )* "\}" ; // fail action << >> cdTextLanguageMap [ CdTextContainer &container ] : << int blockNr; int lang; int blockNrLine; int langLine = 0; >> LanguageMap "\{" ( integer > [ blockNr, blockNrLine] ":" ( integer > [ lang, langLine ] | LangEn << lang = 9; >> ) << if (blockNr >= 0 && blockNr <= 7) { if (lang >= 0 && lang <= 255) { container.language(blockNr, lang); } else { log_message(-2, "%s:%d: Invalid language code, allowed range: [0..255].", filename_, langLine); error_ = 1; } } else { log_message(-2, "%s:%d: Invalid language number, allowed range: [0..7].", filename_, blockNrLine); error_ = 1; } >> )+ "\}" ; cdTextTrack [ CdTextContainer &container ] : CdText "\{" ( cdTextBlock [ container, 1 ] )* "\}" ; cdTextGlobal [ CdTextContainer &container ] : CdText "\{" { cdTextLanguageMap [ container ] } ( cdTextBlock [ container, 0 ] )* "\}" ; } << ANTLRTokenType TocLexer::erraction() { log_message(-2, "%s:%d: Illegal token: %s", parser_->filename_, _line, _lextext); parser_->error_ = 1; return Eof; } >> << void TocParserGram::syn(_ANTLRTokenPtr tok, ANTLRChar *egroup, SetWordType *eset, ANTLRTokenType etok, int k) { int line; error_ = 1; line = LT(1)->getLine(); log_message(-2, "%s:%d: syntax error at \"%s\" ", filename_, line, LT(1)->getType() == Eof ? "EOF" : LT(1)->getText()); if ( !etok && !eset ) { log_message(0, ""); return; } if ( k==1 ) { log_message(0, "missing "); } else { log_message(0, "; \"%s\" not ", LT(1)->getText()); if ( set_deg(eset)>1 ) log_message(-2, " in "); } if ( set_deg(eset)>0 ) edecode(eset); else log_message(0, "%s ", token_tbl[etok]); if ( strlen(egroup) > 0 ) log_message(0, "in %s ", egroup); log_message(0, ""); } Toc *parseToc(const char* inp, const char *filename) { DLGStringInput in(inp); TocLexer scan(&in); ANTLRTokenBuffer pipe(&scan); ANTLRToken aToken; scan.setToken(&aToken); TocParserGram parser(&pipe); parser.filename_ = filename; scan.parser_ = &parser; parser.init(); parser.error_ = 0; Toc *t = parser.toc(); if (parser.error_ != 0) { return NULL; } else { return t; } } Toc *parseToc(FILE *fp, const char *filename) { DLGFileInput in(fp); TocLexer scan(&in); ANTLRTokenBuffer pipe(&scan); ANTLRToken aToken; scan.setToken(&aToken); TocParserGram parser(&pipe); parser.filename_ = filename; scan.parser_ = &parser; parser.init(); parser.error_ = 0; Toc *t = parser.toc(); if (parser.error_ != 0) { return NULL; } else { return t; } } >> cdrdao-cdrdao-f00afb2/trackdb/Track.cc000066400000000000000000001300551511453746600176670ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller * * 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. */ #include #include #include #include #include #include "Track.h" #include "util.h" #include "log.h" #include "TrackDataList.h" #include "CdTextItem.h" #include "lec.h" Track::Track(TrackData::Mode t, TrackData::SubChannelMode st) : length_(0), start_(0), end_(0) { type_ = t; subChannelType_ = st; audioCutMode_ = -1; nofSubTracks_ = 0; subTracks_ = lastSubTrack_ = NULL; nofIndices_ = 0; index_ = new Msf[98]; isrcValid_ = 0; flags_.copy = 0; // digital copy not permitted flags_.preEmphasis = 0; // no pre-emphasis flags_.audioType = 0; // two channel audio } Track::Track(const Track &obj) : length_(obj.length_), start_(obj.start_), end_(obj.end_), cdtext_(obj.cdtext_) { int i; SubTrack *run; type_ = obj.type_; subChannelType_ = obj.subChannelType_; audioCutMode_ = obj.audioCutMode_; nofSubTracks_ = obj.nofSubTracks_; subTracks_ = lastSubTrack_ = NULL; for (run = obj.subTracks_; run != NULL; run = run->next_) { if (subTracks_ == NULL) { subTracks_ = lastSubTrack_ = new SubTrack(*run); } else { lastSubTrack_->next_ = new SubTrack(*run); lastSubTrack_->next_->pred_ = lastSubTrack_; lastSubTrack_ = lastSubTrack_->next_; } } nofIndices_ = obj.nofIndices_; index_ = new Msf[98]; for (i = 0; i < nofIndices_; i++) { index_[i] = obj.index_[i]; } isrcValid_ = obj.isrcValid_; memcpy(isrcCountry_, obj.isrcCountry_, 2); memcpy(isrcOwner_, obj.isrcOwner_, 3); memcpy(isrcYear_, obj.isrcYear_, 2); memcpy(isrcSerial_, obj.isrcSerial_, 5); flags_ = obj.flags_; } Track::~Track() { SubTrack *run = subTracks_; SubTrack *next = NULL; while (run != NULL) { next = run->next_; delete run; run = next; } delete[] index_; } // Returns first sub-track or 'NULL' if no sub-tracks are defined const SubTrack *Track::firstSubTrack() const { return subTracks_ != NULL ? subTracks_ : NULL; } // Returns last sub-track or 'NULL' if no sub-tracks are defined const SubTrack *Track::lastSubTrack() const { return lastSubTrack_ != NULL ? lastSubTrack_ : NULL; } // Appends given sub-track to list of sub-tracks. // return: 0: OK // 1: tried to append PAD sub-track // 2: tried to append sub-track with different audioCutMode int Track::append(const SubTrack &strack) { if (strack.type() == SubTrack::PAD) return 1; if (audioCutMode_ != -1 && audioCutMode_ != strack.audioCutMode()) return 2; if (lastSubTrack_ != NULL && lastSubTrack_->type() == SubTrack::PAD && lastSubTrack_->mode() == strack.mode() && lastSubTrack_->subChannelMode() == strack.subChannelMode()) { // remove padding sub track delete removeSubTrack(lastSubTrack_); } // append sub track insertSubTrackAfter(lastSubTrack_, new SubTrack(strack)); update(); return 0; } // Traverses all sub-tracks to update summary data of track. void Track::update() { long lenLba = 0; // accumulates total length of track in blocks unsigned long slength; // length of track in samples unsigned long padLen; // padding length unsigned long blen; // block length for current data mode SubTrack *run, *next; SubTrack *pad; TrackData::Mode dataMode; TrackData::SubChannelMode subChannelMode; // remove all padding sub-tracks run = subTracks_; while (run != NULL) { next = run->next_; if (run->type() == SubTrack::PAD) { delete removeSubTrack(run); } run = next; } audioCutMode_ = -1; if ((run = subTracks_) != NULL) { do { dataMode = run->mode(); subChannelMode = run->subChannelMode(); if (audioCutMode_ == -1) audioCutMode_ = run->audioCutMode(); else if (audioCutMode_ != run->audioCutMode()) log_message(-3, "Track::update: mixed audio cut mode."); if (audioCutMode_) blen = SAMPLES_PER_BLOCK; else blen = TrackData::dataBlockSize(dataMode, subChannelMode); slength = 0; // find continues range of sub tracks with same data mode do { slength += run->length(); run = run->next_; } while (run != NULL && run->mode() == dataMode && run->subChannelMode() == subChannelMode); if ((padLen = slength % blen) != 0) { padLen = blen - padLen; if (audioCutMode_) pad = new SubTrack(SubTrack::PAD, 0, TrackData(padLen)); else pad = new SubTrack(SubTrack::PAD, 0, TrackData(dataMode, subChannelMode, padLen)); if (run != NULL) { insertSubTrackAfter(run->pred_, pad); } else { insertSubTrackAfter(lastSubTrack_, pad); } slength += padLen; } // at this point 'slength' should be a multiple of 'blen' assert(slength % blen == 0); lenLba += slength / blen; } while (run != NULL); } length_ = Msf(lenLba); slength = 0; for (run = subTracks_; run != NULL; run = run->next_) { run->start(slength); // set start position of sub-track slength += run->length(); } // reset 'start_' if necessary if (start_.lba() >= length_.lba()) { start_ = Msf(0); } } // Sets logical start of track, everthing before start (if != 0) is taken // as pre-gap. FIXME: Already set index marks are not updated. // return: 0: OK // 1: given start behind track end int Track::start(Msf s) { // A length of zero gets a pass for this test. The track length is // optional for the last track entry of the TOC file, because the // actual length of the track filename is not necessarily known at // this stage (mp3...). The actual length will be filled in later by // recomputeLength(). if (s.lba() >= length_.lba() && (length_.lba() != 0)) { return 1; } start_ = s; return 0; } // Sets end of user area of track which is the start of the post-gap. // An index entry is created at this point. The pre-gap length must be // set with 'start()' before this function can be called. // return: 0: OK // 1: start of post-gap is behind or at track end // 2: post-gap within pre-gap // 3: cannot create index mark, 98 index marks are already defined int Track::end(Msf e) { if (e.lba() >= length_.lba()) { return 1; } if (e.lba() != 0 && e.lba() <= start_.lba()) { return 2; } if (e.lba() != 0) { // add index mark for post-gap if (addIndex(Msf(e.lba() - start_.lba())) == 1) { // already 98 index increments defined return 3; } } end_ = e; return 0; } // Appends given index to index increment list. // return: 0: OK // 1: > 98 index increments // 2: index at or beyond track end // 3: index at start int Track::appendIndex(const Msf &index) { if (nofIndices_ == 98) { return 1; } if (index.lba() >= (length_ - start_).lba()) { return 2; } if (index.lba() == 0) { return 3; } index_[nofIndices_] = index; nofIndices_ += 1; return 0; } // Adds index at given position // return: 0: OK // 1: > 98 index increments // 2: cannot add index at specified position int Track::addIndex(const Msf &index) { int i; if (nofIndices_ == 98) { return 1; } if (index.lba() >= (length_ - start_).lba()) { return 2; } if (index.lba() == 0) { return 2; } for (i = 0; i < nofIndices_; i++) { if (index.lba() == index_[i].lba()) return 2; if (index.lba() < index_[i].lba()) break; } if (i == nofIndices_) { // append index index_[nofIndices_] = index; nofIndices_ += 1; } else { int pos = i; for (i = nofIndices_; i > pos; i--) index_[i] = index_[i - 1]; index_[pos] = index; nofIndices_ += 1; } return 0; } // Removes specified index. // return 0: OK // 1: index not found int Track::removeIndex(int index) { int i; if (index < 0 || index >= nofIndices_) return 1; for (i = index; i < nofIndices_ - 1; i++) index_[i] = index_[i + 1]; nofIndices_ -= 1; return 0; } // returns index increment Msf Track::getIndex(int i) const { if (i >= nofIndices_ || i < 0) { return Msf(0); } else { return index_[i]; } } int Track::check(int trackNr) const { int ret = 0; if (length().lba() - start().lba() < Msf(0, 4, 0).lba()) { log_message(-1, "Track %d: Length is shorter than 4 seconds.", trackNr); ret = 1; } for (SubTrack* st = subTracks_; st; st = st->next_) { ret |= st->check(trackNr); } return ret; } bool Track::recomputeLength() { for (SubTrack* st = subTracks_; st; st = st->next_) { if (st->length() == 0) { st->determineLength(); } } update(); return true; } // Sets ISRC code. Expected string: "CCOOOYYSSSSS" // C: country code (ASCII) // O: owner code (ASCII) // Y: year ('0'-'9') // S: serial number ('0'-'9') // return: 0: OK // 1: ilegal ISRC string int Track::isrc(const char *isrc) { int i; if (isrc == NULL) { isrcValid_ = 0; return 0; } if (strlen(isrc) != 12) { return 1; } for (i=0; i < 5; i++) { if (!(isdigit(isrc[i]) || isupper(isrc[i]))) { return 1; } } for (i = 5; i < 12; i++) { if (!isdigit(isrc[i])) { return 1; } } isrcCountry_[0] = isrc[0]; isrcCountry_[1] = isrc[1]; isrcOwner_[0] = isrc[2]; isrcOwner_[1] = isrc[3]; isrcOwner_[2] = isrc[4]; // store BCD isrcYear_[0] = isrc[5] - '0'; isrcYear_[1] = isrc[6] - '0'; isrcSerial_[0] = isrc[7] - '0'; isrcSerial_[1] = isrc[8] - '0'; isrcSerial_[2] = isrc[9] - '0'; isrcSerial_[3] = isrc[10] - '0'; isrcSerial_[4] = isrc[11] - '0'; isrcValid_ = 1; return 0; } const char *Track::isrc() const { static char buf[13]; if (!isrcValid_) return NULL; buf[0] = isrcCountry_[0]; buf[1] = isrcCountry_[1]; buf[2] = isrcOwner_[0]; buf[3] = isrcOwner_[1]; buf[4] = isrcOwner_[2]; buf[5] = isrcYear_[0] + '0'; buf[6] = isrcYear_[1] + '0'; buf[7] = isrcSerial_[0] + '0'; buf[8] = isrcSerial_[1] + '0'; buf[9] = isrcSerial_[2] + '0'; buf[10] = isrcSerial_[3] + '0'; buf[11] = isrcSerial_[4] + '0'; buf[12] = 0; return buf; } int Track::isPadded() const { SubTrack *run; for (run = subTracks_; run != NULL; run = run->next_) { if (run->type() == SubTrack::PAD) return 1; } return 0; } // writes out track data in TOC file syntax void Track::print(std::ostream &out, PrintParams& params) const { SubTrack *st; const char *s; int i; out << "TRACK " << TrackData::mode2String(type()); s = TrackData::subChannelMode2String(subChannelType()); if (*s != 0) out << " " << s; out << std::endl; if (!copyPermitted()) out << "NO "; out << "COPY" << std::endl; if (type() == TrackData::AUDIO) { if (!preEmphasis()) out << "NO "; out << "PRE_EMPHASIS" << std::endl; if (audioType() == 0) out << "TWO_CHANNEL_AUDIO" << std::endl; else out << "FOUR_CHANNEL_AUDIO" << std::endl; if (isrcValid()) { out << "ISRC \"" << isrcCountry(0) << isrcCountry(1) << isrcOwner(0) << isrcOwner(1) << isrcOwner(2) << (char)(isrcYear(0) + '0') << (char)(isrcYear(1) + '0') << (char)(isrcSerial(0) + '0') << (char)(isrcSerial(1) + '0') << (char)(isrcSerial(2) + '0') << (char)(isrcSerial(3) + '0') << (char)(isrcSerial(4) + '0') << "\"" << std::endl; } cdtext_.print(1, out, params); } for (st = subTracks_; st != NULL; st = st->next_) { st->print(out, params); } if (start_.lba() != 0) { out << "START " << start_.str() << std::endl; } for (i = 0; i < nofIndices_; i++) { out << "INDEX " << index_[i].str() << std::endl; } } void Track::collectFiles(std::set& set) { SubTrack* st; for (st = subTracks_; st != NULL; st = st->next_) { const char* f = st->filename(); if (f) set.insert(f); } } void Track::markFileConversion(const char* src, const char* dst) { SubTrack* st; for (st = subTracks_; st != NULL; st = st->next_) { const char* f = st->filename(); if (f && strcmp(f, src) == 0) { st->effectiveFilename(dst); } } } bool Track::resolveFilename(const char* path) { SubTrack* st; for (st = subTracks_; st != NULL; st = st->next_) { std::string rfilename; const char* f = st->filename(); if (f) { // STDIN is a special case (stdin input), don't process it. if (strcmp(f, "STDIN") == 0) continue; if (::resolveFilename(rfilename, f, path)) { st->effectiveFilename(rfilename.c_str()); } else { log_message(-2, "Could not find input file \"%s\".", f); return false; } } } return true; } // Locates 'SubTrack' that contains specified sample. // return: found 'SubTrack' or 'NULL' if given sample is out of range SubTrack *Track::findSubTrack(unsigned long sample) const { SubTrack *run; if (audioCutMode()) { if (sample >= length_.samples()) return NULL; } else { if (sample >= length_.lba() * TrackData::dataBlockSize(type(), subChannelType())) return NULL; } for (run = subTracks_; run != NULL && run->next_ != NULL; run = run->next_) { if (sample < run->next_->start()) return run; } return run; } void Track::countSubTracks() { SubTrack *run; nofSubTracks_ = 0; for (run = subTracks_; run != NULL; run = run->next_) nofSubTracks_++; } // move track start or index increment within track range // return: 0: OK // 1: track length would be shorter than 4 seconds // 2: cannot cross index boundary int Track::moveIndex(int index, long lba) { int i; long rangeMin; long rangeMax; assert(index > 0 && index - 2 < nofIndices_); assert(lba >= 0 && index < length_.lba()); if (index == 1) { if (nofIndices_ > 0 && lba >= start_.lba() + getIndex(0).lba()) return 2; if (lba > length_.lba() - 4 * 75) return 1; // adjust index increments to new track start for (i = 0; i < nofIndices_; i++) { index_[i] = Msf(index_[i].lba() + start_.lba() - lba); } start_ = Msf(lba); return 0; } // adjust 'index' for index array access index -= 2; if (lba <= start_.lba()) return 2; lba -= start_.lba(); rangeMin = (index == 0 ? 0 : index_[index - 1].lba()); rangeMax = (index == nofIndices_ - 1 ? length_.lba() - start_.lba() : index_[index + 1].lba()); if (lba > rangeMin && lba < rangeMax) { index_[index] = Msf(lba); return 0; } return 2; } TrackDataList *Track::removeToEnd(unsigned long sample) { SubTrack *strun; SubTrack *store; int i; assert(sample > 0 && sample < length_.samples()); strun = findSubTrack(sample); assert(strun != NULL); TrackDataList *list = new TrackDataList; if (sample == strun->start()) { // we don't have to split the TrackData object list->append(new TrackData(*strun)); // cannot be the first SubTrack because 'sample' > 0 strun->pred_->next_ = NULL; lastSubTrack_ = strun->pred_; store = strun; strun = strun->next_; delete store; } else { // split audio data object TrackData *part1, *part2; strun->split(sample - strun->start(), &part1, &part2); list->append(part2); store = new SubTrack(strun->type(), *part1); delete part1; if (strun->pred_ == NULL) { subTracks_ = store; } else { strun->pred_->next_ = store; store->pred_ = strun->pred_; } lastSubTrack_ = store; store = strun; strun = strun->next_; delete store; } while (strun != NULL) { list->append(new TrackData(*strun)); store = strun; strun = strun->next_; delete store; } countSubTracks(); update(); checkConsistency(); // adjust index increments for (i = 0; i < nofIndices_; i++) { if (index_[i].lba() + start_.lba() >= length_.lba()) { nofIndices_ = i; break; } } return list; } TrackDataList *Track::removeFromStart(unsigned long sample) { SubTrack *strun; SubTrack *store, *start; int i; assert(sample > 0 && sample < length_.samples()); TrackDataList *list = new TrackDataList; for (strun = subTracks_; strun != NULL && strun->next_ != NULL; strun = strun->next_) { if (sample < strun->next_->start()) break; else list->append(new TrackData(*strun)); } assert(strun != NULL); start = subTracks_; if (sample == strun->start()) { // we don't have to split the TrackData object // cannot be the first SubTrack because 'sample' > 0 strun->pred_->next_ = NULL; subTracks_ = strun; subTracks_->pred_ = NULL; } else { // split actual sub track TrackData *part1, *part2; strun->split(sample - strun->start(), &part1, &part2); list->append(part1); store = new SubTrack(strun->type(), *part2); delete part2; store->next_ = strun->next_; if (store->next_ != NULL) store->next_->pred_ = store; strun->next_ = NULL; subTracks_ = store; if (strun == lastSubTrack_) lastSubTrack_ = store; } // remove unlinked sub tracks while (start != NULL) { store = start; start = start->next_; delete store; } countSubTracks(); update(); checkConsistency(); // adjust index increments for (i = 0; i < nofIndices_; i++) { if (index_[i].lba() + start_.lba() >= length_.lba()) { nofIndices_ = i; break; } } return list; } void Track::prependTrackData(const TrackDataList *list) { SubTrack *start = NULL; SubTrack *last = NULL; SubTrack *ent; const TrackData *run; if (list->count() == 0) return; for (run = list->first(); run != NULL; run = list->next()) { ent = new SubTrack(SubTrack::DATA, *run); if (last == NULL) { start = ent; } else { last->next_ = ent; ent->pred_ = last; } last = ent; } if (subTracks_ == NULL) { subTracks_ = start; lastSubTrack_ = last; } else { last->next_ = subTracks_; subTracks_->pred_ = last; subTracks_ = start; } mergeSubTracks(); // this will also update the sub track counter update(); checkConsistency(); } void Track::appendTrackData(const TrackDataList *list) { SubTrack *start = NULL; SubTrack *last = NULL; SubTrack *ent; const TrackData *run; if (list->count() == 0) return; for (run = list->first(); run != NULL; run = list->next()) { ent = new SubTrack(SubTrack::DATA, *run); if (last == NULL) { start = ent; } else { last->next_ = ent; ent->pred_ = last; } last = ent; } if (lastSubTrack_ != NULL) { if (lastSubTrack_->type() == SubTrack::PAD) lastSubTrack_->type_ = SubTrack::DATA; lastSubTrack_->next_ = start; start->pred_ = lastSubTrack_; lastSubTrack_ = last; } else { subTracks_ = start; lastSubTrack_ = last; } mergeSubTracks(); // this will also update the sub track counter update(); checkConsistency(); } void Track::appendTrackData(const Track *track) { SubTrack *run, *ent; for (run = track->subTracks_; run != NULL; run = run->next_) { ent = new SubTrack(*run); if (lastSubTrack_ == NULL) { subTracks_ = ent; } else { lastSubTrack_->next_ = ent; ent->pred_ = lastSubTrack_; } lastSubTrack_ = ent; } mergeSubTracks(); // this will also update the sub track counter update(); checkConsistency(); } TrackDataList *Track::removeTrackData(unsigned long start, unsigned long end) { SubTrack *run; TrackData *part1, *part2, *part3; unsigned long plen; if (start > end || end >= length_.samples()) return NULL; SubTrack *startSt = findSubTrack(start); SubTrack *endSt = findSubTrack(end); assert(startSt != NULL); assert(endSt != NULL); TrackDataList *list = new TrackDataList; if (startSt == endSt) { if (start == startSt->start() && end == startSt->start() + startSt->length() - 1) { // remove complete sub track list->append(new TrackData(*startSt)); } else if (start == startSt->start()) { // remove first part of sub track startSt->split(end + 1 - startSt->start(), &part1, &part2); list->append(part1); insertSubTrackAfter(startSt, new SubTrack(startSt->type(), *part2)); delete part2; } else if (end == startSt->start() + startSt->length() - 1) { // remove last part of sub track startSt->split(start - startSt->start(), &part1, &part2); list->append(part2); insertSubTrackAfter(startSt, new SubTrack(startSt->type(), *part1)); delete part1; } else { // remove middle part of sub track startSt->split(start - startSt->start(), &part1, &part2); insertSubTrackAfter(startSt->pred_, new SubTrack(startSt->type(), *part1)); plen = part1->length(); delete part1; part2->split(end + 1 - startSt->start() - plen, &part1, &part3); list->append(part1); insertSubTrackAfter(startSt, new SubTrack(startSt->type(), *part3)); delete part3; delete part2; } delete removeSubTrack(startSt); } else { if (start == startSt->start()) { // remove complete sub track list->append(new TrackData(*startSt)); } else { startSt->split(start - startSt->start(), &part1, &part2); list->append(part2); insertSubTrackAfter(startSt->pred_, new SubTrack(startSt->type(), *part1)); delete part1; } for (run = startSt->next_; run != endSt; run = run->next_) list->append(new TrackData(*(startSt->next_))); if (end == endSt->start() + endSt->length() - 1) { // remove complete sub track list->append(new TrackData(*endSt)); } else { endSt->split(end + 1 - endSt->start(), &part1, &part2); list->append(part1); insertSubTrackAfter(endSt, new SubTrack(endSt->type(), *part2)); delete part2; } while (startSt->next_ != endSt) delete removeSubTrack(startSt->next_); delete removeSubTrack(startSt); delete removeSubTrack(endSt); } // adjust index marks unsigned long len; long preGapAdj = 0; long slba = 0; long elba = 0; long indexMove = 0; long indexAdj = 0; int i; if (start < start_.samples()) { if (end < start_.samples()) { len = end - start + 1; slba = -1; elba = -1; } else { len = start_.samples() - start; elba = (end - start_.samples()) / SAMPLES_PER_BLOCK; slba = 0; indexMove = (end - start_.samples() + 1) / SAMPLES_PER_BLOCK; if (((end - start_.samples() + 1) % SAMPLES_PER_BLOCK) != 0) indexMove += 1; } preGapAdj = len / SAMPLES_PER_BLOCK; if ((len % SAMPLES_PER_BLOCK) != 0) indexAdj = 1; } else { slba = (start - start_.samples()) / SAMPLES_PER_BLOCK; if (((start - start_.samples()) % SAMPLES_PER_BLOCK) != 0) slba += 1; elba = (end - start_.samples()) / SAMPLES_PER_BLOCK; indexMove = (end - start + 1) / SAMPLES_PER_BLOCK; if (((end - start + 1) % SAMPLES_PER_BLOCK) != 0) indexMove += 1; } i = 0; while (i < nofIndices_) { if (index_[i].lba() >= slba && index_[i].lba() <= elba) { removeIndex(i); continue; } else if (index_[i].lba() > elba) { if (index_[i].lba() - indexMove <= 0) { removeIndex(i); continue; } else { index_[i] = Msf(index_[i].lba() - indexMove); } if (i > 0 && index_[i - 1].lba() == index_[i].lba()) { removeIndex(i); continue; } } if (index_[i].lba() - indexAdj <= 0) { removeIndex(i); continue; } else { index_[i] = Msf(index_[i].lba() - indexAdj); } i++; } // adjust pre-gap length start_ = Msf(start_.lba() - preGapAdj); mergeSubTracks(); // this will also update the sub track counter update(); checkConsistency(); return list; } void Track::insertTrackData(unsigned long pos, const TrackDataList *list) { const TrackData *run; TrackData *part1, *part2; SubTrack *st; unsigned long len; long blen; int i; if (list == NULL || list->first() == NULL || list->length() == 0) return; if (pos >= length_.samples()) { // append data for (run = list->first(); run != NULL; run = list->next()) { insertSubTrackAfter(lastSubTrack_, new SubTrack(SubTrack::DATA, *run)); } } else { st = findSubTrack(pos); assert(st != NULL); len = list->length(); if (pos == st->start()) { for (run = list->first(); run != NULL; run = list->next()) { insertSubTrackAfter(st->pred_, new SubTrack(SubTrack::DATA, *run)); } } else { st->split(pos - st->start(), &part1, &part2); insertSubTrackAfter(st->pred_, new SubTrack(SubTrack::DATA, *part1)); insertSubTrackAfter(st, new SubTrack(st->type(), *part2)); delete part1; delete part2; for (run = list->first(); run != NULL; run = list->next()) { insertSubTrackAfter(st->pred_, new SubTrack(SubTrack::DATA, *run)); } delete removeSubTrack(st); } blen = len / SAMPLES_PER_BLOCK; if (pos <= start_.samples()) { start_ = Msf(start_.lba() + blen); } else { for (i = 0; i < nofIndices_; i++) { if (index_[i].samples() >= pos) index_[i] = Msf(index_[i].lba() + blen); } } } mergeSubTracks(); // this will also update the sub track counter update(); checkConsistency(); return; } void Track::mergeSubTracks() { SubTrack *run = subTracks_; SubTrack *newSubTrack; TrackData *mergedData; while (run != NULL && run->next_ != NULL) { if (run->type() == run->next_->type() && (mergedData = run->merge(run->next_)) != NULL) { newSubTrack = new SubTrack(run->type(), *mergedData); delete mergedData; newSubTrack->next_ = run->next_->next_; if (newSubTrack->next_ != NULL) newSubTrack->next_->pred_ = newSubTrack; if (run->pred_ == NULL) { subTracks_ = newSubTrack; } else { run->pred_->next_ = newSubTrack; newSubTrack->pred_ = run->pred_; } if (run->next_ == lastSubTrack_) lastSubTrack_ = newSubTrack; delete run->next_; delete run; run = newSubTrack; } else { run = run->next_; } } countSubTracks(); } void Track::checkConsistency() { SubTrack *run, *last = NULL; long cnt = 0; for (run = subTracks_; run != NULL; last = run, run = run->next_) { cnt++; if (run->pred_ != last) log_message(-3, "Track::checkConsistency: wrong pred pointer."); } if (last != lastSubTrack_) log_message(-3, "Track::checkConsistency: wrong last pointer."); if (cnt != nofSubTracks_) log_message(-3, "Track::checkConsistency: wrong sub track counter."); } // Inserts 'newSubTrack' after existing sub track 'subTrack'. If 'subTrack' // is NULL it will be prepended. void Track::insertSubTrackAfter(SubTrack *subTrack, SubTrack *newSubTrack) { if (subTrack == NULL) { if (subTracks_ == NULL) { subTracks_ = lastSubTrack_ = newSubTrack; newSubTrack->next_ = newSubTrack->pred_ = NULL; } else { newSubTrack->next_ = subTracks_; subTracks_->pred_ = newSubTrack; newSubTrack->pred_ = NULL; subTracks_ = newSubTrack; } } else { newSubTrack->next_ = subTrack->next_; if (newSubTrack->next_ != NULL) { newSubTrack->next_->pred_ = newSubTrack; } else { lastSubTrack_ = newSubTrack; } subTrack->next_ = newSubTrack; newSubTrack->pred_ = subTrack; } nofSubTracks_ += 1; checkConsistency(); } // Removes given sub track from list. Returns the removed sub track. SubTrack *Track::removeSubTrack(SubTrack *subTrack) { if (subTrack->pred_ == NULL) { assert(subTrack == subTracks_); subTracks_ = subTrack->next_; if (subTracks_ != NULL) { subTracks_->pred_ = NULL; } else { lastSubTrack_ = NULL; } } else { subTrack->pred_->next_ = subTrack->next_; if (subTrack->next_ != NULL) { subTrack->next_->pred_ = subTrack->pred_; } else { lastSubTrack_ = subTrack->pred_; } } nofSubTracks_ -= 1; subTrack->next_ = subTrack->pred_ = NULL; checkConsistency(); return subTrack; } // Fills provided buffer with an audio block that contains zero data // encoded with given mode. // encMode: encoding mode, see 'TrackReader::readBlock()' // mode: sector mode // smode: sub-channel mode // lba : absolute address of sector // buf : caller provided buffer that is filled with at most 2448 bytes void Track::encodeZeroData(int encMode, TrackData::Mode mode, TrackData::SubChannelMode smode, long lba, unsigned char *buf) { long subChanLen = TrackData::subChannelSize(smode); // we won't have to calculate P and Q parity for zero R-W sub-channels // because 0s have no impact on the parity if (encMode == 0) { memset(buf, 0, AUDIO_BLOCK_LEN + subChanLen); switch (mode) { case TrackData::AUDIO: break; case TrackData::MODE0: lec_encode_mode0_sector(lba, buf); lec_scramble(buf); break; case TrackData::MODE1: case TrackData::MODE1_RAW: lec_encode_mode1_sector(lba, (u_int8_t *)buf); lec_scramble(buf); break; case TrackData::MODE2: case TrackData::MODE2_RAW: lec_encode_mode2_sector(lba, (u_int8_t *)buf); lec_scramble(buf); break; case TrackData::MODE2_FORM1: case TrackData::MODE2_FORM_MIX: // encode as form 1 lec_encode_mode2_form1_sector(lba, (u_int8_t *)buf); lec_scramble(buf); break; case TrackData::MODE2_FORM2: // setup sub header buf[16+2] = 0x20; buf[16+6] = 0x20; lec_encode_mode2_form2_sector(lba, (u_int8_t *)buf); lec_scramble(buf); break; } } else if (encMode == 1) { switch (mode) { case TrackData::AUDIO: memset(buf, 0, AUDIO_BLOCK_LEN + subChanLen); break; case TrackData::MODE0: memset(buf, 0, MODE0_BLOCK_LEN + subChanLen); break; case TrackData::MODE1: case TrackData::MODE1_RAW: memset(buf, 0, MODE1_BLOCK_LEN + subChanLen); break; case TrackData::MODE2: case TrackData::MODE2_RAW: case TrackData::MODE2_FORM_MIX: memset(buf, 0, MODE2_BLOCK_LEN + subChanLen); break; case TrackData::MODE2_FORM1: memset(buf, 0, MODE2_BLOCK_LEN + subChanLen); break; case TrackData::MODE2_FORM2: memset(buf, 0, MODE2_BLOCK_LEN + subChanLen); // setup sub header buf[2] = 0x20; buf[6] = 0x20; break; } } else { log_message(-3, "Illegal sector encoding mode in 'Track::encodeZeroData()'."); } } void Track::addCdTextItem(CdTextItem* item) { assert(item->isTrackPack()); cdtext_.add(item); } void Track::removeCdTextItem(CdTextItem::PackType type, int blockNr) { cdtext_.remove(type, blockNr); } TrackReader::TrackReader(const Track *t) : reader(NULL) { track_ = t; readPos_ = 0; readPosSample_ = 0; readSubTrack_ = NULL; open_ = 0; subChanDelayLineIndex_ = 0; } TrackReader::~TrackReader() { if (open_) { closeData(); } track_ = NULL; readSubTrack_ = NULL; } void TrackReader::init(const Track *t) { if (open_) { closeData(); } track_ = t; readSubTrack_ = NULL; } // initiates reading track // return: 0: OK // 1: data file could not be opened // 2: could not seek to start position int TrackReader::openData() { assert(open_ == 0); assert(track_ != NULL); int ret = 0; //int i; open_ = 1; readPos_ = 0; readPosSample_ = 0; readSubTrack_ = track_->subTracks_; reader.init(readSubTrack_); subChanDelayLineIndex_ = 0; /* for(i = 0; i < MAX_SUB_DEL; i++) memset(subChanDelayLine_[i], 0, 24); */ if (readSubTrack_ != NULL) { ret = reader.openData(); } return ret; } void TrackReader::closeData() { if (open_) { open_ = 0; readPos_ = 0; readPosSample_ = 0; readSubTrack_ = NULL; reader.closeData(); } } long TrackReader::readData(int encodingMode, int subChanEncodingMode, long lba, char *buf, long len) { long err = 0; long b; long offset; assert(open_ != 0); if (readPos_ + len > track_->length_.lba()) { if ((len = track_->length_.lba() - readPos_) <= 0) { return 0; } } for (b = 0; b < len; b++) { if ((offset = readBlock(encodingMode, subChanEncodingMode, lba, (Sample*)buf)) == 0) { err = 1; break; } buf += offset; lba++; } readPos_ += b; return err == 0 ? b : -1; } // Reads one block from sub-tracks and performs the data encoding for the // block. // encodingMode: conrols how the sector data is encoded // 0: returned data is always an audio block (2352 bytes), // data blocks are completely encoded // 1: data is returned mostly unencoded, the block size // depends on the actual sub-track mode, MODE2_FORM1 and // MODE2_FORM2 blocks are extended by the sub header and // filled with 0 bytes to match the MODE2 block size // (2336 bytes). // subChanEncodingMode: conrols how the R-W sub-channel data is encoded // 0: plain R-W data // 1: generate Q and P parity and interleave // lba: Logical block address that must be encoded into header of data blocks // Return: 0 if error occured, else length of block that has been filled // int TrackReader::readBlock(int encodingMode, int subChanEncodingMode, long lba, Sample *buf) { TrackData::Mode dataMode; // current data mode of sub-track TrackData::SubChannelMode subChanMode; // current sub-channel mode of sub-track long actLen; long count; // amount of data the must be read from sub track long blen; long nread = 0; long offset = 0; // block length of returned data long subChannelDataLen; char subChanData[MAX_SUBCHANNEL_LEN]; while (reader.readLeft() == 0) { // skip to next sub track with available data readSubTrack_ = readSubTrack_->next_; // next sub-track must exist since requested length matches available data assert(readSubTrack_ != NULL); reader.init(readSubTrack_); if (reader.openData() != 0) { return 0; } } dataMode = readSubTrack_->mode(); // current data mode subChanMode = readSubTrack_->subChannelMode(); // current sub-channel mode if (track_->audioCutMode()) { count = SAMPLES_PER_BLOCK; blen = AUDIO_BLOCK_LEN; } else { count = TrackData::dataBlockSize(dataMode, subChanMode); blen = count; } subChannelDataLen = TrackData::subChannelSize(subChanMode); char *dataBuf = (char *)buf; if (encodingMode == 0) { offset = AUDIO_BLOCK_LEN; switch (dataMode) { case TrackData::AUDIO: case TrackData::MODE1_RAW: case TrackData::MODE2_RAW: break; case TrackData::MODE0: case TrackData::MODE1: case TrackData::MODE2: case TrackData::MODE2_FORM_MIX: dataBuf += 16; break; case TrackData::MODE2_FORM1: memset(dataBuf + 16, 0, 8); // clear sub-header dataBuf += 24; break; case TrackData::MODE2_FORM2: memset(dataBuf + 16, 0, 8); // clear sub-header dataBuf[16+2] = 0x20; dataBuf[16+6] = 0x20; dataBuf += 24; break; } } else if (encodingMode == 1) { switch (dataMode) { case TrackData::AUDIO: offset = AUDIO_BLOCK_LEN; break; case TrackData::MODE0: offset = MODE0_BLOCK_LEN; break; case TrackData::MODE1: offset = MODE1_BLOCK_LEN; break; case TrackData::MODE1_RAW: offset = MODE1_BLOCK_LEN; break; case TrackData::MODE2: case TrackData::MODE2_FORM_MIX: offset = MODE2_BLOCK_LEN; break; case TrackData::MODE2_FORM1: case TrackData::MODE2_FORM2: offset = MODE2_BLOCK_LEN; memset(dataBuf, 0, MODE2_BLOCK_LEN); dataBuf += 8; // reserve space for sub-header break; case TrackData::MODE2_RAW: offset = MODE2_BLOCK_LEN; break; } } // gather one block of data, block length depends on 'dataMode' while (count > 0) { if (track_->audioCutMode()) actLen = reader.readData(buf + nread, count); else actLen = reader.readData((Sample *)(dataBuf + nread), count); if (actLen < 0) // indicates read error return 0; if (actLen != count) { // end of data in sub-track reached, skip to next sub-track readSubTrack_ = readSubTrack_->next_; // next sub-track must exist since requested length match available data assert(readSubTrack_ != NULL); // mode of next sub-track must match, this is ensured in 'update()'. assert(readSubTrack_->mode() == dataMode); assert(readSubTrack_->subChannelMode() == subChanMode); reader.init(readSubTrack_); if (reader.openData() != 0) { return 0; } } count -= actLen; nread += actLen; } if (subChannelDataLen > 0) { char *subChannelSourceBuf = dataBuf + blen - subChannelDataLen; // save sub-channel data for later processing memcpy(subChanData, subChannelSourceBuf, subChannelDataLen); memset(subChannelSourceBuf, 0, subChannelDataLen); } unsigned char *encBuf = (unsigned char *)buf; if (encodingMode == 0) { // encode data block according to 'dataMode' switch (dataMode) { case TrackData::AUDIO: break; case TrackData::MODE0: lec_encode_mode0_sector(lba, encBuf); lec_scramble(encBuf); break; case TrackData::MODE1: lec_encode_mode1_sector(lba, encBuf); lec_scramble(encBuf); break; case TrackData::MODE1_RAW: { Msf m(lba); if (int2bcd(m.min()) != encBuf[12] || int2bcd(m.sec()) != encBuf[13] || int2bcd(m.frac()) != encBuf[14]) { // sector address mismatch -> rebuild L-EC since it covers the header lec_encode_mode1_sector(lba, encBuf); } lec_scramble(encBuf); } break; case TrackData::MODE2: lec_encode_mode2_sector(lba, encBuf); lec_scramble(encBuf); break; case TrackData::MODE2_FORM1: lec_encode_mode2_form1_sector(lba, encBuf); lec_scramble(encBuf); break; case TrackData::MODE2_FORM2: lec_encode_mode2_form2_sector(lba, encBuf); lec_scramble(encBuf); break; case TrackData::MODE2_FORM_MIX: if ((encBuf[16+2] & 0x20) != 0) lec_encode_mode2_form2_sector(lba, encBuf); else lec_encode_mode2_form1_sector(lba, encBuf); lec_scramble(encBuf); break; case TrackData::MODE2_RAW: { Msf m(lba); // L-EC does not cover sector header so it is relocatable // just update the sector address in the header encBuf[12] = int2bcd(m.min()); encBuf[13] = int2bcd(m.sec()); encBuf[14] = int2bcd(m.frac()); lec_scramble(encBuf); } break; } } else if (encodingMode == 1) { switch (dataMode) { case TrackData::MODE2_FORM2: // add sub header for data form 2 sectors encBuf[2] = 0x20; encBuf[6] = 0x20; break; case TrackData::MODE1_RAW: // strip off sync and header memmove(encBuf, encBuf + 16, MODE1_BLOCK_LEN); break; case TrackData::MODE2_RAW: // strip off sync and header memmove(encBuf, encBuf + 16, MODE2_BLOCK_LEN); break; default: break; } } // encode R-W sub-channel data switch (subChanMode) { case TrackData::SUBCHAN_NONE: break; case TrackData::SUBCHAN_RW: if (subChanEncodingMode == 1) { /*do_encode_sub((unsigned char*)subChanData, 1, 1, &subChanDelayLineIndex_, subChanDelayLine_); */ } break; case TrackData::SUBCHAN_RW_RAW: if (subChanEncodingMode == 0) { // to be done } break; } if (subChannelDataLen > 0) { char *subChannelTargetBuf = (char *)buf + offset; memcpy(subChannelTargetBuf, subChanData, subChannelDataLen); } return (offset + subChannelDataLen); } long TrackReader::readTrackData(Sample *buf, long len) { long actLen; long count = len; long nread = 0; while (count > 0) { actLen = reader.readData(buf + nread, count); if (actLen < 0) { return -1; } if (actLen != count) { // end of audio data in sub-track reached, skip to next sub-track readSubTrack_ = readSubTrack_->next_; // next sub-track must exists since requested length match available data assert(readSubTrack_ != NULL); reader.init(readSubTrack_); if (reader.openData() != 0) { return -1; } } count -= actLen; if (track_->audioCutMode()) nread += actLen; else nread += actLen / SAMPLE_LEN; } return len; } // Seeks to specified sample. // return: 0: OK // 10: sample out of range // return code of 'TrackData::openData()' int TrackReader::seekSample(unsigned long sample) { int ret; unsigned long offset; assert(open_ != 0); if (track_->audioCutMode() == 0) { // all lengths are in byte units -> convert requested sample to a byte // offset // first determine the block which contains the requested sample unsigned long block = sample / SAMPLES_PER_BLOCK; // byte offset into block unsigned long boffset = (sample % SAMPLES_PER_BLOCK) * SAMPLE_LEN; unsigned long blen = TrackData::dataBlockSize(track_->type(), track_->subChannelType()); offset = block * blen + boffset; } else { offset = sample; } // find sub track containing 'sample' SubTrack *st = track_->findSubTrack(offset); if (st == NULL) return 10; // open sub track if necessary if (readSubTrack_ != st) { readSubTrack_ = st; reader.init(readSubTrack_); if ((ret = reader.openData()) != 0) return ret; } assert(offset >= readSubTrack_->start()); unsigned long stOffset = offset - readSubTrack_->start(); // seek in sub track if ((ret = reader.seekSample(stOffset)) != 0) return ret; readPosSample_ = sample; return 0; } long TrackReader::readSamples(Sample *buf, long len) { long ret; long i; assert(open_ != 0); if (readPosSample_ + (unsigned long)len > track_->length_.samples()) { if ((len = track_->length_.samples() - readPosSample_) <= 0) { return 0; } } if (track_->type() == TrackData::AUDIO) { if (track_->audioCutMode() == 1) { if ((ret = readTrackData(buf, len)) > 0) { readPosSample_ += ret; } } else { long subChanLen = TrackData::subChannelSize(track_->subChannelType()); char subChanBuf[MAX_SUBCHANNEL_LEN]; ret = 0; while (len > 0) { long burst = SAMPLES_PER_BLOCK - (readPosSample_ % SAMPLES_PER_BLOCK); int fullBurst = 0; if (burst > len) burst = len; else fullBurst = 1; if (readTrackData(buf, burst * SAMPLE_LEN) <= 0) return -1; buf += burst; len -= burst; readPosSample_ += burst; ret += burst; if (subChanLen > 0 && fullBurst && (unsigned long)readPosSample_ < track_->length_.samples()) { if (readTrackData((Sample*)subChanBuf, subChanLen) < 0) return -1; } } } } else { for (i = 0; i < len; i++) { buf[i].left(16000); buf[i].right(16000); } readPosSample_ += len; ret = len; } return ret; } const char* TrackReader::curFilename() { const TrackData* td = reader.trackData(); if (td) return td->filename(); else return NULL; } SubTrackIterator::SubTrackIterator(const Track *t) { track_ = t; iterator_ = NULL; } SubTrackIterator::~SubTrackIterator() { track_ = NULL; iterator_ = NULL; } const SubTrack *SubTrackIterator::first() { iterator_ = track_->subTracks_; return next(); } const SubTrack *SubTrackIterator::next() { if (iterator_ != NULL) { SubTrack *s = iterator_; iterator_ = iterator_->next_; return s; } else { return NULL; } } cdrdao-cdrdao-f00afb2/trackdb/Track.h000066400000000000000000000147421511453746600175350ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller * * 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. */ #ifndef __TRACK_H__ #define __TRACK_H__ #include #include #include "SubTrack.h" #include "Msf.h" #include "CdTextContainer.h" #include "CdTextItem.h" #include "util.h" class TrackDataList; class Track { public: Track(TrackData::Mode, TrackData::SubChannelMode); Track(const Track &); ~Track(); TrackData::Mode type() const { return type_; } TrackData::SubChannelMode subChannelType() const { return subChannelType_; } int audioCutMode() const { return audioCutMode_; } Msf length() const { return length_; } Msf start() const { return start_; } int start(Msf); Msf end() const { return end_; } int end(Msf); int isPadded() const; int nofSubTracks() const { return nofSubTracks_; } // return first/last sub-track const SubTrack *firstSubTrack() const; const SubTrack *lastSubTrack() const; int append(const SubTrack &); int nofIndices() const { return nofIndices_; } int appendIndex(const Msf &); int addIndex(const Msf &index); int removeIndex(int); Msf getIndex(int) const; int moveIndex(int index, long lba); TrackDataList *removeToEnd(unsigned long samplePos); TrackDataList *removeFromStart(unsigned long sample); void prependTrackData(const TrackDataList *); void appendTrackData(const TrackDataList *); void appendTrackData(const Track *); TrackDataList *removeTrackData(unsigned long start, unsigned long end); void insertTrackData(unsigned long pos, const TrackDataList *list); // fills provided buffer with an audio block that contains zero data // encoded with given mode static void encodeZeroData(int encMode, TrackData::Mode, TrackData::SubChannelMode, long lba, unsigned char *); int check(int trackNr) const; int isrcValid() const { return isrcValid_; } // set ISRC code from given string int isrc(const char *); // sets ISRC code const char *isrc() const; char isrcCountry(int i) const { return isrcCountry_[i]; } // ASCII char isrcOwner(int i) const { return isrcOwner_[i]; } // ASCII char isrcYear(int i) const { return isrcYear_[i]; } // BCD char isrcSerial(int i) const { return isrcSerial_[i]; } // BCD // return/set COPY flag (1: copy permitted, 0: copy not permitted) int copyPermitted() const { return flags_.copy; } void copyPermitted(int c) { flags_.copy = c != 0 ? 1 : 0; } // return/set PRE-EMPHASIS flag (1: audio with pre-emphasis, // 0: audio without pre-emphasis int preEmphasis() const { return flags_.preEmphasis; } void preEmphasis(int p) { flags_.preEmphasis = p != 0 ? 1 : 0; } // return/set audio type (0: two channel audio, 1: four channel audio) int audioType() const { return flags_.audioType; } void audioType(int t) { flags_.audioType = t != 0 ? 1 : 0; } void addCdTextItem(CdTextItem*); void removeCdTextItem(CdTextItem::PackType, int blockNr); int existCdTextBlock(int n) const { return cdtext_.existBlock(n); } const CdTextItem *getCdTextItem(int blockNr, CdTextItem::PackType t) const { return cdtext_.getPack(blockNr, t); } const CdTextContainer& getCdTextItems() const { return cdtext_; } void print(std::ostream &, PrintParams&) const; void collectFiles(std::set& set); void markFileConversion(const char* src, const char* dst); bool resolveFilename(const char* path); bool recomputeLength(); private: friend class TocParserGram; friend class Toc; friend class TrackReader; friend class SubTrackIterator; TrackData::Mode type_; // track type TrackData::SubChannelMode subChannelType_; // sub-channel mode int audioCutMode_; /* -1: undefined 1: lengths of all sub-tracks are in units of samples 0: lengths of all sub-tracks are in byte units */ Msf length_; // total length of track Msf start_; // logical start of track data, end of pre-gap // (where index switches from 0 to 1) Msf end_; // end of track data, start of post-gap int nofSubTracks_; // number of sub tracks SubTrack *subTracks_; // list of subtracks SubTrack *lastSubTrack_; // points to last sub-track in list int nofIndices_; // number of index increments Msf *index_; // index increment times int isrcValid_; char isrcCountry_[2]; char isrcOwner_[3]; char isrcYear_[2]; char isrcSerial_[5]; struct { unsigned int copy : 1; unsigned int preEmphasis : 1; unsigned int audioType : 1; } flags_; CdTextContainer cdtext_; void update(); void insertSubTrackAfter(SubTrack *, SubTrack *newSubtrack); SubTrack *removeSubTrack(SubTrack *); void countSubTracks(); void mergeSubTracks(); SubTrack *findSubTrack(unsigned long sample) const; void checkConsistency(); }; class TrackReader { public: TrackReader(const Track * = 0); ~TrackReader(); void init(const Track *); int openData(); long readData(int raw, int subChanEncodingMode, long lba, char *buf, long len); int seekSample(unsigned long sample); long readSamples(Sample *buf, long len); void closeData(); const char* curFilename(); private: const Track *track_; TrackDataReader reader; long readPos_; // current read position (blocks) long readPosSample_; // current read position (samples) const SubTrack *readSubTrack_; // actual read sub-track int open_; // 1 indicates the 'openData()' was called unsigned long subChanDelayLineIndex_; unsigned char subChanDelayLine_[8][24]; long readTrackData(Sample *buf, long len); int readBlock(int raw, int subChanEncodingMode, long lba, Sample *buf); }; class SubTrackIterator { public: SubTrackIterator(const Track *); ~SubTrackIterator(); const SubTrack *first(); const SubTrack *next(); private: const Track *track_; SubTrack *iterator_; }; #endif cdrdao-cdrdao-f00afb2/trackdb/TrackData.cc000066400000000000000000000704311511453746600204620ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller * * 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. */ #include #include #include #include #include #include #include #include #include #include "TrackData.h" #include "Msf.h" #include "util.h" #include "log.h" #ifdef UNIXWARE extern "C" { extern int strcasecmp(const char *, const char *); } #endif // creates an object representing a portion of an audio data file TrackData::TrackData(const char *filename, long offset, unsigned long start, unsigned long length) { init(filename, offset, start, length); } TrackData::TrackData(const char *filename, unsigned long start, unsigned long length) { init(filename, 0, start, length); } void TrackData::init(const char *filename, long offset, unsigned long start, unsigned long length) { assert(offset >= 0); length_ = length; if (strcmp(filename, "-") == 0) { type_ = STDIN; fileType_ = RAW; // currently only raw data filename_ = strdupCC("STDIN"); } else { type_ = DATAFILE; filename_ = strdupCC(filename); fileType_ = audioFileType(filename_); } effFilename_ = NULL; offset_ = offset; startPos_ = start; swapSamples_ = 0; mode_ = AUDIO; subChannelMode_ = SUBCHAN_NONE; audioCutMode_ = 1; } // creates an AUDIO mode object that contains constant zero data TrackData::TrackData(unsigned long length) { type_ = ZERODATA; mode_ = AUDIO; subChannelMode_ = SUBCHAN_NONE; audioCutMode_ = 1; filename_ = NULL; effFilename_ = NULL; fileType_ = RAW; startPos_ = 0; offset_ = 0; length_ = length; swapSamples_ = 0; } // creates an object that contains constant data with specified mode TrackData::TrackData(Mode m, SubChannelMode sm, unsigned long length) { type_ = ZERODATA; mode_ = m; subChannelMode_ = sm; audioCutMode_ = 0; filename_ = NULL; effFilename_ = NULL; fileType_ = RAW; startPos_ = 0; offset_ = 0; length_ = length; swapSamples_ = 0; } // creates a file object with given mode TrackData::TrackData(Mode m, SubChannelMode sm, const char *filename, long offset, unsigned long length) { init(m, sm, filename, offset, length); } void TrackData::init(Mode m, SubChannelMode sm, const char *filename, long offset, unsigned long length) { assert(offset >= 0); mode_ = m; subChannelMode_ = sm; audioCutMode_ = 0; if (strcmp(filename, "-") == 0) { type_ = STDIN; fileType_ = RAW; // currently only raw data filename_ = strdupCC("STDIN"); } else { type_ = DATAFILE; filename_ = strdupCC(filename); if (mode_ == AUDIO) fileType_ = audioFileType(filename_); else fileType_ = RAW; // data files are always raw } offset_ = offset; length_ = length; effFilename_ = NULL; startPos_ = 0; swapSamples_ = 0; } TrackData::TrackData(Mode m, SubChannelMode sm, const char *filename, unsigned long length) { assert(filename != NULL && *filename != 0); mode_ = m; subChannelMode_ = sm; audioCutMode_ = 0; type_ = FIFO; fileType_ = RAW; filename_ = strdupCC(filename); effFilename_ = NULL; offset_ = 0; length_ = length; startPos_ = 0; swapSamples_ = 0; } // copy constructor TrackData::TrackData(const TrackData &obj) { type_ = obj.type_; mode_ = obj.mode_; subChannelMode_ = obj.subChannelMode_; audioCutMode_ = obj.audioCutMode_; offset_ = obj.offset_; switch (type_) { case DATAFILE: case STDIN: case FIFO: filename_ = strdupCC(obj.filename_); effFilename_ = (obj.effFilename_ ? strdupCC(obj.effFilename_) : NULL); startPos_ = obj.startPos_; fileType_ = obj.fileType_; break; case ZERODATA: filename_ = NULL; effFilename_ = NULL; startPos_ = 0; fileType_ = RAW; break; } length_ = obj.length_; swapSamples_ = obj.swapSamples_; } TrackData::~TrackData() { if (filename_) { delete[] filename_; } if (effFilename_) delete[] effFilename_; } unsigned long TrackData::length() const { return length_; } // Determines length of data by inspecting the data file. The available data // from the specified start point up to the end of file is stored in 'length_'. // Return: 0: OK // 1: cannot open or access the file (see 'errno') // 2: start pos or offset exceeds length of file // 3: track needs conversion to WAV // 4: format is not supported int TrackData::determineLength() { unsigned long len; if (type_ == DATAFILE) { if (mode_ == AUDIO) { switch (audioDataLength(filename_, offset_, &len)) { case 1: log_message(-2, "Cannot open audio file \"%s\": %s", filename_, strerror(errno)); return 1; break; case 2: log_message(-2, "Cannot determine length of audio file \"%s\": %s", filename_, strerror(errno)); return 1; break; case 3: log_message(-2, "Header of audio file \"%s\" is corrupted.", filename_); return 1; break; case 4: log_message(-2, "Invalid offset %ld for audio file \"%s\".", offset_, filename_); return 2; break; case 5: #ifndef HAVE_MP3_SUPPORT if (audioFileType(filename_) == MP3) { log_message (-2, "Can't read file \"%s\": cdrdao was compiled " "without MP3 support.", filename_); return 4; } #endif #ifndef HAVE_OGG_SUPPORT if (audioFileType(filename_) == OGG) { log_message (-2, "Can't read file \"%s\": cdrdao was compiled " "without Ogg/Vorbis support.", filename_); return 4; } #endif return 3; } if (audioCutMode()) { if (startPos_ < len) { length_ = len - startPos_; } else { log_message(-2, "Start position %lu exceeds available data of file \"%s\".", startPos_, filename_); return 2; } } else { length_ = len * sizeof(Sample); } } else { switch (dataFileLength(filename_, offset_, &len)) { case 1: log_message(-2, "Cannot open data file \"%s\": %s", filename_, strerror(errno)); return 1; break; case 2: log_message(-2, "Invalid offset %ld for audio file \"%s\".", offset_, filename_); return 2; break; } length_ = len; } } return 0; } // checks the consistency of object // return: 0: OK // 1: warning occured // 2: error occured int TrackData::check(int trackNr) const { switch (type_) { case ZERODATA: // always OK break; case STDIN: // cannot do much here... break; case FIFO: if (access(filename_, R_OK) != 0) { log_message(-2, "Track %d: Cannot access FIFO \"%s\": %s", trackNr, filename_, strerror(errno)); return 2; } break; case DATAFILE: if (mode_ == AUDIO) { unsigned long len = 0; if (fileType_ == WAVE && subChannelMode_ != SUBCHAN_NONE) { log_message(-2, "Track %d: WAVE audio files cannot contain sub-channel " "data.", trackNr); return 2; } switch (audioDataLength(filename_, offset_, &len)) { case 1: log_message(-2, "Track %d: Cannot open audio file \"%s\": %s", trackNr, filename_, strerror(errno)); return 2; break; case 2: log_message(-2, "Track %d: Cannot access audio file \"%s\": %s", trackNr, filename_, strerror(errno)); return 2; break; case 3: log_message(-2, "Track %d: %s: Unacceptable WAVE file.", trackNr, filename_); return 2; break; case 4: log_message(-2, "Track %d: Invalid offset %ld for audio file \"%s\".", trackNr, offset_, filename_); return 2; break; } if (length() == 0) { log_message(-2, "Track %d: Requested length for audio file \"%s\" is 0.", trackNr, filename_); return 2; } if (audioCutMode()) { if (startPos_ + length() > len) { // requested part exceeds file size log_message(-2, "Track %d: Requested length (%lu + %lu samples) exceeds " "length of audio file \"%s\" (%lu samples at offset %ld).", trackNr, startPos_, length(), filename_, len, offset_); return 2; } } else { if (length() > len * sizeof(Sample)) { log_message(-2, "Track %d: Requested length (%lu bytes) exceeds length of file \"%s\" (%lu bytes at offset %ld).", trackNr, length(), filename_, len, offset_); return 2; } } } else { // data mode unsigned long len; switch (dataFileLength(filename_, offset_, &len)) { case 1: log_message(-2, "Track %d: Cannot open data file \"%s\": %s", trackNr, filename_, strerror(errno)); return 2; break; case 2: log_message(-2, "Track %d: Invalid offset %ld for data file \"%s\".", trackNr, offset_, filename_); return 2; break; } if (length() == 0) { log_message(-2, "Track %d: Requested length for data file \"%s\" is 0.", trackNr, filename_); return 2; } if (length() > len) { log_message(-2, "Track %d: Requested length (%lu bytes) exceeds length of file \"%s\" (%lu bytes at offset %ld).", trackNr, length(), filename_, len, offset_); return 2; } } break; } return 0; } void TrackData::effectiveFilename(const char* name) { if (effFilename_) delete[] effFilename_; effFilename_ = filename_; filename_ = strdupCC(name); fileType_ = audioFileType(filename_); } // writes out contents of object in TOC file syntax void TrackData::print(std::ostream &out, PrintParams& params) const { unsigned long blen; const char *s; if (audioCutMode()) { // we're calculating in samples and not in bytes for audio data blen = SAMPLES_PER_BLOCK; } else { blen = dataBlockSize(mode(), subChannelMode()); } switch (type()) { case STDIN: case DATAFILE: if (audioCutMode()) { if (type() == STDIN) out << "FILE \"-\" "; else if (effFilename_ && !params.conversions) out << "FILE \"" << effFilename_ << "\" "; else out << "FILE \"" << filename_ << "\" "; if (swapSamples_) out << "SWAP "; if (offset_ > 0) out << "#" << offset_ << " "; if (startPos() != 0 && (startPos() % blen) == 0) out << Msf(startPos() / blen).str(); else out << startPos(); out << " "; } else { // data mode if (type() == STDIN) out << "DATAFILE \"-\" "; else if (effFilename_ && !params.conversions) out << "DATAFILE \"" << effFilename_ << "\" "; else out << "DATAFILE \"" << filename_ << "\" "; //out << mode2String(mode()) << " "; if (offset_ > 0) out << "#" << offset_ << " "; } if ((length() % blen) == 0) out << Msf(length() / blen).str(); else out << length(); if (!audioCutMode()) out << " // length in bytes: " << length(); out << std::endl; break; case FIFO: out << "FIFO \"" << filename_ << "\" "; if ((length() % blen) == 0) { out << Msf(length() / blen).str(); out << " // length in bytes: " << length(); } else { out << length(); } out << std::endl; break; case ZERODATA: if (audioCutMode()) { out << "SILENCE "; } else { out << "ZERO " << mode2String(mode()) << " "; } s = subChannelMode2String(subChannelMode()); if (*s != 0) out << s << " "; if ((length() % blen) == 0) out << Msf(length() / blen).str(); else out << length(); out << std::endl; break; } } void TrackData::split(unsigned long pos, TrackData **part1, TrackData **part2) { assert(mode_ == AUDIO); assert(pos > 0 && pos < length_); *part1 = new TrackData(*this); *part2 = new TrackData(*this); (*part1)->length_ = pos; (*part2)->length_ = length_ - pos; if (type_ == DATAFILE) (*part2)->startPos_ = startPos_ + pos; } TrackData *TrackData::merge(const TrackData *obj) const { if (mode_ != AUDIO || type_ != obj->type_ || mode_ != obj->mode_ || subChannelMode_ != obj->subChannelMode_ || offset_ != obj->offset_ || audioCutMode_ != obj->audioCutMode_) return NULL; TrackData *data = NULL; switch (type_) { case ZERODATA: data = new TrackData(*this); data->length_ += obj->length_; break; case DATAFILE: if (strcmp(filename_, obj->filename_) == 0 && startPos_ + length_ == obj->startPos_) { data = new TrackData(*this); data->length_ += obj->length_; } break; case STDIN: case FIFO: // can't merge this type at all break; } return data; } // Checks if given audio file is suitable for cdrdao. 'length' is filled // with number of samples in audio file on success. // return: 0: file is suitable // 1: cannot open or access file // 2: file has wrong format int TrackData::checkAudioFile(const char *fn, unsigned long *length) { int fd; int ret; struct stat buf; long headerLength = 0; enum FileType ft = audioFileType(fn); if (ft != WAVE && ft != RAW) { log_message(-2, "Checking audio file \"%s\": format not supported", fn); return 1; } if ((fd = open(fn, O_RDONLY)) < 0) return 1; ret = fstat(fd, &buf); close(fd); if (ret != 0) return 1; if (ft == WAVE) { if (waveLength(fn, 0, &headerLength, length) != 0) return 2; } else { if (buf.st_size % sizeof(Sample) != 0) { log_message(-1, "%s: Length is not a multiple of sample size (4).", fn); } *length = buf.st_size / sizeof(Sample); } return 0; } // Determines length of header and audio data for WAVE files. 'hdrlen' is // filled with length of WAVE header in bytes. 'datalen' is filled with // length of audio data in samples (if != NULL). // return: 0: OK // 1: error occured // 2: illegal WAVE file int TrackData::waveLength(const char *filename, long offset, long *hdrlen, unsigned long *datalen) { FILE *fp; char magic[4]; long headerLen = 0; long len; short waveFormat; short waveChannels; long waveRate; short waveBits; struct stat sbuf; #ifdef __CYGWIN__ if ((fp = fopen(filename, "rb")) == NULL) #else if ((fp = fopen(filename, "r")) == NULL) #endif { log_message(-2, "Cannot open audio file \"%s\" for reading: %s", filename, strerror(errno)); return 1; } if (offset != 0) { if (fseek(fp, offset, SEEK_SET) != 0) { log_message(-2, "Cannot seek to offset %ld in file \"%s\": %s", offset, filename, strerror(errno)); return 1; } } if (fread(magic, sizeof(char), 4, fp) != 4 || strncmp("RIFF", magic, 4) != 0) { log_message(-2, "%s: not a WAVE file.", filename); fclose(fp); return 2; } readLong(fp); if (fread(magic, sizeof(char), 4, fp) != 4 || strncmp("WAVE", magic, 4) != 0) { log_message(-2, "%s: not a WAVE file.", filename); fclose(fp); return 2; } // search for format chunk for (;;) { if (fread(magic, sizeof(char), 4, fp) != 4) { log_message(-2, "%s: corrupted WAVE file.", filename); fclose(fp); return 1; } len = readLong(fp); len += len & 1; // round to multiple of 2 if (strncmp("fmt ", magic, 4) == 0) { // format chunk found break; } // skip chunk data if (fseek(fp, len, SEEK_CUR) != 0) { log_message(-2, "%s: corrupted WAVE file.", filename); fclose(fp); return 1; } } if (len < 16) { log_message(-2, "%s: corrupted WAVE file.", filename); fclose(fp); return 1; } waveFormat = readShort(fp); if (waveFormat != 1 && waveFormat != -2) { // not PCM format log_message(-2, "%s: not in PCM format.", filename); fclose(fp); return 2; } waveChannels = readShort(fp); if (waveChannels != 2) { log_message(-2, "%s: found %d channel(s), require 2 channels.", filename, waveChannels); fclose(fp); return 2; } waveRate = readLong(fp); if (waveRate != 44100) { log_message(-2, "%s: found sampling rate %ld, require 44100.", filename, waveRate); fclose(fp); return 2; } readLong(fp); // average bytes/second readShort(fp); // block align waveBits = readShort(fp); if (waveBits != 16) { log_message(-2, "%s: found %d bits per sample, require 16.", filename, waveBits); fclose(fp); return 2; } len -= 16; // skip chunk data if (fseek(fp, len, SEEK_CUR) != 0) { log_message(-2, "%s: corrupted WAVE file.", filename); fclose(fp); return 1; } // search wave data chunk for (;;) { if (fread(magic, sizeof(char), 4, fp) != 4) { log_message(-2, "%s: corrupted WAVE file.", filename); fclose(fp); return 1; } len = readLong(fp); if (strncmp("data", magic, 4) == 0) { // found data chunk break; } len += len & 1; // round to multiple of 2 // skip chunk data if (fseek(fp, len, SEEK_CUR) != 0) { log_message(-2, "%s: corrupted WAVE file.", filename); fclose(fp); return 1; } } if ((headerLen = ftell(fp)) < 0) { log_message(-2, "%s: cannot determine file position: %s", filename, strerror(errno)); fclose(fp); return 1; } headerLen -= offset; if (fstat(fileno(fp), &sbuf) != 0) { log_message(-2, "Cannot fstat audio file \"%s\": %s", filename, strerror(errno)); fclose(fp); return 1; } fclose(fp); if (len + headerLen + offset > sbuf.st_size) { log_message(-1, "%s: file length does not match length from WAVE header - using actual length.", filename); len = sbuf.st_size - offset - headerLen; } if (len % sizeof(Sample) != 0) { log_message(-1, "%s: length of data chunk is not a multiple of sample size (4).", filename); } *hdrlen = headerLen; if (datalen != NULL) { *datalen = len / sizeof(Sample); } return 0; } // Returns length in samples for given audio file. // return: 1: file cannot be opened // 2: 'fstat' failed // 3: file header corruption // 4: invalid offset // 5: file need conversion // 0: OK int TrackData::audioDataLength(const char *fname, long offset, unsigned long *length) { int fd; struct stat buf; long headerLength = 0; int ret; *length = 0; if ((fd = open(fname, O_RDONLY)) < 0) return 1; ret = fstat(fd, &buf); close(fd); if (ret != 0) return 2; if (offset > buf.st_size) return 4; FileType ftype = audioFileType(fname); if (ftype == WAVE) { if (waveLength(fname, offset, &headerLength, length) != 0) return 3; } else if (ftype == MP3 || ftype == OGG) { return 5; } else { if (((buf.st_size - offset) % sizeof(Sample)) != 0) { log_message(-1, "Length of file \"%s\" is not a multiple of sample size (4).", fname); } *length = (buf.st_size - offset) / sizeof(Sample); } return 0; } // Sets 'length' to length of given data file. // return: 0: OK // 1: file cannot be opened or accessed // 2: invalid offset int TrackData::dataFileLength(const char *fname, long offset, unsigned long *length) { int fd; struct stat buf; int ret; *length = 0; if ((fd = open(fname, O_RDONLY)) < 0) return 1; ret = fstat(fd, &buf); close(fd); if (ret != 0) return 1; if (offset > buf.st_size) return 2; *length = buf.st_size - offset; return 0; } // determines type of audio file // return: RAW: raw samples // WAVE: wave file TrackData::FileType TrackData::audioFileType(const char *filename) { Util::FileExtension p = Util::fileExtension(filename); if (p == Util::FileExtension::WAV) return WAVE; if (p == Util::FileExtension::MP3) return MP3; if (p == Util::FileExtension::OGG) return OGG; return RAW; } unsigned long TrackData::subChannelSize(SubChannelMode sm) { unsigned long b = 0; switch (sm) { case SUBCHAN_NONE: b = 0; break; case SUBCHAN_RW: case SUBCHAN_RW_RAW: b = PW_SUBCHANNEL_LEN; break; } return b; } unsigned long TrackData::dataBlockSize(Mode m, SubChannelMode sm) { unsigned long b = 0; switch (m) { case AUDIO: case MODE1_RAW: case MODE2_RAW: b = AUDIO_BLOCK_LEN; break; case MODE0: b = MODE0_BLOCK_LEN; break; case MODE1: b = MODE1_BLOCK_LEN; break; case MODE2: case MODE2_FORM_MIX: b = MODE2_BLOCK_LEN; break; case MODE2_FORM1: b = MODE2_FORM1_DATA_LEN; break; case MODE2_FORM2: b = MODE2_FORM2_DATA_LEN; break; } b += subChannelSize(sm); return b; } const char *TrackData::mode2String(Mode m) { const char *ret = NULL; switch (m) { case AUDIO: ret = "AUDIO"; break; case MODE0: ret = "MODE0"; break; case MODE1: ret = "MODE1"; break; case MODE1_RAW: ret = "MODE1_RAW"; break; case MODE2: ret = "MODE2"; break; case MODE2_RAW: ret = "MODE2_RAW"; break; case MODE2_FORM1: ret = "MODE2_FORM1"; break; case MODE2_FORM2: ret = "MODE2_FORM2"; break; case MODE2_FORM_MIX: ret = "MODE2_FORM_MIX"; break; } return ret; } const char *TrackData::subChannelMode2String(SubChannelMode m) { const char *ret = NULL; switch (m) { case SUBCHAN_NONE: ret = ""; break; case SUBCHAN_RW: ret = "RW"; break; case SUBCHAN_RW_RAW: ret = "RW_RAW"; break; } return ret; } TrackDataReader::TrackDataReader(const TrackData *d) { trackData_ = d; open_ = 0; fd_ = -1; readPos_ = 0; headerLength_ = 0; readUnderRunMsgGiven_ = 0; } TrackDataReader::~TrackDataReader() { if (open_) { closeData(); } trackData_ = NULL; } void TrackDataReader::init(const TrackData *d) { if (open_) { closeData(); } trackData_ = d; } // initiates reading audio data, an audio data file is opened // return: 0: OK // 1: file could not be opened // 2: could not seek to start position int TrackDataReader::openData() { assert(open_ == 0); assert(trackData_ != NULL); if (trackData_->type_ == TrackData::DATAFILE) { if (trackData_->mode_ == TrackData::AUDIO) { long headerLength = 0; if (trackData_->fileType_ != TrackData::WAVE && trackData_->fileType_ != TrackData::RAW) { log_message(-2, "Cannot open audio file \"%s\": unsupported format", trackData_->filename_); return 1; } #ifdef __CYGWIN__ if ((fd_ = open(trackData_->filename_, O_RDONLY | O_BINARY)) < 0) #else if ((fd_ = open(trackData_->filename_, O_RDONLY)) < 0) #endif { log_message(-2, "Cannot open audio file \"%s\": %s", trackData_->filename_, strerror(errno)); return 1; } if (trackData_->fileType_ == TrackData::WAVE) { if (TrackData::waveLength(trackData_->filename_, trackData_->offset_, &headerLength) != 0) { log_message(-2, "%s: Unacceptable WAVE file.", trackData_->filename_); return 1; } } if (lseek(fd_, trackData_->offset_ + headerLength + (trackData_->startPos_ * sizeof(Sample)), SEEK_SET) < 0) { log_message(-2, "Cannot seek in audio file \"%s\": %s", trackData_->filename_, strerror(errno)); return 2; } headerLength_ = headerLength; } else { // data mode headerLength_ = 0; #ifdef __CYGWIN__ if ((fd_ = open(trackData_->filename_, O_RDONLY | O_BINARY)) < 0) #else if ((fd_ = open(trackData_->filename_, O_RDONLY)) < 0) #endif { log_message(-2, "Cannot open data file \"%s\": %s", trackData_->filename_, strerror(errno)); return 1; } if (trackData_->offset_ > 0) { if (lseek(fd_, trackData_->offset_ , SEEK_SET) < 0) { log_message(-2, "Cannot seek to offset %ld in file \"%s\": %s", trackData_->offset_, trackData_->filename_, strerror(errno)); return 2; } } } } else if (trackData_->type_ == TrackData::FIFO) { #ifdef __CYGWIN__ if ((fd_ = open(trackData_->filename_, O_RDONLY | O_BINARY)) < 0) #else if ((fd_ = open(trackData_->filename_, O_RDONLY)) < 0) #endif { log_message(-2, "Cannot open FIFO \"%s\": %s", trackData_->filename_, strerror(errno)); return 1; } headerLength_ = 0; } else if (trackData_->type_ == TrackData::STDIN) { headerLength_ = 0; fd_ = fileno(stdin); } readPos_ = 0; open_ = 1; readUnderRunMsgGiven_ = 0; return 0; } // ends reading audio data, an audio data file is closed void TrackDataReader::closeData() { if (open_ != 0) { if (trackData_->type_ == TrackData::DATAFILE || trackData_->type_ == TrackData::FIFO) { close(fd_); } fd_ = -1; open_ = 0; readPos_ = 0; } } // fills 'buffer' with 'len' samples (in case of audio mode) or with 'len' // bytes of data (for all other modes) // return: number of samples written to buffer long TrackDataReader::readData(Sample *buffer, long len) { long readLen = 0; assert(open_ != 0); if (len == 0) { return 0; } if (readPos_ + len > trackData_->length()) { if ((len = trackData_->length() - readPos_) <= 0) { return 0; } } switch (trackData_->type_) { case TrackData::ZERODATA: if (trackData_->audioCutMode()) memset(buffer, 0, len * sizeof(Sample)); else memset(buffer, 0, len); readLen = len; break; case TrackData::STDIN: case TrackData::DATAFILE: case TrackData::FIFO: if (trackData_->audioCutMode()) { readLen = fullRead(fd_, buffer, len * sizeof(Sample)); if (readLen < 0) { log_message(-2, "Read error while reading audio data from file \"%s\": %s", trackData_->filename_, strerror(errno)); } else if (readLen != (long)(len * sizeof(Sample))) { long pad = len * sizeof(Sample) - readLen; if (readUnderRunMsgGiven_ == 0) { log_message(-1, "Could not read expected amount of audio data from file \"%s\".", trackData_->filename_); log_message(-1, "Padding with zeros."); readUnderRunMsgGiven_ = 1; } // Adding zeros to the 'buffer' memset(buffer + readLen, 0, pad); readLen = len; } else { readLen = len; } } else { readLen = fullRead(fd_, buffer, len); if (readLen < 0) { log_message(-2, "Read error while reading data from file \"%s\": %s", trackData_->filename_, strerror(errno)); } else if (readLen != len) { log_message(-2, "Could not read expected amount of data from file \"%s\".", trackData_->filename_); readLen = -1; } } break; } if (readLen > 0) { if (trackData_->mode_ == TrackData::AUDIO && trackData_->subChannelMode_ == TrackData::SUBCHAN_NONE) { int swap = 0; if (trackData_->fileType_ == TrackData::WAVE) { // WAVE files contain little endian samples swap = 1; } if (trackData_->swapSamples_) swap = !swap; if (swap) { // swap samples if (trackData_->audioCutMode()) swapSamples(buffer, readLen); else swapSamples(buffer, readLen / sizeof(Sample)); } } readPos_ += readLen; } return readLen; } // Seeks to specified sample. // return: 0: OK // 10: sample out of range int TrackDataReader::seekSample(unsigned long sample) { assert(open_ != 0); if (sample >= trackData_->length()) return 10; if (trackData_->type_ == TrackData::DATAFILE) { if (trackData_->audioCutMode()) { // 'sample' has samples as unit if (lseek(fd_, trackData_->offset_ + headerLength_ + (sample * sizeof(Sample)) + (trackData_->startPos_ * sizeof(Sample)), SEEK_SET) < 0) { log_message(-2, "Cannot seek in audio file \"%s\": %s", trackData_->filename_, strerror(errno)); return 10; } } else { // 'sample' has byte as unit if (lseek(fd_, trackData_->offset_ + headerLength_ + sample, SEEK_SET) < 0) { log_message(-2, "Cannot seek in audio file \"%s\": %s", trackData_->filename_, strerror(errno)); return 10; } } } readPos_ = sample; return 0; } // Returns number of bytes that are still available for reading. unsigned long TrackDataReader::readLeft() const { assert(open_ != 0); assert(trackData_ != NULL); return trackData_->length() - readPos_; } cdrdao-cdrdao-f00afb2/trackdb/TrackData.h000066400000000000000000000133471511453746600203270ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller * * 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. */ #ifndef __TRACKDATA_H__ #define __TRACKDATA_H__ #include #include #include #include "Sample.h" #include "util.h" #define AUDIO_BLOCK_LEN 2352 #define MODE0_BLOCK_LEN 2336 #define MODE1_BLOCK_LEN 2048 #define MODE2_BLOCK_LEN 2336 #define MODE2_FORM1_DATA_LEN 2048 #define MODE2_FORM2_DATA_LEN 2324 #define PQ_SUBCHANNEL_LEN 16 #define PW_SUBCHANNEL_LEN 96 #define MAX_SUBCHANNEL_LEN 96 #define SAMPLE_LEN 4 class TrackData { public: enum Mode { AUDIO, MODE0, MODE1, MODE2, MODE2_FORM1, MODE2_FORM2, MODE2_FORM_MIX, MODE1_RAW, MODE2_RAW }; enum SubChannelMode { SUBCHAN_NONE, SUBCHAN_RW, SUBCHAN_RW_RAW }; enum Type { DATAFILE, ZERODATA, STDIN, FIFO }; enum FileType { RAW, WAVE, MP3, OGG }; // creates an audio mode file entry TrackData(const char *filename, long offset, unsigned long start, unsigned long length); TrackData(const char *filename, unsigned long start, unsigned long length); // creates a zero audio entry TrackData(unsigned long length); // creates a zero data entry with given mode TrackData(Mode, SubChannelMode, unsigned long length); // creates a file entry with given mode TrackData(Mode, SubChannelMode, const char *filename, long offset, unsigned long length); // create a fifo entry with given mode TrackData(Mode, SubChannelMode, const char *filename, unsigned long length); // copy constructor TrackData(const TrackData &); ~TrackData(); Type type() const { return type_; } Mode mode() const { return mode_; } SubChannelMode subChannelMode() const { return subChannelMode_; } int audioCutMode() const { return audioCutMode_; } const char *filename() const { return filename_; } unsigned long startPos() const { return startPos_; } unsigned long length() const; // sets/returns flag for swapping expected byte order of audio samples void swapSamples(int f) { swapSamples_ = f != 0 ? 1 : 0; } int swapSamples() const { return swapSamples_; } int determineLength(); int check(int trackNr) const; void effectiveFilename(const char*); void split(unsigned long, TrackData **part1, TrackData **part2); TrackData *merge(const TrackData *) const; void print(std::ostream &, PrintParams&) const; static int checkAudioFile(const char *fn, unsigned long *length); static int waveLength(const char *filename, long offset, long *hdrlen, unsigned long *datalen = 0); static int audioDataLength(const char *fname, long offset, unsigned long *length); static FileType audioFileType(const char *filename); static int dataFileLength(const char *fname, long offset, unsigned long *length); static unsigned long dataBlockSize(Mode, SubChannelMode); static unsigned long subChannelSize(SubChannelMode); static const char *mode2String(Mode); static const char *subChannelMode2String(SubChannelMode); private: int audioCutMode_; /* defines if audio cut mode is requested, if yes all lengths are in sample units and sub-channel data is not allowed */ Type type_; // type of data (file, stdin, zero) Mode mode_; // data mode for recording (audio, mode0, mode1, ...) SubChannelMode subChannelMode_; // sub-channel mode FileType fileType_; // only for audio mode data, type of file (raw, wave) char *filename_; // used for object type 'FILE' char *effFilename_; // effective filename (absolute path or converted file) long offset_; // byte offset into file unsigned long length_; // length of data in samples (for audio data) or bytes // only used for audio files: unsigned long startPos_; // starting sample within file, // used for object type 'FILE', mode 'AUDIO' int swapSamples_; // 1 if expected byte order of audio samples should // be swapped friend class TrackDataReader; void init(const char *filename, long offset, unsigned long start, unsigned long length); void init(Mode, SubChannelMode, const char *filename, long offset, unsigned long length); }; class TrackDataReader { public: TrackDataReader(const TrackData * = 0); ~TrackDataReader(); void init(const TrackData *); int openData(); void closeData(); long readData(Sample *buffer, long len); int seekSample(unsigned long sample); const TrackData* trackData() const { return trackData_; } // returns number of bytes/samples that are left for reading unsigned long readLeft() const; private: const TrackData *trackData_; int open_; // 1: data can be retrieved with 'readData()', 'fd_' is valid if // object type is 'FILE' int fd_; // used for object type 'FILE' unsigned long readPos_; // actual read position (samples or bytes) // (0 .. length_-1) long headerLength_; // length of audio file header int readUnderRunMsgGiven_; }; #endif cdrdao-cdrdao-f00afb2/trackdb/TrackDataList.cc000066400000000000000000000036711511453746600213200ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller * * 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. */ #include #include "TrackDataList.h" #include "TrackData.h" TrackDataList::TrackDataList() { list_ = last_ = NULL; iterator_ = NULL; count_ = 0; } void TrackDataList::append(TrackData *a) { Entry *ent = new Entry; ent->data = a; ent->next = NULL; if (list_ == NULL) list_ = ent; else last_->next = ent; last_ = ent; count_++; } unsigned long TrackDataList::length() const { unsigned long len = 0; Entry *run; for (run = list_; run != NULL; run = run->next) len += run->data->length(); return len; } void TrackDataList::clear() { Entry *next; while (list_ != NULL) { next = list_->next; delete list_->data; delete list_; list_ = next; } last_ = NULL; iterator_ = NULL; count_ = 0; } const TrackData *TrackDataList::first() const { if ((((TrackDataList *)this)->iterator_ = list_) != NULL) return iterator_->data; else return NULL; } const TrackData *TrackDataList::next() const { if (iterator_ == NULL || (((TrackDataList *)this)->iterator_ = iterator_->next) == NULL) return NULL; else return iterator_->data; } cdrdao-cdrdao-f00afb2/trackdb/TrackDataList.h000066400000000000000000000024651511453746600211620ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller * * 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. */ #ifndef __TRACKDATALIST_H__ #define __TRACKDATALIST_H__ class TrackData; class TrackDataList { public: TrackDataList(); ~TrackDataList() { clear(); } void append(TrackData *); void clear(); long count() const { return count_; } unsigned long length() const; const TrackData *first() const; const TrackData *next() const; private: struct Entry { TrackData *data; Entry *next; }; Entry *list_; Entry *last_; Entry *iterator_; long count_; }; #endif cdrdao-cdrdao-f00afb2/trackdb/lec.cc000066400000000000000000000355121511453746600173700ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller * * 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. */ #include #include #include #include "lec.h" #define GF8_PRIM_POLY 0x11d /* x^8 + x^4 + x^3 + x^2 + 1 */ #define EDC_POLY 0x8001801b /* (x^16 + x^15 + x^2 + 1) (x^16 + x^2 + x + 1) */ #define LEC_HEADER_OFFSET 12 #define LEC_DATA_OFFSET 16 #define LEC_MODE1_DATA_LEN 2048 #define LEC_MODE1_EDC_OFFSET 2064 #define LEC_MODE1_INTERMEDIATE_OFFSET 2068 #define LEC_MODE1_P_PARITY_OFFSET 2076 #define LEC_MODE1_Q_PARITY_OFFSET 2248 #define LEC_MODE2_FORM1_DATA_LEN (2048+8) #define LEC_MODE2_FORM1_EDC_OFFSET 2072 #define LEC_MODE2_FORM2_DATA_LEN (2324+8) #define LEC_MODE2_FORM2_EDC_OFFSET 2348 typedef u_int8_t gf8_t; static u_int8_t GF8_LOG[256]; static gf8_t GF8_ILOG[256]; static const class Gf8_Q_Coeffs_Results_01 { private: u_int16_t table[43][256]; public: Gf8_Q_Coeffs_Results_01(); ~Gf8_Q_Coeffs_Results_01() {} const u_int16_t *operator[] (int i) const { return &table[i][0]; } operator const u_int16_t *() const { return &table[0][0]; } } CF8_Q_COEFFS_RESULTS_01; static const class CrcTable { private: u_int32_t table[256]; public: CrcTable(); ~CrcTable() {} u_int32_t operator[](int i) const { return table[i]; } operator const u_int32_t *() const { return table; } } CRCTABLE; static const class ScrambleTable { private: u_int8_t table[2340]; public: ScrambleTable(); ~ScrambleTable() {} u_int8_t operator[](int i) const { return table[i]; } operator const u_int8_t *() const { return table; } } SCRAMBLE_TABLE; /* Creates the logarithm and inverse logarithm table that is required * for performing multiplication in the GF(8) domain. */ static void gf8_create_log_tables() { u_int8_t log; u_int16_t b; for (b = 0; b <= 255; b++) { GF8_LOG[b] = 0; GF8_ILOG[b] = 0; } b = 1; for (log = 0; log < 255; log++) { GF8_LOG[(u_int8_t)b] = log; GF8_ILOG[log] = (u_int8_t)b; b <<= 1; if ((b & 0x100) != 0) b ^= GF8_PRIM_POLY; } } /* Addition in the GF(8) domain: just the XOR of the values. */ #define gf8_add(a, b) (a) ^ (b) /* Multiplication in the GF(8) domain: add the logarithms (modulo 255) * and return the inverse logarithm. Not used! */ #if 0 static gf8_t gf8_mult(gf8_t a, gf8_t b) { int16_t sum; if (a == 0 || b == 0) return 0; sum = GF8_LOG[a] + GF8_LOG[b]; if (sum >= 255) sum -= 255; return GF8_ILOG[sum]; } #endif /* Division in the GF(8) domain: Like multiplication but logarithms a * subtracted. */ static gf8_t gf8_div(gf8_t a, gf8_t b) { int16_t sum; assert(b != 0); if (a == 0) return 0; sum = GF8_LOG[a] - GF8_LOG[b]; if (sum < 0) sum += 255; return GF8_ILOG[sum]; } Gf8_Q_Coeffs_Results_01::Gf8_Q_Coeffs_Results_01() { int i, j; u_int16_t c; gf8_t GF8_COEFFS_HELP[2][45]; u_int8_t GF8_Q_COEFFS[2][45]; gf8_create_log_tables(); /* build matrix H: * 1 1 ... 1 1 * a^44 a^43 ... a^1 a^0 * * */ for (j = 0; j < 45; j++) { GF8_COEFFS_HELP[0][j] = 1; /* e0 */ GF8_COEFFS_HELP[1][j] = GF8_ILOG[44-j]; /* e1 */ } /* resolve equation system for parity byte 0 and 1 */ /* e1' = e1 + e0 */ for (j = 0; j < 45; j++) { GF8_Q_COEFFS[1][j] = gf8_add(GF8_COEFFS_HELP[1][j], GF8_COEFFS_HELP[0][j]); } /* e1'' = e1' / (a^1 + 1) */ for (j = 0; j < 45; j++) { GF8_Q_COEFFS[1][j] = gf8_div(GF8_Q_COEFFS[1][j], GF8_Q_COEFFS[1][43]); } /* e0' = e0 + e1 / a^1 */ for (j = 0; j < 45; j++) { GF8_Q_COEFFS[0][j] = gf8_add(GF8_COEFFS_HELP[0][j], gf8_div(GF8_COEFFS_HELP[1][j], GF8_ILOG[1])); } /* e0'' = e0' / (1 + 1 / a^1) */ for (j = 0; j < 45; j++) { GF8_Q_COEFFS[0][j] = gf8_div(GF8_Q_COEFFS[0][j], GF8_Q_COEFFS[0][44]); } /* * Compute the products of 0..255 with all of the Q coefficients in * advance. When building the scalar product between the data vectors * and the P/Q vectors the individual products can be looked up in * this table * * The P parity coefficients are just a subset of the Q coefficients so * that we do not need to create a separate table for them. */ for (j = 0; j < 43; j++) { table[j][0] = 0; for (i = 1; i < 256; i++) { c = GF8_LOG[i] + GF8_LOG[GF8_Q_COEFFS[0][j]]; if (c >= 255) c -= 255; table[j][i] = GF8_ILOG[c]; c = GF8_LOG[i] + GF8_LOG[GF8_Q_COEFFS[1][j]]; if (c >= 255) c -= 255; table[j][i] |= GF8_ILOG[c]<<8; } } } /* Reverses the bits in 'd'. 'bits' defines the bit width of 'd'. */ static u_int32_t mirror_bits(u_int32_t d, int bits) { int i; u_int32_t r = 0; for (i = 0; i < bits; i++) { r <<= 1; if ((d & 0x1) != 0) r |= 0x1; d >>= 1; } return r; } /* Build the CRC lookup table for EDC_POLY poly. The CRC is 32 bit wide * and reversed (i.e. the bit stream is divided by the EDC_POLY with the * LSB first order). */ CrcTable::CrcTable () { u_int32_t i, j; u_int32_t r; for (i = 0; i < 256; i++) { r = mirror_bits(i, 8); r <<= 24; for (j = 0; j < 8; j++) { if ((r & 0x80000000) != 0) { r <<= 1; r ^= EDC_POLY; } else { r <<= 1; } } r = mirror_bits(r, 32); table[i] = r; } } /* Calculates the CRC of given data with given lengths based on the * table lookup algorithm. */ static u_int32_t calc_edc(u_int8_t *data, int len) { u_int32_t crc = 0; while (len--) { crc = CRCTABLE[(int)(crc ^ *data++) & 0xff] ^ (crc >> 8); } return crc; } /* Build the scramble table as defined in the yellow book. The bytes 12 to 2351 of a sector will be XORed with the data of this table. */ ScrambleTable::ScrambleTable() { u_int16_t i, j; u_int16_t reg = 1; u_int8_t d; for (i = 0; i < 2340; i++) { d = 0; for (j = 0; j < 8; j++) { d >>= 1; if ((reg & 0x1) != 0) d |= 0x80; if ((reg & 0x1) != ((reg >> 1) & 0x1)) { reg >>= 1; reg |= 0x4000; /* 15-bit register */ } else { reg >>= 1; } } table[i] = d; } } /* Calc EDC for a MODE 1 sector */ static void calc_mode1_edc(u_int8_t *sector) { u_int32_t crc = calc_edc(sector, LEC_MODE1_DATA_LEN + 16); sector[LEC_MODE1_EDC_OFFSET] = crc & 0xffL; sector[LEC_MODE1_EDC_OFFSET + 1] = (crc >> 8) & 0xffL; sector[LEC_MODE1_EDC_OFFSET + 2] = (crc >> 16) & 0xffL; sector[LEC_MODE1_EDC_OFFSET + 3] = (crc >> 24) & 0xffL; } /* Calc EDC for a XA form 1 sector */ static void calc_mode2_form1_edc(u_int8_t *sector) { u_int32_t crc = calc_edc(sector + LEC_DATA_OFFSET, LEC_MODE2_FORM1_DATA_LEN); sector[LEC_MODE2_FORM1_EDC_OFFSET] = crc & 0xffL; sector[LEC_MODE2_FORM1_EDC_OFFSET + 1] = (crc >> 8) & 0xffL; sector[LEC_MODE2_FORM1_EDC_OFFSET + 2] = (crc >> 16) & 0xffL; sector[LEC_MODE2_FORM1_EDC_OFFSET + 3] = (crc >> 24) & 0xffL; } /* Calc EDC for a XA form 2 sector */ static void calc_mode2_form2_edc(u_int8_t *sector) { u_int32_t crc = calc_edc(sector + LEC_DATA_OFFSET, LEC_MODE2_FORM2_DATA_LEN); sector[LEC_MODE2_FORM2_EDC_OFFSET] = crc & 0xffL; sector[LEC_MODE2_FORM2_EDC_OFFSET + 1] = (crc >> 8) & 0xffL; sector[LEC_MODE2_FORM2_EDC_OFFSET + 2] = (crc >> 16) & 0xffL; sector[LEC_MODE2_FORM2_EDC_OFFSET + 3] = (crc >> 24) & 0xffL; } /* Writes the sync pattern to the given sector. */ static void set_sync_pattern(u_int8_t *sector) { sector[0] = 0; sector[1] = sector[2] = sector[3] = sector[4] = sector[5] = sector[6] = sector[7] = sector[8] = sector[9] = sector[10] = 0xff; sector[11] = 0; } static u_int8_t bin2bcd(u_int8_t b) { return (((b/10) << 4) & 0xf0) | ((b%10) & 0x0f); } /* Builds the sector header. */ static void set_sector_header(u_int8_t mode, u_int32_t adr, u_int8_t *sector) { sector[LEC_HEADER_OFFSET] = bin2bcd(adr / (60*75)); sector[LEC_HEADER_OFFSET + 1] = bin2bcd((adr / 75) % 60); sector[LEC_HEADER_OFFSET + 2] = bin2bcd(adr % 75); sector[LEC_HEADER_OFFSET + 3] = mode; } /* Calculate the P parities for the sector. * The 43 P vectors of length 24 are combined with the GF8_P_COEFFS. */ static void calc_P_parity(u_int8_t *sector) { int i, j; u_int16_t p01_msb, p01_lsb; u_int8_t *p_lsb_start; u_int8_t *p_lsb; u_int8_t *p0, *p1; u_int8_t d0,d1; p_lsb_start = sector + LEC_HEADER_OFFSET; p1 = sector + LEC_MODE1_P_PARITY_OFFSET; p0 = sector + LEC_MODE1_P_PARITY_OFFSET + 2 * 43; for (i = 0; i <= 42; i++) { p_lsb = p_lsb_start; p01_lsb = p01_msb = 0; for (j = 19; j <= 42; j++) { d0 = *p_lsb; d1 = *(p_lsb+1); p01_lsb ^= CF8_Q_COEFFS_RESULTS_01[j][d0]; p01_msb ^= CF8_Q_COEFFS_RESULTS_01[j][d1]; p_lsb += 2 * 43; } *p0 = p01_lsb; *(p0 + 1) = p01_msb; *p1 = p01_lsb>>8; *(p1 + 1) = p01_msb>>8; p0 += 2; p1 += 2; p_lsb_start += 2; } } /* Calculate the Q parities for the sector. * The 26 Q vectors of length 43 are combined with the GF8_Q_COEFFS. */ static void calc_Q_parity(u_int8_t *sector) { int i, j; u_int16_t q01_lsb, q01_msb; u_int8_t *q_lsb_start; u_int8_t *q_lsb; u_int8_t *q0, *q1, *q_start; u_int8_t d0,d1; q_lsb_start = sector + LEC_HEADER_OFFSET; q_start = sector + LEC_MODE1_Q_PARITY_OFFSET; q1 = sector + LEC_MODE1_Q_PARITY_OFFSET; q0 = sector + LEC_MODE1_Q_PARITY_OFFSET + 2 * 26; for (i = 0; i <= 25; i++) { q_lsb = q_lsb_start; q01_lsb = q01_msb = 0; for (j = 0; j <= 42; j++) { d0 = *q_lsb; d1 = *(q_lsb+1); q01_lsb ^= CF8_Q_COEFFS_RESULTS_01[j][d0]; q01_msb ^= CF8_Q_COEFFS_RESULTS_01[j][d1]; q_lsb += 2 * 44; if (q_lsb >= q_start) { q_lsb -= 2 * 1118; } } *q0 = q01_lsb; *(q0 + 1) = q01_msb; *q1 = q01_lsb>>8; *(q1 + 1) = q01_msb>>8; q0 += 2; q1 += 2; q_lsb_start += 2 * 43; } } /* Encodes a MODE 0 sector. * 'adr' is the current physical sector address * 'sector' must be 2352 byte wide */ void lec_encode_mode0_sector(u_int32_t adr, u_int8_t *sector) { u_int16_t i; set_sync_pattern(sector); set_sector_header(0, adr, sector); sector += 16; for (i = 0; i < 2336; i++) *sector++ = 0; } /* Encodes a MODE 1 sector. * 'adr' is the current physical sector address * 'sector' must be 2352 byte wide containing 2048 bytes user data at * offset 16 */ void lec_encode_mode1_sector(u_int32_t adr, u_int8_t *sector) { set_sync_pattern(sector); set_sector_header(1, adr, sector); calc_mode1_edc(sector); /* clear the intermediate field */ sector[LEC_MODE1_INTERMEDIATE_OFFSET] = sector[LEC_MODE1_INTERMEDIATE_OFFSET + 1] = sector[LEC_MODE1_INTERMEDIATE_OFFSET + 2] = sector[LEC_MODE1_INTERMEDIATE_OFFSET + 3] = sector[LEC_MODE1_INTERMEDIATE_OFFSET + 4] = sector[LEC_MODE1_INTERMEDIATE_OFFSET + 5] = sector[LEC_MODE1_INTERMEDIATE_OFFSET + 6] = sector[LEC_MODE1_INTERMEDIATE_OFFSET + 7] = 0; calc_P_parity(sector); calc_Q_parity(sector); } /* Encodes a MODE 2 sector. * 'adr' is the current physical sector address * 'sector' must be 2352 byte wide containing 2336 bytes user data at * offset 16 */ void lec_encode_mode2_sector(u_int32_t adr, u_int8_t *sector) { set_sync_pattern(sector); set_sector_header(2, adr, sector); } /* Encodes a XA form 1 sector. * 'adr' is the current physical sector address * 'sector' must be 2352 byte wide containing 2048+8 bytes user data at * offset 16 */ void lec_encode_mode2_form1_sector(u_int32_t adr, u_int8_t *sector) { set_sync_pattern(sector); calc_mode2_form1_edc(sector); /* P/Q partiy must not contain the sector header so clear it */ sector[LEC_HEADER_OFFSET] = sector[LEC_HEADER_OFFSET + 1] = sector[LEC_HEADER_OFFSET + 2] = sector[LEC_HEADER_OFFSET + 3] = 0; calc_P_parity(sector); calc_Q_parity(sector); /* finally add the sector header */ set_sector_header(2, adr, sector); } /* Encodes a XA form 2 sector. * 'adr' is the current physical sector address * 'sector' must be 2352 byte wide containing 2324+8 bytes user data at * offset 16 */ void lec_encode_mode2_form2_sector(u_int32_t adr, u_int8_t *sector) { set_sync_pattern(sector); calc_mode2_form2_edc(sector); set_sector_header(2, adr, sector); } /* Scrambles and byte swaps an encoded sector. * 'sector' must be 2352 byte wide. */ void lec_scramble(u_int8_t *sector) { u_int16_t i; const u_int8_t *stable = SCRAMBLE_TABLE; u_int8_t *p = sector; u_int8_t tmp; for (i = 0; i < 6; i++) { /* just swap bytes of sector sync */ tmp = *p; *p = *(p + 1); p++; *p++ = tmp; } for (;i < (2352 / 2); i++) { /* scramble and swap bytes */ tmp = *p ^ *stable++; *p = *(p + 1) ^ *stable++; p++; *p++ = tmp; } } #if 0 #include #include #include #include int main(int argc, char **argv) { char *infile; char *outfile; int fd_in, fd_out; u_int8_t buffer1[2352]; u_int8_t buffer2[2352]; u_int32_t lba; int i; #if 0 for (i = 0; i < 2048; i++) buffer1[i + 16] = 234; lba = 150; for (i = 0; i < 100000; i++) { lec_encode_mode1_sector(lba, buffer1); lec_scramble(buffer2); lba++; } #else if (argc != 3) return 1; infile = argv[1]; outfile = argv[2]; if ((fd_in = open(infile, O_RDONLY)) < 0) { perror("Cannot open input file"); return 1; } if ((fd_out = open(outfile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) { perror("Cannot open output file"); return 1; } lba = 150; do { if (read(fd_in, buffer1, 2352) != 2352) break; switch (*(buffer1 + 12 + 3)) { case 1: memcpy(buffer2 + 16, buffer1 + 16, 2048); lec_encode_mode1_sector(lba, buffer2); break; case 2: if ((*(buffer1 + 12 + 4 + 2) & 0x20) != 0) { /* form 2 sector */ memcpy(buffer2 + 16, buffer1 + 16, 2324 + 8); lec_encode_mode2_form2_sector(lba, buffer2); } else { /* form 1 sector */ memcpy(buffer2 + 16, buffer1 + 16, 2048 + 8); lec_encode_mode2_form1_sector(lba, buffer2); } break; } if (memcmp(buffer1, buffer2, 2352) != 0) { printf("Verify error at lba %ld\n", lba); } lec_scramble(buffer2); write(fd_out, buffer2, 2352); lba++; } while (1); close(fd_in); close(fd_out); #endif return 0; } #endif cdrdao-cdrdao-f00afb2/trackdb/lec.h000066400000000000000000000042251511453746600172270ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller * * 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. */ #ifndef __LEC_H__ #define __LEC_H__ #include #include "config.h" #ifndef TRUE #define TRUE 1 #endif /* Encodes a MODE 0 sector. * 'adr' is the current physical sector address * 'sector' must be 2352 byte wide */ void lec_encode_mode0_sector(u_int32_t adr, u_int8_t *sector); /* Encodes a MODE 1 sector. * 'adr' is the current physical sector address * 'sector' must be 2352 byte wide containing 2048 bytes user data at * offset 16 */ void lec_encode_mode1_sector(u_int32_t adr, u_int8_t *sector); /* Encodes a MODE 2 sector. * 'adr' is the current physical sector address * 'sector' must be 2352 byte wide containing 2336 bytes user data at * offset 16 */ void lec_encode_mode2_sector(u_int32_t adr, u_int8_t *sector); /* Encodes a XA form 1 sector. * 'adr' is the current physical sector address * 'sector' must be 2352 byte wide containing 2048+8 bytes user data at * offset 16 */ void lec_encode_mode2_form1_sector(u_int32_t adr, u_int8_t *sector); /* Encodes a XA form 2 sector. * 'adr' is the current physical sector address * 'sector' must be 2352 byte wide containing 2324+8 bytes user data at * offset 16 */ void lec_encode_mode2_form2_sector(u_int32_t adr, u_int8_t *sector); /* Scrambles and byte swaps an encoded sector. * 'sector' must be 2352 byte wide. */ void lec_scramble(u_int8_t *sector); #endif cdrdao-cdrdao-f00afb2/trackdb/log.cc000066400000000000000000000035461511453746600174100ustar00rootroot00000000000000/* cdrdao - logging/message code * * Copyright (C) 2007 Denis Leroy * * 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. */ #include #include #include #include #include "log.h" static struct { int level; } self; void log_init() { memset(&self, 0, sizeof(self)); } // Set verbosity of the logging code. void log_set_verbose(int level) { self.level = level; } // Log a message. void log_message(int level, const char *fmt, ...) { long len = strlen(fmt); char last = len > 0 ? fmt[len - 1] : 0; va_list args; va_start(args, fmt); if (level < 0) { switch (level) { case -1: fprintf(stderr, "WARNING: "); break; case -2: fprintf(stderr, "ERROR: "); break; case -3: fprintf(stderr, "INTERNAL ERROR: "); break; default: fprintf(stderr, "FATAL ERROR: "); break; } vfprintf(stderr, fmt, args); if (last != ' ' && last != '\r') fprintf(stderr, "\n"); fflush(stderr); if (level <= -10) exit(1); } else if (level <= self.level) { vfprintf(stderr, fmt, args); if (last != ' ' && last != '\r') fprintf(stderr, "\n"); fflush(stderr); } va_end(args); } cdrdao-cdrdao-f00afb2/trackdb/log.h000066400000000000000000000025021511453746600172410ustar00rootroot00000000000000/* cdrdao - logging/message code * * Copyright (C) 2007 Denis Leroy * * 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. */ #ifndef __LOG_H__ #define __LOG_H__ // Initialize log code. Must be called first. void log_init(); // Log given formatted message. // // Level definitions: // -1 : warning // -2 : error // -3 : internal error // -4 to -9 : fatal error // -10 and less : fatal error, call will exit the calling thread. // // Levels >= 0 are controlled by the verbosity set below. void log_message(int level, const char *fmt, ...); // Set logging verbosity. Only levels <= set level will be output. void log_set_verbose(int level); #endif cdrdao-cdrdao-f00afb2/trackdb/stX7xrFf000066400000000000000000000000101511453746600177150ustar00rootroot00000000000000! cdrdao-cdrdao-f00afb2/trackdb/util.cc000066400000000000000000000226661511453746600176100ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller * * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "util.h" #include "log.h" #include "Sample.h" using namespace std; char *strdupCC(const char *s) { char *ret; long len; if (s == NULL) { return NULL; } len = strlen(s); ret = new char[len + 1]; strcpy(ret, s); return ret; } char *strdup3CC(const char *s1, const char *s2, const char *s3) { char *ret; long len = 0; if (s1 == NULL && s2 == NULL && s3 == NULL) return NULL; if (s1 != NULL) len = strlen(s1); if (s2 != NULL) len += strlen(s2); if (s3 != NULL) len += strlen(s3); ret = new char[len + 1]; *ret = 0; if (s1 != NULL) strcpy(ret, s1); if (s2 != NULL) strcat(ret, s2); if (s3 != NULL) strcat(ret, s3); return ret; } char *strdupvCC(const char *s1, ...) { const char *p; char *ret; long len; va_list ap; if (s1 == NULL) return NULL; len = strlen(s1); va_start(ap, s1); while ((p = va_arg(ap, const char *)) != NULL) len += strlen(p); va_end(ap); ret = new char[len + 1]; strcpy(ret, s1); va_start(ap, s1); while ((p = va_arg(ap, const char *)) != NULL) strcat(ret, p); va_end(ap); return ret; } long fullRead(int fd, void *buf, long count) { long n = 0; long nread = 0; do { do { n = read(fd, (char *)buf + nread, count); } while (n < 0 && (errno == EAGAIN || errno == EINTR)); if (n < 0) { return -1; } if (n == 0) { return nread; } count -= n; nread += n; } while (count > 0); return nread; } long fullWrite(int fd, const void *buf, long count) { long n; long nwritten = 0; const char *p = (const char *)buf; do { do { n = write(fd, p, count); } while (n < 0 && (errno == EAGAIN || errno == EINTR)); if (n < 0) return -1; if (n == 0) return nwritten; count -= n; nwritten += n; p += n; } while (count > 0); return nwritten; } long readLong(FILE *fp) { unsigned char c1 = getc(fp); unsigned char c2 = getc(fp); unsigned char c3 = getc(fp); unsigned char c4 = getc(fp); return ((long)c4 << 24) | ((long)c3 << 16) | ((long)c2 << 8) | (long)c1; } short readShort(FILE *fp) { unsigned char c1 = getc(fp); unsigned char c2 = getc(fp); return ((short)c2 << 8) | (short)c1; } void swapSamples(Sample *buf, unsigned long len) { unsigned long i; for (i = 0; i < len; i++) { buf[i].swap(); } } unsigned char int2bcd(int d) { if (d >= 0 && d <= 99) return ((d / 10) << 4) | (d % 10); else return d; } int bcd2int(unsigned char d) { unsigned char d1 = d & 0x0f; unsigned char d2 = d >> 4; if (d1 <= 9 && d2 <= 9) { return d2 * 10 + d1; } else { return d; } } const char *stripCwd(const char *fname) { static char *buf = NULL; static long bufLen = 0; char cwd[PATH_MAX + 1]; long len; if (fname == NULL) return NULL; len = strlen(fname); if (buf == NULL || len >= bufLen) { bufLen = len + 1; delete[] buf; buf = new char[bufLen]; } if (getcwd(cwd, PATH_MAX + 1) == NULL) { // if we cannot retrieve the current working directory return 'fname' strcpy(buf, fname); } else { len = strlen(cwd); if (strncmp(cwd, fname, len) == 0) { if (*(fname + len) == '/') strcpy(buf, fname + len + 1); else strcpy(buf, fname + len); if (buf[0] == 0) { // resulting filename would be "" -> return 'fname' strcpy(buf, fname); } } else { strcpy(buf, fname); } } return buf; } namespace Util { FileExtension fileExtension(const char* fname) { const char* e; if (fname && (e = strrchr(fname, '.'))) { e++; if (strcasecmp(e, "toc") == 0) return FileExtension::TOC; if (strcasecmp(e, "cue") == 0) return FileExtension::CUE; if (strcasecmp(e, "wav") == 0) return FileExtension::WAV; if (strcasecmp(e, "mp3") == 0) return FileExtension::MP3; if (strcasecmp(e, "ogg") == 0) return FileExtension::OGG; if (strcasecmp(e, "m3u") == 0) return FileExtension::M3U; } return FileExtension::UNKNOWN; } string to_utf8(const u8* input, size_t input_size, Util::Encoding enc) { const char* from_encoding = "ISO-8859-1"; if (enc == Util::Encoding::MSJIS) from_encoding = "CP932"; // Code Page 932, aka MS-JIS // Have to jump through hoops due to silly const iconv nonsense. char* abuffer = (char*)alloca(input_size + 1); memcpy(abuffer, input, input_size); abuffer[input_size] = 0; // Should not be necessary in theory ICONV_CONST char* src = (ICONV_CONST char*)abuffer; size_t srclen = input_size; size_t dstlen = input_size * 4; char* dst = (char*)alloca(dstlen); char* orig_dst = dst; auto icv = iconv_open("UTF-8", from_encoding); if (!icv) return string((char*)input); if (iconv(icv, &src, &srclen, &dst, &dstlen) == (size_t)-1) { log_message(-1, strerror(errno)); return string((char*)input); } *dst = 0; return string(orig_dst); } bool from_utf8(const string& input, std::vector& output, Encoding enc) { const char* to_encoding; switch (enc) { case Encoding::ASCII: to_encoding = "ASCII"; break; case Encoding::MSJIS: to_encoding = "CP932"; break; default: to_encoding = "ISO-8859-1"; } char* abuffer = (char*)alloca(input.size() + 1); strcpy(abuffer, input.c_str()); ICONV_CONST char* src = (ICONV_CONST char*)abuffer; size_t srclen = input.size(); size_t dstlen = srclen * 4; char* dst = (char*)alloca(dstlen); char* origdst = dst; auto icv = iconv_open(to_encoding, "UTF-8"); if (!icv) return false; if (iconv(icv, &src, &srclen, &dst, &dstlen) == (size_t)-1) return false; while (origdst < dst) output.push_back(*origdst++); output.push_back(0); return true; } Encoding characterCodeToEncoding(u8 code) { switch (code) { case 0x01: return Encoding::ASCII; case 0x80: return Encoding::MSJIS; case 0x81: return Encoding::KOREAN; case 0x82: return Encoding::MANDARIN; default: return Encoding::LATIN; } } const char* encodingToString(Encoding e) { switch (e) { case Encoding::ASCII: return "ENCODING_ASCII"; case Encoding::MSJIS: return "ENCODING_MS_JIS"; case Encoding::KOREAN: return "ENCODING_KOREAN"; case Encoding::MANDARIN: return "ENCODING_MANDARIN"; default: return "ENCODING_ISO_8859_1"; } } bool isStrictAscii(const std::string& str) { for (const auto c: str) { if (((u8)(c)) > 127) return false; } return true; } bool isValidUTF8(const char* str) { const char* encoding = "UTF-8"; char* abuffer = (char*)alloca(strlen(str) + 1); strcpy(abuffer, str); ICONV_CONST char* src = (ICONV_CONST char*)abuffer; size_t srclen = strlen(src); size_t dstlen = srclen * 2; char* dst = (char*)alloca(dstlen); auto icv = iconv_open(encoding, encoding); if (!icv) return true; if (iconv(icv, &src, &srclen, &dst, &dstlen) == (size_t)-1) return false; else return true; } bool processMixedString(std::string& str, bool& is_utf8) { is_utf8 = !isStrictAscii(str); for (size_t i = 0; str.size() >= 4 && i < str.size() - 3; i++) { if (str[i] == '\\' && isdigit(str[i+1]) && isdigit(str[i+2]) && isdigit(str[i+3])) { if (is_utf8) return false; std::string singlechar(1, 0); singlechar[0] = strtol(str.substr(i+1, 3).c_str(), NULL, 8); str = str.replace(i, 4, singlechar); } } return true; } } bool resolveFilename(std::string& abs, const char* file, const char* path) { struct stat st; // First checks if file is already absolute, in which case we do // nothing. if (file[0] == '/') { abs = file; return true; } // Now checks if file is readable in current directory. Current // directory has precedence over search path. if (stat(file, &st) == 0 && (st.st_mode & S_IFREG)) { char cwd[1024]; if (getcwd(cwd, 1024)) { abs = cwd; abs += "/"; } abs += file; return true; } // Now check in search path. std::string afile = path; if (*(afile.end()) != '/') afile += "/"; afile += file; if (stat(afile.c_str(), &st) == 0 && (st.st_mode & S_IFREG)) { abs = afile; return true; } // File not found. abs = ""; return false; } cdrdao-cdrdao-f00afb2/trackdb/util.h000066400000000000000000000046511511453746600174440ustar00rootroot00000000000000/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2022 Andreas Mueller , * Denis Leroy * * 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. */ #ifndef __UTIL_H__ #define __UTIL_H__ #include #include #include #include typedef unsigned char u8; typedef signed char s8; typedef unsigned short u16; typedef signed short s16; typedef unsigned int u32; typedef signed int s32; class Sample; char *strdupCC(const char *s); char *strdup3CC(const char *s1, const char *s2, const char *s3); char *strdupvCC(const char *s1, ...); long fullRead(int fd, void *buf, long count); long fullWrite(int fd, const void *buf, long count); long readLong(FILE *fp); short readShort(FILE *fp); void swapSamples(Sample *buf, unsigned long len); unsigned char int2bcd(int); int bcd2int(unsigned char); const char *stripCwd(const char *fname); bool resolveFilename(std::string& dest, const char* file, const char* path); namespace Util { enum class FileExtension { UNKNOWN = 0, TOC, CUE, WAV, MP3, OGG, M3U, }; FileExtension fileExtension(const char* fname); enum class Encoding { UNSET,LATIN, ASCII, MSJIS, KOREAN, MANDARIN, UTF8 }; bool from_utf8(const std::string& input, std::vector& output, Encoding enc); std::string to_utf8(const u8* input, size_t input_size, Encoding enc); Encoding characterCodeToEncoding(u8); const char* encodingToString(Encoding); bool isStrictAscii(const char* ptr); bool isValidUTF8(const char* ptr); bool processMixedString(std::string& str, bool& is_utf8); } struct PrintParams { PrintParams() : conversions(false), to_file(false), no_utf8(false) {} bool conversions; bool to_file; bool no_utf8; }; #endif cdrdao-cdrdao-f00afb2/utils/000077500000000000000000000000001511453746600160365ustar00rootroot00000000000000cdrdao-cdrdao-f00afb2/utils/.cvsignore000066400000000000000000000000531511453746600200340ustar00rootroot00000000000000Makefile Makefile.in .deps toc2cue toc2mp3 cdrdao-cdrdao-f00afb2/utils/.gitignore000066400000000000000000000000411511453746600200210ustar00rootroot00000000000000cue2toc toc2cddb toc2cue toc2mp3 cdrdao-cdrdao-f00afb2/utils/Makefile.am000066400000000000000000000016621511453746600200770ustar00rootroot00000000000000if COND_TOC2MP3 MAYBE_TOC2MP3 = toc2mp3 else MAYBE_TOC2MP3 = endif bin_PROGRAMS = toc2cue cue2toc toc2cddb $(MAYBE_TOC2MP3) toc2cddb_SOURCES = toc2cddb.cc toc2cue_SOURCES = toc2cue.cc cue2toc_SOURCES = main.c cue2toc.c cue2toc.h timecode.c timecode.h toc2mp3_SOURCES = toc2mp3.cc toc2cddb_LDADD = $(top_builddir)/trackdb/libtrackdb.a @LIBICONV@ toc2cue_LDADD = $(top_builddir)/trackdb/libtrackdb.a @LIBICONV@ toc2mp3_LDADD = $(top_builddir)/trackdb/libtrackdb.a @LAME_LIBS@ @LIBICONV@ if COND_MP3 toc2cddb_LDADD += @MAD_LIBS@ toc2cue_LDADD += @MAD_LIBS@ toc2mp3_LDADD += @MAD_LIBS@ endif if COND_OGG toc2cddb_LDADD += @VORBISFILE_LIBS@ toc2cue_LDADD += @VORBISFILE_LIBS@ toc2mp3_LDADD += @VORBISFILE_LIBS@ endif toc2cddb_LDADD += @AO_LIBS@ toc2cue_LDADD += @AO_LIBS@ toc2mp3_LDADD += @AO_LIBS@ toc2mp3_CXXFLAGS = @LAME_CFLAGS@ AM_CPPFLAGS = -I$(top_builddir)/trackdb man1_MANS = cue2toc.1 toc2cddb.1 toc2cue.1 EXTRA_DIST = $(man1_MANS) cdrdao-cdrdao-f00afb2/utils/cue2toc.1000066400000000000000000000242661511453746600174760ustar00rootroot00000000000000.\" cue2toc.1 - manual page for cue2toc .\" Copyright (C) 2004 Matthias Czapla .\" .\" This file is part of cue2toc. .\" .\" 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA .\" .TH CUE2TOC 1 .SH NAME cue2toc \- convert CUE to TOC format .SH SYNOPSIS .BR "cue2toc" " [" "-hnqv" "] [" "-o" .IR "tocfile" "]" .RB "[" "-w" .IR "wavefile" "] [" "cuefile" "]" .SH DESCRIPTION .B Cue2toc converts .I cuefile from CUE to TOC format and writes the result to .IR "tocfile" "." If either .IR "cuefile" " or " "tocfile" is omitted or a single dash "-" .B cue2toc reads from standard input and writes to standard ouput respectively. CUE files are text files describing the layout of a CD-Rom and typically carry the extension ".cue". Cdrdao is a CD-burning application which has its own native TOC format to describe the disc layout. Although cdrdao has direct support for reading CUE files, it is currently limited to data tracks only. So .BR "cue2toc" "'s" main usefulness lies in converting CUE files containing audio tracks. Output of CD-Text data can be disabled with the .B -n option. CUE files often come with MP3 files but since cdrdao doesnt support decoding them on the fly they probably must be decoded by other means prior to writing the CD (e.g. using .BR "lame" ")." For this reason you can specify a filename with the .B -w option to be used for all audio tracks instead of the one in the CUE file. Of course this is only really useful if all the tracks are based on the same file. This seems to be the case quite often however. .B Cue2toc normally displays warning messages for unsupported commands and constructs. The .B -q option disables these warnings. .SH OPTIONS .TP .B -h print a short help message .TP .B -n no CD-Text; disable output of CD-Text information .TP .BI "-o " "tocfile" write result to .I tocfile instead of standard ouput .TP .B -q quiet mode; do not print warnings .TP .B -v print version number .TP .BI "-w " "wavefile" use .I wavefile for all audio tracks .SH CUE FORMAT What follows is a description of the CUE format expected by .BR "cue2toc" "." For information about the TOC format please consult the .BR "cdrdao" "(1)" manual page. CUE files consist of commands and their arguments which must be separated from each other by any number of whitespace characters. Space, horizontal tabulator, newline and carriage return are recognized as whitespace characters except inside strings surrounded by double quotes, where they are part of the string. Commands are not case sensitive. CD-Text data can be at most 80 characters per item. Timecode values are accepted in the forms "X:X:X", "X:X" and "X" where each "X" must consist of at most two digits and may be zero padded to the left. They are interpreted as "M:S:F", "S:F" and "F" respectively where "M" means "minutes" and must be in the range 0 <= M <= 99, "S" means "seconds" and must be in the range 0 <= S <= 59, and "F" means "frames" and must be in the range 0 <= F <= 74. CUE files are logically divided into a global section and one to 99 track sections. Inside these sections the following commands are allowed: .SS Global Section .B REM .I anything_to_newline .br .B CATALOG .I string .br .B CDTEXTFILE .I string .br .B TITLE .I string .br .B PERFORMER .I string .br .B SONGWRITER .I string .br .B FILE .I string .BR "BINARY" "|" "MOTOROLA" "|" "AIFF" "|" "WAVE" "|" "MP3" .TP .B REM Optional. Introduces a comment. Anything from there on up to and including the next newline character is ignored. Comments can appear anywhere in the file but not between a command and its arguments. .TP .B CATALOG Optional. The Media Catalog Number of the disc. Must be exactly 13 characters. .TP .B CDTEXTFILE Optional. Specifies an external file containing CD-Text data. Ignored. .TP .B TITLE Optional. The CD-Text title of the disc. .TP .B PERFORMER Optional. The CD-Text performer of the disc. .TP .B SONGWRITER Optional. The CD-Text songwriter of the disc. .TP .B FILE Required. The name and type of the file to be used for all following tracks. The .I string contains the name of the file followed by one of .BR "BINARY" ", " "MOTOROLA" ", " "AIFF" ", " "WAVE" " or " "MP3" "." As far as .B cue2toc is concerned the type of the file is effectively ignored. Nonetheless .BR "MOTOROLA" ", " "AIFF" " and " "MP3" cause printing of a warning message since these file types can not be used directly with cdrdao. .LP The first appearance of a .B TRACK command causes leaving of the global section and entering the track section. .SS Track Section .B TRACK .I number .I mode .br .B REM .I anything_to_newline .br .B FLAGS .RB "[" "DCP" "]" .RB "[" "4CH" "]" .RB "[" "PRE" "]" .RB "[" "SCMS" "]" .br .B ISRC .I string .br .B TITLE .I string .br .B PERFORMER .I string .br .B SONGWRITER .I string .br .B PREGAP .I timecode .br .B INDEX .I number .I timecode .br .B POSTGAP .I timecode .br .B FILE .I string .BR "BINARY" "|" "MOTOROLA" "|" "AIFF" "|" "WAVE" "|" "MP3" .TP .B TRACK Required. Starts a new track definition. The .I number is ignored. The .I mode must be one of .BR "AUDIO" ", " "MODE1/2048" ", " "MODE1/2352" "," .BR "MODE2/2336" " or " "MODE2/2352" "." .TP .B FLAGS Optional. Defines the flags for this track. Must be followed by one or more of the following commands: .B DCP (digital copy permitted), .B 4CH (four channel audio), .B PRE (pre-emphasis enabled) and .B SCMS (serial copy management system). .B SCMS is ignored because there is no corresponding option in the TOC format. .TP .B ISRC Optional. The International Standard Recording Code for this track. Must be exactly 12 characters long. .TP .B TITLE Optional. The CD-Text title of this track. .TP .B PERFORMER Optional. The CD-Text performer of this track. .TP .B SONWRITER Optional. The CD-Text songwriter of this track. .TP .B PREGAP Optional. The length of the track pregap to be filled with zero data. Mutually exclusive with .BR "INDEX 0" "." .TP .B POSTGAP Optional. The length of the track postgap to be filled with zero data. .TP .B INDEX Optional. The .I number must be in the range 0 <= .I number <= 99. Index number 1 specifies the start of the track. Index number 0 is the start of the track pregap filled with data from the file, i.e. the difference between index 0 and index 1 is the length of the pregap. Index 0 is mutually exclusive with .BR "PREGAP" "." Index numbers greater than 1 specify subindexes for this track and must be sequential. .TP .B FILE Optional in track section. The syntax is the same as described above and if it appears inside a track specification it takes effect on the next .B TRACK command. .SH LIMITATIONS The command .B CDTEXTFILE and the flag .B SCMS have no equivalent in the TOC format and are ignored. CUE files containing data tracks which specify a starting time greater than zero cannot be converted by .B cue2toc because the TOC format does not provide a way to specify a starting time at all for data tracks. However if the CUE file does not contain any audio tracks you can try to use the CUE file directly with cdrdao. .SH EXAMPLE Suppose we have the following CUE file "uwe.froehn.cue" describing an audio CD with CD-Text data: .nf .in +4m REM Example CUE file with audio tracks CATALOG 1234567890123 TITLE "Der Berg ruft" PERFORMER "Uwe Froehn" FILE "uwe.froehn.mp3" MP3 TRACK 01 AUDIO TITLE "Meine Mama ist die Beste" PERFORMER "Uwe Froehn" SONGWRITER "Hansi Klabuster" REM two seconds pregap filled with audio data INDEX 00 00:00:00 INDEX 01 00:02:00 REM subindexes INDEX 02 00:35:17 INDEX 03 01:12:44 TRACK 02 AUDIO TITLE "Hoch oben im Tal" SONGWRITER "Gabi Geil" REM no pregap INDEX 01 02:45:38 TRACK 03 AUDIO REM pregap with zero data PREGAP 00:4:47 INDEX 01 07:58:74 REM postgap with zero data POSTGAP 00:35:00 .in -4m .fi Since cdrdao cannot decode the MP3 file on the fly this step must be carried out by hand, e.g. using lame: .nf .in +4m lame --decode uwe.froehn.mp3 uwe.froehn.wav .in -4m .fi Although the filename appears only once in the example CUE file it gets written for every track in the TOC file so you would need to edit lots of occurences of the filename in the TOC file by hand. For this reason you can specify a string with the .B -w option to be used by .B cue2toc as the filename for all audio tracks. The command .nf .in +4m cue2toc -w uwe.froehn.wav -o uwe.froehn.toc uwe.froehn.cue .in -4m .fi should produce the file uwe.froehn.toc with the following content: .nf .in +4m CATALOG "1234567890123" CD_DA CD_TEXT { LANGUAGE_MAP { 0 : EN } LANGUAGE 0 { TITLE "Der Berg ruft" PERFORMER "Uwe Froehn" } } TRACK AUDIO CD_TEXT { LANGUAGE 0 { TITLE "Meine Mama ist die Beste" PERFORMER "Uwe Froehn" SONGWRITER "Hansi Klabuster" } } AUDIOFILE "uwe.froehn.wav" 00:00:00 02:45:38 START 00:02:00 INDEX 00:35:17 INDEX 01:12:44 TRACK AUDIO CD_TEXT { LANGUAGE 0 { TITLE "Hoch oben im Tal" SONGWRITER "Gabi Geil" } } AUDIOFILE "uwe.froehn.wav" 02:45:38 05:13:36 TRACK AUDIO PREGAP 00:04:47 AUDIOFILE "uwe.froehn.wav" 07:58:74 SILENCE 00:35:00 .in -4m .fi .SH SEE ALSO .BR cdrdao (1), .BR lame (1) .SH BUGS Since .BR "cue2toc" "'s" definition of the CUE format is entirely based on a number of different CUE files the author came across there is a very high probability that it will not work correctly with all the other CUE files you might encounter. If this is the case for you please send the problematic CUE file along with the version number of .B cue2toc to . .SH AUTHOR Matthias Czapla cdrdao-cdrdao-f00afb2/utils/cue2toc.c000066400000000000000000000600661511453746600175560ustar00rootroot00000000000000/* cue2toc.c - conversion routines * Copyright (C) 2004 Matthias Czapla * * This file is part of cue2toc. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include "cue2toc.h" #include "timecode.h" #define TCBUFLEN 9 /* Buffer length for timecode strings (HH:MM:SS) */ #define MAXCMDLEN 10 /* Longest command (currently SONGWRITER) */ extern const char *progname; /* Set to argv[0] by main */ extern int verbose; /* Set by main */ /* * Input is divied into tokens that are separated by whitespace, horizantal * tabulator, line feed and carriage return. Tokens can be either commands * from a fixed set or strings. If a string is to contain any of the token * delimiting characters it must be enclosed in double quotes. */ static const char token_delimiter[] = { ' ', '\t', '\n', '\r' }; /* Return true if c is one of token_delimiter */ static int isdelim(int c) { int i; int n = sizeof(token_delimiter); for (i = 0; i < n; i++) if (c == token_delimiter[i]) return 1; return 0; } /* Used as return type for get_command and index into cmds */ enum command { REM, CATALOG, CDTEXTFILE, FILECMD, PERFORMER, SONGWRITER, TITLE, TRACK, FLAGS, DCP, FOURCH, PRE, SCMS, ISRC, PREGAP, INDEX, POSTGAP, BINARY, MOTOROLA, AIFF, WAVE, MP3, UNKNOWN, END }; /* Except the last two these are the valid CUE commands */ char cmds[][MAXCMDLEN + 1] = { "REM", "CATALOG", "CDTEXTFILE", "FILE", "PERFORMER", "SONGWRITER", "TITLE", "TRACK", "FLAGS", "DCP", "4CH", "PRE", "SCMS", "ISRC", "PREGAP", "INDEX", "POSTGAP", "BINARY", "MOTOROLA", "AIFF", "WAVE", "MP3", "UNKNOWN", "END" }; /* These are for error messages */ static const char *fname = "stdin"; static long line; /* current line number */ static long tokenstart; /* line where last token started */ /* To generate meaningful error messages in check_once */ enum scope { CUESHEET, GLOBAL, ONETRACK }; /* Fatal error while processing input file */ static void err_fail(const char *s) { fprintf(stderr, "%s:%s:%ld: %s\n", progname, fname, tokenstart, s); exit(EXIT_FAILURE); } /* Fatal error */ static void err_fail2(const char *s) { fprintf(stderr, "%s: %s\n", progname, s); exit(EXIT_FAILURE); } /* EOF while expecting more */ static void err_earlyend() { fprintf(stderr, "%s:%s:%ld: Premature end of file\n", progname, fname, line); exit(EXIT_FAILURE); } /* Warning. Keep on going. */ static void err_warn(const char *s) { if (!verbose) return; fprintf(stderr, "%s:%s:%ld: Warning, %s\n", progname, fname, tokenstart, s); } /* Get next command from file */ static enum command get_command(FILE *f) { int c; char buf[MAXCMDLEN + 1]; int i = 0; /* eat whitespace */ do { c = getc(f); if (c == '\n') line++; } while (isdelim(c)); if (c == EOF) return END; tokenstart = line; /* get command, transform to upper case */ do { buf[i++] = toupper(c); c = getc(f); } while (!isdelim(c) && c!= EOF && i < MAXCMDLEN); if (!isdelim(c)) return UNKNOWN; /* command longer than MAXCMDLEN */ if (c == EOF) return END; if (c == '\n') line++; buf[i] = '\0'; if (strcmp(buf, cmds[REM]) == 0) return REM; else if (strcmp(buf, cmds[CATALOG]) == 0) return CATALOG; else if (strcmp(buf, cmds[CDTEXTFILE]) == 0) return CDTEXTFILE; else if (strcmp(buf, cmds[FILECMD]) == 0) return FILECMD; else if (strcmp(buf, cmds[PERFORMER]) == 0) return PERFORMER; else if (strcmp(buf, cmds[SONGWRITER]) == 0) return SONGWRITER; else if (strcmp(buf, cmds[TITLE]) == 0) return TITLE; else if (strcmp(buf, cmds[TRACK]) == 0) return TRACK; else if (strcmp(buf, cmds[FLAGS]) == 0) return FLAGS; else if (strcmp(buf, cmds[DCP]) == 0) return DCP; else if (strcmp(buf, cmds[FOURCH]) == 0) return FOURCH; else if (strcmp(buf, cmds[PRE]) == 0) return PRE; else if (strcmp(buf, cmds[SCMS]) == 0) return SCMS; else if (strcmp(buf, cmds[ISRC]) == 0) return ISRC; else if (strcmp(buf, cmds[PREGAP]) == 0) return PREGAP; else if (strcmp(buf, cmds[INDEX]) == 0) return INDEX; else if (strcmp(buf, cmds[POSTGAP]) == 0) return POSTGAP; else if (strcmp(buf, cmds[BINARY]) == 0) return BINARY; else if (strcmp(buf, cmds[MOTOROLA]) == 0) return MOTOROLA; else if (strcmp(buf, cmds[AIFF]) == 0) return AIFF; else if (strcmp(buf, cmds[WAVE]) == 0) return WAVE; else if (strcmp(buf, cmds[MP3]) == 0) return MP3; else return UNKNOWN; } /* Skip leading token delimiters then read at most n chars from f into s. * Put terminating Null at the end of s. This implies that s must be * really n + 1. Return number of characters written to s. The only case to * return zero is on EOF before any character was read. * Exit the program indicating failure if string is longer than n. */ static size_t get_string(FILE *f, char *s, size_t n) { int c; size_t i = 0; /* eat whitespace */ do { c = getc(f); if (c == '\n') line++; } while (isdelim(c)); if (c == EOF) return 0; tokenstart = line; if (c == '\"') { c = getc(f); if (c == '\n') line++; while (c != '\"' && c != EOF && i < n) { s[i++] = c; c = getc(f); if (c == '\n') line++; } if (i == n && c != '\"' && c != EOF) err_fail("String too long"); } else { while (!isdelim(c) && c != EOF && i < n) { s[i++] = c; c = getc(f); } if (i == n && !isdelim(c) && c != EOF) err_fail("String too long"); } if (i == 0) err_fail("Empty string"); if (c == '\n') line++; s[i] = '\0'; return i; } /* Return track mode */ static enum track_mode get_track_mode(FILE *f) { char buf[] = "MODE1/2048"; char *pbuf = buf; if (get_string(f, buf, sizeof(buf) - 1) < 1) err_fail("Illegal track mode"); /* transform to upper case */ while (*pbuf) { *pbuf = toupper(*pbuf); pbuf++; } if (strcmp(buf, "AUDIO") == 0) return AUDIO; else if (strcmp(buf, "MODE1/2048") == 0) return MODE1; else if (strcmp(buf, "MODE1/2352") == 0) return MODE1_RAW; else if (strcmp(buf, "MODE2/2336") == 0) return MODE2; else if (strcmp(buf, "MODE2/2352") == 0) return MODE2_RAW; else err_fail("Unsupported track mode"); return AUDIO; } static void check_once(enum command cmd, char *s, enum scope sc); /* Read at most CDTEXTLEN chars into s */ static void get_cdtext(FILE *f, enum command cmd, char *s, enum scope sc) { check_once(cmd, s, sc); if (get_string(f, s, CDTEXTLEN) < 1) err_earlyend(); } /* All strings have their first character initialized to '\0' so if s[0] is not Null the cmd has already been seen in input. In this case print a message end exit program indicating failure. The only purpose of the arguments cmd and sc is to print meaningful error messages. */ static void check_once(enum command cmd, char *s, enum scope sc) { if (s[0] == '\0') return; fprintf(stderr, "%s:%s:%ld: %s allowed only once", progname, fname, line, cmds[cmd]); switch (sc) { case CUESHEET: fprintf(stderr, "\n"); break; case GLOBAL: fprintf(stderr, " in global section\n"); break; case ONETRACK: fprintf(stderr, " per track\n"); break; } exit(EXIT_FAILURE); } /* If this is a data track and does not start at position zero exit the program. The TOC format has no way to specify a data track using only a portion past the first byte of a binary file. */ static void check_cutting_binary(struct trackspec *tr) { if (tr->mode == AUDIO) return; if (tr->pregap_data_from_file) { if (tr->pregap < tr->start) err_fail("TOC format does not allow cutting binary " "files. Try burning CUE file directly.\n"); } else if (tr->start > 0) err_fail("TOC format does not allow cutting binary " "files. Try burning CUE file directly.\n"); } /* Allocate, initialize and return new track */ static struct trackspec* new_track(void) { struct trackspec *track; int i; if ((track = (struct trackspec*) malloc(sizeof(struct trackspec))) == NULL) err_fail("Memory allocation error in new_track()"); track->copy = track->pre_emphasis = track->four_channel_audio = track->pregap_data_from_file = 0; track->isrc[0] = track->title[0] = track->performer[0] = track->songwriter[0] = track->filename[0] = '\0'; track->pregap = track->start = track->postgap = -1; for (i = 0; i < NUM_OF_INDEXES; i++) track->indexes[i] = -1; track->next = NULL; return track; } /* Read the cuefile and return a pointer to the cuesheet */ struct cuesheet* read_cue(const char *cuefile, const char *wavefile) { FILE *f; enum command cmd; struct cuesheet *cs = NULL; struct trackspec *track = NULL; size_t n; int c; char file[FILENAMELEN + 1]; enum command filetype = UNKNOWN; char timecode_buffer[TCBUFLEN]; char devnull[FILENAMELEN + 1]; /* just for eating CDTEXTFILE arg */ if (NULL == cuefile) { f = stdin; } else if (NULL == (f = fopen(cuefile, "r"))) { fprintf(stderr, "%s: Could not open file \"%s\" for " "reading: %s\n", progname, cuefile, strerror(errno)); exit(EXIT_FAILURE); } if (cuefile) fname = cuefile; if ((cs = (struct cuesheet*) malloc(sizeof(struct cuesheet))) == NULL) err_fail("Memory allocation error in read_cue()"); cs->catalog[0] = '\0'; cs->type = 0; cs->title[0] = '\0'; cs->performer[0] = '\0'; cs->songwriter[0] = '\0'; cs->tracklist = NULL; file[0] = '\0'; line = 1; /* global section */ while ((cmd = get_command(f)) != TRACK) { switch (cmd) { case UNKNOWN: err_fail("Unknown command"); case END: err_earlyend(); case REM: c = getc(f); while (c != '\n' && c != EOF) c = getc(f); break; case CDTEXTFILE: err_warn("ignoring CDTEXTFILE..."); if (get_string(f, devnull, FILENAMELEN) == 0) err_warn("Syntactically incorrect " "CDTEXTFILE command. But who " "cares..."); break; case CATALOG: check_once(CATALOG, cs->catalog, CUESHEET); n = get_string(f, cs->catalog, 13); if (n != 13) err_fail("Catalog number must be 13 " "characters long"); break; case TITLE: get_cdtext(f, TITLE, cs->title, GLOBAL); break; case PERFORMER: get_cdtext(f, PERFORMER, cs->performer, GLOBAL); break; case SONGWRITER: get_cdtext(f, SONGWRITER, cs->songwriter, GLOBAL); break; case FILECMD: check_once(FILECMD, file, GLOBAL); if (get_string(f, file, FILENAMELEN) < 1) err_earlyend(); switch (cmd = get_command(f)) { case MOTOROLA: err_warn("big endian binary file"); case BINARY: filetype = BINARY; break; case AIFF: case MP3: err_warn("AIFF and MP3 not supported by " "cdrdao"); case WAVE: if (wavefile) { strncpy(file, wavefile, FILENAMELEN); file[FILENAMELEN] = '\0'; } filetype = WAVE; break; default: err_fail("Unsupported file type"); } break; default: err_fail("Command not allowed in global section"); break; } } /* leaving global section, entering track specifications */ if (file[0] == '\0') err_fail("TRACK without previous FILE"); while (cmd != END) { switch(cmd) { case UNKNOWN: err_fail("Unknown command"); case REM: c = getc(f); while (c != '\n' && c != EOF) c = getc(f); break; case TRACK: if (track == NULL) /* first track */ cs->tracklist = track = new_track(); else { check_cutting_binary(track); track = track->next = new_track(); } /* the CUE format is "TRACK nn MODE" but we are not interested in the track number */ while (isdelim(c = getc(f))) if (c == '\n') line++; while (!isdelim(c = getc(f))) ; if (c == '\n') line++; track->mode = get_track_mode(f); /* audio tracks with binary files seem quite common */ /* if (track->mode == AUDIO && filetype == BINARY || track->mode != AUDIO && filetype == WAVE) err_fail("File and track type mismatch"); */ strcpy(track->filename, file); break; case TITLE: get_cdtext(f, TITLE, track->title, ONETRACK); break; case PERFORMER: get_cdtext(f, PERFORMER, track->performer, ONETRACK); break; case SONGWRITER: get_cdtext(f, SONGWRITER, track->songwriter, ONETRACK); break; case ISRC: check_once(ISRC, track->isrc, ONETRACK); if (get_string(f, track->isrc, 12) != 12) err_fail("ISRC must be 12 characters long"); break; case FLAGS: if (track->copy || track->pre_emphasis || track->four_channel_audio) err_fail("FLAGS allowed only once per track"); /* get the flags */ cmd = get_command(f); while (cmd == DCP || cmd == FOURCH || cmd == PRE || cmd == SCMS) { switch (cmd) { case DCP: track->copy = 1; break; case FOURCH: track->four_channel_audio = 1; break; case PRE: track->pre_emphasis = 1; break; case SCMS: err_warn("serial copy management " "system flag not supported " "by cdrdao"); break; default: err_fail("Should not get here"); } cmd = get_command(f); } /* current non-FLAG command is already in cmd, so avoid get_command() call below */ continue; break; case PREGAP: if (track->pregap != -1) err_fail("PREGAP allowed only once per track"); if (get_string(f, timecode_buffer, TCBUFLEN - 1) < 1) err_earlyend(); track->pregap = tc2fr(timecode_buffer); if (track->pregap == -1) err_fail("Timecode out of range"); track->pregap_data_from_file = 0; break; case POSTGAP: if (track->postgap != -1) err_fail("POSTGAP allowed only once per track"); if (get_string(f, timecode_buffer, TCBUFLEN - 1) < 1) err_earlyend(); track->postgap = tc2fr(timecode_buffer); if (track->postgap == -1) err_fail("Timecode out of range"); break; case INDEX: if (get_string(f, timecode_buffer, 2) < 1) err_earlyend(); n = atoi(timecode_buffer); if (n < 0 || n > 99) err_fail("Index out of range"); /* Index 0 is track pregap and Index 1 is start of track. Index 2 to 99 are the true subindexes and only allowed if the preceding one was there before */ switch (n) { case 0: if (track->start != -1) err_fail("Indexes must be sequential"); if (track->pregap != -1) err_fail("PREGAP allowed only once " "per track"); if (get_string(f, timecode_buffer, TCBUFLEN - 1) < 1) err_earlyend(); /* This is only a temporary value until index 01 is read */ track->pregap = tc2fr(timecode_buffer); if (track->pregap == -1) err_fail("Timecode out of range"); track->pregap_data_from_file = 1; break; case 1: if (track->start != -1) err_fail("Each index allowed only " "once per track"); if (get_string(f, timecode_buffer, TCBUFLEN - 1) < 1) err_fail("Missing timecode"); track->start = tc2fr(timecode_buffer); if (track->start == -1) err_fail("Timecode out of range"); /* Fix the pregap value */ if (track->pregap_data_from_file) track->pregap = track->start - track->pregap; break; case 2: if (track->start == -1) err_fail("Indexes must be sequential"); if (track->indexes[n - 2] != -1) err_fail("Each index allowed only " "once per track"); if (get_string(f, timecode_buffer, TCBUFLEN - 1) < 1) err_fail("Missing timecode"); track->indexes[n - 2] = tc2fr(timecode_buffer); if (track->indexes[n - 2] == -1) err_fail("Timecode out of range"); break; default: /* the other 97 indexes */ /* check if previous index is there */ if (track->indexes[n - 3] == -1) err_fail("Indexes must be sequential"); if (track->indexes[n - 2] != -1) err_fail("Each index allowed only " "once per track"); if (get_string(f, timecode_buffer, TCBUFLEN - 1) < 1) err_fail("Missing timecode"); track->indexes[n - 2] = tc2fr(timecode_buffer); if (track->indexes[n - 2] == -1) err_fail("Timecode out of range"); break; } break; case FILECMD: if (get_string(f, file, FILENAMELEN) < 1) err_earlyend(); switch (cmd = get_command(f)) { case MOTOROLA: err_warn("big endian binary file"); case BINARY: filetype = BINARY; break; case AIFF: case MP3: err_warn("AIFF and MP3 not supported by " "cdrdao"); case WAVE: if (wavefile) { strncpy(file, wavefile, FILENAMELEN); file[FILENAMELEN] = '\0'; } filetype = WAVE; break; default: err_fail("Unsupported file type"); } break; default: err_fail("Command not allowed in track spec"); break; } cmd = get_command(f); } check_cutting_binary(track); return cs; } /* Deduce the disc session type from the track modes */ static enum session_type determine_session_type(struct trackspec *list) { struct trackspec *track = list; /* set to true if track of corresponding type is found */ int audio = 0; int mode1 = 0; int mode2 = 0; while (track != NULL) { switch (track->mode) { case AUDIO: audio = 1; break; case MODE1: case MODE1_RAW: mode1 = 1; break; case MODE2: case MODE2_RAW: mode2 = 1; break; default: /* should never get here */ err_fail2("Don't know how this could happen, but here " "is a track with an unknown mode :|"); } track = track->next; } /* CD_DA only audio * CD_ROM only mode1 with or without audio * CD_ROM_XA only mode2 with or without audio */ if (audio && !mode1 && !mode2) return CD_DA; else if ((audio && mode1 && !mode2) || (!audio && mode1 && !mode2)) return CD_ROM; else if ((audio && !mode1 && mode2) || (!audio && !mode1 && mode2)) return CD_ROM_XA; else return INVALID; } /* Return true if cuesheet contains any CD-Text data */ static int contains_cdtext(struct cuesheet *cs) { struct trackspec *track = cs->tracklist; if (cs->title[0] != '\0' || cs->performer[0] != '\0' || cs->songwriter[0] != '\0') return 1; while (track) { if (track->title[0] != '\0' || track->performer[0] != '\0' || track->songwriter[0] != '\0') return 1; track = track->next; } return 0; } /* fprintf() with indentation. The argument indent is the number of spaces to print per level. E.g. with indent=4 and level=3 there are 12 spaces printed. Every eight spaces are replaced by a single tabulator. The return value is the return value of fprintf(). */ static int ifprintf(FILE *f, int indent, int level, const char *format, ...) { va_list ap; int fprintf_return = 0; int tabs = indent * level / 8; int spaces = indent * level % 8; int i; for (i = 0; i < tabs; i++) fputc('\t', f); for (i = 0; i < spaces; i++) fputc(' ', f); va_start(ap, format); fprintf_return = vfprintf(f, format, ap); va_end(ap); return fprintf_return; } /* Write a track to the file f. The arguments i and l are the indentation amount and level (see ifprintf above). Do not write CD-Text data if cdtext is zero. */ static void write_track(struct trackspec *tr, FILE *f, int i, int l, int cdtext) { char timecode_buffer[TCBUFLEN]; long start = 0, len = 0; int j = 0; fprintf(f, "\n"); ifprintf(f, i, l++, "TRACK "); switch(tr->mode) { case AUDIO: fprintf(f, "AUDIO\n"); break; case MODE1: fprintf(f, "MODE1\n"); break; case MODE1_RAW: fprintf(f, "MODE1_RAW\n"); break; case MODE2: fprintf(f, "MODE2\n"); break; case MODE2_RAW: fprintf(f, "MODE2_RAW\n"); break; default: err_fail2("Unknown track mode"); /* cant get here */ } /* Flags and ISRC */ if (tr->copy) ifprintf(f, i, l, "COPY\n"); if (tr->pre_emphasis) ifprintf(f, i, l, "PRE_EMPHASIS\n"); if (tr->four_channel_audio) ifprintf(f, i, l, "FOUR_CHANNEL_AUDIO\n"); if (tr->isrc[0] != '\0') ifprintf(f, i, l, "ISRC \"%s\"\n", tr->isrc); /* CD-Text data */ if (cdtext && (tr->title[0] != '\0' || tr->performer[0] != '\0' || tr->songwriter[0] != '\0')) { ifprintf(f, i, l++, "CD_TEXT {\n"); ifprintf(f, i, l++, "LANGUAGE 0 {\n"); if (tr->title[0] != '\0') ifprintf(f, i, l, "TITLE \"%s\"\n", tr->title); if (tr->performer[0] != '\0') ifprintf(f, i, l, "PERFORMER \"%s\"\n", tr->performer); if (tr->songwriter[0] != '\0') ifprintf(f, i, l, "SONGWRITER \"%s\"\n", tr->songwriter); ifprintf(f, i, --l, "}\n"); /* LANGUAGE 0 { */ ifprintf(f, i, --l, "}\n"); /* CD_TEXT { */ } /* Pregap with zero data */ if (tr->pregap != -1 && !tr->pregap_data_from_file) { if (fr2tc(timecode_buffer, tr->pregap) == -1) err_fail2("Pregap out of range"); ifprintf(f, i, l, "PREGAP %s\n", timecode_buffer); } /* Specify the file */ start = 0; if (tr->mode == AUDIO) { ifprintf(f, i, l, "AUDIOFILE \"%s\" ", tr->filename); if (tr->start != -1) { if (tr->pregap_data_from_file) { start = tr->start - tr->pregap; } else start = tr->start; } if (fr2tc(timecode_buffer, start) == -1) err_fail2("Track start out of range"); fprintf(f, "%s", timecode_buffer); } else ifprintf(f, i, l, "DATAFILE \"%s\"", tr->filename); /* If next track has the same filename and specified a start value use the difference between start of this and start of the next track as the length of the current track */ if (tr->next && strcmp(tr->filename, tr->next->filename) == 0 && tr->next->start != -1) { if (tr->next->pregap_data_from_file) len = tr->next->start - tr->next->pregap - start; else len = tr->next->start - start; if (fr2tc(timecode_buffer, len) == -1) err_fail2("Track length out of range"); fprintf(f, " %s\n", timecode_buffer); } else fprintf(f, "\n"); /* Pregap with data from file */ if (tr->pregap_data_from_file) { if (fr2tc(timecode_buffer, tr->pregap) == -1) err_fail2("Pregap out of range"); ifprintf(f, i, l, "START %s\n", timecode_buffer); } /* Postgap */ if (tr->postgap != -1) { if (fr2tc(timecode_buffer, tr->postgap) == -1) err_fail2("Postgap out of range"); if (tr->mode == AUDIO) ifprintf(f, i, l, "SILENCE %s\n", timecode_buffer); else ifprintf(f, i, l, "ZERO %s\n", timecode_buffer); } /* Indexes */ while (tr->indexes[j] != -1 && i < NUM_OF_INDEXES) { if (fr2tc(timecode_buffer, tr->indexes[j++]) == -1) err_fail2("Index out of range"); ifprintf(f, i, l, "INDEX %s\n", timecode_buffer); } } /* Write the cuesheet cs to the file named in tocfile. If tocfile is NULL write to stdout. Do not write CD-Text data if cdt is zero. */ void write_toc(const char *tocfile, struct cuesheet *cs, int cdt) { FILE *f = stdout; int i = 4; /* number of chars for indentation */ int l = 0; /* current leven of indentation */ int cdtext = contains_cdtext(cs) && cdt; struct trackspec *track = cs->tracklist; if (tocfile != NULL) if ((f = fopen(tocfile, "w")) == NULL) { fprintf(stderr, "%s: Could not open file \"%s\" for " "writing: %s\n", progname, tocfile, strerror(errno)); exit(EXIT_FAILURE); } if ((cs->type = determine_session_type(cs->tracklist)) == INVALID) err_fail2("Invalid combination of track modes"); ifprintf(f, i, l, "// Generated by cue2toc 0.2\n"); ifprintf(f, i, l, "// Report bugs to \n"); if (cs->catalog[0] != '\0') ifprintf(f, i, l, "CATALOG \"%s\"\n", cs->catalog); switch (cs->type) { case CD_DA: ifprintf(f, i, l, "CD_DA\n"); break; case CD_ROM: ifprintf(f, i, l, "CD_ROM\n"); break; case CD_ROM_XA: ifprintf(f, i, l, "CD_ROM_XA\n"); break; default: err_fail2("Should never get here"); } if (cdtext) { ifprintf(f, i, l++, "CD_TEXT {\n"); ifprintf(f, i, l++, "LANGUAGE_MAP {\n"); ifprintf(f, i, l, "0 : EN\n"); ifprintf(f, i, --l, "}\n"); ifprintf(f, i, l++, "LANGUAGE 0 {\n"); if (cs->title[0] != '\0') ifprintf(f, i, l, "TITLE \"%s\"\n", cs->title); if (cs->performer[0] != '\0') ifprintf(f, i, l, "PERFORMER \"%s\"\n", cs->performer); if (cs->songwriter[0] != '\0') ifprintf(f, i, l, "SONGWRITER \"%s\"\n", cs->songwriter); ifprintf(f, i, --l, "}\n"); ifprintf(f, i, --l, "}\n"); } while (track) { write_track(track, f, i, l, cdtext); track = track->next; } } cdrdao-cdrdao-f00afb2/utils/cue2toc.h000066400000000000000000000045241511453746600175600ustar00rootroot00000000000000/* cue2toc.h - declarations for conversion routines * Copyright (C) 2004 Matthias Czapla * * This file is part of cue2toc. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Maximum length of the FILEname */ #define FILENAMELEN 1024 /* Number of characters allowed per CD-Text entry (w/o termin. Null) */ #define CDTEXTLEN 80 /* Index can be 0 to 99, but 0 and 1 are pre-gap and track start respectively, so 98 are left */ #define NUM_OF_INDEXES 98 enum session_type { CD_DA = 1, /* only audio tracks */ CD_ROM, /* mode1 [and audio] */ CD_ROM_XA, /* mode2 form1 or mode2 form2 [and audio] */ INVALID /* invalid mixture of track modes */ }; enum track_mode { /* corresponding TRACK types in CUE format: */ AUDIO = 1, /* AUDIO (2352) */ MODE1, /* MODE1/2048 */ MODE1_RAW, /* MODE1/2352 */ MODE2, /* MODE2/2336 */ MODE2_RAW /* MODE2/2352 */ }; struct trackspec { enum track_mode mode; int copy; /* boolean */ int pre_emphasis; /* boolean */ int four_channel_audio; /* boolean */ char isrc[13]; char title[CDTEXTLEN + 1]; char performer[CDTEXTLEN + 1]; char songwriter[CDTEXTLEN + 1]; char filename[FILENAMELEN + 1];; long pregap; /* Pre-gap in frames */ int pregap_data_from_file; /* boolean */ long start; /* track start in frames */ long postgap; /* Post-gap in frames */ long indexes[NUM_OF_INDEXES]; /* indexes in frames */ struct trackspec *next; }; struct cuesheet { char catalog[14]; enum session_type type; char title[CDTEXTLEN + 1]; char performer[CDTEXTLEN + 1]; char songwriter[CDTEXTLEN + 1]; struct trackspec *tracklist; }; struct cuesheet *read_cue(const char*, const char*); void write_toc(const char *, struct cuesheet*, int); cdrdao-cdrdao-f00afb2/utils/main.c000066400000000000000000000054161511453746600171340ustar00rootroot00000000000000/* main.c - handle command line arguments * Copyright (C) 2004 Matthias Czapla * * This file is part of cue2toc. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include "cue2toc.h" const char *progname = NULL; int verbose; void usage(void); int main(int argc, char *argv[]) { char *wavefile = NULL; char *outfile = NULL; char *infile = NULL; int nocdtext = 0; int c; struct cuesheet *cs; progname = argv[0]; verbose = 1; opterr = 0; /* we do error msgs ourselves */ while ((c = getopt(argc, argv, ":hno:qvw:")) != -1) switch (c) { case 'h': usage(); exit(EXIT_SUCCESS); break; case 'n': nocdtext = 1; break; case 'o': if (strcmp(optarg, "-") == 0) outfile = NULL; /* use stdout */ else outfile = optarg; break; case 'q': verbose = 0; break; case 'v': printf("cue2toc 0.2\n"); printf("Report bugs to \n"); exit(EXIT_SUCCESS); break; case 'w': wavefile = optarg; break; case ':': fprintf(stderr, "%s: option requires an argument -- " "%c\n", argv[0], optopt); exit(EXIT_FAILURE); case '?': fprintf(stderr, "%s: illegal option -- %c\n", argv[0], optopt); exit(EXIT_FAILURE); } switch(argc - optind) { case 0: infile = NULL; /* use stdin */ break; case 1: if (strcmp(argv[optind], "-") == 0) infile = NULL; /* use stdin */ else infile = argv[optind]; break; default: fprintf(stderr, "%s: bad number of arguments\n", progname); exit(EXIT_FAILURE); } cs = read_cue(infile, wavefile); write_toc(outfile, cs, nocdtext ? 0 : 1); return EXIT_SUCCESS; } void usage(void) { printf("Usage: %s [-hnqv] [-o tocfile] [-w wavefile] [cuefile]\n", progname); printf(" -h\t\tdisplay this help message\n"); printf(" -n\t\tdo not write CD-Text information\n"); printf(" -o tocfile\twrite output to tocfile\n"); printf(" -q\t\tquiet mode\n"); printf(" -v\t\tdisplay version information\n"); printf(" -w wavefile\tname of WAVE file to be used in tocfile\n"); } cdrdao-cdrdao-f00afb2/utils/timecode.c000066400000000000000000000057031511453746600200000ustar00rootroot00000000000000/* timecode.c - timecode conversion routines * Copyright (C) 2004 Matthias Czapla * * This file is part of cue2toc. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #define MAXDIGITS 2 #define NUMOFNUMS 3 /* Interpret argument as timecode value ("MM:SS:FF") and return the total number of frames. Tries to work in a way similar to atoi(), ignoring any trailing non-timecode junk. Skips leading whitespace. I want it to be as flexible as possible, recognizing simple values like "0" (interpreted as "00:00:00"), "1:2" ("00:01:02") and so on. Returns -1 on error (argument NULL or some value out of range) */ long tc2fr(const char *tc) { int minutes = 0; int seconds = 0; int frames = 0; long totalframes = 0; char tmp[MAXDIGITS + 1]; int nums[NUMOFNUMS]; int n = 0; int i = 0; int last_was_colon = 0; int stop = 0; if (tc == NULL) return -1; for (i = 0; i <= MAXDIGITS; i++) tmp[i] = '\0'; while (isspace(*tc)) tc++; for (n = 0; n < NUMOFNUMS; n++) { if (n > 0) { if (tc[0] != ':') { --n; break; } else tc++; } for (i = 0; i < MAXDIGITS; i++) { if (isdigit(tc[i])) { tmp[i] = tc[i]; last_was_colon = 0; } else if (tc[i] == ':') { if (i == 0) stop = 1; break; } else { stop = 1; break; } } if (i != 0) { tmp[i] = '\0'; nums[n] = atoi(tmp); tc = &tc[i]; } else --n; if (stop) break; } if (n == NUMOFNUMS) --n; frames = seconds = minutes = 0; switch (n) { case 0: frames = nums[0]; break; case 1: seconds = nums[0]; frames = nums[1]; break; case 2: minutes = nums[0]; seconds = nums[1]; frames = nums[2]; break; } totalframes = ((60 * minutes) + seconds) * 75 + frames; if (seconds > 59 || frames > 74) return -1; return totalframes; } /* Writes formatted timecode string ("MM:SS:FF") into tc, calculated from frame number fr. Returns -1 on error (frames value out of range) */ int fr2tc(char *tc, long fr) { int m; int s; int f; if (fr > 449999 || fr < 0) { /* 99:59:74 */ strcpy(tc, "00:00:00"); return -1; } f = fr % 75; fr -= f; s = (fr / 75) % 60; fr -= s * 75; m = fr / 75 / 60; sprintf(tc, "%02d:%02d:%02d", m, s, f); return 0; } cdrdao-cdrdao-f00afb2/utils/timecode.h000066400000000000000000000016411511453746600200020ustar00rootroot00000000000000/* timecode.h - declarations for timecode conversion routines * Copyright (C) 2004 Matthias Czapla * * This file is part of cue2toc. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ long tc2fr(const char *); int fr2tc(char *, long fr); cdrdao-cdrdao-f00afb2/utils/toc2cddb.1000066400000000000000000000014541511453746600176100ustar00rootroot00000000000000.TH "TOC2CDDB" "1" "2006-11-17" "1.2.2" "CDRDAO" .SH "NAME" toc2cddb \- translates a TOC file of .I cdrdao(1) into a cddb file and prints it to stdout .SH "SYNOPSIS" .B toc2cddb .I toc_file .PP .B toc2cddb .BR [\| \-h \||\| \-V \|] .SH "DESCRIPTION" .B toc2cddb translates a TOC file of .I cdrdao(1) into a cddb file and prints it to stdout. .SH "OPTIONS" .TP .B \-h Shows a short help message. .TP .B \-V Prints the version of toc2cddb. .SH "SEE ALSO" .I cdrdao(1) .SH "AUTHOR" .B toc2cddb was written by Giuseppe "Cowo" Corbelli and is part of .I cdrdao(1) written by Andreas Mueller . .PP This manual page was written by Francois Wendling and revised by Daniel Baumann , for the Debian project (but may be used by others). cdrdao-cdrdao-f00afb2/utils/toc2cddb.cc000066400000000000000000000144211511453746600200330ustar00rootroot00000000000000/* toc2cddb - translates a TOC file into a cddb file * I use it to print covers for self-made CD-TEXT audio CDs * coupled with disc-cover (http://www.liacs.nl/~jvhemert/disc-cover) * * Cdrdao * Copyright (C) 2002 Andreas Mueller * Toc2cddb * Copyright (C) 2003 Giuseppe "Cowo" Corbelli * Parts by Andreas Mueller * * 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. */ #include #include #include #include #include #include #ifdef HAVE_GETOPT_H #include #endif #include #include "util.h" #include "Toc.h" #define FRAME_OFFSET 150 #define FRAMES_PER_SECOND 75 using namespace std; static int VERBOSE = 1; static unsigned int cddbSum(unsigned int n); const char *calcCddbId(const Toc *toc); void message_args(int level, int addNewLine, const char *fmt, va_list args); void message(int level, const char *fmt, ...); static void printVersion() { message (1, "toc2cddb version %s - (C) Giuseppe \"Cowo\" Corbelli ", VERSION); message (1, "Is a part of cdrdao - (C) Andreas Mueller "); } static void printUsage() { message (0, "toc2cddb converts a cdrdao TOC file into a cddb file and prints it to stdout."); message (0, "Usage: toc2cddb {-V | -h | toc-file}"); } int main (int argc, char *argv[]) { const char *tocFile = NULL; Toc *toc = NULL; const Track *track = NULL; int cdTextLanguage = 0; int c = 0; while ((c = getopt(argc, argv, "Vh")) != EOF) { switch (c) { case 'V': printVersion (); exit (EXIT_SUCCESS); case 'h': printUsage (); exit (EXIT_SUCCESS); case '?': message(-2, "Invalid option: %c", optopt); exit (EXIT_FAILURE); } } if (optind < argc) { tocFile = strdupCC(argv[optind]); optind++; } else { message(-2, "Missing toc-file name."); printUsage (); exit (EXIT_FAILURE); } if (optind != argc) { message(-2, "More arguments than expected."); printUsage (); exit (EXIT_FAILURE); } if ((toc = Toc::read(tocFile)) == NULL) message(-10, "Failed to read toc-file '%s'.", tocFile); if (toc->tocType () != Toc::Type::CD_DA) message (-10, "Toc does not refer to a CDDA"); int ntracks = toc->nofTracks (); if (ntracks < 1) message (-10, "Wrong no. of tracks: %d. Expected >= 0.", ntracks); cout << "# xmcd\n#\n# Track frame offsets:\n#" << endl; { TrackIterator titr (toc); Msf start, end; for (track=titr.first (start, end); track != NULL; track=titr.next (start,end)) cout << "# " << start.lba()+FRAME_OFFSET << endl; int seconds = (end.min () * 60) + end.sec () + (FRAME_OFFSET/FRAMES_PER_SECOND); cout << "#\n# Disc length: " << seconds << " seconds\n#" << endl; } cout << "# Revision: 0\n# Submitted via: cdrdao-" << VERSION << endl; cout << "DISCID=" << calcCddbId (toc) << endl; { const CdTextItem *cdTextItem = NULL; string album(""), albumPerformer(""), genre(""); if ((cdTextItem = toc->getCdTextItem(0, cdTextLanguage, CdTextItem::PackType::TITLE)) != NULL) album = (const char*)cdTextItem->data(); if ((cdTextItem = toc->getCdTextItem(0, cdTextLanguage, CdTextItem::PackType::PERFORMER)) != NULL) albumPerformer = (const char*)cdTextItem->data(); cout << "DTITLE=" << albumPerformer << " / " << album << endl; cout << "DYEAR=" << endl; if ((cdTextItem = toc->getCdTextItem(0, cdTextLanguage, CdTextItem::PackType::GENRE)) != NULL) genre = (const char*)cdTextItem->data(); cout << "DGENRE=" << genre << endl; string title(""); for (int i = 1; i <= ntracks; i++) { if ((cdTextItem = toc->getCdTextItem(i, cdTextLanguage, CdTextItem::PackType::TITLE)) != NULL) title = (const char*)cdTextItem->data(); cout << "TTITLE" << i-1 << "=" << title << endl; } } // Don't know what EXTD means, nor EXTT cout << "EXTD=" << endl; for (int i = 1; i <= ntracks; i++) cout << "EXTT" << i-1 << "=" << endl; cout << "PLAYORDER=" << endl; delete[] tocFile; exit (EXIT_SUCCESS); } static unsigned int cddbSum(unsigned int n) { unsigned int ret; ret = 0; while (n > 0) { ret += (n % 10); n /= 10; } return ret; } const char *calcCddbId(const Toc *toc) { const Track *t; Msf start, end; unsigned int n = 0; unsigned int o = 0; int tcount = 0; static char buf[20]; unsigned long id; TrackIterator itr(toc); for (t = itr.first(start, end); t != NULL; t = itr.next(start, end)) { if (t->type() == TrackData::AUDIO) { n += cddbSum(start.min() * 60 + start.sec() + 2/* gap offset */); o = end.min() * 60 + end.sec(); tcount++; } } id = (n % 0xff) << 24 | o << 8 | tcount; snprintf(buf, sizeof(buf), "%08lx", id); return buf; } void message_args(int level, int addNewLine, const char *fmt, va_list args) { long len = strlen(fmt); char last = len > 0 ? fmt[len - 1] : 0; if (level < 0) { switch (level) { case -1: fprintf(stderr, "WARNING: "); break; case -2: fprintf(stderr, "ERROR: "); break; case -3: fprintf(stderr, "INTERNAL ERROR: "); break; default: fprintf(stderr, "FATAL ERROR: "); break; } vfprintf(stderr, fmt, args); if (addNewLine) { if (last != ' ' && last != '\r') fprintf(stderr, "\n"); } fflush(stderr); if (level <= -10) exit(1); } else if (level <= VERBOSE) { vfprintf(stderr, fmt, args); if (addNewLine) { if (last != ' ' && last != '\r') fprintf(stderr, "\n"); } fflush(stderr); } } void message(int level, const char *fmt, ...) { va_list args; va_start(args, fmt); message_args(level, 1, fmt, args); va_end(args); } cdrdao-cdrdao-f00afb2/utils/toc2cue.1000066400000000000000000000027061511453746600174710ustar00rootroot00000000000000.TH "TOC2CUE" "1" "2006-11-17" "1.2.2" "CDRDAO" .SH "NAME" toc2cue \- converts a TOC files of .I cdrdao(1) into a .cue file .SH "SYNOPSIS" .B toc2cue .BR [\| \-v .IB verbosity_level \|] .I input_toc_file output_cue_file .PP .B toc2cue .BR [\| \-V \|] .SH "DESCRIPTION" .B toc2cue converts a TOC file of .I cdrdao(1) into a .cue file. Please note that the resulting cue file is only valid if the toc-file was created with .I cdrdao(1) using the commands 'read-toc' or 'read-cd'. For manually created or edited toc-files the cue file may not be correct. This program just checks for the most obvious toc-file features that cannot be converted to a cue file. Furthermore, if the toc-file contains audio tracks the byte order of the image file will be wrong. This will result in static noise when the cue file is used for recording (even with .I cdrdao(1) itself). .SH "OPTIONS" .TP .BI "\-v " verbosity_level Sets the verbosity level to use, can be a integer between 1 and 3. By default, only fatal errors are displayed. A verbosity level of 1 shows warnings, 2 warnings and errors, 3 warnings, errors and internal errors. .TP .B \-V Prints the version of toc2cue. .SH "SEE ALSO" .I cdrdao(1) .SH "AUTHOR" .B toc2cue was written by Andreas Mueller and is part of .I cdrdao(1). .PP This manual page was written by Francois Wendling and revised by Daniel Baumann , for the Debian project (but may be used by others). cdrdao-cdrdao-f00afb2/utils/toc2cue.cc000066400000000000000000000312561511453746600177200ustar00rootroot00000000000000/* toc2cue - converts cdrdao's toc-files to .cue files * * Copyright (C) 2001 Andreas Mueller * * 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. */ #include #include #include #include #include #include #include #ifdef HAVE_GETOPT_H #include #endif #include #include "util.h" #include "Toc.h" static const char *PRGNAME = "toc2cue"; static int VERBOSE = 1; void message(int level, const char *fmt, ...) { long len = strlen(fmt); char last = len > 0 ? fmt[len - 1] : 0; va_list args; va_start(args, fmt); if (level < 0) { switch (level) { case -1: fprintf(stderr, "WARNING: "); break; case -2: fprintf(stderr, "ERROR: "); break; case -3: fprintf(stderr, "INTERNAL ERROR: "); break; default: fprintf(stderr, "FATAL ERROR: "); break; } vfprintf(stderr, fmt, args); if (last != ' ' && last != '\r') fprintf(stderr, "\n"); fflush(stderr); if (level <= -10) exit(1); } else if (level <= VERBOSE) { vfprintf(stderr, fmt, args); if (last != ' ' && last != '\r') fprintf(stderr, "\n"); fflush(stderr); } va_end(args); } long sectorSize(TrackData::Mode m) { long bsize = 0; #if 1 // force block size to 2352 bsize = AUDIO_BLOCK_LEN; #else switch (m) { case TrackData::AUDIO: bsize = AUDIO_BLOCK_LEN; break; case TrackData::MODE1: case TrackData::MODE1_RAW: bsize = MODE1_BLOCK_LEN; break; case TrackData::MODE2: case TrackData::MODE2_RAW: case TrackData::MODE2_FORM1: case TrackData::MODE2_FORM2: case TrackData::MODE2_FORM_MIX: bsize = MODE2_BLOCK_LEN; break; case TrackData::MODE0: message(-3, "Illegal mode in 'CdrDriver::blockSize()'."); break; } #endif return bsize; } int convertBin(Toc *toc, char *oldBin, char *newBin, int byteSwap) { Msf start, end; const Track *trun; int trackNr; TrackIterator titr(toc); FILE *in, *out; in = fopen(oldBin, "r"); if(!in) { message(-2, "Failed to open input bin file %s", oldBin); return 1; } out = fopen(newBin, "w+"); if(!out) { message(-2, "Failed to open output bin file %s", newBin); fclose(in); return 1; } for (trun = titr.first(start, end), trackNr = 1; trun != NULL; trun = titr.next(start, end), trackNr++) { TrackData::Mode mode = trun->type(); int iblksize = sectorSize(mode) + TrackData::subChannelSize(trun->subChannelType()); int oblksize = sectorSize(mode); if(mode == TrackData::AUDIO && byteSwap) { printf(" byte swapping audio samples in track %d\n", trackNr); } char buf[AUDIO_BLOCK_LEN + MAX_SUBCHANNEL_LEN]; int cnt; for(cnt = 0; cnt < (end.lba() - start.lba()); cnt++) { int num_read, num_written = 0; num_read = fread(buf, 1, iblksize, in); if(mode == TrackData::AUDIO && byteSwap) { swapSamples((Sample *)buf, SAMPLES_PER_BLOCK); } num_written = fwrite(buf, 1, oblksize, out); } printf(" wrote %d sectors\n", cnt); } fclose(in); fclose(out); return 0; } static void printVersion() { message(1, "toc2cue version %s - (C) Andreas Mueller ", VERSION); message(1, ""); } static void printUsage() { message(0, "Usage: %s [-v #] [-s] [-C output-bin-file] { -V | -h | input-toc-file output-cue-file}", PRGNAME); } static void printHelp() { printUsage(); message(0, "Convert a toc file to a cue file for use with other programs.\n"); message(0, "Options:"); message(0, " -v set verbosity level"); message(0, " -C try to convert the bin file referenced by the toc to a format\n compatible with cue files"); message(0, " -s when -C is specified, byte swap audio data when writing new bin file"); message(0, "\nMutually exclusive options:"); message(0, " -h print this help text"); message(0, " -V print the version number"); message(0, " none convert the provided toc file to a cue file"); } static int parseCommandLine(int argc, char **argv, char **tocFile, char **cueFile, char **convertedBinFile, int *byteSwap) { int c; int printVersion = 0; int printHelpInfo = 0; extern char *optarg; extern int optind, opterr, optopt; opterr = 0; while ((c = getopt(argc, argv, "Vhsv:C:")) != EOF) { switch (c) { case 'V': printVersion = 1; break; case 'v': if (optarg != NULL) { if ((VERBOSE = atoi(optarg)) < 0) { message(-2, "Invalid verbose level: %s\n", optarg); return 0; } } else { message(-2, "Missing verbose level after option '-v'.\n"); return 0; } break; case 'h': printHelpInfo = 1; break; case 's': *byteSwap = 1; break; case 'C': *convertedBinFile = strdupCC(optarg); break; case '?': message(-2, "Invalid option: %c\n", optopt); return 0; break; case ':': message(-2, "option %c missing argument\n", optopt); return 0; break; } } if (printVersion) { printf("%s\n", VERSION); return 1; } if (printHelpInfo) { printHelp(); return 1; } if (optind < argc) { *tocFile = strdupCC(argv[optind]); optind++; } else { message(-2, "Missing toc-file name.\n"); return 0; } if (optind < argc) { *cueFile = strdupCC(argv[optind]); optind++; } else { message(-2, "Missing cue file name.\n"); return 0; } if (optind != argc) { message(-2, "Expecting exactly two arguments.\n"); return 0; } return 2; } int main(int argc, char **argv) { char *tocFile, *cueFile, *convertedBinFile = NULL; Toc *toc; int byteSwapBinAudio = 0; switch (parseCommandLine(argc, argv, &tocFile, &cueFile, &convertedBinFile, &byteSwapBinAudio)) { case 0: // error printUsage(); return 1; break; case 1: // return early return 0; break; } printVersion(); if ((toc = Toc::read(tocFile)) == NULL) { message(-2, "Failed to read toc-file '%s'.", tocFile); return 1; } Msf start, end; const Track *trun; int trackNr; TrackIterator titr(toc); char *binFileName = NULL; int err = 0; int subchan_data_found = 0; // first make some consistency checks, surely not complete to identify // toc-files that can be correctly converted to cue files for (trun = titr.first(start, end), trackNr = 1; trun != NULL; trun = titr.next(start, end), trackNr++) { const SubTrack *strun; int stcount; TrackData::Type sttype1 = TrackData::DATAFILE, sttype2 = TrackData::DATAFILE; SubTrackIterator stitr(trun); switch (trun->type()) { case TrackData::MODE0: case TrackData::MODE2_FORM2: message(-2, "Cannot convert: track %d has unsupported mode.", trackNr); err = 1; break; default: break; } // Check for the presence of subchannel data TrackData::SubChannelMode subchan_mode = trun->subChannelType(); if(subchan_mode) { subchan_data_found = 1; } for (strun = stitr.first(), stcount = 0; strun != NULL; strun = stitr.next(), stcount++) { // store types of first two sub-tracks for later evaluation switch (stcount) { case 0: sttype1 = strun->TrackData::type(); break; case 1: sttype2 = strun->TrackData::type(); break; } // check if whole toc-file just references a single bin file if (strun->TrackData::type() == TrackData::DATAFILE) { if (binFileName == NULL) { binFileName = strdupCC(strun->filename()); } else { if (strcmp(binFileName, strun->filename()) != 0) { message(-2, "Cannot convert: toc-file references multiple data files."); err = 1; } } } } switch (stcount) { case 0: message(-2, "Cannot convert: track %d references no data file.", trackNr); err = 1; break; case 1: if (sttype1 != TrackData::DATAFILE) { message(-2, "Cannot convert: track %d references no data file.", trackNr); err = 1; } break; case 2: if (sttype1 != TrackData::ZERODATA || sttype2 != TrackData::DATAFILE) { message(-2, "Cannot convert: track %d has unsupported layout.", trackNr); err = 1; } break; default: message(-2, "Cannot convert: track %d has unsupported layout.", trackNr); err = 1; break; } } if (binFileName == NULL) { message(-2, "Cannot convert: toc-file references no data file."); err = 1; } if (err) { message(-2, "Cannot convert toc-file '%s' to a cue file.", tocFile); return 1; } std::ofstream out(cueFile); if (!out) { message(-2, "Cannot open cue file \'%s\' for writing: %s", cueFile, strerror(errno)); return 1; } if(convertedBinFile) { // cue file needs to reference the new bin file out << "FILE \"" << convertedBinFile << "\" BINARY" << "\n"; } else { out << "FILE \"" << binFileName << "\" BINARY" << "\n"; } long offset = 0; for (trun = titr.first(start, end), trackNr = 1; trun != NULL; trun = titr.next(start, end), trackNr++) { char buf[20]; snprintf(buf, sizeof(buf), "%02d ", trackNr); out << " TRACK " << buf; switch (trun->type()) { case TrackData::AUDIO: out << "AUDIO"; break; case TrackData::MODE1: case TrackData::MODE2_FORM1: out << "MODE1/2048"; break; case TrackData::MODE2: case TrackData::MODE2_FORM_MIX: out << "MODE2/2336"; break; case TrackData::MODE1_RAW: out << "MODE1/2352"; break; case TrackData::MODE2_RAW: out << "MODE2/2352"; break; default: break; } out << "\n"; if ( trun->copyPermitted() ) { out << " FLAGS DCP\n"; } const SubTrack *strun; SubTrackIterator stitr(trun); int pregap = 0; for (strun = stitr.first(); strun != NULL; strun = stitr.next()) { if (strun->TrackData::type() == TrackData::ZERODATA) { out << " PREGAP " << trun->start().str() << "\n"; pregap = 1; } else { if (!pregap && trun->start().lba() != 0) { out << " INDEX 00 " << Msf(offset).str() << "\n"; out << " INDEX 01 " << Msf(offset + trun->start().lba()).str() << "\n"; } else { out << " INDEX 01 " << Msf(offset).str() << "\n"; } offset += trun->length().lba(); if (pregap) offset -= trun->start().lba(); } } } out.close(); message(1, "Converted toc-file '%s' to cue file '%s'.", tocFile, cueFile); message(1, ""); if(convertedBinFile) { message(1, "Converting bin file..."); if(convertBin(toc, binFileName, convertedBinFile, byteSwapBinAudio)) { message(1, "Error converting bin file '%s' to '%s'", binFileName, convertedBinFile); message(1, ""); } else { message(1, "Converted bin file '%s' to '%s'", binFileName, convertedBinFile); message(1, ""); } } if(subchan_data_found && !convertedBinFile) { message(1, "Subchannel data detected on one or more tracks. The cue/bin"); message(1, "pair may not be compatible with third-party software. You can"); message(1, "use the -C option to create a bin file with subchannel data"); message(1, "removed."); message(1, ""); } message(1, "Please note that the resulting cue file is only valid if the"); message(1, "toc-file was created with cdrdao using the commands 'read-toc'"); message(1, "or 'read-cd'. For manually created or edited toc-files the"); message(1, "cue file may not be correct. This program just checks for"); message(1, "the most obvious toc-file features that cannot be converted to"); message(1, "a cue file."); message(1, ""); message(1, "Furthermore, if the toc-file contains audio tracks the byte"); message(1, "order of the image file will be wrong which results in static"); message(1, "noise when the resulting cue file is used for recording"); message(1, "(even with cdrdao itself). This can be corrected by creating"); message(1, "a new image file with the -C option and specifying the -s flag"); message(1, "to byte swap the audio tracks."); return 0; } cdrdao-cdrdao-f00afb2/utils/toc2mp3.cc000066400000000000000000000416661511453746600176510ustar00rootroot00000000000000/* toc2mp3 - encodes a audio CD disk image to mp3 files for each track * * Copyright (C) 2002 Andreas Mueller * * 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. */ #include #include #include #include #include #include #include #ifdef HAVE_GETOPT_H #include #endif #include #include #include #include #include #include #include #include #include "util.h" #include "Toc.h" #include "CdTextItem.h" using namespace std; // set desired default bit rate for encoding here: #define DEFAULT_ENCODER_BITRATE 192 static const char *PRGNAME = NULL; static int VERBOSE = 1; static int CREATE_ALBUM_DIRECTORY = 0; static string TARGET_DIRECTORY; static string ENCODING; static bool DRY_RUN = false; static string SEPARATOR = "_"; void message_args(int level, int addNewLine, const char *fmt, va_list args) { long len = strlen(fmt); char last = len > 0 ? fmt[len - 1] : 0; if (level < 0) { switch (level) { case -1: fprintf(stderr, "WARNING: "); break; case -2: fprintf(stderr, "ERROR: "); break; case -3: fprintf(stderr, "INTERNAL ERROR: "); break; default: fprintf(stderr, "FATAL ERROR: "); break; } vfprintf(stderr, fmt, args); if (addNewLine) { if (last != ' ' && last != '\r') fprintf(stderr, "\n"); } fflush(stderr); if (level <= -10) exit(1); } else if (level <= VERBOSE) { vfprintf(stderr, fmt, args); if (addNewLine) { if (last != ' ' && last != '\r') fprintf(stderr, "\n"); } fflush(stderr); } } void message(int level, const char *fmt, ...) { va_list args; va_start(args, fmt); message_args(level, 1, fmt, args); va_end(args); } void lame_message(const char *fmt, va_list args) { message_args(1, 0, fmt, args); } void lame_error_message(const char *fmt, va_list args) { message_args(-2, 0, fmt, args); } static void printVersion() { message(1, "toc2mp3 version %s - (C) Andreas Mueller ", VERSION); message(1, ""); } static void printUsage() { message(0, "Usage: %s [-v #] [-d target-dir ] [-c] { -V | toc-file }", PRGNAME); message(0, "\nConverts an audio CD disk image (.toc file) to mp3 files."); message(0, "Each track will be written to a separate mp3 file."); message(0, "Special care is taken that the mp3 files can be played in sequence"); message(0, "without having unwanted noise at the transition points."); message(0, "CD-TEXT information (if available) is used to set ID3 (v2) tags and to"); message(0, "construct the name of the mp3 files.\n"); message(0, "Options:"); message(0, " -h Shows this help."); message(0, " -v Sets verbose level to (0..2)."); message(0, " -V Displays version and exit"); message(0, " -d Specifies directory the mp3 files will be"); message(0, " written to."); message(0, " -c Adds a sub-directory composed out of CD title"); message(0, " and author to specified with -d."); message(0, " -J Force text decoding to given iconv-compatible encoding\n" " (default ISO-8859-1)"); message(0, " -s Filename separator for title, artist (default \"_\")"); message(0, " -n Dry run, show created files but don't actually encode"); message(0, " -b Sets bit rate used for encoding (default %d kbit/s).", DEFAULT_ENCODER_BITRATE); message(0, " See below for supported bit rates."); message(0, ""); message(0, "LAME encoder version: %s", get_lame_version()); message(0, "Supported bit rates: "); for (int i = 0; i < 16 && lame_get_bitrate(1, i) >= 0; i++) { message(0, "%d ", lame_get_bitrate(1, i)); } message(0, ""); } static int parseCommandLine(int argc, char **argv, char **tocFile, int *bitrate) { int c; int printVersion = 0; extern char *optarg; extern int optind, opterr, optopt; ENCODING = "ISO-8859-1"; opterr = 0; while ((c = getopt(argc, argv, "Vhcv:d:b:J:ns:")) != EOF) { switch (c) { case 'V': printVersion = 1; break; case 'v': if (optarg != NULL) { if ((VERBOSE = atoi(optarg)) < 0) { message(-2, "Invalid verbose level: %s", optarg); return 0; } } else { message(-2, "Missing verbose level after option '-v'."); return 0; } break; case 'b': if (optarg != NULL) { *bitrate = atoi(optarg); } else { message(-2, "Missing bit rate value after option '-b'."); return 0; } break; case 'n': DRY_RUN = true; break; case 'c': CREATE_ALBUM_DIRECTORY = 1; break; case 'h': return 0; break; case 'J': ENCODING = optarg; break; case 's': SEPARATOR = optarg; break; case 'd': if (optarg != NULL) { TARGET_DIRECTORY = optarg; } else { message(-2, "Missing target directory after option '-d'."); return 0; } break; case '?': message(-2, "Invalid option: %c", optopt); return 0; break; } } if (printVersion) { return 1; } if (optind < argc) { *tocFile = strdupCC(argv[optind]); optind++; } else { message(-2, "Missing toc-file name."); return 0; } if (optind != argc) { message(-2, "More arguments than expected."); return 0; } return 2; } lame_global_flags *init_encoder(int bitrate) { lame_global_flags *lf; int bitrateOk = 0; for (int i = 0; lame_get_bitrate(1, i) >= 0 && !bitrateOk; i++) { if (bitrate == lame_get_bitrate(1, i)) bitrateOk = 1; } if (!bitrateOk) { message(-2, "Invalid bit rate: %d kbit/s", bitrate); return NULL; } if ((lf = lame_init()) == NULL) { return NULL; } lame_set_msgf(lf, lame_message); lame_set_debugf(lf, lame_message); lame_set_errorf(lf, lame_error_message); lame_set_in_samplerate(lf, 44100); lame_set_num_channels(lf, 2); lame_set_quality(lf, 2); lame_set_mode(lf, STEREO); lame_set_brate(lf, bitrate); //lame_set_VBR(lf, vbr_abr); //lame_set_VBR(lf, vbr_mtrh); //lame_set_VBR_q(lf, 2); //lame_set_VBR_mean_bitrate_kbps(lf, bitrate); //lame_set_VBR_min_bitrate_kbps(lf, 112); //lame_set_VBR_hard_min(lf, 1); //lame_set_bWriteVbrTag(lf, 1); //lame_set_asm_optimizations(lf, AMD_3DNOW, 1); return lf; } string to_utf8(const string& input) { if (ENCODING == "UTF-8") return input; ICONV_CONST char* src = (ICONV_CONST char*)alloca(input.size() + 1); strcpy(src, input.c_str()); size_t srclen = strlen(src); size_t dstlen = srclen * 4; char* dst = (char*)alloca(dstlen); char* orig_dst = dst; auto icv = iconv_open("UTF-8", ENCODING.c_str()); if (!icv) return input; if (iconv(icv, &src, &srclen, &dst, &dstlen) == (size_t)-1) { fputs(strerror(errno), stderr); return input; } *dst = 0; return string(orig_dst); } vector to_utf16(const string& input) { vector vec; ICONV_CONST char* src = (ICONV_CONST char*)alloca(input.size() + 1); strcpy(src, input.c_str()); size_t srclen = strlen(src); size_t dstlen = srclen * 4; vec.resize(dstlen / 2); char* dst = (char*)(&vec[0]); char* orig_dst = dst; auto icv = iconv_open("UTF-16//TRANSLIT", ENCODING.c_str()); if (!icv) return vec; if (iconv(icv, &src, &srclen, &dst, &dstlen) == (size_t)-1) { fputs(strerror(errno), stderr); return vec; } vec.resize((dst - orig_dst) / 2); vec.push_back(0); return vec; } void set_id3v2tag(lame_global_flags* lf, int type, const string &str) { if (ENCODING != "ISO-8859-1") { auto dst = to_utf16(str); switch (type) { case 'a': id3tag_set_textinfo_utf16(lf, "TPE1", (short unsigned int*)&dst[0]); break; case 't': id3tag_set_textinfo_utf16(lf, "TIT2", (short unsigned int*)&dst[0]); break; case 'l': id3tag_set_textinfo_utf16(lf, "TALB", (short unsigned int*)&dst[0]); break; } return; } switch (type) { case 'a': id3tag_set_artist(lf, str.c_str()); break; case 't': id3tag_set_title(lf, str.c_str()); break; case 'l': id3tag_set_album(lf, str.c_str()); break; } } void set_id3_tags(lame_global_flags *lf, int tracknr, const string &title, const string &artist, const string &album) { char buf[100]; id3tag_init(lf); id3tag_add_v2(lf); if (!title.empty()) set_id3v2tag(lf, 't', title.c_str()); if (!artist.empty()) set_id3v2tag(lf, 'a', artist.c_str()); if (!album.empty()) set_id3v2tag(lf, 'l', album.c_str()); if (tracknr > 0 && tracknr <= 255) { snprintf(buf, sizeof(buf), "%d", tracknr); id3tag_set_track(lf, buf); } } int encode_track(lame_global_flags *lf, const Toc *toc, const string &fileName, long startLba, long len) { int fd; int ret = 1; TocReader reader(toc); Sample audioData[SAMPLES_PER_BLOCK]; short int leftSamples[SAMPLES_PER_BLOCK]; short int rightSamples[SAMPLES_PER_BLOCK]; unsigned char mp3buffer[LAME_MAXMP3BUFFER]; if (reader.openData() != 0) { message(-2, "Cannot open audio data."); return 0; } if (reader.seekSample(Msf(startLba).samples()) != 0) { message(-2, "Cannot seek to start sample of track."); return 0; } if ((fd = open(fileName.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) { message(-2, "Cannot open \"%s\" for writing: %s", fileName.c_str(), strerror(errno)); return 0; } while (len > 0) { if (reader.readSamples(audioData, SAMPLES_PER_BLOCK) != SAMPLES_PER_BLOCK) { message(-2, "Cannot read audio data."); ret = 0; break; } for (int i = 0; i < SAMPLES_PER_BLOCK; i++) { leftSamples[i] = audioData[i].left(); rightSamples[i] = audioData[i].right(); } int count = lame_encode_buffer(lf, leftSamples, rightSamples, SAMPLES_PER_BLOCK, mp3buffer, sizeof(mp3buffer)); if (count < 0) { message(-2, "Lame encoder failed: %d", count); ret = 0; break; } if (count > 0) { if (fullWrite(fd, mp3buffer, count) != count) { message(-2, "Failed to write encoded data: %s", strerror(errno)); ret = 0; break; } } len--; } if (ret != 0) { int count = lame_encode_flush_nogap(lf, mp3buffer, sizeof(mp3buffer)); if (count > 0) { if (fullWrite(fd, mp3buffer, count) != count) { message(-2, "Failed to write encoded data: %s", strerror(errno)); ret = 0; } } } if (close(fd) != 0) { message(-2, "Failed to close encoded data file: %s", strerror(errno)); ret = 0; } if (ret != 0) { FILE *fp = fopen(fileName.c_str(), "a+"); if (fp != NULL) { lame_mp3_tags_fid(lf, fp); fclose(fp); } else { message(-2, "Cannot reopen output file for adding headers: %s", strerror(errno)); ret = 0; } } return ret; } string &clean_string(string &s) { int i = 0; int len = s.length(); char c; while (i < len && (c = s[i]) != 0) { if (c == '_') { s[i] = ' '; i++; } else if (iscntrl(c) || c == '/') { s.erase(i, 1); len = s.length(); } else { i++; } } len = s.length(); for (i = 0; i < len && s[i] != 0 && isspace(s[i]); i++) ; if (i >= len) { // string just contains space s = ""; } return s; } int main(int argc, char **argv) { char *tocFile; int bitrate = DEFAULT_ENCODER_BITRATE; Toc *toc; lame_global_flags *lf; string album, albumPerformer, title, performer; int cdTextLanguage = 0; const CdTextItem *cdTextItem; char *tocfileBaseName, *p; char sbuf[100]; int err = 0; setlocale(LC_CTYPE, ""); PRGNAME = *argv; switch (parseCommandLine(argc, argv, &tocFile, &bitrate)) { case 0: printUsage(); exit(1); break; case 1: printf("%s\n", VERSION); exit(0); break; } printVersion(); if ((toc = Toc::read(tocFile)) == NULL) { message(-10, "Failed to read toc-file '%s'.", tocFile); } if ((lf = init_encoder(bitrate)) == NULL) { message(-10, "Cannot initialize lame encoder"); } if ((p = strrchr(tocFile, '/')) != NULL) tocfileBaseName = strdupCC(p + 1); else tocfileBaseName = strdupCC(tocFile); if ((p = strrchr(tocfileBaseName, '.')) != NULL && (strcmp(p, ".toc") == 0 || strcmp(p, ".cue") == 0)) { *p = 0; } if (strlen(tocfileBaseName) == 0) { delete[] tocfileBaseName; tocfileBaseName = strdupCC("unknown"); } if ((cdTextItem = toc->getCdTextItem(0, cdTextLanguage, CdTextItem::PackType::TITLE)) != NULL) { album = (const char*)cdTextItem->data(); clean_string(album); if (album.empty()) album = tocfileBaseName; } else { album = tocfileBaseName; } if ((cdTextItem = toc->getCdTextItem(0, cdTextLanguage, CdTextItem::PackType::PERFORMER)) != NULL) { albumPerformer = (const char*)cdTextItem->data(); clean_string(albumPerformer); } else { albumPerformer = ""; } string mp3TargetDir; if (!TARGET_DIRECTORY.empty()) { mp3TargetDir = TARGET_DIRECTORY; if (*(TARGET_DIRECTORY.end() - 1) != '/') mp3TargetDir += "/"; if (CREATE_ALBUM_DIRECTORY) { if (!album.empty() && !albumPerformer.empty()) { mp3TargetDir += albumPerformer; mp3TargetDir += SEPARATOR; mp3TargetDir += album; } else { mp3TargetDir += tocfileBaseName; } if (mkdir(mp3TargetDir.c_str(), 0777) != 0) { message(-10, "Cannot create album directory \"%s\": %s", mp3TargetDir.c_str(), strerror(errno)); } mp3TargetDir += "/"; } } Msf astart, aend, nstart, nend; const Track *actTrack, *nextTrack; int trackNr; TrackIterator titr(toc); int firstEncodedTrack = 1; trackNr = 1; actTrack = titr.first(astart, aend); nextTrack = titr.next(nstart, nend); while (actTrack != NULL && err == 0) { if (actTrack->type() == TrackData::AUDIO) { // Retrieve CD-TEXT data for track title and performer if ((cdTextItem = toc->getCdTextItem(trackNr, cdTextLanguage, CdTextItem::PackType::TITLE)) != NULL) { title = (const char*)cdTextItem->data(); clean_string(title); } else { title = ""; } if ((cdTextItem = toc->getCdTextItem(trackNr, cdTextLanguage, CdTextItem::PackType::PERFORMER)) != NULL) { performer = (const char*)cdTextItem->data(); clean_string(performer); } else { performer = ""; } // build mp3 file name string mp3FileName; snprintf(sbuf, sizeof(sbuf), "%02d", trackNr); mp3FileName += sbuf; mp3FileName += SEPARATOR; if (!title.empty()) { mp3FileName += to_utf8(title); mp3FileName += SEPARATOR; } mp3FileName += to_utf8(album); if (!albumPerformer.empty()) { mp3FileName += SEPARATOR; mp3FileName += to_utf8(albumPerformer); } mp3FileName += ".mp3"; long len = aend.lba() - astart.lba(); if (nextTrack != NULL && nextTrack->type() == TrackData::AUDIO) len += nextTrack->start().lba(); if (len > 0) { set_id3_tags(lf, trackNr, title, performer, album); if (firstEncodedTrack) { if (lame_init_params(lf) < 0) { message(-2, "Setting of lame parameters failed"); err = 1; break; } message(1, "Lame encoder settings:"); lame_print_config(lf); message(1, "Selected bit rate: %d kbit/s", bitrate); if (VERBOSE >= 2) lame_print_internals(lf); message(1, ""); message(1, "Starting encoding to target directory \"%s\"...", mp3TargetDir.empty() ? "." : mp3TargetDir.c_str()); firstEncodedTrack = 0; } else { if (lame_init_bitstream(lf) != 0) { message(-2, "Cannot initialize bit stream."); err = 1; break; } } message(1, "Encoding track %d to \"%s\"...", trackNr, mp3FileName.c_str()); if (!DRY_RUN && !encode_track(lf, toc, mp3TargetDir + mp3FileName, astart.lba(), len)) { message(-2, "Encoding of track %d failed.", trackNr); err = 1; break; } } } actTrack = nextTrack; astart = nstart; aend = nend; trackNr++; if (actTrack != NULL) nextTrack = titr.next(nstart, nend); } lame_close(lf); exit(err); }