FAQ 2.1.0
Contents
- 1 What is aMSN?
- 2 Where can I get aMSN ?
- 3 Troubleshooting
- 3.1 Why are arabic fonts displayed from left to right instead of right to left?
- 3.2 I have enabled the traydock icon, but when I minimize aMSN, it is still shown in both the taskbar and the tray. How can I make it display in the tray only?
- 3.3 When I close aMSN's window, it quits instead of minimizing to tray
- 3.4 I don't see the traydock even if I enabled it, what's the problem?
- 3.5 Does aMSN run on 64-bit systems?
- 3.6 When notify window pops up, the windows taskbar partially hides it, can I fix this?
- 3.7 Can I see who blocked me?
- 3.8 My jpeg webcam does not currently work, will my jpeg webcam work in the future (example: D-link dsb-c310)?
- 3.9 Why can't I receive acceptable quality images from my contacts using aMSN?
- 3.10 I can't read Chinese or Japanese with aMSN, even after changing the text encoding. Where can I find help?
- 3.11 How do I capture bug report information from a segmentation fault? (LINUX)
- 3.12 I want to report a bug, how do I open the status log and the protocol debugger?
- 3.13 When I double click "amsn" file from a graphical file browser, like Konqueror or Nautilus, it opens a text editor instead of running aMSN. What shall I do (Linux)?
- 3.14 Sometimes aMSN "hangs", why is this?
- 3.15 I try to run amsn but I get this error:
- 3.16 Can I use aMSN behind a proxy server?
- 3.17 I'm using aMSN behind a firewall, or using IP-Masquerade. Sending files won't work, can I fix it?
- 3.18 With version 0.94 I could see when someone opened a conversation window with me, but since version 0.95 this doesn't happen anymore, why?
- 3.19 I liked the XXXX skin when using the previous version, but it seems to be incompatible with the latest version... when will it be ?
- 3.20 As soon as I try to log on or change aMSN's language, it crashes with the following message: X Error of failed request: BadValue (integer parameter out of range for operation), Major opcode of failed request: 45 (X_OpenFont)
- 3.21 I try to run aMSN and it gives this error: Error in startup script: time value too large/small to represent while executing [...] procedure "ConvertLocalToUTC".
- 4 Using aMSN
- 5 Running on Linux
- 6 Running on Windows
- 7 Running on Mac OS X
- 8 Other Questions
|
What is aMSN?
What is aMSN?
aMSN is a Microsoft Messenger clone. It allows you to keep in touch with your friends and exchange instant messages and files.
Back to top
What do I need to run aMSN?
- Windows and Mac OS X. aMSN will run right out of the box if you download the official packages, which can be found at http://amsn.sourceforge.net/download.php.
- Linux. You will need Tcl 8.4 / Tk 8.4 or above in order to run aMSN. These two packages (Tcl & Tk) are usually installed by default on most distributions. These can also be installed as a dependency if your packaging system supports it (rpm, deb, etc.). If for some reason your distribution does not currently provide you with Tcl 8.4 or Tk 8.4, you may download them and follow the installation instructions at http://tcl.tk.
Back to top
Where can I get aMSN ?
You can download the packages of aMSN at http://amsn.sourceforge.net/download.php.
For Linux users : You can also get aMSN using your distribution's package management system (apt-get install amsn for debian/ubuntu for example).
Back to top
Troubleshooting
Why are arabic fonts displayed from left to right instead of right to left?
- Windows: Go to 'Control Panel' → 'Regional and Language Options' → Languages tab, and enable the option "Install files for complex scripts and right-to-left languages"
- Linux: Installing the Arabic locale should solve this issue.
Back to top
I have enabled the traydock icon, but when I minimize aMSN, it is still shown in both the taskbar and the tray. How can I make it display in the tray only?
The first time you will close aMSN with the 'X' button in the main window's border. It should ask you if you want to quit or minimize it to tray. You must choose the 'Minimize to Tray' option if you want it to disappear from the taskbar.
Alternatively, you can also click the "Minimize to Tray" option from the Account menu.
Back to top
When I close aMSN's window, it quits instead of minimizing to tray
The first time you will close aMSN with the 'X' button in the main window's border. It should ask you if you want to quit or minimize it to tray. You must choose the 'Minimize to Tray' option if you want it to minimize to the tray.
If you chose 'Quit' and enabled the "Remember my choice" option, it will always quit and will not ask you again. If you want to change this behavior and want it to ask you again so you can change your choice, you will have to do the following procedure :
Press Ctrl-Shift-C from aMsn's main window, a new window titled "Console" will appear in which you can type commands. Type the following and press enter :
::config::setKey closingdocks 0
You can now close this new Console window and the next time you close aMSN's main window, it will ask you again to make a choice.
Back to top
I don't see the traydock even if I enabled it, what's the problem?
- Linux: Make sure the file msn/utils/linux/traydock/libtray.so exists. If it does not exist, make sure you download an official package of aMSN at: http://amsn-project.net/download.php
If you compiled aMSN yourself, please make sure you have the X11 development packages installed and follow this page to compile aMSN correctly.
NOTE: There is no traydock icon on Mac OS X
Back to top
Does aMSN run on 64-bit systems?
Yes, many users have been able to run aMSN on 64-bit architectures. However, you will have to compile tcltls by yourself. There isn't a package for x84_64 on the aMSN site so you need to download it from: [1]
Back to top
When notify window pops up, the windows taskbar partially hides it, can I fix this?
Yes, you can move the notify window X pixels to the left and Y pixels to the top. You can customize this by modifying the "X Offset" and "Y Offset" values in (menu) 'Account' → 'Preferences' → 'Advanced' → “Offset the position of the notification pop-up.” and clicking “Save” to save your modifications.
Back to top
Can I see who blocked me?
No, this feature is no longer available because the block detection bug that was happening in the Microsoft servers has now been fixed.
There is NO safe way to know if someone blocked you
Back to top
My jpeg webcam does not currently work, will my jpeg webcam work in the future (example: D-link dsb-c310)?
JPEG webcams support is currently supported since the 0.97 version of aMSN.
If you are using a version prior to 0.97, please update to the latest version of aMSN.
Back to top
Why can't I receive acceptable quality images from my contacts using aMSN?
If the image is of a poor quality, it's probably because the other user's webcam is of poor quality. aMSN's quality of the webcam is the same as the official msn client.
Back to top
I can't read Chinese or Japanese with aMSN, even after changing the text encoding. Where can I find help?
Please read the documentation about getting SCIM to work with aMSN.
Back to top
How do I capture bug report information from a segmentation fault? (LINUX)
Make sure amsn was compiled with debugging symbols, if you installed it using a binary package, you should probably download from source and recompile it. To enable debugging symbols, configure it with :
./configure --enable-debug
If you're unable to compile it, then you can still send us information without the debugging symbols.
Once it is compiled/installed, go to the directory where you have installed aMSN (example: /usr/share/amsn or /home/yourusername/amsn-0.95/) type:
$ gdb --args wish amsn
(gdb) run
[then when it segfaults, type]
(gdb) bt
(gdb) bt full
You will then receive the bug report information. Please report this information to the forums: http://amsn-project.net/forums
MAKE SURE THAT YOU SEARCH THE FORUMS FIRST TO SEE IF IT WAS ALREADY REPORTED
Back to top
I want to report a bug, how do I open the status log and the protocol debugger?
Open your contact list and press the following key combinations :
status log: ctrl + s (Command-S on Mac OS X)
protocol debug: ctrl + d (Command-D on Mac OS X)
Back to top
When I double click "amsn" file from a graphical file browser, like Konqueror or Nautilus, it opens a text editor instead of running aMSN. What shall I do (Linux)?
aMSN is written in Tcl/Tk, an interpreted language, so the "amsn" file is just a text file with the program code. The file manager might
think it's a text file, so it will launch the text editor.
In Konqueror (KDE) or Nautilus (Gnome), running aMSN can be done by right-clicking the “amsn” file and choosing "Open with..." Konqueror) or "Launch with..." (Gnome), depending on the file browser.
Type "wish". This launches the "amsn" script.
If you are told the the "wish" command doesn't exist, you need to install Tcl/Tk.
Back to top
Sometimes aMSN "hangs", why is this?
When aMSN hangs it's usually a problem with the sound configuration. Perhaps you're playing a sound but the sound card is blocked, and the play command stops until the sound card is available. Try disabling sound or changing the sound command configuration.
If aMSN still hangs, and you are using a 2.6.x kernel, try running aMSN with:
export LD_ASSUME_KERNEL=2.2.5 && amsn
This command will tell the dynamic linker to use the old thread model. For more information on this issue, see: http://people.redhat.com/drepper/assumekernel.html
If you are on Mac OS X it often happens when you receive a smiley on a chatwindow, it's a known issue.
Back to top
I try to run amsn but I get this error:
bash: ./amsn: bad interpreter: No such file or directory
You need to install the tcl/tk packages, because you need the wish interpreter. If you think you have it, try typing:
wish /usr/share/amsn/amsn
instead of:
amsn
If this works, edit /usr/share/amsn/amsn and change the first line to :
#!/usr/bin/wish
where /usr/bin/wish would be the location of the wish interpreter.
You can find out the location of the 'wish' interpreter by typing :
which wish
Back to top
Can I use aMSN behind a proxy server?
Yes, we provide support for HTTP and SOCKS5 proxies.
Back to top
I'm using aMSN behind a firewall, or using IP-Masquerade. Sending files won't work, can I fix it?
In this case, the firewall may be blocking incoming connections. File transfers work this way: When you want to send someone a file, you send an invitation with your IP address and a port number. Then the remote client must connect to your IP:port to start the transfer.
The used port is usually 6891, 6892 and so on (first transfer is on port 6891,but if you start a new file transfer while the first one hasn't finished yet, then it will use 6892, and so on).
If you are using a firewall, you must make sure that it allows incoming connections to port 6891 (and next ones if you want to be able to make more than one transfer at the same time).
If you are behind a router, enable port forwarding for ports 6891 to 6900 to your PC's internal IP address.
You can change the port value from the "Connection" tab of the Preferences window.
Back to top
With version 0.94 I could see when someone opened a conversation window with me, but since version 0.95 this doesn't happen anymore, why?
Users with MSN7 and later versions of MSN will automatically "open a conversation window" with you as soon as you (or they) connect. It is done automatically because they try to download your display picture. So, as soon as someone connects, the screen was flooded with windows from people just trying to download the display picture. This was annoying, so the feature was removed.
Note also that since Windows Live Messenger 8.0, the user would not join the chat until he sends the first message, so this is a second reason why it is not possible anymore.
Back to top
I liked the XXXX skin when using the previous version, but it seems to be incompatible with the latest version... when will it be ?
We don't know yet, check on the skin website or email the author of the skin to obtain more information or to ask him to update his skin to work better with the new version.
Back to top
As soon as I try to log on or change aMSN's language, it crashes with the following message: X Error of failed request: BadValue (integer parameter out of range for operation), Major opcode of failed request: 45 (X_OpenFont)
First of all, it may be a font problem: try making aMSN run with a different font (under Account -> Preferences -> Appearance).
Second, you may need to run aMSN using a different encoding (under Account -> Preferences -> Appearance again, utf-8 is a safe choice).
Third, try clearing your font cache with the command:
fc-cache -fv
Then, make sure your locale (your LC_ALL or LC_CTYPE environment variable) is installed on your system:
set | grep LC_
and make sure the corresponding directories (after the = ) exist on /usr/lib/locale . If they don't, install them according to your distribution.
Finally, if none of the above works, try disabling some FontPath's from /etc/X11/XF86Config or /etc/X11/Xorg.conf until you find out which font path contains problematic fonts, and recreate the fonts.cache , fonts.dir and fonts.scale in that directory.
Back to top
I try to run aMSN and it gives this error: Error in startup script: time value too large/small to represent while executing [...] procedure "ConvertLocalToUTC".
Make you sure the file /etc/localtime exists. If it doesn't, link it to /usr/share/zoneinfo/YOUR/TIME/ZONE and retry starting aMSN.
To create the file under Linux :
ln -s /usr/share/zoneinfo/YOUR/TIME/ZONE /etc/localtime
Back to top
Using aMSN
What are the keyboard shortcuts ?
For and up to date list of keyboard shortcuts, please read the Shortcuts page.
Back to top
What does the special icon on the right of the buddies mean?
The icon
in the buddy list means that the corresponding contact do not have you in his list.
Back to top
Can I copy a contact address to the clipboard?
Yes, right click on that contact name on the contact list, then choose "Properties". In the new window, you can copy the email/nickname/personal message of the user.
Can I copy or open a URL address in a contact's nickname/personal message?
Yes, right click on that contact name on the contact list, then in the pop-up menu, You will have the choice to copy or open any URL in the contact's nickname or personal message.
Back to top
How can I set my personal message like in MSN7 ?
The Personal Message (PSM) is the text appearing under your nick. This feature is now available since aMSN 0.96.
To set your PSM, you need to click on the "Account" menu then "Change nick ...", there will be a field to change the PSM.
Back to top
How can I access the history of the messages I sent in my chat windows?
If you want to access previous messages you sent in your chat windows you only need to use the Control key with the arrows. It works the same way as in a shell so Ctrl-Up(Command-Up on MacOSX) gives you the previous message sent and Ctrl-Down(Command-Down on Mac OS X), the next one.
See the Shortcuts page for a list of all keyboard shortcuts.
Back to top
In the preferences' privacy tab, what do those four lists mean?
There are four lists, known as:
Allow List (AL), Block List (BL), Forward or Contact List (FL) and Reverse List (RL).
AL : This list contains the emails of people who are allowed to see you when you get online and they can also chat with you.
BL : This is the block list, which means it contains the list of people you are blocking. So this means they can't see you when you are online, and they can't chat with you.
FL : This list contains all contacts that are shown on your contact list.
RL : This is the reverse list, it contains the email addresses of people who have you in their list.
Back to top
In the preferences' privacy tab, what do the different colors in the contacts mean?
You should notice the colors in the list headers:
- Allow List: green foreground
- Block List: red foreground
- Forward List: red background
- Reverse List: yellow background
A contact in any list will take a different color depending the lists that contact is contained on:
- If it's in Allow list, it will have green foreground.
- If it's in Block list, it will have red foreground.
- If it's in Forward and Reverse lists, it will have white background.
- If it's in Forward list, but not in Reverse list, it will have red background.
- If it's in Reverse list, but not in Forward list, it will have yellow background.
- If it's not in Forward or Reverse list, it will have a black background.
Let's be a bit more specific:
- Green font: the contact is able to contact you.
- Red font: the contact is NOT able to contact you (BLOCKED).
- White background: the contact has you in their contacts list and they are in yours.
- Yellow background: the contact has you in their contacts list, but you no longer have them in yours.
- Red background: the contact is in your contacts list, but you are not in theirs.
- Black background: the contact has deleted you from their contacts list and you have deleted them from yours.
Back to top
I want to add my own custom smileys, how can I do it?
You may add custom smileys (also known as emoticons) by following these steps :
- Open a chat window of any contact
- Click the “Insert Emoticon” button found on the chat window (Screenshot 5.1)
- Click the “Add new custom smiley” button (Screenshot 5.2)
- Type a Description for your emoticon in the “Description” text box (Screenshot 5.3)
- Type the Text triggers for your emoticon in the “Text triggers” text box. Text triggers are triggers which display an icon when they are typed and Enter is pressed. (Screenshot 5.3)
example: (test)
When (test) is typed in the chat window and Enter is pressed, the emoticon associated with the (test) Text trigger will be displayed.
- Browse for the new emoticon that you would like to use by clicking the Browse button located to the right of the Smiley filename text box and select the image or emoticon that you would like to use. Click “Open”. (Screenshot 5.4)
If your image is larger than normal emoticons, you will see a message box saying “The smiley you choose is bigger than normal size. Do you want to resize it?” If you want your image or emoticon resized so that you can use it as an emoticon, simply click “Yes”
By clicking “Yes” your image may be scaled down and display incorrectly.
- Click the “Insert Emoticon” button found on the chat window. You will now see your custom emoticon added to the emoticon chooser. (Screenshot 5.6)
Back to top
Nicknames are now truncated. Is it possible to revert back to full nicknames?
Yes. To have nicknames displayed in their full length on the contact list, in the alerts and the chat window, go to 'Tools' → 'Preferences' → 'Advanced Tab', and uncheck the selection which reads, Truncate nicknames longer than window width in window titles and contact list.” (Screenshot 5.7)
The same can be done for nicknames inside the chat window conversations by disabling the option “Truncate nicknames longer than window width inside conversations.”(Screenshot 5.7)
Back to top
How can I browse through my webcam logs and convert the .cam (cam recordings) to a movie file such as .mpeg?
The file format of those .cam files are a direct dump of the data received on the socket, which means it's in the MS proprietary format. For this reason, no player can play those files, only amsn.
Actually there's a tool to do it released by Hyriand (linux only). See http://amsn-project.net/forums/viewtopic.php?t=2954
Back to top
How can I make my webcam work?
If your webcam will not work with aMSN, please make sure your webcam is plugged in, turned on, and ready to be used.
Other applications that can be used to test if your webcam is working correctly on Linux:
XawTv
GnomeMeeting
V4L
On Mac you can try the macam project if you do not have an Apple iSight
Back to top
Where are the "stolen" display pictures saved?
- Windows : C:\Documents andSettings\MyWindowsUsername\amsn\youremail_profile\displaypic\cache
- Linux : /home/yourusername/.amsn/yourusername@youremail.com/displaypic/cache
- Mac OS X: Home / Library / Application Support / your_email_profile / displaypic / cache
You can also access all the previous display pictures of a user from :
- The contact's properties page
- The "Change Display picture" window
Back to top
How can I change the directory where the profiles information are saved ?
There is no option to do this, you have to modify the code of aMSN, but it is not complicated. In the aMSN folder, look for a amsn (/usr/share/amsn/amsn) file and open it for editing with your favorite text editor.
Search for the following code :
} elseif {$tcl_platform(platform) == "windows"} {
if {[info exists env(USERPROFILE)]} {
set HOME "[file join $env(USERPROFILE) amsn]"
set files_dir "[file join $env(USERPROFILE) amsn_received]"
} else {
set HOME "[file join [pwd] amsn_config]"
set files_dir "[file join [pwd] amsn_received]"
}
change it to
} elseif {$tcl_platform(platform) == "windows"} {
set HOME "[file join [pwd] amsn_config]"
set files_dir "[file join [pwd] amsn_received]"</nowiki>
in order to save the files in the directory where aMSN is launched.
Back to top
Running on Linux
How can I use anti-aliased fonts in aMSN?
Use a distro that has tcl/tk 8.5 or higher, or take a look at: Enabling_antialiasing
That page will provide you information on how to re-compile Tk with anti-alias support.
Back to top
How do I create a shortcut to aMSN on my desktop on Linux?
- KDE
- Right-click on the K-menu and a Panel Menu will appear as seen in the screenshot below:
- Click Add Non-KDE Application
- A Non-KDE Application Configuration dialog box will be displayed
- Enter the text as shown below:
- Click “OK” and an aMSN icon will be added to your kicker menu :
- If you want to change the icon or other configurations, simply right-click the new aMSN button, and a menu will be displayed. Click “Configure aMSN Button...” and the Non-KDE Application Configuration will be displayed.
Back to top
How do I open file-transfer ports in SUSE Linux?
(Guide thanks to John Hillier)
- Open 'YaST' -> 'Security and Users' -> 'Firewall' -> 'Firewall Configuration'.
- Click on "Expert" in 'Additional Services' and add port 6891.
Back to top
My aMSN sound notifications are not being played until I stop playing my music. How can I fix this so I can hear both at the same time?
- KDE: You can configure XMMS, amaroK, etc. to play sound through arts, and use artsplay as sound play command for aMSN which is able to mix sounds.
- Gnome: You can use esdplay and configure XMMS for playing through ESD.
Back to top
When I try running aMSN, I get an error "unknown color Black". How can I fix it ?
This problem is not coming from aMSN, it's an Xorg faulty installation. You probably have a bad Xorg configuration for the file rgb.txt (especially with some versions of Xgl).
If you are using xgl, you most probably have the file rgb.txt in /etc/X11 . Xgl in Ubuntu Dapper is usually misconfigured and looks for the file in /usr/share/X11 . Make a symlink to it in /usr/share/X11 and restart your X server.
If you are not using xgl, open your /etc/X11/xorg.conf and look for a line that says:
Section "Files"
RgbPath "/etc/X11/rgb"
If the RgbPath line does not exist at all, add it under the section "Files". Then make sure the file exists in the directory defined in RgbPath (/etc/X11/ in this case). You may need to copy it from another location in your computer, or you can download it from http://amsn.sourceforge.net/rgb.txt . You must also restart your X server for the changes to take effect. PLEASE NOTE: the line in xorg.conf must NOT contain the extension of the file!!!
Back to top
TLS does not seem to work and I have tcl/tk 8.5. How can I fix it ?
TLS 1.5 is broken, in order to fix it, you have to find out where your copy of TLS is with :
locate tls.tcl
or if you do not use locate :
find / -name tls.tcl
Those commands should give you something like /usr/lib/tls1.50/tls.tcl. In the same directory, you should find a file named pkgIndex.tcl. Edit this file with your favorite editor (vi, emacs, nano/pico, etc..) :
vi /usr/lib/tls1.50/pkgIndex.tcl
and change the line :
package ifneeded tls 1.5
by
package ifneeded tls 1.50
TLS should now work well. If it not the case, please let us know on the forums
Back to top
aMSN does not seem to work correctly with some files, especially files containing the character ` (back quote). How to fix it ?
aMSN cannot handle files containing the character `(back quote) in their path. A way to resolve this issue is to mount the partition containing the file with this caracter with the 'utf8' option. Refer to the man page of your version of mount to find the right option for your file system.
Back to top
Running on Windows
How can I prevent/make aMSN from loading on windows start ?
You can do that by clicking on the checkbox 'load aMSN at Windows start' in Account -> Preferences -> Session
Back to top
Whenever I go to preferences->session, the 'load amsn at windows start' is disabled, even if it does load at windows start !
We cannot detect if aMSN loads at Windows start so the checkbox is disabled. However, the change is taken in consideration if you modified the value and then press the "Save"' button.
Back to top
Running on Mac OS X
I have a question about Mac OS X, where can I go to find answers?
You can get answers to questions about Mac OS X on the aMSN Mac Forum found at: http://forums.cocoaforge.com/viewforum.php?f=14
Why do some characters in the aMSN contact list appear as squares?
These are Unicode characters. Unicode support has been added for Mac OS X since version 0.96 of aMSN.
Why can't I use the shortcut Command-Space to switch keyboard layouts?
This seems to be an issue with the Tcl/Tk frameworks that aMSN depends on. It is currently being looked into.
How do I sign into more than one account with Mac aMSN?
You need to duplicate the aMSN application, and then run both copies. The easiest way to do this, is to find the application in Finder, and press Command-D to duplicate the application.
aMSN is incredibly slow on my new Intel Mac, what can I do to speed it up?
aMSN 0.96 is the first Universal binary version of aMSN, please update to at least that version. You can further speed up aMSN by turning off smileys in the contact list (the option is in aMSN's preferences under the Appearence tab), and also by colapsing your offline group.
Webcam doesn't work on my Intel Mac!
Update to the latest aMSN version (0.97 or higher), and you will then be able to use webcam!
How do I update aMSN to the latest development version on a Mac?
Up to date instructions on how to do this can be found at the SVN wiki page.
I want to delete aMSN but I cannot empty the Trash!
You may be getting erros like "libtls.dylib is in use". To delete the files, you need to restart your computer, and then you will be able to delete the files.
Where are aMSN's preferences files stored on a Mac?
They're stored at: Your Home Folder -> Library -> Application Support -> amsn .
Back to top
Other Questions
I noticed aMSN is opening some ports over port 60000. Is it normal? Is it a backdoor? Why does this happen?
This is normal. aMSN uses sockets as a locking system to avoid two aMSN instances use the same profile at once (which could cause trouble). This is the better platform independent locking system we found.
If you check ~/.amsn/profiles, you can see what port is used for each profile.
Back to top
What is the Audio and Video Assistant?
The Audio and Video Assistant is an easy way to configure and fine-tune your webcam as well as your audio input (microphone). The Audio and Video Assistant provides options to maximize the quality of your webcam broadcast.
The Audio and Video Assistant can be started from within a chat window by clicking 'Edit' → 'Edit audio and video settings'.
The Configure Webcam dialog will then be shown. You may change your video settings by clicking “Change video settings” button.
You can also start the assistant using the Ctrl-N shortcut from the main window. Refer to the Shortcuts page for an up to date list of keyboard shortcuts.
Back to top
How do I remove aMSN completely?
After uninstalling aMSN, your profiles (per account settings, log files, etc..) are still stored on your system. You may remove them by following these simple procedures :
rm -rf ~/.amsn
Delete C:\Documents and Settings\$USER\amsn where $USER is your username.
Remove the aMSN application. Remove this folder : Home / Library / Application Support / aMSN
Back to top
The mail traydock icon in the system tray continues to show up, how do I get rid of it?
You must read your unread mails to make the traydock icon disappear.
Back to top
I enabled the logging of conversations on aMSN, but I cannot find the logfiles. Where are they stored?
In order for logging to be enabled, you must first create a profile. This can be done at the aMSN login-screen by enabling the "Remember me" option.
You will then find the log here here:
- Linux: ~/.amsn/your_email_profile/logs
- Windows: %USERPROFILE%\amsn\your_email_profile\logs Where %USERPROFILE% is usually
C:\Documents and Settings\%user%
where %user% is the username of your Windows account.
- Mac OS X: /Home / Library / Application Support / aMSN / your_email_profile / logs
Back to top
Can I disable custom and/or animated smileys?
Choose the Preferences option from the Account menu, then click on the tab that says Appearance. Here you can set the various options regarding Emotions Icons and Smileys.
Back to top
Why doesn't aMSN support audio / Why did aMSN drop linphone support?
- The support of Linphone in aMSN has been dropped some time ago because it was not complete and difficult to maintain. Moreover, the only person able to make it work and to resume its development is no more active in the aMSN's development, so the support has just been dropped.
- Now aMSN supports webcam session (not videconference), this support is complete and stable and easier to maintain.
- About Audio support, it is delayed for a next release. Farsight project, developped by Burgerman will give audio support to aMSN, we are just waiting for a stable version.
Back to top
I have another question, can you help me?
Yes, we can. But before asking questions, search this wiki for your question. If you couldn't find it, then take a look at the aMSN forums found at: http://amsn-project.net/forums
Make sure you SEARCH before posting
Most likely your question has already been answered. You can also view more information at aMSN's sourceforge project page, which is located at: http://sourceforge.net/projects/amsn
Before submitting a bug report or asking for support, please document the following information:
- aMSN version :
- Tcl and Tk version :
- Kernel version :
- Distribution :
- System architecture (32-bit, PPC, 64-bit, etc.) :
- Stack trace of the submitted error (if applicable) :
- Last error messages in debug windows (Ctrl+D and Ctrl+S in contact list) :
- Possible ways to replicate the bug :
Here's an example of a user's documentation :
- aMSN version : 0.96
- Tcl and Tk version : 8.4.16
- Kernel version : Linux 2.6.12-8-386 (Found by typing: uname -s -r in an xterm)
- Distribution : Debian
- System architecture (32-bit, PPC, 64-bit, etc.) : 32-bit
- Stack trace of the submitted error (if applicable) : NA (not applicable)
- Last error messages in debug windows (Ctrl+D and Ctrl+S in contact list) :
- Possible ways to replicate the bug : Open a chat window and send a custom emoticon which is animated to an msn 7.5 user.
Send this information with your bug report so that we may further investigate the issue.
If you still have a question that has not been covered in this FAQ, you can visit the aMSN forum at: http://amsn-project.net/forums or contact us on IRC (Internet Relay Chat) at :
server: irc.freenode.net
channel: #amsn
There is a bot on the channel that is able to give you some indications if you use the following commands :
- amsn install
- amsn version
- amsn download
- amsn tcl/tk version
- amsn libstd
- amsn svn
... and some others
In case you have some trouble to connect to our IRC channel because of network policies, you can try this http://cgiirc.blitzed.org/
Back to top
Enjoy using aMSN!
amsn-0.98.9/FAQ 0000644 0001750 0001750 00000106410 10734014202 012716 0 ustar billiob billiob Frequently Asked Questions
The latest version of this FAQ can be found at http://amsn-project.net/faq.php
FAQ 2.1.0
Contents
1 What is aMSN?
1.1 What is aMSN?
1.2 What do I need to run aMSN?
2 Where can I get aMSN ?
3 Troubleshooting
3.1 Why are arabic fonts displayed from left to right instead of right to left?
3.2 I have enabled the traydock icon, but when I minimize aMSN, it is still shown in both the taskbar and the tray. How can I make it display in the tray only?
3.3 When I close aMSN's window, it quits instead of minimizing to tray
3.4 I don't see the traydock even if I enabled it, what's the problem?
3.5 Does aMSN run on 64-bit systems?
3.6 When notify window pops up, the windows taskbar partially hides it, can I fix this?
3.7 Can I see who blocked me?
3.8 My jpeg webcam does not currently work, will my jpeg webcam work in the future (example: D-link dsb-c310)?
3.9 Why can't I receive acceptable quality images from my contacts using aMSN?
3.10 I can't read Chinese or Japanese with aMSN, even after changing the text encoding. Where can I find help?
3.11 How do I capture bug report information from a segmentation fault? (LINUX)
3.12 I want to report a bug, how do I open the status log and the protocol debugger?
3.13 When I double click "amsn" file from a graphical file browser, like Konqueror or Nautilus, it opens a text editor instead of running aMSN. What shall I do (Linux)?
3.14 Sometimes aMSN "hangs", why is this?
3.15 I try to run amsn but I get this error:
3.16 Can I use aMSN behind a proxy server?
3.17 I'm using aMSN behind a firewall, or using IP-Masquerade. Sending files won't work, can I fix it?
3.18 With version 0.94 I could see when someone opened a conversation window with me, but since version 0.95 this doesn't happen anymore, why?
3.19 I liked the XXXX skin when using the previous version, but it seems to be incompatible with the latest version... when will it be ?
3.20 As soon as I try to log on or change aMSN's language, it crashes with the following message: X Error of failed request: BadValue (integer parameter out of range for operation), Major opcode of failed request: 45 (X_OpenFont)
3.21 I try to run aMSN and it gives this error: Error in startup script: time value too large/small to represent while executing [...] procedure "ConvertLocalToUTC".
4 Using aMSN
4.1 What are the keyboard shortcuts ?
4.2 What does the special icon on the right of the buddies mean?
4.3 Can I copy a contact address to the clipboard?
4.4 Can I copy or open a URL address in a contact's nickname/personal message?
4.5 How can I set my personal message like in MSN7 ?
4.6 How can I access the history of the messages I sent in my chat windows?
4.7 In the preferences' privacy tab, what do those four lists mean?
4.8 In the preferences' privacy tab, what do the different colors in the contacts mean?
4.9 I want to add my own custom smileys, how can I do it?
4.10 Nicknames are now truncated. Is it possible to revert back to full nicknames?
4.11 How can I browse through my webcam logs and convert the .cam (cam recordings) to a movie file such as .mpeg?
4.12 How can I make my webcam work?
4.13 Where are the "stolen" display pictures saved?
4.14 How can I change the directory where the profiles information are saved ?
5 Running on Linux
5.1 How can I use anti-aliased fonts in aMSN?
5.2 How do I create a shortcut to aMSN on my desktop on Linux?
5.3 How do I open file-transfer ports in SUSE Linux?
5.4 My aMSN sound notifications are not being played until I stop playing my music. How can I fix this so I can hear both at the same time?
5.5 When I try running aMSN, I get an error "unknown color Black". How can I fix it ?
5.6 TLS does not seem to work and I have tcl/tk 8.5. How can I fix it ?
5.7 aMSN does not seem to work correctly with some files, especially files containing the character ` (back quote). How to fix it ?
6 Running on Windows
6.1 How can I prevent/make aMSN from loading on windows start ?
6.2 Whenever I go to preferences->session, the 'load amsn at windows start' is disabled, even if it does load at windows start !
7 Running on Mac OS X
7.1 I have a question about Mac OS X, where can I go to find answers?
7.2 Why do some characters in the aMSN contact list appear as squares?
7.3 Why can't I use the shortcut Command-Space to switch keyboard layouts?
7.4 How do I sign into more than one account with Mac aMSN?
7.5 aMSN is incredibly slow on my new Intel Mac, what can I do to speed it up?
7.6 Webcam doesn't work on my Intel Mac!
7.7 How do I update aMSN to the latest development version on a Mac?
7.8 I want to delete aMSN but I cannot empty the Trash!
7.9 Where are aMSN's preferences files stored on a Mac?
8 Other Questions
8.1 I noticed aMSN is opening some ports over port 60000. Is it normal? Is it a backdoor? Why does this happen?
8.2 What is the Audio and Video Assistant?
8.3 How do I remove aMSN completely?
8.4 The mail traydock icon in the system tray continues to show up, how do I get rid of it?
8.5 I enabled the logging of conversations on aMSN, but I cannot find the logfiles. Where are they stored?
8.6 Can I disable custom and/or animated smileys?
8.7 Why doesn't aMSN support audio / Why did aMSN drop linphone support?
8.8 I have another question, can you help me?
=== What is aMSN? ===
== What is aMSN? ==
aMSN is a Microsoft Messenger clone. It allows you to keep in touch with your friends and exchange instant messages and files.
== What do I need to run aMSN? ==
Windows and Mac OS X. aMSN will run right out of the box if you download the official packages, which can be found at http://amsn.sourceforge.net/download.php.
Linux. You will need Tcl 8.4 / Tk 8.4 or above in order to run aMSN. These two packages (Tcl & Tk) are usually installed by default on most distributions. These can also be installed as a dependency if your packaging system supports it (rpm, deb, etc.). If for some reason your distribution does not currently provide you with Tcl 8.4 or Tk 8.4, you may download them and follow the installation instructions at http://tcl.tk.
== Where can I get aMSN ? ==
You can download the packages of aMSN at http://amsn.sourceforge.net/download.php.
For Linux users : You can also get aMSN using your distribution's package management system (apt-get install amsn for debian/ubuntu for example).
=== Troubleshooting ===
== Why are arabic fonts displayed from left to right instead of right to left? ==
Windows: Go to 'Control Panel' ? 'Regional and Language Options' ? Languages tab, and enable the option "Install files for complex scripts and right-to-left languages"
Linux: Installing the Arabic locale should solve this issue.
== I have enabled the traydock icon, but when I minimize aMSN, it is still shown in both the taskbar and the tray. How can I make it display in the tray only? ==
The first time you will close aMSN with the 'X' button in the main window's border. It should ask you if you want to quit or minimize it to tray. You must choose the 'Minimize to Tray' option if you want it to disappear from the taskbar.
Alternatively, you can also click the "Minimize to Tray" option from the Account menu.
== When I close aMSN's window, it quits instead of minimizing to tray ==
The first time you will close aMSN with the 'X' button in the main window's border. It should ask you if you want to quit or minimize it to tray. You must choose the 'Minimize to Tray' option if you want it to minimize to the tray.
If you chose 'Quit' and enabled the "Remember my choice" option, it will always quit and will not ask you again. If you want to change this behavior and want it to ask you again so you can change your choice, you will have to do the following procedure :
Press Ctrl-Shift-C from aMsn's main window, a new window titled "Console" will appear in which you can type commands. Type the following and press enter :
::config::setKey closingdocks 0
You can now close this new Console window and the next time you close aMSN's main window, it will ask you again to make a choice.
== I don't see the traydock even if I enabled it, what's the problem? ==
Linux: Make sure the file msn/utils/linux/traydock/libtray.so exists. If it does not exist, make sure you download an official package of aMSN at: http://amsn-project.net/download.php
If you compiled aMSN yourself, please make sure you have the X11 development packages installed and follow this page to compile aMSN correctly : http://amsn-project.net/wiki/Compiling_aMSN
NOTE: There is no traydock icon on Mac OS X
== Does aMSN run on 64-bit systems? ==
Yes, many users have been able to run aMSN on 64-bit architectures. However, you will have to compile tcltls by yourself. There isn't a package for x84_64 on the aMSN site so you need to download it from: [1]
== When notify window pops up, the windows taskbar partially hides it, can I fix this? ==
Yes, you can move the notify window X pixels to the left and Y pixels to the top. You can customize this by modifying the "X Offset" and "Y Offset" values in (menu) 'Account' ? 'Preferences' ? 'Advanced' ? Offset the position of the notification pop-up. and clicking Save to save your modifications.
== Can I see who blocked me? ==
No, this feature is no longer available because the block detection bug that was happening in the Microsoft servers has now been fixed.
There is NO safe way to know if someone blocked you
== My jpeg webcam does not currently work, will my jpeg webcam work in the future (example: D-link dsb-c310)? ==
JPEG webcams support is currently supported since the 0.97 version of aMSN.
If you are using a version prior to 0.97, please update to the latest version of aMSN.
== Why can't I receive acceptable quality images from my contacts using aMSN? ==
If the image is of a poor quality, it's probably because the other user's webcam is of poor quality. aMSN's quality of the webcam is the same as the official msn client.
== I can't read Chinese or Japanese with aMSN, even after changing the text encoding. Where can I find help? ==
Please read the documentation about getting SCIM to work with aMSN (http://amsn-project.net/wiki/SCIM_Input )
== How do I capture bug report information from a segmentation fault? (LINUX) ==
Make sure amsn was compiled with debugging symbols, if you installed it using a binary package, you should probably download from source and recompile it. To enable debugging symbols, configure it with : ./configure --enable-debug If you're unable to compile it, then you can still send us information without the debugging symbols. Once it is compiled/installed, go to the directory where you have installed aMSN (example: /usr/share/amsn or /home/yourusername/amsn-0.95/) type:
$ gdb --args wish amsn
(gdb) run
[then when it segfaults, type]
(gdb) bt
(gdb) bt full
You will then receive the bug report information. Please report this information to the forums: http://amsn-project.net/forums
MAKE SURE THAT YOU SEARCH THE FORUMS FIRST TO SEE IF IT WAS ALREADY REPORTED
== I want to report a bug, how do I open the status log and the protocol debugger? ==
Open your contact list and press the following key combinations :
status log: ctrl + s (Command-S on Mac OS X) protocol debug: ctrl + d (Command-D on Mac OS X)
== When I double click "amsn" file from a graphical file browser, like Konqueror or Nautilus, it opens a text editor instead of running aMSN. What shall I do (Linux)? ==
aMSN is written in Tcl/Tk, an interpreted language, so the "amsn" file is just a text file with the program code. The file manager might think it's a text file, so it will launch the text editor.
In Konqueror (KDE) or Nautilus (Gnome), running aMSN can be done by right-clicking the amsn file and choosing "Open with..." Konqueror) or "Launch with..." (Gnome), depending on the file browser.
Type "wish". This launches the "amsn" script.
If you are told the the "wish" command doesn't exist, you need to install Tcl/Tk.
== Sometimes aMSN "hangs", why is this? ==
When aMSN hangs it's usually a problem with the sound configuration. Perhaps you're playing a sound but the sound card is blocked, and the play command stops until the sound card is available. Try disabling sound or changing the sound command configuration.
If aMSN still hangs, and you are using a 2.6.x kernel, try running aMSN with:
export LD_ASSUME_KERNEL=2.2.5 && amsn
This command will tell the dynamic linker to use the old thread model. For more information on this issue, see: http://people.redhat.com/drepper/assumekernel.html
If you are on Mac OS X it often happens when you receive a smiley on a chatwindow, it's a known issue.
== I try to run amsn but I get this error: ==
bash: ./amsn: bad interpreter: No such file or directory
You need to install the tcl/tk packages, because you need the wish interpreter. If you think you have it, try typing:
wish /usr/share/amsn/amsn
instead of:
amsn
If this works, edit /usr/share/amsn/amsn and change the first line to :
#!/usr/bin/wish
where /usr/bin/wish would be the location of the wish interpreter. You can find out the location of the 'wish' interpreter by typing :
which wish
== Can I use aMSN behind a proxy server? ==
Yes, we provide support for HTTP and SOCKS5 proxies.
== I'm using aMSN behind a firewall, or using IP-Masquerade. Sending files won't work, can I fix it? ==
In this case, the firewall may be blocking incoming connections. File transfers work this way: When you want to send someone a file, you send an invitation with your IP address and a port number. Then the remote client must connect to your IP:port to start the transfer.
The used port is usually 6891, 6892 and so on (first transfer is on port 6891,but if you start a new file transfer while the first one hasn't finished yet, then it will use 6892, and so on).
If you are using a firewall, you must make sure that it allows incoming connections to port 6891 (and next ones if you want to be able to make more than one transfer at the same time).
If you are behind a router, enable port forwarding for ports 6891 to 6900 to your PC's internal IP address.
You can change the port value from the "Connection" tab of the Preferences window.
== With version 0.94 I could see when someone opened a conversation window with me, but since version 0.95 this doesn't happen anymore, why? ==
Users with MSN7 and later versions of MSN will automatically "open a conversation window" with you as soon as you (or they) connect. It is done automatically because they try to download your display picture. So, as soon as someone connects, the screen was flooded with windows from people just trying to download the display picture. This was annoying, so the feature was removed.
Note also that since Windows Live Messenger 8.0, the user would not join the chat until he sends the first message, so this is a second reason why it is not possible anymore.
== I liked the XXXX skin when using the previous version, but it seems to be incompatible with the latest version... when will it be ? ==
We don't know yet, check on the skin website or email the author of the skin to obtain more information or to ask him to update his skin to work better with the new version.
== As soon as I try to log on or change aMSN's language, it crashes with the following message: X Error of failed request: BadValue (integer parameter out of range for operation), Major opcode of failed request: 45 (X_OpenFont) ==
First of all, it may be a font problem: try making aMSN run with a different font (under Account -> Preferences -> Appearance).
Second, you may need to run aMSN using a different encoding (under Account -> Preferences -> Appearance again, utf-8 is a safe choice).
Third, try clearing your font cache with the command:
fc-cache -fv
Then, make sure your locale (your LC_ALL or LC_CTYPE environment variable) is installed on your system:
set | grep LC_
and make sure the corresponding directories (after the = ) exist on /usr/lib/locale . If they don't, install them according to your distribution.
Finally, if none of the above works, try disabling some FontPath's from /etc/X11/XF86Config or /etc/X11/Xorg.conf until you find out which font path contains problematic fonts, and recreate the fonts.cache , fonts.dir and fonts.scale in that directory.
== I try to run aMSN and it gives this error: Error in startup script: time value too large/small to represent while executing [...] procedure "ConvertLocalToUTC". ==
Make you sure the file /etc/localtime exists. If it doesn't, link it to /usr/share/zoneinfo/YOUR/TIME/ZONE and retry starting aMSN. To create the file under Linux : ln -s /usr/share/zoneinfo/YOUR/TIME/ZONE /etc/localtime
=== Using aMSN ===
== What are the keyboard shortcuts ? ==
For and up to date list of keyboard shortcuts, please read the http://amsn-project.net/wiki/Shortcuts page.
== What does the special icon on the right of the buddies mean? ==
The icon [white X on red round background] in the buddy list means that the corresponding contact do not have you in his list.
== Can I copy a contact address to the clipboard? ==
Yes, right click on that contact name on the contact list, then choose "Properties". In the new window, you can copy the email/nickname/personal message of the user.
== Can I copy or open a URL address in a contact's nickname/personal message? ==
Yes, right click on that contact name on the contact list, then in the pop-up menu, You will have the choice to copy or open any URL in the contact's nickname or personal message.
== How can I set my personal message like in MSN7 ? ==
The Personal Message (PSM) is the text appearing under your nick. This feature is now available since aMSN 0.96.
To set your PSM, you need to click on the "Account" menu then "Change nick ...", there will be a field to change the PSM.
== How can I access the history of the messages I sent in my chat windows? ==
If you want to access previous messages you sent in your chat windows you only need to use the Control key with the arrows. It works the same way as in a shell so Ctrl-Up(Command-Up on MacOSX) gives you the previous message sent and Ctrl-Down(Command-Down on Mac OS X), the next one.
See the http://amsn-project.net/wiki/Shortcuts page for a list of all keyboard shortcuts.
== In the preferences' privacy tab, what do those four lists mean? ==
There are four lists, known as:
Allow List (AL), Block List (BL), Forward or Contact List (FL) and Reverse List (RL).
AL : This list contains the emails of people who are allowed to see you when you get online and they can also chat with you.
BL : This is the block list, which means it contains the list of people you are blocking. So this means they can't see you when you are online, and they can't chat with you.
FL : This list contains all contacts that are shown on your contact list.
RL : This is the reverse list, it contains the email addresses of people who have you in their list.
== In the preferences' privacy tab, what do the different colors in the contacts mean? ==
You should notice the colors in the list headers:
Allow List: green foreground
Block List: red foreground
Forward List: red background
Reverse List: yellow background
A contact in any list will take a different color depending the lists that contact is contained on:
If it's in Allow list, it will have green foreground.
If it's in Block list, it will have red foreground.
If it's in Forward and Reverse lists, it will have white background.
If it's in Forward list, but not in Reverse list, it will have red background.
If it's in Reverse list, but not in Forward list, it will have yellow background.
If it's not in Forward or Reverse list, it will have a black background.
Let's be a bit more specific:
Green font: the contact is able to contact you.
Red font: the contact is NOT able to contact you (BLOCKED).
White background: the contact has you in their contacts list and they are in yours.
Yellow background: the contact has you in their contacts list, but you no longer have them in yours.
Red background: the contact is in your contacts list, but you are not in theirs.
Black background: the contact has deleted you from their contacts list and you have deleted them from yours.
== I want to add my own custom smileys, how can I do it? ==
You may add custom smileys (also known as emoticons) by following these steps :
Open a chat window of any contact
Click the Insert Emoticon button found on the chat window (Screenshot 5.1)
Click the Add new custom smiley button (Screenshot 5.2)
Type a Description for your emoticon in the Description text box (Screenshot 5.3)
Type the Text triggers for your emoticon in the Text triggers text box. Text triggers are triggers which display an icon when they are typed and Enter is pressed. (Screenshot 5.3)
example: (test)
When (test) is typed in the chat window and Enter is pressed, the emoticon associated with the (test) Text trigger will be displayed.
Browse for the new emoticon that you would like to use by clicking the Browse button located to the right of the Smiley filename text box and select the image or emoticon that you would like to use. Click Open. (Screenshot 5.4)
If your image is larger than normal emoticons, you will see a message box saying The smiley you choose is bigger than normal size. Do you want to resize it? If you want your image or emoticon resized so that you can use it as an emoticon, simply click Yes (Screenshot 5.5)
By clicking Yes your image may be scaled down and display incorrectly.
Click the Insert Emoticon button found on the chat window. You will now see your custom emoticon added to the emoticon chooser. (Screenshot 5.6)
== Nicknames are now truncated. Is it possible to revert back to full nicknames? ==
Yes. To have nicknames displayed in their full length on the contact list, in the alerts and the chat window, go to 'Tools' ? 'Preferences' ? 'Advanced Tab', and uncheck the selection which reads, Truncate nicknames longer than window width in window titles and contact list. (Screenshot 5.7)
The same can be done for nicknames inside the chat window conversations by disabling the option Truncate nicknames longer than window width inside conversations.(Screenshot 5.7)
== How can I browse through my webcam logs and convert the .cam (cam recordings) to a movie file such as .mpeg? ==
The file format of those .cam files are a direct dump of the data received on the socket, which means it's in the MS proprietary format. For this reason, no player can play those files, only amsn.
Actually there's a tool to do it released by Hyriand (linux only). See http://amsn-project.net/forums/viewtopic.php?t=2954
== How can I make my webcam work? ==
If your webcam will not work with aMSN, please make sure your webcam is plugged in, turned on, and ready to be used.
Other applications that can be used to test if your webcam is working correctly on Linux:
XawTv
GnomeMeeting
V4L
On Mac you can try the macam project if you do not have an Apple iSight
== Where are the "stolen" display pictures saved? ==
Windows : C:\Documents andSettings\MyWindowsUsername\amsn\youremail_profile\displaypic\cache
Linux : /home/yourusername/.amsn/yourusername@youremail.com/displaypic/cache
Mac OS X: Home / Library / Application Support / your_email_profile / displaypic / cache
You can also access all the previous display pictures of a user from :
The contact's properties page
The "Change Display picture" window
== How can I change the directory where the profiles information are saved ? ==
There is no option to do this, you have to modify the code of aMSN, but it is not complicated. In the aMSN folder, look for a amsn (/usr/share/amsn/amsn) file and open it for editing with your favorite text editor. Search for the following code :
} elseif {$tcl_platform(platform) == "windows"} {
if {[info exists env(USERPROFILE)]} {
set HOME "[file join $env(USERPROFILE) amsn]"
set files_dir "[file join $env(USERPROFILE) amsn_received]"
} else {
set HOME "[file join [pwd] amsn_config]"
set files_dir "[file join [pwd] amsn_received]"
}
change it to
} elseif {$tcl_platform(platform) == "windows"} {
set HOME "[file join [pwd] amsn_config]"
set files_dir "[file join [pwd] amsn_received]"
in order to save the files in the directory where aMSN is launched.
=== Running on Linux ===
== How can I use anti-aliased fonts in aMSN? ==
Use a distro that has tcl/tk 8.5 or higher, or take a look at: http://amsn-project.net/wiki/Enabling_antialiasing
That page will provide you information on how to re-compile Tk with anti-alias support.
== How do I create a shortcut to aMSN on my desktop on Linux? ==
KDE
Right-click on the K-menu and a Panel Menu will appear as seen in the screenshot below:
Click Add Non-KDE Application
A Non-KDE Application Configuration dialog box will be displayed
Enter the text as shown below:
Click OK and an aMSN icon will be added to your kicker menu :
If you want to change the icon or other configurations, simply right-click the new aMSN button, and a menu will be displayed. Click Configure aMSN Button... and the Non-KDE Application Configuration will be displayed.
== How do I open file-transfer ports in SUSE Linux?==
(Guide thanks to John Hillier)
Open 'YaST' -> 'Security and Users' -> 'Firewall' -> 'Firewall Configuration'.
Click on "Expert" in 'Additional Services' and add port 6891.
My aMSN sound notifications are not being played until I stop playing my music. How can I fix this so I can hear both at the same time?
KDE: You can configure XMMS, amaroK, etc. to play sound through arts, and use artsplay as sound play command for aMSN which is able to mix sounds.
Gnome: You can use esdplay and configure XMMS for playing through ESD.
== When I try running aMSN, I get an error "unknown color Black". How can I fix it ?==
This problem is not coming from aMSN, it's an Xorg faulty installation. You probably have a bad Xorg configuration for the file rgb.txt (especially with some versions of Xgl).
If you are using xgl, you most probably have the file rgb.txt in /etc/X11 . Xgl in Ubuntu Dapper is usually misconfigured and looks for the file in /usr/share/X11 . Make a symlink to it in /usr/share/X11 and restart your X server.
If you are not using xgl, open your /etc/X11/xorg.conf and look for a line that says:
Section "Files"
RgbPath "/etc/X11/rgb"
If the RgbPath line does not exist at all, add it under the section "Files". Then make sure the file exists in the directory defined in RgbPath (/etc/X11/ in this case). You may need to copy it from another location in your computer, or you can download it from http://amsn.sourceforge.net/rgb.txt . You must also restart your X server for the changes to take effect. PLEASE NOTE: the line in xorg.conf must NOT contain the extension of the file!!!
TLS does not seem to work and I have tcl/tk 8.5. How can I fix it ?
TLS 1.5 is broken, in order to fix it, you have to find out where your copy of TLS is with :
locate tls.tcl
or if you do not use locate :
find / -name tls.tcl
Those commands should give you something like /usr/lib/tls1.50/tls.tcl. In the same directory, you should find a file named pkgIndex.tcl. Edit this file with your favorite editor (vi, emacs, nano/pico, etc..) :
vi /usr/lib/tls1.50/pkgIndex.tcl
and change the line :
package ifneeded tls 1.5
by
package ifneeded tls 1.50
TLS should now work well. If it not the case, please let us know on the forums
== aMSN does not seem to work correctly with some files, especially files containing the character ` (back quote). How to fix it ? ==
aMSN cannot handle files containing the character `(back quote) in their path. A way to resolve this issue is to mount the partition containing the file with this caracter with the 'utf8' option. Refer to the man page of your version of mount to find the right option for your file system.
=== Running on Windows ===
== How can I prevent/make aMSN from loading on windows start ? ==
You can do that by clicking on the checkbox 'load aMSN at Windows start' in Account -> Preferences -> Session
== Whenever I go to preferences->session, the 'load amsn at windows start' is disabled, even if it does load at windows start ! ==
We cannot detect if aMSN loads at Windows start so the checkbox is disabled. However, the change is taken in consideration if you modified the value and then press the "Save"' button.
=== Running on Mac OS X ===
== I have a question about Mac OS X, where can I go to find answers? ==
You can get answers to questions about Mac OS X on the aMSN Mac Forum found at: http://forums.cocoaforge.com/viewforum.php?f=14
== Why do some characters in the aMSN contact list appear as squares? ==
These are Unicode characters. Unicode support has been added for Mac OS X since version 0.96 of aMSN.
== Why can't I use the shortcut Command-Space to switch keyboard layouts? ==
This seems to be an issue with the Tcl/Tk frameworks that aMSN depends on. It is currently being looked into.
== How do I sign into more than one account with Mac aMSN? ==
You need to duplicate the aMSN application, and then run both copies. The easiest way to do this, is to find the application in Finder, and press Command-D to duplicate the application.
== aMSN is incredibly slow on my new Intel Mac, what can I do to speed it up? ==
aMSN 0.96 is the first Universal binary version of aMSN, please update to at least that version. You can further speed up aMSN by turning off smileys in the contact list (the option is in aMSN's preferences under the Appearence tab), and also by colapsing your offline group.
== Webcam doesn't work on my Intel Mac! ==
Update to the latest aMSN version (0.97 or higher), and you will then be able to use webcam!
== How do I update aMSN to the latest development version on a Mac? ==
Up to date instructions on how to do this can be found at the http://amsn-project.net/wiki/SVN wiki page.
== I want to delete aMSN but I cannot empty the Trash! ==
You may be getting erros like "libtls.dylib is in use". To delete the files, you need to restart your computer, and then you will be able to delete the files.
== Where are aMSN's preferences files stored on a Mac? ==
They're stored at: Your Home Folder -> Library -> Application Support -> amsn .
=== Other Questions ===
== I noticed aMSN is opening some ports over port 60000. Is it normal? Is it a backdoor? Why does this happen? ==
This is normal. aMSN uses sockets as a locking system to avoid two aMSN instances use the same profile at once (which could cause trouble). This is the better platform independent locking system we found.
If you check ~/.amsn/profiles, you can see what port is used for each profile.
== What is the Audio and Video Assistant? ==
The Audio and Video Assistant is an easy way to configure and fine-tune your webcam as well as your audio input (microphone). The Audio and Video Assistant provides options to maximize the quality of your webcam broadcast.
The Audio and Video Assistant can be started from within a chat window by clicking 'Edit' ? 'Edit audio and video settings'. The Configure Webcam dialog will then be shown. You may change your video settings by clicking Change video settings button.
You can also start the assistant using the Ctrl-N shortcut from the main window. Refer to the http://amsn-project.net/wiki/Shortcuts page for an up to date list of keyboard shortcuts.
== How do I remove aMSN completely? ==
After uninstalling aMSN, your profiles (per account settings, log files, etc..) are still stored on your system. You may remove them by following these simple procedures :
Linux:
rm -rf ~/.amsn
Windows:
Delete C:\Documents and Settings\$USER\amsn where $USER is your username.
Mac OS X
Remove the aMSN application. Remove this folder : Home / Library / Application Support / aMSN
== The mail traydock icon in the system tray continues to show up, how do I get rid of it? ==
You must read your unread mails to make the traydock icon disappear.
== I enabled the logging of conversations on aMSN, but I cannot find the logfiles. Where are they stored? ==
In order for logging to be enabled, you must first create a profile. This can be done at the aMSN login-screen by enabling the "Remember me" option.
You will then find the log here here:
Linux: ~/.amsn/your_email_profile/logs
Windows: %USERPROFILE%\amsn\your_email_profile\logs Where %USERPROFILE% is usually
C:\Documents and Settings\%user% where %user% is the username of your Windows account.
Mac OS X: /Home / Library / Application Support / aMSN / your_email_profile / logs
== Can I disable custom and/or animated smileys? ==
Choose the Preferences option from the Account menu, then click on the tab that says Appearance. Here you can set the various options regarding Emotions Icons and Smileys.
Why doesn't aMSN support audio / Why did aMSN drop linphone support?
The support of Linphone in aMSN has been dropped some time ago because it was not complete and difficult to maintain. Moreover, the only person able to make it work and to resume its development is no more active in the aMSN's development, so the support has just been dropped.
Now aMSN supports webcam session (not videconference), this support is complete and stable and easier to maintain.
About Audio support, it is delayed for a next release. Farsight project, developped by Burgerman will give audio support to aMSN, we are just waiting for a stable version.
== I have another question, can you help me? ==
Yes, we can. But before asking questions, search this wiki for your question. If you couldn't find it, then take a look at the aMSN forums found at: http://amsn-project.net/forums
Make sure you SEARCH before posting
Most likely your question has already been answered. You can also view more information at aMSN's sourceforge project page, which is located at: http://sourceforge.net/projects/amsn
Before submitting a bug report or asking for support, please document the following information:
aMSN version :
Tcl and Tk version :
Kernel version :
Distribution :
System architecture (32-bit, PPC, 64-bit, etc.) :
Stack trace of the submitted error (if applicable) :
Last error messages in debug windows (Ctrl+D and Ctrl+S in contact list) :
Possible ways to replicate the bug :
Here's an example of a user's documentation :
aMSN version : 0.96
Tcl and Tk version : 8.4.16
Kernel version : Linux 2.6.12-8-386 (Found by typing: uname -s -r in an xterm)
Distribution : Debian
System architecture (32-bit, PPC, 64-bit, etc.) : 32-bit
Stack trace of the submitted error (if applicable) : NA (not applicable)
Last error messages in debug windows (Ctrl+D and Ctrl+S in contact list) :
Possible ways to replicate the bug : Open a chat window and send a custom emoticon which is animated to an msn 7.5 user.
Send this information with your bug report so that we may further investigate the issue.
If you still have a question that has not been covered in this FAQ, you can visit the aMSN forum at: http://amsn-project.net/forums or contact us on IRC (Internet Relay Chat) at :
server: irc.freenode.net channel: #amsn
There is a bot on the channel that is able to give you some indications if you use the following commands :
amsn install
amsn version
amsn download
amsn tcl/tk version
amsn libstd
amsn svn
... and some others
In case you have some trouble to connect to our IRC channel because of network policies, you can try this http://cgiirc.blitzed.org/
Enjoy using aMSN! amsn-0.98.9/TODO 0000644 0001750 0001750 00000013523 11757234003 013067 0 ustar billiob billiob AMSN TO-DO List
============
Check our Wiki page TO-DO list:
http://amsn.sourceforge.net/wiki
DONE We must finish MSNP2P (Sending files through MSNP2P and do transfer
dialogs)
DONE We must send to waste all MSNP7 code
- We should do a GUI cleanup (alarms...)
DONE We must do proxy's work...
DONE It doesn't update with the new people that enters the chat... it doesn't give you a chance to talk to certain people...
DONE In logging/preferences, look at disabled items (add features or remove this items from GUI)
BugList / TODO list
Hey maybe we should restart using this thing...? (23/11/03)
>Ok here is a new version of the TODO list (04/01/03)
>>It's big, it's bad! It's the all mighty bug/todo list!
>>Here are the stuff we wanna implement and bugs we want to fix...
>>Feel free to tell us about any options that aren't here that would interest you...
>>Feel free to inform us of any bugs that aren't here (we just ordered 4 boxes of ZAP!)
Contact amsn-devel@lists.sourceforge.net
*********************************************************
***Bug Fixes and TODO before next release (priority 1)***
*********************************************************
- Have a correct msnp2pv2 implementation.
- Make sure everything is installed correctly and FAQ and HELP are in the amsn directory.
- Make good RPMs, for Redhat, Suse, Mandrake, etc.
DONE Improve font selection (unify with color selection)
- When selecting a new color for the font in a chat, don't change only
the color of the text send but the color of the text being written too (for all window).
- When queue is cleared, NAK every message in queue
- Check for connection state, make sure amsn disconnects if connection goes down. -> add timeouts to changestates and keepalive
- When we get a NAK from a message, try to enqueue it again, as probably it will success.
DONE Fix focus and children things with list window. (For example add_user from chat window), and dialogs in general.
DONE Check functionality of all proxies with new MSNP9 protocol (socks, not keep-alive http proxies)
DONE Get rid of all MSNP7 code.. it sure is useless now
DONE We sometimes get double pasting, just bind our paste procedure to the <
> event, instead of to
************************************************
***Existing Feature Improvements (priority 2)***
************************************************
** General issues **
DONE Option to display or not the chat button bar
- Add option to modify keepalive interval (in seconds)
DONE Make a Pure PNG Reader (will be used for buddy icons + filetransfer previews, and maybe other stuff)
DONE In the Privacy tab, if 2 users have exactly the same nickname in a listbox, we can control only the first user
(we can't delete the second user with that nick from the list ...)
- Improve truncation to check picture widths, instead of using fixed values
DONE Load AMSN faster (load pictures on demand -> GetImage wrapper? Maybe use GetSkinFile?)
DONE Get rid of global variables list_al, list_bl, make use of ::abook:: namespace (avatars, custom nicknames, etc)
- Clean ugly GUI code (long window names xx.xx.xxx.xx, use -Class instead of repeated options all the time)
** Remote Control issues **
- If text sent over socket contains the color word, it disappears from the text (change the string map call)
- make it possible to send more than one space between each words in messages
** Dock Issues **
- New message alert
** File Transfer issues **
- File Transfer AUTH protocol fix
- Display link to received file and click to open
- Send files through server with MSNP2P if behind NAT
** Alarm system improvements and bugs **
DONE JPG Support (use same as for MSN6 Pictures)
** Logging system improvements and bugs **
- Use XML instead of custom syntax to speed up things
- Add date limit or file size limit for log files
- Add option for partial logging of only certain users
- Save to LOG (if logging disabled, allows to log certain conversations only)
- Compress log files with optimal algorithm for text files
- Logging syntax options (timestamps, email or nics, etc)
DONE Display by day/month/year
- Display last X lines of the log in the window when opening a chat window with someone
** WindowsXP issues **
DONE Problem with URLs
DONE Problem with sound
- Selections don't appear
- Ugly program icons (WISH icon, not ours)
DONE Fonts dialog all messed up
DONE Alarms options (paths) aren't saved correctly if they contain spaces
- ImageMagick is never detected since there is a convert.exe program in the System32 DIR and exec looks for that one first
- Browser problems in windows when URL contains weird characters
** MSNP2P Stuff **
- Do checksum checking, understand error message, send error messages, etc...
*********************************
***Extra Features (priority 3)***
*********************************
- Have status always on top of contact list
DONE Finish the plugins system
- Menu accelerators
- Be able to change their font in chat (same as you, or different)
DONE Autoconnect (when connection detected)
- Notebook like chat windows (as an option)
- Resume File Transfers
- Socks5 Proxy Support with UserName/Password
- Better management of special characters and \n in nicks
- Make video/audio conferencing work with GbnomeMeeting, check for embedding possibilities
****************************************
***Eye Candy and Gadgets (priority 4)***
****************************************
- Background image
- Make games work (should be rather simple, some special parameters passed to the browser I'm guessing)
- Make notify window size configurable
- Transparent background message windows (is it possible now with 8.4?)
- AutoUpgrade AMSN
- Direct connection between amsn clients, without sb, real time chat
- Balloons in privacy lists (show email)
- GUI for translations, automatic updates from amsn GUI (no website)
- Have support for multiple sessions (tabs for each session)
amsn-0.98.9/maemo.diff 0000644 0001750 0001750 00000002606 11275402630 014325 0 ustar billiob billiob Index: debian/control.in
===================================================================
--- debian/control.in (revision 10906)
+++ debian/control.in (working copy)
@@ -1,5 +1,5 @@
Source: amsn
-Section: x11
+Section: user/x11
Priority: optional
Maintainer: Theodore Karkoulis
Build-Depends: debhelper (>> 4.0.0), tcl#TCL_VERSION#-dev, tk#TK_VERSION#-dev, libpng12-dev, libjpeg62-dev
Index: configure.ac
===================================================================
--- configure.ac (revision 10906)
+++ configure.ac (working copy)
@@ -357,7 +357,7 @@
dnl do some OS specific stuff here
dnl Check for libstdc++
-AC_CHECK_LIB(stdc++,main,CXX_LIB="-lstdc++", AC_MSG_ERROR(stdc++ library not found) )
+#AC_CHECK_LIB(stdc++,main,CXX_LIB="-lstdc++", AC_MSG_ERROR(stdc++ library not found) )
AC_SUBST(CXX_LIB)
AC_SUBST(LDLIBS)
Index: amsn
===================================================================
--- amsn (revision 10906)
+++ amsn (working copy)
@@ -1,6 +1,5 @@
-#!/bin/sh
-# \
-exec wish $0 $@
+#!/usr/bin/wish
+#
###
###
Index: utils/linux/capture/capture.c
===================================================================
--- utils/linux/capture/capture.c (revision 10906)
+++ utils/linux/capture/capture.c (working copy)
@@ -1032,6 +1032,8 @@
ng_debug = 0;
# endif
ng_init();
+
+ yuv2rgb_init();
// End of Initialisation
return TCL_OK;
amsn-0.98.9/socks.tcl 0000644 0001750 0001750 00000020224 11101035551 014207 0 ustar billiob billiob ##############################################################################
# Socks5 Client Library v1.1
# (C)2000 Kerem 'Waster_' HADIMLI
#
# How to use:
# 1) Create your socket connected to the Socks server.
# 2) Call socks:init procedure with these 6 parameters:
# 1- Socket ID : The socket identifier that's connected to the socks5 server.
# 2- Server hostname : The main (not socks) server you want to connect
# 3- Server port : The port you want to connect on the main server
# 4- Authentication : If you want username/password authentication enabled, set this to 1, otherwise 0.
# 5- Username : Username to use on Socks Server if authentication is enabled. NULL if authentication is not enabled.
# 6- Password : Password to use on Socks Server if authentication is enabled. NULL if authentication is not enabled.
# 3) It'll return you a string starting with:
# a- "OK" if successful, now you can send/receive any data from the socket.
# b- "ERROR:$explanation" if unsuccessful, $explanation is the explanation like "Host not found". The socket will be automatically closed on an error.
#
#
# Notes:
# - This library enters tkwait ::Socks5::loop (see Tk man pages), and returns only
# when SOCKS initialization is complete.
# - This library uses a global array: socks_idlist. Make sure your program
# doesn't use that.
# - NEVER use file IDs instead of socket IDs!
# - NEVER bind the socket (fileevent) before calling socks:init procedure.
##############################################################################
#
# Author contact information:
# E-mail : waster@iname.com
# ICQ# : 27216346
# Jabber : waster@jabber.org (New IM System - http://www.jabber.org)
#
##############################################################################
# $Id: socks.tcl 10641 2008-10-26 09:42:01Z tomhennigan $
#set socks_idlist(stat,$sck) ...
#set socks_idlist(data,$sck) ...
namespace eval ::Socks5 {
proc Init {sck addr port auth user pass} {
variable socks_idlist
# if { [catch {fconfigure $sck}] != 0 } {return "ERROR:Connection closed with Socks Server!"} ;# Socket doesn't exist
set ver "\x05" ;#Socks version
status_log "SOCKS : $sck $addr\n"
set addr [split $addr " "] ;# Remove port from address
set addr [lindex $addr 0]
status_log "SOCKS : $addr\n"
if {$auth==0} {
set method "\x00"
set nmethods "\x01"
} elseif {$auth==1} {
set method "\x00\x02"
set nmethods "\x02"
} else {
status_log "ERROR: $auth"
return "ERROR:"
}
set nomatchingmethod "\xFF" ;#No matching methods
set cmd_connect "\x01" ;#Connect command
set rsv "\x00" ;#Reserved
set atyp "\x03" ;#Address Type (domain)
set dlen "[binary format c [string length $addr]]" ;#Domain length (binary 1 byte)
set port [binary format S $port] ;#Network byte-ordered port (2 binary-bytes)
set authver "\x01" ;#User/Pass auth. version
set ulen "[binary format c [string length $user]]" ;#Username length (binary 1 byte)
set plen "[binary format c [string length $pass]]" ;#Password length (binary 1 byte)
set a ""
set socks_idlist(stat,$sck) 0
set socks_idlist(data,$sck) ""
status_log "doing fconfigure now in socks5\n"
fconfigure $sck -translation {binary binary} -blocking 0
status_log "writing to socket in socks5 writing : $ver$nmethods$method\n"
puts -nonewline $sck "$ver$nmethods$method"
if { [catch { flush $sck }] } {
catch {close $sck}
status_log "ERROR:Couldn't flush Socks Server after writing!"
return "ERROR:Couldn't flush Socks Server after writing!"
}
status_log "doing fileevent now in socks5\n"
fileevent $sck readable "::Socks5::Readable $sck"
status_log "going into tkwait\n"
tkwait variable ::Socks5::socks_idlist(stat,$sck)
set a $socks_idlist(data,$sck)
if {[eof $sck]} {
catch {close $sck}
status_log "ERROR:Connection closed with Socks Server!"
return "ERROR:Connection closed with Socks Server!"
}
set serv_ver ""
set method $nomatchingmethod
binary scan $a "cc" serv_ver smethod
if {$serv_ver!=5} {
catch {close $sck}
status_log "ERROR:Socks Server isn't version 5!"
return "ERROR:Socks Server isn't version 5!"
}
if {$smethod==0} {
} elseif {$smethod==2} { ;#User/Pass authorization required
if {$auth==0} {
catch {close $sck}
status_log "ERROR:Method not supported by Socks Server!"
return "ERROR:Method not supported by Socks Server!"
}
puts -nonewline $sck "$authver$ulen$user$plen$pass"
flush $sck
tkwait variable ::Socks5::socks_idlist(stat,$sck)
set a $socks_idlist(data,$sck)
if {[eof $sck]} {
catch {close $sck}
status_log "ERROR:Connection closed with Socks Server!"
return "ERROR:Connection closed with Socks Server!"
}
set auth_ver ""
set status "\x00"
binary scan $a "cc" auth_ver status
if {$auth_ver!=1} {
catch {close $sck}
status_log "ERROR:Socks Server's authentication isn't supported!"
return "ERROR:Socks Server's authentication isn't supported!"
}
if {$status!=0} {
catch {close $sck}
status_log "ERROR:Wrong username or password!"
return "ERROR:Wrong username or password!"
}
} else {
fileevent $sck readable {}
unset socks_idlist(stat,$sck)
unset socks_idlist(data,$sck)
catch {close $sck}
status_log "ERROR:Method not supported by Socks Server!"
return "ERROR:Method not supported by Socks Server!"
}
#
# We send request4connect
#
status_log "second write\n"
puts -nonewline $sck "$ver$cmd_connect$rsv$atyp$dlen$addr$port"
flush $sck
tkwait variable ::Socks5::socks_idlist(stat,$sck)
set a $socks_idlist(data,$sck)
if {[eof $sck]} {
catch {close $sck}
status_log "ERROR:Connection closed with Socks Server!"
return "ERROR:Connection closed with Socks Server!"
}
fileevent $sck readable {}
unset socks_idlist(stat,$sck)
unset socks_idlist(data,$sck)
set serv_ver ""
set rep ""
binary scan $a cc serv_ver rep
if {$serv_ver!=5} {
catch {close $sck}
status_log "ERROR:Socks Server isn't version 5!"
return "ERROR:Socks Server isn't version 5!"
}
if {$rep==0} {
fconfigure $sck -translation {auto auto}
status_log "SOCKS: OK"
return "OK"
} elseif {$rep==1} {
catch {close $sck}
status_log "ERROR:Socks server responded:\nGeneral SOCKS server failure"
return "ERROR:Socks server responded:\nGeneral SOCKS server failure"
} elseif {$rep==2} {
catch {close $sck}
status_log "ERROR:Socks server responded:\nConnection not allowed by ruleset"
return "ERROR:Socks server responded:\nConnection not allowed by ruleset"
} elseif {$rep==3} {
catch {close $sck}
status_log "ERROR:Socks server responded:\nNetwork unreachable"
return "ERROR:Socks server responded:\nNetwork unreachable"
} elseif {$rep==4} {
catch {close $sck}
status_log "ERROR:Socks server responded:\nHost unreachable"
return "ERROR:Socks server responded:\nHost unreachable"
} elseif {$rep==5} {
catch {close $sck}
status_log "ERROR:Socks server responded:\nConnection refused"
return "ERROR:Socks server responded:\nConnection refused"
} elseif {$rep==6} {
catch {close $sck}
status_log "ERROR:Socks server responded:\nTTL expired"
return "ERROR:Socks server responded:\nTTL expired"
} elseif {$rep==7} {
catch {close $sck}
status_log "ERROR:Socks server responded:\nCommand not supported"
return "ERROR:Socks server responded:\nCommand not supported"
} elseif {$rep==8} {
catch {close $sck}
status_log "ERROR:Socks server responded:\nAddress type not supported"
return "ERROR:Socks server responded:\nAddress type not supported"
} else {
catch {close $sck}
status_log "ERROR:Socks server responded:\nUnknown Error"
return "ERROR:Socks server responded:\nUnknown Error"
}
status_log "finished sock5 init"
}
#
# Change the variable value, so 'tkwait' loop will end in socks:init procedure.
#
proc Readable {sck} {
variable socks_idlist
if { [catch {set socks_idlist(data,$sck) [read $sck]} res] } {
status_log "Error when reading from sock server : $res"
}
incr socks_idlist(stat,$sck)
}
}
amsn-0.98.9/ca-certs/ 0000755 0001750 0001750 00000000000 11757711634 014106 5 ustar billiob billiob amsn-0.98.9/ca-certs/VeriSign_International_Server_Class_3_CA.pem 0000644 0001750 0001750 00000002375 11346125707 024467 0 ustar billiob billiob -----BEGIN CERTIFICATE-----
MIIDgzCCAuygAwIBAgIQRvzrurTQLw+SYJgjP5MHjzANBgkqhkiG9w0BAQUFADBf
MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsT
LkNsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw
HhcNOTcwNDE3MDAwMDAwWhcNMTYxMDI0MjM1OTU5WjCBujEfMB0GA1UEChMWVmVy
aVNpZ24gVHJ1c3QgTmV0d29yazEXMBUGA1UECxMOVmVyaVNpZ24sIEluYy4xMzAx
BgNVBAsTKlZlcmlTaWduIEludGVybmF0aW9uYWwgU2VydmVyIENBIC0gQ2xhc3Mg
MzFJMEcGA1UECxNAd3d3LnZlcmlzaWduLmNvbS9DUFMgSW5jb3JwLmJ5IFJlZi4g
TElBQklMSVRZIExURC4oYyk5NyBWZXJpU2lnbjCBnzANBgkqhkiG9w0BAQEFAAOB
jQAwgYkCgYEA2IKA6NYZAn0fhRg5JaJlK+G/1AXTvOY2O6rwTGxbtueqPHNFVbLx
veqXQu2aNAoV1Klc9UAl3dkHwTKydWzEyruj/lYncUOqY/UwPpMo5frxCTvzt01O
OfdcSVq4wR3Tsor+cDCVQsv+K1GLWjw6+SJPkLICp1OcTzTnqwSye28CAwEAAaOB
4zCB4DAPBgNVHRMECDAGAQH/AgEAMEQGA1UdIAQ9MDswOQYLYIZIAYb4RQEHAQEw
KjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL0NQUzA0BgNV
HSUELTArBggrBgEFBQcDAQYIKwYBBQUHAwIGCWCGSAGG+EIEAQYKYIZIAYb4RQEI
ATALBgNVHQ8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgEGMDEGA1UdHwQqMCgwJqAk
oCKGIGh0dHA6Ly9jcmwudmVyaXNpZ24uY29tL3BjYTMuY3JsMA0GCSqGSIb3DQEB
BQUAA4GBAECOSZeWinPdjk3vPmG3yqBirfQOCrt1PeJu2CzHv/S5jDabyqLQnHJG
OfamggNlEcS8vy2m9dk7CrWY+rN4uR7yK0xi1f2yeh3fM/1z+aXYLYwq6tH8sCi2
6UlIE0uDihtIeyT3ON5vQVS4q1drBt/HotSp9vE2YoCI8ot11oBx
-----END CERTIFICATE-----
amsn-0.98.9/ca-certs/README 0000644 0001750 0001750 00000000305 11346410561 014751 0 ustar billiob billiob after adding a certfile here, you need to run the command:
$ c_rehash .
This will create the correct symlink.
If you want to see more info from a cert, just run:
openssl x509 -in {certfile} -text
amsn-0.98.9/ca-certs/75ced341.0 0000777 0001750 0001750 00000000000 11757711634 023713 2Microsoft_Internet_Authority.pem ustar billiob billiob amsn-0.98.9/ca-certs/6e7f22c1.0 0000777 0001750 0001750 00000000000 11757711634 025321 2VeriSign_Class3_Extended_Validation_CA.pem ustar billiob billiob amsn-0.98.9/ca-certs/37621ded.0 0000777 0001750 0001750 00000000000 11757711634 025703 2VeriSign_International_Server_Class_3_CA.pem ustar billiob billiob amsn-0.98.9/ca-certs/VeriSign_Class3_Extended_Validation_CA.pem 0000644 0001750 0001750 00000004130 11346125707 024074 0 ustar billiob billiob -----BEGIN CERTIFICATE-----
MIIF5DCCBMygAwIBAgIQW3dZxheE4V7HJ8AylSkoazANBgkqhkiG9w0BAQUFADCB
yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMTYxMTA3MjM1OTU5WjCBujEL
MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2UgYXQg
aHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL3JwYSAoYykwNjE0MDIGA1UEAxMrVmVy
aVNpZ24gQ2xhc3MgMyBFeHRlbmRlZCBWYWxpZGF0aW9uIFNTTCBDQTCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAJjboFXrnP0XeeOabhQdsVuYI4cWbod2
nLU4O7WgerQHYwkZ5iqISKnnnbYwWgiXDOyq5BZpcmIjmvt6VCiYxQwtt9citsj5
OBfH3doxRpqUFI6e7nigtyLUSVSXTeV0W5K87Gws3+fBthsaVWtmCAN/Ra+aM/EQ
wGyZSpIkMQht3QI+YXZ4eLbtfjeubPOJ4bfh3BXMt1afgKCxBX9ONxX/ty8ejwY4
P1C3aSijtWZfNhpSSENmUt+ikk/TGGC+4+peGXEFv54cbGhyJW+ze3PJbb0S/5tB
Ml706H7FC6NMZNFOvCYIZfsZl1h44TO/7Wg+sSdFb8Di7Jdp91zT91ECAwEAAaOC
AdIwggHOMB0GA1UdDgQWBBT8ilC6nrklWntVhU+VAGOP6VhrQzASBgNVHRMBAf8E
CDAGAQH/AgEAMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRw
czovL3d3dy52ZXJpc2lnbi5jb20vY3BzMD0GA1UdHwQ2MDQwMqAwoC6GLGh0dHA6
Ly9FVlNlY3VyZS1jcmwudmVyaXNpZ24uY29tL3BjYTMtZzUuY3JsMA4GA1UdDwEB
/wQEAwIBBjARBglghkgBhvhCAQEEBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZ
MFcwVRYJaW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7
GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwKQYDVR0R
BCIwIKQeMBwxGjAYBgNVBAMTEUNsYXNzM0NBMjA0OC0xLTQ3MD0GCCsGAQUFBwEB
BDEwLzAtBggrBgEFBQcwAYYhaHR0cDovL0VWU2VjdXJlLW9jc3AudmVyaXNpZ24u
Y29tMB8GA1UdIwQYMBaAFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqGSIb3DQEB
BQUAA4IBAQCWovp/5j3t1CvOtxU/wHIDX4u6FpAl98KD2Md1NGNoElMMU4l7yVYJ
p8M2RE4O0GJis4b66KGbNGeNUyIXPv2s7mcuQ+JdfzOE8qJwwG6Cl8A0/SXGI3/t
5rDFV0OEst4t8dD2SB8UcVeyrDHhlyQjyRNddOVG7wl8nuGZMQoIeRuPcZ8XZsg4
z+6Ml7YGuXNG5NOUweVgtSV1LdlpMezNlsOjdv3odESsErlNv1HoudRETifLriDR
fip8tmNHnna6l9AW5wtsbfdDbzMLKTB3+p359U64drPNGLT5IO892+bKrZvQTtKH
qQ2mRHNQ3XBb7a1+Srwi1agm5MKFIA3Z
-----END CERTIFICATE-----
amsn-0.98.9/ca-certs/Microsoft_Secure_Server_Authority.pem 0000644 0001750 0001750 00000004232 11346121634 023450 0 ustar billiob billiob -----BEGIN CERTIFICATE-----
MIIGEzCCA/ugAwIBAgIKYRZtLwAEAAAAIDANBgkqhkiG9w0BAQUFADAnMSUwIwYD
VQQDExxNaWNyb3NvZnQgSW50ZXJuZXQgQXV0aG9yaXR5MB4XDTA4MDQwOTIxMzc1
NFoXDTExMDIxOTE4MjQ1M1owgYsxEzARBgoJkiaJk/IsZAEZFgNjb20xGTAXBgoJ
kiaJk/IsZAEZFgltaWNyb3NvZnQxFDASBgoJkiaJk/IsZAEZFgRjb3JwMRcwFQYK
CZImiZPyLGQBGRYHcmVkbW9uZDEqMCgGA1UEAxMhTWljcm9zb2Z0IFNlY3VyZSBT
ZXJ2ZXIgQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
kYTz6fKXvrdfIr5o3Ue4CRIzhTE+8JE4hrLTQki3emjYn/CfHRPb7hmMiOZmWBdE
DUEymyXOyZ7Sy2tC6WaBC4onVYotPoSsaOZJv6EJeHPk64RiWTfX+XqufRndYOEC
DUmotYQNPV/8InioIBf9+gOSsAMdmyGZF6C1PkJqvPZTRxNv6hxuMMb6uOQIPoFX
/ceQvAOZcJx2qGsAVKsJHylYkC0GgVyFVhOI0vcZZBcP5T+NtOmyjVBWdxS413HL
D+8w+3wG0bOP8EyOeRnuf0KLXGBangte0ZFIRd28GXpo5UrcA/r5000e2RTHmhC4
8YPMIoi+q9XZoF5R0Z069QIDAQABo4IB2jCCAdYwEgYDVR0TAQH/BAgwBgEB/wIB
ADAdBgNVHQ4EFgQUFFXEOeA9LtFVLkiWsNh+FCIGk7wwCwYDVR0PBAQDAgGGMBIG
CSsGAQQBgjcVAQQFAgMFAAUwIwYJKwYBBAGCNxUCBBYEFM7FoL4P/nlmdZEP8PeS
WzWYqBWzMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMB8GA1UdIwQYMBaAFMbb
u8DYIBmS8WD8iPFYf7wbTo8aMIGjBgNVHR8EgZswgZgwgZWggZKggY+GNmh0dHA6
Ly9tc2NybC5taWNyb3NvZnQuY29tL3BraS9tc2NvcnAvY3JsL21zd3d3KDQpLmNy
bIY0aHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9tc2NvcnAvY3JsL21zd3d3
KDQpLmNybIYfaHR0cDovL2NvcnBwa2kvY3JsL21zd3d3KDQpLmNybDB5BggrBgEF
BQcBAQRtMGswPAYIKwYBBQUHMAKGMGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9w
a2kvbXNjb3JwL21zd3d3KDQpLmNydDArBggrBgEFBQcwAoYfaHR0cDovL2NvcnBw
a2kvYWlhL21zd3d3KDQpLmNydDANBgkqhkiG9w0BAQUFAAOCAgEAempuzk/VLM4N
H9TAbFtCjKc95iGmyx2bHbEk9m2cbGxXjBre+N4cJoIYYmhLrZ6L712ov1NjM73b
m8fb2Fy8Yw8Cmwc8VtarPZT2yzGr8MhNUDVuZswaKfjCY3H7RYv/XKc7AOMd25WP
/M0WTT4Bna6hl9dUaDGwv5SZFFIJ17FLo4FR2H7IkOOI/WcUPAHeDXUewp4qRPE/
560xZrLSeNH2lKnOAwwXxwnXSo5WOF5AQXh1nRdbBV9Nu7yI6jH1QV6fKf6oFU2Y
IOjpnJ0FihVB6XoZ0wNOUMzPEEQcTfIoVoc+t0iK02wcmTLgBgbYU703dHvvPTcn
IfdI2mscx8l9MjUOdklIIve0FhCxRPqHpEeKjM95gllbXmWgQxAXiog+A62fEo5d
M7nfeEyiweSlhj1cv+2dyhzyS5saKYkk3ocCnOMCyD0M+4gJx4n4b/zT3rcujyN+
7m20PbBTjcdTT1+AxOs75rON2hhKUqqrk2MDCpnEJsNK4TuRyDUtm9r+AxaZ4XRK
MT8InY1Xl9hzrIK6MVERYH46kxg6odwpzJ8Urn4dREBiMy6Gzq8mtyXvpYEcmeGL
zz1aT7qNNbQ0qqbPb6RpOMHlUWOIhVWJC71T5WK1pynAc3P9zOm8BkUYvIyJvCbR
bufCGVng4FAtVZ1advxSVRoa4GyuFZ8=
-----END CERTIFICATE-----
amsn-0.98.9/ca-certs/GTE_CyberTrust_Global_Root.pem 0000644 0001750 0001750 00000001554 11346410561 021673 0 ustar billiob billiob -----BEGIN CERTIFICATE-----
MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgw
FgYDVQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRy
dXN0IFNvbHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3Qg
R2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1
MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYD
VQQLEx5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMT
GkdURSBDeWJlclRydXN0IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUA
A4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4usJTQGz0O9pTAipTHBsiQl8i4
ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcqlHHK6XALn
ZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8F
LztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh3
46B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq
81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0PlZPvy5TYnh+d
XIVtx6quTx8itc2VrbqnzPmrC3p/
-----END CERTIFICATE-----
amsn-0.98.9/ca-certs/Microsoft_Internet_Authority.pem 0000644 0001750 0001750 00000003421 11346121634 022463 0 ustar billiob billiob -----BEGIN CERTIFICATE-----
MIIFCjCCBHOgAwIBAgIEBycWdTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJV
UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU
cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds
b2JhbCBSb290MB4XDTA4MDIxOTE4MjcwMloXDTExMDIxOTE4MjQ1M1owJzElMCMG
A1UEAxMcTWljcm9zb2Z0IEludGVybmV0IEF1dGhvcml0eTCCAiIwDQYJKoZIhvcN
AQEBBQADggIPADCCAgoCggIBAKiloatvDehDG/rQriel2AC9qmSJdvjKb2fmJf30
K7SaC3zQu8kGQxENUEFsHsH0jmBejJ9vvn9tHZ8hGL+kORvWUVBskdMzP65rC0V0
VeVgUYzPZ7MvrLfhh9+v3yJ7qRuf1aNgmzJg5t1AA91X+aRrFT4lRzl9BFWhQ1VS
XaD7l6qoiyhD8FbrdLRAe61swsRmzWeXoy6NJpOBsGXaCSG1Jooylro+zkWxt97c
NkNf/wYqoYcIXo02YpFbwreveejW9a0Lh/1z9+e9aiMtC5QnPT57GTqNINt5R0rp
Iz4g3GJhmjXVoVF/tev5DMJuhRgPoz0W0aA3UnSmTWh2RFvgqawLqSRrKUhVjySi
/m5s62uG5xxIftO7/6ljzS061CFoV/RBl/I3WghYp04sr4cSXWa/rL449YhBT8BJ
jltefWCYAOcT1nA4oFXwXbl1qCUIkZ0bqwju2FGW5vl2qh6vmzcQjc3XxD0m2UqC
yJNFa9SUgVXtUCqeOI+KqgLW01tpqZteG10byWKmppTVAvdPwHoGE0bl6wBwXldE
f7Pn4lqu6Yp4bedP3Qv1sfp2H7D98cxSwYRt3UcXN2kjTPv+pby2fEHm9GWf3iE/
7OtzUI7LYhP7+rGyuCYTtZKH1jDWHrTZBpnAPmrAQQHCI8/4TjF9ZQ1mqRi6x9I9
9XGfAgMBAAGjggFvMIIBazASBgNVHRMBAf8ECDAGAQH/AgEBMFMGA1UdIARMMEow
SAYJKwYBBAGxPgEAMDswOQYIKwYBBQUHAgEWLWh0dHA6Ly9jeWJlcnRydXN0Lm9t
bmlyb290LmNvbS9yZXBvc2l0b3J5LmNmbTAOBgNVHQ8BAf8EBAMCAYYwgYkGA1Ud
IwSBgTB/oXmkdzB1MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0
aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAh
BgNVBAMTGkdURSBDeWJlclRydXN0IEdsb2JhbCBSb290ggIBpTBFBgNVHR8EPjA8
MDqgOKA2hjRodHRwOi8vd3d3LnB1YmxpYy10cnVzdC5jb20vY2dpLWJpbi9DUkwv
MjAxOC9jZHAuY3JsMB0GA1UdDgQWBBTG27vA2CAZkvFg/IjxWH+8G06PGjANBgkq
hkiG9w0BAQUFAAOBgQBnSDXCyiqGmHTAEJOtZYVm/IbzGtzCY423NF6/yuccYZkm
spJnDoh8nq3nx3P2KBEyPAqoQ1MEFC+ByQjV4AAQ9dMQALUGNRfHhFUhBeeIybYd
bzvKOxSlIYSwO2T56+oXyDlkbQWKmHec5qzCE0lwGHslsRU/CHwhuFu2nH+CxQ==
-----END CERTIFICATE-----
amsn-0.98.9/ca-certs/874806e2.0 0000777 0001750 0001750 00000000000 11757711634 024547 2Microsoft_Secure_Server_Authority.pem ustar billiob billiob amsn-0.98.9/ca-certs/c692a373.0 0000777 0001750 0001750 00000000000 11757711634 023040 2GTE_CyberTrust_Global_Root.pem ustar billiob billiob amsn-0.98.9/utils/ 0000755 0001750 0001750 00000000000 11757711634 013545 5 ustar billiob billiob amsn-0.98.9/utils/snit/ 0000755 0001750 0001750 00000000000 11757711634 014522 5 ustar billiob billiob amsn-0.98.9/utils/snit/snit.tcl 0000644 0001750 0001750 00000002072 11020317540 016161 0 ustar billiob billiob #-----------------------------------------------------------------------
# TITLE:
# snit.tcl
#
# AUTHOR:
# Will Duquette
#
# DESCRIPTION:
# Snit's Not Incr Tcl, a simple object system in Pure Tcl.
#
# Snit 1.x Loader
#
# Copyright (C) 2003-2006 by William H. Duquette
# This code is licensed as described in license.txt.
#
#-----------------------------------------------------------------------
package require Tcl 8.3
# Define the snit namespace and save the library directory
namespace eval ::snit:: {
set library [file dirname [info script]]
}
# Select the implementation based on the version of the Tcl core
# executing this code. For 8.3 we use a backport emulating various
# 8.4 features
if {[package vsatisfies [package provide Tcl] 8.4]} {
source [file join $::snit::library main1.tcl]
} else {
source [file join $::snit::library main1_83.tcl]
source [file join $::snit::library snit_tcl83_utils.tcl]
}
# Load the library of Snit validation types.
source [file join $::snit::library validate.tcl]
package provide snit 1.3.1
amsn-0.98.9/utils/snit/snit_tcl83_utils.tcl 0000644 0001750 0001750 00000014324 11020317540 020421 0 ustar billiob billiob #--------------------------------------------------------------------------
# TITLE:
# snit_tcl83_utils.tcl
#
# AUTHOR:
# Kenneth Green, 28 Aug 2004
#
# DESCRIPTION:
# Utilities to support the back-port of snit from Tcl 8.4 to 8.3
#
#--------------------------------------------------------------------------
# Copyright
#
# Copyright (c) 2005 Kenneth Green
# Modified by Andreas Kupries.
# All rights reserved. This code is licensed as described in license.txt.
#--------------------------------------------------------------------------
# This code is freely distributable, but is provided as-is with
# no warranty expressed or implied.
#--------------------------------------------------------------------------
# Acknowledgements
# The changes described in this file are made to the awesome 'snit'
# library as provided by William H. Duquette under the terms
# defined in the associated 'license.txt'.
#-----------------------------------------------------------------------
#-----------------------------------------------------------------------
# Namespace
namespace eval ::snit83 {}
#-----------------------------------------------------------------------
# Some Snit83 variables
namespace eval ::snit83 {
variable cmdTraceTable
array set cmdTraceTable {}
namespace eval private {}
}
#-----------------------------------------------------------------------
# Initialisation
#
# Override Tcl functions so we can mimic some behaviours. This is
# conditional on not having been done already. Otherwise loading snit
# twice will fail the second time.
#
if [info exists tk_version] {
if {
![llength [info procs destroy]] ||
![regexp snit83 [info body destroy]]
} {
rename destroy __destroy__
}
}
if {
![llength [info procs namespace]] ||
![regexp snit83 [info body namespace]]
} {
rename namespace __namespace__
rename rename __rename__ ;# must be last one renamed!
}
#-----------------------------------------------------------------------
# Global namespace functions
# destroy -
#
# Perform delete tracing and then invoke the actual Tk destroy command
if [info exists tk_version] {
proc destroy { w } {
variable ::snit83::cmdTraceTable
set index "delete,$w"
if [info exists cmdTraceTable($index)] {
set cmd $cmdTraceTable($index)
::unset cmdTraceTable($index) ;# prevent recursive tracing
if [catch {eval $cmd $oldName \"$newName\" delete} err] { ; # "
error $err
}
}
return [__destroy__ $w]
}
}
# namespace -
#
# Add limited support for 'namespace exists'. Must be a fully
# qualified namespace name (pattern match support not provided).
proc namespace { cmd args } {
if {[string equal $cmd "exists"]} {
set ptn [lindex $args 0]
return [::snit83::private::NamespaceIsDescendantOf :: $ptn]
} elseif {[string equal $cmd "delete"]} {
if [namespace exists [lindex $args 0]] {
return [uplevel 1 [subst {__namespace__ $cmd $args}]]
}
} else {
return [uplevel 1 [subst {__namespace__ $cmd $args}]]
}
}
# rename -
#
# Perform rename tracing and then invoke the actual Tcl rename command
proc rename { oldName newName } {
variable ::snit83::cmdTraceTable
# Get caller's namespace since rename must be performed
# in the context of the caller's namespace
set callerNs "::"
set callerLevel [expr {[info level] - 1}]
if { $callerLevel > 0 } {
set callerInfo [info level $callerLevel]
set procName [lindex $callerInfo 0]
set callerNs [namespace qualifiers $procName]
}
#puts "rename: callerNs: $callerNs"
#puts "rename: '$oldName' -> '$newName'"
#puts "rename: rcds - [join [array names cmdTraceTable] "\nrename: rcds - "]"
set result [namespace eval $callerNs [concat __rename__ [list $oldName $newName]]]
set index1 "rename,$oldName"
set index2 "rename,::$oldName"
foreach index [list $index1 $index2] {
if [info exists cmdTraceTable($index)] {
set cmd $cmdTraceTable($index)
#puts "rename: '$cmd' { $oldName -> $newName }"
::unset cmdTraceTable($index) ;# prevent recursive tracing
if {![string equal $newName ""]} {
# Create a new trace record under the new name
set cmdTraceTable(rename,$newName) $cmd
}
if [catch {eval $cmd $oldName \"$newName\" rename} err] {
error $err
}
break
}
}
return $result
}
#-----------------------------------------------------------------------
# Private functions
proc ::snit83::private::NamespaceIsDescendantOf { parent child } {
set result 0
foreach ns [__namespace__ children $parent] {
if [string match $ns $child] {
set result 1
break;
} else {
if [set result [NamespaceIsDescendantOf $ns $child]] {
break
}
}
}
return $result
}
#-----------------------------------------------------------------------
# Utility functions
proc ::snit83::traceAddCommand {name ops command} {
variable cmdTraceTable
#puts "::snit83::traceAddCommand n/$name/ o/$ops/ c/$command/"
#puts "XX [join [array names cmdTraceTable] "\nXX "]"
foreach op $ops {
set index "$op,$name"
#puts "::snit83::traceAddCommand: index = $index cmd = $command"
set cmdTraceTable($index) $command
}
}
proc ::snit83::traceRemoveCommand {name ops command} {
variable cmdTraceTable
#puts "::snit83::traceRemoveCommand n/$name/ o/$ops/ c/$command/"
#puts "YY [join [array names cmdTraceTable] "\nYY "]"
foreach op $ops {
set index "$op,$name"
#puts "::snit83::traceRemoveCommand: index = $index cmd = $command"
catch { ::unset cmdTraceTable($index) }
}
}
# Add support for 'unset -nocomplain'
proc ::snit83::unset { args } {
#puts "::snit83::unset - args: '$args'"
set noComplain 0
if {[string equal [lindex $args 0] "-nocomplain"]} {
set noComplain 1
set args [lrange $args 1 end]
}
if {[string equal [lindex $args 0] "--"]} {
set args [lrange $args 1 end]
}
if [catch {
uplevel 1 [linsert $args 0 ::unset]
} err] {
if { !$noComplain } {
error $err
}
}
}
amsn-0.98.9/utils/snit/validate.tcl 0000644 0001750 0001750 00000043524 11020317540 017004 0 ustar billiob billiob #-----------------------------------------------------------------------
# TITLE:
# validate.tcl
#
# AUTHOR:
# Will Duquette
#
# DESCRIPTION:
# Snit validation types.
#
#-----------------------------------------------------------------------
namespace eval ::snit:: {
namespace export \
boolean \
double \
enum \
fpixels \
integer \
listtype \
pixels \
stringtype \
window
}
#-----------------------------------------------------------------------
# snit::boolean
snit::type ::snit::boolean {
#-------------------------------------------------------------------
# Type Methods
typemethod validate {value} {
if {![string is boolean -strict $value]} {
return -code error \
"invalid boolean \"$value\", should be one of: 1, 0, true, false, yes, no, on, off"
}
return
}
#-------------------------------------------------------------------
# Constructor
# None needed; no options
#-------------------------------------------------------------------
# Public Methods
method validate {value} {
$type validate $value
}
}
#-----------------------------------------------------------------------
# snit::double
snit::type ::snit::double {
#-------------------------------------------------------------------
# Options
# -min value
#
# Minimum value
option -min -default "" -readonly 1
# -max value
#
# Maximum value
option -max -default "" -readonly 1
#-------------------------------------------------------------------
# Type Methods
typemethod validate {value} {
if {![string is double -strict $value]} {
return -code error \
"invalid value \"$value\", expected double"
}
return
}
#-------------------------------------------------------------------
# Constructor
constructor {args} {
# FIRST, get the options
$self configurelist $args
if {"" != $options(-min) &&
![string is double -strict $options(-min)]} {
return -code error \
"invalid -min: \"$options(-min)\""
}
if {"" != $options(-max) &&
![string is double -strict $options(-max)]} {
return -code error \
"invalid -max: \"$options(-max)\""
}
if {"" != $options(-min) &&
"" != $options(-max) &&
$options(-max) < $options(-min)} {
return -code error "-max < -min"
}
}
#-------------------------------------------------------------------
# Public Methods
method validate {value} {
$type validate $value
if {("" != $options(-min) && $value < $options(-min)) ||
("" != $options(-max) && $value > $options(-max))} {
set msg "invalid value \"$value\", expected double"
if {"" != $options(-min) && "" != $options(-max)} {
append msg " in range $options(-min), $options(-max)"
} elseif {"" != $options(-min)} {
append msg " no less than $options(-min)"
}
return -code error $msg
}
return
}
}
#-----------------------------------------------------------------------
# snit::enum
snit::type ::snit::enum {
#-------------------------------------------------------------------
# Options
# -values list
#
# Valid values for this type
option -values -default {} -readonly 1
#-------------------------------------------------------------------
# Type Methods
typemethod validate {value} {
# No -values specified; it's always valid
return
}
#-------------------------------------------------------------------
# Constructor
constructor {args} {
$self configurelist $args
if {[llength $options(-values)] == 0} {
return -code error \
"invalid -values: \"\""
}
}
#-------------------------------------------------------------------
# Public Methods
method validate {value} {
if {[lsearch -exact $options(-values) $value] == -1} {
return -code error \
"invalid value \"$value\", should be one of: [join $options(-values) {, }]"
}
}
}
#-----------------------------------------------------------------------
# snit::fpixels
snit::type ::snit::fpixels {
#-------------------------------------------------------------------
# Options
# -min value
#
# Minimum value
option -min -default "" -readonly 1
# -max value
#
# Maximum value
option -max -default "" -readonly 1
#-------------------------------------------------------------------
# Instance variables
variable min "" ;# -min, no suffix
variable max "" ;# -max, no suffix
#-------------------------------------------------------------------
# Type Methods
typemethod validate {value} {
if {[catch {winfo fpixels . $value} dummy]} {
return -code error \
"invalid value \"$value\", expected fpixels"
}
return
}
#-------------------------------------------------------------------
# Constructor
constructor {args} {
# FIRST, get the options
$self configurelist $args
if {"" != $options(-min) &&
[catch {winfo fpixels . $options(-min)} min]} {
return -code error \
"invalid -min: \"$options(-min)\""
}
if {"" != $options(-max) &&
[catch {winfo fpixels . $options(-max)} max]} {
return -code error \
"invalid -max: \"$options(-max)\""
}
if {"" != $min &&
"" != $max &&
$max < $min} {
return -code error "-max < -min"
}
}
#-------------------------------------------------------------------
# Public Methods
method validate {value} {
$type validate $value
set val [winfo fpixels . $value]
if {("" != $min && $val < $min) ||
("" != $max && $val > $max)} {
set msg "invalid value \"$value\", expected fpixels"
if {"" != $min && "" != $max} {
append msg " in range $options(-min), $options(-max)"
} elseif {"" != $min} {
append msg " no less than $options(-min)"
}
return -code error $msg
}
return
}
}
#-----------------------------------------------------------------------
# snit::integer
snit::type ::snit::integer {
#-------------------------------------------------------------------
# Options
# -min value
#
# Minimum value
option -min -default "" -readonly 1
# -max value
#
# Maximum value
option -max -default "" -readonly 1
#-------------------------------------------------------------------
# Type Methods
typemethod validate {value} {
if {![string is integer -strict $value]} {
return -code error \
"invalid value \"$value\", expected integer"
}
return
}
#-------------------------------------------------------------------
# Constructor
constructor {args} {
# FIRST, get the options
$self configurelist $args
if {"" != $options(-min) &&
![string is integer -strict $options(-min)]} {
return -code error \
"invalid -min: \"$options(-min)\""
}
if {"" != $options(-max) &&
![string is integer -strict $options(-max)]} {
return -code error \
"invalid -max: \"$options(-max)\""
}
if {"" != $options(-min) &&
"" != $options(-max) &&
$options(-max) < $options(-min)} {
return -code error "-max < -min"
}
}
#-------------------------------------------------------------------
# Public Methods
method validate {value} {
$type validate $value
if {("" != $options(-min) && $value < $options(-min)) ||
("" != $options(-max) && $value > $options(-max))} {
set msg "invalid value \"$value\", expected integer"
if {"" != $options(-min) && "" != $options(-max)} {
append msg " in range $options(-min), $options(-max)"
} elseif {"" != $options(-min)} {
append msg " no less than $options(-min)"
}
return -code error $msg
}
return
}
}
#-----------------------------------------------------------------------
# snit::list
snit::type ::snit::listtype {
#-------------------------------------------------------------------
# Options
# -type type
#
# Specifies a value type
option -type -readonly 1
# -minlen len
#
# Minimum list length
option -minlen -readonly 1 -default 0
# -maxlen len
#
# Maximum list length
option -maxlen -readonly 1
#-------------------------------------------------------------------
# Type Methods
typemethod validate {value} {
if {[catch {llength $value} result]} {
return -code error \
"invalid value \"$value\", expected list"
}
return
}
#-------------------------------------------------------------------
# Constructor
constructor {args} {
# FIRST, get the options
$self configurelist $args
if {"" != $options(-minlen) &&
(![string is integer -strict $options(-minlen)] ||
$options(-minlen) < 0)} {
return -code error \
"invalid -minlen: \"$options(-minlen)\""
}
if {"" == $options(-minlen)} {
set options(-minlen) 0
}
if {"" != $options(-maxlen) &&
![string is integer -strict $options(-maxlen)]} {
return -code error \
"invalid -maxlen: \"$options(-maxlen)\""
}
if {"" != $options(-maxlen) &&
$options(-maxlen) < $options(-minlen)} {
return -code error "-maxlen < -minlen"
}
}
#-------------------------------------------------------------------
# Methods
method validate {value} {
$type validate $value
set len [llength $value]
if {$len < $options(-minlen)} {
return -code error \
"value has too few elements; at least $options(-minlen) expected"
} elseif {"" != $options(-maxlen)} {
if {$len > $options(-maxlen)} {
return -code error \
"value has too many elements; no more than $options(-maxlen) expected"
}
}
# NEXT, check each value
if {"" != $options(-type)} {
foreach item $value {
set cmd $options(-type)
lappend cmd validate $item
uplevel \#0 $cmd
}
}
}
}
#-----------------------------------------------------------------------
# snit::pixels
snit::type ::snit::pixels {
#-------------------------------------------------------------------
# Options
# -min value
#
# Minimum value
option -min -default "" -readonly 1
# -max value
#
# Maximum value
option -max -default "" -readonly 1
#-------------------------------------------------------------------
# Instance variables
variable min "" ;# -min, no suffix
variable max "" ;# -max, no suffix
#-------------------------------------------------------------------
# Type Methods
typemethod validate {value} {
if {[catch {winfo pixels . $value} dummy]} {
return -code error \
"invalid value \"$value\", expected pixels"
}
return
}
#-------------------------------------------------------------------
# Constructor
constructor {args} {
# FIRST, get the options
$self configurelist $args
if {"" != $options(-min) &&
[catch {winfo pixels . $options(-min)} min]} {
return -code error \
"invalid -min: \"$options(-min)\""
}
if {"" != $options(-max) &&
[catch {winfo pixels . $options(-max)} max]} {
return -code error \
"invalid -max: \"$options(-max)\""
}
if {"" != $min &&
"" != $max &&
$max < $min} {
return -code error "-max < -min"
}
}
#-------------------------------------------------------------------
# Public Methods
method validate {value} {
$type validate $value
set val [winfo pixels . $value]
if {("" != $min && $val < $min) ||
("" != $max && $val > $max)} {
set msg "invalid value \"$value\", expected pixels"
if {"" != $min && "" != $max} {
append msg " in range $options(-min), $options(-max)"
} elseif {"" != $min} {
append msg " no less than $options(-min)"
}
return -code error $msg
}
return
}
}
#-----------------------------------------------------------------------
# snit::stringtype
snit::type ::snit::stringtype {
#-------------------------------------------------------------------
# Options
# -minlen len
#
# Minimum list length
option -minlen -readonly 1 -default 0
# -maxlen len
#
# Maximum list length
option -maxlen -readonly 1
# -nocase 0|1
#
# globs and regexps are case-insensitive if -nocase 1.
option -nocase -readonly 1 -default 0
# -glob pattern
#
# Glob-match pattern, or ""
option -glob -readonly 1
# -regexp regexp
#
# Regular expression to match
option -regexp -readonly 1
#-------------------------------------------------------------------
# Type Methods
typemethod validate {value} {
# By default, any string (hence, any Tcl value) is valid.
return
}
#-------------------------------------------------------------------
# Constructor
constructor {args} {
# FIRST, get the options
$self configurelist $args
# NEXT, validate -minlen and -maxlen
if {"" != $options(-minlen) &&
(![string is integer -strict $options(-minlen)] ||
$options(-minlen) < 0)} {
return -code error \
"invalid -minlen: \"$options(-minlen)\""
}
if {"" == $options(-minlen)} {
set options(-minlen) 0
}
if {"" != $options(-maxlen) &&
![string is integer -strict $options(-maxlen)]} {
return -code error \
"invalid -maxlen: \"$options(-maxlen)\""
}
if {"" != $options(-maxlen) &&
$options(-maxlen) < $options(-minlen)} {
return -code error "-maxlen < -minlen"
}
# NEXT, validate -nocase
if {[catch {snit::boolean validate $options(-nocase)} result]} {
return -code error "invalid -nocase: $result"
}
# Validate the glob
if {"" != $options(-glob) &&
[catch {string match $options(-glob) ""} dummy]} {
return -code error \
"invalid -glob: \"$options(-glob)\""
}
# Validate the regexp
if {"" != $options(-regexp) &&
[catch {regexp $options(-regexp) ""} dummy]} {
return -code error \
"invalid -regexp: \"$options(-regexp)\""
}
}
#-------------------------------------------------------------------
# Methods
method validate {value} {
# Usually we'd call [$type validate $value] here, but
# as it's a no-op, don't bother.
# FIRST, validate the length.
set len [string length $value]
if {$len < $options(-minlen)} {
return -code error \
"too short: at least $options(-minlen) characters expected"
} elseif {"" != $options(-maxlen)} {
if {$len > $options(-maxlen)} {
return -code error \
"too long: no more than $options(-maxlen) characters expected"
}
}
# NEXT, check the glob match, with or without case.
if {"" != $options(-glob)} {
if {$options(-nocase)} {
set result [string match -nocase $options(-glob) $value]
} else {
set result [string match $options(-glob) $value]
}
if {!$result} {
return -code error \
"invalid value \"$value\""
}
}
# NEXT, check regexp match with or without case
if {"" != $options(-regexp)} {
if {$options(-nocase)} {
set result [regexp -nocase -- $options(-regexp) $value]
} else {
set result [regexp -- $options(-regexp) $value]
}
if {!$result} {
return -code error \
"invalid value \"$value\""
}
}
}
}
#-----------------------------------------------------------------------
# snit::window
snit::type ::snit::window {
#-------------------------------------------------------------------
# Type Methods
typemethod validate {value} {
if {![winfo exists $value]} {
return -code error \
"invalid value \"$value\", value is not a window"
}
return
}
#-------------------------------------------------------------------
# Constructor
# None needed; no options
#-------------------------------------------------------------------
# Public Methods
method validate {value} {
$type validate $value
}
}
amsn-0.98.9/utils/snit/pkgIndex.tcl 0000644 0001750 0001750 00000000320 11020317540 016747 0 ustar billiob billiob if {[package vsatisfies [package provide Tcl] 8.5]} {
package ifneeded snit 2.2.1 \
[list source [file join $dir snit2.tcl]]
}
package ifneeded snit 1.3.1 [list source [file join $dir snit.tcl]]
amsn-0.98.9/utils/snit/snit83.tcl 0000644 0001750 0001750 00000351504 10405240242 016343 0 ustar billiob billiob #-----------------------------------------------------------------------
# TITLE:
# snit.tcl
#
# AUTHOR:
# Will Duquette
#
# DESCRIPTION:
# Snit's Not Incr Tcl, a simple object system in Pure Tcl.
#
# Copyright (C) 2003-2005 by William H. Duquette
# This code is licensed as described in license.txt.
#
#-----------------------------------------------------------------------
# Back-port to Tcl8.3 by Kenneth Green (kmg)
# Modified by Andreas Kupries.
# 06 Jun 2005
#
# Local changes marked with "#kmg-tcl83"
#
# Global changes:
# " eq " => "string equal"
# " ne " -> "!string equal"
# " trace add variable " -> "trace variable "
# " write " -> "w" in all calls to 'trace variable'
# " unset -nocomplain " -> "::snit83::unset -nocomplain"
# " -glob " -> "" in all calls to 'array names'
#-----------------------------------------------------------------------
package provide snit 1.1
#-----------------------------------------------------------------------
# Namespace
namespace eval ::snit:: {
namespace export \
compile type widget widgetadaptor typemethod method macro
}
#-----------------------------------------------------------------------
# Some Snit variables
namespace eval ::snit:: {
variable reservedArgs {type selfns win self}
# Widget classes which can be hulls (must have -class)
variable hulltypes {
toplevel tk::toplevel
frame tk::frame ttk::frame
labelframe tk::labelframe ttk::labelframe
}
}
source [file dirname [info script]]/snit_tcl83_utils.tcl
#-----------------------------------------------------------------------
# Snit Type Implementation template
namespace eval ::snit:: {
# Template type definition: All internal and user-visible Snit
# implementation code.
#
# The following placeholders will automatically be replaced with
# the client's code, in two passes:
#
# First pass:
# %COMPILEDDEFS% The compiled type definition.
#
# Second pass:
# %TYPE% The fully qualified type name.
# %IVARDECS% Instance variable declarations
# %TVARDECS% Type variable declarations
# %TCONSTBODY% Type constructor body
# %INSTANCEVARS% The compiled instance variable initialization code.
# %TYPEVARS% The compiled type variable initialization code.
# This is the overall type template.
variable typeTemplate
# This is the normal type proc
variable nominalTypeProc
# This is the "-hastypemethods no" type proc
variable simpleTypeProc
}
set ::snit::typeTemplate {
#-------------------------------------------------------------------
# The type's namespace definition and the user's type variables
namespace eval %TYPE% {%TYPEVARS%
}
#----------------------------------------------------------------
# Commands for use in methods, typemethods, etc.
#
# These are implemented as aliases into the Snit runtime library.
interp alias {} %TYPE%::installhull {} ::snit::RT.installhull %TYPE%
interp alias {} %TYPE%::install {} ::snit::RT.install %TYPE%
interp alias {} %TYPE%::typevariable {} ::variable
interp alias {} %TYPE%::variable {} ::snit::RT.variable
interp alias {} %TYPE%::mytypevar {} ::snit::RT.mytypevar %TYPE%
interp alias {} %TYPE%::typevarname {} ::snit::RT.mytypevar %TYPE%
interp alias {} %TYPE%::myvar {} ::snit::RT.myvar
interp alias {} %TYPE%::varname {} ::snit::RT.myvar
interp alias {} %TYPE%::codename {} ::snit::RT.codename %TYPE%
interp alias {} %TYPE%::myproc {} ::snit::RT.myproc %TYPE%
interp alias {} %TYPE%::mymethod {} ::snit::RT.mymethod
interp alias {} %TYPE%::mytypemethod {} ::snit::RT.mytypemethod %TYPE%
interp alias {} %TYPE%::from {} ::snit::RT.from %TYPE%
#-------------------------------------------------------------------
# Snit's internal variables
namespace eval %TYPE% {
# Array: General Snit Info
#
# ns: The type's namespace
# hasinstances: T or F, from pragma -hasinstances.
# simpledispatch: T or F, from pragma -hasinstances.
# canreplace: T or F, from pragma -canreplace.
# counter: Count of instances created so far.
# widgetclass: Set by widgetclass statement.
# hulltype: Hull type (frame or toplevel) for widgets only.
# exceptmethods: Methods explicitly not delegated to *
# excepttypemethods: Methods explicitly not delegated to *
# tvardecs: Type variable declarations--for dynamic methods
# ivardecs: Instance variable declarations--for dyn. methods
typevariable Snit_info
set Snit_info(ns) %TYPE%::
set Snit_info(hasinstances) 1
set Snit_info(simpledispatch) 0
set Snit_info(canreplace) 0
set Snit_info(counter) 0
set Snit_info(widgetclass) {}
set Snit_info(hulltype) frame
set Snit_info(exceptmethods) {}
set Snit_info(excepttypemethods) {}
set Snit_info(tvardecs) {%TVARDECS%}
set Snit_info(ivardecs) {%IVARDECS%}
# Array: Public methods of this type.
# The index is the method name, or "*".
# The value is [list $pattern $componentName], where
# $componentName is "" for normal methods.
typevariable Snit_typemethodInfo
array unset Snit_typemethodInfo
# Array: Public methods of instances of this type.
# The index is the method name, or "*".
# The value is [list $pattern $componentName], where
# $componentName is "" for normal methods.
typevariable Snit_methodInfo
array unset Snit_methodInfo
# Array: option information. See dictionary.txt.
typevariable Snit_optionInfo
array unset Snit_optionInfo
set Snit_optionInfo(local) {}
set Snit_optionInfo(delegated) {}
set Snit_optionInfo(starcomp) {}
set Snit_optionInfo(except) {}
}
#----------------------------------------------------------------
# Compiled Procs
#
# These commands are created or replaced during compilation:
# Snit_instanceVars selfns
#
# Initializes the instance variables, if any. Called during
# instance creation.
proc %TYPE%::Snit_instanceVars {selfns} {
%INSTANCEVARS%
}
# Type Constructor
proc %TYPE%::Snit_typeconstructor {type} {
%TVARDECS%
%TCONSTBODY%
}
#----------------------------------------------------------------
# Default Procs
#
# These commands might be replaced during compilation:
# Snit_destructor type selfns win self
#
# Default destructor for the type. By default, it does
# nothing. It's replaced by any user destructor.
# For types, it's called by method destroy; for widgettypes,
# it's called by a destroy event handler.
proc %TYPE%::Snit_destructor {type selfns win self} { }
#----------------------------------------------------------
# Compiled Definitions
%COMPILEDDEFS%
#----------------------------------------------------------
# Finally, call the Type Constructor
%TYPE%::Snit_typeconstructor %TYPE%
}
#-----------------------------------------------------------------------
# Type procs
#
# These procs expect the fully-qualified type name to be
# substituted in for %TYPE%.
# This is the nominal type proc. It supports typemethods and
# delegated typemethods.
set ::snit::nominalTypeProc {
# Type dispatcher function. Note: This function lives
# in the parent of the %TYPE% namespace! All accesses to
# %TYPE% variables and methods must be qualified!
proc %TYPE% {{method ""} args} {
# First, if there's no method, and no args, and there's a create
# method, and this isn't a widget, then method is "create" and
# "args" is %AUTO%.
if {[string equal $method ""] && [llength $args] == 0} {
::variable %TYPE%::Snit_info
if {$Snit_info(hasinstances) && !$Snit_info(isWidget)} {
set method create
lappend args %AUTO%
} else {
error "wrong \# args: should be \"%TYPE% method args\""
}
}
# Next, retrieve the command.
variable %TYPE%::Snit_typemethodCache
while 1 {
if {[catch {set Snit_typemethodCache($method)} commandRec]} {
set commandRec [::snit::RT.CacheTypemethodCommand %TYPE% $method]
if {[llength $commandRec] == 0} {
return -code error "\"%TYPE% $method\" is not defined"
}
}
# If we've got a real command, break.
if {[lindex $commandRec 0] == 0} {
break
}
# Otherwise, we need to look up again...if we can.
if {[llength $args] == 0} {
return -code error \
"wrong number args: should be \"%TYPE% $method method args\""
}
lappend method [lindex $args 0]
set args [lrange $args 1 end]
}
set command [lindex $commandRec 1]
# Pass along the return code unchanged.
set retval [catch {uplevel 1 $command $args} result]
if {$retval} {
if {$retval == 1} {
global errorInfo
global errorCode
return -code error -errorinfo $errorInfo \
-errorcode $errorCode $result
} else {
return -code $retval $result
}
}
return $result
}
}
# This is the simplified type proc for when there are no typemethods
# except create. In this case, it doesn't take a method argument;
# the method is always "create".
set ::snit::simpleTypeProc {
# Type dispatcher function. Note: This function lives
# in the parent of the %TYPE% namespace! All accesses to
# %TYPE% variables and methods must be qualified!
proc %TYPE% {args} {
::variable %TYPE%::Snit_info
# FIRST, if the are no args, the single arg is %AUTO%
if {[llength $args] == 0} {
if {$Snit_info(isWidget)} {
error "wrong \# args: should be \"%TYPE% name args\""
}
lappend args %AUTO%
}
# NEXT, we're going to call the create method.
# Pass along the return code unchanged.
if {$Snit_info(isWidget)} {
set command [list ::snit::RT.widget.typemethod.create %TYPE%]
} else {
set command [list ::snit::RT.type.typemethod.create %TYPE%]
}
set retval [catch {uplevel 1 $command $args} result]
if {$retval} {
if {$retval == 1} {
global errorInfo
global errorCode
return -code error -errorinfo $errorInfo \
-errorcode $errorCode $result
} else {
return -code $retval $result
}
}
return $result
}
}
#-----------------------------------------------------------------------
# Instance procs
#
# The following must be substituted into these proc bodies:
#
# %SELFNS% The instance namespace
# %WIN% The original instance name
# %TYPE% The fully-qualified type name
#
# Nominal instance proc body: supports method caching and delegation.
#
# proc $instanceName {method args} ....
set ::snit::nominalInstanceProc {
set self [set %SELFNS%::Snit_instance]
while {1} {
if {[catch {set %SELFNS%::Snit_methodCache($method)} commandRec]} {
set commandRec [snit::RT.CacheMethodCommand %TYPE% %SELFNS% %WIN% $self $method]
if {[llength $commandRec] == 0} {
return -code error \
"\"$self $method\" is not defined"
}
}
# If we've got a real command, break.
if {[lindex $commandRec 0] == 0} {
break
}
# Otherwise, we need to look up again...if we can.
if {[llength $args] == 0} {
return -code error \
"wrong number args: should be \"$self $method method args\""
}
lappend method [lindex $args 0]
set args [lrange $args 1 end]
}
set command [lindex $commandRec 1]
# Pass along the return code unchanged.
set retval [catch {uplevel 1 $command $args} result]
if {$retval} {
if {$retval == 1} {
global errorInfo
global errorCode
return -code error -errorinfo $errorInfo \
-errorcode $errorCode $result
} else {
return -code $retval $result
}
}
return $result
}
# Simplified method proc body: No delegation allowed; no support for
# upvar or exotic return codes or hierarchical methods. Designed for
# max speed for simple types.
#
# proc $instanceName {method args} ....
set ::snit::simpleInstanceProc {
set self [set %SELFNS%::Snit_instance]
if {[lsearch -exact ${%TYPE%::Snit_methods} $method] == -1} {
set optlist [join ${%TYPE%::Snit_methods} ", "]
set optlist [linsert $optlist "end-1" "or"]
error "bad option \"$method\": must be $optlist"
}
eval [linsert $args 0 \
%TYPE%::Snit_method$method %TYPE% %SELFNS% %WIN% $self]
}
#=======================================================================
# Snit Type Definition
#
# These are the procs used to define Snit types, widgets, and
# widgetadaptors.
#-----------------------------------------------------------------------
# Snit Compilation Variables
#
# The following variables are used while Snit is compiling a type,
# and are disposed afterwards.
namespace eval ::snit:: {
# The compiler variable contains the name of the slave interpreter
# used to compile type definitions.
variable compiler ""
# The compile array accumulates information about the type or
# widgettype being compiled. It is cleared before and after each
# compilation. It has these indices:
#
# type: The name of the type being compiled, for use
# in compilation procs.
# defs: Compiled definitions, both standard and client.
# which: type, widget, widgetadaptor
# instancevars: Instance variable definitions and initializations.
# ivprocdec: Instance variable proc declarations.
# tvprocdec: Type variable proc declarations.
# typeconstructor: Type constructor body.
# widgetclass: The widgetclass, for snit::widgets, only
# hasoptions: False, initially; set to true when first
# option is defined.
# localoptions: Names of local options.
# delegatedoptions: Names of delegated options.
# localmethods: Names of locally defined methods.
# delegatesmethods: no if no delegated methods, yes otherwise.
# hashierarchic : no if no hierarchic methods, yes otherwise.
# components: Names of defined components.
# typecomponents: Names of defined typecomponents.
# typevars: Typevariable definitions and initializations.
# varnames: Names of instance variables
# typevarnames Names of type variables
# hasconstructor False, initially; true when constructor is
# defined.
# resource-$opt The option's resource name
# class-$opt The option's class
# -default-$opt The option's default value
# -validatemethod-$opt The option's validate method
# -configuremethod-$opt The option's configure method
# -cgetmethod-$opt The option's cget method.
# -hastypeinfo The -hastypeinfo pragma
# -hastypedestroy The -hastypedestroy pragma
# -hastypemethods The -hastypemethods pragma
# -hasinfo The -hasinfo pragma
# -hasinstances The -hasinstances pragma
# -simpledispatch The -simpledispatch pragma
# -canreplace The -canreplace pragma
variable compile
# This variable accumulates method dispatch information; it has
# the same structure as the %TYPE%::Snit_methodInfo array, and is
# used to initialize it.
variable methodInfo
# This variable accumulates typemethod dispatch information; it has
# the same structure as the %TYPE%::Snit_typemethodInfo array, and is
# used to initialize it.
variable typemethodInfo
# The following variable lists the reserved type definition statement
# names, e.g., the names you can't use as macros. It's built at
# compiler definition time using "info commands".
variable reservedwords {}
}
#-----------------------------------------------------------------------
# type compilation commands
#
# The type and widgettype commands use a slave interpreter to compile
# the type definition. These are the procs
# that are aliased into it.
# Initialize the compiler
proc ::snit::Comp.Init {} {
variable compiler
variable reservedwords
if {[string equal $compiler ""]} {
# Create the compiler's interpreter
set compiler [interp create]
# Initialize the interpreter
$compiler eval {
# Load package information
# TBD: see if this can be moved outside.
catch {package require ::snit::__does_not_exist__}
# Protect some Tcl commands our type definitions
# will shadow.
rename proc _proc
rename variable _variable
}
# Define compilation aliases.
$compiler alias pragma ::snit::Comp.statement.pragma
$compiler alias widgetclass ::snit::Comp.statement.widgetclass
$compiler alias hulltype ::snit::Comp.statement.hulltype
$compiler alias constructor ::snit::Comp.statement.constructor
$compiler alias destructor ::snit::Comp.statement.destructor
$compiler alias option ::snit::Comp.statement.option
$compiler alias oncget ::snit::Comp.statement.oncget
$compiler alias onconfigure ::snit::Comp.statement.onconfigure
$compiler alias method ::snit::Comp.statement.method
$compiler alias typemethod ::snit::Comp.statement.typemethod
$compiler alias typeconstructor ::snit::Comp.statement.typeconstructor
$compiler alias proc ::snit::Comp.statement.proc
$compiler alias typevariable ::snit::Comp.statement.typevariable
$compiler alias variable ::snit::Comp.statement.variable
$compiler alias typecomponent ::snit::Comp.statement.typecomponent
$compiler alias component ::snit::Comp.statement.component
$compiler alias delegate ::snit::Comp.statement.delegate
$compiler alias expose ::snit::Comp.statement.expose
# Get the list of reserved words
set reservedwords [$compiler eval {info commands}]
}
}
# Compile a type definition, and return the results as a list of two
# items: the fully-qualified type name, and a script that will define
# the type when executed.
#
# which type, widget, or widgetadaptor
# type the type name
# body the type definition
proc ::snit::Comp.Compile {which type body} {
variable typeTemplate
variable nominalTypeProc
variable simpleTypeProc
variable compile
variable compiler
variable methodInfo
variable typemethodInfo
# FIRST, qualify the name.
if {![string match "::*" $type]} {
# Get caller's namespace;
# append :: if not global namespace.
set ns [uplevel 2 [list namespace current]]
if {"::" != $ns} {
append ns "::"
}
set type "$ns$type"
}
# NEXT, create and initialize the compiler, if needed.
Comp.Init
# NEXT, initialize the class data
array unset methodInfo
array unset typemethodInfo
array unset compile
set compile(type) $type
set compile(defs) {}
set compile(which) $which
set compile(hasoptions) no
set compile(localoptions) {}
set compile(instancevars) {}
set compile(typevars) {}
set compile(delegatedoptions) {}
set compile(ivprocdec) {}
set compile(tvprocdec) {}
set compile(typeconstructor) {}
set compile(widgetclass) {}
set compile(hulltype) {}
set compile(localmethods) {}
set compile(delegatesmethods) no
set compile(hashierarchic) no
set compile(components) {}
set compile(typecomponents) {}
set compile(varnames) {}
set compile(typevarnames) {}
set compile(hasconstructor) no
set compile(-hastypedestroy) yes
set compile(-hastypeinfo) yes
set compile(-hastypemethods) yes
set compile(-hasinfo) yes
set compile(-hasinstances) yes
set compile(-simpledispatch) no
set compile(-canreplace) no
set isWidget [string match widget* $which]
set isWidgetAdaptor [string match widgetadaptor $which]
# NEXT, Evaluate the type's definition in the class interpreter.
$compiler eval $body
# NEXT, Add the standard definitions
append compile(defs) \
"\nset %TYPE%::Snit_info(isWidget) $isWidget\n"
append compile(defs) \
"\nset %TYPE%::Snit_info(isWidgetAdaptor) $isWidgetAdaptor\n"
# Indicate whether the type can create instances that replace
# existing commands.
append compile(defs) "\nset %TYPE%::Snit_info(canreplace) $compile(-canreplace)\n"
# Check pragmas for conflict.
if {!$compile(-hastypemethods) && !$compile(-hasinstances)} {
error "$which $type has neither typemethods nor instances"
}
if {$compile(-simpledispatch) && $compile(delegatesmethods)} {
error "$which $type requests -simpledispatch but delegates methods."
}
if {$compile(-simpledispatch) && $compile(hashierarchic)} {
error "$which $type requests -simpledispatch but defines hierarchical methods."
}
# If there are typemethods, define the standard typemethods and
# the nominal type proc. Otherwise define the simple type proc.
if {$compile(-hastypemethods)} {
# Add the info typemethod unless the pragma forbids it.
if {$compile(-hastypeinfo)} {
Comp.statement.delegate typemethod info \
using {::snit::RT.typemethod.info %t}
}
# Add the destroy typemethod unless the pragma forbids it.
if {$compile(-hastypedestroy)} {
Comp.statement.delegate typemethod destroy \
using {::snit::RT.typemethod.destroy %t}
}
# Add the nominal type proc.
append compile(defs) $nominalTypeProc
} else {
# Add the simple type proc.
append compile(defs) $simpleTypeProc
}
# Add standard methods/typemethods that only make sense if the
# type has instances.
if {$compile(-hasinstances)} {
# If we're using simple dispatch, remember that.
if {$compile(-simpledispatch)} {
append compile(defs) "\nset %TYPE%::Snit_info(simpledispatch) 1\n"
}
# Add the info method unless the pragma forbids it.
if {$compile(-hasinfo)} {
if {!$compile(-simpledispatch)} {
Comp.statement.delegate method info \
using {::snit::RT.method.info %t %n %w %s}
} else {
Comp.statement.method info {args} {
eval [linsert $args 0 \
::snit::RT.method.info $type $selfns $win $self]
}
}
}
# Add the option handling stuff if there are any options.
if {$compile(hasoptions)} {
Comp.statement.variable options
if {!$compile(-simpledispatch)} {
Comp.statement.delegate method cget \
using {::snit::RT.method.cget %t %n %w %s}
Comp.statement.delegate method configurelist \
using {::snit::RT.method.configurelist %t %n %w %s}
Comp.statement.delegate method configure \
using {::snit::RT.method.configure %t %n %w %s}
} else {
Comp.statement.method cget {args} {
eval [linsert $args 0 \
::snit::RT.method.cget $type $selfns $win $self]
}
Comp.statement.method configurelist {args} {
eval [linsert $args 0 \
::snit::RT.method.configurelist $type $selfns $win $self]
}
Comp.statement.method configure {args} {
eval [linsert $args 0 \
::snit::RT.method.configure $type $selfns $win $self]
}
}
}
# Add a default constructor, if they haven't already defined one.
# If there are options, it will configure args; otherwise it
# will do nothing.
if {!$compile(hasconstructor)} {
if {$compile(hasoptions)} {
Comp.statement.constructor {args} {
$self configurelist $args
}
} else {
Comp.statement.constructor {} {}
}
}
if {!$isWidget} {
if {!$compile(-simpledispatch)} {
Comp.statement.delegate method destroy \
using {::snit::RT.method.destroy %t %n %w %s}
} else {
Comp.statement.method destroy {args} {
eval [linsert $args 0 \
::snit::RT.method.destroy $type $selfns $win $self]
}
}
Comp.statement.delegate typemethod create \
using {::snit::RT.type.typemethod.create %t}
} else {
Comp.statement.delegate typemethod create \
using {::snit::RT.widget.typemethod.create %t}
}
# Save the list of method names, for -simpledispatch; otherwise,
# save the method info.
if {$compile(-simpledispatch)} {
append compile(defs) \
"\nset %TYPE%::Snit_methods [list $compile(localmethods)]\n"
} else {
append compile(defs) \
"\narray set %TYPE%::Snit_methodInfo [list [array get methodInfo]]\n"
}
} else {
append compile(defs) "\nset %TYPE%::Snit_info(hasinstances) 0\n"
}
# NEXT, compiling the type definition built up a set of information
# about the type's locally defined options; add this information to
# the compiled definition.
Comp.SaveOptionInfo
# NEXT, compiling the type definition built up a set of information
# about the typemethods; save the typemethod info.
append compile(defs) \
"\narray set %TYPE%::Snit_typemethodInfo [list [array get typemethodInfo]]\n"
# NEXT, if this is a widget define the hull component if it isn't
# already defined.
if {$isWidget} {
Comp.DefineComponent hull
}
# NEXT, substitute the compiled definition into the type template
# to get the type definition script.
set defscript [Expand $typeTemplate \
%COMPILEDDEFS% $compile(defs)]
# NEXT, substitute the defined macros into the type definition script.
# This is done as a separate step so that the compile(defs) can
# contain the macros defined below.
set defscript [Expand $defscript \
%TYPE% $type \
%IVARDECS% $compile(ivprocdec) \
%TVARDECS% $compile(tvprocdec) \
%TCONSTBODY% $compile(typeconstructor) \
%INSTANCEVARS% $compile(instancevars) \
%TYPEVARS% $compile(typevars) \
]
array unset compile
return [list $type $defscript]
}
# Information about locally-defined options is accumulated during
# compilation, but not added to the compiled definition--the option
# statement can appear multiple times, so it's easier this way.
# This proc fills in Snit_optionInfo with the accumulated information.
#
# It also computes the option's resource and class names if needed.
#
# Note that the information for delegated options was put in
# Snit_optionInfo during compilation.
proc ::snit::Comp.SaveOptionInfo {} {
variable compile
foreach option $compile(localoptions) {
if {[string equal $compile(resource-$option) ""]} {
set compile(resource-$option) [string range $option 1 end]
}
if {[string equal $compile(class-$option) ""]} {
set compile(class-$option) [Capitalize $compile(resource-$option)]
}
# NOTE: Don't verify that the validate, configure, and cget
# values name real methods; the methods might be defined outside
# the typedefinition using snit::method.
Mappend compile(defs) {
# Option %OPTION%
lappend %TYPE%::Snit_optionInfo(local) %OPTION%
set %TYPE%::Snit_optionInfo(islocal-%OPTION%) 1
set %TYPE%::Snit_optionInfo(resource-%OPTION%) %RESOURCE%
set %TYPE%::Snit_optionInfo(class-%OPTION%) %CLASS%
set %TYPE%::Snit_optionInfo(default-%OPTION%) %DEFAULT%
set %TYPE%::Snit_optionInfo(validate-%OPTION%) %VALIDATE%
set %TYPE%::Snit_optionInfo(configure-%OPTION%) %CONFIGURE%
set %TYPE%::Snit_optionInfo(cget-%OPTION%) %CGET%
set %TYPE%::Snit_optionInfo(readonly-%OPTION%) %READONLY%
} %OPTION% $option \
%RESOURCE% $compile(resource-$option) \
%CLASS% $compile(class-$option) \
%DEFAULT% [list $compile(-default-$option)] \
%VALIDATE% [list $compile(-validatemethod-$option)] \
%CONFIGURE% [list $compile(-configuremethod-$option)] \
%CGET% [list $compile(-cgetmethod-$option)] \
%READONLY% $compile(-readonly-$option)
}
}
# Evaluates a compiled type definition, thus making the type available.
proc ::snit::Comp.Define {compResult} {
# The compilation result is a list containing the fully qualified
# type name and a script to evaluate to define the type.
set type [lindex $compResult 0]
set defscript [lindex $compResult 1]
# Execute the type definition script.
# Consider using namespace eval %TYPE%. See if it's faster.
if {[catch {eval $defscript} result]} {
namespace delete $type
catch {rename $type ""}
error $result
}
return $type
}
# Sets pragma options which control how the type is defined.
proc ::snit::Comp.statement.pragma {args} {
variable compile
set errRoot "Error in \"pragma...\""
foreach {opt val} $args {
switch -exact -- $opt {
-hastypeinfo -
-hastypedestroy -
-hastypemethods -
-hasinstances -
-simpledispatch -
-hasinfo -
-canreplace {
if {![string is boolean -strict $val]} {
error "$errRoot, \"$opt\" requires a boolean value"
}
set compile($opt) $val
}
default {
error "$errRoot, unknown pragma"
}
}
}
}
# Defines a widget's option class name.
# This statement is only available for snit::widgets,
# not for snit::types or snit::widgetadaptors.
proc ::snit::Comp.statement.widgetclass {name} {
variable compile
# First, widgetclass can only be set for true widgets
if {"widget" != $compile(which)} {
error "widgetclass cannot be set for snit::$compile(which)s"
}
# Next, validate the option name. We'll require that it begin
# with an uppercase letter.
set initial [string index $name 0]
if {![string is upper $initial]} {
error "widgetclass \"$name\" does not begin with an uppercase letter"
}
if {"" != $compile(widgetclass)} {
error "too many widgetclass statements"
}
# Next, save it.
Mappend compile(defs) {
set %TYPE%::Snit_info(widgetclass) %WIDGETCLASS%
} %WIDGETCLASS% [list $name]
set compile(widgetclass) $name
}
# Defines a widget's hull type.
# This statement is only available for snit::widgets,
# not for snit::types or snit::widgetadaptors.
proc ::snit::Comp.statement.hulltype {name} {
variable compile
variable hulltypes
# First, hulltype can only be set for true widgets
if {"widget" != $compile(which)} {
error "hulltype cannot be set for snit::$compile(which)s"
}
# Next, it must be one of the valid hulltypes (frame, toplevel, ...)
if {[lsearch -exact $hulltypes [string trimleft $name :]] == -1} {
error "invalid hulltype \"$name\", should be one of\
[join $hulltypes {, }]"
}
if {"" != $compile(hulltype)} {
error "too many hulltype statements"
}
# Next, save it.
Mappend compile(defs) {
set %TYPE%::Snit_info(hulltype) %HULLTYPE%
} %HULLTYPE% $name
set compile(hulltype) $name
}
# Defines a constructor.
proc ::snit::Comp.statement.constructor {arglist body} {
variable compile
CheckArgs "constructor" $arglist
# Next, add a magic reference to self.
set arglist [concat type selfns win self $arglist]
# Next, add variable declarations to body:
set body "%TVARDECS%%IVARDECS%\n$body"
set compile(hasconstructor) yes
append compile(defs) "proc %TYPE%::Snit_constructor [list $arglist] [list $body]\n"
}
# Defines a destructor.
proc ::snit::Comp.statement.destructor {body} {
variable compile
# Next, add variable declarations to body:
set body "%TVARDECS%%IVARDECS%\n$body"
append compile(defs) "proc %TYPE%::Snit_destructor {type selfns win self} [list $body]\n\n"
}
# Defines a type option. The option value can be a triple, specifying
# the option's -name, resource name, and class name.
proc ::snit::Comp.statement.option {optionDef args} {
variable compile
# First, get the three option names.
set option [lindex $optionDef 0]
set resourceName [lindex $optionDef 1]
set className [lindex $optionDef 2]
set errRoot "Error in \"option [list $optionDef]...\""
# Next, validate the option name.
if {![Comp.OptionNameIsValid $option]} {
error "$errRoot, badly named option \"$option\""
}
if {[Contains $option $compile(delegatedoptions)]} {
error "$errRoot, cannot define \"$option\" locally, it has been delegated"
}
if {![Contains $option $compile(localoptions)]} {
# Remember that we've seen this one.
set compile(hasoptions) yes
lappend compile(localoptions) $option
# Initialize compilation info for this option.
set compile(resource-$option) ""
set compile(class-$option) ""
set compile(-default-$option) ""
set compile(-validatemethod-$option) ""
set compile(-configuremethod-$option) ""
set compile(-cgetmethod-$option) ""
set compile(-readonly-$option) 0
}
# NEXT, see if we have a resource name. If so, make sure it
# isn't being redefined differently.
if {![string equal $resourceName ""]} {
if {[string equal $compile(resource-$option) ""]} {
# If it's undefined, just save the value.
set compile(resource-$option) $resourceName
} elseif {![string equal $resourceName $compile(resource-$option)]} {
# It's been redefined differently.
error "$errRoot, resource name redefined from \"$compile(resource-$option)\" to \"$resourceName\""
}
}
# NEXT, see if we have a class name. If so, make sure it
# isn't being redefined differently.
if {![string equal $className ""]} {
if {[string equal $compile(class-$option) ""]} {
# If it's undefined, just save the value.
set compile(class-$option) $className
} elseif {![string equal $className $compile(class-$option)]} {
# It's been redefined differently.
error "$errRoot, class name redefined from \"$compile(class-$option)\" to \"$className\""
}
}
# NEXT, handle the args; it's not an error to redefine these.
if {[llength $args] == 1} {
set compile(-default-$option) [lindex $args 0]
} else {
foreach {optopt val} $args {
switch -exact -- $optopt {
-default -
-validatemethod -
-configuremethod -
-cgetmethod {
set compile($optopt-$option) $val
}
-readonly {
if {![string is boolean -strict $val]} {
error "$errRoot, -readonly requires a boolean, got \"$val\""
}
set compile($optopt-$option) $val
}
default {
error "$errRoot, unknown option definition option \"$optopt\""
}
}
}
}
}
# 1 if the option name is valid, 0 otherwise.
proc ::snit::Comp.OptionNameIsValid {option} {
if {![string match {-*} $option] || [string match {*[A-Z ]*} $option]} {
return 0
}
return 1
}
# Defines an option's cget handler
proc ::snit::Comp.statement.oncget {option body} {
variable compile
set errRoot "Error in \"oncget $option...\""
if {[lsearch -exact $compile(delegatedoptions) $option] != -1} {
return -code error "$errRoot, option \"$option\" is delegated"
}
if {[lsearch -exact $compile(localoptions) $option] == -1} {
return -code error "$errRoot, option \"$option\" unknown"
}
# Next, add variable declarations to body:
set body "%TVARDECS%%IVARDECS%\n$body"
Comp.statement.method _cget$option {_option} $body
Comp.statement.option $option -cgetmethod _cget$option
}
# Defines an option's configure handler.
proc ::snit::Comp.statement.onconfigure {option arglist body} {
variable compile
if {[lsearch -exact $compile(delegatedoptions) $option] != -1} {
return -code error "onconfigure $option: option \"$option\" is delegated"
}
if {[lsearch -exact $compile(localoptions) $option] == -1} {
return -code error "onconfigure $option: option \"$option\" unknown"
}
if {[llength $arglist] != 1} {
error \
"onconfigure $option handler should have one argument, got \"$arglist\""
}
CheckArgs "onconfigure $option" $arglist
# Next, add a magic reference to the option name
set arglist [concat _option $arglist]
Comp.statement.method _configure$option $arglist $body
Comp.statement.option $option -configuremethod _configure$option
}
# Defines an instance method.
proc ::snit::Comp.statement.method {method arglist body} {
variable compile
variable methodInfo
# FIRST, check the method name against previously defined
# methods.
Comp.CheckMethodName $method 0 ::snit::methodInfo \
"Error in \"method [list $method]...\""
if {[llength $method] > 1} {
set compile(hashierarchic) yes
}
# Remeber this method
lappend compile(localmethods) $method
CheckArgs "method [list $method]" $arglist
# Next, add magic references to type and self.
set arglist [concat type selfns win self $arglist]
# Next, add variable declarations to body:
set body "%TVARDECS%%IVARDECS%\n$body"
# Next, save the definition script.
if {[llength $method] == 1} {
set methodInfo($method) {0 "%t::Snit_method%m %t %n %w %s" ""}
Mappend compile(defs) {
proc %TYPE%::Snit_method%METHOD% %ARGLIST% %BODY%
} %METHOD% $method %ARGLIST% [list $arglist] %BODY% [list $body]
} else {
set methodInfo($method) {0 "%t::Snit_hmethod%j %t %n %w %s" ""}
Mappend compile(defs) {
proc %TYPE%::Snit_hmethod%JMETHOD% %ARGLIST% %BODY%
} %JMETHOD% [join $method _] %ARGLIST% [list $arglist] \
%BODY% [list $body]
}
}
# Check for name collisions; save prefix information.
#
# method The name of the method or typemethod.
# delFlag 1 if delegated, 0 otherwise.
# infoVar The fully qualified name of the array containing
# information about the defined methods.
# errRoot The root string for any error messages.
proc ::snit::Comp.CheckMethodName {method delFlag infoVar errRoot} {
upvar $infoVar methodInfo
# FIRST, make sure the method name is a valid Tcl list.
if {[catch {lindex $method 0}]} {
error "$errRoot, the name \"$method\" must have list syntax."
}
# NEXT, check whether we can define it.
if {![catch {set methodInfo($method)} data]} {
# We can't redefine methods with submethods.
if {[lindex $data 0] == 1} {
error "$errRoot, \"$method\" has submethods."
}
# You can't delegate a method that's defined locally,
# and you can't define a method locally if it's been delegated.
if {$delFlag && [string equal [lindex $data 2] ""]} {
error "$errRoot, \"$method\" has been defined locally."
} elseif {!$delFlag && ![string equal [lindex $data 2] ""]} {
error "$errRoot, \"$method\" has been delegated"
}
}
# Handle hierarchical case.
if {[llength $method] > 1} {
set prefix {}
set tokens $method
while {[llength $tokens] > 1} {
lappend prefix [lindex $tokens 0]
set tokens [lrange $tokens 1 end]
if {![catch {set methodInfo($prefix)} result]} {
# Prefix is known. If it's not a prefix, throw an
# error.
if {[lindex $result 0] == 0} {
error "$errRoot, \"$prefix\" has no submethods."
}
}
set methodInfo($prefix) [list 1]
}
}
}
# Defines a typemethod method.
proc ::snit::Comp.statement.typemethod {method arglist body} {
variable compile
variable typemethodInfo
# FIRST, check the typemethod name against previously defined
# typemethods.
Comp.CheckMethodName $method 0 ::snit::typemethodInfo \
"Error in \"typemethod [list $method]...\""
CheckArgs "typemethod $method" $arglist
# First, add magic reference to type.
set arglist [concat type $arglist]
# Next, add typevariable declarations to body:
set body "%TVARDECS%\n$body"
# Next, save the definition script
if {[llength $method] == 1} {
set typemethodInfo($method) {0 "%t::Snit_typemethod%m %t" ""}
Mappend compile(defs) {
proc %TYPE%::Snit_typemethod%METHOD% %ARGLIST% %BODY%
} %METHOD% $method %ARGLIST% [list $arglist] %BODY% [list $body]
} else {
set typemethodInfo($method) {0 "%t::Snit_htypemethod%j %t" ""}
Mappend compile(defs) {
proc %TYPE%::Snit_htypemethod%JMETHOD% %ARGLIST% %BODY%
} %JMETHOD% [join $method _] \
%ARGLIST% [list $arglist] %BODY% [list $body]
}
}
# Defines a type constructor.
proc ::snit::Comp.statement.typeconstructor {body} {
variable compile
if {"" != $compile(typeconstructor)} {
error "too many typeconstructors"
}
set compile(typeconstructor) $body
}
# Defines a static proc in the type's namespace.
proc ::snit::Comp.statement.proc {proc arglist body} {
variable compile
# If "ns" is defined, the proc can see instance variables.
if {[lsearch -exact $arglist selfns] != -1} {
# Next, add instance variable declarations to body:
set body "%IVARDECS%\n$body"
}
# The proc can always see typevariables.
set body "%TVARDECS%\n$body"
append compile(defs) "
# Proc $proc
proc [list %TYPE%::$proc $arglist $body]
"
}
# Defines a static variable in the type's namespace.
proc ::snit::Comp.statement.typevariable {name args} {
variable compile
set errRoot "Error in \"typevariable $name...\""
set len [llength $args]
if {$len > 2 ||
($len == 2 && ![string equal [lindex $args 0] "-array"])} {
error "$errRoot, too many initializers"
}
if {[lsearch -exact $compile(varnames) $name] != -1} {
error "$errRoot, \"$name\" is already an instance variable"
}
lappend compile(typevarnames) $name
if {$len == 1} {
append compile(typevars) \
"\n\t [list ::variable $name [lindex $args 0]]"
} elseif {$len == 2} {
append compile(typevars) \
"\n\t [list ::variable $name]"
append compile(typevars) \
"\n\t [list array set $name [lindex $args 1]]"
} else {
append compile(typevars) \
"\n\t [list ::variable $name]"
}
append compile(tvprocdec) "\n\t typevariable ${name}"
}
# Defines an instance variable; the definition will go in the
# type's create typemethod.
proc ::snit::Comp.statement.variable {name args} {
variable compile
set errRoot "Error in \"variable $name...\""
set len [llength $args]
if {$len > 2 ||
($len == 2 && ![string equal [lindex $args 0] "-array"])} {
error "$errRoot, too many initializers"
}
if {[lsearch -exact $compile(typevarnames) $name] != -1} {
error "$errRoot, \"$name\" is already a typevariable"
}
lappend compile(varnames) $name
if {$len == 1} {
append compile(instancevars) \
"\nset \${selfns}::$name [list [lindex $args 0]]\n"
} elseif {$len == 2} {
append compile(instancevars) \
"\narray set \${selfns}::$name [list [lindex $args 1]]\n"
}
append compile(ivprocdec) "\n\t "
Mappend compile(ivprocdec) {::variable ${selfns}::%N} %N $name
}
# Defines a typecomponent, and handles component options.
#
# component The logical name of the delegate
# args options.
proc ::snit::Comp.statement.typecomponent {component args} {
variable compile
set errRoot "Error in \"typecomponent $component...\""
# FIRST, define the component
Comp.DefineTypecomponent $component $errRoot
# NEXT, handle the options.
set publicMethod ""
set inheritFlag 0
foreach {opt val} $args {
switch -exact -- $opt {
-public {
set publicMethod $val
}
-inherit {
set inheritFlag $val
if {![string is boolean $inheritFlag]} {
error "typecomponent $component -inherit: expected boolean value, got \"$val\""
}
}
default {
error "typecomponent $component: Invalid option \"$opt\""
}
}
}
# NEXT, if -public specified, define the method.
if {![string equal $publicMethod ""]} {
Comp.statement.delegate typemethod [list $publicMethod *] to $component
}
# NEXT, if "-inherit 1" is specified, delegate typemethod * to
# this component.
if {$inheritFlag} {
Comp.statement.delegate typemethod "*" to $component
}
}
# Defines a name to be a typecomponent
#
# The name becomes a typevariable; in addition, it gets a
# write trace so that when it is set, all of the component mechanisms
# get updated.
#
# component The component name
proc ::snit::Comp.DefineTypecomponent {component {errRoot "Error"}} {
variable compile
if {[lsearch -exact $compile(varnames) $component] != -1} {
error "$errRoot, \"$component\" is already an instance variable"
}
if {[lsearch -exact $compile(typecomponents) $component] == -1} {
# Remember we've done this.
lappend compile(typecomponents) $component
# Make it a type variable with no initial value
Comp.statement.typevariable $component ""
# Add a write trace to do the component thing.
Mappend compile(typevars) {
trace variable %COMP% w \
[list ::snit::RT.TypecomponentTrace [list %TYPE%] %COMP%]
} %TYPE% $compile(type) %COMP% $component
}
}
# Defines a component, and handles component options.
#
# component The logical name of the delegate
# args options.
#
# TBD: Ideally, it should be possible to call this statement multiple
# times, possibly changing the option values. To do that, I'd need
# to cache the option values and not act on them until *after* I'd
# read the entire type definition.
proc ::snit::Comp.statement.component {component args} {
variable compile
set errRoot "Error in \"component $component...\""
# FIRST, define the component
Comp.DefineComponent $component $errRoot
# NEXT, handle the options.
set publicMethod ""
set inheritFlag 0
foreach {opt val} $args {
switch -exact -- $opt {
-public {
set publicMethod $val
}
-inherit {
set inheritFlag $val
if {![string is boolean $inheritFlag]} {
error "component $component -inherit: expected boolean value, got \"$val\""
}
}
default {
error "component $component: Invalid option \"$opt\""
}
}
}
# NEXT, if -public specified, define the method.
if {![string equal $publicMethod ""]} {
Comp.statement.delegate method [list $publicMethod *] to $component
}
# NEXT, if -inherit is specified, delegate method/option * to
# this component.
if {$inheritFlag} {
Comp.statement.delegate method "*" to $component
Comp.statement.delegate option "*" to $component
}
}
# Defines a name to be a component
#
# The name becomes an instance variable; in addition, it gets a
# write trace so that when it is set, all of the component mechanisms
# get updated.
#
# component The component name
proc ::snit::Comp.DefineComponent {component {errRoot "Error"}} {
variable compile
if {[lsearch -exact $compile(typevarnames) $component] != -1} {
error "$errRoot, \"$component\" is already a typevariable"
}
if {[lsearch -exact $compile(components) $component] == -1} {
# Remember we've done this.
lappend compile(components) $component
# Make it an instance variable with no initial value
Comp.statement.variable $component ""
# Add a write trace to do the component thing.
Mappend compile(instancevars) {
trace variable ${selfns}::%COMP% w \
[list ::snit::RT.ComponentTrace [list %TYPE%] $selfns %COMP%]
} %TYPE% $compile(type) %COMP% $component
}
}
# Creates a delegated method, typemethod, or option.
proc ::snit::Comp.statement.delegate {what name args} {
# FIRST, dispatch to correct handler.
switch $what {
typemethod { Comp.DelegatedTypemethod $name $args }
method { Comp.DelegatedMethod $name $args }
option { Comp.DelegatedOption $name $args }
default {
error "Error in \"delegate $what $name...\", \"$what\"?"
}
}
if {([llength $args] % 2) != 0} {
error "Error in \"delegate $what $name...\", invalid syntax"
}
}
# Creates a delegated typemethod delegating it to a particular
# typecomponent or an arbitrary command.
#
# method The name of the method
# arglist Delegation options
proc ::snit::Comp.DelegatedTypemethod {method arglist} {
variable compile
variable typemethodInfo
set errRoot "Error in \"delegate typemethod [list $method]...\""
# Next, parse the delegation options.
set component ""
set target ""
set exceptions {}
set pattern ""
set methodTail [lindex $method end]
foreach {opt value} $arglist {
switch -exact $opt {
to { set component $value }
as { set target $value }
except { set exceptions $value }
using { set pattern $value }
default {
error "$errRoot, unknown delegation option \"$opt\""
}
}
}
if {[string equal $component ""] && [string equal $pattern ""]} {
error "$errRoot, missing \"to\""
}
if {[string equal $methodTail "*"] && ![string equal $target ""]} {
error "$errRoot, cannot specify \"as\" with \"*\""
}
if {![string equal $methodTail "*"] && ![string equal $exceptions ""]} {
error "$errRoot, can only specify \"except\" with \"*\""
}
if {![string equal $pattern ""] && ![string equal $target ""]} {
error "$errRoot, cannot specify both \"as\" and \"using\""
}
foreach token [lrange $method 1 end-1] {
if {[string equal $token "*"]} {
error "$errRoot, \"*\" must be the last token."
}
}
# NEXT, define the component
if {![string equal $component ""]} {
Comp.DefineTypecomponent $component $errRoot
}
# NEXT, define the pattern.
if {[string equal $pattern ""]} {
if {[string equal $methodTail "*"]} {
set pattern "%c %m"
} elseif {![string equal $target ""]} {
set pattern "%c $target"
} else {
set pattern "%c %m"
}
}
# Make sure the pattern is a valid list.
if {[catch {lindex $pattern 0} result]} {
error "$errRoot, the using pattern, \"$pattern\", is not a valid list"
}
# NEXT, check the method name against previously defined
# methods.
Comp.CheckMethodName $method 1 ::snit::typemethodInfo $errRoot
set typemethodInfo($method) [list 0 $pattern $component]
if {[string equal $methodTail "*"]} {
Mappend compile(defs) {
set %TYPE%::Snit_info(excepttypemethods) %EXCEPT%
} %EXCEPT% [list $exceptions]
}
}
# Creates a delegated method delegating it to a particular
# component or command.
#
# method The name of the method
# arglist Delegation options.
proc ::snit::Comp.DelegatedMethod {method arglist} {
variable compile
variable methodInfo
set errRoot "Error in \"delegate method [list $method]...\""
# Next, parse the delegation options.
set component ""
set target ""
set exceptions {}
set pattern ""
set methodTail [lindex $method end]
foreach {opt value} $arglist {
switch -exact $opt {
to { set component $value }
as { set target $value }
except { set exceptions $value }
using { set pattern $value }
default {
error "$errRoot, unknown delegation option \"$opt\""
}
}
}
if {[string equal $component ""] && [string equal $pattern ""]} {
error "$errRoot, missing \"to\""
}
if {[string equal $methodTail "*"] && ![string equal $target ""]} {
error "$errRoot, cannot specify \"as\" with \"*\""
}
if {![string equal $methodTail "*"] && ![string equal $exceptions ""]} {
error "$errRoot, can only specify \"except\" with \"*\""
}
if {![string equal $pattern ""] &&![string equal $target ""]} {
error "$errRoot, cannot specify both \"as\" and \"using\""
}
foreach token [lrange $method 1 end-1] {
if {[string equal $token "*"]} {
error "$errRoot, \"*\" must be the last token."
}
}
# NEXT, we delegate some methods
set compile(delegatesmethods) yes
# NEXT, define the component. Allow typecomponents.
if {![string equal $component ""]} {
if {[lsearch -exact $compile(typecomponents) $component] == -1} {
Comp.DefineComponent $component $errRoot
}
}
# NEXT, define the pattern.
if {[string equal $pattern ""]} {
if {[string equal $methodTail "*"]} {
set pattern "%c %m"
} elseif {![string equal $target ""]} {
set pattern "%c $target"
} else {
set pattern "%c %m"
}
}
# Make sure the pattern is a valid list.
if {[catch {lindex $pattern 0} result]} {
error "$errRoot, the using pattern, \"$pattern\", is not a valid list"
}
# NEXT, check the method name against previously defined
# methods.
Comp.CheckMethodName $method 1 ::snit::methodInfo $errRoot
# NEXT, save the method info.
set methodInfo($method) [list 0 $pattern $component]
if {[string equal $methodTail "*"]} {
Mappend compile(defs) {
set %TYPE%::Snit_info(exceptmethods) %EXCEPT%
} %EXCEPT% [list $exceptions]
}
}
# Creates a delegated option, delegating it to a particular
# component and, optionally, to a particular option of that
# component.
#
# optionDef The option definition
# args definition arguments.
proc ::snit::Comp.DelegatedOption {optionDef arglist} {
variable compile
# First, get the three option names.
set option [lindex $optionDef 0]
set resourceName [lindex $optionDef 1]
set className [lindex $optionDef 2]
set errRoot "Error in \"delegate option [list $optionDef]...\""
# Next, parse the delegation options.
set component ""
set target ""
set exceptions {}
foreach {opt value} $arglist {
switch -exact $opt {
to { set component $value }
as { set target $value }
except { set exceptions $value }
default {
error "$errRoot, unknown delegation option \"$opt\""
}
}
}
if {[string equal $component ""]} {
error "$errRoot, missing \"to\""
}
if {[string equal $option "*"] && ![string equal $target ""]} {
error "$errRoot, cannot specify \"as\" with \"delegate option *\""
}
if {![string equal $option "*"] && ![string equal $exceptions ""]} {
error "$errRoot, can only specify \"except\" with \"delegate option *\""
}
# Next, validate the option name
if {"*" != $option} {
if {![Comp.OptionNameIsValid $option]} {
error "$errRoot, badly named option \"$option\""
}
}
if {[Contains $option $compile(localoptions)]} {
error "$errRoot, \"$option\" has been defined locally"
}
if {[Contains $option $compile(delegatedoptions)]} {
error "$errRoot, \"$option\" is multiply delegated"
}
# NEXT, define the component
Comp.DefineComponent $component $errRoot
# Next, define the target option, if not specified.
if {![string equal $option "*"] &&
[string equal $target ""]} {
set target $option
}
# NEXT, save the delegation data.
set compile(hasoptions) yes
if {![string equal $option "*"]} {
lappend compile(delegatedoptions) $option
# Next, compute the resource and class names, if they aren't
# already defined.
if {"" == $resourceName} {
set resourceName [string range $option 1 end]
}
if {"" == $className} {
set className [Capitalize $resourceName]
}
Mappend compile(defs) {
set %TYPE%::Snit_optionInfo(islocal-%OPTION%) 0
set %TYPE%::Snit_optionInfo(resource-%OPTION%) %RES%
set %TYPE%::Snit_optionInfo(class-%OPTION%) %CLASS%
lappend %TYPE%::Snit_optionInfo(delegated) %OPTION%
set %TYPE%::Snit_optionInfo(target-%OPTION%) [list %COMP% %TARGET%]
lappend %TYPE%::Snit_optionInfo(delegated-%COMP%) %OPTION%
} %OPTION% $option \
%COMP% $component \
%TARGET% $target \
%RES% $resourceName \
%CLASS% $className
} else {
Mappend compile(defs) {
set %TYPE%::Snit_optionInfo(starcomp) %COMP%
set %TYPE%::Snit_optionInfo(except) %EXCEPT%
} %COMP% $component %EXCEPT% [list $exceptions]
}
}
# Exposes a component, effectively making the component's command an
# instance method.
#
# component The logical name of the delegate
# "as" sugar; if not "", must be "as"
# methodname The desired method name for the component's command, or ""
proc ::snit::Comp.statement.expose {component {"as" ""} {methodname ""}} {
variable compile
# FIRST, define the component
Comp.DefineComponent $component
# NEXT, define the method just as though it were in the type
# definition.
if {[string equal $methodname ""]} {
set methodname $component
}
Comp.statement.method $methodname args [Expand {
if {[llength $args] == 0} {
return $%COMPONENT%
}
if {[string equal $%COMPONENT% ""]} {
error "undefined component \"%COMPONENT%\""
}
set cmd [linsert $args 0 $%COMPONENT%]
return [uplevel 1 $cmd]
} %COMPONENT% $component]
}
#-----------------------------------------------------------------------
# Public commands
# Compile a type definition, and return the results as a list of two
# items: the fully-qualified type name, and a script that will define
# the type when executed.
#
# which type, widget, or widgetadaptor
# type the type name
# body the type definition
proc ::snit::compile {which type body} {
return [Comp.Compile $which $type $body]
}
proc ::snit::type {type body} {
return [Comp.Define [Comp.Compile type $type $body]]
}
proc ::snit::widget {type body} {
return [Comp.Define [Comp.Compile widget $type $body]]
}
proc ::snit::widgetadaptor {type body} {
return [Comp.Define [Comp.Compile widgetadaptor $type $body]]
}
proc ::snit::typemethod {type method arglist body} {
# Make sure the type exists.
if {![info exists ${type}::Snit_info]} {
error "no such type: \"$type\""
}
upvar ${type}::Snit_info Snit_info
upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo
# FIRST, check the typemethod name against previously defined
# typemethods.
Comp.CheckMethodName $method 0 ${type}::Snit_typemethodInfo \
"Cannot define \"$method\""
# NEXT, check the arguments
CheckArgs "snit::typemethod $type $method" $arglist
# Next, add magic reference to type.
set arglist [concat type $arglist]
# Next, add typevariable declarations to body:
set body "$Snit_info(tvardecs)\n$body"
# Next, define it.
if {[llength $method] == 1} {
set Snit_typemethodInfo($method) {0 "%t::Snit_typemethod%m %t" ""}
uplevel 1 [list proc ${type}::Snit_typemethod$method $arglist $body]
} else {
set Snit_typemethodInfo($method) {0 "%t::Snit_htypemethod%j %t" ""}
set suffix [join $method _]
uplevel 1 [list proc ${type}::Snit_htypemethod$suffix $arglist $body]
}
}
proc ::snit::method {type method arglist body} {
# Make sure the type exists.
if {![info exists ${type}::Snit_info]} {
error "no such type: \"$type\""
}
upvar ${type}::Snit_methodInfo Snit_methodInfo
upvar ${type}::Snit_info Snit_info
# FIRST, check the method name against previously defined
# methods.
Comp.CheckMethodName $method 0 ${type}::Snit_methodInfo \
"Cannot define \"$method\""
# NEXT, check the arguments
CheckArgs "snit::method $type $method" $arglist
# Next, add magic references to type and self.
set arglist [concat type selfns win self $arglist]
# Next, add variable declarations to body:
set body "$Snit_info(tvardecs)$Snit_info(ivardecs)\n$body"
# Next, define it.
if {[llength $method] == 1} {
set Snit_methodInfo($method) {0 "%t::Snit_method%m %t %n %w %s" ""}
uplevel 1 [list proc ${type}::Snit_method$method $arglist $body]
} else {
set Snit_methodInfo($method) {0 "%t::Snit_hmethod%j %t %n %w %s" ""}
set suffix [join $method _]
uplevel 1 [list proc ${type}::Snit_hmethod$suffix $arglist $body]
}
}
# Defines a proc within the compiler; this proc can call other
# type definition statements, and thus can be used for meta-programming.
proc ::snit::macro {name arglist body} {
variable compiler
variable reservedwords
# FIRST, make sure the compiler is defined.
Comp.Init
# NEXT, check the macro name against the reserved words
if {[lsearch -exact $reservedwords $name] != -1} {
error "invalid macro name \"$name\""
}
# NEXT, see if the name has a namespace; if it does, define the
# namespace.
set ns [namespace qualifiers $name]
if {![string equal $ns ""]} {
$compiler eval "namespace eval $ns {}"
}
# NEXT, define the macro
$compiler eval [list _proc $name $arglist $body]
}
#-----------------------------------------------------------------------
# Utility Functions
#
# These are utility functions used while compiling Snit types.
# Builds a template from a tagged list of text blocks, then substitutes
# all symbols in the mapTable, returning the expanded template.
proc ::snit::Expand {template args} {
return [string map $args $template]
}
# Expands a template and appends it to a variable.
proc ::snit::Mappend {varname template args} {
upvar $varname myvar
append myvar [string map $args $template]
}
# Checks argument list against reserved args
proc ::snit::CheckArgs {which arglist} {
variable reservedArgs
foreach name $reservedArgs {
if {[Contains $name $arglist]} {
error "$which's arglist may not contain \"$name\" explicitly"
}
}
}
# Returns 1 if a value is in a list, and 0 otherwise.
proc ::snit::Contains {value list} {
if {[lsearch -exact $list $value] != -1} {
return 1
} else {
return 0
}
}
# Capitalizes the first letter of a string.
proc ::snit::Capitalize {text} {
set first [string index $text 0]
set rest [string range $text 1 end]
return "[string toupper $first]$rest"
}
# Converts an arbitrary white-space-delimited string into a list
# by splitting on white-space and deleting empty tokens.
proc ::snit::Listify {str} {
set result {}
foreach token [split [string trim $str]] {
if {[string length $token] > 0} {
lappend result $token
}
}
return $result
}
#=======================================================================
# Snit Runtime Library
#
# These are procs used by Snit types and widgets at runtime.
#-----------------------------------------------------------------------
# Object Creation
# Creates a new instance of the snit::type given its name and the args.
#
# type The snit::type
# name The instance name
# args Args to pass to the constructor
proc ::snit::RT.type.typemethod.create {type name args} {
variable ${type}::Snit_info
variable ${type}::Snit_optionInfo
# FIRST, qualify the name.
if {![string match "::*" $name]} {
# Get caller's namespace;
# append :: if not global namespace.
set ns [uplevel 1 [list namespace current]]
if {"::" != $ns} {
append ns "::"
}
set name "$ns$name"
}
# NEXT, if %AUTO% appears in the name, generate a unique
# command name. Otherwise, ensure that the name isn't in use.
if {[string match "*%AUTO%*" $name]} {
set name [::snit::RT.UniqueName Snit_info(counter) $type $name]
} elseif {$Snit_info(canreplace) && [llength [info commands $name]]} {
#kmg-tcl83
#
# Had to add this elseif branch to pass test rename-1.5
#
# Allowed to replace so must first destroy the prior instance
$name destroy
} elseif {!$Snit_info(canreplace) && [llength [info commands $name]]} {
error "command \"$name\" already exists"
}
# NEXT, create the instance's namespace.
set selfns \
[::snit::RT.UniqueInstanceNamespace Snit_info(counter) $type]
namespace eval $selfns {}
# NEXT, install the dispatcher
RT.MakeInstanceCommand $type $selfns $name
# Initialize the options to their defaults.
upvar ${selfns}::options options
foreach opt $Snit_optionInfo(local) {
set options($opt) $Snit_optionInfo(default-$opt)
}
# Initialize the instance vars to their defaults.
# selfns must be defined, as it is used implicitly.
${type}::Snit_instanceVars $selfns
# Execute the type's constructor.
set errcode [catch {
RT.ConstructInstance $type $selfns $name $args
} result]
if {$errcode} {
global errorInfo
global errorCode
set theInfo $errorInfo
set theCode $errorCode
::snit::RT.DestroyObject $type $selfns $name
error "Error in constructor: $result" $theInfo $theCode
}
# NEXT, return the object's name.
return $name
}
# Creates a new instance of the snit::widget or snit::widgetadaptor
# given its name and the args.
#
# type The snit::widget or snit::widgetadaptor
# name The instance name
# args Args to pass to the constructor
proc ::snit::RT.widget.typemethod.create {type name args} {
variable ${type}::Snit_info
variable ${type}::Snit_optionInfo
# FIRST, if %AUTO% appears in the name, generate a unique
# command name.
if {[string match "*%AUTO%*" $name]} {
set name [::snit::RT.UniqueName Snit_info(counter) $type $name]
}
# NEXT, create the instance's namespace.
set selfns \
[::snit::RT.UniqueInstanceNamespace Snit_info(counter) $type]
namespace eval $selfns { }
# NEXT, Initialize the widget's own options to their defaults.
upvar ${selfns}::options options
foreach opt $Snit_optionInfo(local) {
set options($opt) $Snit_optionInfo(default-$opt)
}
# Initialize the instance vars to their defaults.
${type}::Snit_instanceVars $selfns
# NEXT, if this is a normal widget (not a widget adaptor) then
# create a frame as its hull. We set the frame's -class to
# the user's widgetclass, or, if none, to the basename of
# the $type with an initial upper case letter.
if {!$Snit_info(isWidgetAdaptor)} {
# FIRST, determine the class name
if {"" == $Snit_info(widgetclass)} {
set Snit_info(widgetclass) \
[::snit::Capitalize [namespace tail $type]]
}
# NEXT, create the widget
set self $name
package require Tk
${type}::installhull using \
$Snit_info(hulltype) -class $Snit_info(widgetclass)
# NEXT, let's query the option database for our
# widget, now that we know that it exists.
foreach opt $Snit_optionInfo(local) {
set dbval [RT.OptionDbGet $type $name $opt]
if {"" != $dbval} {
set options($opt) $dbval
}
}
}
# Execute the type's constructor, and verify that it
# has a hull.
set errcode [catch {
RT.ConstructInstance $type $selfns $name $args
::snit::RT.Component $type $selfns hull
# Prepare to call the object's destructor when the
# event is received. Use a Snit-specific bindtag
# so that the widget name's tag is unencumbered.
bind Snit$type$name [::snit::Expand {
::snit::RT.DestroyObject %TYPE% %NS% %W
} %TYPE% $type %NS% $selfns]
# Insert the bindtag into the list of bindtags right
# after the widget name.
set taglist [bindtags $name]
set ndx [lsearch -exact $taglist $name]
incr ndx
bindtags $name [linsert $taglist $ndx Snit$type$name]
} result]
if {$errcode} {
global errorInfo
global errorCode
set theInfo $errorInfo
set theCode $errorCode
::snit::RT.DestroyObject $type $selfns $name
error "Error in constructor: $result" $theInfo $theCode
}
# NEXT, return the object's name.
return $name
}
# RT.MakeInstanceCommand type selfns instance
#
# type The object type
# selfns The instance namespace
# instance The instance name
#
# Creates the instance proc.
proc ::snit::RT.MakeInstanceCommand {type selfns instance} {
variable ${type}::Snit_info
# FIRST, remember the instance name. The Snit_instance variable
# allows the instance to figure out its current name given the
# instance namespace.
upvar ${selfns}::Snit_instance Snit_instance
set Snit_instance $instance
# NEXT, qualify the proc name if it's a widget.
if {$Snit_info(isWidget)} {
set procname ::$instance
} else {
set procname $instance
}
# NEXT, install the new proc
if {!$Snit_info(simpledispatch)} {
set instanceProc $::snit::nominalInstanceProc
} else {
set instanceProc $::snit::simpleInstanceProc
}
proc $procname {method args} \
[string map \
[list %SELFNS% $selfns %WIN% $instance %TYPE% $type] \
$instanceProc]
#kmg-tcl83
# NEXT, add the trace.
::snit83::traceAddCommand $procname {rename delete} \
[list ::snit::RT.InstanceTrace $type $selfns $instance]
}
# This proc is called when the instance command is renamed.
# If op is delete, then new will always be "", so op is redundant.
#
# type The fully-qualified type name
# selfns The instance namespace
# win The original instance/tk window name.
# old old instance command name
# new new instance command name
# op rename or delete
#
# If the op is delete, we need to clean up the object; otherwise,
# we need to track the change.
#
# NOTE: In Tcl 8.4.2 there's a bug: errors in rename and delete
# traces aren't propagated correctly. Instead, they silently
# vanish. Add a catch to output any error message.
proc ::snit::RT.InstanceTrace {type selfns win old new op} {
variable ${type}::Snit_info
# Note to developers ...
# For Tcl 8.4.0, errors thrown in trace handlers vanish silently.
# Therefore we catch them here and create some output to help in
# debugging such problems.
if {[catch {
# FIRST, clean up if necessary
if {"" == $new} {
if {$Snit_info(isWidget)} {
destroy $win
} else {
::snit::RT.DestroyObject $type $selfns $win
}
} else {
# Otherwise, track the change.
variable ${selfns}::Snit_instance
set Snit_instance [uplevel 1 [list namespace which -command $new]]
# Also, clear the instance caches, as many cached commands
# might be invalid.
RT.ClearInstanceCaches $selfns
}
} result]} {
global errorInfo
# Pop up the console on Windows wish, to enable stdout.
# This clobbers errorInfo on unix, so save it so we can print it.
set ei $errorInfo
catch {console show}
puts "Error in ::snit::RT.InstanceTrace $type $selfns $win $old $new $op:"
puts $ei
}
}
# Calls the instance constructor and handles related housekeeping.
proc ::snit::RT.ConstructInstance {type selfns instance arglist} {
variable ${type}::Snit_optionInfo
variable ${selfns}::Snit_iinfo
# Track whether we are constructed or not.
set Snit_iinfo(constructed) 0
# Call the user's constructor
eval [linsert $arglist 0 \
${type}::Snit_constructor $type $selfns $instance $instance]
set Snit_iinfo(constructed) 1
# Unset the configure cache for all -readonly options.
# This ensures that the next time anyone tries to
# configure it, an error is thrown.
foreach opt $Snit_optionInfo(local) {
if {$Snit_optionInfo(readonly-$opt)} {
::snit83::unset -nocomplain ${selfns}::Snit_configureCache($opt)
}
}
return
}
# Returns a unique command name.
#
# REQUIRE: type is a fully qualified name.
# REQUIRE: name contains "%AUTO%"
# PROMISE: the returned command name is unused.
proc ::snit::RT.UniqueName {countervar type name} {
upvar $countervar counter
while 1 {
# FIRST, bump the counter and define the %AUTO% instance name;
# then substitute it into the specified name. Wrap around at
# 2^31 - 2 to prevent overflow problems.
incr counter
if {$counter > 2147483646} {
set counter 0
}
set auto "[namespace tail $type]$counter"
set candidate [Expand $name %AUTO% $auto]
if {![llength [info commands $candidate]]} {
return $candidate
}
}
}
# Returns a unique instance namespace, fully qualified.
#
# countervar The name of a counter variable
# type The instance's type
#
# REQUIRE: type is fully qualified
# PROMISE: The returned namespace name is unused.
proc ::snit::RT.UniqueInstanceNamespace {countervar type} {
upvar $countervar counter
while 1 {
# FIRST, bump the counter and define the namespace name.
# Then see if it already exists. Wrap around at
# 2^31 - 2 to prevent overflow problems.
incr counter
if {$counter > 2147483646} {
set counter 0
}
set ins "${type}::Snit_inst${counter}"
if {![namespace exists $ins]} {
return $ins
}
}
}
# Retrieves an option's value from the option database.
# Returns "" if no value is found.
proc ::snit::RT.OptionDbGet {type self opt} {
variable ${type}::Snit_optionInfo
return [option get $self \
$Snit_optionInfo(resource-$opt) \
$Snit_optionInfo(class-$opt)]
}
#-----------------------------------------------------------------------
# Object Destruction
# Implements the standard "destroy" method
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
proc ::snit::RT.method.destroy {type selfns win self} {
variable ${selfns}::Snit_iinfo
# Can't destroy the object if it isn't complete constructed.
if {!$Snit_iinfo(constructed)} {
return -code error "Called 'destroy' method in constructor"
}
# Calls Snit_cleanup, which (among other things) calls the
# user's destructor.
::snit::RT.DestroyObject $type $selfns $win
}
# This is the function that really cleans up; it's automatically
# called when any instance is destroyed, e.g., by "$object destroy"
# for types, and by the event for widgets.
#
# type The fully-qualified type name.
# selfns The instance namespace
# win The original instance command name.
proc ::snit::RT.DestroyObject {type selfns win} {
variable ${type}::Snit_info
# If the variable Snit_instance doesn't exist then there's no
# instance command for this object -- it's most likely a
# widgetadaptor. Consequently, there are some things that
# we don't need to do.
if {[info exists ${selfns}::Snit_instance]} {
upvar ${selfns}::Snit_instance instance
# First, remove the trace on the instance name, so that we
# don't call RT.DestroyObject recursively.
RT.RemoveInstanceTrace $type $selfns $win $instance
# Next, call the user's destructor
${type}::Snit_destructor $type $selfns $win $instance
# Next, if this isn't a widget, delete the instance command.
# If it is a widget, get the hull component's name, and rename
# it back to the widget name
# Next, delete the hull component's instance command,
# if there is one.
if {$Snit_info(isWidget)} {
set hullcmd [::snit::RT.Component $type $selfns hull]
catch {rename $instance ""}
# Clear the bind event
bind Snit$type$win ""
if {[llength [info commands $hullcmd]]} {
# FIRST, rename the hull back to its original name.
# If the hull is itself a megawidget, it will have its
# own cleanup to do, and it might not do it properly
# if it doesn't have the right name.
rename $hullcmd ::$instance
# NEXT, destroy it.
destroy $instance
}
} else {
catch {rename $instance ""}
}
}
# Next, delete the instance's namespace. This kills any
# instance variables.
namespace delete $selfns
}
# Remove instance trace
#
# type The fully qualified type name
# selfns The instance namespace
# win The original instance name/Tk window name
# instance The current instance name
proc ::snit::RT.RemoveInstanceTrace {type selfns win instance} {
variable ${type}::Snit_info
if {$Snit_info(isWidget)} {
set procname ::$instance
} else {
set procname $instance
}
# NEXT, remove any trace on this name
catch {
#kmg-tcl83
::snit83::traceRemoveCommand $procname {rename delete} \
[list ::snit::RT.InstanceTrace $type $selfns $win]
}
}
#-----------------------------------------------------------------------
# Typecomponent Management and Method Caching
# Typecomponent trace; used for write trace on typecomponent
# variables. Saves the new component object name, provided
# that certain conditions are met. Also clears the typemethod
# cache.
proc ::snit::RT.TypecomponentTrace {type component n1 n2 op} {
upvar ${type}::Snit_info Snit_info
upvar ${type}::${component} cvar
upvar ${type}::Snit_typecomponents Snit_typecomponents
# Save the new component value.
set Snit_typecomponents($component) $cvar
# Clear the typemethod cache.
# TBD: can we unset just the elements related to
# this component?
::snit83::unset -nocomplain -- ${type}::Snit_typemethodCache
}
# Generates and caches the command for a typemethod.
#
# type The type
# method The name of the typemethod to call.
#
# The return value is one of the following lists:
#
# {} There's no such method.
# {1} The method has submethods; look again.
# {0 } Here's the command to execute.
proc snit::RT.CacheTypemethodCommand {type method} {
upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo
upvar ${type}::Snit_typecomponents Snit_typecomponents
upvar ${type}::Snit_typemethodCache Snit_typemethodCache
upvar ${type}::Snit_info Snit_info
# FIRST, get the pattern data and the typecomponent name.
set implicitCreate 0
set instanceName ""
set starredMethod [lreplace $method end end *]
set methodTail [lindex $method end]
if {[info exists Snit_typemethodInfo($method)]} {
set key $method
} elseif {[info exists Snit_typemethodInfo($starredMethod)]} {
if {[lsearch -exact $Snit_info(excepttypemethods) $methodTail] == -1} {
set key $starredMethod
} else {
return [list ]
}
} elseif {$Snit_info(hasinstances)} {
# Assume the unknown name is an instance name to create, unless
# this is a widget and the style of the name is wrong, or the
# name mimics a standard typemethod.
if {[set ${type}::Snit_info(isWidget)] &&
![string match ".*" $method]} {
return [list ]
}
# Without this check, the call "$type info" will redefine the
# standard "::info" command, with disastrous results. Since it's
# a likely thing to do if !-typeinfo, put in an explicit check.
if {[string equal $method "info"] || [string equal $method "destroy"]} {
return [list ]
}
set implicitCreate 1
set instanceName $method
set key create
set method create
} else {
return [list ]
}
foreach {flag pattern compName} $Snit_typemethodInfo($key) {}
if {$flag == 1} {
return [list 1]
}
# NEXT, build the substitution list
set subList [list \
%% % \
%t $type \
%M $method \
%m [lindex $method end] \
%j [join $method _]]
if {![string equal $compName ""]} {
if {![info exists Snit_typecomponents($compName)]} {
error "$type delegates typemethod \"$method\" to undefined typecomponent \"$compName\""
}
lappend subList %c [list $Snit_typecomponents($compName)]
}
set command {}
foreach subpattern $pattern {
lappend command [string map $subList $subpattern]
}
if {$implicitCreate} {
# In this case, $method is the name of the instance to
# create. Don't cache, as we usually won't do this one
# again.
lappend command $instanceName
} else {
set Snit_typemethodCache($method) [list 0 $command]
}
return [list 0 $command]
}
#-----------------------------------------------------------------------
# Component Management and Method Caching
# Retrieves the object name given the component name.
proc ::snit::RT.Component {type selfns name} {
variable ${selfns}::Snit_components
if {[catch {set Snit_components($name)} result]} {
variable ${selfns}::Snit_instance
error "component \"$name\" is undefined in $type $Snit_instance"
}
return $result
}
# Component trace; used for write trace on component instance
# variables. Saves the new component object name, provided
# that certain conditions are met. Also clears the method
# cache.
proc ::snit::RT.ComponentTrace {type selfns component n1 n2 op} {
upvar ${type}::Snit_info Snit_info
upvar ${selfns}::${component} cvar
upvar ${selfns}::Snit_components Snit_components
# If they try to redefine the hull component after
# it's been defined, that's an error--but only if
# this is a widget or widget adaptor.
if {"hull" == $component &&
$Snit_info(isWidget) &&
[info exists Snit_components($component)]} {
set cvar $Snit_components($component)
error "The hull component cannot be redefined"
}
# Save the new component value.
set Snit_components($component) $cvar
# Clear the instance caches.
# TBD: can we unset just the elements related to
# this component?
RT.ClearInstanceCaches $selfns
}
# Generates and caches the command for a method.
#
# type: The instance's type
# selfns: The instance's private namespace
# win: The instance's original name (a Tk widget name, for
# snit::widgets.
# self: The instance's current name.
# method: The name of the method to call.
#
# The return value is one of the following lists:
#
# {} There's no such method.
# {1} The method has submethods; look again.
# {0 } Here's the command to execute.
proc ::snit::RT.CacheMethodCommand {type selfns win self method} {
variable ${type}::Snit_info
variable ${type}::Snit_methodInfo
variable ${type}::Snit_typecomponents
variable ${selfns}::Snit_components
variable ${selfns}::Snit_methodCache
# FIRST, get the pattern data and the component name.
set starredMethod [lreplace $method end end *]
set methodTail [lindex $method end]
if {[info exists Snit_methodInfo($method)]} {
set key $method
} elseif {[info exists Snit_methodInfo($starredMethod)] &&
[lsearch -exact $Snit_info(exceptmethods) $methodTail] == -1} {
set key $starredMethod
} else {
return [list ]
}
foreach {flag pattern compName} $Snit_methodInfo($key) {}
if {$flag == 1} {
return [list 1]
}
# NEXT, build the substitution list
set subList [list \
%% % \
%t $type \
%M $method \
%m [lindex $method end] \
%j [join $method _] \
%n [list $selfns] \
%w [list $win] \
%s [list $self]]
if {![string equal $compName ""]} {
if {[info exists Snit_components($compName)]} {
set compCmd $Snit_components($compName)
} elseif {[info exists Snit_typecomponents($compName)]} {
set compCmd $Snit_typecomponents($compName)
} else {
error "$type $self delegates method \"$method\" to undefined component \"$compName\""
}
lappend subList %c [list $compCmd]
}
# Note: The cached command will executed faster if it's
# already a list.
set command {}
foreach subpattern $pattern {
lappend command [string map $subList $subpattern]
}
set commandRec [list 0 $command]
set Snit_methodCache($method) $commandRec
return $commandRec
}
# Looks up a method's command.
#
# type: The instance's type
# selfns: The instance's private namespace
# win: The instance's original name (a Tk widget name, for
# snit::widgets.
# self: The instance's current name.
# method: The name of the method to call.
# errPrefix: Prefix for any error method
proc ::snit::RT.LookupMethodCommand {type selfns win self method errPrefix} {
set commandRec [snit::RT.CacheMethodCommand \
$type $selfns $win $self \
$method]
if {[llength $commandRec] == 0} {
return -code error \
"$errPrefix, \"$self $method\" is not defined"
} elseif {[lindex $commandRec 0] == 1} {
return -code error \
"$errPrefix, wrong number args: should be \"$self\" $method method args"
}
return [lindex $commandRec 1]
}
# Clears all instance command caches
proc ::snit::RT.ClearInstanceCaches {selfns} {
::snit83::unset -nocomplain -- ${selfns}::Snit_methodCache
::snit83::unset -nocomplain -- ${selfns}::Snit_cgetCache
::snit83::unset -nocomplain -- ${selfns}::Snit_configureCache
::snit83::unset -nocomplain -- ${selfns}::Snit_validateCache
}
#-----------------------------------------------------------------------
# Component Installation
# Implements %TYPE%::installhull. The variables self and selfns
# must be defined in the caller's context.
#
# Installs the named widget as the hull of a
# widgetadaptor. Once the widget is hijacked, its new name
# is assigned to the hull component.
proc ::snit::RT.installhull {type {using "using"} {widgetType ""} args} {
variable ${type}::Snit_info
variable ${type}::Snit_optionInfo
upvar self self
upvar selfns selfns
upvar ${selfns}::hull hull
upvar ${selfns}::options options
# FIRST, make sure we can do it.
if {!$Snit_info(isWidget)} {
error "installhull is valid only for snit::widgetadaptors"
}
if {[info exists ${selfns}::Snit_instance]} {
error "hull already installed for $type $self"
}
# NEXT, has it been created yet? If not, create it using
# the specified arguments.
if {"using" == $using} {
# FIRST, create the widget
set cmd [linsert $args 0 $widgetType $self]
set obj [uplevel 1 $cmd]
# NEXT, for each option explicitly delegated to the hull
# that doesn't appear in the usedOpts list, get the
# option database value and apply it--provided that the
# real option name and the target option name are different.
# (If they are the same, then the option database was
# already queried as part of the normal widget creation.)
#
# Also, we don't need to worry about implicitly delegated
# options, as the option and target option names must be
# the same.
if {[info exists Snit_optionInfo(delegated-hull)]} {
# FIRST, extract all option names from args
set usedOpts {}
set ndx [lsearch -glob $args "-*"]
foreach {opt val} [lrange $args $ndx end] {
lappend usedOpts $opt
}
foreach opt $Snit_optionInfo(delegated-hull) {
set target [lindex $Snit_optionInfo(target-$opt) 1]
if {"$target" == $opt} {
continue
}
set result [lsearch -exact $usedOpts $target]
if {$result != -1} {
continue
}
set dbval [RT.OptionDbGet $type $self $opt]
$obj configure $target $dbval
}
}
} else {
set obj $using
if {![string equal $obj $self]} {
error \
"hull name mismatch: \"$obj\" != \"$self\""
}
}
# NEXT, get the local option defaults.
foreach opt $Snit_optionInfo(local) {
set dbval [RT.OptionDbGet $type $self $opt]
if {"" != $dbval} {
set options($opt) $dbval
}
}
# NEXT, do the magic
set i 0
while 1 {
incr i
set newName "::hull${i}$self"
if {![llength [info commands $newName]]} {
break
}
}
rename ::$self $newName
RT.MakeInstanceCommand $type $selfns $self
# Note: this relies on RT.ComponentTrace to do the dirty work.
set hull $newName
return
}
# Implements %TYPE%::install.
#
# Creates a widget and installs it as the named component.
# It expects self and selfns to be defined in the caller's context.
proc ::snit::RT.install {type compName "using" widgetType winPath args} {
variable ${type}::Snit_optionInfo
variable ${type}::Snit_info
upvar self self
upvar selfns selfns
upvar ${selfns}::$compName comp
upvar ${selfns}::hull hull
# We do the magic option database stuff only if $self is
# a widget.
if {$Snit_info(isWidget)} {
if {"" == $hull} {
error "tried to install \"$compName\" before the hull exists"
}
# FIRST, query the option database and save the results
# into args. Insert them before the first option in the
# list, in case there are any non-standard parameters.
#
# Note: there might not be any delegated options; if so,
# don't bother.
if {[info exists Snit_optionInfo(delegated-$compName)]} {
set ndx [lsearch -glob $args "-*"]
foreach opt $Snit_optionInfo(delegated-$compName) {
set dbval [RT.OptionDbGet $type $self $opt]
if {"" != $dbval} {
set target [lindex $Snit_optionInfo(target-$opt) 1]
set args [linsert $args $ndx $target $dbval]
}
}
}
}
# NEXT, create the component and save it.
set cmd [concat [list $widgetType $winPath] $args]
set comp [uplevel 1 $cmd]
# NEXT, handle the option database for "delegate option *",
# in widgets only.
if {$Snit_info(isWidget) && [string equal $Snit_optionInfo(starcomp) $compName]} {
# FIRST, get the list of option specs from the widget.
# If configure doesn't work, skip it.
if {[catch {$comp configure} specs]} {
return
}
# NEXT, get the set of explicitly used options from args
set usedOpts {}
set ndx [lsearch -glob $args "-*"]
foreach {opt val} [lrange $args $ndx end] {
lappend usedOpts $opt
}
# NEXT, "delegate option *" matches all options defined
# by this widget that aren't defined by the widget as a whole,
# and that aren't excepted. Plus, we skip usedOpts. So build
# a list of the options it can't match.
set skiplist [concat \
$usedOpts \
$Snit_optionInfo(except) \
$Snit_optionInfo(local) \
$Snit_optionInfo(delegated)]
# NEXT, loop over all of the component's options, and set
# any not in the skip list for which there is an option
# database value.
foreach spec $specs {
# Skip aliases
if {[llength $spec] != 5} {
continue
}
set opt [lindex $spec 0]
if {[lsearch -exact $skiplist $opt] != -1} {
continue
}
set res [lindex $spec 1]
set cls [lindex $spec 2]
set dbvalue [option get $self $res $cls]
if {"" != $dbvalue} {
$comp configure $opt $dbvalue
}
}
}
return
}
#-----------------------------------------------------------------------
# Method/Variable Name Qualification
# Implements %TYPE%::variable. Requires selfns.
proc ::snit::RT.variable {varname} {
upvar selfns selfns
if {![string match "::*" $varname]} {
uplevel 1 [list upvar 1 ${selfns}::$varname $varname]
} else {
# varname is fully qualified; let the standard
# "variable" command handle it.
uplevel 1 [list ::variable $varname]
}
}
# Fully qualifies a typevariable name.
#
# This is used to implement the mytypevar command.
proc ::snit::RT.mytypevar {type name} {
return ${type}::$name
}
# Fully qualifies an instance variable name.
#
# This is used to implement the myvar command.
proc ::snit::RT.myvar {name} {
upvar selfns selfns
return ${selfns}::$name
}
# Use this like "list" to convert a proc call into a command
# string to pass to another object (e.g., as a -command).
# Qualifies the proc name properly.
#
# This is used to implement the "myproc" command.
proc ::snit::RT.myproc {type procname args} {
set procname "${type}::$procname"
return [linsert $args 0 $procname]
}
# DEPRECATED
proc ::snit::RT.codename {type name} {
return "${type}::$name"
}
# Use this like "list" to convert a typemethod call into a command
# string to pass to another object (e.g., as a -command).
# Inserts the type command at the beginning.
#
# This is used to implement the "mytypemethod" command.
proc ::snit::RT.mytypemethod {type args} {
return [linsert $args 0 $type]
}
# Use this like "list" to convert a method call into a command
# string to pass to another object (e.g., as a -command).
# Inserts the code at the beginning to call the right object, even if
# the object's name has changed. Requires that selfns be defined
# in the calling context, eg. can only be called in instance
# code.
#
# This is used to implement the "mymethod" command.
proc ::snit::RT.mymethod {args} {
upvar selfns selfns
return [linsert $args 0 ::snit::RT.CallInstance ${selfns}]
}
# Calls an instance method for an object given its
# instance namespace and remaining arguments (the first of which
# will be the method name.
#
# selfns The instance namespace
# args The arguments
#
# Uses the selfns to determine $self, and calls the method
# in the normal way.
#
# This is used to implement the "mymethod" command.
proc ::snit::RT.CallInstance {selfns args} {
upvar ${selfns}::Snit_instance self
set retval [catch {uplevel 1 [linsert $args 0 $self]} result]
if {$retval} {
if {$retval == 1} {
global errorInfo
global errorCode
return -code error -errorinfo $errorInfo \
-errorcode $errorCode $result
} else {
return -code $retval $result
}
}
return $result
}
# Looks for the named option in the named variable. If found,
# it and its value are removed from the list, and the value
# is returned. Otherwise, the default value is returned.
# If the option is undelegated, it's own default value will be
# used if none is specified.
#
# Implements the "from" command.
proc ::snit::RT.from {type argvName option {defvalue ""}} {
variable ${type}::Snit_optionInfo
upvar $argvName argv
set ioption [lsearch -exact $argv $option]
if {$ioption == -1} {
if {"" == $defvalue &&
[info exists Snit_optionInfo(default-$option)]} {
return $Snit_optionInfo(default-$option)
} else {
return $defvalue
}
}
set ivalue [expr {$ioption + 1}]
set value [lindex $argv $ivalue]
set argv [lreplace $argv $ioption $ivalue]
return $value
}
#-----------------------------------------------------------------------
# Type Destruction
# Implements the standard "destroy" typemethod:
# Destroys a type completely.
#
# type The snit type
proc ::snit::RT.typemethod.destroy {type} {
variable ${type}::Snit_info
# FIRST, destroy all instances
foreach selfns [namespace children $type] {
if {![namespace exists $selfns]} {
continue
}
upvar ${selfns}::Snit_instance obj
if {$Snit_info(isWidget)} {
destroy $obj
} else {
if {[llength [info commands $obj]]} {
$obj destroy
}
}
}
# NEXT, destroy the type's data.
namespace delete $type
# NEXT, get rid of the type command.
rename $type ""
}
#-----------------------------------------------------------------------
# Option Handling
# Implements the standard "cget" method
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
# option The name of the option
proc ::snit::RT.method.cget {type selfns win self option} {
if {[catch {set ${selfns}::Snit_cgetCache($option)} command]} {
set command [snit::RT.CacheCgetCommand $type $selfns $win $self $option]
if {[llength $command] == 0} {
return -code error "unknown option \"$option\""
}
}
uplevel 1 $command
}
# Retrieves and caches the command that implements "cget" for the
# specified option.
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
# option The name of the option
proc ::snit::RT.CacheCgetCommand {type selfns win self option} {
variable ${type}::Snit_optionInfo
variable ${selfns}::Snit_cgetCache
if {[info exists Snit_optionInfo(islocal-$option)]} {
# We know the item; it's either local, or explicitly delegated.
if {$Snit_optionInfo(islocal-$option)} {
# It's a local option. If it has a cget method defined,
# use it; otherwise just return the value.
if {[string equal $Snit_optionInfo(cget-$option) ""]} {
set command [list set ${selfns}::options($option)]
} else {
set command [snit::RT.LookupMethodCommand \
$type $selfns $win $self \
$Snit_optionInfo(cget-$option) \
"can't cget $option"]
lappend command $option
}
set Snit_cgetCache($option) $command
return $command
}
# Explicitly delegated option; get target
set comp [lindex $Snit_optionInfo(target-$option) 0]
set target [lindex $Snit_optionInfo(target-$option) 1]
} elseif {![string equal $Snit_optionInfo(starcomp) ""] &&
[lsearch -exact $Snit_optionInfo(except) $option] == -1} {
# Unknown option, but unknowns are delegated; get target.
set comp $Snit_optionInfo(starcomp)
set target $option
} else {
return ""
}
# Get the component's object.
set obj [RT.Component $type $selfns $comp]
set command [list $obj cget $target]
set Snit_cgetCache($option) $command
return $command
}
# Implements the standard "configurelist" method
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
# optionlist A list of options and their values.
proc ::snit::RT.method.configurelist {type selfns win self optionlist} {
variable ${type}::Snit_optionInfo
foreach {option value} $optionlist {
# FIRST, get the configure command, caching it if need be.
if {[catch {set ${selfns}::Snit_configureCache($option)} command]} {
set command [snit::RT.CacheConfigureCommand \
$type $selfns $win $self $option]
if {[llength $command] == 0} {
return -code error "unknown option \"$option\""
}
}
# NEXT, the caching the configure command also cached the
# validate command, if any. If we have one, run it.
set valcommand [set ${selfns}::Snit_validateCache($option)]
if {[llength $valcommand]} {
lappend valcommand $value
uplevel 1 $valcommand
}
# NEXT, configure the option with the value.
lappend command $value
uplevel 1 $command
}
return
}
# Retrieves and caches the command that stores the named option.
# Also stores the command that validates the name option if any;
# If none, the validate command is "", so that the cache is always
# populated.
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
# option An option name
proc ::snit::RT.CacheConfigureCommand {type selfns win self option} {
variable ${type}::Snit_optionInfo
variable ${selfns}::Snit_configureCache
variable ${selfns}::Snit_validateCache
if {[info exist Snit_optionInfo(islocal-$option)]} {
# We know the item; it's either local, or explicitly delegated.
if {$Snit_optionInfo(islocal-$option)} {
# It's a local option.
# If it's readonly, it throws an error if we're already
# constructed.
if {$Snit_optionInfo(readonly-$option)} {
if {[set ${selfns}::Snit_iinfo(constructed)]} {
error "option $option can only be set at instance creation"
}
}
# If it has a validate method, cache that for later.
if {![string equal $Snit_optionInfo(validate-$option) ""]} {
set command [snit::RT.LookupMethodCommand \
$type $selfns $win $self \
$Snit_optionInfo(validate-$option) \
"can't validate $option"]
lappend command $option
set Snit_validateCache($option) $command
} else {
set Snit_validateCache($option) ""
}
# If it has a configure method defined,
# cache it; otherwise, just set the value.
if {[string equal $Snit_optionInfo(configure-$option) ""]} {
set command [list set ${selfns}::options($option)]
} else {
set command [snit::RT.LookupMethodCommand \
$type $selfns $win $self \
$Snit_optionInfo(configure-$option) \
"can't configure $option"]
lappend command $option
}
set Snit_configureCache($option) $command
return $command
}
# Delegated option: get target.
set comp [lindex $Snit_optionInfo(target-$option) 0]
set target [lindex $Snit_optionInfo(target-$option) 1]
} elseif {$Snit_optionInfo(starcomp) != "" &&
[lsearch -exact $Snit_optionInfo(except) $option] == -1} {
# Unknown option, but unknowns are delegated.
set comp $Snit_optionInfo(starcomp)
set target $option
} else {
return ""
}
# There is no validate command in this case; save an empty string.
set Snit_validateCache($option) ""
# Get the component's object
set obj [RT.Component $type $selfns $comp]
set command [list $obj configure $target]
set Snit_configureCache($option) $command
return $command
}
# Implements the standard "configure" method
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
# args A list of options and their values, possibly empty.
proc ::snit::RT.method.configure {type selfns win self args} {
# If two or more arguments, set values as usual.
if {[llength $args] >= 2} {
::snit::RT.method.configurelist $type $selfns $win $self $args
return
}
# If zero arguments, acquire data for each known option
# and return the list
if {[llength $args] == 0} {
set result {}
foreach opt [RT.method.info.options $type $selfns $win $self] {
# Refactor this, so that we don't need to call via $self.
lappend result [RT.GetOptionDbSpec \
$type $selfns $win $self $opt]
}
return $result
}
# They want it for just one.
set opt [lindex $args 0]
return [RT.GetOptionDbSpec $type $selfns $win $self $opt]
}
# Retrieves the option database spec for a single option.
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
# option The name of an option
#
# TBD: This is a bad name. What it's returning is the
# result of the configure query.
proc ::snit::RT.GetOptionDbSpec {type selfns win self opt} {
variable ${type}::Snit_optionInfo
upvar ${selfns}::Snit_components Snit_components
upvar ${selfns}::options options
if {[info exists options($opt)]} {
# This is a locally-defined option. Just build the
# list and return it.
set res $Snit_optionInfo(resource-$opt)
set cls $Snit_optionInfo(class-$opt)
set def $Snit_optionInfo(default-$opt)
return [list $opt $res $cls $def \
[RT.method.cget $type $selfns $win $self $opt]]
} elseif {[info exists Snit_optionInfo(target-$opt)]} {
# This is an explicitly delegated option. The only
# thing we don't have is the default.
set res $Snit_optionInfo(resource-$opt)
set cls $Snit_optionInfo(class-$opt)
# Get the default
set logicalName [lindex $Snit_optionInfo(target-$opt) 0]
set comp $Snit_components($logicalName)
set target [lindex $Snit_optionInfo(target-$opt) 1]
if {[catch {$comp configure $target} result]} {
set defValue {}
} else {
set defValue [lindex $result 3]
}
return [list $opt $res $cls $defValue [$self cget $opt]]
} elseif {![string equal $Snit_optionInfo(starcomp) ""] &&
[lsearch -exact $Snit_optionInfo(except) $opt] == -1} {
set logicalName $Snit_optionInfo(starcomp)
set target $opt
set comp $Snit_components($logicalName)
if {[catch {set value [$comp cget $target]} result]} {
error "unknown option \"$opt\""
}
if {![catch {$comp configure $target} result]} {
# Replace the delegated option name with the local name.
return [::snit::Expand $result $target $opt]
}
# configure didn't work; return simple form.
return [list $opt "" "" "" $value]
} else {
error "unknown option \"$opt\""
}
}
#-----------------------------------------------------------------------
# Type Introspection
# Implements the standard "info" typemethod.
#
# type The snit type
# command The info subcommand
# args All other arguments.
proc ::snit::RT.typemethod.info {type command args} {
global errorInfo
global errorCode
switch -exact $command {
typevars -
typemethods -
instances {
# TBD: it should be possible to delete this error
# handling.
set errflag [catch {
uplevel 1 [linsert $args 0 \
::snit::RT.typemethod.info.$command $type]
} result]
if {$errflag} {
return -code error -errorinfo $errorInfo \
-errorcode $errorCode $result
} else {
return $result
}
}
default {
error "\"$type info $command\" is not defined"
}
}
}
# Returns a list of the type's typevariables whose names match a
# pattern, excluding Snit internal variables.
#
# type A Snit type
# pattern Optional. The glob pattern to match. Defaults
# to *.
proc ::snit::RT.typemethod.info.typevars {type {pattern *}} {
set result {}
foreach name [info vars "${type}::$pattern"] {
set tail [namespace tail $name]
if {![string match "Snit_*" $tail]} {
lappend result $name
}
}
return $result
}
# Returns a list of the type's methods whose names match a
# pattern. If "delegate typemethod *" is used, the list may
# not be complete.
#
# type A Snit type
# pattern Optional. The glob pattern to match. Defaults
# to *.
proc ::snit::RT.typemethod.info.typemethods {type {pattern *}} {
variable ${type}::Snit_typemethodInfo
variable ${type}::Snit_typemethodCache
# FIRST, get the explicit names, skipping prefixes.
set result {}
foreach name [array names Snit_typemethodInfo $pattern] {
if {[lindex $Snit_typemethodInfo($name) 0] != 1} {
lappend result $name
}
}
# NEXT, add any from the cache that aren't explicit.
if {[info exists Snit_typemethodInfo(*)]} {
# First, remove "*" from the list.
set ndx [lsearch -exact $result "*"]
if {$ndx != -1} {
set result [lreplace $result $ndx $ndx]
}
foreach name [array names Snit_typemethodCache $pattern] {
if {[lsearch -exact $result $name] == -1} {
lappend result $name
}
}
}
return $result
}
# Returns a list of the type's instances whose names match
# a pattern.
#
# type A Snit type
# pattern Optional. The glob pattern to match
# Defaults to *
#
# REQUIRE: type is fully qualified.
proc ::snit::RT.typemethod.info.instances {type {pattern *}} {
set result {}
foreach selfns [namespace children $type] {
upvar ${selfns}::Snit_instance instance
if {[string match $pattern $instance]} {
lappend result $instance
}
}
return $result
}
#-----------------------------------------------------------------------
# Instance Introspection
# Implements the standard "info" method.
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
# command The info subcommand
# args All other arguments.
proc ::snit::RT.method.info {type selfns win self command args} {
switch -exact $command {
type -
vars -
options -
methods -
typevars -
typemethods {
set errflag [catch {
uplevel 1 [linsert $args 0 ::snit::RT.method.info.$command \
$type $selfns $win $self]
} result]
if {$errflag} {
global errorInfo
return -code error -errorinfo $errorInfo $result
} else {
return $result
}
}
default {
# error "\"$self info $command\" is not defined"
return -code error "\"$self info $command\" is not defined"
}
}
}
# $self info type
#
# Returns the instance's type
proc ::snit::RT.method.info.type {type selfns win self} {
return $type
}
# $self info typevars
#
# Returns the instance's type's typevariables
proc ::snit::RT.method.info.typevars {type selfns win self {pattern *}} {
return [RT.typemethod.info.typevars $type $pattern]
}
# $self info typemethods
#
# Returns the instance's type's typemethods
proc ::snit::RT.method.info.typemethods {type selfns win self {pattern *}} {
return [RT.typemethod.info.typemethods $type $pattern]
}
# Returns a list of the instance's methods whose names match a
# pattern. If "delegate method *" is used, the list may
# not be complete.
#
# type A Snit type
# selfns The instance namespace
# win The original instance name
# self The current instance name
# pattern Optional. The glob pattern to match. Defaults
# to *.
proc ::snit::RT.method.info.methods {type selfns win self {pattern *}} {
variable ${type}::Snit_methodInfo
variable ${selfns}::Snit_methodCache
# FIRST, get the explicit names, skipping prefixes.
set result {}
foreach name [array names Snit_methodInfo $pattern] {
if {[lindex $Snit_methodInfo($name) 0] != 1} {
lappend result $name
}
}
# NEXT, add any from the cache that aren't explicit.
if {[info exists Snit_methodInfo(*)]} {
# First, remove "*" from the list.
set ndx [lsearch -exact $result "*"]
if {$ndx != -1} {
set result [lreplace $result $ndx $ndx]
}
foreach name [array names Snit_methodCache $pattern] {
if {[lsearch -exact $result $name] == -1} {
lappend result $name
}
}
}
return $result
}
# $self info vars
#
# Returns the instance's instance variables
proc ::snit::RT.method.info.vars {type selfns win self {pattern *}} {
set result {}
foreach name [info vars "${selfns}::$pattern"] {
set tail [namespace tail $name]
if {![string match "Snit_*" $tail]} {
lappend result $name
}
}
return $result
}
# $self info options
#
# Returns a list of the names of the instance's options
proc ::snit::RT.method.info.options {type selfns win self {pattern *}} {
variable ${type}::Snit_optionInfo
# First, get the local and explicitly delegated options
set result [concat $Snit_optionInfo(local) $Snit_optionInfo(delegated)]
# If "configure" works as for Tk widgets, add the resulting
# options to the list. Skip excepted options
if {![string equal $Snit_optionInfo(starcomp) ""]} {
upvar ${selfns}::Snit_components Snit_components
set logicalName $Snit_optionInfo(starcomp)
set comp $Snit_components($logicalName)
if {![catch {$comp configure} records]} {
foreach record $records {
set opt [lindex $record 0]
if {[lsearch -exact $result $opt] == -1 &&
[lsearch -exact $Snit_optionInfo(except) $opt] == -1} {
lappend result $opt
}
}
}
}
# Next, apply the pattern
set names {}
foreach name $result {
if {[string match $pattern $name]} {
lappend names $name
}
}
return $names
}
amsn-0.98.9/utils/snit/main2.tcl 0000644 0001750 0001750 00000364120 11020317540 016217 0 ustar billiob billiob #-----------------------------------------------------------------------
# TITLE:
# main2.tcl
#
# AUTHOR:
# Will Duquette
#
# DESCRIPTION:
# Snit's Not Incr Tcl, a simple object system in Pure Tcl.
#
# Snit 2.x Compiler and Run-Time Library
#
# Copyright (C) 2003-2006 by William H. Duquette
# This code is licensed as described in license.txt.
#
#-----------------------------------------------------------------------
#-----------------------------------------------------------------------
# Namespace
namespace eval ::snit:: {
namespace export \
compile type widget widgetadaptor typemethod method macro
}
#-----------------------------------------------------------------------
# Some Snit variables
namespace eval ::snit:: {
variable reservedArgs {type selfns win self}
# Widget classes which can be hulls (must have -class)
variable hulltypes {
toplevel tk::toplevel
frame tk::frame ttk::frame
labelframe tk::labelframe ttk::labelframe
}
}
#-----------------------------------------------------------------------
# Snit Type Implementation template
namespace eval ::snit:: {
# Template type definition: All internal and user-visible Snit
# implementation code.
#
# The following placeholders will automatically be replaced with
# the client's code, in two passes:
#
# First pass:
# %COMPILEDDEFS% The compiled type definition.
#
# Second pass:
# %TYPE% The fully qualified type name.
# %IVARDECS% Instance variable declarations
# %TVARDECS% Type variable declarations
# %TCONSTBODY% Type constructor body
# %INSTANCEVARS% The compiled instance variable initialization code.
# %TYPEVARS% The compiled type variable initialization code.
# This is the overall type template.
variable typeTemplate
# This is the normal type proc
variable nominalTypeProc
# This is the "-hastypemethods no" type proc
variable simpleTypeProc
}
set ::snit::typeTemplate {
#-------------------------------------------------------------------
# The type's namespace definition and the user's type variables
namespace eval %TYPE% {%TYPEVARS%
}
#----------------------------------------------------------------
# Commands for use in methods, typemethods, etc.
#
# These are implemented as aliases into the Snit runtime library.
interp alias {} %TYPE%::installhull {} ::snit::RT.installhull %TYPE%
interp alias {} %TYPE%::install {} ::snit::RT.install %TYPE%
interp alias {} %TYPE%::typevariable {} ::variable
interp alias {} %TYPE%::variable {} ::snit::RT.variable
interp alias {} %TYPE%::mytypevar {} ::snit::RT.mytypevar %TYPE%
interp alias {} %TYPE%::typevarname {} ::snit::RT.mytypevar %TYPE%
interp alias {} %TYPE%::myvar {} ::snit::RT.myvar
interp alias {} %TYPE%::varname {} ::snit::RT.myvar
interp alias {} %TYPE%::codename {} ::snit::RT.codename %TYPE%
interp alias {} %TYPE%::myproc {} ::snit::RT.myproc %TYPE%
interp alias {} %TYPE%::mymethod {} ::snit::RT.mymethod
interp alias {} %TYPE%::mytypemethod {} ::snit::RT.mytypemethod %TYPE%
interp alias {} %TYPE%::from {} ::snit::RT.from %TYPE%
#-------------------------------------------------------------------
# Snit's internal variables
namespace eval %TYPE% {
# Array: General Snit Info
#
# ns: The type's namespace
# hasinstances: T or F, from pragma -hasinstances.
# simpledispatch: T or F, from pragma -hasinstances.
# canreplace: T or F, from pragma -canreplace.
# counter: Count of instances created so far.
# widgetclass: Set by widgetclass statement.
# hulltype: Hull type (frame or toplevel) for widgets only.
# exceptmethods: Methods explicitly not delegated to *
# excepttypemethods: Methods explicitly not delegated to *
# tvardecs: Type variable declarations--for dynamic methods
# ivardecs: Instance variable declarations--for dyn. methods
typevariable Snit_info
set Snit_info(ns) %TYPE%::
set Snit_info(hasinstances) 1
set Snit_info(simpledispatch) 0
set Snit_info(canreplace) 0
set Snit_info(counter) 0
set Snit_info(widgetclass) {}
set Snit_info(hulltype) frame
set Snit_info(exceptmethods) {}
set Snit_info(excepttypemethods) {}
set Snit_info(tvardecs) {%TVARDECS%}
set Snit_info(ivardecs) {%IVARDECS%}
# Array: Public methods of this type.
# The index is the method name, or "*".
# The value is [list $pattern $componentName], where
# $componentName is "" for normal methods.
typevariable Snit_typemethodInfo
array unset Snit_typemethodInfo
# Array: Public methods of instances of this type.
# The index is the method name, or "*".
# The value is [list $pattern $componentName], where
# $componentName is "" for normal methods.
typevariable Snit_methodInfo
array unset Snit_methodInfo
# Array: option information. See dictionary.txt.
typevariable Snit_optionInfo
array unset Snit_optionInfo
set Snit_optionInfo(local) {}
set Snit_optionInfo(delegated) {}
set Snit_optionInfo(starcomp) {}
set Snit_optionInfo(except) {}
}
#----------------------------------------------------------------
# Compiled Procs
#
# These commands are created or replaced during compilation:
# Snit_instanceVars selfns
#
# Initializes the instance variables, if any. Called during
# instance creation.
proc %TYPE%::Snit_instanceVars {selfns} {
%INSTANCEVARS%
}
# Type Constructor
proc %TYPE%::Snit_typeconstructor {type} {
%TVARDECS%
namespace path [namespace parent $type]
%TCONSTBODY%
}
#----------------------------------------------------------------
# Default Procs
#
# These commands might be replaced during compilation:
# Snit_destructor type selfns win self
#
# Default destructor for the type. By default, it does
# nothing. It's replaced by any user destructor.
# For types, it's called by method destroy; for widgettypes,
# it's called by a destroy event handler.
proc %TYPE%::Snit_destructor {type selfns win self} { }
#----------------------------------------------------------
# Compiled Definitions
%COMPILEDDEFS%
#----------------------------------------------------------
# Finally, call the Type Constructor
%TYPE%::Snit_typeconstructor %TYPE%
}
#-----------------------------------------------------------------------
# Type procs
#
# These procs expect the fully-qualified type name to be
# substituted in for %TYPE%.
# This is the nominal type proc. It supports typemethods and
# delegated typemethods.
set ::snit::nominalTypeProc {
# WHD: Code for creating the type ensemble
namespace eval %TYPE% {
namespace ensemble create \
-unknown [list ::snit::RT.UnknownTypemethod %TYPE% ""] \
-prefixes 0
}
}
# This is the simplified type proc for when there are no typemethods
# except create. In this case, it doesn't take a method argument;
# the method is always "create".
set ::snit::simpleTypeProc {
# Type dispatcher function. Note: This function lives
# in the parent of the %TYPE% namespace! All accesses to
# %TYPE% variables and methods must be qualified!
proc %TYPE% {args} {
::variable %TYPE%::Snit_info
# FIRST, if the are no args, the single arg is %AUTO%
if {[llength $args] == 0} {
if {$Snit_info(isWidget)} {
error "wrong \# args: should be \"%TYPE% name args\""
}
lappend args %AUTO%
}
# NEXT, we're going to call the create method.
# Pass along the return code unchanged.
if {$Snit_info(isWidget)} {
set command [list ::snit::RT.widget.typemethod.create %TYPE%]
} else {
set command [list ::snit::RT.type.typemethod.create %TYPE%]
}
set retval [catch {uplevel 1 $command $args} result]
if {$retval} {
if {$retval == 1} {
global errorInfo
global errorCode
return -code error -errorinfo $errorInfo \
-errorcode $errorCode $result
} else {
return -code $retval $result
}
}
return $result
}
}
#=======================================================================
# Snit Type Definition
#
# These are the procs used to define Snit types, widgets, and
# widgetadaptors.
#-----------------------------------------------------------------------
# Snit Compilation Variables
#
# The following variables are used while Snit is compiling a type,
# and are disposed afterwards.
namespace eval ::snit:: {
# The compiler variable contains the name of the slave interpreter
# used to compile type definitions.
variable compiler ""
# The compile array accumulates information about the type or
# widgettype being compiled. It is cleared before and after each
# compilation. It has these indices:
#
# type: The name of the type being compiled, for use
# in compilation procs.
# defs: Compiled definitions, both standard and client.
# which: type, widget, widgetadaptor
# instancevars: Instance variable definitions and initializations.
# ivprocdec: Instance variable proc declarations.
# tvprocdec: Type variable proc declarations.
# typeconstructor: Type constructor body.
# widgetclass: The widgetclass, for snit::widgets, only
# hasoptions: False, initially; set to true when first
# option is defined.
# localoptions: Names of local options.
# delegatedoptions: Names of delegated options.
# localmethods: Names of locally defined methods.
# delegatesmethods: no if no delegated methods, yes otherwise.
# hashierarchic : no if no hierarchic methods, yes otherwise.
# components: Names of defined components.
# typecomponents: Names of defined typecomponents.
# typevars: Typevariable definitions and initializations.
# varnames: Names of instance variables
# typevarnames Names of type variables
# hasconstructor False, initially; true when constructor is
# defined.
# resource-$opt The option's resource name
# class-$opt The option's class
# -default-$opt The option's default value
# -validatemethod-$opt The option's validate method
# -configuremethod-$opt The option's configure method
# -cgetmethod-$opt The option's cget method.
# -hastypeinfo The -hastypeinfo pragma
# -hastypedestroy The -hastypedestroy pragma
# -hastypemethods The -hastypemethods pragma
# -hasinfo The -hasinfo pragma
# -hasinstances The -hasinstances pragma
# -simpledispatch The -simpledispatch pragma WHD: OBSOLETE
# -canreplace The -canreplace pragma
variable compile
# This variable accumulates method dispatch information; it has
# the same structure as the %TYPE%::Snit_methodInfo array, and is
# used to initialize it.
variable methodInfo
# This variable accumulates typemethod dispatch information; it has
# the same structure as the %TYPE%::Snit_typemethodInfo array, and is
# used to initialize it.
variable typemethodInfo
# The following variable lists the reserved type definition statement
# names, e.g., the names you can't use as macros. It's built at
# compiler definition time using "info commands".
variable reservedwords {}
}
#-----------------------------------------------------------------------
# type compilation commands
#
# The type and widgettype commands use a slave interpreter to compile
# the type definition. These are the procs
# that are aliased into it.
# Initialize the compiler
proc ::snit::Comp.Init {} {
variable compiler
variable reservedwords
if {$compiler eq ""} {
# Create the compiler's interpreter
set compiler [interp create]
# Initialize the interpreter
$compiler eval {
# Load package information
# TBD: see if this can be moved outside.
# @mdgen NODEP: ::snit::__does_not_exist__
catch {package require ::snit::__does_not_exist__}
# Protect some Tcl commands our type definitions
# will shadow.
rename proc _proc
rename variable _variable
}
# Define compilation aliases.
$compiler alias pragma ::snit::Comp.statement.pragma
$compiler alias widgetclass ::snit::Comp.statement.widgetclass
$compiler alias hulltype ::snit::Comp.statement.hulltype
$compiler alias constructor ::snit::Comp.statement.constructor
$compiler alias destructor ::snit::Comp.statement.destructor
$compiler alias option ::snit::Comp.statement.option
$compiler alias oncget ::snit::Comp.statement.oncget
$compiler alias onconfigure ::snit::Comp.statement.onconfigure
$compiler alias method ::snit::Comp.statement.method
$compiler alias typemethod ::snit::Comp.statement.typemethod
$compiler alias typeconstructor ::snit::Comp.statement.typeconstructor
$compiler alias proc ::snit::Comp.statement.proc
$compiler alias typevariable ::snit::Comp.statement.typevariable
$compiler alias variable ::snit::Comp.statement.variable
$compiler alias typecomponent ::snit::Comp.statement.typecomponent
$compiler alias component ::snit::Comp.statement.component
$compiler alias delegate ::snit::Comp.statement.delegate
$compiler alias expose ::snit::Comp.statement.expose
# Get the list of reserved words
set reservedwords [$compiler eval {info commands}]
}
}
# Compile a type definition, and return the results as a list of two
# items: the fully-qualified type name, and a script that will define
# the type when executed.
#
# which type, widget, or widgetadaptor
# type the type name
# body the type definition
proc ::snit::Comp.Compile {which type body} {
variable typeTemplate
variable nominalTypeProc
variable simpleTypeProc
variable compile
variable compiler
variable methodInfo
variable typemethodInfo
# FIRST, qualify the name.
if {![string match "::*" $type]} {
# Get caller's namespace;
# append :: if not global namespace.
set ns [uplevel 2 [list namespace current]]
if {"::" != $ns} {
append ns "::"
}
set type "$ns$type"
}
# NEXT, create and initialize the compiler, if needed.
Comp.Init
# NEXT, initialize the class data
array unset methodInfo
array unset typemethodInfo
array unset compile
set compile(type) $type
set compile(defs) {}
set compile(which) $which
set compile(hasoptions) no
set compile(localoptions) {}
set compile(instancevars) {}
set compile(typevars) {}
set compile(delegatedoptions) {}
set compile(ivprocdec) {}
set compile(tvprocdec) {}
set compile(typeconstructor) {}
set compile(widgetclass) {}
set compile(hulltype) {}
set compile(localmethods) {}
set compile(delegatesmethods) no
set compile(hashierarchic) no
set compile(components) {}
set compile(typecomponents) {}
set compile(varnames) {}
set compile(typevarnames) {}
set compile(hasconstructor) no
set compile(-hastypedestroy) yes
set compile(-hastypeinfo) yes
set compile(-hastypemethods) yes
set compile(-hasinfo) yes
set compile(-hasinstances) yes
set compile(-canreplace) no
set isWidget [string match widget* $which]
set isWidgetAdaptor [string match widgetadaptor $which]
# NEXT, Evaluate the type's definition in the class interpreter.
$compiler eval $body
# NEXT, Add the standard definitions
append compile(defs) \
"\nset %TYPE%::Snit_info(isWidget) $isWidget\n"
append compile(defs) \
"\nset %TYPE%::Snit_info(isWidgetAdaptor) $isWidgetAdaptor\n"
# Indicate whether the type can create instances that replace
# existing commands.
append compile(defs) "\nset %TYPE%::Snit_info(canreplace) $compile(-canreplace)\n"
# Check pragmas for conflict.
if {!$compile(-hastypemethods) && !$compile(-hasinstances)} {
error "$which $type has neither typemethods nor instances"
}
# If there are typemethods, define the standard typemethods and
# the nominal type proc. Otherwise define the simple type proc.
if {$compile(-hastypemethods)} {
# Add the info typemethod unless the pragma forbids it.
if {$compile(-hastypeinfo)} {
Comp.statement.delegate typemethod info \
using {::snit::RT.typemethod.info %t}
}
# Add the destroy typemethod unless the pragma forbids it.
if {$compile(-hastypedestroy)} {
Comp.statement.delegate typemethod destroy \
using {::snit::RT.typemethod.destroy %t}
}
# Add the nominal type proc.
append compile(defs) $nominalTypeProc
} else {
# Add the simple type proc.
append compile(defs) $simpleTypeProc
}
# Add standard methods/typemethods that only make sense if the
# type has instances.
if {$compile(-hasinstances)} {
# Add the info method unless the pragma forbids it.
if {$compile(-hasinfo)} {
Comp.statement.delegate method info \
using {::snit::RT.method.info %t %n %w %s}
}
# Add the option handling stuff if there are any options.
if {$compile(hasoptions)} {
Comp.statement.variable options
Comp.statement.delegate method cget \
using {::snit::RT.method.cget %t %n %w %s}
Comp.statement.delegate method configurelist \
using {::snit::RT.method.configurelist %t %n %w %s}
Comp.statement.delegate method configure \
using {::snit::RT.method.configure %t %n %w %s}
}
# Add a default constructor, if they haven't already defined one.
# If there are options, it will configure args; otherwise it
# will do nothing.
if {!$compile(hasconstructor)} {
if {$compile(hasoptions)} {
Comp.statement.constructor {args} {
$self configurelist $args
}
} else {
Comp.statement.constructor {} {}
}
}
if {!$isWidget} {
Comp.statement.delegate method destroy \
using {::snit::RT.method.destroy %t %n %w %s}
Comp.statement.delegate typemethod create \
using {::snit::RT.type.typemethod.create %t}
} else {
Comp.statement.delegate typemethod create \
using {::snit::RT.widget.typemethod.create %t}
}
# Save the method info.
append compile(defs) \
"\narray set %TYPE%::Snit_methodInfo [list [array get methodInfo]]\n"
} else {
append compile(defs) "\nset %TYPE%::Snit_info(hasinstances) 0\n"
}
# NEXT, compiling the type definition built up a set of information
# about the type's locally defined options; add this information to
# the compiled definition.
Comp.SaveOptionInfo
# NEXT, compiling the type definition built up a set of information
# about the typemethods; save the typemethod info.
append compile(defs) \
"\narray set %TYPE%::Snit_typemethodInfo [list [array get typemethodInfo]]\n"
# NEXT, if this is a widget define the hull component if it isn't
# already defined.
if {$isWidget} {
Comp.DefineComponent hull
}
# NEXT, substitute the compiled definition into the type template
# to get the type definition script.
set defscript [Expand $typeTemplate \
%COMPILEDDEFS% $compile(defs)]
# NEXT, substitute the defined macros into the type definition script.
# This is done as a separate step so that the compile(defs) can
# contain the macros defined below.
set defscript [Expand $defscript \
%TYPE% $type \
%IVARDECS% $compile(ivprocdec) \
%TVARDECS% $compile(tvprocdec) \
%TCONSTBODY% $compile(typeconstructor) \
%INSTANCEVARS% $compile(instancevars) \
%TYPEVARS% $compile(typevars) \
]
array unset compile
return [list $type $defscript]
}
# Information about locally-defined options is accumulated during
# compilation, but not added to the compiled definition--the option
# statement can appear multiple times, so it's easier this way.
# This proc fills in Snit_optionInfo with the accumulated information.
#
# It also computes the option's resource and class names if needed.
#
# Note that the information for delegated options was put in
# Snit_optionInfo during compilation.
proc ::snit::Comp.SaveOptionInfo {} {
variable compile
foreach option $compile(localoptions) {
if {$compile(resource-$option) eq ""} {
set compile(resource-$option) [string range $option 1 end]
}
if {$compile(class-$option) eq ""} {
set compile(class-$option) [Capitalize $compile(resource-$option)]
}
# NOTE: Don't verify that the validate, configure, and cget
# values name real methods; the methods might be defined outside
# the typedefinition using snit::method.
Mappend compile(defs) {
# Option %OPTION%
lappend %TYPE%::Snit_optionInfo(local) %OPTION%
set %TYPE%::Snit_optionInfo(islocal-%OPTION%) 1
set %TYPE%::Snit_optionInfo(resource-%OPTION%) %RESOURCE%
set %TYPE%::Snit_optionInfo(class-%OPTION%) %CLASS%
set %TYPE%::Snit_optionInfo(default-%OPTION%) %DEFAULT%
set %TYPE%::Snit_optionInfo(validate-%OPTION%) %VALIDATE%
set %TYPE%::Snit_optionInfo(configure-%OPTION%) %CONFIGURE%
set %TYPE%::Snit_optionInfo(cget-%OPTION%) %CGET%
set %TYPE%::Snit_optionInfo(readonly-%OPTION%) %READONLY%
set %TYPE%::Snit_optionInfo(typespec-%OPTION%) %TYPESPEC%
} %OPTION% $option \
%RESOURCE% $compile(resource-$option) \
%CLASS% $compile(class-$option) \
%DEFAULT% [list $compile(-default-$option)] \
%VALIDATE% [list $compile(-validatemethod-$option)] \
%CONFIGURE% [list $compile(-configuremethod-$option)] \
%CGET% [list $compile(-cgetmethod-$option)] \
%READONLY% $compile(-readonly-$option) \
%TYPESPEC% [list $compile(-type-$option)]
}
}
# Evaluates a compiled type definition, thus making the type available.
proc ::snit::Comp.Define {compResult} {
# The compilation result is a list containing the fully qualified
# type name and a script to evaluate to define the type.
set type [lindex $compResult 0]
set defscript [lindex $compResult 1]
# Execute the type definition script.
# Consider using namespace eval %TYPE%. See if it's faster.
if {[catch {eval $defscript} result]} {
namespace delete $type
catch {rename $type ""}
error $result
}
return $type
}
# Sets pragma options which control how the type is defined.
proc ::snit::Comp.statement.pragma {args} {
variable compile
set errRoot "Error in \"pragma...\""
foreach {opt val} $args {
switch -exact -- $opt {
-hastypeinfo -
-hastypedestroy -
-hastypemethods -
-hasinstances -
-simpledispatch -
-hasinfo -
-canreplace {
if {![string is boolean -strict $val]} {
error "$errRoot, \"$opt\" requires a boolean value"
}
set compile($opt) $val
}
default {
error "$errRoot, unknown pragma"
}
}
}
}
# Defines a widget's option class name.
# This statement is only available for snit::widgets,
# not for snit::types or snit::widgetadaptors.
proc ::snit::Comp.statement.widgetclass {name} {
variable compile
# First, widgetclass can only be set for true widgets
if {"widget" != $compile(which)} {
error "widgetclass cannot be set for snit::$compile(which)s"
}
# Next, validate the option name. We'll require that it begin
# with an uppercase letter.
set initial [string index $name 0]
if {![string is upper $initial]} {
error "widgetclass \"$name\" does not begin with an uppercase letter"
}
if {"" != $compile(widgetclass)} {
error "too many widgetclass statements"
}
# Next, save it.
Mappend compile(defs) {
set %TYPE%::Snit_info(widgetclass) %WIDGETCLASS%
} %WIDGETCLASS% [list $name]
set compile(widgetclass) $name
}
# Defines a widget's hull type.
# This statement is only available for snit::widgets,
# not for snit::types or snit::widgetadaptors.
proc ::snit::Comp.statement.hulltype {name} {
variable compile
variable hulltypes
# First, hulltype can only be set for true widgets
if {"widget" != $compile(which)} {
error "hulltype cannot be set for snit::$compile(which)s"
}
# Next, it must be one of the valid hulltypes (frame, toplevel, ...)
if {[lsearch -exact $hulltypes [string trimleft $name :]] == -1} {
error "invalid hulltype \"$name\", should be one of\
[join $hulltypes {, }]"
}
if {"" != $compile(hulltype)} {
error "too many hulltype statements"
}
# Next, save it.
Mappend compile(defs) {
set %TYPE%::Snit_info(hulltype) %HULLTYPE%
} %HULLTYPE% $name
set compile(hulltype) $name
}
# Defines a constructor.
proc ::snit::Comp.statement.constructor {arglist body} {
variable compile
CheckArgs "constructor" $arglist
# Next, add a magic reference to self.
set arglist [concat type selfns win self $arglist]
# Next, add variable declarations to body:
set body "%TVARDECS%\n%IVARDECS%\n$body"
set compile(hasconstructor) yes
append compile(defs) "proc %TYPE%::Snit_constructor [list $arglist] [list $body]\n"
}
# Defines a destructor.
proc ::snit::Comp.statement.destructor {body} {
variable compile
# Next, add variable declarations to body:
set body "%TVARDECS%\n%IVARDECS%\n$body"
append compile(defs) "proc %TYPE%::Snit_destructor {type selfns win self} [list $body]\n\n"
}
# Defines a type option. The option value can be a triple, specifying
# the option's -name, resource name, and class name.
proc ::snit::Comp.statement.option {optionDef args} {
variable compile
# First, get the three option names.
set option [lindex $optionDef 0]
set resourceName [lindex $optionDef 1]
set className [lindex $optionDef 2]
set errRoot "Error in \"option [list $optionDef]...\""
# Next, validate the option name.
if {![Comp.OptionNameIsValid $option]} {
error "$errRoot, badly named option \"$option\""
}
if {$option in $compile(delegatedoptions)} {
error "$errRoot, cannot define \"$option\" locally, it has been delegated"
}
if {!($option in $compile(localoptions))} {
# Remember that we've seen this one.
set compile(hasoptions) yes
lappend compile(localoptions) $option
# Initialize compilation info for this option.
set compile(resource-$option) ""
set compile(class-$option) ""
set compile(-default-$option) ""
set compile(-validatemethod-$option) ""
set compile(-configuremethod-$option) ""
set compile(-cgetmethod-$option) ""
set compile(-readonly-$option) 0
set compile(-type-$option) ""
}
# NEXT, see if we have a resource name. If so, make sure it
# isn't being redefined differently.
if {$resourceName ne ""} {
if {$compile(resource-$option) eq ""} {
# If it's undefined, just save the value.
set compile(resource-$option) $resourceName
} elseif {$resourceName ne $compile(resource-$option)} {
# It's been redefined differently.
error "$errRoot, resource name redefined from \"$compile(resource-$option)\" to \"$resourceName\""
}
}
# NEXT, see if we have a class name. If so, make sure it
# isn't being redefined differently.
if {$className ne ""} {
if {$compile(class-$option) eq ""} {
# If it's undefined, just save the value.
set compile(class-$option) $className
} elseif {$className ne $compile(class-$option)} {
# It's been redefined differently.
error "$errRoot, class name redefined from \"$compile(class-$option)\" to \"$className\""
}
}
# NEXT, handle the args; it's not an error to redefine these.
if {[llength $args] == 1} {
set compile(-default-$option) [lindex $args 0]
} else {
foreach {optopt val} $args {
switch -exact -- $optopt {
-default -
-validatemethod -
-configuremethod -
-cgetmethod {
set compile($optopt-$option) $val
}
-type {
set compile($optopt-$option) $val
if {[llength $val] == 1} {
# The type spec *is* the validation object
append compile(defs) \
"\nset %TYPE%::Snit_optionInfo(typeobj-$option) [list $val]\n"
} else {
# Compilation the creation of the validation object
set cmd [linsert $val 1 %TYPE%::Snit_TypeObj_%AUTO%]
append compile(defs) \
"\nset %TYPE%::Snit_optionInfo(typeobj-$option) \[$cmd\]\n"
}
}
-readonly {
if {![string is boolean -strict $val]} {
error "$errRoot, -readonly requires a boolean, got \"$val\""
}
set compile($optopt-$option) $val
}
default {
error "$errRoot, unknown option definition option \"$optopt\""
}
}
}
}
}
# 1 if the option name is valid, 0 otherwise.
proc ::snit::Comp.OptionNameIsValid {option} {
if {![string match {-*} $option] || [string match {*[A-Z ]*} $option]} {
return 0
}
return 1
}
# Defines an option's cget handler
proc ::snit::Comp.statement.oncget {option body} {
variable compile
set errRoot "Error in \"oncget $option...\""
if {[lsearch -exact $compile(delegatedoptions) $option] != -1} {
return -code error "$errRoot, option \"$option\" is delegated"
}
if {[lsearch -exact $compile(localoptions) $option] == -1} {
return -code error "$errRoot, option \"$option\" unknown"
}
Comp.statement.method _cget$option {_option} $body
Comp.statement.option $option -cgetmethod _cget$option
}
# Defines an option's configure handler.
proc ::snit::Comp.statement.onconfigure {option arglist body} {
variable compile
if {[lsearch -exact $compile(delegatedoptions) $option] != -1} {
return -code error "onconfigure $option: option \"$option\" is delegated"
}
if {[lsearch -exact $compile(localoptions) $option] == -1} {
return -code error "onconfigure $option: option \"$option\" unknown"
}
if {[llength $arglist] != 1} {
error \
"onconfigure $option handler should have one argument, got \"$arglist\""
}
CheckArgs "onconfigure $option" $arglist
# Next, add a magic reference to the option name
set arglist [concat _option $arglist]
Comp.statement.method _configure$option $arglist $body
Comp.statement.option $option -configuremethod _configure$option
}
# Defines an instance method.
proc ::snit::Comp.statement.method {method arglist body} {
variable compile
variable methodInfo
# FIRST, check the method name against previously defined
# methods.
Comp.CheckMethodName $method 0 ::snit::methodInfo \
"Error in \"method [list $method]...\""
if {[llength $method] > 1} {
set compile(hashierarchic) yes
}
# Remeber this method
lappend compile(localmethods) $method
CheckArgs "method [list $method]" $arglist
# Next, add magic references to type and self.
set arglist [concat type selfns win self $arglist]
# Next, add variable declarations to body:
set body "%TVARDECS%\n%IVARDECS%\n# END snit method prolog\n$body"
# Next, save the definition script.
if {[llength $method] == 1} {
set methodInfo($method) {0 "%t::Snit_method%m %t %n %w %s" ""}
Mappend compile(defs) {
proc %TYPE%::Snit_method%METHOD% %ARGLIST% %BODY%
} %METHOD% $method %ARGLIST% [list $arglist] %BODY% [list $body]
} else {
set methodInfo($method) {0 "%t::Snit_hmethod%j %t %n %w %s" ""}
Mappend compile(defs) {
proc %TYPE%::Snit_hmethod%JMETHOD% %ARGLIST% %BODY%
} %JMETHOD% [join $method _] %ARGLIST% [list $arglist] \
%BODY% [list $body]
}
}
# Check for name collisions; save prefix information.
#
# method The name of the method or typemethod.
# delFlag 1 if delegated, 0 otherwise.
# infoVar The fully qualified name of the array containing
# information about the defined methods.
# errRoot The root string for any error messages.
proc ::snit::Comp.CheckMethodName {method delFlag infoVar errRoot} {
upvar $infoVar methodInfo
# FIRST, make sure the method name is a valid Tcl list.
if {[catch {lindex $method 0}]} {
error "$errRoot, the name \"$method\" must have list syntax."
}
# NEXT, check whether we can define it.
if {![catch {set methodInfo($method)} data]} {
# We can't redefine methods with submethods.
if {[lindex $data 0] == 1} {
error "$errRoot, \"$method\" has submethods."
}
# You can't delegate a method that's defined locally,
# and you can't define a method locally if it's been delegated.
if {$delFlag && [lindex $data 2] eq ""} {
error "$errRoot, \"$method\" has been defined locally."
} elseif {!$delFlag && [lindex $data 2] ne ""} {
error "$errRoot, \"$method\" has been delegated"
}
}
# Handle hierarchical case.
if {[llength $method] > 1} {
set prefix {}
set tokens $method
while {[llength $tokens] > 1} {
lappend prefix [lindex $tokens 0]
set tokens [lrange $tokens 1 end]
if {![catch {set methodInfo($prefix)} result]} {
# Prefix is known. If it's not a prefix, throw an
# error.
if {[lindex $result 0] == 0} {
error "$errRoot, \"$prefix\" has no submethods."
}
}
set methodInfo($prefix) [list 1]
}
}
}
# Defines a typemethod method.
proc ::snit::Comp.statement.typemethod {method arglist body} {
variable compile
variable typemethodInfo
# FIRST, check the typemethod name against previously defined
# typemethods.
Comp.CheckMethodName $method 0 ::snit::typemethodInfo \
"Error in \"typemethod [list $method]...\""
CheckArgs "typemethod $method" $arglist
# First, add magic reference to type.
set arglist [concat type $arglist]
# Next, add typevariable declarations to body:
set body "%TVARDECS%\n# END snit method prolog\n$body"
# Next, save the definition script
if {[llength $method] == 1} {
set typemethodInfo($method) {0 "%t::Snit_typemethod%m %t" ""}
Mappend compile(defs) {
proc %TYPE%::Snit_typemethod%METHOD% %ARGLIST% %BODY%
} %METHOD% $method %ARGLIST% [list $arglist] %BODY% [list $body]
} else {
set typemethodInfo($method) {0 "%t::Snit_htypemethod%j %t" ""}
Mappend compile(defs) {
proc %TYPE%::Snit_htypemethod%JMETHOD% %ARGLIST% %BODY%
} %JMETHOD% [join $method _] \
%ARGLIST% [list $arglist] %BODY% [list $body]
}
}
# Defines a type constructor.
proc ::snit::Comp.statement.typeconstructor {body} {
variable compile
if {"" != $compile(typeconstructor)} {
error "too many typeconstructors"
}
set compile(typeconstructor) $body
}
# Defines a static proc in the type's namespace.
proc ::snit::Comp.statement.proc {proc arglist body} {
variable compile
# If "ns" is defined, the proc can see instance variables.
if {[lsearch -exact $arglist selfns] != -1} {
# Next, add instance variable declarations to body:
set body "%IVARDECS%\n$body"
}
# The proc can always see typevariables.
set body "%TVARDECS%\n$body"
append compile(defs) "
# Proc $proc
proc [list %TYPE%::$proc $arglist $body]
"
}
# Defines a static variable in the type's namespace.
proc ::snit::Comp.statement.typevariable {name args} {
variable compile
set errRoot "Error in \"typevariable $name...\""
set len [llength $args]
if {$len > 2 ||
($len == 2 && [lindex $args 0] ne "-array")} {
error "$errRoot, too many initializers"
}
if {[lsearch -exact $compile(varnames) $name] != -1} {
error "$errRoot, \"$name\" is already an instance variable"
}
lappend compile(typevarnames) $name
if {$len == 1} {
append compile(typevars) \
"\n\t [list ::variable $name [lindex $args 0]]"
} elseif {$len == 2} {
append compile(typevars) \
"\n\t [list ::variable $name]"
append compile(typevars) \
"\n\t [list array set $name [lindex $args 1]]"
} else {
append compile(typevars) \
"\n\t [list ::variable $name]"
}
if {$compile(tvprocdec) eq ""} {
set compile(tvprocdec) "\n\t"
append compile(tvprocdec) "namespace upvar [list $compile(type)]"
}
append compile(tvprocdec) " [list $name $name]"
}
# Defines an instance variable; the definition will go in the
# type's create typemethod.
proc ::snit::Comp.statement.variable {name args} {
variable compile
set errRoot "Error in \"variable $name...\""
set len [llength $args]
if {$len > 2 ||
($len == 2 && [lindex $args 0] ne "-array")} {
error "$errRoot, too many initializers"
}
if {[lsearch -exact $compile(typevarnames) $name] != -1} {
error "$errRoot, \"$name\" is already a typevariable"
}
lappend compile(varnames) $name
# Add a ::variable to instancevars, so that ::variable is used
# at least once; ::variable makes the variable visible to
# [info vars] even if no value is assigned.
append compile(instancevars) "\n"
Mappend compile(instancevars) {::variable ${selfns}::%N} %N $name
if {$len == 1} {
append compile(instancevars) \
"\nset $name [list [lindex $args 0]]\n"
} elseif {$len == 2} {
append compile(instancevars) \
"\narray set $name [list [lindex $args 1]]\n"
}
if {$compile(ivprocdec) eq ""} {
set compile(ivprocdec) "\n\t"
append compile(ivprocdec) {namespace upvar $selfns}
}
append compile(ivprocdec) " [list $name $name]"
}
# Defines a typecomponent, and handles component options.
#
# component The logical name of the delegate
# args options.
proc ::snit::Comp.statement.typecomponent {component args} {
variable compile
set errRoot "Error in \"typecomponent $component...\""
# FIRST, define the component
Comp.DefineTypecomponent $component $errRoot
# NEXT, handle the options.
set publicMethod ""
set inheritFlag 0
foreach {opt val} $args {
switch -exact -- $opt {
-public {
set publicMethod $val
}
-inherit {
set inheritFlag $val
if {![string is boolean $inheritFlag]} {
error "typecomponent $component -inherit: expected boolean value, got \"$val\""
}
}
default {
error "typecomponent $component: Invalid option \"$opt\""
}
}
}
# NEXT, if -public specified, define the method.
if {$publicMethod ne ""} {
Comp.statement.delegate typemethod [list $publicMethod *] to $component
}
# NEXT, if "-inherit 1" is specified, delegate typemethod * to
# this component.
if {$inheritFlag} {
Comp.statement.delegate typemethod "*" to $component
}
}
# Defines a name to be a typecomponent
#
# The name becomes a typevariable; in addition, it gets a
# write trace so that when it is set, all of the component mechanisms
# get updated.
#
# component The component name
proc ::snit::Comp.DefineTypecomponent {component {errRoot "Error"}} {
variable compile
if {[lsearch -exact $compile(varnames) $component] != -1} {
error "$errRoot, \"$component\" is already an instance variable"
}
if {[lsearch -exact $compile(typecomponents) $component] == -1} {
# Remember we've done this.
lappend compile(typecomponents) $component
# Make it a type variable with no initial value
Comp.statement.typevariable $component ""
# Add a write trace to do the component thing.
Mappend compile(typevars) {
trace add variable %COMP% write \
[list ::snit::RT.TypecomponentTrace [list %TYPE%] %COMP%]
} %TYPE% $compile(type) %COMP% $component
}
}
# Defines a component, and handles component options.
#
# component The logical name of the delegate
# args options.
#
# TBD: Ideally, it should be possible to call this statement multiple
# times, possibly changing the option values. To do that, I'd need
# to cache the option values and not act on them until *after* I'd
# read the entire type definition.
proc ::snit::Comp.statement.component {component args} {
variable compile
set errRoot "Error in \"component $component...\""
# FIRST, define the component
Comp.DefineComponent $component $errRoot
# NEXT, handle the options.
set publicMethod ""
set inheritFlag 0
foreach {opt val} $args {
switch -exact -- $opt {
-public {
set publicMethod $val
}
-inherit {
set inheritFlag $val
if {![string is boolean $inheritFlag]} {
error "component $component -inherit: expected boolean value, got \"$val\""
}
}
default {
error "component $component: Invalid option \"$opt\""
}
}
}
# NEXT, if -public specified, define the method.
if {$publicMethod ne ""} {
Comp.statement.delegate method [list $publicMethod *] to $component
}
# NEXT, if -inherit is specified, delegate method/option * to
# this component.
if {$inheritFlag} {
Comp.statement.delegate method "*" to $component
Comp.statement.delegate option "*" to $component
}
}
# Defines a name to be a component
#
# The name becomes an instance variable; in addition, it gets a
# write trace so that when it is set, all of the component mechanisms
# get updated.
#
# component The component name
proc ::snit::Comp.DefineComponent {component {errRoot "Error"}} {
variable compile
if {[lsearch -exact $compile(typevarnames) $component] != -1} {
error "$errRoot, \"$component\" is already a typevariable"
}
if {[lsearch -exact $compile(components) $component] == -1} {
# Remember we've done this.
lappend compile(components) $component
# Make it an instance variable with no initial value
Comp.statement.variable $component ""
# Add a write trace to do the component thing.
Mappend compile(instancevars) {
trace add variable ${selfns}::%COMP% write \
[list ::snit::RT.ComponentTrace [list %TYPE%] $selfns %COMP%]
} %TYPE% $compile(type) %COMP% $component
}
}
# Creates a delegated method, typemethod, or option.
proc ::snit::Comp.statement.delegate {what name args} {
# FIRST, dispatch to correct handler.
switch $what {
typemethod { Comp.DelegatedTypemethod $name $args }
method { Comp.DelegatedMethod $name $args }
option { Comp.DelegatedOption $name $args }
default {
error "Error in \"delegate $what $name...\", \"$what\"?"
}
}
if {([llength $args] % 2) != 0} {
error "Error in \"delegate $what $name...\", invalid syntax"
}
}
# Creates a delegated typemethod delegating it to a particular
# typecomponent or an arbitrary command.
#
# method The name of the method
# arglist Delegation options
proc ::snit::Comp.DelegatedTypemethod {method arglist} {
variable compile
variable typemethodInfo
set errRoot "Error in \"delegate typemethod [list $method]...\""
# Next, parse the delegation options.
set component ""
set target ""
set exceptions {}
set pattern ""
set methodTail [lindex $method end]
foreach {opt value} $arglist {
switch -exact $opt {
to { set component $value }
as { set target $value }
except { set exceptions $value }
using { set pattern $value }
default {
error "$errRoot, unknown delegation option \"$opt\""
}
}
}
if {$component eq "" && $pattern eq ""} {
error "$errRoot, missing \"to\""
}
if {$methodTail eq "*" && $target ne ""} {
error "$errRoot, cannot specify \"as\" with \"*\""
}
if {$methodTail ne "*" && $exceptions ne ""} {
error "$errRoot, can only specify \"except\" with \"*\""
}
if {$pattern ne "" && $target ne ""} {
error "$errRoot, cannot specify both \"as\" and \"using\""
}
foreach token [lrange $method 1 end-1] {
if {$token eq "*"} {
error "$errRoot, \"*\" must be the last token."
}
}
# NEXT, define the component
if {$component ne ""} {
Comp.DefineTypecomponent $component $errRoot
}
# NEXT, define the pattern.
if {$pattern eq ""} {
if {$methodTail eq "*"} {
set pattern "%c %m"
} elseif {$target ne ""} {
set pattern "%c $target"
} else {
set pattern "%c %m"
}
}
# Make sure the pattern is a valid list.
if {[catch {lindex $pattern 0} result]} {
error "$errRoot, the using pattern, \"$pattern\", is not a valid list"
}
# NEXT, check the method name against previously defined
# methods.
Comp.CheckMethodName $method 1 ::snit::typemethodInfo $errRoot
set typemethodInfo($method) [list 0 $pattern $component]
if {[string equal $methodTail "*"]} {
Mappend compile(defs) {
set %TYPE%::Snit_info(excepttypemethods) %EXCEPT%
} %EXCEPT% [list $exceptions]
}
}
# Creates a delegated method delegating it to a particular
# component or command.
#
# method The name of the method
# arglist Delegation options.
proc ::snit::Comp.DelegatedMethod {method arglist} {
variable compile
variable methodInfo
set errRoot "Error in \"delegate method [list $method]...\""
# Next, parse the delegation options.
set component ""
set target ""
set exceptions {}
set pattern ""
set methodTail [lindex $method end]
foreach {opt value} $arglist {
switch -exact $opt {
to { set component $value }
as { set target $value }
except { set exceptions $value }
using { set pattern $value }
default {
error "$errRoot, unknown delegation option \"$opt\""
}
}
}
if {$component eq "" && $pattern eq ""} {
error "$errRoot, missing \"to\""
}
if {$methodTail eq "*" && $target ne ""} {
error "$errRoot, cannot specify \"as\" with \"*\""
}
if {$methodTail ne "*" && $exceptions ne ""} {
error "$errRoot, can only specify \"except\" with \"*\""
}
if {$pattern ne "" && $target ne ""} {
error "$errRoot, cannot specify both \"as\" and \"using\""
}
foreach token [lrange $method 1 end-1] {
if {$token eq "*"} {
error "$errRoot, \"*\" must be the last token."
}
}
# NEXT, we delegate some methods
set compile(delegatesmethods) yes
# NEXT, define the component. Allow typecomponents.
if {$component ne ""} {
if {[lsearch -exact $compile(typecomponents) $component] == -1} {
Comp.DefineComponent $component $errRoot
}
}
# NEXT, define the pattern.
if {$pattern eq ""} {
if {$methodTail eq "*"} {
set pattern "%c %m"
} elseif {$target ne ""} {
set pattern "%c $target"
} else {
set pattern "%c %m"
}
}
# Make sure the pattern is a valid list.
if {[catch {lindex $pattern 0} result]} {
error "$errRoot, the using pattern, \"$pattern\", is not a valid list"
}
# NEXT, check the method name against previously defined
# methods.
Comp.CheckMethodName $method 1 ::snit::methodInfo $errRoot
# NEXT, save the method info.
set methodInfo($method) [list 0 $pattern $component]
if {[string equal $methodTail "*"]} {
Mappend compile(defs) {
set %TYPE%::Snit_info(exceptmethods) %EXCEPT%
} %EXCEPT% [list $exceptions]
}
}
# Creates a delegated option, delegating it to a particular
# component and, optionally, to a particular option of that
# component.
#
# optionDef The option definition
# args definition arguments.
proc ::snit::Comp.DelegatedOption {optionDef arglist} {
variable compile
# First, get the three option names.
set option [lindex $optionDef 0]
set resourceName [lindex $optionDef 1]
set className [lindex $optionDef 2]
set errRoot "Error in \"delegate option [list $optionDef]...\""
# Next, parse the delegation options.
set component ""
set target ""
set exceptions {}
foreach {opt value} $arglist {
switch -exact $opt {
to { set component $value }
as { set target $value }
except { set exceptions $value }
default {
error "$errRoot, unknown delegation option \"$opt\""
}
}
}
if {$component eq ""} {
error "$errRoot, missing \"to\""
}
if {$option eq "*" && $target ne ""} {
error "$errRoot, cannot specify \"as\" with \"delegate option *\""
}
if {$option ne "*" && $exceptions ne ""} {
error "$errRoot, can only specify \"except\" with \"delegate option *\""
}
# Next, validate the option name
if {"*" != $option} {
if {![Comp.OptionNameIsValid $option]} {
error "$errRoot, badly named option \"$option\""
}
}
if {$option in $compile(localoptions)} {
error "$errRoot, \"$option\" has been defined locally"
}
if {$option in $compile(delegatedoptions)} {
error "$errRoot, \"$option\" is multiply delegated"
}
# NEXT, define the component
Comp.DefineComponent $component $errRoot
# Next, define the target option, if not specified.
if {![string equal $option "*"] &&
[string equal $target ""]} {
set target $option
}
# NEXT, save the delegation data.
set compile(hasoptions) yes
if {![string equal $option "*"]} {
lappend compile(delegatedoptions) $option
# Next, compute the resource and class names, if they aren't
# already defined.
if {"" == $resourceName} {
set resourceName [string range $option 1 end]
}
if {"" == $className} {
set className [Capitalize $resourceName]
}
Mappend compile(defs) {
set %TYPE%::Snit_optionInfo(islocal-%OPTION%) 0
set %TYPE%::Snit_optionInfo(resource-%OPTION%) %RES%
set %TYPE%::Snit_optionInfo(class-%OPTION%) %CLASS%
lappend %TYPE%::Snit_optionInfo(delegated) %OPTION%
set %TYPE%::Snit_optionInfo(target-%OPTION%) [list %COMP% %TARGET%]
lappend %TYPE%::Snit_optionInfo(delegated-%COMP%) %OPTION%
} %OPTION% $option \
%COMP% $component \
%TARGET% $target \
%RES% $resourceName \
%CLASS% $className
} else {
Mappend compile(defs) {
set %TYPE%::Snit_optionInfo(starcomp) %COMP%
set %TYPE%::Snit_optionInfo(except) %EXCEPT%
} %COMP% $component %EXCEPT% [list $exceptions]
}
}
# Exposes a component, effectively making the component's command an
# instance method.
#
# component The logical name of the delegate
# "as" sugar; if not "", must be "as"
# methodname The desired method name for the component's command, or ""
proc ::snit::Comp.statement.expose {component {"as" ""} {methodname ""}} {
variable compile
# FIRST, define the component
Comp.DefineComponent $component
# NEXT, define the method just as though it were in the type
# definition.
if {[string equal $methodname ""]} {
set methodname $component
}
Comp.statement.method $methodname args [Expand {
if {[llength $args] == 0} {
return $%COMPONENT%
}
if {[string equal $%COMPONENT% ""]} {
error "undefined component \"%COMPONENT%\""
}
set cmd [linsert $args 0 $%COMPONENT%]
return [uplevel 1 $cmd]
} %COMPONENT% $component]
}
#-----------------------------------------------------------------------
# Public commands
# Compile a type definition, and return the results as a list of two
# items: the fully-qualified type name, and a script that will define
# the type when executed.
#
# which type, widget, or widgetadaptor
# type the type name
# body the type definition
proc ::snit::compile {which type body} {
return [Comp.Compile $which $type $body]
}
proc ::snit::type {type body} {
return [Comp.Define [Comp.Compile type $type $body]]
}
proc ::snit::widget {type body} {
return [Comp.Define [Comp.Compile widget $type $body]]
}
proc ::snit::widgetadaptor {type body} {
return [Comp.Define [Comp.Compile widgetadaptor $type $body]]
}
proc ::snit::typemethod {type method arglist body} {
# Make sure the type exists.
if {![info exists ${type}::Snit_info]} {
error "no such type: \"$type\""
}
upvar ${type}::Snit_info Snit_info
upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo
# FIRST, check the typemethod name against previously defined
# typemethods.
Comp.CheckMethodName $method 0 ${type}::Snit_typemethodInfo \
"Cannot define \"$method\""
# NEXT, check the arguments
CheckArgs "snit::typemethod $type $method" $arglist
# Next, add magic reference to type.
set arglist [concat type $arglist]
# Next, add typevariable declarations to body:
set body "$Snit_info(tvardecs)\n$body"
# Next, define it.
if {[llength $method] == 1} {
set Snit_typemethodInfo($method) {0 "%t::Snit_typemethod%m %t" ""}
uplevel 1 [list proc ${type}::Snit_typemethod$method $arglist $body]
} else {
set Snit_typemethodInfo($method) {0 "%t::Snit_htypemethod%j %t" ""}
set suffix [join $method _]
uplevel 1 [list proc ${type}::Snit_htypemethod$suffix $arglist $body]
}
}
proc ::snit::method {type method arglist body} {
# Make sure the type exists.
if {![info exists ${type}::Snit_info]} {
error "no such type: \"$type\""
}
upvar ${type}::Snit_methodInfo Snit_methodInfo
upvar ${type}::Snit_info Snit_info
# FIRST, check the method name against previously defined
# methods.
Comp.CheckMethodName $method 0 ${type}::Snit_methodInfo \
"Cannot define \"$method\""
# NEXT, check the arguments
CheckArgs "snit::method $type $method" $arglist
# Next, add magic references to type and self.
set arglist [concat type selfns win self $arglist]
# Next, add variable declarations to body:
set body "$Snit_info(tvardecs)\n$Snit_info(ivardecs)\n$body"
# Next, define it.
if {[llength $method] == 1} {
set Snit_methodInfo($method) {0 "%t::Snit_method%m %t %n %w %s" ""}
uplevel 1 [list proc ${type}::Snit_method$method $arglist $body]
} else {
set Snit_methodInfo($method) {0 "%t::Snit_hmethod%j %t %n %w %s" ""}
set suffix [join $method _]
uplevel 1 [list proc ${type}::Snit_hmethod$suffix $arglist $body]
}
}
# Defines a proc within the compiler; this proc can call other
# type definition statements, and thus can be used for meta-programming.
proc ::snit::macro {name arglist body} {
variable compiler
variable reservedwords
# FIRST, make sure the compiler is defined.
Comp.Init
# NEXT, check the macro name against the reserved words
if {[lsearch -exact $reservedwords $name] != -1} {
error "invalid macro name \"$name\""
}
# NEXT, see if the name has a namespace; if it does, define the
# namespace.
set ns [namespace qualifiers $name]
if {$ns ne ""} {
$compiler eval "namespace eval $ns {}"
}
# NEXT, define the macro
$compiler eval [list _proc $name $arglist $body]
}
#-----------------------------------------------------------------------
# Utility Functions
#
# These are utility functions used while compiling Snit types.
# Builds a template from a tagged list of text blocks, then substitutes
# all symbols in the mapTable, returning the expanded template.
proc ::snit::Expand {template args} {
return [string map $args $template]
}
# Expands a template and appends it to a variable.
proc ::snit::Mappend {varname template args} {
upvar $varname myvar
append myvar [string map $args $template]
}
# Checks argument list against reserved args
proc ::snit::CheckArgs {which arglist} {
variable reservedArgs
foreach name $reservedArgs {
if {$name in $arglist} {
error "$which's arglist may not contain \"$name\" explicitly"
}
}
}
# Capitalizes the first letter of a string.
proc ::snit::Capitalize {text} {
return [string toupper $text 0]
}
#=======================================================================
# Snit Runtime Library
#
# These are procs used by Snit types and widgets at runtime.
#-----------------------------------------------------------------------
# Object Creation
# Creates a new instance of the snit::type given its name and the args.
#
# type The snit::type
# name The instance name
# args Args to pass to the constructor
proc ::snit::RT.type.typemethod.create {type name args} {
variable ${type}::Snit_info
variable ${type}::Snit_optionInfo
# FIRST, qualify the name.
if {![string match "::*" $name]} {
# Get caller's namespace;
# append :: if not global namespace.
set ns [uplevel 1 [list namespace current]]
if {"::" != $ns} {
append ns "::"
}
set name "$ns$name"
}
# NEXT, if %AUTO% appears in the name, generate a unique
# command name. Otherwise, ensure that the name isn't in use.
if {[string match "*%AUTO%*" $name]} {
set name [::snit::RT.UniqueName Snit_info(counter) $type $name]
} elseif {!$Snit_info(canreplace) && [llength [info commands $name]]} {
error "command \"$name\" already exists"
}
# NEXT, create the instance's namespace.
set selfns \
[::snit::RT.UniqueInstanceNamespace Snit_info(counter) $type]
namespace eval $selfns {}
# NEXT, install the dispatcher
RT.MakeInstanceCommand $type $selfns $name
# Initialize the options to their defaults.
namespace upvar ${selfns} options options
foreach opt $Snit_optionInfo(local) {
set options($opt) $Snit_optionInfo(default-$opt)
}
# Initialize the instance vars to their defaults.
# selfns must be defined, as it is used implicitly.
${type}::Snit_instanceVars $selfns
# Execute the type's constructor.
set errcode [catch {
RT.ConstructInstance $type $selfns $name $args
} result]
if {$errcode} {
global errorInfo
global errorCode
set theInfo $errorInfo
set theCode $errorCode
::snit::RT.DestroyObject $type $selfns $name
error "Error in constructor: $result" $theInfo $theCode
}
# NEXT, return the object's name.
return $name
}
# Creates a new instance of the snit::widget or snit::widgetadaptor
# given its name and the args.
#
# type The snit::widget or snit::widgetadaptor
# name The instance name
# args Args to pass to the constructor
proc ::snit::RT.widget.typemethod.create {type name args} {
variable ${type}::Snit_info
variable ${type}::Snit_optionInfo
# FIRST, if %AUTO% appears in the name, generate a unique
# command name.
if {[string match "*%AUTO%*" $name]} {
set name [::snit::RT.UniqueName Snit_info(counter) $type $name]
}
# NEXT, create the instance's namespace.
set selfns \
[::snit::RT.UniqueInstanceNamespace Snit_info(counter) $type]
namespace eval $selfns { }
# NEXT, Initialize the widget's own options to their defaults.
namespace upvar $selfns options options
foreach opt $Snit_optionInfo(local) {
set options($opt) $Snit_optionInfo(default-$opt)
}
# Initialize the instance vars to their defaults.
${type}::Snit_instanceVars $selfns
# NEXT, if this is a normal widget (not a widget adaptor) then create a
# frame as its hull. We set the frame's -class to the user's widgetclass,
# or, if none, search for -class in the args list, otherwise default to
# the basename of the $type with an initial upper case letter.
if {!$Snit_info(isWidgetAdaptor)} {
# FIRST, determine the class name
set wclass $Snit_info(widgetclass)
if {$Snit_info(widgetclass) eq ""} {
set idx [lsearch -exact $args -class]
if {$idx >= 0 && ($idx%2 == 0)} {
# -class exists and is in the -option position
set wclass [lindex $args [expr {$idx+1}]]
set args [lreplace $args $idx [expr {$idx+1}]]
} else {
set wclass [::snit::Capitalize [namespace tail $type]]
}
}
# NEXT, create the widget
set self $name
package require Tk
${type}::installhull using $Snit_info(hulltype) -class $wclass
# NEXT, let's query the option database for our
# widget, now that we know that it exists.
foreach opt $Snit_optionInfo(local) {
set dbval [RT.OptionDbGet $type $name $opt]
if {"" != $dbval} {
set options($opt) $dbval
}
}
}
# Execute the type's constructor, and verify that it
# has a hull.
set errcode [catch {
RT.ConstructInstance $type $selfns $name $args
::snit::RT.Component $type $selfns hull
# Prepare to call the object's destructor when the
# event is received. Use a Snit-specific bindtag
# so that the widget name's tag is unencumbered.
bind Snit$type$name [::snit::Expand {
::snit::RT.DestroyObject %TYPE% %NS% %W
} %TYPE% $type %NS% $selfns]
# Insert the bindtag into the list of bindtags right
# after the widget name.
set taglist [bindtags $name]
set ndx [lsearch -exact $taglist $name]
incr ndx
bindtags $name [linsert $taglist $ndx Snit$type$name]
} result]
if {$errcode} {
global errorInfo
global errorCode
set theInfo $errorInfo
set theCode $errorCode
::snit::RT.DestroyObject $type $selfns $name
error "Error in constructor: $result" $theInfo $theCode
}
# NEXT, return the object's name.
return $name
}
# RT.MakeInstanceCommand type selfns instance
#
# type The object type
# selfns The instance namespace
# instance The instance name
#
# Creates the instance proc.
proc ::snit::RT.MakeInstanceCommand {type selfns instance} {
variable ${type}::Snit_info
# FIRST, remember the instance name. The Snit_instance variable
# allows the instance to figure out its current name given the
# instance namespace.
namespace upvar $selfns Snit_instance Snit_instance
set Snit_instance $instance
# NEXT, qualify the proc name if it's a widget.
if {$Snit_info(isWidget)} {
set procname ::$instance
} else {
set procname $instance
}
# NEXT, install the new proc
# WHD: Snit 2.0 code
set unknownCmd [list ::snit::RT.UnknownMethod $type $selfns $instance ""]
set createCmd [list namespace ensemble create \
-command $procname \
-unknown $unknownCmd \
-prefixes 0]
namespace eval $selfns $createCmd
# NEXT, add the trace.
trace add command $procname {rename delete} \
[list ::snit::RT.InstanceTrace $type $selfns $instance]
}
# This proc is called when the instance command is renamed.
# If op is delete, then new will always be "", so op is redundant.
#
# type The fully-qualified type name
# selfns The instance namespace
# win The original instance/tk window name.
# old old instance command name
# new new instance command name
# op rename or delete
#
# If the op is delete, we need to clean up the object; otherwise,
# we need to track the change.
#
# NOTE: In Tcl 8.4.2 there's a bug: errors in rename and delete
# traces aren't propagated correctly. Instead, they silently
# vanish. Add a catch to output any error message.
proc ::snit::RT.InstanceTrace {type selfns win old new op} {
variable ${type}::Snit_info
# Note to developers ...
# For Tcl 8.4.0, errors thrown in trace handlers vanish silently.
# Therefore we catch them here and create some output to help in
# debugging such problems.
if {[catch {
# FIRST, clean up if necessary
if {"" == $new} {
if {$Snit_info(isWidget)} {
destroy $win
} else {
::snit::RT.DestroyObject $type $selfns $win
}
} else {
# Otherwise, track the change.
variable ${selfns}::Snit_instance
set Snit_instance [uplevel 1 [list namespace which -command $new]]
# Also, clear the instance caches, as many cached commands
# might be invalid.
RT.ClearInstanceCaches $selfns
}
} result]} {
global errorInfo
# Pop up the console on Windows wish, to enable stdout.
# This clobbers errorInfo on unix, so save it so we can print it.
set ei $errorInfo
catch {console show}
puts "Error in ::snit::RT.InstanceTrace $type $selfns $win $old $new $op:"
puts $ei
}
}
# Calls the instance constructor and handles related housekeeping.
proc ::snit::RT.ConstructInstance {type selfns instance arglist} {
variable ${type}::Snit_optionInfo
variable ${selfns}::Snit_iinfo
# Track whether we are constructed or not.
set Snit_iinfo(constructed) 0
# Call the user's constructor
eval [linsert $arglist 0 \
${type}::Snit_constructor $type $selfns $instance $instance]
set Snit_iinfo(constructed) 1
# Validate the initial set of options (including defaults)
foreach option $Snit_optionInfo(local) {
set value [set ${selfns}::options($option)]
if {$Snit_optionInfo(typespec-$option) ne ""} {
if {[catch {
$Snit_optionInfo(typeobj-$option) validate $value
} result]} {
return -code error "invalid $option default: $result"
}
}
}
# Unset the configure cache for all -readonly options.
# This ensures that the next time anyone tries to
# configure it, an error is thrown.
foreach opt $Snit_optionInfo(local) {
if {$Snit_optionInfo(readonly-$opt)} {
unset -nocomplain ${selfns}::Snit_configureCache($opt)
}
}
return
}
# Returns a unique command name.
#
# REQUIRE: type is a fully qualified name.
# REQUIRE: name contains "%AUTO%"
# PROMISE: the returned command name is unused.
proc ::snit::RT.UniqueName {countervar type name} {
upvar $countervar counter
while 1 {
# FIRST, bump the counter and define the %AUTO% instance name;
# then substitute it into the specified name. Wrap around at
# 2^31 - 2 to prevent overflow problems.
incr counter
if {$counter > 2147483646} {
set counter 0
}
set auto "[namespace tail $type]$counter"
set candidate [Expand $name %AUTO% $auto]
if {![llength [info commands $candidate]]} {
return $candidate
}
}
}
# Returns a unique instance namespace, fully qualified.
#
# countervar The name of a counter variable
# type The instance's type
#
# REQUIRE: type is fully qualified
# PROMISE: The returned namespace name is unused.
proc ::snit::RT.UniqueInstanceNamespace {countervar type} {
upvar $countervar counter
while 1 {
# FIRST, bump the counter and define the namespace name.
# Then see if it already exists. Wrap around at
# 2^31 - 2 to prevent overflow problems.
incr counter
if {$counter > 2147483646} {
set counter 0
}
set ins "${type}::Snit_inst${counter}"
if {![namespace exists $ins]} {
return $ins
}
}
}
# Retrieves an option's value from the option database.
# Returns "" if no value is found.
proc ::snit::RT.OptionDbGet {type self opt} {
variable ${type}::Snit_optionInfo
return [option get $self \
$Snit_optionInfo(resource-$opt) \
$Snit_optionInfo(class-$opt)]
}
#-----------------------------------------------------------------------
# Object Destruction
# Implements the standard "destroy" method
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
proc ::snit::RT.method.destroy {type selfns win self} {
variable ${selfns}::Snit_iinfo
# Can't destroy the object if it isn't complete constructed.
if {!$Snit_iinfo(constructed)} {
return -code error "Called 'destroy' method in constructor"
}
# Calls Snit_cleanup, which (among other things) calls the
# user's destructor.
::snit::RT.DestroyObject $type $selfns $win
}
# This is the function that really cleans up; it's automatically
# called when any instance is destroyed, e.g., by "$object destroy"
# for types, and by the event for widgets.
#
# type The fully-qualified type name.
# selfns The instance namespace
# win The original instance command name.
proc ::snit::RT.DestroyObject {type selfns win} {
variable ${type}::Snit_info
# If the variable Snit_instance doesn't exist then there's no
# instance command for this object -- it's most likely a
# widgetadaptor. Consequently, there are some things that
# we don't need to do.
if {[info exists ${selfns}::Snit_instance]} {
namespace upvar $selfns Snit_instance instance
# First, remove the trace on the instance name, so that we
# don't call RT.DestroyObject recursively.
RT.RemoveInstanceTrace $type $selfns $win $instance
# Next, call the user's destructor
${type}::Snit_destructor $type $selfns $win $instance
# Next, if this isn't a widget, delete the instance command.
# If it is a widget, get the hull component's name, and rename
# it back to the widget name
# Next, delete the hull component's instance command,
# if there is one.
if {$Snit_info(isWidget)} {
set hullcmd [::snit::RT.Component $type $selfns hull]
catch {rename $instance ""}
# Clear the bind event
bind Snit$type$win ""
if {[llength [info commands $hullcmd]]} {
# FIRST, rename the hull back to its original name.
# If the hull is itself a megawidget, it will have its
# own cleanup to do, and it might not do it properly
# if it doesn't have the right name.
rename $hullcmd ::$instance
# NEXT, destroy it.
destroy $instance
}
} else {
catch {rename $instance ""}
}
}
# Next, delete the instance's namespace. This kills any
# instance variables.
namespace delete $selfns
return
}
# Remove instance trace
#
# type The fully qualified type name
# selfns The instance namespace
# win The original instance name/Tk window name
# instance The current instance name
proc ::snit::RT.RemoveInstanceTrace {type selfns win instance} {
variable ${type}::Snit_info
if {$Snit_info(isWidget)} {
set procname ::$instance
} else {
set procname $instance
}
# NEXT, remove any trace on this name
catch {
trace remove command $procname {rename delete} \
[list ::snit::RT.InstanceTrace $type $selfns $win]
}
}
#-----------------------------------------------------------------------
# Typecomponent Management and Method Caching
# Typecomponent trace; used for write trace on typecomponent
# variables. Saves the new component object name, provided
# that certain conditions are met. Also clears the typemethod
# cache.
proc ::snit::RT.TypecomponentTrace {type component n1 n2 op} {
namespace upvar $type \
Snit_info Snit_info \
$component cvar \
Snit_typecomponents Snit_typecomponents
# Save the new component value.
set Snit_typecomponents($component) $cvar
# Clear the typemethod cache.
# TBD: can we unset just the elements related to
# this component?
# WHD: Namespace 2.0 code
namespace ensemble configure $type -map {}
}
# WHD: Snit 2.0 code
#
# RT.UnknownTypemethod type eId eCmd method args
#
# type The type
# eId The ensemble command ID; "" for the instance itself.
# eCmd The ensemble command name.
# method The unknown method name.
# args The additional arguments, if any.
#
# This proc looks up the method relative to the specified ensemble.
# If no method is found, it assumes that the "create" method is
# desired, and that the "method" is the instance name. In this case,
# it returns the "create" typemethod command with the instance name
# appended; this will cause the instance to be created without updating
# the -map. If the method is found, the method's command is created and
# added to the -map; the function returns the empty list.
proc snit::RT.UnknownTypemethod {type eId eCmd method args} {
namespace upvar $type \
Snit_typemethodInfo Snit_typemethodInfo \
Snit_typecomponents Snit_typecomponents \
Snit_info Snit_info
# FIRST, get the pattern data and the typecomponent name.
set implicitCreate 0
set instanceName ""
set fullMethod $eId
lappend fullMethod $method
set starredMethod [concat $eId *]
set methodTail $method
if {[info exists Snit_typemethodInfo($fullMethod)]} {
set key $fullMethod
} elseif {[info exists Snit_typemethodInfo($starredMethod)]} {
if {[lsearch -exact $Snit_info(excepttypemethods) $methodTail] == -1} {
set key $starredMethod
} else {
# WHD: The method is explicitly not delegated, so this is an error.
# Or should we treat it as an instance name?
return [list ]
}
} elseif {$Snit_info(hasinstances)} {
# Assume the unknown name is an instance name to create, unless
# this is a widget and the style of the name is wrong, or the
# name mimics a standard typemethod.
if {[set ${type}::Snit_info(isWidget)] &&
![string match ".*" $method]} {
return [list ]
}
# Without this check, the call "$type info" will redefine the
# standard "::info" command, with disastrous results. Since it's
# a likely thing to do if !-typeinfo, put in an explicit check.
if {$method eq "info" || $method eq "destroy"} {
return [list ]
}
set implicitCreate 1
set instanceName $method
set key create
set method create
} else {
return [list ]
}
foreach {flag pattern compName} $Snit_typemethodInfo($key) {}
if {$flag == 1} {
# FIRST, define the ensemble command.
lappend eId $method
set newCmd ${type}::Snit_ten[llength $eId]_[join $eId _]
set unknownCmd [list ::snit::RT.UnknownTypemethod \
$type $eId]
set createCmd [list namespace ensemble create \
-command $newCmd \
-unknown $unknownCmd \
-prefixes 0]
namespace eval $type $createCmd
# NEXT, add the method to the current ensemble
set map [namespace ensemble configure $eCmd -map]
dict append map $method $newCmd
namespace ensemble configure $eCmd -map $map
return [list ]
}
# NEXT, build the substitution list
set subList [list \
%% % \
%t $type \
%M $fullMethod \
%m [lindex $fullMethod end] \
%j [join $fullMethod _]]
if {$compName ne ""} {
if {![info exists Snit_typecomponents($compName)]} {
error "$type delegates typemethod \"$method\" to undefined typecomponent \"$compName\""
}
lappend subList %c [list $Snit_typecomponents($compName)]
}
set command {}
foreach subpattern $pattern {
lappend command [string map $subList $subpattern]
}
if {$implicitCreate} {
# In this case, $method is the name of the instance to
# create. Don't cache, as we usually won't do this one
# again.
lappend command $instanceName
return $command
}
# NEXT, if the actual command name isn't fully qualified,
# assume it's global.
set cmd [lindex $command 0]
if {[string index $cmd 0] ne ":"} {
set command [lreplace $command 0 0 "::$cmd"]
}
# NEXT, update the ensemble map.
set map [namespace ensemble configure $eCmd -map]
dict append map $method $command
namespace ensemble configure $eCmd -map $map
return [list ]
}
#-----------------------------------------------------------------------
# Component Management and Method Caching
# Retrieves the object name given the component name.
proc ::snit::RT.Component {type selfns name} {
variable ${selfns}::Snit_components
if {[catch {set Snit_components($name)} result]} {
variable ${selfns}::Snit_instance
error "component \"$name\" is undefined in $type $Snit_instance"
}
return $result
}
# Component trace; used for write trace on component instance
# variables. Saves the new component object name, provided
# that certain conditions are met. Also clears the method
# cache.
proc ::snit::RT.ComponentTrace {type selfns component n1 n2 op} {
namespace upvar $type Snit_info Snit_info
namespace upvar $selfns \
$component cvar \
Snit_components Snit_components
# If they try to redefine the hull component after
# it's been defined, that's an error--but only if
# this is a widget or widget adaptor.
if {"hull" == $component &&
$Snit_info(isWidget) &&
[info exists Snit_components($component)]} {
set cvar $Snit_components($component)
error "The hull component cannot be redefined"
}
# Save the new component value.
set Snit_components($component) $cvar
# Clear the instance caches.
# TBD: can we unset just the elements related to
# this component?
RT.ClearInstanceCaches $selfns
}
# WHD: Snit 2.0 code
#
# RT.UnknownMethod type selfns win eId eCmd method args
#
# type The type or widget command.
# selfns The instance namespace.
# win The original instance name.
# eId The ensemble command ID; "" for the instance itself.
# eCmd The real ensemble command name
# method The unknown method name
# args The additional arguments, if any.
#
# This proc looks up the method relative to the specific ensemble.
# If no method is found, it returns an empty list; this will result in
# the parent ensemble throwing an error.
# If the method is found, the ensemble's -map is extended with the
# correct command, and the empty list is returned; this caches the
# method's command. If the method is found, and it is also an
# ensemble, the ensemble command is created with an empty map.
proc ::snit::RT.UnknownMethod {type selfns win eId eCmd method args} {
variable ${type}::Snit_info
variable ${type}::Snit_methodInfo
variable ${type}::Snit_typecomponents
variable ${selfns}::Snit_components
# FIRST, get the "self" value
set self [set ${selfns}::Snit_instance]
# FIRST, get the pattern data and the component name.
set fullMethod $eId
lappend fullMethod $method
set starredMethod [concat $eId *]
set methodTail $method
if {[info exists Snit_methodInfo($fullMethod)]} {
set key $fullMethod
} elseif {[info exists Snit_methodInfo($starredMethod)] &&
[lsearch -exact $Snit_info(exceptmethods) $methodTail] == -1} {
set key $starredMethod
} else {
return [list ]
}
foreach {flag pattern compName} $Snit_methodInfo($key) {}
if {$flag == 1} {
# FIRST, define the ensemble command.
lappend eId $method
# Fix provided by Anton Kovalenko; previously this call erroneously
# used ${type} rather than ${selfns}.
set newCmd ${selfns}::Snit_en[llength $eId]_[join $eId _]
set unknownCmd [list ::snit::RT.UnknownMethod \
$type $selfns $win $eId]
set createCmd [list namespace ensemble create \
-command $newCmd \
-unknown $unknownCmd \
-prefixes 0]
namespace eval $selfns $createCmd
# NEXT, add the method to the current ensemble
set map [namespace ensemble configure $eCmd -map]
dict append map $method $newCmd
namespace ensemble configure $eCmd -map $map
return [list ]
}
# NEXT, build the substitution list
set subList [list \
%% % \
%t $type \
%M $fullMethod \
%m [lindex $fullMethod end] \
%j [join $fullMethod _] \
%n [list $selfns] \
%w [list $win] \
%s [list $self]]
if {$compName ne ""} {
if {[info exists Snit_components($compName)]} {
set compCmd $Snit_components($compName)
} elseif {[info exists Snit_typecomponents($compName)]} {
set compCmd $Snit_typecomponents($compName)
} else {
error "$type $self delegates method \"$fullMethod\" to undefined component \"$compName\""
}
lappend subList %c [list $compCmd]
}
# Note: The cached command will execute faster if it's
# already a list.
set command {}
foreach subpattern $pattern {
lappend command [string map $subList $subpattern]
}
# NEXT, if the actual command name isn't fully qualified,
# assume it's global.
set cmd [lindex $command 0]
if {[string index $cmd 0] ne ":"} {
set command [lreplace $command 0 0 "::$cmd"]
}
# NEXT, update the ensemble map.
set map [namespace ensemble configure $eCmd -map]
dict append map $method $command
namespace ensemble configure $eCmd -map $map
return [list ]
}
# Clears all instance command caches
proc ::snit::RT.ClearInstanceCaches {selfns} {
# WHD: clear ensemble -map
if {![info exists ${selfns}::Snit_instance]} {
# Component variable set prior to constructor
# via the "variable" type definition statement.
return
}
set self [set ${selfns}::Snit_instance]
namespace ensemble configure $self -map {}
unset -nocomplain -- ${selfns}::Snit_cgetCache
unset -nocomplain -- ${selfns}::Snit_configureCache
unset -nocomplain -- ${selfns}::Snit_validateCache
}
#-----------------------------------------------------------------------
# Component Installation
# Implements %TYPE%::installhull. The variables self and selfns
# must be defined in the caller's context.
#
# Installs the named widget as the hull of a
# widgetadaptor. Once the widget is hijacked, its new name
# is assigned to the hull component.
proc ::snit::RT.installhull {type {using "using"} {widgetType ""} args} {
variable ${type}::Snit_info
variable ${type}::Snit_optionInfo
upvar 1 self self
upvar 1 selfns selfns
namespace upvar $selfns \
hull hull \
options options
# FIRST, make sure we can do it.
if {!$Snit_info(isWidget)} {
error "installhull is valid only for snit::widgetadaptors"
}
if {[info exists ${selfns}::Snit_instance]} {
error "hull already installed for $type $self"
}
# NEXT, has it been created yet? If not, create it using
# the specified arguments.
if {"using" == $using} {
# FIRST, create the widget
set cmd [linsert $args 0 $widgetType $self]
set obj [uplevel 1 $cmd]
# NEXT, for each option explicitly delegated to the hull
# that doesn't appear in the usedOpts list, get the
# option database value and apply it--provided that the
# real option name and the target option name are different.
# (If they are the same, then the option database was
# already queried as part of the normal widget creation.)
#
# Also, we don't need to worry about implicitly delegated
# options, as the option and target option names must be
# the same.
if {[info exists Snit_optionInfo(delegated-hull)]} {
# FIRST, extract all option names from args
set usedOpts {}
set ndx [lsearch -glob $args "-*"]
foreach {opt val} [lrange $args $ndx end] {
lappend usedOpts $opt
}
foreach opt $Snit_optionInfo(delegated-hull) {
set target [lindex $Snit_optionInfo(target-$opt) 1]
if {"$target" == $opt} {
continue
}
set result [lsearch -exact $usedOpts $target]
if {$result != -1} {
continue
}
set dbval [RT.OptionDbGet $type $self $opt]
$obj configure $target $dbval
}
}
} else {
set obj $using
if {$obj ne $self} {
error \
"hull name mismatch: \"$obj\" != \"$self\""
}
}
# NEXT, get the local option defaults.
foreach opt $Snit_optionInfo(local) {
set dbval [RT.OptionDbGet $type $self $opt]
if {"" != $dbval} {
set options($opt) $dbval
}
}
# NEXT, do the magic
set i 0
while 1 {
incr i
set newName "::hull${i}$self"
if {![llength [info commands $newName]]} {
break
}
}
rename ::$self $newName
RT.MakeInstanceCommand $type $selfns $self
# Note: this relies on RT.ComponentTrace to do the dirty work.
set hull $newName
return
}
# Implements %TYPE%::install.
#
# Creates a widget and installs it as the named component.
# It expects self and selfns to be defined in the caller's context.
proc ::snit::RT.install {type compName "using" widgetType winPath args} {
variable ${type}::Snit_optionInfo
variable ${type}::Snit_info
upvar 1 self self
upvar 1 selfns selfns
namespace upvar ${selfns} \
$compName comp \
hull hull
# We do the magic option database stuff only if $self is
# a widget.
if {$Snit_info(isWidget)} {
if {"" == $hull} {
error "tried to install \"$compName\" before the hull exists"
}
# FIRST, query the option database and save the results
# into args. Insert them before the first option in the
# list, in case there are any non-standard parameters.
#
# Note: there might not be any delegated options; if so,
# don't bother.
if {[info exists Snit_optionInfo(delegated-$compName)]} {
set ndx [lsearch -glob $args "-*"]
foreach opt $Snit_optionInfo(delegated-$compName) {
set dbval [RT.OptionDbGet $type $self $opt]
if {"" != $dbval} {
set target [lindex $Snit_optionInfo(target-$opt) 1]
set args [linsert $args $ndx $target $dbval]
}
}
}
}
# NEXT, create the component and save it.
set cmd [concat [list $widgetType $winPath] $args]
set comp [uplevel 1 $cmd]
# NEXT, handle the option database for "delegate option *",
# in widgets only.
if {$Snit_info(isWidget) && $Snit_optionInfo(starcomp) eq $compName} {
# FIRST, get the list of option specs from the widget.
# If configure doesn't work, skip it.
if {[catch {$comp configure} specs]} {
return
}
# NEXT, get the set of explicitly used options from args
set usedOpts {}
set ndx [lsearch -glob $args "-*"]
foreach {opt val} [lrange $args $ndx end] {
lappend usedOpts $opt
}
# NEXT, "delegate option *" matches all options defined
# by this widget that aren't defined by the widget as a whole,
# and that aren't excepted. Plus, we skip usedOpts. So build
# a list of the options it can't match.
set skiplist [concat \
$usedOpts \
$Snit_optionInfo(except) \
$Snit_optionInfo(local) \
$Snit_optionInfo(delegated)]
# NEXT, loop over all of the component's options, and set
# any not in the skip list for which there is an option
# database value.
foreach spec $specs {
# Skip aliases
if {[llength $spec] != 5} {
continue
}
set opt [lindex $spec 0]
if {[lsearch -exact $skiplist $opt] != -1} {
continue
}
set res [lindex $spec 1]
set cls [lindex $spec 2]
set dbvalue [option get $self $res $cls]
if {"" != $dbvalue} {
$comp configure $opt $dbvalue
}
}
}
return
}
#-----------------------------------------------------------------------
# Method/Variable Name Qualification
# Implements %TYPE%::variable. Requires selfns.
proc ::snit::RT.variable {varname} {
upvar 1 selfns selfns
if {![string match "::*" $varname]} {
uplevel 1 [list upvar 1 ${selfns}::$varname $varname]
} else {
# varname is fully qualified; let the standard
# "variable" command handle it.
uplevel 1 [list ::variable $varname]
}
}
# Fully qualifies a typevariable name.
#
# This is used to implement the mytypevar command.
proc ::snit::RT.mytypevar {type name} {
return ${type}::$name
}
# Fully qualifies an instance variable name.
#
# This is used to implement the myvar command.
proc ::snit::RT.myvar {name} {
upvar 1 selfns selfns
return ${selfns}::$name
}
# Use this like "list" to convert a proc call into a command
# string to pass to another object (e.g., as a -command).
# Qualifies the proc name properly.
#
# This is used to implement the "myproc" command.
proc ::snit::RT.myproc {type procname args} {
set procname "${type}::$procname"
return [linsert $args 0 $procname]
}
# DEPRECATED
proc ::snit::RT.codename {type name} {
return "${type}::$name"
}
# Use this like "list" to convert a typemethod call into a command
# string to pass to another object (e.g., as a -command).
# Inserts the type command at the beginning.
#
# This is used to implement the "mytypemethod" command.
proc ::snit::RT.mytypemethod {type args} {
return [linsert $args 0 $type]
}
# Use this like "list" to convert a method call into a command
# string to pass to another object (e.g., as a -command).
# Inserts the code at the beginning to call the right object, even if
# the object's name has changed. Requires that selfns be defined
# in the calling context, eg. can only be called in instance
# code.
#
# This is used to implement the "mymethod" command.
proc ::snit::RT.mymethod {args} {
upvar 1 selfns selfns
return [linsert $args 0 ::snit::RT.CallInstance ${selfns}]
}
# Calls an instance method for an object given its
# instance namespace and remaining arguments (the first of which
# will be the method name.
#
# selfns The instance namespace
# args The arguments
#
# Uses the selfns to determine $self, and calls the method
# in the normal way.
#
# This is used to implement the "mymethod" command.
proc ::snit::RT.CallInstance {selfns args} {
namespace upvar $selfns Snit_instance self
set retval [catch {uplevel 1 [linsert $args 0 $self]} result]
if {$retval} {
if {$retval == 1} {
global errorInfo
global errorCode
return -code error -errorinfo $errorInfo \
-errorcode $errorCode $result
} else {
return -code $retval $result
}
}
return $result
}
# Looks for the named option in the named variable. If found,
# it and its value are removed from the list, and the value
# is returned. Otherwise, the default value is returned.
# If the option is undelegated, it's own default value will be
# used if none is specified.
#
# Implements the "from" command.
proc ::snit::RT.from {type argvName option {defvalue ""}} {
namespace upvar $type Snit_optionInfo Snit_optionInfo
upvar $argvName argv
set ioption [lsearch -exact $argv $option]
if {$ioption == -1} {
if {"" == $defvalue &&
[info exists Snit_optionInfo(default-$option)]} {
return $Snit_optionInfo(default-$option)
} else {
return $defvalue
}
}
set ivalue [expr {$ioption + 1}]
set value [lindex $argv $ivalue]
set argv [lreplace $argv $ioption $ivalue]
return $value
}
#-----------------------------------------------------------------------
# Type Destruction
# Implements the standard "destroy" typemethod:
# Destroys a type completely.
#
# type The snit type
proc ::snit::RT.typemethod.destroy {type} {
variable ${type}::Snit_info
# FIRST, destroy all instances
foreach selfns [namespace children $type] {
if {![namespace exists $selfns]} {
continue
}
namespace upvar $selfns Snit_instance obj
if {$Snit_info(isWidget)} {
destroy $obj
} else {
if {[llength [info commands $obj]]} {
$obj destroy
}
}
}
# NEXT, get rid of the type command.
rename $type ""
# NEXT, destroy the type's data.
namespace delete $type
}
#-----------------------------------------------------------------------
# Option Handling
# Implements the standard "cget" method
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
# option The name of the option
proc ::snit::RT.method.cget {type selfns win self option} {
if {[catch {set ${selfns}::Snit_cgetCache($option)} command]} {
set command [snit::RT.CacheCgetCommand $type $selfns $win $self $option]
if {[llength $command] == 0} {
return -code error "unknown option \"$option\""
}
}
uplevel 1 $command
}
# Retrieves and caches the command that implements "cget" for the
# specified option.
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
# option The name of the option
proc ::snit::RT.CacheCgetCommand {type selfns win self option} {
variable ${type}::Snit_optionInfo
variable ${selfns}::Snit_cgetCache
if {[info exists Snit_optionInfo(islocal-$option)]} {
# We know the item; it's either local, or explicitly delegated.
if {$Snit_optionInfo(islocal-$option)} {
# It's a local option. If it has a cget method defined,
# use it; otherwise just return the value.
if {$Snit_optionInfo(cget-$option) eq ""} {
set command [list set ${selfns}::options($option)]
} else {
# WHD: Snit 2.0 code -- simpler, no slower.
set command [list \
$self \
{*}$Snit_optionInfo(cget-$option) \
$option]
}
set Snit_cgetCache($option) $command
return $command
}
# Explicitly delegated option; get target
set comp [lindex $Snit_optionInfo(target-$option) 0]
set target [lindex $Snit_optionInfo(target-$option) 1]
} elseif {$Snit_optionInfo(starcomp) ne "" &&
[lsearch -exact $Snit_optionInfo(except) $option] == -1} {
# Unknown option, but unknowns are delegated; get target.
set comp $Snit_optionInfo(starcomp)
set target $option
} else {
return ""
}
# Get the component's object.
set obj [RT.Component $type $selfns $comp]
set command [list $obj cget $target]
set Snit_cgetCache($option) $command
return $command
}
# Implements the standard "configurelist" method
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
# optionlist A list of options and their values.
proc ::snit::RT.method.configurelist {type selfns win self optionlist} {
variable ${type}::Snit_optionInfo
foreach {option value} $optionlist {
# FIRST, get the configure command, caching it if need be.
if {[catch {set ${selfns}::Snit_configureCache($option)} command]} {
set command [snit::RT.CacheConfigureCommand \
$type $selfns $win $self $option]
if {[llength $command] == 0} {
return -code error "unknown option \"$option\""
}
}
# NEXT, if we have a type-validation object, use it.
# TBD: Should test (islocal-$option) here, but islocal
# isn't defined for implicitly delegated options.
if {[info exists Snit_optionInfo(typeobj-$option)]
&& $Snit_optionInfo(typeobj-$option) ne ""} {
if {[catch {
$Snit_optionInfo(typeobj-$option) validate $value
} result]} {
return -code error "invalid $option value: $result"
}
}
# NEXT, the caching the configure command also cached the
# validate command, if any. If we have one, run it.
set valcommand [set ${selfns}::Snit_validateCache($option)]
if {[llength $valcommand]} {
lappend valcommand $value
uplevel 1 $valcommand
}
# NEXT, configure the option with the value.
lappend command $value
uplevel 1 $command
}
return
}
# Retrieves and caches the command that stores the named option.
# Also stores the command that validates the name option if any;
# If none, the validate command is "", so that the cache is always
# populated.
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
# option An option name
proc ::snit::RT.CacheConfigureCommand {type selfns win self option} {
variable ${type}::Snit_optionInfo
variable ${selfns}::Snit_configureCache
variable ${selfns}::Snit_validateCache
if {[info exist Snit_optionInfo(islocal-$option)]} {
# We know the item; it's either local, or explicitly delegated.
if {$Snit_optionInfo(islocal-$option)} {
# It's a local option.
# If it's readonly, it throws an error if we're already
# constructed.
if {$Snit_optionInfo(readonly-$option)} {
if {[set ${selfns}::Snit_iinfo(constructed)]} {
error "option $option can only be set at instance creation"
}
}
# If it has a validate method, cache that for later.
if {$Snit_optionInfo(validate-$option) ne ""} {
# WHD: Snit 2.0 code -- simpler, no slower.
set command [list \
$self \
{*}$Snit_optionInfo(validate-$option) \
$option]
set Snit_validateCache($option) $command
} else {
set Snit_validateCache($option) ""
}
# If it has a configure method defined,
# cache it; otherwise, just set the value.
if {$Snit_optionInfo(configure-$option) eq ""} {
set command [list set ${selfns}::options($option)]
} else {
# WHD: Snit 2.0 code -- simpler, no slower.
set command [list \
$self \
{*}$Snit_optionInfo(configure-$option) \
$option]
}
set Snit_configureCache($option) $command
return $command
}
# Delegated option: get target.
set comp [lindex $Snit_optionInfo(target-$option) 0]
set target [lindex $Snit_optionInfo(target-$option) 1]
} elseif {$Snit_optionInfo(starcomp) != "" &&
[lsearch -exact $Snit_optionInfo(except) $option] == -1} {
# Unknown option, but unknowns are delegated.
set comp $Snit_optionInfo(starcomp)
set target $option
} else {
return ""
}
# There is no validate command in this case; save an empty string.
set Snit_validateCache($option) ""
# Get the component's object
set obj [RT.Component $type $selfns $comp]
set command [list $obj configure $target]
set Snit_configureCache($option) $command
return $command
}
# Implements the standard "configure" method
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
# args A list of options and their values, possibly empty.
proc ::snit::RT.method.configure {type selfns win self args} {
# If two or more arguments, set values as usual.
if {[llength $args] >= 2} {
::snit::RT.method.configurelist $type $selfns $win $self $args
return
}
# If zero arguments, acquire data for each known option
# and return the list
if {[llength $args] == 0} {
set result {}
foreach opt [RT.method.info.options $type $selfns $win $self] {
# Refactor this, so that we don't need to call via $self.
lappend result [RT.GetOptionDbSpec \
$type $selfns $win $self $opt]
}
return $result
}
# They want it for just one.
set opt [lindex $args 0]
return [RT.GetOptionDbSpec $type $selfns $win $self $opt]
}
# Retrieves the option database spec for a single option.
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
# option The name of an option
#
# TBD: This is a bad name. What it's returning is the
# result of the configure query.
proc ::snit::RT.GetOptionDbSpec {type selfns win self opt} {
variable ${type}::Snit_optionInfo
namespace upvar $selfns \
Snit_components Snit_components \
options options
if {[info exists options($opt)]} {
# This is a locally-defined option. Just build the
# list and return it.
set res $Snit_optionInfo(resource-$opt)
set cls $Snit_optionInfo(class-$opt)
set def $Snit_optionInfo(default-$opt)
return [list $opt $res $cls $def \
[RT.method.cget $type $selfns $win $self $opt]]
} elseif {[info exists Snit_optionInfo(target-$opt)]} {
# This is an explicitly delegated option. The only
# thing we don't have is the default.
set res $Snit_optionInfo(resource-$opt)
set cls $Snit_optionInfo(class-$opt)
# Get the default
set logicalName [lindex $Snit_optionInfo(target-$opt) 0]
set comp $Snit_components($logicalName)
set target [lindex $Snit_optionInfo(target-$opt) 1]
if {[catch {$comp configure $target} result]} {
set defValue {}
} else {
set defValue [lindex $result 3]
}
return [list $opt $res $cls $defValue [$self cget $opt]]
} elseif {$Snit_optionInfo(starcomp) ne "" &&
[lsearch -exact $Snit_optionInfo(except) $opt] == -1} {
set logicalName $Snit_optionInfo(starcomp)
set target $opt
set comp $Snit_components($logicalName)
if {[catch {set value [$comp cget $target]} result]} {
error "unknown option \"$opt\""
}
if {![catch {$comp configure $target} result]} {
# Replace the delegated option name with the local name.
return [::snit::Expand $result $target $opt]
}
# configure didn't work; return simple form.
return [list $opt "" "" "" $value]
} else {
error "unknown option \"$opt\""
}
}
#-----------------------------------------------------------------------
# Type Introspection
# Implements the standard "info" typemethod.
#
# type The snit type
# command The info subcommand
# args All other arguments.
proc ::snit::RT.typemethod.info {type command args} {
global errorInfo
global errorCode
switch -exact $command {
args -
body -
default -
typevars -
typemethods -
instances {
# TBD: it should be possible to delete this error
# handling.
set errflag [catch {
uplevel 1 [linsert $args 0 \
::snit::RT.typemethod.info.$command $type]
} result]
if {$errflag} {
return -code error -errorinfo $errorInfo \
-errorcode $errorCode $result
} else {
return $result
}
}
default {
error "\"$type info $command\" is not defined"
}
}
}
# Returns a list of the type's typevariables whose names match a
# pattern, excluding Snit internal variables.
#
# type A Snit type
# pattern Optional. The glob pattern to match. Defaults
# to *.
proc ::snit::RT.typemethod.info.typevars {type {pattern *}} {
set result {}
foreach name [info vars "${type}::$pattern"] {
set tail [namespace tail $name]
if {![string match "Snit_*" $tail]} {
lappend result $name
}
}
return $result
}
# Returns a list of the type's methods whose names match a
# pattern. If "delegate typemethod *" is used, the list may
# not be complete.
#
# type A Snit type
# pattern Optional. The glob pattern to match. Defaults
# to *.
proc ::snit::RT.typemethod.info.typemethods {type {pattern *}} {
variable ${type}::Snit_typemethodInfo
# FIRST, get the explicit names, skipping prefixes.
set result {}
foreach name [array names Snit_typemethodInfo -glob $pattern] {
if {[lindex $Snit_typemethodInfo($name) 0] != 1} {
lappend result $name
}
}
# NEXT, add any from the cache that aren't explicit.
# WHD: fixed up to use newstyle method cache/list of subcommands.
if {[info exists Snit_typemethodInfo(*)]} {
# First, remove "*" from the list.
set ndx [lsearch -exact $result "*"]
if {$ndx != -1} {
set result [lreplace $result $ndx $ndx]
}
# Next, get the type's -map
array set typemethodCache [namespace ensemble configure $type -map]
# Next, get matching names from the cache that we don't already
# know about.
foreach name [array names typemethodCache -glob $pattern] {
if {[lsearch -exact $result $name] == -1} {
lappend result $name
}
}
}
return $result
}
# $type info args
#
# Returns a method's list of arguments. does not work for delegated
# methods, nor for the internal dispatch methods of multi-word
# methods.
proc ::snit::RT.typemethod.info.args {type method} {
upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo
# Snit_methodInfo: method -> list (flag cmd component)
# flag : 1 -> internal dispatcher for multi-word method.
# 0 -> regular method
#
# cmd : template mapping from method to command prefix, may
# contain placeholders for various pieces of information.
#
# component : is empty for normal methods.
#parray Snit_typemethodInfo
if {![info exists Snit_typemethodInfo($method)]} {
return -code error "Unknown typemethod \"$method\""
}
foreach {flag cmd component} $Snit_typemethodInfo($method) break
if {$flag} {
return -code error "Unknown typemethod \"$method\""
}
if {$component != ""} {
return -code error "Delegated typemethod \"$method\""
}
set map [list %m $method %j [join $method _] %t $type]
set theproc [lindex [string map $map $cmd] 0]
return [lrange [::info args $theproc] 1 end]
}
# $type info body
#
# Returns a method's body. does not work for delegated
# methods, nor for the internal dispatch methods of multi-word
# methods.
proc ::snit::RT.typemethod.info.body {type method} {
upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo
# Snit_methodInfo: method -> list (flag cmd component)
# flag : 1 -> internal dispatcher for multi-word method.
# 0 -> regular method
#
# cmd : template mapping from method to command prefix, may
# contain placeholders for various pieces of information.
#
# component : is empty for normal methods.
#parray Snit_typemethodInfo
if {![info exists Snit_typemethodInfo($method)]} {
return -code error "Unknown typemethod \"$method\""
}
foreach {flag cmd component} $Snit_typemethodInfo($method) break
if {$flag} {
return -code error "Unknown typemethod \"$method\""
}
if {$component != ""} {
return -code error "Delegated typemethod \"$method\""
}
set map [list %m $method %j [join $method _] %t $type]
set theproc [lindex [string map $map $cmd] 0]
return [RT.body [::info body $theproc]]
}
# $type info default
#
# Returns a method's list of arguments. does not work for delegated
# methods, nor for the internal dispatch methods of multi-word
# methods.
proc ::snit::RT.typemethod.info.default {type method aname dvar} {
upvar 1 $dvar def
upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo
# Snit_methodInfo: method -> list (flag cmd component)
# flag : 1 -> internal dispatcher for multi-word method.
# 0 -> regular method
#
# cmd : template mapping from method to command prefix, may
# contain placeholders for various pieces of information.
#
# component : is empty for normal methods.
#parray Snit_methodInfo
if {![info exists Snit_typemethodInfo($method)]} {
return -code error "Unknown typemethod \"$method\""
}
foreach {flag cmd component} $Snit_typemethodInfo($method) break
if {$flag} {
return -code error "Unknown typemethod \"$method\""
}
if {$component != ""} {
return -code error "Delegated typemethod \"$method\""
}
set map [list %m $method %j [join $method _] %t $type]
set theproc [lindex [string map $map $cmd] 0]
return [::info default $theproc $aname def]
}
# Returns a list of the type's instances whose names match
# a pattern.
#
# type A Snit type
# pattern Optional. The glob pattern to match
# Defaults to *
#
# REQUIRE: type is fully qualified.
proc ::snit::RT.typemethod.info.instances {type {pattern *}} {
set result {}
foreach selfns [namespace children $type] {
namespace upvar $selfns Snit_instance instance
if {[string match $pattern $instance]} {
lappend result $instance
}
}
return $result
}
#-----------------------------------------------------------------------
# Instance Introspection
# Implements the standard "info" method.
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
# command The info subcommand
# args All other arguments.
proc ::snit::RT.method.info {type selfns win self command args} {
switch -exact $command {
args -
body -
default -
type -
vars -
options -
methods -
typevars -
typemethods {
set errflag [catch {
uplevel 1 [linsert $args 0 ::snit::RT.method.info.$command \
$type $selfns $win $self]
} result]
if {$errflag} {
global errorInfo
return -code error -errorinfo $errorInfo $result
} else {
return $result
}
}
default {
# error "\"$self info $command\" is not defined"
return -code error "\"$self info $command\" is not defined"
}
}
}
# $self info type
#
# Returns the instance's type
proc ::snit::RT.method.info.type {type selfns win self} {
return $type
}
# $self info typevars
#
# Returns the instance's type's typevariables
proc ::snit::RT.method.info.typevars {type selfns win self {pattern *}} {
return [RT.typemethod.info.typevars $type $pattern]
}
# $self info typemethods
#
# Returns the instance's type's typemethods
proc ::snit::RT.method.info.typemethods {type selfns win self {pattern *}} {
return [RT.typemethod.info.typemethods $type $pattern]
}
# Returns a list of the instance's methods whose names match a
# pattern. If "delegate method *" is used, the list may
# not be complete.
#
# type A Snit type
# selfns The instance namespace
# win The original instance name
# self The current instance name
# pattern Optional. The glob pattern to match. Defaults
# to *.
proc ::snit::RT.method.info.methods {type selfns win self {pattern *}} {
variable ${type}::Snit_methodInfo
# FIRST, get the explicit names, skipping prefixes.
set result {}
foreach name [array names Snit_methodInfo -glob $pattern] {
if {[lindex $Snit_methodInfo($name) 0] != 1} {
lappend result $name
}
}
# NEXT, add any from the cache that aren't explicit.
# WHD: Fixed up to use newstyle method cache/list of subcommands.
if {[info exists Snit_methodInfo(*)]} {
# First, remove "*" from the list.
set ndx [lsearch -exact $result "*"]
if {$ndx != -1} {
set result [lreplace $result $ndx $ndx]
}
# Next, get the instance's -map
set self [set ${selfns}::Snit_instance]
array set methodCache [namespace ensemble configure $self -map]
# Next, get matching names from the cache that we don't already
# know about.
foreach name [array names methodCache -glob $pattern] {
if {[lsearch -exact $result $name] == -1} {
lappend result $name
}
}
}
return $result
}
# $self info args
#
# Returns a method's list of arguments. does not work for delegated
# methods, nor for the internal dispatch methods of multi-word
# methods.
proc ::snit::RT.method.info.args {type selfns win self method} {
upvar ${type}::Snit_methodInfo Snit_methodInfo
# Snit_methodInfo: method -> list (flag cmd component)
# flag : 1 -> internal dispatcher for multi-word method.
# 0 -> regular method
#
# cmd : template mapping from method to command prefix, may
# contain placeholders for various pieces of information.
#
# component : is empty for normal methods.
#parray Snit_methodInfo
if {![info exists Snit_methodInfo($method)]} {
return -code error "Unknown method \"$method\""
}
foreach {flag cmd component} $Snit_methodInfo($method) break
if {$flag} {
return -code error "Unknown method \"$method\""
}
if {$component != ""} {
return -code error "Delegated method \"$method\""
}
set map [list %m $method %j [join $method _] %t $type %n $selfns %w $win %s $self]
set theproc [lindex [string map $map $cmd] 0]
return [lrange [::info args $theproc] 4 end]
}
# $self info body
#
# Returns a method's body. does not work for delegated
# methods, nor for the internal dispatch methods of multi-word
# methods.
proc ::snit::RT.method.info.body {type selfns win self method} {
upvar ${type}::Snit_methodInfo Snit_methodInfo
# Snit_methodInfo: method -> list (flag cmd component)
# flag : 1 -> internal dispatcher for multi-word method.
# 0 -> regular method
#
# cmd : template mapping from method to command prefix, may
# contain placeholders for various pieces of information.
#
# component : is empty for normal methods.
#parray Snit_methodInfo
if {![info exists Snit_methodInfo($method)]} {
return -code error "Unknown method \"$method\""
}
foreach {flag cmd component} $Snit_methodInfo($method) break
if {$flag} {
return -code error "Unknown method \"$method\""
}
if {$component != ""} {
return -code error "Delegated method \"$method\""
}
set map [list %m $method %j [join $method _] %t $type %n $selfns %w $win %s $self]
set theproc [lindex [string map $map $cmd] 0]
return [RT.body [::info body $theproc]]
}
# $self info default
#
# Returns a method's list of arguments. does not work for delegated
# methods, nor for the internal dispatch methods of multi-word
# methods.
proc ::snit::RT.method.info.default {type selfns win self method aname dvar} {
upvar 1 $dvar def
upvar ${type}::Snit_methodInfo Snit_methodInfo
# Snit_methodInfo: method -> list (flag cmd component)
# flag : 1 -> internal dispatcher for multi-word method.
# 0 -> regular method
#
# cmd : template mapping from method to command prefix, may
# contain placeholders for various pieces of information.
#
# component : is empty for normal methods.
if {![info exists Snit_methodInfo($method)]} {
return -code error "Unknown method \"$method\""
}
foreach {flag cmd component} $Snit_methodInfo($method) break
if {$flag} {
return -code error "Unknown method \"$method\""
}
if {$component != ""} {
return -code error "Delegated method \"$method\""
}
set map [list %m $method %j [join $method _] %t $type %n $selfns %w $win %s $self]
set theproc [lindex [string map $map $cmd] 0]
return [::info default $theproc $aname def]
}
# $self info vars
#
# Returns the instance's instance variables
proc ::snit::RT.method.info.vars {type selfns win self {pattern *}} {
set result {}
foreach name [info vars "${selfns}::$pattern"] {
set tail [namespace tail $name]
if {![string match "Snit_*" $tail]} {
lappend result $name
}
}
return $result
}
# $self info options
#
# Returns a list of the names of the instance's options
proc ::snit::RT.method.info.options {type selfns win self {pattern *}} {
variable ${type}::Snit_optionInfo
# First, get the local and explicitly delegated options
set result [concat $Snit_optionInfo(local) $Snit_optionInfo(delegated)]
# If "configure" works as for Tk widgets, add the resulting
# options to the list. Skip excepted options
if {$Snit_optionInfo(starcomp) ne ""} {
namespace upvar $selfns Snit_components Snit_components
set logicalName $Snit_optionInfo(starcomp)
set comp $Snit_components($logicalName)
if {![catch {$comp configure} records]} {
foreach record $records {
set opt [lindex $record 0]
if {[lsearch -exact $result $opt] == -1 &&
[lsearch -exact $Snit_optionInfo(except) $opt] == -1} {
lappend result $opt
}
}
}
}
# Next, apply the pattern
set names {}
foreach name $result {
if {[string match $pattern $name]} {
lappend names $name
}
}
return $names
}
proc ::snit::RT.body {body} {
regsub -all ".*# END snit method prolog\n" $body {} body
return $body
}
amsn-0.98.9/utils/snit/main1.tcl 0000644 0001750 0001750 00000371134 11020317540 016221 0 ustar billiob billiob #-----------------------------------------------------------------------
# TITLE:
# main1.tcl
#
# AUTHOR:
# Will Duquette
#
# DESCRIPTION:
# Snit's Not Incr Tcl, a simple object system in Pure Tcl.
#
# Snit 1.x Compiler and Run-Time Library, Tcl 8.4 and later
#
# Copyright (C) 2003-2006 by William H. Duquette
# This code is licensed as described in license.txt.
#
#-----------------------------------------------------------------------
#-----------------------------------------------------------------------
# Namespace
namespace eval ::snit:: {
namespace export \
compile type widget widgetadaptor typemethod method macro
}
#-----------------------------------------------------------------------
# Some Snit variables
namespace eval ::snit:: {
variable reservedArgs {type selfns win self}
# Widget classes which can be hulls (must have -class)
variable hulltypes {
toplevel tk::toplevel
frame tk::frame ttk::frame
labelframe tk::labelframe ttk::labelframe
}
}
#-----------------------------------------------------------------------
# Snit Type Implementation template
namespace eval ::snit:: {
# Template type definition: All internal and user-visible Snit
# implementation code.
#
# The following placeholders will automatically be replaced with
# the client's code, in two passes:
#
# First pass:
# %COMPILEDDEFS% The compiled type definition.
#
# Second pass:
# %TYPE% The fully qualified type name.
# %IVARDECS% Instance variable declarations
# %TVARDECS% Type variable declarations
# %TCONSTBODY% Type constructor body
# %INSTANCEVARS% The compiled instance variable initialization code.
# %TYPEVARS% The compiled type variable initialization code.
# This is the overall type template.
variable typeTemplate
# This is the normal type proc
variable nominalTypeProc
# This is the "-hastypemethods no" type proc
variable simpleTypeProc
}
set ::snit::typeTemplate {
#-------------------------------------------------------------------
# The type's namespace definition and the user's type variables
namespace eval %TYPE% {%TYPEVARS%
}
#----------------------------------------------------------------
# Commands for use in methods, typemethods, etc.
#
# These are implemented as aliases into the Snit runtime library.
interp alias {} %TYPE%::installhull {} ::snit::RT.installhull %TYPE%
interp alias {} %TYPE%::install {} ::snit::RT.install %TYPE%
interp alias {} %TYPE%::typevariable {} ::variable
interp alias {} %TYPE%::variable {} ::snit::RT.variable
interp alias {} %TYPE%::mytypevar {} ::snit::RT.mytypevar %TYPE%
interp alias {} %TYPE%::typevarname {} ::snit::RT.mytypevar %TYPE%
interp alias {} %TYPE%::myvar {} ::snit::RT.myvar
interp alias {} %TYPE%::varname {} ::snit::RT.myvar
interp alias {} %TYPE%::codename {} ::snit::RT.codename %TYPE%
interp alias {} %TYPE%::myproc {} ::snit::RT.myproc %TYPE%
interp alias {} %TYPE%::mymethod {} ::snit::RT.mymethod
interp alias {} %TYPE%::mytypemethod {} ::snit::RT.mytypemethod %TYPE%
interp alias {} %TYPE%::from {} ::snit::RT.from %TYPE%
#-------------------------------------------------------------------
# Snit's internal variables
namespace eval %TYPE% {
# Array: General Snit Info
#
# ns: The type's namespace
# hasinstances: T or F, from pragma -hasinstances.
# simpledispatch: T or F, from pragma -hasinstances.
# canreplace: T or F, from pragma -canreplace.
# counter: Count of instances created so far.
# widgetclass: Set by widgetclass statement.
# hulltype: Hull type (frame or toplevel) for widgets only.
# exceptmethods: Methods explicitly not delegated to *
# excepttypemethods: Methods explicitly not delegated to *
# tvardecs: Type variable declarations--for dynamic methods
# ivardecs: Instance variable declarations--for dyn. methods
typevariable Snit_info
set Snit_info(ns) %TYPE%::
set Snit_info(hasinstances) 1
set Snit_info(simpledispatch) 0
set Snit_info(canreplace) 0
set Snit_info(counter) 0
set Snit_info(widgetclass) {}
set Snit_info(hulltype) frame
set Snit_info(exceptmethods) {}
set Snit_info(excepttypemethods) {}
set Snit_info(tvardecs) {%TVARDECS%}
set Snit_info(ivardecs) {%IVARDECS%}
# Array: Public methods of this type.
# The index is the method name, or "*".
# The value is [list $pattern $componentName], where
# $componentName is "" for normal methods.
typevariable Snit_typemethodInfo
array unset Snit_typemethodInfo
# Array: Public methods of instances of this type.
# The index is the method name, or "*".
# The value is [list $pattern $componentName], where
# $componentName is "" for normal methods.
typevariable Snit_methodInfo
array unset Snit_methodInfo
# Array: option information. See dictionary.txt.
typevariable Snit_optionInfo
array unset Snit_optionInfo
set Snit_optionInfo(local) {}
set Snit_optionInfo(delegated) {}
set Snit_optionInfo(starcomp) {}
set Snit_optionInfo(except) {}
}
#----------------------------------------------------------------
# Compiled Procs
#
# These commands are created or replaced during compilation:
# Snit_instanceVars selfns
#
# Initializes the instance variables, if any. Called during
# instance creation.
proc %TYPE%::Snit_instanceVars {selfns} {
%INSTANCEVARS%
}
# Type Constructor
proc %TYPE%::Snit_typeconstructor {type} {
%TVARDECS%
%TCONSTBODY%
}
#----------------------------------------------------------------
# Default Procs
#
# These commands might be replaced during compilation:
# Snit_destructor type selfns win self
#
# Default destructor for the type. By default, it does
# nothing. It's replaced by any user destructor.
# For types, it's called by method destroy; for widgettypes,
# it's called by a destroy event handler.
proc %TYPE%::Snit_destructor {type selfns win self} { }
#----------------------------------------------------------
# Compiled Definitions
%COMPILEDDEFS%
#----------------------------------------------------------
# Finally, call the Type Constructor
%TYPE%::Snit_typeconstructor %TYPE%
}
#-----------------------------------------------------------------------
# Type procs
#
# These procs expect the fully-qualified type name to be
# substituted in for %TYPE%.
# This is the nominal type proc. It supports typemethods and
# delegated typemethods.
set ::snit::nominalTypeProc {
# Type dispatcher function. Note: This function lives
# in the parent of the %TYPE% namespace! All accesses to
# %TYPE% variables and methods must be qualified!
proc %TYPE% {{method ""} args} {
# First, if there's no method, and no args, and there's a create
# method, and this isn't a widget, then method is "create" and
# "args" is %AUTO%.
if {"" == $method && [llength $args] == 0} {
::variable %TYPE%::Snit_info
if {$Snit_info(hasinstances) && !$Snit_info(isWidget)} {
set method create
lappend args %AUTO%
} else {
error "wrong \# args: should be \"%TYPE% method args\""
}
}
# Next, retrieve the command.
variable %TYPE%::Snit_typemethodCache
while 1 {
if {[catch {set Snit_typemethodCache($method)} commandRec]} {
set commandRec [::snit::RT.CacheTypemethodCommand %TYPE% $method]
if {[llength $commandRec] == 0} {
return -code error "\"%TYPE% $method\" is not defined"
}
}
# If we've got a real command, break.
if {[lindex $commandRec 0] == 0} {
break
}
# Otherwise, we need to look up again...if we can.
if {[llength $args] == 0} {
return -code error \
"wrong number args: should be \"%TYPE% $method method args\""
}
lappend method [lindex $args 0]
set args [lrange $args 1 end]
}
set command [lindex $commandRec 1]
# Pass along the return code unchanged.
set retval [catch {uplevel 1 $command $args} result]
if {$retval} {
if {$retval == 1} {
global errorInfo
global errorCode
return -code error -errorinfo $errorInfo \
-errorcode $errorCode $result
} else {
return -code $retval $result
}
}
return $result
}
}
# This is the simplified type proc for when there are no typemethods
# except create. In this case, it doesn't take a method argument;
# the method is always "create".
set ::snit::simpleTypeProc {
# Type dispatcher function. Note: This function lives
# in the parent of the %TYPE% namespace! All accesses to
# %TYPE% variables and methods must be qualified!
proc %TYPE% {args} {
::variable %TYPE%::Snit_info
# FIRST, if the are no args, the single arg is %AUTO%
if {[llength $args] == 0} {
if {$Snit_info(isWidget)} {
error "wrong \# args: should be \"%TYPE% name args\""
}
lappend args %AUTO%
}
# NEXT, we're going to call the create method.
# Pass along the return code unchanged.
if {$Snit_info(isWidget)} {
set command [list ::snit::RT.widget.typemethod.create %TYPE%]
} else {
set command [list ::snit::RT.type.typemethod.create %TYPE%]
}
set retval [catch {uplevel 1 $command $args} result]
if {$retval} {
if {$retval == 1} {
global errorInfo
global errorCode
return -code error -errorinfo $errorInfo \
-errorcode $errorCode $result
} else {
return -code $retval $result
}
}
return $result
}
}
#-----------------------------------------------------------------------
# Instance procs
#
# The following must be substituted into these proc bodies:
#
# %SELFNS% The instance namespace
# %WIN% The original instance name
# %TYPE% The fully-qualified type name
#
# Nominal instance proc body: supports method caching and delegation.
#
# proc $instanceName {method args} ....
set ::snit::nominalInstanceProc {
set self [set %SELFNS%::Snit_instance]
while {1} {
if {[catch {set %SELFNS%::Snit_methodCache($method)} commandRec]} {
set commandRec [snit::RT.CacheMethodCommand %TYPE% %SELFNS% %WIN% $self $method]
if {[llength $commandRec] == 0} {
return -code error \
"\"$self $method\" is not defined"
}
}
# If we've got a real command, break.
if {[lindex $commandRec 0] == 0} {
break
}
# Otherwise, we need to look up again...if we can.
if {[llength $args] == 0} {
return -code error \
"wrong number args: should be \"$self $method method args\""
}
lappend method [lindex $args 0]
set args [lrange $args 1 end]
}
set command [lindex $commandRec 1]
# Pass along the return code unchanged.
set retval [catch {uplevel 1 $command $args} result]
if {$retval} {
if {$retval == 1} {
global errorInfo
global errorCode
return -code error -errorinfo $errorInfo \
-errorcode $errorCode $result
} else {
return -code $retval $result
}
}
return $result
}
# Simplified method proc body: No delegation allowed; no support for
# upvar or exotic return codes or hierarchical methods. Designed for
# max speed for simple types.
#
# proc $instanceName {method args} ....
set ::snit::simpleInstanceProc {
set self [set %SELFNS%::Snit_instance]
if {[lsearch -exact ${%TYPE%::Snit_methods} $method] == -1} {
set optlist [join ${%TYPE%::Snit_methods} ", "]
set optlist [linsert $optlist "end-1" "or"]
error "bad option \"$method\": must be $optlist"
}
eval [linsert $args 0 \
%TYPE%::Snit_method$method %TYPE% %SELFNS% %WIN% $self]
}
#=======================================================================
# Snit Type Definition
#
# These are the procs used to define Snit types, widgets, and
# widgetadaptors.
#-----------------------------------------------------------------------
# Snit Compilation Variables
#
# The following variables are used while Snit is compiling a type,
# and are disposed afterwards.
namespace eval ::snit:: {
# The compiler variable contains the name of the slave interpreter
# used to compile type definitions.
variable compiler ""
# The compile array accumulates information about the type or
# widgettype being compiled. It is cleared before and after each
# compilation. It has these indices:
#
# type: The name of the type being compiled, for use
# in compilation procs.
# defs: Compiled definitions, both standard and client.
# which: type, widget, widgetadaptor
# instancevars: Instance variable definitions and initializations.
# ivprocdec: Instance variable proc declarations.
# tvprocdec: Type variable proc declarations.
# typeconstructor: Type constructor body.
# widgetclass: The widgetclass, for snit::widgets, only
# hasoptions: False, initially; set to true when first
# option is defined.
# localoptions: Names of local options.
# delegatedoptions: Names of delegated options.
# localmethods: Names of locally defined methods.
# delegatesmethods: no if no delegated methods, yes otherwise.
# hashierarchic : no if no hierarchic methods, yes otherwise.
# components: Names of defined components.
# typecomponents: Names of defined typecomponents.
# typevars: Typevariable definitions and initializations.
# varnames: Names of instance variables
# typevarnames Names of type variables
# hasconstructor False, initially; true when constructor is
# defined.
# resource-$opt The option's resource name
# class-$opt The option's class
# -default-$opt The option's default value
# -validatemethod-$opt The option's validate method
# -configuremethod-$opt The option's configure method
# -cgetmethod-$opt The option's cget method.
# -hastypeinfo The -hastypeinfo pragma
# -hastypedestroy The -hastypedestroy pragma
# -hastypemethods The -hastypemethods pragma
# -hasinfo The -hasinfo pragma
# -hasinstances The -hasinstances pragma
# -simpledispatch The -simpledispatch pragma
# -canreplace The -canreplace pragma
variable compile
# This variable accumulates method dispatch information; it has
# the same structure as the %TYPE%::Snit_methodInfo array, and is
# used to initialize it.
variable methodInfo
# This variable accumulates typemethod dispatch information; it has
# the same structure as the %TYPE%::Snit_typemethodInfo array, and is
# used to initialize it.
variable typemethodInfo
# The following variable lists the reserved type definition statement
# names, e.g., the names you can't use as macros. It's built at
# compiler definition time using "info commands".
variable reservedwords {}
}
#-----------------------------------------------------------------------
# type compilation commands
#
# The type and widgettype commands use a slave interpreter to compile
# the type definition. These are the procs
# that are aliased into it.
# Initialize the compiler
proc ::snit::Comp.Init {} {
variable compiler
variable reservedwords
if {"" == $compiler} {
# Create the compiler's interpreter
set compiler [interp create]
# Initialize the interpreter
$compiler eval {
# Load package information
# TBD: see if this can be moved outside.
# @mdgen NODEP: ::snit::__does_not_exist__
catch {package require ::snit::__does_not_exist__}
# Protect some Tcl commands our type definitions
# will shadow.
rename proc _proc
rename variable _variable
}
# Define compilation aliases.
$compiler alias pragma ::snit::Comp.statement.pragma
$compiler alias widgetclass ::snit::Comp.statement.widgetclass
$compiler alias hulltype ::snit::Comp.statement.hulltype
$compiler alias constructor ::snit::Comp.statement.constructor
$compiler alias destructor ::snit::Comp.statement.destructor
$compiler alias option ::snit::Comp.statement.option
$compiler alias oncget ::snit::Comp.statement.oncget
$compiler alias onconfigure ::snit::Comp.statement.onconfigure
$compiler alias method ::snit::Comp.statement.method
$compiler alias typemethod ::snit::Comp.statement.typemethod
$compiler alias typeconstructor ::snit::Comp.statement.typeconstructor
$compiler alias proc ::snit::Comp.statement.proc
$compiler alias typevariable ::snit::Comp.statement.typevariable
$compiler alias variable ::snit::Comp.statement.variable
$compiler alias typecomponent ::snit::Comp.statement.typecomponent
$compiler alias component ::snit::Comp.statement.component
$compiler alias delegate ::snit::Comp.statement.delegate
$compiler alias expose ::snit::Comp.statement.expose
# Get the list of reserved words
set reservedwords [$compiler eval {info commands}]
}
}
# Compile a type definition, and return the results as a list of two
# items: the fully-qualified type name, and a script that will define
# the type when executed.
#
# which type, widget, or widgetadaptor
# type the type name
# body the type definition
proc ::snit::Comp.Compile {which type body} {
variable typeTemplate
variable nominalTypeProc
variable simpleTypeProc
variable compile
variable compiler
variable methodInfo
variable typemethodInfo
# FIRST, qualify the name.
if {![string match "::*" $type]} {
# Get caller's namespace;
# append :: if not global namespace.
set ns [uplevel 2 [list namespace current]]
if {"::" != $ns} {
append ns "::"
}
set type "$ns$type"
}
# NEXT, create and initialize the compiler, if needed.
Comp.Init
# NEXT, initialize the class data
array unset methodInfo
array unset typemethodInfo
array unset compile
set compile(type) $type
set compile(defs) {}
set compile(which) $which
set compile(hasoptions) no
set compile(localoptions) {}
set compile(instancevars) {}
set compile(typevars) {}
set compile(delegatedoptions) {}
set compile(ivprocdec) {}
set compile(tvprocdec) {}
set compile(typeconstructor) {}
set compile(widgetclass) {}
set compile(hulltype) {}
set compile(localmethods) {}
set compile(delegatesmethods) no
set compile(hashierarchic) no
set compile(components) {}
set compile(typecomponents) {}
set compile(varnames) {}
set compile(typevarnames) {}
set compile(hasconstructor) no
set compile(-hastypedestroy) yes
set compile(-hastypeinfo) yes
set compile(-hastypemethods) yes
set compile(-hasinfo) yes
set compile(-hasinstances) yes
set compile(-simpledispatch) no
set compile(-canreplace) no
set isWidget [string match widget* $which]
set isWidgetAdaptor [string match widgetadaptor $which]
# NEXT, Evaluate the type's definition in the class interpreter.
$compiler eval $body
# NEXT, Add the standard definitions
append compile(defs) \
"\nset %TYPE%::Snit_info(isWidget) $isWidget\n"
append compile(defs) \
"\nset %TYPE%::Snit_info(isWidgetAdaptor) $isWidgetAdaptor\n"
# Indicate whether the type can create instances that replace
# existing commands.
append compile(defs) "\nset %TYPE%::Snit_info(canreplace) $compile(-canreplace)\n"
# Check pragmas for conflict.
if {!$compile(-hastypemethods) && !$compile(-hasinstances)} {
error "$which $type has neither typemethods nor instances"
}
if {$compile(-simpledispatch) && $compile(delegatesmethods)} {
error "$which $type requests -simpledispatch but delegates methods."
}
if {$compile(-simpledispatch) && $compile(hashierarchic)} {
error "$which $type requests -simpledispatch but defines hierarchical methods."
}
# If there are typemethods, define the standard typemethods and
# the nominal type proc. Otherwise define the simple type proc.
if {$compile(-hastypemethods)} {
# Add the info typemethod unless the pragma forbids it.
if {$compile(-hastypeinfo)} {
Comp.statement.delegate typemethod info \
using {::snit::RT.typemethod.info %t}
}
# Add the destroy typemethod unless the pragma forbids it.
if {$compile(-hastypedestroy)} {
Comp.statement.delegate typemethod destroy \
using {::snit::RT.typemethod.destroy %t}
}
# Add the nominal type proc.
append compile(defs) $nominalTypeProc
} else {
# Add the simple type proc.
append compile(defs) $simpleTypeProc
}
# Add standard methods/typemethods that only make sense if the
# type has instances.
if {$compile(-hasinstances)} {
# If we're using simple dispatch, remember that.
if {$compile(-simpledispatch)} {
append compile(defs) "\nset %TYPE%::Snit_info(simpledispatch) 1\n"
}
# Add the info method unless the pragma forbids it.
if {$compile(-hasinfo)} {
if {!$compile(-simpledispatch)} {
Comp.statement.delegate method info \
using {::snit::RT.method.info %t %n %w %s}
} else {
Comp.statement.method info {args} {
eval [linsert $args 0 \
::snit::RT.method.info $type $selfns $win $self]
}
}
}
# Add the option handling stuff if there are any options.
if {$compile(hasoptions)} {
Comp.statement.variable options
if {!$compile(-simpledispatch)} {
Comp.statement.delegate method cget \
using {::snit::RT.method.cget %t %n %w %s}
Comp.statement.delegate method configurelist \
using {::snit::RT.method.configurelist %t %n %w %s}
Comp.statement.delegate method configure \
using {::snit::RT.method.configure %t %n %w %s}
} else {
Comp.statement.method cget {args} {
eval [linsert $args 0 \
::snit::RT.method.cget $type $selfns $win $self]
}
Comp.statement.method configurelist {args} {
eval [linsert $args 0 \
::snit::RT.method.configurelist $type $selfns $win $self]
}
Comp.statement.method configure {args} {
eval [linsert $args 0 \
::snit::RT.method.configure $type $selfns $win $self]
}
}
}
# Add a default constructor, if they haven't already defined one.
# If there are options, it will configure args; otherwise it
# will do nothing.
if {!$compile(hasconstructor)} {
if {$compile(hasoptions)} {
Comp.statement.constructor {args} {
$self configurelist $args
}
} else {
Comp.statement.constructor {} {}
}
}
if {!$isWidget} {
if {!$compile(-simpledispatch)} {
Comp.statement.delegate method destroy \
using {::snit::RT.method.destroy %t %n %w %s}
} else {
Comp.statement.method destroy {args} {
eval [linsert $args 0 \
::snit::RT.method.destroy $type $selfns $win $self]
}
}
Comp.statement.delegate typemethod create \
using {::snit::RT.type.typemethod.create %t}
} else {
Comp.statement.delegate typemethod create \
using {::snit::RT.widget.typemethod.create %t}
}
# Save the list of method names, for -simpledispatch; otherwise,
# save the method info.
if {$compile(-simpledispatch)} {
append compile(defs) \
"\nset %TYPE%::Snit_methods [list $compile(localmethods)]\n"
} else {
append compile(defs) \
"\narray set %TYPE%::Snit_methodInfo [list [array get methodInfo]]\n"
}
} else {
append compile(defs) "\nset %TYPE%::Snit_info(hasinstances) 0\n"
}
# NEXT, compiling the type definition built up a set of information
# about the type's locally defined options; add this information to
# the compiled definition.
Comp.SaveOptionInfo
# NEXT, compiling the type definition built up a set of information
# about the typemethods; save the typemethod info.
append compile(defs) \
"\narray set %TYPE%::Snit_typemethodInfo [list [array get typemethodInfo]]\n"
# NEXT, if this is a widget define the hull component if it isn't
# already defined.
if {$isWidget} {
Comp.DefineComponent hull
}
# NEXT, substitute the compiled definition into the type template
# to get the type definition script.
set defscript [Expand $typeTemplate \
%COMPILEDDEFS% $compile(defs)]
# NEXT, substitute the defined macros into the type definition script.
# This is done as a separate step so that the compile(defs) can
# contain the macros defined below.
set defscript [Expand $defscript \
%TYPE% $type \
%IVARDECS% $compile(ivprocdec) \
%TVARDECS% $compile(tvprocdec) \
%TCONSTBODY% $compile(typeconstructor) \
%INSTANCEVARS% $compile(instancevars) \
%TYPEVARS% $compile(typevars) \
]
array unset compile
return [list $type $defscript]
}
# Information about locally-defined options is accumulated during
# compilation, but not added to the compiled definition--the option
# statement can appear multiple times, so it's easier this way.
# This proc fills in Snit_optionInfo with the accumulated information.
#
# It also computes the option's resource and class names if needed.
#
# Note that the information for delegated options was put in
# Snit_optionInfo during compilation.
proc ::snit::Comp.SaveOptionInfo {} {
variable compile
foreach option $compile(localoptions) {
if {"" == $compile(resource-$option)} {
set compile(resource-$option) [string range $option 1 end]
}
if {"" == $compile(class-$option)} {
set compile(class-$option) [Capitalize $compile(resource-$option)]
}
# NOTE: Don't verify that the validate, configure, and cget
# values name real methods; the methods might be defined outside
# the typedefinition using snit::method.
Mappend compile(defs) {
# Option %OPTION%
lappend %TYPE%::Snit_optionInfo(local) %OPTION%
set %TYPE%::Snit_optionInfo(islocal-%OPTION%) 1
set %TYPE%::Snit_optionInfo(resource-%OPTION%) %RESOURCE%
set %TYPE%::Snit_optionInfo(class-%OPTION%) %CLASS%
set %TYPE%::Snit_optionInfo(default-%OPTION%) %DEFAULT%
set %TYPE%::Snit_optionInfo(validate-%OPTION%) %VALIDATE%
set %TYPE%::Snit_optionInfo(configure-%OPTION%) %CONFIGURE%
set %TYPE%::Snit_optionInfo(cget-%OPTION%) %CGET%
set %TYPE%::Snit_optionInfo(readonly-%OPTION%) %READONLY%
set %TYPE%::Snit_optionInfo(typespec-%OPTION%) %TYPESPEC%
} %OPTION% $option \
%RESOURCE% $compile(resource-$option) \
%CLASS% $compile(class-$option) \
%DEFAULT% [list $compile(-default-$option)] \
%VALIDATE% [list $compile(-validatemethod-$option)] \
%CONFIGURE% [list $compile(-configuremethod-$option)] \
%CGET% [list $compile(-cgetmethod-$option)] \
%READONLY% $compile(-readonly-$option) \
%TYPESPEC% [list $compile(-type-$option)]
}
}
# Evaluates a compiled type definition, thus making the type available.
proc ::snit::Comp.Define {compResult} {
# The compilation result is a list containing the fully qualified
# type name and a script to evaluate to define the type.
set type [lindex $compResult 0]
set defscript [lindex $compResult 1]
# Execute the type definition script.
# Consider using namespace eval %TYPE%. See if it's faster.
if {[catch {eval $defscript} result]} {
namespace delete $type
catch {rename $type ""}
error $result
}
return $type
}
# Sets pragma options which control how the type is defined.
proc ::snit::Comp.statement.pragma {args} {
variable compile
set errRoot "Error in \"pragma...\""
foreach {opt val} $args {
switch -exact -- $opt {
-hastypeinfo -
-hastypedestroy -
-hastypemethods -
-hasinstances -
-simpledispatch -
-hasinfo -
-canreplace {
if {![string is boolean -strict $val]} {
error "$errRoot, \"$opt\" requires a boolean value"
}
set compile($opt) $val
}
default {
error "$errRoot, unknown pragma"
}
}
}
}
# Defines a widget's option class name.
# This statement is only available for snit::widgets,
# not for snit::types or snit::widgetadaptors.
proc ::snit::Comp.statement.widgetclass {name} {
variable compile
# First, widgetclass can only be set for true widgets
if {"widget" != $compile(which)} {
error "widgetclass cannot be set for snit::$compile(which)s"
}
# Next, validate the option name. We'll require that it begin
# with an uppercase letter.
set initial [string index $name 0]
if {![string is upper $initial]} {
error "widgetclass \"$name\" does not begin with an uppercase letter"
}
if {"" != $compile(widgetclass)} {
error "too many widgetclass statements"
}
# Next, save it.
Mappend compile(defs) {
set %TYPE%::Snit_info(widgetclass) %WIDGETCLASS%
} %WIDGETCLASS% [list $name]
set compile(widgetclass) $name
}
# Defines a widget's hull type.
# This statement is only available for snit::widgets,
# not for snit::types or snit::widgetadaptors.
proc ::snit::Comp.statement.hulltype {name} {
variable compile
variable hulltypes
# First, hulltype can only be set for true widgets
if {"widget" != $compile(which)} {
error "hulltype cannot be set for snit::$compile(which)s"
}
# Next, it must be one of the valid hulltypes (frame, toplevel, ...)
if {[lsearch -exact $hulltypes [string trimleft $name :]] == -1} {
error "invalid hulltype \"$name\", should be one of\
[join $hulltypes {, }]"
}
if {"" != $compile(hulltype)} {
error "too many hulltype statements"
}
# Next, save it.
Mappend compile(defs) {
set %TYPE%::Snit_info(hulltype) %HULLTYPE%
} %HULLTYPE% $name
set compile(hulltype) $name
}
# Defines a constructor.
proc ::snit::Comp.statement.constructor {arglist body} {
variable compile
CheckArgs "constructor" $arglist
# Next, add a magic reference to self.
set arglist [concat type selfns win self $arglist]
# Next, add variable declarations to body:
set body "%TVARDECS%%IVARDECS%\n$body"
set compile(hasconstructor) yes
append compile(defs) "proc %TYPE%::Snit_constructor [list $arglist] [list $body]\n"
}
# Defines a destructor.
proc ::snit::Comp.statement.destructor {body} {
variable compile
# Next, add variable declarations to body:
set body "%TVARDECS%%IVARDECS%\n$body"
append compile(defs) "proc %TYPE%::Snit_destructor {type selfns win self} [list $body]\n\n"
}
# Defines a type option. The option value can be a triple, specifying
# the option's -name, resource name, and class name.
proc ::snit::Comp.statement.option {optionDef args} {
variable compile
# First, get the three option names.
set option [lindex $optionDef 0]
set resourceName [lindex $optionDef 1]
set className [lindex $optionDef 2]
set errRoot "Error in \"option [list $optionDef]...\""
# Next, validate the option name.
if {![Comp.OptionNameIsValid $option]} {
error "$errRoot, badly named option \"$option\""
}
if {[Contains $option $compile(delegatedoptions)]} {
error "$errRoot, cannot define \"$option\" locally, it has been delegated"
}
if {![Contains $option $compile(localoptions)]} {
# Remember that we've seen this one.
set compile(hasoptions) yes
lappend compile(localoptions) $option
# Initialize compilation info for this option.
set compile(resource-$option) ""
set compile(class-$option) ""
set compile(-default-$option) ""
set compile(-validatemethod-$option) ""
set compile(-configuremethod-$option) ""
set compile(-cgetmethod-$option) ""
set compile(-readonly-$option) 0
set compile(-type-$option) ""
}
# NEXT, see if we have a resource name. If so, make sure it
# isn't being redefined differently.
if {"" != $resourceName} {
if {"" == $compile(resource-$option)} {
# If it's undefined, just save the value.
set compile(resource-$option) $resourceName
} elseif {![string equal $resourceName $compile(resource-$option)]} {
# It's been redefined differently.
error "$errRoot, resource name redefined from \"$compile(resource-$option)\" to \"$resourceName\""
}
}
# NEXT, see if we have a class name. If so, make sure it
# isn't being redefined differently.
if {"" != $className} {
if {"" == $compile(class-$option)} {
# If it's undefined, just save the value.
set compile(class-$option) $className
} elseif {![string equal $className $compile(class-$option)]} {
# It's been redefined differently.
error "$errRoot, class name redefined from \"$compile(class-$option)\" to \"$className\""
}
}
# NEXT, handle the args; it's not an error to redefine these.
if {[llength $args] == 1} {
set compile(-default-$option) [lindex $args 0]
} else {
foreach {optopt val} $args {
switch -exact -- $optopt {
-default -
-validatemethod -
-configuremethod -
-cgetmethod {
set compile($optopt-$option) $val
}
-type {
set compile($optopt-$option) $val
if {[llength $val] == 1} {
# The type spec *is* the validation object
append compile(defs) \
"\nset %TYPE%::Snit_optionInfo(typeobj-$option) [list $val]\n"
} else {
# Compilation the creation of the validation object
set cmd [linsert $val 1 %TYPE%::Snit_TypeObj_%AUTO%]
append compile(defs) \
"\nset %TYPE%::Snit_optionInfo(typeobj-$option) \[$cmd\]\n"
}
}
-readonly {
if {![string is boolean -strict $val]} {
error "$errRoot, -readonly requires a boolean, got \"$val\""
}
set compile($optopt-$option) $val
}
default {
error "$errRoot, unknown option definition option \"$optopt\""
}
}
}
}
}
# 1 if the option name is valid, 0 otherwise.
proc ::snit::Comp.OptionNameIsValid {option} {
if {![string match {-*} $option] || [string match {*[A-Z ]*} $option]} {
return 0
}
return 1
}
# Defines an option's cget handler
proc ::snit::Comp.statement.oncget {option body} {
variable compile
set errRoot "Error in \"oncget $option...\""
if {[lsearch -exact $compile(delegatedoptions) $option] != -1} {
return -code error "$errRoot, option \"$option\" is delegated"
}
if {[lsearch -exact $compile(localoptions) $option] == -1} {
return -code error "$errRoot, option \"$option\" unknown"
}
Comp.statement.method _cget$option {_option} $body
Comp.statement.option $option -cgetmethod _cget$option
}
# Defines an option's configure handler.
proc ::snit::Comp.statement.onconfigure {option arglist body} {
variable compile
if {[lsearch -exact $compile(delegatedoptions) $option] != -1} {
return -code error "onconfigure $option: option \"$option\" is delegated"
}
if {[lsearch -exact $compile(localoptions) $option] == -1} {
return -code error "onconfigure $option: option \"$option\" unknown"
}
if {[llength $arglist] != 1} {
error \
"onconfigure $option handler should have one argument, got \"$arglist\""
}
CheckArgs "onconfigure $option" $arglist
# Next, add a magic reference to the option name
set arglist [concat _option $arglist]
Comp.statement.method _configure$option $arglist $body
Comp.statement.option $option -configuremethod _configure$option
}
# Defines an instance method.
proc ::snit::Comp.statement.method {method arglist body} {
variable compile
variable methodInfo
# FIRST, check the method name against previously defined
# methods.
Comp.CheckMethodName $method 0 ::snit::methodInfo \
"Error in \"method [list $method]...\""
if {[llength $method] > 1} {
set compile(hashierarchic) yes
}
# Remeber this method
lappend compile(localmethods) $method
CheckArgs "method [list $method]" $arglist
# Next, add magic references to type and self.
set arglist [concat type selfns win self $arglist]
# Next, add variable declarations to body:
set body "%TVARDECS%%IVARDECS%\n# END snit method prolog\n$body"
# Next, save the definition script.
if {[llength $method] == 1} {
set methodInfo($method) {0 "%t::Snit_method%m %t %n %w %s" ""}
Mappend compile(defs) {
proc %TYPE%::Snit_method%METHOD% %ARGLIST% %BODY%
} %METHOD% $method %ARGLIST% [list $arglist] %BODY% [list $body]
} else {
set methodInfo($method) {0 "%t::Snit_hmethod%j %t %n %w %s" ""}
Mappend compile(defs) {
proc %TYPE%::Snit_hmethod%JMETHOD% %ARGLIST% %BODY%
} %JMETHOD% [join $method _] %ARGLIST% [list $arglist] \
%BODY% [list $body]
}
}
# Check for name collisions; save prefix information.
#
# method The name of the method or typemethod.
# delFlag 1 if delegated, 0 otherwise.
# infoVar The fully qualified name of the array containing
# information about the defined methods.
# errRoot The root string for any error messages.
proc ::snit::Comp.CheckMethodName {method delFlag infoVar errRoot} {
upvar $infoVar methodInfo
# FIRST, make sure the method name is a valid Tcl list.
if {[catch {lindex $method 0}]} {
error "$errRoot, the name \"$method\" must have list syntax."
}
# NEXT, check whether we can define it.
if {![catch {set methodInfo($method)} data]} {
# We can't redefine methods with submethods.
if {[lindex $data 0] == 1} {
error "$errRoot, \"$method\" has submethods."
}
# You can't delegate a method that's defined locally,
# and you can't define a method locally if it's been delegated.
if {$delFlag && "" == [lindex $data 2]} {
error "$errRoot, \"$method\" has been defined locally."
} elseif {!$delFlag && "" != [lindex $data 2]} {
error "$errRoot, \"$method\" has been delegated"
}
}
# Handle hierarchical case.
if {[llength $method] > 1} {
set prefix {}
set tokens $method
while {[llength $tokens] > 1} {
lappend prefix [lindex $tokens 0]
set tokens [lrange $tokens 1 end]
if {![catch {set methodInfo($prefix)} result]} {
# Prefix is known. If it's not a prefix, throw an
# error.
if {[lindex $result 0] == 0} {
error "$errRoot, \"$prefix\" has no submethods."
}
}
set methodInfo($prefix) [list 1]
}
}
}
# Defines a typemethod method.
proc ::snit::Comp.statement.typemethod {method arglist body} {
variable compile
variable typemethodInfo
# FIRST, check the typemethod name against previously defined
# typemethods.
Comp.CheckMethodName $method 0 ::snit::typemethodInfo \
"Error in \"typemethod [list $method]...\""
CheckArgs "typemethod $method" $arglist
# First, add magic reference to type.
set arglist [concat type $arglist]
# Next, add typevariable declarations to body:
set body "%TVARDECS%\n# END snit method prolog\n$body"
# Next, save the definition script
if {[llength $method] == 1} {
set typemethodInfo($method) {0 "%t::Snit_typemethod%m %t" ""}
Mappend compile(defs) {
proc %TYPE%::Snit_typemethod%METHOD% %ARGLIST% %BODY%
} %METHOD% $method %ARGLIST% [list $arglist] %BODY% [list $body]
} else {
set typemethodInfo($method) {0 "%t::Snit_htypemethod%j %t" ""}
Mappend compile(defs) {
proc %TYPE%::Snit_htypemethod%JMETHOD% %ARGLIST% %BODY%
} %JMETHOD% [join $method _] \
%ARGLIST% [list $arglist] %BODY% [list $body]
}
}
# Defines a type constructor.
proc ::snit::Comp.statement.typeconstructor {body} {
variable compile
if {"" != $compile(typeconstructor)} {
error "too many typeconstructors"
}
set compile(typeconstructor) $body
}
# Defines a static proc in the type's namespace.
proc ::snit::Comp.statement.proc {proc arglist body} {
variable compile
# If "ns" is defined, the proc can see instance variables.
if {[lsearch -exact $arglist selfns] != -1} {
# Next, add instance variable declarations to body:
set body "%IVARDECS%\n$body"
}
# The proc can always see typevariables.
set body "%TVARDECS%\n$body"
append compile(defs) "
# Proc $proc
proc [list %TYPE%::$proc $arglist $body]
"
}
# Defines a static variable in the type's namespace.
proc ::snit::Comp.statement.typevariable {name args} {
variable compile
set errRoot "Error in \"typevariable $name...\""
set len [llength $args]
if {$len > 2 ||
($len == 2 && "-array" != [lindex $args 0])} {
error "$errRoot, too many initializers"
}
if {[lsearch -exact $compile(varnames) $name] != -1} {
error "$errRoot, \"$name\" is already an instance variable"
}
lappend compile(typevarnames) $name
if {$len == 1} {
append compile(typevars) \
"\n\t [list ::variable $name [lindex $args 0]]"
} elseif {$len == 2} {
append compile(typevars) \
"\n\t [list ::variable $name]"
append compile(typevars) \
"\n\t [list array set $name [lindex $args 1]]"
} else {
append compile(typevars) \
"\n\t [list ::variable $name]"
}
append compile(tvprocdec) "\n\t typevariable ${name}"
}
# Defines an instance variable; the definition will go in the
# type's create typemethod.
proc ::snit::Comp.statement.variable {name args} {
variable compile
set errRoot "Error in \"variable $name...\""
set len [llength $args]
if {$len > 2 ||
($len == 2 && "-array" != [lindex $args 0])} {
error "$errRoot, too many initializers"
}
if {[lsearch -exact $compile(typevarnames) $name] != -1} {
error "$errRoot, \"$name\" is already a typevariable"
}
lappend compile(varnames) $name
if {$len == 1} {
append compile(instancevars) \
"\nset \${selfns}::$name [list [lindex $args 0]]\n"
} elseif {$len == 2} {
append compile(instancevars) \
"\narray set \${selfns}::$name [list [lindex $args 1]]\n"
}
append compile(ivprocdec) "\n\t "
Mappend compile(ivprocdec) {::variable ${selfns}::%N} %N $name
}
# Defines a typecomponent, and handles component options.
#
# component The logical name of the delegate
# args options.
proc ::snit::Comp.statement.typecomponent {component args} {
variable compile
set errRoot "Error in \"typecomponent $component...\""
# FIRST, define the component
Comp.DefineTypecomponent $component $errRoot
# NEXT, handle the options.
set publicMethod ""
set inheritFlag 0
foreach {opt val} $args {
switch -exact -- $opt {
-public {
set publicMethod $val
}
-inherit {
set inheritFlag $val
if {![string is boolean $inheritFlag]} {
error "typecomponent $component -inherit: expected boolean value, got \"$val\""
}
}
default {
error "typecomponent $component: Invalid option \"$opt\""
}
}
}
# NEXT, if -public specified, define the method.
if {"" != $publicMethod} {
Comp.statement.delegate typemethod [list $publicMethod *] to $component
}
# NEXT, if "-inherit 1" is specified, delegate typemethod * to
# this component.
if {$inheritFlag} {
Comp.statement.delegate typemethod "*" to $component
}
}
# Defines a name to be a typecomponent
#
# The name becomes a typevariable; in addition, it gets a
# write trace so that when it is set, all of the component mechanisms
# get updated.
#
# component The component name
proc ::snit::Comp.DefineTypecomponent {component {errRoot "Error"}} {
variable compile
if {[lsearch -exact $compile(varnames) $component] != -1} {
error "$errRoot, \"$component\" is already an instance variable"
}
if {[lsearch -exact $compile(typecomponents) $component] == -1} {
# Remember we've done this.
lappend compile(typecomponents) $component
# Make it a type variable with no initial value
Comp.statement.typevariable $component ""
# Add a write trace to do the component thing.
Mappend compile(typevars) {
trace add variable %COMP% write \
[list ::snit::RT.TypecomponentTrace [list %TYPE%] %COMP%]
} %TYPE% $compile(type) %COMP% $component
}
}
# Defines a component, and handles component options.
#
# component The logical name of the delegate
# args options.
#
# TBD: Ideally, it should be possible to call this statement multiple
# times, possibly changing the option values. To do that, I'd need
# to cache the option values and not act on them until *after* I'd
# read the entire type definition.
proc ::snit::Comp.statement.component {component args} {
variable compile
set errRoot "Error in \"component $component...\""
# FIRST, define the component
Comp.DefineComponent $component $errRoot
# NEXT, handle the options.
set publicMethod ""
set inheritFlag 0
foreach {opt val} $args {
switch -exact -- $opt {
-public {
set publicMethod $val
}
-inherit {
set inheritFlag $val
if {![string is boolean $inheritFlag]} {
error "component $component -inherit: expected boolean value, got \"$val\""
}
}
default {
error "component $component: Invalid option \"$opt\""
}
}
}
# NEXT, if -public specified, define the method.
if {"" != $publicMethod} {
Comp.statement.delegate method [list $publicMethod *] to $component
}
# NEXT, if -inherit is specified, delegate method/option * to
# this component.
if {$inheritFlag} {
Comp.statement.delegate method "*" to $component
Comp.statement.delegate option "*" to $component
}
}
# Defines a name to be a component
#
# The name becomes an instance variable; in addition, it gets a
# write trace so that when it is set, all of the component mechanisms
# get updated.
#
# component The component name
proc ::snit::Comp.DefineComponent {component {errRoot "Error"}} {
variable compile
if {[lsearch -exact $compile(typevarnames) $component] != -1} {
error "$errRoot, \"$component\" is already a typevariable"
}
if {[lsearch -exact $compile(components) $component] == -1} {
# Remember we've done this.
lappend compile(components) $component
# Make it an instance variable with no initial value
Comp.statement.variable $component ""
# Add a write trace to do the component thing.
Mappend compile(instancevars) {
trace add variable ${selfns}::%COMP% write \
[list ::snit::RT.ComponentTrace [list %TYPE%] $selfns %COMP%]
} %TYPE% $compile(type) %COMP% $component
}
}
# Creates a delegated method, typemethod, or option.
proc ::snit::Comp.statement.delegate {what name args} {
# FIRST, dispatch to correct handler.
switch $what {
typemethod { Comp.DelegatedTypemethod $name $args }
method { Comp.DelegatedMethod $name $args }
option { Comp.DelegatedOption $name $args }
default {
error "Error in \"delegate $what $name...\", \"$what\"?"
}
}
if {([llength $args] % 2) != 0} {
error "Error in \"delegate $what $name...\", invalid syntax"
}
}
# Creates a delegated typemethod delegating it to a particular
# typecomponent or an arbitrary command.
#
# method The name of the method
# arglist Delegation options
proc ::snit::Comp.DelegatedTypemethod {method arglist} {
variable compile
variable typemethodInfo
set errRoot "Error in \"delegate typemethod [list $method]...\""
# Next, parse the delegation options.
set component ""
set target ""
set exceptions {}
set pattern ""
set methodTail [lindex $method end]
foreach {opt value} $arglist {
switch -exact $opt {
to { set component $value }
as { set target $value }
except { set exceptions $value }
using { set pattern $value }
default {
error "$errRoot, unknown delegation option \"$opt\""
}
}
}
if {"" == $component && "" == $pattern} {
error "$errRoot, missing \"to\""
}
if {"*" == $methodTail && "" != $target} {
error "$errRoot, cannot specify \"as\" with \"*\""
}
if {"*" != $methodTail && "" != $exceptions} {
error "$errRoot, can only specify \"except\" with \"*\""
}
if {"" != $pattern && "" != $target} {
error "$errRoot, cannot specify both \"as\" and \"using\""
}
foreach token [lrange $method 1 end-1] {
if {"*" == $token} {
error "$errRoot, \"*\" must be the last token."
}
}
# NEXT, define the component
if {"" != $component} {
Comp.DefineTypecomponent $component $errRoot
}
# NEXT, define the pattern.
if {"" == $pattern} {
if {"*" == $methodTail} {
set pattern "%c %m"
} elseif {"" != $target} {
set pattern "%c $target"
} else {
set pattern "%c %m"
}
}
# Make sure the pattern is a valid list.
if {[catch {lindex $pattern 0} result]} {
error "$errRoot, the using pattern, \"$pattern\", is not a valid list"
}
# NEXT, check the method name against previously defined
# methods.
Comp.CheckMethodName $method 1 ::snit::typemethodInfo $errRoot
set typemethodInfo($method) [list 0 $pattern $component]
if {[string equal $methodTail "*"]} {
Mappend compile(defs) {
set %TYPE%::Snit_info(excepttypemethods) %EXCEPT%
} %EXCEPT% [list $exceptions]
}
}
# Creates a delegated method delegating it to a particular
# component or command.
#
# method The name of the method
# arglist Delegation options.
proc ::snit::Comp.DelegatedMethod {method arglist} {
variable compile
variable methodInfo
set errRoot "Error in \"delegate method [list $method]...\""
# Next, parse the delegation options.
set component ""
set target ""
set exceptions {}
set pattern ""
set methodTail [lindex $method end]
foreach {opt value} $arglist {
switch -exact $opt {
to { set component $value }
as { set target $value }
except { set exceptions $value }
using { set pattern $value }
default {
error "$errRoot, unknown delegation option \"$opt\""
}
}
}
if {"" == $component && "" == $pattern} {
error "$errRoot, missing \"to\""
}
if {"*" == $methodTail && "" != $target} {
error "$errRoot, cannot specify \"as\" with \"*\""
}
if {"*" != $methodTail && "" != $exceptions} {
error "$errRoot, can only specify \"except\" with \"*\""
}
if {"" != $pattern && "" != $target} {
error "$errRoot, cannot specify both \"as\" and \"using\""
}
foreach token [lrange $method 1 end-1] {
if {"*" == $token} {
error "$errRoot, \"*\" must be the last token."
}
}
# NEXT, we delegate some methods
set compile(delegatesmethods) yes
# NEXT, define the component. Allow typecomponents.
if {"" != $component} {
if {[lsearch -exact $compile(typecomponents) $component] == -1} {
Comp.DefineComponent $component $errRoot
}
}
# NEXT, define the pattern.
if {"" == $pattern} {
if {"*" == $methodTail} {
set pattern "%c %m"
} elseif {"" != $target} {
set pattern "%c $target"
} else {
set pattern "%c %m"
}
}
# Make sure the pattern is a valid list.
if {[catch {lindex $pattern 0} result]} {
error "$errRoot, the using pattern, \"$pattern\", is not a valid list"
}
# NEXT, check the method name against previously defined
# methods.
Comp.CheckMethodName $method 1 ::snit::methodInfo $errRoot
# NEXT, save the method info.
set methodInfo($method) [list 0 $pattern $component]
if {[string equal $methodTail "*"]} {
Mappend compile(defs) {
set %TYPE%::Snit_info(exceptmethods) %EXCEPT%
} %EXCEPT% [list $exceptions]
}
}
# Creates a delegated option, delegating it to a particular
# component and, optionally, to a particular option of that
# component.
#
# optionDef The option definition
# args definition arguments.
proc ::snit::Comp.DelegatedOption {optionDef arglist} {
variable compile
# First, get the three option names.
set option [lindex $optionDef 0]
set resourceName [lindex $optionDef 1]
set className [lindex $optionDef 2]
set errRoot "Error in \"delegate option [list $optionDef]...\""
# Next, parse the delegation options.
set component ""
set target ""
set exceptions {}
foreach {opt value} $arglist {
switch -exact $opt {
to { set component $value }
as { set target $value }
except { set exceptions $value }
default {
error "$errRoot, unknown delegation option \"$opt\""
}
}
}
if {"" == $component} {
error "$errRoot, missing \"to\""
}
if {"*" == $option && "" != $target} {
error "$errRoot, cannot specify \"as\" with \"delegate option *\""
}
if {"*" != $option && "" != $exceptions} {
error "$errRoot, can only specify \"except\" with \"delegate option *\""
}
# Next, validate the option name
if {"*" != $option} {
if {![Comp.OptionNameIsValid $option]} {
error "$errRoot, badly named option \"$option\""
}
}
if {[Contains $option $compile(localoptions)]} {
error "$errRoot, \"$option\" has been defined locally"
}
if {[Contains $option $compile(delegatedoptions)]} {
error "$errRoot, \"$option\" is multiply delegated"
}
# NEXT, define the component
Comp.DefineComponent $component $errRoot
# Next, define the target option, if not specified.
if {![string equal $option "*"] &&
[string equal $target ""]} {
set target $option
}
# NEXT, save the delegation data.
set compile(hasoptions) yes
if {![string equal $option "*"]} {
lappend compile(delegatedoptions) $option
# Next, compute the resource and class names, if they aren't
# already defined.
if {"" == $resourceName} {
set resourceName [string range $option 1 end]
}
if {"" == $className} {
set className [Capitalize $resourceName]
}
Mappend compile(defs) {
set %TYPE%::Snit_optionInfo(islocal-%OPTION%) 0
set %TYPE%::Snit_optionInfo(resource-%OPTION%) %RES%
set %TYPE%::Snit_optionInfo(class-%OPTION%) %CLASS%
lappend %TYPE%::Snit_optionInfo(delegated) %OPTION%
set %TYPE%::Snit_optionInfo(target-%OPTION%) [list %COMP% %TARGET%]
lappend %TYPE%::Snit_optionInfo(delegated-%COMP%) %OPTION%
} %OPTION% $option \
%COMP% $component \
%TARGET% $target \
%RES% $resourceName \
%CLASS% $className
} else {
Mappend compile(defs) {
set %TYPE%::Snit_optionInfo(starcomp) %COMP%
set %TYPE%::Snit_optionInfo(except) %EXCEPT%
} %COMP% $component %EXCEPT% [list $exceptions]
}
}
# Exposes a component, effectively making the component's command an
# instance method.
#
# component The logical name of the delegate
# "as" sugar; if not "", must be "as"
# methodname The desired method name for the component's command, or ""
proc ::snit::Comp.statement.expose {component {"as" ""} {methodname ""}} {
variable compile
# FIRST, define the component
Comp.DefineComponent $component
# NEXT, define the method just as though it were in the type
# definition.
if {[string equal $methodname ""]} {
set methodname $component
}
Comp.statement.method $methodname args [Expand {
if {[llength $args] == 0} {
return $%COMPONENT%
}
if {[string equal $%COMPONENT% ""]} {
error "undefined component \"%COMPONENT%\""
}
set cmd [linsert $args 0 $%COMPONENT%]
return [uplevel 1 $cmd]
} %COMPONENT% $component]
}
#-----------------------------------------------------------------------
# Public commands
# Compile a type definition, and return the results as a list of two
# items: the fully-qualified type name, and a script that will define
# the type when executed.
#
# which type, widget, or widgetadaptor
# type the type name
# body the type definition
proc ::snit::compile {which type body} {
return [Comp.Compile $which $type $body]
}
proc ::snit::type {type body} {
return [Comp.Define [Comp.Compile type $type $body]]
}
proc ::snit::widget {type body} {
return [Comp.Define [Comp.Compile widget $type $body]]
}
proc ::snit::widgetadaptor {type body} {
return [Comp.Define [Comp.Compile widgetadaptor $type $body]]
}
proc ::snit::typemethod {type method arglist body} {
# Make sure the type exists.
if {![info exists ${type}::Snit_info]} {
error "no such type: \"$type\""
}
upvar ${type}::Snit_info Snit_info
upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo
# FIRST, check the typemethod name against previously defined
# typemethods.
Comp.CheckMethodName $method 0 ${type}::Snit_typemethodInfo \
"Cannot define \"$method\""
# NEXT, check the arguments
CheckArgs "snit::typemethod $type $method" $arglist
# Next, add magic reference to type.
set arglist [concat type $arglist]
# Next, add typevariable declarations to body:
set body "$Snit_info(tvardecs)\n$body"
# Next, define it.
if {[llength $method] == 1} {
set Snit_typemethodInfo($method) {0 "%t::Snit_typemethod%m %t" ""}
uplevel 1 [list proc ${type}::Snit_typemethod$method $arglist $body]
} else {
set Snit_typemethodInfo($method) {0 "%t::Snit_htypemethod%j %t" ""}
set suffix [join $method _]
uplevel 1 [list proc ${type}::Snit_htypemethod$suffix $arglist $body]
}
}
proc ::snit::method {type method arglist body} {
# Make sure the type exists.
if {![info exists ${type}::Snit_info]} {
error "no such type: \"$type\""
}
upvar ${type}::Snit_methodInfo Snit_methodInfo
upvar ${type}::Snit_info Snit_info
# FIRST, check the method name against previously defined
# methods.
Comp.CheckMethodName $method 0 ${type}::Snit_methodInfo \
"Cannot define \"$method\""
# NEXT, check the arguments
CheckArgs "snit::method $type $method" $arglist
# Next, add magic references to type and self.
set arglist [concat type selfns win self $arglist]
# Next, add variable declarations to body:
set body "$Snit_info(tvardecs)$Snit_info(ivardecs)\n$body"
# Next, define it.
if {[llength $method] == 1} {
set Snit_methodInfo($method) {0 "%t::Snit_method%m %t %n %w %s" ""}
uplevel 1 [list proc ${type}::Snit_method$method $arglist $body]
} else {
set Snit_methodInfo($method) {0 "%t::Snit_hmethod%j %t %n %w %s" ""}
set suffix [join $method _]
uplevel 1 [list proc ${type}::Snit_hmethod$suffix $arglist $body]
}
}
# Defines a proc within the compiler; this proc can call other
# type definition statements, and thus can be used for meta-programming.
proc ::snit::macro {name arglist body} {
variable compiler
variable reservedwords
# FIRST, make sure the compiler is defined.
Comp.Init
# NEXT, check the macro name against the reserved words
if {[lsearch -exact $reservedwords $name] != -1} {
error "invalid macro name \"$name\""
}
# NEXT, see if the name has a namespace; if it does, define the
# namespace.
set ns [namespace qualifiers $name]
if {"" != $ns} {
$compiler eval "namespace eval $ns {}"
}
# NEXT, define the macro
$compiler eval [list _proc $name $arglist $body]
}
#-----------------------------------------------------------------------
# Utility Functions
#
# These are utility functions used while compiling Snit types.
# Builds a template from a tagged list of text blocks, then substitutes
# all symbols in the mapTable, returning the expanded template.
proc ::snit::Expand {template args} {
return [string map $args $template]
}
# Expands a template and appends it to a variable.
proc ::snit::Mappend {varname template args} {
upvar $varname myvar
append myvar [string map $args $template]
}
# Checks argument list against reserved args
proc ::snit::CheckArgs {which arglist} {
variable reservedArgs
foreach name $reservedArgs {
if {[Contains $name $arglist]} {
error "$which's arglist may not contain \"$name\" explicitly"
}
}
}
# Returns 1 if a value is in a list, and 0 otherwise.
proc ::snit::Contains {value list} {
if {[lsearch -exact $list $value] != -1} {
return 1
} else {
return 0
}
}
# Capitalizes the first letter of a string.
proc ::snit::Capitalize {text} {
return [string toupper $text 0]
}
# Converts an arbitrary white-space-delimited string into a list
# by splitting on white-space and deleting empty tokens.
proc ::snit::Listify {str} {
set result {}
foreach token [split [string trim $str]] {
if {[string length $token] > 0} {
lappend result $token
}
}
return $result
}
#=======================================================================
# Snit Runtime Library
#
# These are procs used by Snit types and widgets at runtime.
#-----------------------------------------------------------------------
# Object Creation
# Creates a new instance of the snit::type given its name and the args.
#
# type The snit::type
# name The instance name
# args Args to pass to the constructor
proc ::snit::RT.type.typemethod.create {type name args} {
variable ${type}::Snit_info
variable ${type}::Snit_optionInfo
# FIRST, qualify the name.
if {![string match "::*" $name]} {
# Get caller's namespace;
# append :: if not global namespace.
set ns [uplevel 1 [list namespace current]]
if {"::" != $ns} {
append ns "::"
}
set name "$ns$name"
}
# NEXT, if %AUTO% appears in the name, generate a unique
# command name. Otherwise, ensure that the name isn't in use.
if {[string match "*%AUTO%*" $name]} {
set name [::snit::RT.UniqueName Snit_info(counter) $type $name]
} elseif {!$Snit_info(canreplace) && [llength [info commands $name]]} {
error "command \"$name\" already exists"
}
# NEXT, create the instance's namespace.
set selfns \
[::snit::RT.UniqueInstanceNamespace Snit_info(counter) $type]
namespace eval $selfns {}
# NEXT, install the dispatcher
RT.MakeInstanceCommand $type $selfns $name
# Initialize the options to their defaults.
upvar ${selfns}::options options
foreach opt $Snit_optionInfo(local) {
set options($opt) $Snit_optionInfo(default-$opt)
}
# Initialize the instance vars to their defaults.
# selfns must be defined, as it is used implicitly.
${type}::Snit_instanceVars $selfns
# Execute the type's constructor.
set errcode [catch {
RT.ConstructInstance $type $selfns $name $args
} result]
if {$errcode} {
global errorInfo
global errorCode
set theInfo $errorInfo
set theCode $errorCode
::snit::RT.DestroyObject $type $selfns $name
error "Error in constructor: $result" $theInfo $theCode
}
# NEXT, return the object's name.
return $name
}
# Creates a new instance of the snit::widget or snit::widgetadaptor
# given its name and the args.
#
# type The snit::widget or snit::widgetadaptor
# name The instance name
# args Args to pass to the constructor
proc ::snit::RT.widget.typemethod.create {type name args} {
variable ${type}::Snit_info
variable ${type}::Snit_optionInfo
# FIRST, if %AUTO% appears in the name, generate a unique
# command name.
if {[string match "*%AUTO%*" $name]} {
set name [::snit::RT.UniqueName Snit_info(counter) $type $name]
}
# NEXT, create the instance's namespace.
set selfns \
[::snit::RT.UniqueInstanceNamespace Snit_info(counter) $type]
namespace eval $selfns { }
# NEXT, Initialize the widget's own options to their defaults.
upvar ${selfns}::options options
foreach opt $Snit_optionInfo(local) {
set options($opt) $Snit_optionInfo(default-$opt)
}
# Initialize the instance vars to their defaults.
${type}::Snit_instanceVars $selfns
# NEXT, if this is a normal widget (not a widget adaptor) then create a
# frame as its hull. We set the frame's -class to the user's widgetclass,
# or, if none, search for -class in the args list, otherwise default to
# the basename of the $type with an initial upper case letter.
if {!$Snit_info(isWidgetAdaptor)} {
# FIRST, determine the class name
set wclass $Snit_info(widgetclass)
if {$Snit_info(widgetclass) eq ""} {
set idx [lsearch -exact $args -class]
if {$idx >= 0 && ($idx%2 == 0)} {
# -class exists and is in the -option position
set wclass [lindex $args [expr {$idx+1}]]
set args [lreplace $args $idx [expr {$idx+1}]]
} else {
set wclass [::snit::Capitalize [namespace tail $type]]
}
}
# NEXT, create the widget
set self $name
package require Tk
${type}::installhull using $Snit_info(hulltype) -class $wclass
# NEXT, let's query the option database for our
# widget, now that we know that it exists.
foreach opt $Snit_optionInfo(local) {
set dbval [RT.OptionDbGet $type $name $opt]
if {"" != $dbval} {
set options($opt) $dbval
}
}
}
# Execute the type's constructor, and verify that it
# has a hull.
set errcode [catch {
RT.ConstructInstance $type $selfns $name $args
::snit::RT.Component $type $selfns hull
# Prepare to call the object's destructor when the
# event is received. Use a Snit-specific bindtag
# so that the widget name's tag is unencumbered.
bind Snit$type$name [::snit::Expand {
::snit::RT.DestroyObject %TYPE% %NS% %W
} %TYPE% $type %NS% $selfns]
# Insert the bindtag into the list of bindtags right
# after the widget name.
set taglist [bindtags $name]
set ndx [lsearch -exact $taglist $name]
incr ndx
bindtags $name [linsert $taglist $ndx Snit$type$name]
} result]
if {$errcode} {
global errorInfo
global errorCode
set theInfo $errorInfo
set theCode $errorCode
::snit::RT.DestroyObject $type $selfns $name
error "Error in constructor: $result" $theInfo $theCode
}
# NEXT, return the object's name.
return $name
}
# RT.MakeInstanceCommand type selfns instance
#
# type The object type
# selfns The instance namespace
# instance The instance name
#
# Creates the instance proc.
proc ::snit::RT.MakeInstanceCommand {type selfns instance} {
variable ${type}::Snit_info
# FIRST, remember the instance name. The Snit_instance variable
# allows the instance to figure out its current name given the
# instance namespace.
upvar ${selfns}::Snit_instance Snit_instance
set Snit_instance $instance
# NEXT, qualify the proc name if it's a widget.
if {$Snit_info(isWidget)} {
set procname ::$instance
} else {
set procname $instance
}
# NEXT, install the new proc
if {!$Snit_info(simpledispatch)} {
set instanceProc $::snit::nominalInstanceProc
} else {
set instanceProc $::snit::simpleInstanceProc
}
proc $procname {method args} \
[string map \
[list %SELFNS% $selfns %WIN% $instance %TYPE% $type] \
$instanceProc]
# NEXT, add the trace.
trace add command $procname {rename delete} \
[list ::snit::RT.InstanceTrace $type $selfns $instance]
}
# This proc is called when the instance command is renamed.
# If op is delete, then new will always be "", so op is redundant.
#
# type The fully-qualified type name
# selfns The instance namespace
# win The original instance/tk window name.
# old old instance command name
# new new instance command name
# op rename or delete
#
# If the op is delete, we need to clean up the object; otherwise,
# we need to track the change.
#
# NOTE: In Tcl 8.4.2 there's a bug: errors in rename and delete
# traces aren't propagated correctly. Instead, they silently
# vanish. Add a catch to output any error message.
proc ::snit::RT.InstanceTrace {type selfns win old new op} {
variable ${type}::Snit_info
# Note to developers ...
# For Tcl 8.4.0, errors thrown in trace handlers vanish silently.
# Therefore we catch them here and create some output to help in
# debugging such problems.
if {[catch {
# FIRST, clean up if necessary
if {"" == $new} {
if {$Snit_info(isWidget)} {
destroy $win
} else {
::snit::RT.DestroyObject $type $selfns $win
}
} else {
# Otherwise, track the change.
variable ${selfns}::Snit_instance
set Snit_instance [uplevel 1 [list namespace which -command $new]]
# Also, clear the instance caches, as many cached commands
# might be invalid.
RT.ClearInstanceCaches $selfns
}
} result]} {
global errorInfo
# Pop up the console on Windows wish, to enable stdout.
# This clobbers errorInfo on unix, so save it so we can print it.
set ei $errorInfo
catch {console show}
puts "Error in ::snit::RT.InstanceTrace $type $selfns $win $old $new $op:"
puts $ei
}
}
# Calls the instance constructor and handles related housekeeping.
proc ::snit::RT.ConstructInstance {type selfns instance arglist} {
variable ${type}::Snit_optionInfo
variable ${selfns}::Snit_iinfo
# Track whether we are constructed or not.
set Snit_iinfo(constructed) 0
# Call the user's constructor
eval [linsert $arglist 0 \
${type}::Snit_constructor $type $selfns $instance $instance]
set Snit_iinfo(constructed) 1
# Validate the initial set of options (including defaults)
foreach option $Snit_optionInfo(local) {
set value [set ${selfns}::options($option)]
if {"" != $Snit_optionInfo(typespec-$option)} {
if {[catch {
$Snit_optionInfo(typeobj-$option) validate $value
} result]} {
return -code error "invalid $option default: $result"
}
}
}
# Unset the configure cache for all -readonly options.
# This ensures that the next time anyone tries to
# configure it, an error is thrown.
foreach opt $Snit_optionInfo(local) {
if {$Snit_optionInfo(readonly-$opt)} {
unset -nocomplain ${selfns}::Snit_configureCache($opt)
}
}
return
}
# Returns a unique command name.
#
# REQUIRE: type is a fully qualified name.
# REQUIRE: name contains "%AUTO%"
# PROMISE: the returned command name is unused.
proc ::snit::RT.UniqueName {countervar type name} {
upvar $countervar counter
while 1 {
# FIRST, bump the counter and define the %AUTO% instance name;
# then substitute it into the specified name. Wrap around at
# 2^31 - 2 to prevent overflow problems.
incr counter
if {$counter > 2147483646} {
set counter 0
}
set auto "[namespace tail $type]$counter"
set candidate [Expand $name %AUTO% $auto]
if {![llength [info commands $candidate]]} {
return $candidate
}
}
}
# Returns a unique instance namespace, fully qualified.
#
# countervar The name of a counter variable
# type The instance's type
#
# REQUIRE: type is fully qualified
# PROMISE: The returned namespace name is unused.
proc ::snit::RT.UniqueInstanceNamespace {countervar type} {
upvar $countervar counter
while 1 {
# FIRST, bump the counter and define the namespace name.
# Then see if it already exists. Wrap around at
# 2^31 - 2 to prevent overflow problems.
incr counter
if {$counter > 2147483646} {
set counter 0
}
set ins "${type}::Snit_inst${counter}"
if {![namespace exists $ins]} {
return $ins
}
}
}
# Retrieves an option's value from the option database.
# Returns "" if no value is found.
proc ::snit::RT.OptionDbGet {type self opt} {
variable ${type}::Snit_optionInfo
return [option get $self \
$Snit_optionInfo(resource-$opt) \
$Snit_optionInfo(class-$opt)]
}
#-----------------------------------------------------------------------
# Object Destruction
# Implements the standard "destroy" method
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
proc ::snit::RT.method.destroy {type selfns win self} {
variable ${selfns}::Snit_iinfo
# Can't destroy the object if it isn't complete constructed.
if {!$Snit_iinfo(constructed)} {
return -code error "Called 'destroy' method in constructor"
}
# Calls Snit_cleanup, which (among other things) calls the
# user's destructor.
::snit::RT.DestroyObject $type $selfns $win
}
# This is the function that really cleans up; it's automatically
# called when any instance is destroyed, e.g., by "$object destroy"
# for types, and by the event for widgets.
#
# type The fully-qualified type name.
# selfns The instance namespace
# win The original instance command name.
proc ::snit::RT.DestroyObject {type selfns win} {
variable ${type}::Snit_info
# If the variable Snit_instance doesn't exist then there's no
# instance command for this object -- it's most likely a
# widgetadaptor. Consequently, there are some things that
# we don't need to do.
if {[info exists ${selfns}::Snit_instance]} {
upvar ${selfns}::Snit_instance instance
# First, remove the trace on the instance name, so that we
# don't call RT.DestroyObject recursively.
RT.RemoveInstanceTrace $type $selfns $win $instance
# Next, call the user's destructor
${type}::Snit_destructor $type $selfns $win $instance
# Next, if this isn't a widget, delete the instance command.
# If it is a widget, get the hull component's name, and rename
# it back to the widget name
# Next, delete the hull component's instance command,
# if there is one.
if {$Snit_info(isWidget)} {
set hullcmd [::snit::RT.Component $type $selfns hull]
catch {rename $instance ""}
# Clear the bind event
bind Snit$type$win ""
if {[llength [info commands $hullcmd]]} {
# FIRST, rename the hull back to its original name.
# If the hull is itself a megawidget, it will have its
# own cleanup to do, and it might not do it properly
# if it doesn't have the right name.
rename $hullcmd ::$instance
# NEXT, destroy it.
destroy $instance
}
} else {
catch {rename $instance ""}
}
}
# Next, delete the instance's namespace. This kills any
# instance variables.
namespace delete $selfns
return
}
# Remove instance trace
#
# type The fully qualified type name
# selfns The instance namespace
# win The original instance name/Tk window name
# instance The current instance name
proc ::snit::RT.RemoveInstanceTrace {type selfns win instance} {
variable ${type}::Snit_info
if {$Snit_info(isWidget)} {
set procname ::$instance
} else {
set procname $instance
}
# NEXT, remove any trace on this name
catch {
trace remove command $procname {rename delete} \
[list ::snit::RT.InstanceTrace $type $selfns $win]
}
}
#-----------------------------------------------------------------------
# Typecomponent Management and Method Caching
# Typecomponent trace; used for write trace on typecomponent
# variables. Saves the new component object name, provided
# that certain conditions are met. Also clears the typemethod
# cache.
proc ::snit::RT.TypecomponentTrace {type component n1 n2 op} {
upvar ${type}::Snit_info Snit_info
upvar ${type}::${component} cvar
upvar ${type}::Snit_typecomponents Snit_typecomponents
# Save the new component value.
set Snit_typecomponents($component) $cvar
# Clear the typemethod cache.
# TBD: can we unset just the elements related to
# this component?
unset -nocomplain -- ${type}::Snit_typemethodCache
}
# Generates and caches the command for a typemethod.
#
# type The type
# method The name of the typemethod to call.
#
# The return value is one of the following lists:
#
# {} There's no such method.
# {1} The method has submethods; look again.
# {0 } Here's the command to execute.
proc snit::RT.CacheTypemethodCommand {type method} {
upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo
upvar ${type}::Snit_typecomponents Snit_typecomponents
upvar ${type}::Snit_typemethodCache Snit_typemethodCache
upvar ${type}::Snit_info Snit_info
# FIRST, get the pattern data and the typecomponent name.
set implicitCreate 0
set instanceName ""
set starredMethod [lreplace $method end end *]
set methodTail [lindex $method end]
if {[info exists Snit_typemethodInfo($method)]} {
set key $method
} elseif {[info exists Snit_typemethodInfo($starredMethod)]} {
if {[lsearch -exact $Snit_info(excepttypemethods) $methodTail] == -1} {
set key $starredMethod
} else {
return [list ]
}
} elseif {$Snit_info(hasinstances)} {
# Assume the unknown name is an instance name to create, unless
# this is a widget and the style of the name is wrong, or the
# name mimics a standard typemethod.
if {[set ${type}::Snit_info(isWidget)] &&
![string match ".*" $method]} {
return [list ]
}
# Without this check, the call "$type info" will redefine the
# standard "::info" command, with disastrous results. Since it's
# a likely thing to do if !-typeinfo, put in an explicit check.
if {"info" == $method || "destroy" == $method} {
return [list ]
}
set implicitCreate 1
set instanceName $method
set key create
set method create
} else {
return [list ]
}
foreach {flag pattern compName} $Snit_typemethodInfo($key) {}
if {$flag == 1} {
return [list 1]
}
# NEXT, build the substitution list
set subList [list \
%% % \
%t $type \
%M $method \
%m [lindex $method end] \
%j [join $method _]]
if {"" != $compName} {
if {![info exists Snit_typecomponents($compName)]} {
error "$type delegates typemethod \"$method\" to undefined typecomponent \"$compName\""
}
lappend subList %c [list $Snit_typecomponents($compName)]
}
set command {}
foreach subpattern $pattern {
lappend command [string map $subList $subpattern]
}
if {$implicitCreate} {
# In this case, $method is the name of the instance to
# create. Don't cache, as we usually won't do this one
# again.
lappend command $instanceName
} else {
set Snit_typemethodCache($method) [list 0 $command]
}
return [list 0 $command]
}
#-----------------------------------------------------------------------
# Component Management and Method Caching
# Retrieves the object name given the component name.
proc ::snit::RT.Component {type selfns name} {
variable ${selfns}::Snit_components
if {[catch {set Snit_components($name)} result]} {
variable ${selfns}::Snit_instance
error "component \"$name\" is undefined in $type $Snit_instance"
}
return $result
}
# Component trace; used for write trace on component instance
# variables. Saves the new component object name, provided
# that certain conditions are met. Also clears the method
# cache.
proc ::snit::RT.ComponentTrace {type selfns component n1 n2 op} {
upvar ${type}::Snit_info Snit_info
upvar ${selfns}::${component} cvar
upvar ${selfns}::Snit_components Snit_components
# If they try to redefine the hull component after
# it's been defined, that's an error--but only if
# this is a widget or widget adaptor.
if {"hull" == $component &&
$Snit_info(isWidget) &&
[info exists Snit_components($component)]} {
set cvar $Snit_components($component)
error "The hull component cannot be redefined"
}
# Save the new component value.
set Snit_components($component) $cvar
# Clear the instance caches.
# TBD: can we unset just the elements related to
# this component?
RT.ClearInstanceCaches $selfns
}
# Generates and caches the command for a method.
#
# type: The instance's type
# selfns: The instance's private namespace
# win: The instance's original name (a Tk widget name, for
# snit::widgets.
# self: The instance's current name.
# method: The name of the method to call.
#
# The return value is one of the following lists:
#
# {} There's no such method.
# {1} The method has submethods; look again.
# {0 } Here's the command to execute.
proc ::snit::RT.CacheMethodCommand {type selfns win self method} {
variable ${type}::Snit_info
variable ${type}::Snit_methodInfo
variable ${type}::Snit_typecomponents
variable ${selfns}::Snit_components
variable ${selfns}::Snit_methodCache
# FIRST, get the pattern data and the component name.
set starredMethod [lreplace $method end end *]
set methodTail [lindex $method end]
if {[info exists Snit_methodInfo($method)]} {
set key $method
} elseif {[info exists Snit_methodInfo($starredMethod)] &&
[lsearch -exact $Snit_info(exceptmethods) $methodTail] == -1} {
set key $starredMethod
} else {
return [list ]
}
foreach {flag pattern compName} $Snit_methodInfo($key) {}
if {$flag == 1} {
return [list 1]
}
# NEXT, build the substitution list
set subList [list \
%% % \
%t $type \
%M $method \
%m [lindex $method end] \
%j [join $method _] \
%n [list $selfns] \
%w [list $win] \
%s [list $self]]
if {"" != $compName} {
if {[info exists Snit_components($compName)]} {
set compCmd $Snit_components($compName)
} elseif {[info exists Snit_typecomponents($compName)]} {
set compCmd $Snit_typecomponents($compName)
} else {
error "$type $self delegates method \"$method\" to undefined component \"$compName\""
}
lappend subList %c [list $compCmd]
}
# Note: The cached command will executed faster if it's
# already a list.
set command {}
foreach subpattern $pattern {
lappend command [string map $subList $subpattern]
}
set commandRec [list 0 $command]
set Snit_methodCache($method) $commandRec
return $commandRec
}
# Looks up a method's command.
#
# type: The instance's type
# selfns: The instance's private namespace
# win: The instance's original name (a Tk widget name, for
# snit::widgets.
# self: The instance's current name.
# method: The name of the method to call.
# errPrefix: Prefix for any error method
proc ::snit::RT.LookupMethodCommand {type selfns win self method errPrefix} {
set commandRec [snit::RT.CacheMethodCommand \
$type $selfns $win $self \
$method]
if {[llength $commandRec] == 0} {
return -code error \
"$errPrefix, \"$self $method\" is not defined"
} elseif {[lindex $commandRec 0] == 1} {
return -code error \
"$errPrefix, wrong number args: should be \"$self\" $method method args"
}
return [lindex $commandRec 1]
}
# Clears all instance command caches
proc ::snit::RT.ClearInstanceCaches {selfns} {
unset -nocomplain -- ${selfns}::Snit_methodCache
unset -nocomplain -- ${selfns}::Snit_cgetCache
unset -nocomplain -- ${selfns}::Snit_configureCache
unset -nocomplain -- ${selfns}::Snit_validateCache
}
#-----------------------------------------------------------------------
# Component Installation
# Implements %TYPE%::installhull. The variables self and selfns
# must be defined in the caller's context.
#
# Installs the named widget as the hull of a
# widgetadaptor. Once the widget is hijacked, its new name
# is assigned to the hull component.
proc ::snit::RT.installhull {type {using "using"} {widgetType ""} args} {
variable ${type}::Snit_info
variable ${type}::Snit_optionInfo
upvar self self
upvar selfns selfns
upvar ${selfns}::hull hull
upvar ${selfns}::options options
# FIRST, make sure we can do it.
if {!$Snit_info(isWidget)} {
error "installhull is valid only for snit::widgetadaptors"
}
if {[info exists ${selfns}::Snit_instance]} {
error "hull already installed for $type $self"
}
# NEXT, has it been created yet? If not, create it using
# the specified arguments.
if {"using" == $using} {
# FIRST, create the widget
set cmd [linsert $args 0 $widgetType $self]
set obj [uplevel 1 $cmd]
# NEXT, for each option explicitly delegated to the hull
# that doesn't appear in the usedOpts list, get the
# option database value and apply it--provided that the
# real option name and the target option name are different.
# (If they are the same, then the option database was
# already queried as part of the normal widget creation.)
#
# Also, we don't need to worry about implicitly delegated
# options, as the option and target option names must be
# the same.
if {[info exists Snit_optionInfo(delegated-hull)]} {
# FIRST, extract all option names from args
set usedOpts {}
set ndx [lsearch -glob $args "-*"]
foreach {opt val} [lrange $args $ndx end] {
lappend usedOpts $opt
}
foreach opt $Snit_optionInfo(delegated-hull) {
set target [lindex $Snit_optionInfo(target-$opt) 1]
if {"$target" == $opt} {
continue
}
set result [lsearch -exact $usedOpts $target]
if {$result != -1} {
continue
}
set dbval [RT.OptionDbGet $type $self $opt]
$obj configure $target $dbval
}
}
} else {
set obj $using
if {![string equal $obj $self]} {
error \
"hull name mismatch: \"$obj\" != \"$self\""
}
}
# NEXT, get the local option defaults.
foreach opt $Snit_optionInfo(local) {
set dbval [RT.OptionDbGet $type $self $opt]
if {"" != $dbval} {
set options($opt) $dbval
}
}
# NEXT, do the magic
set i 0
while 1 {
incr i
set newName "::hull${i}$self"
if {![llength [info commands $newName]]} {
break
}
}
rename ::$self $newName
RT.MakeInstanceCommand $type $selfns $self
# Note: this relies on RT.ComponentTrace to do the dirty work.
set hull $newName
return
}
# Implements %TYPE%::install.
#
# Creates a widget and installs it as the named component.
# It expects self and selfns to be defined in the caller's context.
proc ::snit::RT.install {type compName "using" widgetType winPath args} {
variable ${type}::Snit_optionInfo
variable ${type}::Snit_info
upvar self self
upvar selfns selfns
upvar ${selfns}::$compName comp
upvar ${selfns}::hull hull
# We do the magic option database stuff only if $self is
# a widget.
if {$Snit_info(isWidget)} {
if {"" == $hull} {
error "tried to install \"$compName\" before the hull exists"
}
# FIRST, query the option database and save the results
# into args. Insert them before the first option in the
# list, in case there are any non-standard parameters.
#
# Note: there might not be any delegated options; if so,
# don't bother.
if {[info exists Snit_optionInfo(delegated-$compName)]} {
set ndx [lsearch -glob $args "-*"]
foreach opt $Snit_optionInfo(delegated-$compName) {
set dbval [RT.OptionDbGet $type $self $opt]
if {"" != $dbval} {
set target [lindex $Snit_optionInfo(target-$opt) 1]
set args [linsert $args $ndx $target $dbval]
}
}
}
}
# NEXT, create the component and save it.
set cmd [concat [list $widgetType $winPath] $args]
set comp [uplevel 1 $cmd]
# NEXT, handle the option database for "delegate option *",
# in widgets only.
if {$Snit_info(isWidget) && [string equal $Snit_optionInfo(starcomp) $compName]} {
# FIRST, get the list of option specs from the widget.
# If configure doesn't work, skip it.
if {[catch {$comp configure} specs]} {
return
}
# NEXT, get the set of explicitly used options from args
set usedOpts {}
set ndx [lsearch -glob $args "-*"]
foreach {opt val} [lrange $args $ndx end] {
lappend usedOpts $opt
}
# NEXT, "delegate option *" matches all options defined
# by this widget that aren't defined by the widget as a whole,
# and that aren't excepted. Plus, we skip usedOpts. So build
# a list of the options it can't match.
set skiplist [concat \
$usedOpts \
$Snit_optionInfo(except) \
$Snit_optionInfo(local) \
$Snit_optionInfo(delegated)]
# NEXT, loop over all of the component's options, and set
# any not in the skip list for which there is an option
# database value.
foreach spec $specs {
# Skip aliases
if {[llength $spec] != 5} {
continue
}
set opt [lindex $spec 0]
if {[lsearch -exact $skiplist $opt] != -1} {
continue
}
set res [lindex $spec 1]
set cls [lindex $spec 2]
set dbvalue [option get $self $res $cls]
if {"" != $dbvalue} {
$comp configure $opt $dbvalue
}
}
}
return
}
#-----------------------------------------------------------------------
# Method/Variable Name Qualification
# Implements %TYPE%::variable. Requires selfns.
proc ::snit::RT.variable {varname} {
upvar selfns selfns
if {![string match "::*" $varname]} {
uplevel 1 [list upvar 1 ${selfns}::$varname $varname]
} else {
# varname is fully qualified; let the standard
# "variable" command handle it.
uplevel 1 [list ::variable $varname]
}
}
# Fully qualifies a typevariable name.
#
# This is used to implement the mytypevar command.
proc ::snit::RT.mytypevar {type name} {
return ${type}::$name
}
# Fully qualifies an instance variable name.
#
# This is used to implement the myvar command.
proc ::snit::RT.myvar {name} {
upvar selfns selfns
return ${selfns}::$name
}
# Use this like "list" to convert a proc call into a command
# string to pass to another object (e.g., as a -command).
# Qualifies the proc name properly.
#
# This is used to implement the "myproc" command.
proc ::snit::RT.myproc {type procname args} {
set procname "${type}::$procname"
return [linsert $args 0 $procname]
}
# DEPRECATED
proc ::snit::RT.codename {type name} {
return "${type}::$name"
}
# Use this like "list" to convert a typemethod call into a command
# string to pass to another object (e.g., as a -command).
# Inserts the type command at the beginning.
#
# This is used to implement the "mytypemethod" command.
proc ::snit::RT.mytypemethod {type args} {
return [linsert $args 0 $type]
}
# Use this like "list" to convert a method call into a command
# string to pass to another object (e.g., as a -command).
# Inserts the code at the beginning to call the right object, even if
# the object's name has changed. Requires that selfns be defined
# in the calling context, eg. can only be called in instance
# code.
#
# This is used to implement the "mymethod" command.
proc ::snit::RT.mymethod {args} {
upvar selfns selfns
return [linsert $args 0 ::snit::RT.CallInstance ${selfns}]
}
# Calls an instance method for an object given its
# instance namespace and remaining arguments (the first of which
# will be the method name.
#
# selfns The instance namespace
# args The arguments
#
# Uses the selfns to determine $self, and calls the method
# in the normal way.
#
# This is used to implement the "mymethod" command.
proc ::snit::RT.CallInstance {selfns args} {
upvar ${selfns}::Snit_instance self
set retval [catch {uplevel 1 [linsert $args 0 $self]} result]
if {$retval} {
if {$retval == 1} {
global errorInfo
global errorCode
return -code error -errorinfo $errorInfo \
-errorcode $errorCode $result
} else {
return -code $retval $result
}
}
return $result
}
# Looks for the named option in the named variable. If found,
# it and its value are removed from the list, and the value
# is returned. Otherwise, the default value is returned.
# If the option is undelegated, it's own default value will be
# used if none is specified.
#
# Implements the "from" command.
proc ::snit::RT.from {type argvName option {defvalue ""}} {
variable ${type}::Snit_optionInfo
upvar $argvName argv
set ioption [lsearch -exact $argv $option]
if {$ioption == -1} {
if {"" == $defvalue &&
[info exists Snit_optionInfo(default-$option)]} {
return $Snit_optionInfo(default-$option)
} else {
return $defvalue
}
}
set ivalue [expr {$ioption + 1}]
set value [lindex $argv $ivalue]
set argv [lreplace $argv $ioption $ivalue]
return $value
}
#-----------------------------------------------------------------------
# Type Destruction
# Implements the standard "destroy" typemethod:
# Destroys a type completely.
#
# type The snit type
proc ::snit::RT.typemethod.destroy {type} {
variable ${type}::Snit_info
# FIRST, destroy all instances
foreach selfns [namespace children $type] {
if {![namespace exists $selfns]} {
continue
}
upvar ${selfns}::Snit_instance obj
if {$Snit_info(isWidget)} {
destroy $obj
} else {
if {[llength [info commands $obj]]} {
$obj destroy
}
}
}
# NEXT, destroy the type's data.
namespace delete $type
# NEXT, get rid of the type command.
rename $type ""
}
#-----------------------------------------------------------------------
# Option Handling
# Implements the standard "cget" method
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
# option The name of the option
proc ::snit::RT.method.cget {type selfns win self option} {
if {[catch {set ${selfns}::Snit_cgetCache($option)} command]} {
set command [snit::RT.CacheCgetCommand $type $selfns $win $self $option]
if {[llength $command] == 0} {
return -code error "unknown option \"$option\""
}
}
uplevel 1 $command
}
# Retrieves and caches the command that implements "cget" for the
# specified option.
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
# option The name of the option
proc ::snit::RT.CacheCgetCommand {type selfns win self option} {
variable ${type}::Snit_optionInfo
variable ${selfns}::Snit_cgetCache
if {[info exists Snit_optionInfo(islocal-$option)]} {
# We know the item; it's either local, or explicitly delegated.
if {$Snit_optionInfo(islocal-$option)} {
# It's a local option. If it has a cget method defined,
# use it; otherwise just return the value.
if {"" == $Snit_optionInfo(cget-$option)} {
set command [list set ${selfns}::options($option)]
} else {
set command [snit::RT.LookupMethodCommand \
$type $selfns $win $self \
$Snit_optionInfo(cget-$option) \
"can't cget $option"]
lappend command $option
}
set Snit_cgetCache($option) $command
return $command
}
# Explicitly delegated option; get target
set comp [lindex $Snit_optionInfo(target-$option) 0]
set target [lindex $Snit_optionInfo(target-$option) 1]
} elseif {"" != $Snit_optionInfo(starcomp) &&
[lsearch -exact $Snit_optionInfo(except) $option] == -1} {
# Unknown option, but unknowns are delegated; get target.
set comp $Snit_optionInfo(starcomp)
set target $option
} else {
return ""
}
# Get the component's object.
set obj [RT.Component $type $selfns $comp]
set command [list $obj cget $target]
set Snit_cgetCache($option) $command
return $command
}
# Implements the standard "configurelist" method
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
# optionlist A list of options and their values.
proc ::snit::RT.method.configurelist {type selfns win self optionlist} {
variable ${type}::Snit_optionInfo
foreach {option value} $optionlist {
# FIRST, get the configure command, caching it if need be.
if {[catch {set ${selfns}::Snit_configureCache($option)} command]} {
set command [snit::RT.CacheConfigureCommand \
$type $selfns $win $self $option]
if {[llength $command] == 0} {
return -code error "unknown option \"$option\""
}
}
# NEXT, if we have a type-validation object, use it.
# TBD: Should test (islocal-$option) here, but islocal
# isn't defined for implicitly delegated options.
if {[info exists Snit_optionInfo(typeobj-$option)]
&& "" != $Snit_optionInfo(typeobj-$option)} {
if {[catch {
$Snit_optionInfo(typeobj-$option) validate $value
} result]} {
return -code error "invalid $option value: $result"
}
}
# NEXT, the caching the configure command also cached the
# validate command, if any. If we have one, run it.
set valcommand [set ${selfns}::Snit_validateCache($option)]
if {[llength $valcommand]} {
lappend valcommand $value
uplevel 1 $valcommand
}
# NEXT, configure the option with the value.
lappend command $value
uplevel 1 $command
}
return
}
# Retrieves and caches the command that stores the named option.
# Also stores the command that validates the name option if any;
# If none, the validate command is "", so that the cache is always
# populated.
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
# option An option name
proc ::snit::RT.CacheConfigureCommand {type selfns win self option} {
variable ${type}::Snit_optionInfo
variable ${selfns}::Snit_configureCache
variable ${selfns}::Snit_validateCache
if {[info exist Snit_optionInfo(islocal-$option)]} {
# We know the item; it's either local, or explicitly delegated.
if {$Snit_optionInfo(islocal-$option)} {
# It's a local option.
# If it's readonly, it throws an error if we're already
# constructed.
if {$Snit_optionInfo(readonly-$option)} {
if {[set ${selfns}::Snit_iinfo(constructed)]} {
error "option $option can only be set at instance creation"
}
}
# If it has a validate method, cache that for later.
if {"" != $Snit_optionInfo(validate-$option)} {
set command [snit::RT.LookupMethodCommand \
$type $selfns $win $self \
$Snit_optionInfo(validate-$option) \
"can't validate $option"]
lappend command $option
set Snit_validateCache($option) $command
} else {
set Snit_validateCache($option) ""
}
# If it has a configure method defined,
# cache it; otherwise, just set the value.
if {"" == $Snit_optionInfo(configure-$option)} {
set command [list set ${selfns}::options($option)]
} else {
set command [snit::RT.LookupMethodCommand \
$type $selfns $win $self \
$Snit_optionInfo(configure-$option) \
"can't configure $option"]
lappend command $option
}
set Snit_configureCache($option) $command
return $command
}
# Delegated option: get target.
set comp [lindex $Snit_optionInfo(target-$option) 0]
set target [lindex $Snit_optionInfo(target-$option) 1]
} elseif {$Snit_optionInfo(starcomp) != "" &&
[lsearch -exact $Snit_optionInfo(except) $option] == -1} {
# Unknown option, but unknowns are delegated.
set comp $Snit_optionInfo(starcomp)
set target $option
} else {
return ""
}
# There is no validate command in this case; save an empty string.
set Snit_validateCache($option) ""
# Get the component's object
set obj [RT.Component $type $selfns $comp]
set command [list $obj configure $target]
set Snit_configureCache($option) $command
return $command
}
# Implements the standard "configure" method
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
# args A list of options and their values, possibly empty.
proc ::snit::RT.method.configure {type selfns win self args} {
# If two or more arguments, set values as usual.
if {[llength $args] >= 2} {
::snit::RT.method.configurelist $type $selfns $win $self $args
return
}
# If zero arguments, acquire data for each known option
# and return the list
if {[llength $args] == 0} {
set result {}
foreach opt [RT.method.info.options $type $selfns $win $self] {
# Refactor this, so that we don't need to call via $self.
lappend result [RT.GetOptionDbSpec \
$type $selfns $win $self $opt]
}
return $result
}
# They want it for just one.
set opt [lindex $args 0]
return [RT.GetOptionDbSpec $type $selfns $win $self $opt]
}
# Retrieves the option database spec for a single option.
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
# option The name of an option
#
# TBD: This is a bad name. What it's returning is the
# result of the configure query.
proc ::snit::RT.GetOptionDbSpec {type selfns win self opt} {
variable ${type}::Snit_optionInfo
upvar ${selfns}::Snit_components Snit_components
upvar ${selfns}::options options
if {[info exists options($opt)]} {
# This is a locally-defined option. Just build the
# list and return it.
set res $Snit_optionInfo(resource-$opt)
set cls $Snit_optionInfo(class-$opt)
set def $Snit_optionInfo(default-$opt)
return [list $opt $res $cls $def \
[RT.method.cget $type $selfns $win $self $opt]]
} elseif {[info exists Snit_optionInfo(target-$opt)]} {
# This is an explicitly delegated option. The only
# thing we don't have is the default.
set res $Snit_optionInfo(resource-$opt)
set cls $Snit_optionInfo(class-$opt)
# Get the default
set logicalName [lindex $Snit_optionInfo(target-$opt) 0]
set comp $Snit_components($logicalName)
set target [lindex $Snit_optionInfo(target-$opt) 1]
if {[catch {$comp configure $target} result]} {
set defValue {}
} else {
set defValue [lindex $result 3]
}
return [list $opt $res $cls $defValue [$self cget $opt]]
} elseif {"" != $Snit_optionInfo(starcomp) &&
[lsearch -exact $Snit_optionInfo(except) $opt] == -1} {
set logicalName $Snit_optionInfo(starcomp)
set target $opt
set comp $Snit_components($logicalName)
if {[catch {set value [$comp cget $target]} result]} {
error "unknown option \"$opt\""
}
if {![catch {$comp configure $target} result]} {
# Replace the delegated option name with the local name.
return [::snit::Expand $result $target $opt]
}
# configure didn't work; return simple form.
return [list $opt "" "" "" $value]
} else {
error "unknown option \"$opt\""
}
}
#-----------------------------------------------------------------------
# Type Introspection
# Implements the standard "info" typemethod.
#
# type The snit type
# command The info subcommand
# args All other arguments.
proc ::snit::RT.typemethod.info {type command args} {
global errorInfo
global errorCode
switch -exact $command {
args -
body -
default -
typevars -
typemethods -
instances {
# TBD: it should be possible to delete this error
# handling.
set errflag [catch {
uplevel 1 [linsert $args 0 \
::snit::RT.typemethod.info.$command $type]
} result]
if {$errflag} {
return -code error -errorinfo $errorInfo \
-errorcode $errorCode $result
} else {
return $result
}
}
default {
error "\"$type info $command\" is not defined"
}
}
}
# Returns a list of the type's typevariables whose names match a
# pattern, excluding Snit internal variables.
#
# type A Snit type
# pattern Optional. The glob pattern to match. Defaults
# to *.
proc ::snit::RT.typemethod.info.typevars {type {pattern *}} {
set result {}
foreach name [info vars "${type}::$pattern"] {
set tail [namespace tail $name]
if {![string match "Snit_*" $tail]} {
lappend result $name
}
}
return $result
}
# Returns a list of the type's methods whose names match a
# pattern. If "delegate typemethod *" is used, the list may
# not be complete.
#
# type A Snit type
# pattern Optional. The glob pattern to match. Defaults
# to *.
proc ::snit::RT.typemethod.info.typemethods {type {pattern *}} {
variable ${type}::Snit_typemethodInfo
variable ${type}::Snit_typemethodCache
# FIRST, get the explicit names, skipping prefixes.
set result {}
foreach name [array names Snit_typemethodInfo $pattern] {
if {[lindex $Snit_typemethodInfo($name) 0] != 1} {
lappend result $name
}
}
# NEXT, add any from the cache that aren't explicit.
if {[info exists Snit_typemethodInfo(*)]} {
# First, remove "*" from the list.
set ndx [lsearch -exact $result "*"]
if {$ndx != -1} {
set result [lreplace $result $ndx $ndx]
}
foreach name [array names Snit_typemethodCache $pattern] {
if {[lsearch -exact $result $name] == -1} {
lappend result $name
}
}
}
return $result
}
# $type info args
#
# Returns a method's list of arguments. does not work for delegated
# methods, nor for the internal dispatch methods of multi-word
# methods.
proc ::snit::RT.typemethod.info.args {type method} {
upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo
# Snit_methodInfo: method -> list (flag cmd component)
# flag : 1 -> internal dispatcher for multi-word method.
# 0 -> regular method
#
# cmd : template mapping from method to command prefix, may
# contain placeholders for various pieces of information.
#
# component : is empty for normal methods.
#parray Snit_typemethodInfo
if {![info exists Snit_typemethodInfo($method)]} {
return -code error "Unknown typemethod \"$method\""
}
foreach {flag cmd component} $Snit_typemethodInfo($method) break
if {$flag} {
return -code error "Unknown typemethod \"$method\""
}
if {$component != ""} {
return -code error "Delegated typemethod \"$method\""
}
set map [list %m $method %j [join $method _] %t $type]
set theproc [lindex [string map $map $cmd] 0]
return [lrange [::info args $theproc] 1 end]
}
# $type info body
#
# Returns a method's body. does not work for delegated
# methods, nor for the internal dispatch methods of multi-word
# methods.
proc ::snit::RT.typemethod.info.body {type method} {
upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo
# Snit_methodInfo: method -> list (flag cmd component)
# flag : 1 -> internal dispatcher for multi-word method.
# 0 -> regular method
#
# cmd : template mapping from method to command prefix, may
# contain placeholders for various pieces of information.
#
# component : is empty for normal methods.
#parray Snit_typemethodInfo
if {![info exists Snit_typemethodInfo($method)]} {
return -code error "Unknown typemethod \"$method\""
}
foreach {flag cmd component} $Snit_typemethodInfo($method) break
if {$flag} {
return -code error "Unknown typemethod \"$method\""
}
if {$component != ""} {
return -code error "Delegated typemethod \"$method\""
}
set map [list %m $method %j [join $method _] %t $type]
set theproc [lindex [string map $map $cmd] 0]
return [RT.body [::info body $theproc]]
}
# $type info default
#
# Returns a method's list of arguments. does not work for delegated
# methods, nor for the internal dispatch methods of multi-word
# methods.
proc ::snit::RT.typemethod.info.default {type method aname dvar} {
upvar 1 $dvar def
upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo
# Snit_methodInfo: method -> list (flag cmd component)
# flag : 1 -> internal dispatcher for multi-word method.
# 0 -> regular method
#
# cmd : template mapping from method to command prefix, may
# contain placeholders for various pieces of information.
#
# component : is empty for normal methods.
#parray Snit_methodInfo
if {![info exists Snit_typemethodInfo($method)]} {
return -code error "Unknown typemethod \"$method\""
}
foreach {flag cmd component} $Snit_typemethodInfo($method) break
if {$flag} {
return -code error "Unknown typemethod \"$method\""
}
if {$component != ""} {
return -code error "Delegated typemethod \"$method\""
}
set map [list %m $method %j [join $method _] %t $type]
set theproc [lindex [string map $map $cmd] 0]
return [::info default $theproc $aname def]
}
# Returns a list of the type's instances whose names match
# a pattern.
#
# type A Snit type
# pattern Optional. The glob pattern to match
# Defaults to *
#
# REQUIRE: type is fully qualified.
proc ::snit::RT.typemethod.info.instances {type {pattern *}} {
set result {}
foreach selfns [namespace children $type] {
upvar ${selfns}::Snit_instance instance
if {[string match $pattern $instance]} {
lappend result $instance
}
}
return $result
}
#-----------------------------------------------------------------------
# Instance Introspection
# Implements the standard "info" method.
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
# command The info subcommand
# args All other arguments.
proc ::snit::RT.method.info {type selfns win self command args} {
switch -exact $command {
args -
body -
default -
type -
vars -
options -
methods -
typevars -
typemethods {
set errflag [catch {
uplevel 1 [linsert $args 0 ::snit::RT.method.info.$command \
$type $selfns $win $self]
} result]
if {$errflag} {
global errorInfo
return -code error -errorinfo $errorInfo $result
} else {
return $result
}
}
default {
# error "\"$self info $command\" is not defined"
return -code error "\"$self info $command\" is not defined"
}
}
}
# $self info type
#
# Returns the instance's type
proc ::snit::RT.method.info.type {type selfns win self} {
return $type
}
# $self info typevars
#
# Returns the instance's type's typevariables
proc ::snit::RT.method.info.typevars {type selfns win self {pattern *}} {
return [RT.typemethod.info.typevars $type $pattern]
}
# $self info typemethods
#
# Returns the instance's type's typemethods
proc ::snit::RT.method.info.typemethods {type selfns win self {pattern *}} {
return [RT.typemethod.info.typemethods $type $pattern]
}
# Returns a list of the instance's methods whose names match a
# pattern. If "delegate method *" is used, the list may
# not be complete.
#
# type A Snit type
# selfns The instance namespace
# win The original instance name
# self The current instance name
# pattern Optional. The glob pattern to match. Defaults
# to *.
proc ::snit::RT.method.info.methods {type selfns win self {pattern *}} {
variable ${type}::Snit_methodInfo
variable ${selfns}::Snit_methodCache
# FIRST, get the explicit names, skipping prefixes.
set result {}
foreach name [array names Snit_methodInfo $pattern] {
if {[lindex $Snit_methodInfo($name) 0] != 1} {
lappend result $name
}
}
# NEXT, add any from the cache that aren't explicit.
if {[info exists Snit_methodInfo(*)]} {
# First, remove "*" from the list.
set ndx [lsearch -exact $result "*"]
if {$ndx != -1} {
set result [lreplace $result $ndx $ndx]
}
foreach name [array names Snit_methodCache $pattern] {
if {[lsearch -exact $result $name] == -1} {
lappend result $name
}
}
}
return $result
}
# $self info args
#
# Returns a method's list of arguments. does not work for delegated
# methods, nor for the internal dispatch methods of multi-word
# methods.
proc ::snit::RT.method.info.args {type selfns win self method} {
upvar ${type}::Snit_methodInfo Snit_methodInfo
# Snit_methodInfo: method -> list (flag cmd component)
# flag : 1 -> internal dispatcher for multi-word method.
# 0 -> regular method
#
# cmd : template mapping from method to command prefix, may
# contain placeholders for various pieces of information.
#
# component : is empty for normal methods.
#parray Snit_methodInfo
if {![info exists Snit_methodInfo($method)]} {
return -code error "Unknown method \"$method\""
}
foreach {flag cmd component} $Snit_methodInfo($method) break
if {$flag} {
return -code error "Unknown method \"$method\""
}
if {$component != ""} {
return -code error "Delegated method \"$method\""
}
set map [list %m $method %j [join $method _] %t $type %n $selfns %w $win %s $self]
set theproc [lindex [string map $map $cmd] 0]
return [lrange [::info args $theproc] 4 end]
}
# $self info body
#
# Returns a method's body. does not work for delegated
# methods, nor for the internal dispatch methods of multi-word
# methods.
proc ::snit::RT.method.info.body {type selfns win self method} {
upvar ${type}::Snit_methodInfo Snit_methodInfo
# Snit_methodInfo: method -> list (flag cmd component)
# flag : 1 -> internal dispatcher for multi-word method.
# 0 -> regular method
#
# cmd : template mapping from method to command prefix, may
# contain placeholders for various pieces of information.
#
# component : is empty for normal methods.
#parray Snit_methodInfo
if {![info exists Snit_methodInfo($method)]} {
return -code error "Unknown method \"$method\""
}
foreach {flag cmd component} $Snit_methodInfo($method) break
if {$flag} {
return -code error "Unknown method \"$method\""
}
if {$component != ""} {
return -code error "Delegated method \"$method\""
}
set map [list %m $method %j [join $method _] %t $type %n $selfns %w $win %s $self]
set theproc [lindex [string map $map $cmd] 0]
return [RT.body [::info body $theproc]]
}
# $self info default
#
# Returns a method's list of arguments. does not work for delegated
# methods, nor for the internal dispatch methods of multi-word
# methods.
proc ::snit::RT.method.info.default {type selfns win self method aname dvar} {
upvar 1 $dvar def
upvar ${type}::Snit_methodInfo Snit_methodInfo
# Snit_methodInfo: method -> list (flag cmd component)
# flag : 1 -> internal dispatcher for multi-word method.
# 0 -> regular method
#
# cmd : template mapping from method to command prefix, may
# contain placeholders for various pieces of information.
#
# component : is empty for normal methods.
if {![info exists Snit_methodInfo($method)]} {
return -code error "Unknown method \"$method\""
}
foreach {flag cmd component} $Snit_methodInfo($method) break
if {$flag} {
return -code error "Unknown method \"$method\""
}
if {$component != ""} {
return -code error "Delegated method \"$method\""
}
set map [list %m $method %j [join $method _] %t $type %n $selfns %w $win %s $self]
set theproc [lindex [string map $map $cmd] 0]
return [::info default $theproc $aname def]
}
# $self info vars
#
# Returns the instance's instance variables
proc ::snit::RT.method.info.vars {type selfns win self {pattern *}} {
set result {}
foreach name [info vars "${selfns}::$pattern"] {
set tail [namespace tail $name]
if {![string match "Snit_*" $tail]} {
lappend result $name
}
}
return $result
}
# $self info options
#
# Returns a list of the names of the instance's options
proc ::snit::RT.method.info.options {type selfns win self {pattern *}} {
variable ${type}::Snit_optionInfo
# First, get the local and explicitly delegated options
set result [concat $Snit_optionInfo(local) $Snit_optionInfo(delegated)]
# If "configure" works as for Tk widgets, add the resulting
# options to the list. Skip excepted options
if {"" != $Snit_optionInfo(starcomp)} {
upvar ${selfns}::Snit_components Snit_components
set logicalName $Snit_optionInfo(starcomp)
set comp $Snit_components($logicalName)
if {![catch {$comp configure} records]} {
foreach record $records {
set opt [lindex $record 0]
if {[lsearch -exact $result $opt] == -1 &&
[lsearch -exact $Snit_optionInfo(except) $opt] == -1} {
lappend result $opt
}
}
}
}
# Next, apply the pattern
set names {}
foreach name $result {
if {[string match $pattern $name]} {
lappend names $name
}
}
return $names
}
proc ::snit::RT.body {body} {
regsub -all ".*# END snit method prolog\n" $body {} body
return $body
}
amsn-0.98.9/utils/snit/snit2.tcl 0000644 0001750 0001750 00000001401 11020317540 016236 0 ustar billiob billiob #-----------------------------------------------------------------------
# TITLE:
# snit2.tcl
#
# AUTHOR:
# Will Duquette
#
# DESCRIPTION:
# Snit's Not Incr Tcl, a simple object system in Pure Tcl.
#
# Snit 2.x Loader
#
# Copyright (C) 2003-2006 by William H. Duquette
# This code is licensed as described in license.txt.
#
#-----------------------------------------------------------------------
package require Tcl 8.5
# Define the snit namespace and save the library directory
namespace eval ::snit:: {
set library [file dirname [info script]]
}
# Load the kernel.
source [file join $::snit::library main2.tcl]
# Load the library of Snit validation types.
source [file join $::snit::library validate.tcl]
package provide snit 2.2.1
amsn-0.98.9/utils/snit/main1_83.tcl 0000644 0001750 0001750 00000372640 11020317540 016536 0 ustar billiob billiob #-----------------------------------------------------------------------
# TITLE:
# main1_83.tcl
#
# AUTHOR:
# Will Duquette
#
# DESCRIPTION:
# Snit's Not Incr Tcl, a simple object system in Pure Tcl.
#
# Snit 1.x Compiler and Run-Time Library, Tcl 8.3 and later
#
# Copyright (C) 2003-2006 by William H. Duquette
# This code is licensed as described in license.txt.
#
#-----------------------------------------------------------------------
# Back-port to Tcl8.3 by Kenneth Green (kmg)
# Modified by Andreas Kupries.
# Further modified by Will Duquette 12 Aug 2006
#
# Local changes marked with "#kmg-tcl83"
#
# Global changes:
# " trace add variable " -> "trace variable "
# " write " -> "w" in all calls to 'trace variable'
# " unset -nocomplain " -> "::snit83::unset -nocomplain"
#-----------------------------------------------------------------------
#-----------------------------------------------------------------------
# Namespace
namespace eval ::snit:: {
namespace export \
compile type widget widgetadaptor typemethod method macro
}
#-----------------------------------------------------------------------
# Some Snit variables
namespace eval ::snit:: {
variable reservedArgs {type selfns win self}
# Widget classes which can be hulls (must have -class)
variable hulltypes {
toplevel tk::toplevel
frame tk::frame ttk::frame
labelframe tk::labelframe ttk::labelframe
}
}
#-----------------------------------------------------------------------
# Snit Type Implementation template
namespace eval ::snit:: {
# Template type definition: All internal and user-visible Snit
# implementation code.
#
# The following placeholders will automatically be replaced with
# the client's code, in two passes:
#
# First pass:
# %COMPILEDDEFS% The compiled type definition.
#
# Second pass:
# %TYPE% The fully qualified type name.
# %IVARDECS% Instance variable declarations
# %TVARDECS% Type variable declarations
# %TCONSTBODY% Type constructor body
# %INSTANCEVARS% The compiled instance variable initialization code.
# %TYPEVARS% The compiled type variable initialization code.
# This is the overall type template.
variable typeTemplate
# This is the normal type proc
variable nominalTypeProc
# This is the "-hastypemethods no" type proc
variable simpleTypeProc
}
set ::snit::typeTemplate {
#-------------------------------------------------------------------
# The type's namespace definition and the user's type variables
namespace eval %TYPE% {%TYPEVARS%
}
#----------------------------------------------------------------
# Commands for use in methods, typemethods, etc.
#
# These are implemented as aliases into the Snit runtime library.
interp alias {} %TYPE%::installhull {} ::snit::RT.installhull %TYPE%
interp alias {} %TYPE%::install {} ::snit::RT.install %TYPE%
interp alias {} %TYPE%::typevariable {} ::variable
interp alias {} %TYPE%::variable {} ::snit::RT.variable
interp alias {} %TYPE%::mytypevar {} ::snit::RT.mytypevar %TYPE%
interp alias {} %TYPE%::typevarname {} ::snit::RT.mytypevar %TYPE%
interp alias {} %TYPE%::myvar {} ::snit::RT.myvar
interp alias {} %TYPE%::varname {} ::snit::RT.myvar
interp alias {} %TYPE%::codename {} ::snit::RT.codename %TYPE%
interp alias {} %TYPE%::myproc {} ::snit::RT.myproc %TYPE%
interp alias {} %TYPE%::mymethod {} ::snit::RT.mymethod
interp alias {} %TYPE%::mytypemethod {} ::snit::RT.mytypemethod %TYPE%
interp alias {} %TYPE%::from {} ::snit::RT.from %TYPE%
#-------------------------------------------------------------------
# Snit's internal variables
namespace eval %TYPE% {
# Array: General Snit Info
#
# ns: The type's namespace
# hasinstances: T or F, from pragma -hasinstances.
# simpledispatch: T or F, from pragma -hasinstances.
# canreplace: T or F, from pragma -canreplace.
# counter: Count of instances created so far.
# widgetclass: Set by widgetclass statement.
# hulltype: Hull type (frame or toplevel) for widgets only.
# exceptmethods: Methods explicitly not delegated to *
# excepttypemethods: Methods explicitly not delegated to *
# tvardecs: Type variable declarations--for dynamic methods
# ivardecs: Instance variable declarations--for dyn. methods
typevariable Snit_info
set Snit_info(ns) %TYPE%::
set Snit_info(hasinstances) 1
set Snit_info(simpledispatch) 0
set Snit_info(canreplace) 0
set Snit_info(counter) 0
set Snit_info(widgetclass) {}
set Snit_info(hulltype) frame
set Snit_info(exceptmethods) {}
set Snit_info(excepttypemethods) {}
set Snit_info(tvardecs) {%TVARDECS%}
set Snit_info(ivardecs) {%IVARDECS%}
# Array: Public methods of this type.
# The index is the method name, or "*".
# The value is [list $pattern $componentName], where
# $componentName is "" for normal methods.
typevariable Snit_typemethodInfo
array unset Snit_typemethodInfo
# Array: Public methods of instances of this type.
# The index is the method name, or "*".
# The value is [list $pattern $componentName], where
# $componentName is "" for normal methods.
typevariable Snit_methodInfo
array unset Snit_methodInfo
# Array: option information. See dictionary.txt.
typevariable Snit_optionInfo
array unset Snit_optionInfo
set Snit_optionInfo(local) {}
set Snit_optionInfo(delegated) {}
set Snit_optionInfo(starcomp) {}
set Snit_optionInfo(except) {}
}
#----------------------------------------------------------------
# Compiled Procs
#
# These commands are created or replaced during compilation:
# Snit_instanceVars selfns
#
# Initializes the instance variables, if any. Called during
# instance creation.
proc %TYPE%::Snit_instanceVars {selfns} {
%INSTANCEVARS%
}
# Type Constructor
proc %TYPE%::Snit_typeconstructor {type} {
%TVARDECS%
%TCONSTBODY%
}
#----------------------------------------------------------------
# Default Procs
#
# These commands might be replaced during compilation:
# Snit_destructor type selfns win self
#
# Default destructor for the type. By default, it does
# nothing. It's replaced by any user destructor.
# For types, it's called by method destroy; for widgettypes,
# it's called by a destroy event handler.
proc %TYPE%::Snit_destructor {type selfns win self} { }
#----------------------------------------------------------
# Compiled Definitions
%COMPILEDDEFS%
#----------------------------------------------------------
# Finally, call the Type Constructor
%TYPE%::Snit_typeconstructor %TYPE%
}
#-----------------------------------------------------------------------
# Type procs
#
# These procs expect the fully-qualified type name to be
# substituted in for %TYPE%.
# This is the nominal type proc. It supports typemethods and
# delegated typemethods.
set ::snit::nominalTypeProc {
# Type dispatcher function. Note: This function lives
# in the parent of the %TYPE% namespace! All accesses to
# %TYPE% variables and methods must be qualified!
proc %TYPE% {{method ""} args} {
# First, if there's no method, and no args, and there's a create
# method, and this isn't a widget, then method is "create" and
# "args" is %AUTO%.
if {"" == $method && [llength $args] == 0} {
::variable %TYPE%::Snit_info
if {$Snit_info(hasinstances) && !$Snit_info(isWidget)} {
set method create
lappend args %AUTO%
} else {
error "wrong \# args: should be \"%TYPE% method args\""
}
}
# Next, retrieve the command.
variable %TYPE%::Snit_typemethodCache
while 1 {
if {[catch {set Snit_typemethodCache($method)} commandRec]} {
set commandRec [::snit::RT.CacheTypemethodCommand %TYPE% $method]
if {[llength $commandRec] == 0} {
return -code error "\"%TYPE% $method\" is not defined"
}
}
# If we've got a real command, break.
if {[lindex $commandRec 0] == 0} {
break
}
# Otherwise, we need to look up again...if we can.
if {[llength $args] == 0} {
return -code error \
"wrong number args: should be \"%TYPE% $method method args\""
}
lappend method [lindex $args 0]
set args [lrange $args 1 end]
}
set command [lindex $commandRec 1]
# Pass along the return code unchanged.
set retval [catch {uplevel 1 $command $args} result]
if {$retval} {
if {$retval == 1} {
global errorInfo
global errorCode
return -code error -errorinfo $errorInfo \
-errorcode $errorCode $result
} else {
return -code $retval $result
}
}
return $result
}
}
# This is the simplified type proc for when there are no typemethods
# except create. In this case, it doesn't take a method argument;
# the method is always "create".
set ::snit::simpleTypeProc {
# Type dispatcher function. Note: This function lives
# in the parent of the %TYPE% namespace! All accesses to
# %TYPE% variables and methods must be qualified!
proc %TYPE% {args} {
::variable %TYPE%::Snit_info
# FIRST, if the are no args, the single arg is %AUTO%
if {[llength $args] == 0} {
if {$Snit_info(isWidget)} {
error "wrong \# args: should be \"%TYPE% name args\""
}
lappend args %AUTO%
}
# NEXT, we're going to call the create method.
# Pass along the return code unchanged.
if {$Snit_info(isWidget)} {
set command [list ::snit::RT.widget.typemethod.create %TYPE%]
} else {
set command [list ::snit::RT.type.typemethod.create %TYPE%]
}
set retval [catch {uplevel 1 $command $args} result]
if {$retval} {
if {$retval == 1} {
global errorInfo
global errorCode
return -code error -errorinfo $errorInfo \
-errorcode $errorCode $result
} else {
return -code $retval $result
}
}
return $result
}
}
#-----------------------------------------------------------------------
# Instance procs
#
# The following must be substituted into these proc bodies:
#
# %SELFNS% The instance namespace
# %WIN% The original instance name
# %TYPE% The fully-qualified type name
#
# Nominal instance proc body: supports method caching and delegation.
#
# proc $instanceName {method args} ....
set ::snit::nominalInstanceProc {
set self [set %SELFNS%::Snit_instance]
while {1} {
if {[catch {set %SELFNS%::Snit_methodCache($method)} commandRec]} {
set commandRec [snit::RT.CacheMethodCommand %TYPE% %SELFNS% %WIN% $self $method]
if {[llength $commandRec] == 0} {
return -code error \
"\"$self $method\" is not defined"
}
}
# If we've got a real command, break.
if {[lindex $commandRec 0] == 0} {
break
}
# Otherwise, we need to look up again...if we can.
if {[llength $args] == 0} {
return -code error \
"wrong number args: should be \"$self $method method args\""
}
lappend method [lindex $args 0]
set args [lrange $args 1 end]
}
set command [lindex $commandRec 1]
# Pass along the return code unchanged.
set retval [catch {uplevel 1 $command $args} result]
if {$retval} {
if {$retval == 1} {
global errorInfo
global errorCode
return -code error -errorinfo $errorInfo \
-errorcode $errorCode $result
} else {
return -code $retval $result
}
}
return $result
}
# Simplified method proc body: No delegation allowed; no support for
# upvar or exotic return codes or hierarchical methods. Designed for
# max speed for simple types.
#
# proc $instanceName {method args} ....
set ::snit::simpleInstanceProc {
set self [set %SELFNS%::Snit_instance]
if {[lsearch -exact ${%TYPE%::Snit_methods} $method] == -1} {
set optlist [join ${%TYPE%::Snit_methods} ", "]
set optlist [linsert $optlist "end-1" "or"]
error "bad option \"$method\": must be $optlist"
}
eval [linsert $args 0 \
%TYPE%::Snit_method$method %TYPE% %SELFNS% %WIN% $self]
}
#=======================================================================
# Snit Type Definition
#
# These are the procs used to define Snit types, widgets, and
# widgetadaptors.
#-----------------------------------------------------------------------
# Snit Compilation Variables
#
# The following variables are used while Snit is compiling a type,
# and are disposed afterwards.
namespace eval ::snit:: {
# The compiler variable contains the name of the slave interpreter
# used to compile type definitions.
variable compiler ""
# The compile array accumulates information about the type or
# widgettype being compiled. It is cleared before and after each
# compilation. It has these indices:
#
# type: The name of the type being compiled, for use
# in compilation procs.
# defs: Compiled definitions, both standard and client.
# which: type, widget, widgetadaptor
# instancevars: Instance variable definitions and initializations.
# ivprocdec: Instance variable proc declarations.
# tvprocdec: Type variable proc declarations.
# typeconstructor: Type constructor body.
# widgetclass: The widgetclass, for snit::widgets, only
# hasoptions: False, initially; set to true when first
# option is defined.
# localoptions: Names of local options.
# delegatedoptions: Names of delegated options.
# localmethods: Names of locally defined methods.
# delegatesmethods: no if no delegated methods, yes otherwise.
# hashierarchic : no if no hierarchic methods, yes otherwise.
# components: Names of defined components.
# typecomponents: Names of defined typecomponents.
# typevars: Typevariable definitions and initializations.
# varnames: Names of instance variables
# typevarnames Names of type variables
# hasconstructor False, initially; true when constructor is
# defined.
# resource-$opt The option's resource name
# class-$opt The option's class
# -default-$opt The option's default value
# -validatemethod-$opt The option's validate method
# -configuremethod-$opt The option's configure method
# -cgetmethod-$opt The option's cget method.
# -hastypeinfo The -hastypeinfo pragma
# -hastypedestroy The -hastypedestroy pragma
# -hastypemethods The -hastypemethods pragma
# -hasinfo The -hasinfo pragma
# -hasinstances The -hasinstances pragma
# -simpledispatch The -simpledispatch pragma
# -canreplace The -canreplace pragma
variable compile
# This variable accumulates method dispatch information; it has
# the same structure as the %TYPE%::Snit_methodInfo array, and is
# used to initialize it.
variable methodInfo
# This variable accumulates typemethod dispatch information; it has
# the same structure as the %TYPE%::Snit_typemethodInfo array, and is
# used to initialize it.
variable typemethodInfo
# The following variable lists the reserved type definition statement
# names, e.g., the names you can't use as macros. It's built at
# compiler definition time using "info commands".
variable reservedwords {}
}
#-----------------------------------------------------------------------
# type compilation commands
#
# The type and widgettype commands use a slave interpreter to compile
# the type definition. These are the procs
# that are aliased into it.
# Initialize the compiler
proc ::snit::Comp.Init {} {
variable compiler
variable reservedwords
if {"" == $compiler} {
# Create the compiler's interpreter
set compiler [interp create]
# Initialize the interpreter
$compiler eval {
# Load package information
# TBD: see if this can be moved outside.
# @mdgen NODEP: ::snit::__does_not_exist__
catch {package require ::snit::__does_not_exist__}
# Protect some Tcl commands our type definitions
# will shadow.
rename proc _proc
rename variable _variable
}
# Define compilation aliases.
$compiler alias pragma ::snit::Comp.statement.pragma
$compiler alias widgetclass ::snit::Comp.statement.widgetclass
$compiler alias hulltype ::snit::Comp.statement.hulltype
$compiler alias constructor ::snit::Comp.statement.constructor
$compiler alias destructor ::snit::Comp.statement.destructor
$compiler alias option ::snit::Comp.statement.option
$compiler alias oncget ::snit::Comp.statement.oncget
$compiler alias onconfigure ::snit::Comp.statement.onconfigure
$compiler alias method ::snit::Comp.statement.method
$compiler alias typemethod ::snit::Comp.statement.typemethod
$compiler alias typeconstructor ::snit::Comp.statement.typeconstructor
$compiler alias proc ::snit::Comp.statement.proc
$compiler alias typevariable ::snit::Comp.statement.typevariable
$compiler alias variable ::snit::Comp.statement.variable
$compiler alias typecomponent ::snit::Comp.statement.typecomponent
$compiler alias component ::snit::Comp.statement.component
$compiler alias delegate ::snit::Comp.statement.delegate
$compiler alias expose ::snit::Comp.statement.expose
# Get the list of reserved words
set reservedwords [$compiler eval {info commands}]
}
}
# Compile a type definition, and return the results as a list of two
# items: the fully-qualified type name, and a script that will define
# the type when executed.
#
# which type, widget, or widgetadaptor
# type the type name
# body the type definition
proc ::snit::Comp.Compile {which type body} {
variable typeTemplate
variable nominalTypeProc
variable simpleTypeProc
variable compile
variable compiler
variable methodInfo
variable typemethodInfo
# FIRST, qualify the name.
if {![string match "::*" $type]} {
# Get caller's namespace;
# append :: if not global namespace.
set ns [uplevel 2 [list namespace current]]
if {"::" != $ns} {
append ns "::"
}
set type "$ns$type"
}
# NEXT, create and initialize the compiler, if needed.
Comp.Init
# NEXT, initialize the class data
array unset methodInfo
array unset typemethodInfo
array unset compile
set compile(type) $type
set compile(defs) {}
set compile(which) $which
set compile(hasoptions) no
set compile(localoptions) {}
set compile(instancevars) {}
set compile(typevars) {}
set compile(delegatedoptions) {}
set compile(ivprocdec) {}
set compile(tvprocdec) {}
set compile(typeconstructor) {}
set compile(widgetclass) {}
set compile(hulltype) {}
set compile(localmethods) {}
set compile(delegatesmethods) no
set compile(hashierarchic) no
set compile(components) {}
set compile(typecomponents) {}
set compile(varnames) {}
set compile(typevarnames) {}
set compile(hasconstructor) no
set compile(-hastypedestroy) yes
set compile(-hastypeinfo) yes
set compile(-hastypemethods) yes
set compile(-hasinfo) yes
set compile(-hasinstances) yes
set compile(-simpledispatch) no
set compile(-canreplace) no
set isWidget [string match widget* $which]
set isWidgetAdaptor [string match widgetadaptor $which]
# NEXT, Evaluate the type's definition in the class interpreter.
$compiler eval $body
# NEXT, Add the standard definitions
append compile(defs) \
"\nset %TYPE%::Snit_info(isWidget) $isWidget\n"
append compile(defs) \
"\nset %TYPE%::Snit_info(isWidgetAdaptor) $isWidgetAdaptor\n"
# Indicate whether the type can create instances that replace
# existing commands.
append compile(defs) "\nset %TYPE%::Snit_info(canreplace) $compile(-canreplace)\n"
# Check pragmas for conflict.
if {!$compile(-hastypemethods) && !$compile(-hasinstances)} {
error "$which $type has neither typemethods nor instances"
}
if {$compile(-simpledispatch) && $compile(delegatesmethods)} {
error "$which $type requests -simpledispatch but delegates methods."
}
if {$compile(-simpledispatch) && $compile(hashierarchic)} {
error "$which $type requests -simpledispatch but defines hierarchical methods."
}
# If there are typemethods, define the standard typemethods and
# the nominal type proc. Otherwise define the simple type proc.
if {$compile(-hastypemethods)} {
# Add the info typemethod unless the pragma forbids it.
if {$compile(-hastypeinfo)} {
Comp.statement.delegate typemethod info \
using {::snit::RT.typemethod.info %t}
}
# Add the destroy typemethod unless the pragma forbids it.
if {$compile(-hastypedestroy)} {
Comp.statement.delegate typemethod destroy \
using {::snit::RT.typemethod.destroy %t}
}
# Add the nominal type proc.
append compile(defs) $nominalTypeProc
} else {
# Add the simple type proc.
append compile(defs) $simpleTypeProc
}
# Add standard methods/typemethods that only make sense if the
# type has instances.
if {$compile(-hasinstances)} {
# If we're using simple dispatch, remember that.
if {$compile(-simpledispatch)} {
append compile(defs) "\nset %TYPE%::Snit_info(simpledispatch) 1\n"
}
# Add the info method unless the pragma forbids it.
if {$compile(-hasinfo)} {
if {!$compile(-simpledispatch)} {
Comp.statement.delegate method info \
using {::snit::RT.method.info %t %n %w %s}
} else {
Comp.statement.method info {args} {
eval [linsert $args 0 \
::snit::RT.method.info $type $selfns $win $self]
}
}
}
# Add the option handling stuff if there are any options.
if {$compile(hasoptions)} {
Comp.statement.variable options
if {!$compile(-simpledispatch)} {
Comp.statement.delegate method cget \
using {::snit::RT.method.cget %t %n %w %s}
Comp.statement.delegate method configurelist \
using {::snit::RT.method.configurelist %t %n %w %s}
Comp.statement.delegate method configure \
using {::snit::RT.method.configure %t %n %w %s}
} else {
Comp.statement.method cget {args} {
eval [linsert $args 0 \
::snit::RT.method.cget $type $selfns $win $self]
}
Comp.statement.method configurelist {args} {
eval [linsert $args 0 \
::snit::RT.method.configurelist $type $selfns $win $self]
}
Comp.statement.method configure {args} {
eval [linsert $args 0 \
::snit::RT.method.configure $type $selfns $win $self]
}
}
}
# Add a default constructor, if they haven't already defined one.
# If there are options, it will configure args; otherwise it
# will do nothing.
if {!$compile(hasconstructor)} {
if {$compile(hasoptions)} {
Comp.statement.constructor {args} {
$self configurelist $args
}
} else {
Comp.statement.constructor {} {}
}
}
if {!$isWidget} {
if {!$compile(-simpledispatch)} {
Comp.statement.delegate method destroy \
using {::snit::RT.method.destroy %t %n %w %s}
} else {
Comp.statement.method destroy {args} {
eval [linsert $args 0 \
::snit::RT.method.destroy $type $selfns $win $self]
}
}
Comp.statement.delegate typemethod create \
using {::snit::RT.type.typemethod.create %t}
} else {
Comp.statement.delegate typemethod create \
using {::snit::RT.widget.typemethod.create %t}
}
# Save the list of method names, for -simpledispatch; otherwise,
# save the method info.
if {$compile(-simpledispatch)} {
append compile(defs) \
"\nset %TYPE%::Snit_methods [list $compile(localmethods)]\n"
} else {
append compile(defs) \
"\narray set %TYPE%::Snit_methodInfo [list [array get methodInfo]]\n"
}
} else {
append compile(defs) "\nset %TYPE%::Snit_info(hasinstances) 0\n"
}
# NEXT, compiling the type definition built up a set of information
# about the type's locally defined options; add this information to
# the compiled definition.
Comp.SaveOptionInfo
# NEXT, compiling the type definition built up a set of information
# about the typemethods; save the typemethod info.
append compile(defs) \
"\narray set %TYPE%::Snit_typemethodInfo [list [array get typemethodInfo]]\n"
# NEXT, if this is a widget define the hull component if it isn't
# already defined.
if {$isWidget} {
Comp.DefineComponent hull
}
# NEXT, substitute the compiled definition into the type template
# to get the type definition script.
set defscript [Expand $typeTemplate \
%COMPILEDDEFS% $compile(defs)]
# NEXT, substitute the defined macros into the type definition script.
# This is done as a separate step so that the compile(defs) can
# contain the macros defined below.
set defscript [Expand $defscript \
%TYPE% $type \
%IVARDECS% $compile(ivprocdec) \
%TVARDECS% $compile(tvprocdec) \
%TCONSTBODY% $compile(typeconstructor) \
%INSTANCEVARS% $compile(instancevars) \
%TYPEVARS% $compile(typevars) \
]
array unset compile
return [list $type $defscript]
}
# Information about locally-defined options is accumulated during
# compilation, but not added to the compiled definition--the option
# statement can appear multiple times, so it's easier this way.
# This proc fills in Snit_optionInfo with the accumulated information.
#
# It also computes the option's resource and class names if needed.
#
# Note that the information for delegated options was put in
# Snit_optionInfo during compilation.
proc ::snit::Comp.SaveOptionInfo {} {
variable compile
foreach option $compile(localoptions) {
if {"" == $compile(resource-$option)} {
set compile(resource-$option) [string range $option 1 end]
}
if {"" == $compile(class-$option)} {
set compile(class-$option) [Capitalize $compile(resource-$option)]
}
# NOTE: Don't verify that the validate, configure, and cget
# values name real methods; the methods might be defined outside
# the typedefinition using snit::method.
Mappend compile(defs) {
# Option %OPTION%
lappend %TYPE%::Snit_optionInfo(local) %OPTION%
set %TYPE%::Snit_optionInfo(islocal-%OPTION%) 1
set %TYPE%::Snit_optionInfo(resource-%OPTION%) %RESOURCE%
set %TYPE%::Snit_optionInfo(class-%OPTION%) %CLASS%
set %TYPE%::Snit_optionInfo(default-%OPTION%) %DEFAULT%
set %TYPE%::Snit_optionInfo(validate-%OPTION%) %VALIDATE%
set %TYPE%::Snit_optionInfo(configure-%OPTION%) %CONFIGURE%
set %TYPE%::Snit_optionInfo(cget-%OPTION%) %CGET%
set %TYPE%::Snit_optionInfo(readonly-%OPTION%) %READONLY%
set %TYPE%::Snit_optionInfo(typespec-%OPTION%) %TYPESPEC%
} %OPTION% $option \
%RESOURCE% $compile(resource-$option) \
%CLASS% $compile(class-$option) \
%DEFAULT% [list $compile(-default-$option)] \
%VALIDATE% [list $compile(-validatemethod-$option)] \
%CONFIGURE% [list $compile(-configuremethod-$option)] \
%CGET% [list $compile(-cgetmethod-$option)] \
%READONLY% $compile(-readonly-$option) \
%TYPESPEC% [list $compile(-type-$option)]
}
}
# Evaluates a compiled type definition, thus making the type available.
proc ::snit::Comp.Define {compResult} {
# The compilation result is a list containing the fully qualified
# type name and a script to evaluate to define the type.
set type [lindex $compResult 0]
set defscript [lindex $compResult 1]
# Execute the type definition script.
# Consider using namespace eval %TYPE%. See if it's faster.
if {[catch {eval $defscript} result]} {
namespace delete $type
catch {rename $type ""}
error $result
}
return $type
}
# Sets pragma options which control how the type is defined.
proc ::snit::Comp.statement.pragma {args} {
variable compile
set errRoot "Error in \"pragma...\""
foreach {opt val} $args {
switch -exact -- $opt {
-hastypeinfo -
-hastypedestroy -
-hastypemethods -
-hasinstances -
-simpledispatch -
-hasinfo -
-canreplace {
if {![string is boolean -strict $val]} {
error "$errRoot, \"$opt\" requires a boolean value"
}
set compile($opt) $val
}
default {
error "$errRoot, unknown pragma"
}
}
}
}
# Defines a widget's option class name.
# This statement is only available for snit::widgets,
# not for snit::types or snit::widgetadaptors.
proc ::snit::Comp.statement.widgetclass {name} {
variable compile
# First, widgetclass can only be set for true widgets
if {"widget" != $compile(which)} {
error "widgetclass cannot be set for snit::$compile(which)s"
}
# Next, validate the option name. We'll require that it begin
# with an uppercase letter.
set initial [string index $name 0]
if {![string is upper $initial]} {
error "widgetclass \"$name\" does not begin with an uppercase letter"
}
if {"" != $compile(widgetclass)} {
error "too many widgetclass statements"
}
# Next, save it.
Mappend compile(defs) {
set %TYPE%::Snit_info(widgetclass) %WIDGETCLASS%
} %WIDGETCLASS% [list $name]
set compile(widgetclass) $name
}
# Defines a widget's hull type.
# This statement is only available for snit::widgets,
# not for snit::types or snit::widgetadaptors.
proc ::snit::Comp.statement.hulltype {name} {
variable compile
variable hulltypes
# First, hulltype can only be set for true widgets
if {"widget" != $compile(which)} {
error "hulltype cannot be set for snit::$compile(which)s"
}
# Next, it must be one of the valid hulltypes (frame, toplevel, ...)
if {[lsearch -exact $hulltypes [string trimleft $name :]] == -1} {
error "invalid hulltype \"$name\", should be one of\
[join $hulltypes {, }]"
}
if {"" != $compile(hulltype)} {
error "too many hulltype statements"
}
# Next, save it.
Mappend compile(defs) {
set %TYPE%::Snit_info(hulltype) %HULLTYPE%
} %HULLTYPE% $name
set compile(hulltype) $name
}
# Defines a constructor.
proc ::snit::Comp.statement.constructor {arglist body} {
variable compile
CheckArgs "constructor" $arglist
# Next, add a magic reference to self.
set arglist [concat type selfns win self $arglist]
# Next, add variable declarations to body:
set body "%TVARDECS%%IVARDECS%\n$body"
set compile(hasconstructor) yes
append compile(defs) "proc %TYPE%::Snit_constructor [list $arglist] [list $body]\n"
}
# Defines a destructor.
proc ::snit::Comp.statement.destructor {body} {
variable compile
# Next, add variable declarations to body:
set body "%TVARDECS%%IVARDECS%\n$body"
append compile(defs) "proc %TYPE%::Snit_destructor {type selfns win self} [list $body]\n\n"
}
# Defines a type option. The option value can be a triple, specifying
# the option's -name, resource name, and class name.
proc ::snit::Comp.statement.option {optionDef args} {
variable compile
# First, get the three option names.
set option [lindex $optionDef 0]
set resourceName [lindex $optionDef 1]
set className [lindex $optionDef 2]
set errRoot "Error in \"option [list $optionDef]...\""
# Next, validate the option name.
if {![Comp.OptionNameIsValid $option]} {
error "$errRoot, badly named option \"$option\""
}
if {[Contains $option $compile(delegatedoptions)]} {
error "$errRoot, cannot define \"$option\" locally, it has been delegated"
}
if {![Contains $option $compile(localoptions)]} {
# Remember that we've seen this one.
set compile(hasoptions) yes
lappend compile(localoptions) $option
# Initialize compilation info for this option.
set compile(resource-$option) ""
set compile(class-$option) ""
set compile(-default-$option) ""
set compile(-validatemethod-$option) ""
set compile(-configuremethod-$option) ""
set compile(-cgetmethod-$option) ""
set compile(-readonly-$option) 0
set compile(-type-$option) ""
}
# NEXT, see if we have a resource name. If so, make sure it
# isn't being redefined differently.
if {"" != $resourceName} {
if {"" == $compile(resource-$option)} {
# If it's undefined, just save the value.
set compile(resource-$option) $resourceName
} elseif {![string equal $resourceName $compile(resource-$option)]} {
# It's been redefined differently.
error "$errRoot, resource name redefined from \"$compile(resource-$option)\" to \"$resourceName\""
}
}
# NEXT, see if we have a class name. If so, make sure it
# isn't being redefined differently.
if {"" != $className} {
if {"" == $compile(class-$option)} {
# If it's undefined, just save the value.
set compile(class-$option) $className
} elseif {![string equal $className $compile(class-$option)]} {
# It's been redefined differently.
error "$errRoot, class name redefined from \"$compile(class-$option)\" to \"$className\""
}
}
# NEXT, handle the args; it's not an error to redefine these.
if {[llength $args] == 1} {
set compile(-default-$option) [lindex $args 0]
} else {
foreach {optopt val} $args {
switch -exact -- $optopt {
-default -
-validatemethod -
-configuremethod -
-cgetmethod {
set compile($optopt-$option) $val
}
-type {
set compile($optopt-$option) $val
if {[llength $val] == 1} {
# The type spec *is* the validation object
append compile(defs) \
"\nset %TYPE%::Snit_optionInfo(typeobj-$option) [list $val]\n"
} else {
# Compilation the creation of the validation object
set cmd [linsert $val 1 %TYPE%::Snit_TypeObj_%AUTO%]
append compile(defs) \
"\nset %TYPE%::Snit_optionInfo(typeobj-$option) \[$cmd\]\n"
}
}
-readonly {
if {![string is boolean -strict $val]} {
error "$errRoot, -readonly requires a boolean, got \"$val\""
}
set compile($optopt-$option) $val
}
default {
error "$errRoot, unknown option definition option \"$optopt\""
}
}
}
}
}
# 1 if the option name is valid, 0 otherwise.
proc ::snit::Comp.OptionNameIsValid {option} {
if {![string match {-*} $option] || [string match {*[A-Z ]*} $option]} {
return 0
}
return 1
}
# Defines an option's cget handler
proc ::snit::Comp.statement.oncget {option body} {
variable compile
set errRoot "Error in \"oncget $option...\""
if {[lsearch -exact $compile(delegatedoptions) $option] != -1} {
return -code error "$errRoot, option \"$option\" is delegated"
}
if {[lsearch -exact $compile(localoptions) $option] == -1} {
return -code error "$errRoot, option \"$option\" unknown"
}
Comp.statement.method _cget$option {_option} $body
Comp.statement.option $option -cgetmethod _cget$option
}
# Defines an option's configure handler.
proc ::snit::Comp.statement.onconfigure {option arglist body} {
variable compile
if {[lsearch -exact $compile(delegatedoptions) $option] != -1} {
return -code error "onconfigure $option: option \"$option\" is delegated"
}
if {[lsearch -exact $compile(localoptions) $option] == -1} {
return -code error "onconfigure $option: option \"$option\" unknown"
}
if {[llength $arglist] != 1} {
error \
"onconfigure $option handler should have one argument, got \"$arglist\""
}
CheckArgs "onconfigure $option" $arglist
# Next, add a magic reference to the option name
set arglist [concat _option $arglist]
Comp.statement.method _configure$option $arglist $body
Comp.statement.option $option -configuremethod _configure$option
}
# Defines an instance method.
proc ::snit::Comp.statement.method {method arglist body} {
variable compile
variable methodInfo
# FIRST, check the method name against previously defined
# methods.
Comp.CheckMethodName $method 0 ::snit::methodInfo \
"Error in \"method [list $method]...\""
if {[llength $method] > 1} {
set compile(hashierarchic) yes
}
# Remeber this method
lappend compile(localmethods) $method
CheckArgs "method [list $method]" $arglist
# Next, add magic references to type and self.
set arglist [concat type selfns win self $arglist]
# Next, add variable declarations to body:
set body "%TVARDECS%%IVARDECS%\n# END snit method prolog\n$body"
# Next, save the definition script.
if {[llength $method] == 1} {
set methodInfo($method) {0 "%t::Snit_method%m %t %n %w %s" ""}
Mappend compile(defs) {
proc %TYPE%::Snit_method%METHOD% %ARGLIST% %BODY%
} %METHOD% $method %ARGLIST% [list $arglist] %BODY% [list $body]
} else {
set methodInfo($method) {0 "%t::Snit_hmethod%j %t %n %w %s" ""}
Mappend compile(defs) {
proc %TYPE%::Snit_hmethod%JMETHOD% %ARGLIST% %BODY%
} %JMETHOD% [join $method _] %ARGLIST% [list $arglist] \
%BODY% [list $body]
}
}
# Check for name collisions; save prefix information.
#
# method The name of the method or typemethod.
# delFlag 1 if delegated, 0 otherwise.
# infoVar The fully qualified name of the array containing
# information about the defined methods.
# errRoot The root string for any error messages.
proc ::snit::Comp.CheckMethodName {method delFlag infoVar errRoot} {
upvar $infoVar methodInfo
# FIRST, make sure the method name is a valid Tcl list.
if {[catch {lindex $method 0}]} {
error "$errRoot, the name \"$method\" must have list syntax."
}
# NEXT, check whether we can define it.
if {![catch {set methodInfo($method)} data]} {
# We can't redefine methods with submethods.
if {[lindex $data 0] == 1} {
error "$errRoot, \"$method\" has submethods."
}
# You can't delegate a method that's defined locally,
# and you can't define a method locally if it's been delegated.
if {$delFlag && "" == [lindex $data 2]} {
error "$errRoot, \"$method\" has been defined locally."
} elseif {!$delFlag && "" != [lindex $data 2]} {
error "$errRoot, \"$method\" has been delegated"
}
}
# Handle hierarchical case.
if {[llength $method] > 1} {
set prefix {}
set tokens $method
while {[llength $tokens] > 1} {
lappend prefix [lindex $tokens 0]
set tokens [lrange $tokens 1 end]
if {![catch {set methodInfo($prefix)} result]} {
# Prefix is known. If it's not a prefix, throw an
# error.
if {[lindex $result 0] == 0} {
error "$errRoot, \"$prefix\" has no submethods."
}
}
set methodInfo($prefix) [list 1]
}
}
}
# Defines a typemethod method.
proc ::snit::Comp.statement.typemethod {method arglist body} {
variable compile
variable typemethodInfo
# FIRST, check the typemethod name against previously defined
# typemethods.
Comp.CheckMethodName $method 0 ::snit::typemethodInfo \
"Error in \"typemethod [list $method]...\""
CheckArgs "typemethod $method" $arglist
# First, add magic reference to type.
set arglist [concat type $arglist]
# Next, add typevariable declarations to body:
set body "%TVARDECS%\n# END snit method prolog\n$body"
# Next, save the definition script
if {[llength $method] == 1} {
set typemethodInfo($method) {0 "%t::Snit_typemethod%m %t" ""}
Mappend compile(defs) {
proc %TYPE%::Snit_typemethod%METHOD% %ARGLIST% %BODY%
} %METHOD% $method %ARGLIST% [list $arglist] %BODY% [list $body]
} else {
set typemethodInfo($method) {0 "%t::Snit_htypemethod%j %t" ""}
Mappend compile(defs) {
proc %TYPE%::Snit_htypemethod%JMETHOD% %ARGLIST% %BODY%
} %JMETHOD% [join $method _] \
%ARGLIST% [list $arglist] %BODY% [list $body]
}
}
# Defines a type constructor.
proc ::snit::Comp.statement.typeconstructor {body} {
variable compile
if {"" != $compile(typeconstructor)} {
error "too many typeconstructors"
}
set compile(typeconstructor) $body
}
# Defines a static proc in the type's namespace.
proc ::snit::Comp.statement.proc {proc arglist body} {
variable compile
# If "ns" is defined, the proc can see instance variables.
if {[lsearch -exact $arglist selfns] != -1} {
# Next, add instance variable declarations to body:
set body "%IVARDECS%\n$body"
}
# The proc can always see typevariables.
set body "%TVARDECS%\n$body"
append compile(defs) "
# Proc $proc
proc [list %TYPE%::$proc $arglist $body]
"
}
# Defines a static variable in the type's namespace.
proc ::snit::Comp.statement.typevariable {name args} {
variable compile
set errRoot "Error in \"typevariable $name...\""
set len [llength $args]
if {$len > 2 ||
($len == 2 && "-array" != [lindex $args 0])} {
error "$errRoot, too many initializers"
}
if {[lsearch -exact $compile(varnames) $name] != -1} {
error "$errRoot, \"$name\" is already an instance variable"
}
lappend compile(typevarnames) $name
if {$len == 1} {
append compile(typevars) \
"\n\t [list ::variable $name [lindex $args 0]]"
} elseif {$len == 2} {
append compile(typevars) \
"\n\t [list ::variable $name]"
append compile(typevars) \
"\n\t [list array set $name [lindex $args 1]]"
} else {
append compile(typevars) \
"\n\t [list ::variable $name]"
}
append compile(tvprocdec) "\n\t typevariable ${name}"
}
# Defines an instance variable; the definition will go in the
# type's create typemethod.
proc ::snit::Comp.statement.variable {name args} {
variable compile
set errRoot "Error in \"variable $name...\""
set len [llength $args]
if {$len > 2 ||
($len == 2 && "-array" != [lindex $args 0])} {
error "$errRoot, too many initializers"
}
if {[lsearch -exact $compile(typevarnames) $name] != -1} {
error "$errRoot, \"$name\" is already a typevariable"
}
lappend compile(varnames) $name
if {$len == 1} {
append compile(instancevars) \
"\nset \${selfns}::$name [list [lindex $args 0]]\n"
} elseif {$len == 2} {
append compile(instancevars) \
"\narray set \${selfns}::$name [list [lindex $args 1]]\n"
}
append compile(ivprocdec) "\n\t "
Mappend compile(ivprocdec) {::variable ${selfns}::%N} %N $name
}
# Defines a typecomponent, and handles component options.
#
# component The logical name of the delegate
# args options.
proc ::snit::Comp.statement.typecomponent {component args} {
variable compile
set errRoot "Error in \"typecomponent $component...\""
# FIRST, define the component
Comp.DefineTypecomponent $component $errRoot
# NEXT, handle the options.
set publicMethod ""
set inheritFlag 0
foreach {opt val} $args {
switch -exact -- $opt {
-public {
set publicMethod $val
}
-inherit {
set inheritFlag $val
if {![string is boolean $inheritFlag]} {
error "typecomponent $component -inherit: expected boolean value, got \"$val\""
}
}
default {
error "typecomponent $component: Invalid option \"$opt\""
}
}
}
# NEXT, if -public specified, define the method.
if {"" != $publicMethod} {
Comp.statement.delegate typemethod [list $publicMethod *] to $component
}
# NEXT, if "-inherit 1" is specified, delegate typemethod * to
# this component.
if {$inheritFlag} {
Comp.statement.delegate typemethod "*" to $component
}
}
# Defines a name to be a typecomponent
#
# The name becomes a typevariable; in addition, it gets a
# write trace so that when it is set, all of the component mechanisms
# get updated.
#
# component The component name
proc ::snit::Comp.DefineTypecomponent {component {errRoot "Error"}} {
variable compile
if {[lsearch -exact $compile(varnames) $component] != -1} {
error "$errRoot, \"$component\" is already an instance variable"
}
if {[lsearch -exact $compile(typecomponents) $component] == -1} {
# Remember we've done this.
lappend compile(typecomponents) $component
# Make it a type variable with no initial value
Comp.statement.typevariable $component ""
# Add a write trace to do the component thing.
Mappend compile(typevars) {
trace variable %COMP% w \
[list ::snit::RT.TypecomponentTrace [list %TYPE%] %COMP%]
} %TYPE% $compile(type) %COMP% $component
}
}
# Defines a component, and handles component options.
#
# component The logical name of the delegate
# args options.
#
# TBD: Ideally, it should be possible to call this statement multiple
# times, possibly changing the option values. To do that, I'd need
# to cache the option values and not act on them until *after* I'd
# read the entire type definition.
proc ::snit::Comp.statement.component {component args} {
variable compile
set errRoot "Error in \"component $component...\""
# FIRST, define the component
Comp.DefineComponent $component $errRoot
# NEXT, handle the options.
set publicMethod ""
set inheritFlag 0
foreach {opt val} $args {
switch -exact -- $opt {
-public {
set publicMethod $val
}
-inherit {
set inheritFlag $val
if {![string is boolean $inheritFlag]} {
error "component $component -inherit: expected boolean value, got \"$val\""
}
}
default {
error "component $component: Invalid option \"$opt\""
}
}
}
# NEXT, if -public specified, define the method.
if {"" != $publicMethod} {
Comp.statement.delegate method [list $publicMethod *] to $component
}
# NEXT, if -inherit is specified, delegate method/option * to
# this component.
if {$inheritFlag} {
Comp.statement.delegate method "*" to $component
Comp.statement.delegate option "*" to $component
}
}
# Defines a name to be a component
#
# The name becomes an instance variable; in addition, it gets a
# write trace so that when it is set, all of the component mechanisms
# get updated.
#
# component The component name
proc ::snit::Comp.DefineComponent {component {errRoot "Error"}} {
variable compile
if {[lsearch -exact $compile(typevarnames) $component] != -1} {
error "$errRoot, \"$component\" is already a typevariable"
}
if {[lsearch -exact $compile(components) $component] == -1} {
# Remember we've done this.
lappend compile(components) $component
# Make it an instance variable with no initial value
Comp.statement.variable $component ""
# Add a write trace to do the component thing.
Mappend compile(instancevars) {
trace variable ${selfns}::%COMP% w \
[list ::snit::RT.ComponentTrace [list %TYPE%] $selfns %COMP%]
} %TYPE% $compile(type) %COMP% $component
}
}
# Creates a delegated method, typemethod, or option.
proc ::snit::Comp.statement.delegate {what name args} {
# FIRST, dispatch to correct handler.
switch $what {
typemethod { Comp.DelegatedTypemethod $name $args }
method { Comp.DelegatedMethod $name $args }
option { Comp.DelegatedOption $name $args }
default {
error "Error in \"delegate $what $name...\", \"$what\"?"
}
}
if {([llength $args] % 2) != 0} {
error "Error in \"delegate $what $name...\", invalid syntax"
}
}
# Creates a delegated typemethod delegating it to a particular
# typecomponent or an arbitrary command.
#
# method The name of the method
# arglist Delegation options
proc ::snit::Comp.DelegatedTypemethod {method arglist} {
variable compile
variable typemethodInfo
set errRoot "Error in \"delegate typemethod [list $method]...\""
# Next, parse the delegation options.
set component ""
set target ""
set exceptions {}
set pattern ""
set methodTail [lindex $method end]
foreach {opt value} $arglist {
switch -exact $opt {
to { set component $value }
as { set target $value }
except { set exceptions $value }
using { set pattern $value }
default {
error "$errRoot, unknown delegation option \"$opt\""
}
}
}
if {"" == $component && "" == $pattern} {
error "$errRoot, missing \"to\""
}
if {"*" == $methodTail && "" != $target} {
error "$errRoot, cannot specify \"as\" with \"*\""
}
if {"*" != $methodTail && "" != $exceptions} {
error "$errRoot, can only specify \"except\" with \"*\""
}
if {"" != $pattern && "" != $target} {
error "$errRoot, cannot specify both \"as\" and \"using\""
}
foreach token [lrange $method 1 end-1] {
if {"*" == $token} {
error "$errRoot, \"*\" must be the last token."
}
}
# NEXT, define the component
if {"" != $component} {
Comp.DefineTypecomponent $component $errRoot
}
# NEXT, define the pattern.
if {"" == $pattern} {
if {"*" == $methodTail} {
set pattern "%c %m"
} elseif {"" != $target} {
set pattern "%c $target"
} else {
set pattern "%c %m"
}
}
# Make sure the pattern is a valid list.
if {[catch {lindex $pattern 0} result]} {
error "$errRoot, the using pattern, \"$pattern\", is not a valid list"
}
# NEXT, check the method name against previously defined
# methods.
Comp.CheckMethodName $method 1 ::snit::typemethodInfo $errRoot
set typemethodInfo($method) [list 0 $pattern $component]
if {[string equal $methodTail "*"]} {
Mappend compile(defs) {
set %TYPE%::Snit_info(excepttypemethods) %EXCEPT%
} %EXCEPT% [list $exceptions]
}
}
# Creates a delegated method delegating it to a particular
# component or command.
#
# method The name of the method
# arglist Delegation options.
proc ::snit::Comp.DelegatedMethod {method arglist} {
variable compile
variable methodInfo
set errRoot "Error in \"delegate method [list $method]...\""
# Next, parse the delegation options.
set component ""
set target ""
set exceptions {}
set pattern ""
set methodTail [lindex $method end]
foreach {opt value} $arglist {
switch -exact $opt {
to { set component $value }
as { set target $value }
except { set exceptions $value }
using { set pattern $value }
default {
error "$errRoot, unknown delegation option \"$opt\""
}
}
}
if {"" == $component && "" == $pattern} {
error "$errRoot, missing \"to\""
}
if {"*" == $methodTail && "" != $target} {
error "$errRoot, cannot specify \"as\" with \"*\""
}
if {"*" != $methodTail && "" != $exceptions} {
error "$errRoot, can only specify \"except\" with \"*\""
}
if {"" != $pattern && "" != $target} {
error "$errRoot, cannot specify both \"as\" and \"using\""
}
foreach token [lrange $method 1 end-1] {
if {"*" == $token} {
error "$errRoot, \"*\" must be the last token."
}
}
# NEXT, we delegate some methods
set compile(delegatesmethods) yes
# NEXT, define the component. Allow typecomponents.
if {"" != $component} {
if {[lsearch -exact $compile(typecomponents) $component] == -1} {
Comp.DefineComponent $component $errRoot
}
}
# NEXT, define the pattern.
if {"" == $pattern} {
if {"*" == $methodTail} {
set pattern "%c %m"
} elseif {"" != $target} {
set pattern "%c $target"
} else {
set pattern "%c %m"
}
}
# Make sure the pattern is a valid list.
if {[catch {lindex $pattern 0} result]} {
error "$errRoot, the using pattern, \"$pattern\", is not a valid list"
}
# NEXT, check the method name against previously defined
# methods.
Comp.CheckMethodName $method 1 ::snit::methodInfo $errRoot
# NEXT, save the method info.
set methodInfo($method) [list 0 $pattern $component]
if {[string equal $methodTail "*"]} {
Mappend compile(defs) {
set %TYPE%::Snit_info(exceptmethods) %EXCEPT%
} %EXCEPT% [list $exceptions]
}
}
# Creates a delegated option, delegating it to a particular
# component and, optionally, to a particular option of that
# component.
#
# optionDef The option definition
# args definition arguments.
proc ::snit::Comp.DelegatedOption {optionDef arglist} {
variable compile
# First, get the three option names.
set option [lindex $optionDef 0]
set resourceName [lindex $optionDef 1]
set className [lindex $optionDef 2]
set errRoot "Error in \"delegate option [list $optionDef]...\""
# Next, parse the delegation options.
set component ""
set target ""
set exceptions {}
foreach {opt value} $arglist {
switch -exact $opt {
to { set component $value }
as { set target $value }
except { set exceptions $value }
default {
error "$errRoot, unknown delegation option \"$opt\""
}
}
}
if {"" == $component} {
error "$errRoot, missing \"to\""
}
if {"*" == $option && "" != $target} {
error "$errRoot, cannot specify \"as\" with \"delegate option *\""
}
if {"*" != $option && "" != $exceptions} {
error "$errRoot, can only specify \"except\" with \"delegate option *\""
}
# Next, validate the option name
if {"*" != $option} {
if {![Comp.OptionNameIsValid $option]} {
error "$errRoot, badly named option \"$option\""
}
}
if {[Contains $option $compile(localoptions)]} {
error "$errRoot, \"$option\" has been defined locally"
}
if {[Contains $option $compile(delegatedoptions)]} {
error "$errRoot, \"$option\" is multiply delegated"
}
# NEXT, define the component
Comp.DefineComponent $component $errRoot
# Next, define the target option, if not specified.
if {![string equal $option "*"] &&
[string equal $target ""]} {
set target $option
}
# NEXT, save the delegation data.
set compile(hasoptions) yes
if {![string equal $option "*"]} {
lappend compile(delegatedoptions) $option
# Next, compute the resource and class names, if they aren't
# already defined.
if {"" == $resourceName} {
set resourceName [string range $option 1 end]
}
if {"" == $className} {
set className [Capitalize $resourceName]
}
Mappend compile(defs) {
set %TYPE%::Snit_optionInfo(islocal-%OPTION%) 0
set %TYPE%::Snit_optionInfo(resource-%OPTION%) %RES%
set %TYPE%::Snit_optionInfo(class-%OPTION%) %CLASS%
lappend %TYPE%::Snit_optionInfo(delegated) %OPTION%
set %TYPE%::Snit_optionInfo(target-%OPTION%) [list %COMP% %TARGET%]
lappend %TYPE%::Snit_optionInfo(delegated-%COMP%) %OPTION%
} %OPTION% $option \
%COMP% $component \
%TARGET% $target \
%RES% $resourceName \
%CLASS% $className
} else {
Mappend compile(defs) {
set %TYPE%::Snit_optionInfo(starcomp) %COMP%
set %TYPE%::Snit_optionInfo(except) %EXCEPT%
} %COMP% $component %EXCEPT% [list $exceptions]
}
}
# Exposes a component, effectively making the component's command an
# instance method.
#
# component The logical name of the delegate
# "as" sugar; if not "", must be "as"
# methodname The desired method name for the component's command, or ""
proc ::snit::Comp.statement.expose {component {"as" ""} {methodname ""}} {
variable compile
# FIRST, define the component
Comp.DefineComponent $component
# NEXT, define the method just as though it were in the type
# definition.
if {[string equal $methodname ""]} {
set methodname $component
}
Comp.statement.method $methodname args [Expand {
if {[llength $args] == 0} {
return $%COMPONENT%
}
if {[string equal $%COMPONENT% ""]} {
error "undefined component \"%COMPONENT%\""
}
set cmd [linsert $args 0 $%COMPONENT%]
return [uplevel 1 $cmd]
} %COMPONENT% $component]
}
#-----------------------------------------------------------------------
# Public commands
# Compile a type definition, and return the results as a list of two
# items: the fully-qualified type name, and a script that will define
# the type when executed.
#
# which type, widget, or widgetadaptor
# type the type name
# body the type definition
proc ::snit::compile {which type body} {
return [Comp.Compile $which $type $body]
}
proc ::snit::type {type body} {
return [Comp.Define [Comp.Compile type $type $body]]
}
proc ::snit::widget {type body} {
return [Comp.Define [Comp.Compile widget $type $body]]
}
proc ::snit::widgetadaptor {type body} {
return [Comp.Define [Comp.Compile widgetadaptor $type $body]]
}
proc ::snit::typemethod {type method arglist body} {
# Make sure the type exists.
if {![info exists ${type}::Snit_info]} {
error "no such type: \"$type\""
}
upvar ${type}::Snit_info Snit_info
upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo
# FIRST, check the typemethod name against previously defined
# typemethods.
Comp.CheckMethodName $method 0 ${type}::Snit_typemethodInfo \
"Cannot define \"$method\""
# NEXT, check the arguments
CheckArgs "snit::typemethod $type $method" $arglist
# Next, add magic reference to type.
set arglist [concat type $arglist]
# Next, add typevariable declarations to body:
set body "$Snit_info(tvardecs)\n$body"
# Next, define it.
if {[llength $method] == 1} {
set Snit_typemethodInfo($method) {0 "%t::Snit_typemethod%m %t" ""}
uplevel 1 [list proc ${type}::Snit_typemethod$method $arglist $body]
} else {
set Snit_typemethodInfo($method) {0 "%t::Snit_htypemethod%j %t" ""}
set suffix [join $method _]
uplevel 1 [list proc ${type}::Snit_htypemethod$suffix $arglist $body]
}
}
proc ::snit::method {type method arglist body} {
# Make sure the type exists.
if {![info exists ${type}::Snit_info]} {
error "no such type: \"$type\""
}
upvar ${type}::Snit_methodInfo Snit_methodInfo
upvar ${type}::Snit_info Snit_info
# FIRST, check the method name against previously defined
# methods.
Comp.CheckMethodName $method 0 ${type}::Snit_methodInfo \
"Cannot define \"$method\""
# NEXT, check the arguments
CheckArgs "snit::method $type $method" $arglist
# Next, add magic references to type and self.
set arglist [concat type selfns win self $arglist]
# Next, add variable declarations to body:
set body "$Snit_info(tvardecs)$Snit_info(ivardecs)\n$body"
# Next, define it.
if {[llength $method] == 1} {
set Snit_methodInfo($method) {0 "%t::Snit_method%m %t %n %w %s" ""}
uplevel 1 [list proc ${type}::Snit_method$method $arglist $body]
} else {
set Snit_methodInfo($method) {0 "%t::Snit_hmethod%j %t %n %w %s" ""}
set suffix [join $method _]
uplevel 1 [list proc ${type}::Snit_hmethod$suffix $arglist $body]
}
}
# Defines a proc within the compiler; this proc can call other
# type definition statements, and thus can be used for meta-programming.
proc ::snit::macro {name arglist body} {
variable compiler
variable reservedwords
# FIRST, make sure the compiler is defined.
Comp.Init
# NEXT, check the macro name against the reserved words
if {[lsearch -exact $reservedwords $name] != -1} {
error "invalid macro name \"$name\""
}
# NEXT, see if the name has a namespace; if it does, define the
# namespace.
set ns [namespace qualifiers $name]
if {"" != $ns} {
$compiler eval "namespace eval $ns {}"
}
# NEXT, define the macro
$compiler eval [list _proc $name $arglist $body]
}
#-----------------------------------------------------------------------
# Utility Functions
#
# These are utility functions used while compiling Snit types.
# Builds a template from a tagged list of text blocks, then substitutes
# all symbols in the mapTable, returning the expanded template.
proc ::snit::Expand {template args} {
return [string map $args $template]
}
# Expands a template and appends it to a variable.
proc ::snit::Mappend {varname template args} {
upvar $varname myvar
append myvar [string map $args $template]
}
# Checks argument list against reserved args
proc ::snit::CheckArgs {which arglist} {
variable reservedArgs
foreach name $reservedArgs {
if {[Contains $name $arglist]} {
error "$which's arglist may not contain \"$name\" explicitly"
}
}
}
# Returns 1 if a value is in a list, and 0 otherwise.
proc ::snit::Contains {value list} {
if {[lsearch -exact $list $value] != -1} {
return 1
} else {
return 0
}
}
# Capitalizes the first letter of a string.
proc ::snit::Capitalize {text} {
set first [string index $text 0]
set rest [string range $text 1 end]
return "[string toupper $first]$rest"
}
# Converts an arbitrary white-space-delimited string into a list
# by splitting on white-space and deleting empty tokens.
proc ::snit::Listify {str} {
set result {}
foreach token [split [string trim $str]] {
if {[string length $token] > 0} {
lappend result $token
}
}
return $result
}
#=======================================================================
# Snit Runtime Library
#
# These are procs used by Snit types and widgets at runtime.
#-----------------------------------------------------------------------
# Object Creation
# Creates a new instance of the snit::type given its name and the args.
#
# type The snit::type
# name The instance name
# args Args to pass to the constructor
proc ::snit::RT.type.typemethod.create {type name args} {
variable ${type}::Snit_info
variable ${type}::Snit_optionInfo
# FIRST, qualify the name.
if {![string match "::*" $name]} {
# Get caller's namespace;
# append :: if not global namespace.
set ns [uplevel 1 [list namespace current]]
if {"::" != $ns} {
append ns "::"
}
set name "$ns$name"
}
# NEXT, if %AUTO% appears in the name, generate a unique
# command name. Otherwise, ensure that the name isn't in use.
if {[string match "*%AUTO%*" $name]} {
set name [::snit::RT.UniqueName Snit_info(counter) $type $name]
} elseif {$Snit_info(canreplace) && [llength [info commands $name]]} {
#kmg-tcl83
#
# Had to add this elseif branch to pass test rename-1.5
#
# Allowed to replace so must first destroy the prior instance
$name destroy
} elseif {!$Snit_info(canreplace) && [llength [info commands $name]]} {
error "command \"$name\" already exists"
}
# NEXT, create the instance's namespace.
set selfns \
[::snit::RT.UniqueInstanceNamespace Snit_info(counter) $type]
namespace eval $selfns {}
# NEXT, install the dispatcher
RT.MakeInstanceCommand $type $selfns $name
# Initialize the options to their defaults.
upvar ${selfns}::options options
foreach opt $Snit_optionInfo(local) {
set options($opt) $Snit_optionInfo(default-$opt)
}
# Initialize the instance vars to their defaults.
# selfns must be defined, as it is used implicitly.
${type}::Snit_instanceVars $selfns
# Execute the type's constructor.
set errcode [catch {
RT.ConstructInstance $type $selfns $name $args
} result]
if {$errcode} {
global errorInfo
global errorCode
set theInfo $errorInfo
set theCode $errorCode
::snit::RT.DestroyObject $type $selfns $name
error "Error in constructor: $result" $theInfo $theCode
}
# NEXT, return the object's name.
return $name
}
# Creates a new instance of the snit::widget or snit::widgetadaptor
# given its name and the args.
#
# type The snit::widget or snit::widgetadaptor
# name The instance name
# args Args to pass to the constructor
proc ::snit::RT.widget.typemethod.create {type name args} {
variable ${type}::Snit_info
variable ${type}::Snit_optionInfo
# FIRST, if %AUTO% appears in the name, generate a unique
# command name.
if {[string match "*%AUTO%*" $name]} {
set name [::snit::RT.UniqueName Snit_info(counter) $type $name]
}
# NEXT, create the instance's namespace.
set selfns \
[::snit::RT.UniqueInstanceNamespace Snit_info(counter) $type]
namespace eval $selfns { }
# NEXT, Initialize the widget's own options to their defaults.
upvar ${selfns}::options options
foreach opt $Snit_optionInfo(local) {
set options($opt) $Snit_optionInfo(default-$opt)
}
# Initialize the instance vars to their defaults.
${type}::Snit_instanceVars $selfns
# NEXT, if this is a normal widget (not a widget adaptor) then create a
# frame as its hull. We set the frame's -class to the user's widgetclass,
# or, if none, search for -class in the args list, otherwise default to
# the basename of the $type with an initial upper case letter.
if {!$Snit_info(isWidgetAdaptor)} {
# FIRST, determine the class name
set wclass $Snit_info(widgetclass)
if {$Snit_info(widgetclass) == ""} {
set idx [lsearch -exact $args -class]
if {$idx >= 0 && ($idx%2 == 0)} {
# -class exists and is in the -option position
set wclass [lindex $args [expr {$idx+1}]]
set args [lreplace $args $idx [expr {$idx+1}]]
} else {
set wclass [::snit::Capitalize [namespace tail $type]]
}
}
# NEXT, create the widget
set self $name
package require Tk
${type}::installhull using $Snit_info(hulltype) -class $wclass
# NEXT, let's query the option database for our
# widget, now that we know that it exists.
foreach opt $Snit_optionInfo(local) {
set dbval [RT.OptionDbGet $type $name $opt]
if {"" != $dbval} {
set options($opt) $dbval
}
}
}
# Execute the type's constructor, and verify that it
# has a hull.
set errcode [catch {
RT.ConstructInstance $type $selfns $name $args
::snit::RT.Component $type $selfns hull
# Prepare to call the object's destructor when the
# event is received. Use a Snit-specific bindtag
# so that the widget name's tag is unencumbered.
bind Snit$type$name [::snit::Expand {
::snit::RT.DestroyObject %TYPE% %NS% %W
} %TYPE% $type %NS% $selfns]
# Insert the bindtag into the list of bindtags right
# after the widget name.
set taglist [bindtags $name]
set ndx [lsearch -exact $taglist $name]
incr ndx
bindtags $name [linsert $taglist $ndx Snit$type$name]
} result]
if {$errcode} {
global errorInfo
global errorCode
set theInfo $errorInfo
set theCode $errorCode
::snit::RT.DestroyObject $type $selfns $name
error "Error in constructor: $result" $theInfo $theCode
}
# NEXT, return the object's name.
return $name
}
# RT.MakeInstanceCommand type selfns instance
#
# type The object type
# selfns The instance namespace
# instance The instance name
#
# Creates the instance proc.
proc ::snit::RT.MakeInstanceCommand {type selfns instance} {
variable ${type}::Snit_info
# FIRST, remember the instance name. The Snit_instance variable
# allows the instance to figure out its current name given the
# instance namespace.
upvar ${selfns}::Snit_instance Snit_instance
set Snit_instance $instance
# NEXT, qualify the proc name if it's a widget.
if {$Snit_info(isWidget)} {
set procname ::$instance
} else {
set procname $instance
}
# NEXT, install the new proc
if {!$Snit_info(simpledispatch)} {
set instanceProc $::snit::nominalInstanceProc
} else {
set instanceProc $::snit::simpleInstanceProc
}
proc $procname {method args} \
[string map \
[list %SELFNS% $selfns %WIN% $instance %TYPE% $type] \
$instanceProc]
#kmg-tcl83
# NEXT, add the trace.
::snit83::traceAddCommand $procname {rename delete} \
[list ::snit::RT.InstanceTrace $type $selfns $instance]
}
# This proc is called when the instance command is renamed.
# If op is delete, then new will always be "", so op is redundant.
#
# type The fully-qualified type name
# selfns The instance namespace
# win The original instance/tk window name.
# old old instance command name
# new new instance command name
# op rename or delete
#
# If the op is delete, we need to clean up the object; otherwise,
# we need to track the change.
#
# NOTE: In Tcl 8.4.2 there's a bug: errors in rename and delete
# traces aren't propagated correctly. Instead, they silently
# vanish. Add a catch to output any error message.
proc ::snit::RT.InstanceTrace {type selfns win old new op} {
variable ${type}::Snit_info
# Note to developers ...
# For Tcl 8.4.0, errors thrown in trace handlers vanish silently.
# Therefore we catch them here and create some output to help in
# debugging such problems.
if {[catch {
# FIRST, clean up if necessary
if {"" == $new} {
if {$Snit_info(isWidget)} {
destroy $win
} else {
::snit::RT.DestroyObject $type $selfns $win
}
} else {
# Otherwise, track the change.
variable ${selfns}::Snit_instance
set Snit_instance [uplevel 1 [list namespace which -command $new]]
# Also, clear the instance caches, as many cached commands
# might be invalid.
RT.ClearInstanceCaches $selfns
}
} result]} {
global errorInfo
# Pop up the console on Windows wish, to enable stdout.
# This clobbers errorInfo on unix, so save it so we can print it.
set ei $errorInfo
catch {console show}
puts "Error in ::snit::RT.InstanceTrace $type $selfns $win $old $new $op:"
puts $ei
}
}
# Calls the instance constructor and handles related housekeeping.
proc ::snit::RT.ConstructInstance {type selfns instance arglist} {
variable ${type}::Snit_optionInfo
variable ${selfns}::Snit_iinfo
# Track whether we are constructed or not.
set Snit_iinfo(constructed) 0
# Call the user's constructor
eval [linsert $arglist 0 \
${type}::Snit_constructor $type $selfns $instance $instance]
set Snit_iinfo(constructed) 1
# Validate the initial set of options (including defaults)
foreach option $Snit_optionInfo(local) {
set value [set ${selfns}::options($option)]
if {"" != $Snit_optionInfo(typespec-$option)} {
if {[catch {
$Snit_optionInfo(typeobj-$option) validate $value
} result]} {
return -code error "invalid $option default: $result"
}
}
}
# Unset the configure cache for all -readonly options.
# This ensures that the next time anyone tries to
# configure it, an error is thrown.
foreach opt $Snit_optionInfo(local) {
if {$Snit_optionInfo(readonly-$opt)} {
::snit83::unset -nocomplain ${selfns}::Snit_configureCache($opt)
}
}
return
}
# Returns a unique command name.
#
# REQUIRE: type is a fully qualified name.
# REQUIRE: name contains "%AUTO%"
# PROMISE: the returned command name is unused.
proc ::snit::RT.UniqueName {countervar type name} {
upvar $countervar counter
while 1 {
# FIRST, bump the counter and define the %AUTO% instance name;
# then substitute it into the specified name. Wrap around at
# 2^31 - 2 to prevent overflow problems.
incr counter
if {$counter > 2147483646} {
set counter 0
}
set auto "[namespace tail $type]$counter"
set candidate [Expand $name %AUTO% $auto]
if {![llength [info commands $candidate]]} {
return $candidate
}
}
}
# Returns a unique instance namespace, fully qualified.
#
# countervar The name of a counter variable
# type The instance's type
#
# REQUIRE: type is fully qualified
# PROMISE: The returned namespace name is unused.
proc ::snit::RT.UniqueInstanceNamespace {countervar type} {
upvar $countervar counter
while 1 {
# FIRST, bump the counter and define the namespace name.
# Then see if it already exists. Wrap around at
# 2^31 - 2 to prevent overflow problems.
incr counter
if {$counter > 2147483646} {
set counter 0
}
set ins "${type}::Snit_inst${counter}"
if {![namespace exists $ins]} {
return $ins
}
}
}
# Retrieves an option's value from the option database.
# Returns "" if no value is found.
proc ::snit::RT.OptionDbGet {type self opt} {
variable ${type}::Snit_optionInfo
return [option get $self \
$Snit_optionInfo(resource-$opt) \
$Snit_optionInfo(class-$opt)]
}
#-----------------------------------------------------------------------
# Object Destruction
# Implements the standard "destroy" method
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
proc ::snit::RT.method.destroy {type selfns win self} {
variable ${selfns}::Snit_iinfo
# Can't destroy the object if it isn't complete constructed.
if {!$Snit_iinfo(constructed)} {
return -code error "Called 'destroy' method in constructor"
}
# Calls Snit_cleanup, which (among other things) calls the
# user's destructor.
::snit::RT.DestroyObject $type $selfns $win
}
# This is the function that really cleans up; it's automatically
# called when any instance is destroyed, e.g., by "$object destroy"
# for types, and by the event for widgets.
#
# type The fully-qualified type name.
# selfns The instance namespace
# win The original instance command name.
proc ::snit::RT.DestroyObject {type selfns win} {
variable ${type}::Snit_info
# If the variable Snit_instance doesn't exist then there's no
# instance command for this object -- it's most likely a
# widgetadaptor. Consequently, there are some things that
# we don't need to do.
if {[info exists ${selfns}::Snit_instance]} {
upvar ${selfns}::Snit_instance instance
# First, remove the trace on the instance name, so that we
# don't call RT.DestroyObject recursively.
RT.RemoveInstanceTrace $type $selfns $win $instance
# Next, call the user's destructor
${type}::Snit_destructor $type $selfns $win $instance
# Next, if this isn't a widget, delete the instance command.
# If it is a widget, get the hull component's name, and rename
# it back to the widget name
# Next, delete the hull component's instance command,
# if there is one.
if {$Snit_info(isWidget)} {
set hullcmd [::snit::RT.Component $type $selfns hull]
catch {rename $instance ""}
# Clear the bind event
bind Snit$type$win ""
if {[llength [info commands $hullcmd]]} {
# FIRST, rename the hull back to its original name.
# If the hull is itself a megawidget, it will have its
# own cleanup to do, and it might not do it properly
# if it doesn't have the right name.
rename $hullcmd ::$instance
# NEXT, destroy it.
destroy $instance
}
} else {
catch {rename $instance ""}
}
}
# Next, delete the instance's namespace. This kills any
# instance variables.
namespace delete $selfns
return
}
# Remove instance trace
#
# type The fully qualified type name
# selfns The instance namespace
# win The original instance name/Tk window name
# instance The current instance name
proc ::snit::RT.RemoveInstanceTrace {type selfns win instance} {
variable ${type}::Snit_info
if {$Snit_info(isWidget)} {
set procname ::$instance
} else {
set procname $instance
}
# NEXT, remove any trace on this name
catch {
#kmg-tcl83
::snit83::traceRemoveCommand $procname {rename delete} \
[list ::snit::RT.InstanceTrace $type $selfns $win]
}
}
#-----------------------------------------------------------------------
# Typecomponent Management and Method Caching
# Typecomponent trace; used for write trace on typecomponent
# variables. Saves the new component object name, provided
# that certain conditions are met. Also clears the typemethod
# cache.
proc ::snit::RT.TypecomponentTrace {type component n1 n2 op} {
upvar ${type}::Snit_info Snit_info
upvar ${type}::${component} cvar
upvar ${type}::Snit_typecomponents Snit_typecomponents
# Save the new component value.
set Snit_typecomponents($component) $cvar
# Clear the typemethod cache.
# TBD: can we unset just the elements related to
# this component?
::snit83::unset -nocomplain -- ${type}::Snit_typemethodCache
}
# Generates and caches the command for a typemethod.
#
# type The type
# method The name of the typemethod to call.
#
# The return value is one of the following lists:
#
# {} There's no such method.
# {1} The method has submethods; look again.
# {0 } Here's the command to execute.
proc snit::RT.CacheTypemethodCommand {type method} {
upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo
upvar ${type}::Snit_typecomponents Snit_typecomponents
upvar ${type}::Snit_typemethodCache Snit_typemethodCache
upvar ${type}::Snit_info Snit_info
# FIRST, get the pattern data and the typecomponent name.
set implicitCreate 0
set instanceName ""
set starredMethod [lreplace $method end end *]
set methodTail [lindex $method end]
if {[info exists Snit_typemethodInfo($method)]} {
set key $method
} elseif {[info exists Snit_typemethodInfo($starredMethod)]} {
if {[lsearch -exact $Snit_info(excepttypemethods) $methodTail] == -1} {
set key $starredMethod
} else {
return [list ]
}
} elseif {$Snit_info(hasinstances)} {
# Assume the unknown name is an instance name to create, unless
# this is a widget and the style of the name is wrong, or the
# name mimics a standard typemethod.
if {[set ${type}::Snit_info(isWidget)] &&
![string match ".*" $method]} {
return [list ]
}
# Without this check, the call "$type info" will redefine the
# standard "::info" command, with disastrous results. Since it's
# a likely thing to do if !-typeinfo, put in an explicit check.
if {"info" == $method || "destroy" == $method} {
return [list ]
}
set implicitCreate 1
set instanceName $method
set key create
set method create
} else {
return [list ]
}
foreach {flag pattern compName} $Snit_typemethodInfo($key) {}
if {$flag == 1} {
return [list 1]
}
# NEXT, build the substitution list
set subList [list \
%% % \
%t $type \
%M $method \
%m [lindex $method end] \
%j [join $method _]]
if {"" != $compName} {
if {![info exists Snit_typecomponents($compName)]} {
error "$type delegates typemethod \"$method\" to undefined typecomponent \"$compName\""
}
lappend subList %c [list $Snit_typecomponents($compName)]
}
set command {}
foreach subpattern $pattern {
lappend command [string map $subList $subpattern]
}
if {$implicitCreate} {
# In this case, $method is the name of the instance to
# create. Don't cache, as we usually won't do this one
# again.
lappend command $instanceName
} else {
set Snit_typemethodCache($method) [list 0 $command]
}
return [list 0 $command]
}
#-----------------------------------------------------------------------
# Component Management and Method Caching
# Retrieves the object name given the component name.
proc ::snit::RT.Component {type selfns name} {
variable ${selfns}::Snit_components
if {[catch {set Snit_components($name)} result]} {
variable ${selfns}::Snit_instance
error "component \"$name\" is undefined in $type $Snit_instance"
}
return $result
}
# Component trace; used for write trace on component instance
# variables. Saves the new component object name, provided
# that certain conditions are met. Also clears the method
# cache.
proc ::snit::RT.ComponentTrace {type selfns component n1 n2 op} {
upvar ${type}::Snit_info Snit_info
upvar ${selfns}::${component} cvar
upvar ${selfns}::Snit_components Snit_components
# If they try to redefine the hull component after
# it's been defined, that's an error--but only if
# this is a widget or widget adaptor.
if {"hull" == $component &&
$Snit_info(isWidget) &&
[info exists Snit_components($component)]} {
set cvar $Snit_components($component)
error "The hull component cannot be redefined"
}
# Save the new component value.
set Snit_components($component) $cvar
# Clear the instance caches.
# TBD: can we unset just the elements related to
# this component?
RT.ClearInstanceCaches $selfns
}
# Generates and caches the command for a method.
#
# type: The instance's type
# selfns: The instance's private namespace
# win: The instance's original name (a Tk widget name, for
# snit::widgets.
# self: The instance's current name.
# method: The name of the method to call.
#
# The return value is one of the following lists:
#
# {} There's no such method.
# {1} The method has submethods; look again.
# {0 } Here's the command to execute.
proc ::snit::RT.CacheMethodCommand {type selfns win self method} {
variable ${type}::Snit_info
variable ${type}::Snit_methodInfo
variable ${type}::Snit_typecomponents
variable ${selfns}::Snit_components
variable ${selfns}::Snit_methodCache
# FIRST, get the pattern data and the component name.
set starredMethod [lreplace $method end end *]
set methodTail [lindex $method end]
if {[info exists Snit_methodInfo($method)]} {
set key $method
} elseif {[info exists Snit_methodInfo($starredMethod)] &&
[lsearch -exact $Snit_info(exceptmethods) $methodTail] == -1} {
set key $starredMethod
} else {
return [list ]
}
foreach {flag pattern compName} $Snit_methodInfo($key) {}
if {$flag == 1} {
return [list 1]
}
# NEXT, build the substitution list
set subList [list \
%% % \
%t $type \
%M $method \
%m [lindex $method end] \
%j [join $method _] \
%n [list $selfns] \
%w [list $win] \
%s [list $self]]
if {"" != $compName} {
if {[info exists Snit_components($compName)]} {
set compCmd $Snit_components($compName)
} elseif {[info exists Snit_typecomponents($compName)]} {
set compCmd $Snit_typecomponents($compName)
} else {
error "$type $self delegates method \"$method\" to undefined component \"$compName\""
}
lappend subList %c [list $compCmd]
}
# Note: The cached command will executed faster if it's
# already a list.
set command {}
foreach subpattern $pattern {
lappend command [string map $subList $subpattern]
}
set commandRec [list 0 $command]
set Snit_methodCache($method) $commandRec
return $commandRec
}
# Looks up a method's command.
#
# type: The instance's type
# selfns: The instance's private namespace
# win: The instance's original name (a Tk widget name, for
# snit::widgets.
# self: The instance's current name.
# method: The name of the method to call.
# errPrefix: Prefix for any error method
proc ::snit::RT.LookupMethodCommand {type selfns win self method errPrefix} {
set commandRec [snit::RT.CacheMethodCommand \
$type $selfns $win $self \
$method]
if {[llength $commandRec] == 0} {
return -code error \
"$errPrefix, \"$self $method\" is not defined"
} elseif {[lindex $commandRec 0] == 1} {
return -code error \
"$errPrefix, wrong number args: should be \"$self\" $method method args"
}
return [lindex $commandRec 1]
}
# Clears all instance command caches
proc ::snit::RT.ClearInstanceCaches {selfns} {
::snit83::unset -nocomplain -- ${selfns}::Snit_methodCache
::snit83::unset -nocomplain -- ${selfns}::Snit_cgetCache
::snit83::unset -nocomplain -- ${selfns}::Snit_configureCache
::snit83::unset -nocomplain -- ${selfns}::Snit_validateCache
}
#-----------------------------------------------------------------------
# Component Installation
# Implements %TYPE%::installhull. The variables self and selfns
# must be defined in the caller's context.
#
# Installs the named widget as the hull of a
# widgetadaptor. Once the widget is hijacked, its new name
# is assigned to the hull component.
proc ::snit::RT.installhull {type {using "using"} {widgetType ""} args} {
variable ${type}::Snit_info
variable ${type}::Snit_optionInfo
upvar self self
upvar selfns selfns
upvar ${selfns}::hull hull
upvar ${selfns}::options options
# FIRST, make sure we can do it.
if {!$Snit_info(isWidget)} {
error "installhull is valid only for snit::widgetadaptors"
}
if {[info exists ${selfns}::Snit_instance]} {
error "hull already installed for $type $self"
}
# NEXT, has it been created yet? If not, create it using
# the specified arguments.
if {"using" == $using} {
# FIRST, create the widget
set cmd [linsert $args 0 $widgetType $self]
set obj [uplevel 1 $cmd]
# NEXT, for each option explicitly delegated to the hull
# that doesn't appear in the usedOpts list, get the
# option database value and apply it--provided that the
# real option name and the target option name are different.
# (If they are the same, then the option database was
# already queried as part of the normal widget creation.)
#
# Also, we don't need to worry about implicitly delegated
# options, as the option and target option names must be
# the same.
if {[info exists Snit_optionInfo(delegated-hull)]} {
# FIRST, extract all option names from args
set usedOpts {}
set ndx [lsearch -glob $args "-*"]
foreach {opt val} [lrange $args $ndx end] {
lappend usedOpts $opt
}
foreach opt $Snit_optionInfo(delegated-hull) {
set target [lindex $Snit_optionInfo(target-$opt) 1]
if {"$target" == $opt} {
continue
}
set result [lsearch -exact $usedOpts $target]
if {$result != -1} {
continue
}
set dbval [RT.OptionDbGet $type $self $opt]
$obj configure $target $dbval
}
}
} else {
set obj $using
if {![string equal $obj $self]} {
error \
"hull name mismatch: \"$obj\" != \"$self\""
}
}
# NEXT, get the local option defaults.
foreach opt $Snit_optionInfo(local) {
set dbval [RT.OptionDbGet $type $self $opt]
if {"" != $dbval} {
set options($opt) $dbval
}
}
# NEXT, do the magic
set i 0
while 1 {
incr i
set newName "::hull${i}$self"
if {![llength [info commands $newName]]} {
break
}
}
rename ::$self $newName
RT.MakeInstanceCommand $type $selfns $self
# Note: this relies on RT.ComponentTrace to do the dirty work.
set hull $newName
return
}
# Implements %TYPE%::install.
#
# Creates a widget and installs it as the named component.
# It expects self and selfns to be defined in the caller's context.
proc ::snit::RT.install {type compName "using" widgetType winPath args} {
variable ${type}::Snit_optionInfo
variable ${type}::Snit_info
upvar self self
upvar selfns selfns
upvar ${selfns}::$compName comp
upvar ${selfns}::hull hull
# We do the magic option database stuff only if $self is
# a widget.
if {$Snit_info(isWidget)} {
if {"" == $hull} {
error "tried to install \"$compName\" before the hull exists"
}
# FIRST, query the option database and save the results
# into args. Insert them before the first option in the
# list, in case there are any non-standard parameters.
#
# Note: there might not be any delegated options; if so,
# don't bother.
if {[info exists Snit_optionInfo(delegated-$compName)]} {
set ndx [lsearch -glob $args "-*"]
foreach opt $Snit_optionInfo(delegated-$compName) {
set dbval [RT.OptionDbGet $type $self $opt]
if {"" != $dbval} {
set target [lindex $Snit_optionInfo(target-$opt) 1]
set args [linsert $args $ndx $target $dbval]
}
}
}
}
# NEXT, create the component and save it.
set cmd [concat [list $widgetType $winPath] $args]
set comp [uplevel 1 $cmd]
# NEXT, handle the option database for "delegate option *",
# in widgets only.
if {$Snit_info(isWidget) && [string equal $Snit_optionInfo(starcomp) $compName]} {
# FIRST, get the list of option specs from the widget.
# If configure doesn't work, skip it.
if {[catch {$comp configure} specs]} {
return
}
# NEXT, get the set of explicitly used options from args
set usedOpts {}
set ndx [lsearch -glob $args "-*"]
foreach {opt val} [lrange $args $ndx end] {
lappend usedOpts $opt
}
# NEXT, "delegate option *" matches all options defined
# by this widget that aren't defined by the widget as a whole,
# and that aren't excepted. Plus, we skip usedOpts. So build
# a list of the options it can't match.
set skiplist [concat \
$usedOpts \
$Snit_optionInfo(except) \
$Snit_optionInfo(local) \
$Snit_optionInfo(delegated)]
# NEXT, loop over all of the component's options, and set
# any not in the skip list for which there is an option
# database value.
foreach spec $specs {
# Skip aliases
if {[llength $spec] != 5} {
continue
}
set opt [lindex $spec 0]
if {[lsearch -exact $skiplist $opt] != -1} {
continue
}
set res [lindex $spec 1]
set cls [lindex $spec 2]
set dbvalue [option get $self $res $cls]
if {"" != $dbvalue} {
$comp configure $opt $dbvalue
}
}
}
return
}
#-----------------------------------------------------------------------
# Method/Variable Name Qualification
# Implements %TYPE%::variable. Requires selfns.
proc ::snit::RT.variable {varname} {
upvar selfns selfns
if {![string match "::*" $varname]} {
uplevel 1 [list upvar 1 ${selfns}::$varname $varname]
} else {
# varname is fully qualified; let the standard
# "variable" command handle it.
uplevel 1 [list ::variable $varname]
}
}
# Fully qualifies a typevariable name.
#
# This is used to implement the mytypevar command.
proc ::snit::RT.mytypevar {type name} {
return ${type}::$name
}
# Fully qualifies an instance variable name.
#
# This is used to implement the myvar command.
proc ::snit::RT.myvar {name} {
upvar selfns selfns
return ${selfns}::$name
}
# Use this like "list" to convert a proc call into a command
# string to pass to another object (e.g., as a -command).
# Qualifies the proc name properly.
#
# This is used to implement the "myproc" command.
proc ::snit::RT.myproc {type procname args} {
set procname "${type}::$procname"
return [linsert $args 0 $procname]
}
# DEPRECATED
proc ::snit::RT.codename {type name} {
return "${type}::$name"
}
# Use this like "list" to convert a typemethod call into a command
# string to pass to another object (e.g., as a -command).
# Inserts the type command at the beginning.
#
# This is used to implement the "mytypemethod" command.
proc ::snit::RT.mytypemethod {type args} {
return [linsert $args 0 $type]
}
# Use this like "list" to convert a method call into a command
# string to pass to another object (e.g., as a -command).
# Inserts the code at the beginning to call the right object, even if
# the object's name has changed. Requires that selfns be defined
# in the calling context, eg. can only be called in instance
# code.
#
# This is used to implement the "mymethod" command.
proc ::snit::RT.mymethod {args} {
upvar selfns selfns
return [linsert $args 0 ::snit::RT.CallInstance ${selfns}]
}
# Calls an instance method for an object given its
# instance namespace and remaining arguments (the first of which
# will be the method name.
#
# selfns The instance namespace
# args The arguments
#
# Uses the selfns to determine $self, and calls the method
# in the normal way.
#
# This is used to implement the "mymethod" command.
proc ::snit::RT.CallInstance {selfns args} {
upvar ${selfns}::Snit_instance self
set retval [catch {uplevel 1 [linsert $args 0 $self]} result]
if {$retval} {
if {$retval == 1} {
global errorInfo
global errorCode
return -code error -errorinfo $errorInfo \
-errorcode $errorCode $result
} else {
return -code $retval $result
}
}
return $result
}
# Looks for the named option in the named variable. If found,
# it and its value are removed from the list, and the value
# is returned. Otherwise, the default value is returned.
# If the option is undelegated, it's own default value will be
# used if none is specified.
#
# Implements the "from" command.
proc ::snit::RT.from {type argvName option {defvalue ""}} {
variable ${type}::Snit_optionInfo
upvar $argvName argv
set ioption [lsearch -exact $argv $option]
if {$ioption == -1} {
if {"" == $defvalue &&
[info exists Snit_optionInfo(default-$option)]} {
return $Snit_optionInfo(default-$option)
} else {
return $defvalue
}
}
set ivalue [expr {$ioption + 1}]
set value [lindex $argv $ivalue]
set argv [lreplace $argv $ioption $ivalue]
return $value
}
#-----------------------------------------------------------------------
# Type Destruction
# Implements the standard "destroy" typemethod:
# Destroys a type completely.
#
# type The snit type
proc ::snit::RT.typemethod.destroy {type} {
variable ${type}::Snit_info
# FIRST, destroy all instances
foreach selfns [namespace children $type] {
if {![namespace exists $selfns]} {
continue
}
upvar ${selfns}::Snit_instance obj
if {$Snit_info(isWidget)} {
destroy $obj
} else {
if {[llength [info commands $obj]]} {
$obj destroy
}
}
}
# NEXT, destroy the type's data.
namespace delete $type
# NEXT, get rid of the type command.
rename $type ""
}
#-----------------------------------------------------------------------
# Option Handling
# Implements the standard "cget" method
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
# option The name of the option
proc ::snit::RT.method.cget {type selfns win self option} {
if {[catch {set ${selfns}::Snit_cgetCache($option)} command]} {
set command [snit::RT.CacheCgetCommand $type $selfns $win $self $option]
if {[llength $command] == 0} {
return -code error "unknown option \"$option\""
}
}
uplevel 1 $command
}
# Retrieves and caches the command that implements "cget" for the
# specified option.
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
# option The name of the option
proc ::snit::RT.CacheCgetCommand {type selfns win self option} {
variable ${type}::Snit_optionInfo
variable ${selfns}::Snit_cgetCache
if {[info exists Snit_optionInfo(islocal-$option)]} {
# We know the item; it's either local, or explicitly delegated.
if {$Snit_optionInfo(islocal-$option)} {
# It's a local option. If it has a cget method defined,
# use it; otherwise just return the value.
if {"" == $Snit_optionInfo(cget-$option)} {
set command [list set ${selfns}::options($option)]
} else {
set command [snit::RT.LookupMethodCommand \
$type $selfns $win $self \
$Snit_optionInfo(cget-$option) \
"can't cget $option"]
lappend command $option
}
set Snit_cgetCache($option) $command
return $command
}
# Explicitly delegated option; get target
set comp [lindex $Snit_optionInfo(target-$option) 0]
set target [lindex $Snit_optionInfo(target-$option) 1]
} elseif {"" != $Snit_optionInfo(starcomp) &&
[lsearch -exact $Snit_optionInfo(except) $option] == -1} {
# Unknown option, but unknowns are delegated; get target.
set comp $Snit_optionInfo(starcomp)
set target $option
} else {
return ""
}
# Get the component's object.
set obj [RT.Component $type $selfns $comp]
set command [list $obj cget $target]
set Snit_cgetCache($option) $command
return $command
}
# Implements the standard "configurelist" method
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
# optionlist A list of options and their values.
proc ::snit::RT.method.configurelist {type selfns win self optionlist} {
variable ${type}::Snit_optionInfo
foreach {option value} $optionlist {
# FIRST, get the configure command, caching it if need be.
if {[catch {set ${selfns}::Snit_configureCache($option)} command]} {
set command [snit::RT.CacheConfigureCommand \
$type $selfns $win $self $option]
if {[llength $command] == 0} {
return -code error "unknown option \"$option\""
}
}
# NEXT, if we have a type-validation object, use it.
# TBD: Should test (islocal-$option) here, but islocal
# isn't defined for implicitly delegated options.
if {[info exists Snit_optionInfo(typeobj-$option)]
&& "" != $Snit_optionInfo(typeobj-$option)} {
if {[catch {
$Snit_optionInfo(typeobj-$option) validate $value
} result]} {
return -code error "invalid $option value: $result"
}
}
# NEXT, the caching the configure command also cached the
# validate command, if any. If we have one, run it.
set valcommand [set ${selfns}::Snit_validateCache($option)]
if {[llength $valcommand]} {
lappend valcommand $value
uplevel 1 $valcommand
}
# NEXT, configure the option with the value.
lappend command $value
uplevel 1 $command
}
return
}
# Retrieves and caches the command that stores the named option.
# Also stores the command that validates the name option if any;
# If none, the validate command is "", so that the cache is always
# populated.
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
# option An option name
proc ::snit::RT.CacheConfigureCommand {type selfns win self option} {
variable ${type}::Snit_optionInfo
variable ${selfns}::Snit_configureCache
variable ${selfns}::Snit_validateCache
if {[info exist Snit_optionInfo(islocal-$option)]} {
# We know the item; it's either local, or explicitly delegated.
if {$Snit_optionInfo(islocal-$option)} {
# It's a local option.
# If it's readonly, it throws an error if we're already
# constructed.
if {$Snit_optionInfo(readonly-$option)} {
if {[set ${selfns}::Snit_iinfo(constructed)]} {
error "option $option can only be set at instance creation"
}
}
# If it has a validate method, cache that for later.
if {"" != $Snit_optionInfo(validate-$option)} {
set command [snit::RT.LookupMethodCommand \
$type $selfns $win $self \
$Snit_optionInfo(validate-$option) \
"can't validate $option"]
lappend command $option
set Snit_validateCache($option) $command
} else {
set Snit_validateCache($option) ""
}
# If it has a configure method defined,
# cache it; otherwise, just set the value.
if {"" == $Snit_optionInfo(configure-$option)} {
set command [list set ${selfns}::options($option)]
} else {
set command [snit::RT.LookupMethodCommand \
$type $selfns $win $self \
$Snit_optionInfo(configure-$option) \
"can't configure $option"]
lappend command $option
}
set Snit_configureCache($option) $command
return $command
}
# Delegated option: get target.
set comp [lindex $Snit_optionInfo(target-$option) 0]
set target [lindex $Snit_optionInfo(target-$option) 1]
} elseif {$Snit_optionInfo(starcomp) != "" &&
[lsearch -exact $Snit_optionInfo(except) $option] == -1} {
# Unknown option, but unknowns are delegated.
set comp $Snit_optionInfo(starcomp)
set target $option
} else {
return ""
}
# There is no validate command in this case; save an empty string.
set Snit_validateCache($option) ""
# Get the component's object
set obj [RT.Component $type $selfns $comp]
set command [list $obj configure $target]
set Snit_configureCache($option) $command
return $command
}
# Implements the standard "configure" method
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
# args A list of options and their values, possibly empty.
proc ::snit::RT.method.configure {type selfns win self args} {
# If two or more arguments, set values as usual.
if {[llength $args] >= 2} {
::snit::RT.method.configurelist $type $selfns $win $self $args
return
}
# If zero arguments, acquire data for each known option
# and return the list
if {[llength $args] == 0} {
set result {}
foreach opt [RT.method.info.options $type $selfns $win $self] {
# Refactor this, so that we don't need to call via $self.
lappend result [RT.GetOptionDbSpec \
$type $selfns $win $self $opt]
}
return $result
}
# They want it for just one.
set opt [lindex $args 0]
return [RT.GetOptionDbSpec $type $selfns $win $self $opt]
}
# Retrieves the option database spec for a single option.
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
# option The name of an option
#
# TBD: This is a bad name. What it's returning is the
# result of the configure query.
proc ::snit::RT.GetOptionDbSpec {type selfns win self opt} {
variable ${type}::Snit_optionInfo
upvar ${selfns}::Snit_components Snit_components
upvar ${selfns}::options options
if {[info exists options($opt)]} {
# This is a locally-defined option. Just build the
# list and return it.
set res $Snit_optionInfo(resource-$opt)
set cls $Snit_optionInfo(class-$opt)
set def $Snit_optionInfo(default-$opt)
return [list $opt $res $cls $def \
[RT.method.cget $type $selfns $win $self $opt]]
} elseif {[info exists Snit_optionInfo(target-$opt)]} {
# This is an explicitly delegated option. The only
# thing we don't have is the default.
set res $Snit_optionInfo(resource-$opt)
set cls $Snit_optionInfo(class-$opt)
# Get the default
set logicalName [lindex $Snit_optionInfo(target-$opt) 0]
set comp $Snit_components($logicalName)
set target [lindex $Snit_optionInfo(target-$opt) 1]
if {[catch {$comp configure $target} result]} {
set defValue {}
} else {
set defValue [lindex $result 3]
}
return [list $opt $res $cls $defValue [$self cget $opt]]
} elseif {"" != $Snit_optionInfo(starcomp) &&
[lsearch -exact $Snit_optionInfo(except) $opt] == -1} {
set logicalName $Snit_optionInfo(starcomp)
set target $opt
set comp $Snit_components($logicalName)
if {[catch {set value [$comp cget $target]} result]} {
error "unknown option \"$opt\""
}
if {![catch {$comp configure $target} result]} {
# Replace the delegated option name with the local name.
return [::snit::Expand $result $target $opt]
}
# configure didn't work; return simple form.
return [list $opt "" "" "" $value]
} else {
error "unknown option \"$opt\""
}
}
#-----------------------------------------------------------------------
# Type Introspection
# Implements the standard "info" typemethod.
#
# type The snit type
# command The info subcommand
# args All other arguments.
proc ::snit::RT.typemethod.info {type command args} {
global errorInfo
global errorCode
switch -exact $command {
args -
body -
default -
typevars -
typemethods -
instances {
# TBD: it should be possible to delete this error
# handling.
set errflag [catch {
uplevel 1 [linsert $args 0 \
::snit::RT.typemethod.info.$command $type]
} result]
if {$errflag} {
return -code error -errorinfo $errorInfo \
-errorcode $errorCode $result
} else {
return $result
}
}
default {
error "\"$type info $command\" is not defined"
}
}
}
# Returns a list of the type's typevariables whose names match a
# pattern, excluding Snit internal variables.
#
# type A Snit type
# pattern Optional. The glob pattern to match. Defaults
# to *.
proc ::snit::RT.typemethod.info.typevars {type {pattern *}} {
set result {}
foreach name [info vars "${type}::$pattern"] {
set tail [namespace tail $name]
if {![string match "Snit_*" $tail]} {
lappend result $name
}
}
return $result
}
# Returns a list of the type's methods whose names match a
# pattern. If "delegate typemethod *" is used, the list may
# not be complete.
#
# type A Snit type
# pattern Optional. The glob pattern to match. Defaults
# to *.
proc ::snit::RT.typemethod.info.typemethods {type {pattern *}} {
variable ${type}::Snit_typemethodInfo
variable ${type}::Snit_typemethodCache
# FIRST, get the explicit names, skipping prefixes.
set result {}
foreach name [array names Snit_typemethodInfo $pattern] {
if {[lindex $Snit_typemethodInfo($name) 0] != 1} {
lappend result $name
}
}
# NEXT, add any from the cache that aren't explicit.
if {[info exists Snit_typemethodInfo(*)]} {
# First, remove "*" from the list.
set ndx [lsearch -exact $result "*"]
if {$ndx != -1} {
set result [lreplace $result $ndx $ndx]
}
foreach name [array names Snit_typemethodCache $pattern] {
if {[lsearch -exact $result $name] == -1} {
lappend result $name
}
}
}
return $result
}
# $type info args
#
# Returns a method's list of arguments. does not work for delegated
# methods, nor for the internal dispatch methods of multi-word
# methods.
proc ::snit::RT.typemethod.info.args {type method} {
upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo
# Snit_methodInfo: method -> list (flag cmd component)
# flag : 1 -> internal dispatcher for multi-word method.
# 0 -> regular method
#
# cmd : template mapping from method to command prefix, may
# contain placeholders for various pieces of information.
#
# component : is empty for normal methods.
#parray Snit_typemethodInfo
if {![info exists Snit_typemethodInfo($method)]} {
return -code error "Unknown typemethod \"$method\""
}
foreach {flag cmd component} $Snit_typemethodInfo($method) break
if {$flag} {
return -code error "Unknown typemethod \"$method\""
}
if {$component != ""} {
return -code error "Delegated typemethod \"$method\""
}
set map [list %m $method %j [join $method _] %t $type]
set theproc [lindex [string map $map $cmd] 0]
return [lrange [::info args $theproc] 1 end]
}
# $type info body
#
# Returns a method's body. does not work for delegated
# methods, nor for the internal dispatch methods of multi-word
# methods.
proc ::snit::RT.typemethod.info.body {type method} {
upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo
# Snit_methodInfo: method -> list (flag cmd component)
# flag : 1 -> internal dispatcher for multi-word method.
# 0 -> regular method
#
# cmd : template mapping from method to command prefix, may
# contain placeholders for various pieces of information.
#
# component : is empty for normal methods.
#parray Snit_typemethodInfo
if {![info exists Snit_typemethodInfo($method)]} {
return -code error "Unknown typemethod \"$method\""
}
foreach {flag cmd component} $Snit_typemethodInfo($method) break
if {$flag} {
return -code error "Unknown typemethod \"$method\""
}
if {$component != ""} {
return -code error "Delegated typemethod \"$method\""
}
set map [list %m $method %j [join $method _] %t $type]
set theproc [lindex [string map $map $cmd] 0]
return [RT.body [::info body $theproc]]
}
# $type info default
#
# Returns a method's list of arguments. does not work for delegated
# methods, nor for the internal dispatch methods of multi-word
# methods.
proc ::snit::RT.typemethod.info.default {type method aname dvar} {
upvar 1 $dvar def
upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo
# Snit_methodInfo: method -> list (flag cmd component)
# flag : 1 -> internal dispatcher for multi-word method.
# 0 -> regular method
#
# cmd : template mapping from method to command prefix, may
# contain placeholders for various pieces of information.
#
# component : is empty for normal methods.
#parray Snit_methodInfo
if {![info exists Snit_typemethodInfo($method)]} {
return -code error "Unknown typemethod \"$method\""
}
foreach {flag cmd component} $Snit_typemethodInfo($method) break
if {$flag} {
return -code error "Unknown typemethod \"$method\""
}
if {$component != ""} {
return -code error "Delegated typemethod \"$method\""
}
set map [list %m $method %j [join $method _] %t $type]
set theproc [lindex [string map $map $cmd] 0]
return [::info default $theproc $aname def]
}
# Returns a list of the type's instances whose names match
# a pattern.
#
# type A Snit type
# pattern Optional. The glob pattern to match
# Defaults to *
#
# REQUIRE: type is fully qualified.
proc ::snit::RT.typemethod.info.instances {type {pattern *}} {
set result {}
foreach selfns [namespace children $type] {
upvar ${selfns}::Snit_instance instance
if {[string match $pattern $instance]} {
lappend result $instance
}
}
return $result
}
#-----------------------------------------------------------------------
# Instance Introspection
# Implements the standard "info" method.
#
# type The snit type
# selfns The instance's instance namespace
# win The instance's original name
# self The instance's current name
# command The info subcommand
# args All other arguments.
proc ::snit::RT.method.info {type selfns win self command args} {
switch -exact $command {
args -
body -
default -
type -
vars -
options -
methods -
typevars -
typemethods {
set errflag [catch {
uplevel 1 [linsert $args 0 ::snit::RT.method.info.$command \
$type $selfns $win $self]
} result]
if {$errflag} {
global errorInfo
return -code error -errorinfo $errorInfo $result
} else {
return $result
}
}
default {
# error "\"$self info $command\" is not defined"
return -code error "\"$self info $command\" is not defined"
}
}
}
# $self info type
#
# Returns the instance's type
proc ::snit::RT.method.info.type {type selfns win self} {
return $type
}
# $self info typevars
#
# Returns the instance's type's typevariables
proc ::snit::RT.method.info.typevars {type selfns win self {pattern *}} {
return [RT.typemethod.info.typevars $type $pattern]
}
# $self info typemethods
#
# Returns the instance's type's typemethods
proc ::snit::RT.method.info.typemethods {type selfns win self {pattern *}} {
return [RT.typemethod.info.typemethods $type $pattern]
}
# Returns a list of the instance's methods whose names match a
# pattern. If "delegate method *" is used, the list may
# not be complete.
#
# type A Snit type
# selfns The instance namespace
# win The original instance name
# self The current instance name
# pattern Optional. The glob pattern to match. Defaults
# to *.
proc ::snit::RT.method.info.methods {type selfns win self {pattern *}} {
variable ${type}::Snit_methodInfo
variable ${selfns}::Snit_methodCache
# FIRST, get the explicit names, skipping prefixes.
set result {}
foreach name [array names Snit_methodInfo $pattern] {
if {[lindex $Snit_methodInfo($name) 0] != 1} {
lappend result $name
}
}
# NEXT, add any from the cache that aren't explicit.
if {[info exists Snit_methodInfo(*)]} {
# First, remove "*" from the list.
set ndx [lsearch -exact $result "*"]
if {$ndx != -1} {
set result [lreplace $result $ndx $ndx]
}
foreach name [array names Snit_methodCache $pattern] {
if {[lsearch -exact $result $name] == -1} {
lappend result $name
}
}
}
return $result
}
# $self info args
#
# Returns a method's list of arguments. does not work for delegated
# methods, nor for the internal dispatch methods of multi-word
# methods.
proc ::snit::RT.method.info.args {type selfns win self method} {
upvar ${type}::Snit_methodInfo Snit_methodInfo
# Snit_methodInfo: method -> list (flag cmd component)
# flag : 1 -> internal dispatcher for multi-word method.
# 0 -> regular method
#
# cmd : template mapping from method to command prefix, may
# contain placeholders for various pieces of information.
#
# component : is empty for normal methods.
#parray Snit_methodInfo
if {![info exists Snit_methodInfo($method)]} {
return -code error "Unknown method \"$method\""
}
foreach {flag cmd component} $Snit_methodInfo($method) break
if {$flag} {
return -code error "Unknown method \"$method\""
}
if {$component != ""} {
return -code error "Delegated method \"$method\""
}
set map [list %m $method %j [join $method _] %t $type %n $selfns %w $win %s $self]
set theproc [lindex [string map $map $cmd] 0]
return [lrange [::info args $theproc] 4 end]
}
# $self info body
#
# Returns a method's body. does not work for delegated
# methods, nor for the internal dispatch methods of multi-word
# methods.
proc ::snit::RT.method.info.body {type selfns win self method} {
upvar ${type}::Snit_methodInfo Snit_methodInfo
# Snit_methodInfo: method -> list (flag cmd component)
# flag : 1 -> internal dispatcher for multi-word method.
# 0 -> regular method
#
# cmd : template mapping from method to command prefix, may
# contain placeholders for various pieces of information.
#
# component : is empty for normal methods.
#parray Snit_methodInfo
if {![info exists Snit_methodInfo($method)]} {
return -code error "Unknown method \"$method\""
}
foreach {flag cmd component} $Snit_methodInfo($method) break
if {$flag} {
return -code error "Unknown method \"$method\""
}
if {$component != ""} {
return -code error "Delegated method \"$method\""
}
set map [list %m $method %j [join $method _] %t $type %n $selfns %w $win %s $self]
set theproc [lindex [string map $map $cmd] 0]
return [RT.body [::info body $theproc]]
}
# $self info default
#
# Returns a method's list of arguments. does not work for delegated
# methods, nor for the internal dispatch methods of multi-word
# methods.
proc ::snit::RT.method.info.default {type selfns win self method aname dvar} {
upvar 1 $dvar def
upvar ${type}::Snit_methodInfo Snit_methodInfo
# Snit_methodInfo: method -> list (flag cmd component)
# flag : 1 -> internal dispatcher for multi-word method.
# 0 -> regular method
#
# cmd : template mapping from method to command prefix, may
# contain placeholders for various pieces of information.
#
# component : is empty for normal methods.
if {![info exists Snit_methodInfo($method)]} {
return -code error "Unknown method \"$method\""
}
foreach {flag cmd component} $Snit_methodInfo($method) break
if {$flag} {
return -code error "Unknown method \"$method\""
}
if {$component != ""} {
return -code error "Delegated method \"$method\""
}
set map [list %m $method %j [join $method _] %t $type %n $selfns %w $win %s $self]
set theproc [lindex [string map $map $cmd] 0]
return [::info default $theproc $aname def]
}
# $self info vars
#
# Returns the instance's instance variables
proc ::snit::RT.method.info.vars {type selfns win self {pattern *}} {
set result {}
foreach name [info vars "${selfns}::$pattern"] {
set tail [namespace tail $name]
if {![string match "Snit_*" $tail]} {
lappend result $name
}
}
return $result
}
# $self info options
#
# Returns a list of the names of the instance's options
proc ::snit::RT.method.info.options {type selfns win self {pattern *}} {
variable ${type}::Snit_optionInfo
# First, get the local and explicitly delegated options
set result [concat $Snit_optionInfo(local) $Snit_optionInfo(delegated)]
# If "configure" works as for Tk widgets, add the resulting
# options to the list. Skip excepted options
if {"" != $Snit_optionInfo(starcomp)} {
upvar ${selfns}::Snit_components Snit_components
set logicalName $Snit_optionInfo(starcomp)
set comp $Snit_components($logicalName)
if {![catch {$comp configure} records]} {
foreach record $records {
set opt [lindex $record 0]
if {[lsearch -exact $result $opt] == -1 &&
[lsearch -exact $Snit_optionInfo(except) $opt] == -1} {
lappend result $opt
}
}
}
}
# Next, apply the pattern
set names {}
foreach name $result {
if {[string match $pattern $name]} {
lappend names $name
}
}
return $names
}
proc ::snit::RT.body {body} {
regsub -all ".*# END snit method prolog\n" $body {} body
return $body
}
amsn-0.98.9/utils/pixmapprogbar/ 0000755 0001750 0001750 00000000000 11757711634 016420 5 ustar billiob billiob amsn-0.98.9/utils/pixmapprogbar/trough.gif 0000644 0001750 0001750 00000000617 10252127467 020415 0 ustar billiob billiob GIF89aN !Created with The GIMP !
, N 0IWx7յy5An+xn kq"&{{˪NeiƏШnZ!:Z`8 Zn
-r89uj~dxlvxr{m{wsv~~nȼпŵ¸ý(=iKhp@Â5H!-:x<.)z,XbB#5Tiq%Ɂ3XRI7Mύ>3ϛE*]ʴӛ ; amsn-0.98.9/utils/pixmapprogbar/pixmapprogbar.tcl 0000644 0001750 0001750 00000004705 10252127467 021777 0 ustar billiob billiob package require snit
package require scalable-bg
snit::widget pixmapprogbar {
variable progress
variable barwidth
option -font -configuremethod SetFont
option -foreground -configuremethod SetFg -default black -cgetmethod GetFg
option -fg -configuremethod SetFg -cgetmethod GetFg
option -overforeground -configuremethod SetOverFg -default white -cgetmethod GetOverFg
option -overfg -configuremethod SetOverFg -cgetmethod GetOverFg
component trough
delegate option * to trough
constructor { args } {
install trough using canvas $win.c -bg white -highlightthickness 0 -relief flat
$self configurelist $args
set troughimg [image create photo -file trough.gif]
scalable-bg trough -source $troughimg -width [$trough cget -width] -height [$trough cget -height] -n 1 -w 1 -s 1 -e 1
set barimg [image create photo -file bar.gif]
scalable-bg bar -source $barimg -width 0 -height [$trough cget -height] -n 3 -w 3 -s 6 -e 6
set progress 0
set barwidth 0
$trough create image 0 0 -anchor nw -image [trough name] -tag trough
$trough create image 0 0 -anchor nw -image [bar name] -tag bar
$trough create text 0 0 -anchor c -text "0%" -tag indicator
$self configurelist $args
pack $trough -expand true -fill x
bind $trough "$self Resize %w %h"
}
method Resize { w h } {
$trough coords indicator [expr [winfo width $trough] / 2] [expr [winfo height $trough] / 2]
set barwidth [expr round($progress * [winfo width $trough])]
set barheight [winfo height $trough]
bar configure -width $barwidth -height $barheight
}
method setprogress { value } {
set progress $value
set barwidth [expr round($value * [winfo width $trough])]
bar configure -width $barwidth
if { $barwidth > [lindex [$trough coords indicator] 0] } {
$trough itemconfigure indicator -fill $options(-overforeground)
} else {
$trough itemconfigure indicator -fill $options(-foreground)
}
$trough itemconfigure indicator -text "[expr round($value * 100)]%"
}
method SetFont { option value } {
set options(-font) $value
$trough itemconfigure indicator -font $value
}
method SetFg { option value } {
set options(-foreground) $value
set options(-fg) $value
$trough itemconfigure indicator -fill $value
}
method GetFg { option } {
return $options(-foreground)
}
method SetOverFg { option value } {
set options(-overforeground) $value
set options(-overfg) $value
}
method GetOverFg { option } {
return $options(-overforeground)
}
} amsn-0.98.9/utils/pixmapprogbar/bar.gif 0000644 0001750 0001750 00000000371 10252127467 017646 0 ustar billiob billiob GIF89aN
!
, N Ќ@8ͻRdihlLm,t$T!PH$K:yKIEvumnn p(znх8 >^|~vpte|g}t uŽ ; amsn-0.98.9/utils/pixmapprogbar/test.tcl 0000644 0001750 0001750 00000001322 10313040522 020053 0 ustar billiob billiob #!/usr/bin/wish
lappend auto_path ../
source pixmapprogbar.tcl
package require pixmapbutton
frame .top
pixmapprogbar .top.pb -height 20 -overfg blue -font [font create -family helvetica -size 12 -weight bold]
frame .bottom
button .bottom.1 -text "step 1" -command ".top.pb setprogress 0.2"
button .bottom.2 -text "step 2" -command ".top.pb setprogress 0.4"
button .bottom.3 -text "step 3" -command ".top.pb setprogress 0.6"
button .bottom.4 -text "step 4" -command ".top.pb setprogress 0.8"
button .bottom.5 -text "step 5" -command ".top.pb setprogress 1.0"
pack .top.pb -expand true -fill x
pack .bottom.1 .bottom.2 .bottom.3 .bottom.4 .bottom.5
pack .top .bottom -side top -pady 10
puts [.top.pb cget -foreground]
amsn-0.98.9/utils/farsight/ 0000755 0001750 0001750 00000000000 11757711723 015353 5 ustar billiob billiob amsn-0.98.9/utils/farsight/pkgIndex.tcl 0000644 0001750 0001750 00000000327 11234373740 017623 0 ustar billiob billiob # Tcl package index file
if {[package vcompare [info tclversion] 8.4] < 0} return
package ifneeded Farsight 0.1 "[list load [file join $dir tcl_farsight[info shared]] Farsight]; package provide Farsight 0.1"
amsn-0.98.9/utils/farsight/src/ 0000755 0001750 0001750 00000000000 11757711633 016142 5 ustar billiob billiob amsn-0.98.9/utils/farsight/src/tcl_farsight.c 0000644 0001750 0001750 00000400044 11755433160 020753 0 ustar billiob billiob /*
File : tcl_farsight.c
Description : Contains all functions for accessing farsight 2
Author : Youness El Alaoui (KaKaRoTo - kakaroto@users.sourceforge.net)
*/
// Include the header file
#include "tcl_farsight.h"
#include
#include
#include
#include
#include
#ifdef HAVE_FARSTREAM
#define LIBNAME "Farstream"
#define PREFIX "farstream"
#include
#include
#include
#else
#ifdef HAVE_FARSIGHT
#define LIBNAME "Farsight"
#define PREFIX "farsight"
#include
#include
#include
#else
# error "HAVE_FARSTREAM or HAVE_FARSIGHT must be defined\n";
#endif /* HAVE_FARSIGHT */
#endif /* HAVE_FARSTREAM */
#ifdef G_OS_WIN32
#include
#include
#include
#define snprintf _snprintf
#define inet_ntop inet_ntop_win32
#else
#include
#include
#include
#endif
#define OLD_AUDIO_CALL "A6"
#define OLD_AUDIO_VIDEO_CALL "AV6"
#define NEW_AUDIO_CALL "A19"
#define NEW_AUDIO_VIDEO_CALL "AV19"
typedef enum {
RTP_AUDIO = 1,
RTP_VIDEO = 2,
RTP_ICE6 = 4,
RTP_ICE19 = 8,
RTP_AUDIO_ICE6 = (RTP_AUDIO | RTP_ICE6),
RTP_AUDIO_ICE19 = (RTP_AUDIO | RTP_ICE19),
RTP_AUDIO_VIDEO_ICE6 = (RTP_AUDIO | RTP_VIDEO | RTP_ICE6),
RTP_AUDIO_VIDEO_ICE19 = (RTP_AUDIO | RTP_VIDEO | RTP_ICE19),
} FsCallType;
static GList * get_plugins_filtered (gboolean source, gboolean audio);
static FsCallType call_type;
/* Options, does not need to be freed */
static Tcl_Obj *level_callback = NULL;
static Tcl_Interp *level_callback_interp = NULL;
static Tcl_Obj *debug_callback = NULL;
static Tcl_Interp *debug_callback_interp = NULL;
static char *audio_source = NULL;
static char *audio_source_device = NULL;
static char *audio_source_pipeline = NULL;
static char *audio_sink = NULL;
static char *audio_sink_device = NULL;
static char *audio_sink_pipeline = NULL;
static char *video_source = NULL;
static char *video_source_device = NULL;
static gulong video_preview_xid = 0;
static char *video_source_pipeline = NULL;
static char *video_sink = NULL;
static gulong video_sink_xid = 0;
static char *video_sink_pipeline = NULL;
static GstElement *pipeline = NULL;
static GstElement *test_pipeline = NULL;
static GstElement *source_bin = NULL;
static GstElement *volumeIn = NULL;
static GstElement *volumeOut = NULL;
static GstElement *levelIn = NULL;
static GstElement *levelOut = NULL;
static GstElement *preview = NULL;
static FsParticipant *participant = NULL;
static FsSession *audio_session = NULL;
static FsStream *audio_stream = NULL;
static FsSession *video_session = NULL;
static FsStream *video_stream = NULL;
static gboolean audio_candidates_prepared = FALSE;
static gboolean audio_codecs_ready = FALSE;
static Tcl_Obj *audio_local_candidates = NULL;
static gboolean video_candidates_prepared = FALSE;
static gboolean video_codecs_ready = FALSE;
static Tcl_Obj *video_local_candidates = NULL;
static Tcl_Obj *callback = NULL;
static Tcl_Interp *callback_interp = NULL;
static Tcl_ThreadId main_tid = 0;
static int audio_components_selected = 0;
static int video_components_selected = 0;
static FsElementAddedNotifier *fsnotifier = NULL;
#ifdef __APPLE__
static GList *cocoa_windows = NULL;
#endif
#ifdef _WIN32
static const char *inet_ntop_win32(int af, const void *src, char *dst, socklen_t cnt)
{
if (af == AF_INET) {
struct sockaddr_in in;
memset(&in, 0, sizeof(in));
in.sin_family = AF_INET;
memcpy(&in.sin_addr, src, sizeof(struct in_addr));
getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST);
return dst;
}
return NULL;
}
#endif
static char *host2ip(char *hostname)
{
struct addrinfo * result;
static char ip[30];
const char * ret;
int error;
error = getaddrinfo(hostname, NULL, NULL, &result);
if (error != 0) {
return NULL;
}
if (result) {
ret = inet_ntop (AF_INET,
&((struct sockaddr_in *) result->ai_addr)->sin_addr,
ip, INET_ADDRSTRLEN);
freeaddrinfo (result);
if (ret == NULL) {
return NULL;
}
}
return ip;
}
static gboolean
g_object_has_property (GObject *object, const gchar *property)
{
GObjectClass *klass;
klass = G_OBJECT_GET_CLASS (object);
return NULL != g_object_class_find_property (klass, property);
}
static void Close ()
{
#ifdef __APPLE__
GList *i = NULL;
#endif
if (participant) {
g_object_unref (participant);
participant = NULL;
}
if (audio_stream) {
g_object_unref (audio_stream);
audio_stream = NULL;
}
if (audio_session) {
g_object_unref (audio_session);
audio_session = NULL;
}
if (video_stream) {
g_object_unref (video_stream);
video_stream = NULL;
}
if (video_session) {
g_object_unref (video_session);
video_session = NULL;
}
if (pipeline) {
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (pipeline);
pipeline = NULL;
}
if (test_pipeline) {
gst_element_set_state (test_pipeline, GST_STATE_NULL);
gst_object_unref (test_pipeline);
test_pipeline = NULL;
}
if (volumeIn) {
gst_object_unref (volumeIn);
volumeIn = NULL;
}
if (volumeOut) {
gst_object_unref (volumeOut);
volumeOut = NULL;
}
if (levelIn) {
gst_object_unref (levelIn);
levelIn = NULL;
}
if (levelOut) {
gst_object_unref (levelOut);
levelOut = NULL;
}
if (preview) {
gst_object_unref (preview);
preview = NULL;
}
if (source_bin) {
gst_element_set_state (source_bin, GST_STATE_NULL);
gst_object_unref (source_bin);
source_bin = NULL;
}
audio_candidates_prepared = FALSE;
audio_codecs_ready = FALSE;
video_candidates_prepared = FALSE;
video_codecs_ready = FALSE;
audio_components_selected = 0;
video_components_selected = 0;
if (audio_local_candidates) {
Tcl_DecrRefCount(audio_local_candidates);
audio_local_candidates = NULL;
}
if (video_local_candidates) {
Tcl_DecrRefCount(video_local_candidates);
video_local_candidates = NULL;
}
if (callback) {
Tcl_DecrRefCount (callback);
callback = NULL;
callback_interp = NULL;
}
if (fsnotifier != NULL) {
g_object_unref (fsnotifier);
}
fsnotifier = NULL;
#ifdef __APPLE__
for (i = g_list_first(cocoa_windows); i; ) {
NSWindow *win = (NSWindow *) i->data;
i = g_list_next(i);
cocoa_windows = g_list_remove(cocoa_windows, win);
[win close];
}
#endif
}
static void
_notify_debug (gchar *format, ...)
{
Tcl_Obj *msg = NULL;
Tcl_Obj *eval = Tcl_NewStringObj ("eval", -1);
Tcl_Obj *args = Tcl_NewListObj (0, NULL);
Tcl_Obj *command[] = {eval, debug_callback, args};
Tcl_Interp *interp = debug_callback_interp;
gchar *message;
va_list ap;
va_start (ap, format);
message = g_strdup_vprintf (format, ap);
va_end (ap);
msg = Tcl_NewStringObj (message, -1);
Tcl_ListObjAppendElement(NULL, args, msg);
if (debug_callback && debug_callback_interp) {
/* Take the callback here in case it gets Closed by the eval */
Tcl_Obj *cbk = debug_callback;
Tcl_IncrRefCount (eval);
Tcl_IncrRefCount (args);
Tcl_IncrRefCount (cbk);
if (Tcl_EvalObjv(interp, 3, command, TCL_EVAL_GLOBAL) == TCL_ERROR) {
g_debug ("Error executing debug handler : %s --- %s",
Tcl_GetStringResult(interp), msg);
}
Tcl_DecrRefCount (cbk);
Tcl_DecrRefCount (args);
Tcl_DecrRefCount (eval);
}
g_free (message);
}
static void
_notify_callback (char *status_msg, Tcl_Obj *obj1, Tcl_Obj *obj2)
{
Tcl_Obj *status = Tcl_NewStringObj (status_msg, -1);
Tcl_Obj *eval = Tcl_NewStringObj ("eval", -1);
Tcl_Obj *empty = Tcl_NewListObj (0, NULL);
Tcl_Obj *args = Tcl_NewListObj (0, NULL);
Tcl_Obj *command[] = {eval, callback, args};
Tcl_Interp *interp = callback_interp;
Tcl_ListObjAppendElement(NULL, args, status);
if (obj1)
Tcl_ListObjAppendElement(NULL, args, obj1);
else
Tcl_ListObjAppendElement(NULL, args, empty);
if (obj2)
Tcl_ListObjAppendElement(NULL, args, obj2);
else
Tcl_ListObjAppendElement(NULL, args, empty);
if (callback && callback_interp) {
/* Take the callback here in case it gets Closed by the eval */
Tcl_Obj *cbk = callback;
Tcl_IncrRefCount (eval);
Tcl_IncrRefCount (args);
Tcl_IncrRefCount (cbk);
if (Tcl_EvalObjv(interp, 3, command, TCL_EVAL_GLOBAL) == TCL_ERROR) {
_notify_debug ("Error executing %s handler : %s", status_msg,
Tcl_GetStringResult(interp));
}
Tcl_DecrRefCount (cbk);
Tcl_DecrRefCount (args);
Tcl_DecrRefCount (eval);
}
}
static void
_notify_level (char *direction, gfloat level)
{
Tcl_Obj *dir = Tcl_NewStringObj (direction, -1);
Tcl_Obj *eval = Tcl_NewStringObj ("eval", -1);
Tcl_Obj *args = Tcl_NewListObj (0, NULL);
Tcl_Obj *command[] = {eval, level_callback, args};
Tcl_Interp *interp = level_callback_interp;
if (level < -1000)
level = -1000;
Tcl_ListObjAppendElement(NULL, args, dir);
Tcl_ListObjAppendElement(NULL, args, Tcl_NewDoubleObj (level));
if (level_callback && level_callback_interp) {
/* Take the callback here in case it gets Closed by the eval */
Tcl_Obj *cbk = level_callback;
Tcl_IncrRefCount (eval);
Tcl_IncrRefCount (args);
Tcl_IncrRefCount (cbk);
if (Tcl_EvalObjv(interp, 3, command, TCL_EVAL_GLOBAL) == TCL_ERROR) {
_notify_debug ("Error executing level handler (%s, %f) : %s",
direction, level, Tcl_GetStringResult(interp));
}
Tcl_DecrRefCount (cbk);
Tcl_DecrRefCount (args);
Tcl_DecrRefCount (eval);
}
}
static void
_notify_error (char *error)
{
Tcl_Obj *obj = Tcl_NewStringObj (error, -1);
_notify_debug ("An error occured : %s", error);
_notify_callback ("ERROR", obj, obj);
Close ();
}
typedef struct {
Tcl_Event header;
char *error;
} FarsightErrorEvent;
static int Farsight_ErrorEventProc (Tcl_Event *evPtr, int flags)
{
FarsightErrorEvent *ev = (FarsightErrorEvent *) evPtr;
char *error = ev->error;
_notify_error (error);
return 1;
}
static void
_notify_error_post (char *error)
{
FarsightErrorEvent *evPtr;
evPtr = (FarsightErrorEvent *)ckalloc(sizeof(FarsightErrorEvent));
evPtr->header.proc = Farsight_ErrorEventProc;
evPtr->header.nextPtr = NULL;
evPtr->error = error;
Tcl_ThreadQueueEvent(main_tid, (Tcl_Event *)evPtr, TCL_QUEUE_TAIL);
Tcl_ThreadAlert(main_tid);
}
static void
_notify_active (char *msg, const char *local, const char *remote)
{
Tcl_Obj *local_candidate = Tcl_NewStringObj (local, -1);
Tcl_Obj *remote_candidate = Tcl_NewStringObj (remote, -1);
_notify_callback (msg, local_candidate, remote_candidate);
}
static void
_notify_prepared (gchar *msg, FsSession *session,
Tcl_Obj *local_candidates)
{
Tcl_Obj *local_codecs = Tcl_NewListObj (0, NULL);
GList *codecs = NULL;
GList *item = NULL;
g_object_get (session, "codecs", &codecs, NULL);
for (item = g_list_first (codecs); item; item = g_list_next (item))
{
FsCodec *codec = item->data;
Tcl_Obj *tcl_codec = NULL;
Tcl_Obj *elements[3];
elements[0] = Tcl_NewStringObj (codec->encoding_name, -1);
elements[1] = Tcl_NewIntObj (codec->id);
elements[2] = Tcl_NewIntObj (codec->clock_rate);
tcl_codec = Tcl_NewListObj (3, elements);
Tcl_ListObjAppendElement(NULL, local_codecs, tcl_codec);
}
fs_codec_list_destroy (codecs);
_notify_callback (msg, local_codecs, local_candidates == NULL ?
Tcl_NewListObj (0, NULL) : Tcl_DuplicateObj(local_candidates));
}
static void
_notify_audio_prepared ()
{
if (audio_codecs_ready && audio_candidates_prepared) {
_notify_prepared ("PREPARED_AUDIO", audio_session, audio_local_candidates);
}
}
static void
_notify_video_prepared ()
{
if (video_codecs_ready && video_candidates_prepared) {
_notify_prepared ("PREPARED_VIDEO", video_session, video_local_candidates);
}
}
static const char *
_fs_candidate_type_to_string (FsCandidateType type)
{
switch (type) {
case FS_CANDIDATE_TYPE_HOST:
return "host";
break;
case FS_CANDIDATE_TYPE_SRFLX:
return "srflx";
break;
case FS_CANDIDATE_TYPE_PRFLX:
return "prflx";
break;
case FS_CANDIDATE_TYPE_RELAY:
return "relay";
break;
default:
return "";
break;
}
}
static void
_new_local_candidate (FsStream *stream, FsCandidate *candidate)
{
Tcl_Obj *tcl_candidate = NULL;
Tcl_Obj *elements[11];
Tcl_Obj **local_candidates = NULL;
if (stream == audio_stream)
local_candidates = &audio_local_candidates;
else
local_candidates = &video_local_candidates;
if (*local_candidates == NULL) {
*local_candidates = Tcl_NewListObj (0, NULL);
Tcl_IncrRefCount(*local_candidates);
}
elements[0] = Tcl_NewStringObj (candidate->foundation == NULL ?
"" : candidate->foundation, -1);
elements[1] = Tcl_NewIntObj (candidate->component_id);
elements[2] = Tcl_NewStringObj (candidate->ip, -1);
elements[3] = Tcl_NewIntObj (candidate->port);
elements[4] = Tcl_NewStringObj (candidate->base_ip, -1);
elements[5] = Tcl_NewIntObj (candidate->base_port);
elements[6] = Tcl_NewStringObj (candidate->proto == FS_NETWORK_PROTOCOL_UDP ?
"UDP" : "TCP", -1);
if (call_type & RTP_ICE6)
elements[7] = Tcl_NewDoubleObj ((gfloat) candidate->priority / 1000);
else
elements[7] = Tcl_NewIntObj (candidate->priority);
elements[8] = Tcl_NewStringObj (
_fs_candidate_type_to_string (candidate->type), -1);
elements[9] = Tcl_NewStringObj (candidate->username == NULL ?
"" : candidate->username, -1);
elements[10] = Tcl_NewStringObj (candidate->password == NULL ?
"" : candidate->password, -1);
tcl_candidate = Tcl_NewListObj (11, elements);
Tcl_ListObjAppendElement(NULL, *local_candidates, tcl_candidate);
}
static void
_local_candidates_prepared (FsStream *stream)
{
if (stream == audio_stream) {
audio_candidates_prepared = TRUE;
_notify_debug ("AUDIO CANDIDATES ARE PREPARED");
_notify_audio_prepared ();
} else {
video_candidates_prepared = TRUE;
_notify_debug ("VIDEO CANDIDATES ARE PREPARED");
_notify_video_prepared ();
}
}
static void
_sink_element_added (GstBin *bin, GstElement *sink, gpointer user_data)
{
g_object_set (sink, "async", FALSE, NULL);
g_object_set (sink, "sync", FALSE, NULL);
}
static gchar *
get_device_property_name (gchar *plugin_name)
{
if (!strcmp (plugin_name, "dshowaudiosrc") ||
!strcmp (plugin_name, "dshowvideosrc"))
return "device-name";
else
return "device";
}
static GstElement * _test_source (gchar *name)
{
GstPropertyProbe *probe = NULL;
GstElement *element = NULL;
GstElement *tee = NULL;
GstElement *queue = NULL;
GstElement *valve = NULL;
GstElement *fakesink = NULL;
GstElement *bin = NULL;
GstPad *bin_pad = NULL;
GstStateChangeReturn state_ret;
GValueArray *arr;
_notify_debug("Testing source %s", name);
if (!strcmp (name, "dtmfsrc") || !strcmp (name, "audiotestsrc") ||
!strcmp (name, "autoaudiosrc") || !strcmp (name, "autovideosrc") ||
!strcmp (name, "videotestsrc") || !strcmp (name, "ximagesrc") ||
!strcmp (name, "dx9screencapsrc") || !strcmp (name, "gdiscreencapsrc"))
return NULL;
element = gst_element_factory_make (name, NULL);
if (element == NULL)
return NULL;
if (g_object_has_property (element, "buffer-time"))
g_object_set(element, "buffer-time", G_GINT64_CONSTANT(20000), NULL);
if (g_object_has_property (element, "is-live"))
g_object_set(element, "is-live", TRUE, NULL);
/* Build a bin and put the element in it with a tee ! fakesink */
bin = gst_bin_new ("source_bin");
if (bin == NULL) {
_notify_debug ("Could not create source bin");
gst_object_unref (element);
return NULL;
}
if (gst_bin_add (GST_BIN (bin), element) == FALSE) {
_notify_debug ("Could not add source to source bin");
gst_object_unref (element);
gst_object_unref (bin);
return NULL;
}
tee = gst_element_factory_make ("tee", NULL);
if (tee == NULL || gst_bin_add (GST_BIN (bin), tee) == FALSE) {
_notify_debug ("Could not add tee to source bin");
if (tee) gst_object_unref (tee);
gst_object_unref (bin);
return NULL;
}
if (gst_element_link(element, tee) == FALSE) {
_notify_debug ("Could not link source to tee");
gst_object_unref (bin);
return NULL;
}
queue = gst_element_factory_make ("queue", NULL);
if (queue == NULL ||
gst_bin_add (GST_BIN (bin), queue) == FALSE) {
_notify_debug ("Could not add queue to source bin");
gst_object_unref (queue);
gst_object_unref (bin);
return NULL;
}
if (gst_element_link(tee, queue) == FALSE) {
_notify_debug ("Could not link tee to queue");
gst_object_unref (bin);
return NULL;
}
fakesink = gst_element_factory_make ("fakesink", NULL);
if (fakesink == NULL) {
_notify_debug ("Could not create fakesink in source bin");
gst_object_unref (bin);
return NULL;
}
g_object_set (fakesink, "async", FALSE, NULL);
g_object_set (fakesink, "sync", FALSE, NULL);
if (gst_bin_add (GST_BIN (bin), fakesink) == FALSE) {
_notify_debug ("Could not add fakesink to source bin");
gst_object_unref (fakesink);
gst_object_unref (bin);
return NULL;
}
if (gst_element_link(queue, fakesink) == FALSE) {
_notify_debug ("Could not link fakesink to source");
gst_object_unref (bin);
return NULL;
}
queue = gst_element_factory_make ("queue", NULL);
if (queue == NULL ||
gst_bin_add (GST_BIN (bin), queue) == FALSE) {
_notify_debug ("Could not add second queue to source bin");
gst_object_unref (queue);
gst_object_unref (bin);
return NULL;
}
if (gst_element_link(tee, queue) == FALSE) {
_notify_debug ("Could not link tee to second queue");
gst_object_unref (bin);
return NULL;
}
valve = gst_element_factory_make ("valve", "hack_valve");
if (valve == NULL ||
gst_bin_add (GST_BIN (bin), valve) == FALSE) {
_notify_debug ("Could not add valve to source bin");
gst_object_unref (valve);
gst_object_unref (bin);
return NULL;
}
if (gst_element_link(queue, valve) == FALSE) {
_notify_debug ("Could not link queue to valve");
gst_object_unref (bin);
return NULL;
}
g_object_set (valve, "drop", TRUE, NULL);
bin_pad = gst_element_get_static_pad (valve, "src");
gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("src", bin_pad));
gst_object_unref (bin_pad);
GST_OBJECT_FLAG_UNSET (bin, GST_ELEMENT_IS_SINK);
/* Test the source */
state_ret = gst_element_set_state (bin, GST_STATE_PLAYING);
if (state_ret == GST_STATE_CHANGE_ASYNC) {
_notify_debug ("Waiting for %s to go to state PLAYING", name);
state_ret = gst_element_get_state (bin, NULL, NULL,
GST_CLOCK_TIME_NONE);
}
if (state_ret != GST_STATE_CHANGE_FAILURE) {
gst_element_set_locked_state (bin, TRUE);
source_bin = bin;
gst_object_ref (bin);
return bin;
}
if (GST_IS_PROPERTY_PROBE (element)) {
probe = GST_PROPERTY_PROBE (element);
if (probe) {
arr = gst_property_probe_probe_and_get_values_name (probe, get_device_property_name(name));
if (arr && arr->n_values > 0) {
guint i;
for (i = 0; i < arr->n_values; ++i) {
const gchar *device;
GValue *val;
val = g_value_array_get_nth (arr, i);
if (val == NULL || !G_VALUE_HOLDS_STRING (val))
continue;
device = g_value_get_string (val);
if (device == NULL)
continue;
g_object_set(element, get_device_property_name(name), device, NULL);
state_ret = gst_element_set_state (bin, GST_STATE_PLAYING);
if (state_ret == GST_STATE_CHANGE_ASYNC) {
_notify_debug ("Waiting for %s to go to state PLAYING", name);
state_ret = gst_element_get_state (bin, NULL, NULL,
GST_CLOCK_TIME_NONE);
}
if (state_ret != GST_STATE_CHANGE_FAILURE) {
g_value_array_free (arr);
gst_element_set_locked_state (bin, TRUE);
source_bin = bin;
gst_object_ref (bin);
return bin;
}
}
g_value_array_free (arr);
}
}
}
gst_element_set_state (bin, GST_STATE_NULL);
gst_object_unref (bin);
return NULL;
}
static GstElement *
_create_audio_source ()
{
GstElement *src = NULL;
GList *sources, *walk;
gchar *priority_sources[] = {"dshowaudiosrc",
"directsoundsrc",
"osxaudiosrc",
"gconfaudiosrc",
"pulsesrc",
"alsasrc",
"oss4src",
"osssrc",
NULL};
gchar **test_source = NULL;
_notify_debug ("Creating audio_source : %s --- %s -- %s",
audio_source_pipeline ? audio_source_pipeline : "(null)",
audio_source ? audio_source : "(null)",
audio_source_device ? audio_source_device : "(null)");
if (audio_source_pipeline) {
GstPad *pad = NULL;
GstBin *bin;
gchar *desc;
GError *error = NULL;
GstStateChangeReturn state_ret;
/* parse the pipeline to a bin */
desc = g_strdup_printf ("bin.( %s ! queue )", audio_source_pipeline);
bin = (GstBin *) gst_parse_launch (desc, &error);
g_free (desc);
if (bin) {
/* find pads and ghost them if necessary */
if ((pad = gst_bin_find_unlinked_pad (bin, GST_PAD_SRC))) {
gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("src", pad));
gst_object_unref (pad);
}
src = GST_ELEMENT (bin);
}
if (error) {
_notify_debug ("Error while creating audio_source pipeline (%d): %s",
error->code, error->message? error->message : "(null)");
}
state_ret = gst_element_set_state (src, GST_STATE_READY);
if (state_ret == GST_STATE_CHANGE_ASYNC) {
_notify_debug ("Waiting for audio_source_pipeline to go to state READY");
state_ret = gst_element_get_state (src, NULL, NULL,
GST_CLOCK_TIME_NONE);
}
if (state_ret == GST_STATE_CHANGE_FAILURE) {
gst_object_unref (src);
return NULL;
}
GST_OBJECT_FLAG_UNSET (src, GST_ELEMENT_IS_SINK);
return src;
} else if (audio_source) {
if (strcmp (audio_source, "-") == 0) {
/* User disabled audio*/
return NULL;
} else {
GstStateChangeReturn state_ret;
src = gst_element_factory_make (audio_source, NULL);
if (src && audio_source_device)
g_object_set(src, get_device_property_name(audio_source), audio_source_device, NULL);
state_ret = gst_element_set_state (src, GST_STATE_READY);
if (state_ret == GST_STATE_CHANGE_ASYNC) {
_notify_debug ("Waiting for %s to go to state READY", audio_source);
state_ret = gst_element_get_state (src, NULL, NULL,
GST_CLOCK_TIME_NONE);
}
if (state_ret == GST_STATE_CHANGE_FAILURE) {
gst_object_unref (src);
return NULL;
}
GST_OBJECT_FLAG_UNSET (src, GST_ELEMENT_IS_SINK);
return src;
}
}
for (test_source = priority_sources; *test_source; test_source++) {
GstElement *element = _test_source (*test_source);
if (element == NULL)
continue;
_notify_debug ("Using audio_source %s", *test_source);
src = element;
break;
}
if (src) {
GST_OBJECT_FLAG_UNSET (src, GST_ELEMENT_IS_SINK);
return src;
}
sources = get_plugins_filtered (TRUE, TRUE);
for (walk = sources; walk; walk = g_list_next (walk)) {
GstElement *element;
GstElementFactory *factory = GST_ELEMENT_FACTORY(walk->data);
element = _test_source (GST_PLUGIN_FEATURE_NAME(factory));
if (element == NULL)
continue;
_notify_debug ("Using audio_source %s", GST_PLUGIN_FEATURE_NAME(factory));
src = element;
break;
}
for (walk = sources; walk; walk = g_list_next (walk)) {
if (walk->data)
gst_object_unref (GST_ELEMENT_FACTORY (walk->data));
}
g_list_free (sources);
if (src)
GST_OBJECT_FLAG_UNSET (src, GST_ELEMENT_IS_SINK);
return src;
}
static GstElement *
_create_audio_sink ()
{
GstElement *snk = NULL;
if (audio_sink_pipeline) {
GstPad *pad = NULL;
GstBin *bin;
gchar *desc;
GError *error = NULL;
/* parse the pipeline to a bin */
desc = g_strdup_printf ("bin.( %s ! queue )", audio_sink_pipeline);
bin = (GstBin *) gst_parse_launch (desc, &error);
g_free (desc);
if (bin) {
/* find pads and ghost them if necessary */
if ((pad = gst_bin_find_unlinked_pad (bin, GST_PAD_SINK))) {
gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("sink", pad));
gst_object_unref (pad);
}
snk = GST_ELEMENT (bin);
}
if (error) {
_notify_debug ("Error while creating audio_sink pipeline (%d): %s",
error->code, error->message ? error->message : "(null)");
}
} else if (audio_sink && strcmp (audio_sink, "autoaudiosink") != 0) {
snk = gst_element_factory_make (audio_sink, NULL);
if (snk && audio_sink_device)
g_object_set(snk, "device", audio_sink_device, NULL);
if (snk) {
if (g_object_has_property (snk, "sync")) {
g_object_set(snk, "sync", FALSE, NULL);
g_object_set(snk, "async", FALSE, NULL);
}
}
}
if (snk == NULL) {
snk = gst_element_factory_make ("autoaudiosink", NULL);
g_signal_connect (snk, "element-added",
G_CALLBACK (_sink_element_added), NULL);
}
return snk;
}
static void
_audio_src_pad_added (FsStream *self, GstPad *pad,
FsCodec *codec, gpointer user_data)
{
GstElement *pipeline = user_data;
GstElement *snk = NULL;
GstElement *convert = gst_element_factory_make ("audioconvert", NULL);
GstElement *resample = gst_element_factory_make ("audioresample", NULL);
GstElement *convert2 = gst_element_factory_make ("audioconvert", NULL);
GstPad *sink_pad = NULL;
GstPadLinkReturn ret;
snk = _create_audio_sink ();
if (snk == NULL) {
_notify_error_post ("Could not create audio_sink");
if (convert) gst_object_unref (convert);
if (resample) gst_object_unref (resample);
if (convert2) gst_object_unref (convert2);
return;
}
if (gst_bin_add (GST_BIN (pipeline), snk) == FALSE) {
_notify_error_post ("Could not add audio_sink to pipeline");
if (snk) gst_object_unref (snk);
if (convert) gst_object_unref (convert);
if (resample) gst_object_unref (resample);
if (convert2) gst_object_unref (convert2);
return;
}
if (gst_bin_add (GST_BIN (pipeline), convert) == FALSE) {
_notify_error_post ("Could not add converter to pipeline");
if (convert) gst_object_unref (convert);
if (resample) gst_object_unref (resample);
if (convert2) gst_object_unref (convert2);
return;
}
if (gst_bin_add (GST_BIN (pipeline), resample) == FALSE) {
_notify_error_post ("Could not add resampler to pipeline");
if (resample) gst_object_unref (resample);
if (convert2) gst_object_unref (convert2);
return;
}
if (gst_bin_add (GST_BIN (pipeline), convert2) == FALSE) {
_notify_error_post ("Could not add second converter to pipeline");
if (convert2) gst_object_unref (convert2);
return;
}
volumeOut = gst_element_factory_make ("volume", NULL);
if (volumeOut) {
gst_object_ref (volumeOut);
if (gst_bin_add (GST_BIN (pipeline), volumeOut) == FALSE) {
_notify_debug ("Could not add output volume to pipeline");
gst_object_unref (volumeOut);
volumeOut = NULL;
goto no_volume;
}
if (gst_element_link(volumeOut, convert) == FALSE) {
_notify_debug ("Could not link volume out to converter");
gst_bin_remove (GST_BIN (pipeline), volumeOut);
gst_object_unref (volumeOut);
volumeOut = NULL;
goto no_volume;
}
sink_pad = gst_element_get_static_pad (volumeOut, "sink");
} else {
no_volume:
sink_pad = gst_element_get_static_pad (convert, "sink");
}
ret = gst_pad_link (pad, sink_pad);
gst_object_unref (sink_pad);
if (ret != GST_PAD_LINK_OK) {
_notify_error_post ("Could not link volume/sink to fsrtpconference sink pad");
return;
}
if (gst_element_link(convert, resample) == FALSE) {
_notify_error_post ("Could not link converter to resampler");
return;
}
if (gst_element_link(resample, convert2) == FALSE) {
_notify_error_post ("Could not link resampler to second converter");
return;
}
levelOut = gst_element_factory_make ("level", NULL);
if (levelOut) {
gst_object_ref (levelOut);
if (gst_bin_add (GST_BIN (pipeline), levelOut) == FALSE) {
_notify_debug ("Could not add output level to pipeline");
gst_object_unref (levelOut);
levelOut = NULL;
goto no_level;
}
g_object_set (G_OBJECT (levelOut), "message", TRUE, NULL);
if (gst_element_link(convert2, levelOut) == FALSE) {
_notify_debug ("Could not link level out to converter");
gst_bin_remove (GST_BIN (pipeline), levelOut);
gst_object_unref (levelOut);
levelOut = NULL;
goto no_level;
}
if (gst_element_link(levelOut, snk) == FALSE) {
_notify_debug ("Could not link audio_sink to level out");
gst_element_unlink(convert2, levelOut);
gst_bin_remove (GST_BIN (pipeline), levelOut);
gst_object_unref (levelOut);
levelOut = NULL;
goto no_level;
}
} else {
no_level:
if (gst_element_link(convert2, snk) == FALSE) {
_notify_error_post ("Could not link audio_sink to converter");
return;
}
}
if (gst_element_set_state (volumeOut, GST_STATE_PLAYING) ==
GST_STATE_CHANGE_FAILURE) {
_notify_error_post ("Unable to set volume OUT to PLAYING");
return;
}
if (gst_element_set_state (convert, GST_STATE_PLAYING) ==
GST_STATE_CHANGE_FAILURE) {
_notify_error_post ("Unable to set converter to PLAYING");
return;
}
if (gst_element_set_state (resample, GST_STATE_PLAYING) ==
GST_STATE_CHANGE_FAILURE) {
_notify_error_post ("Unable to set resampler to PLAYING");
return;
}
if (gst_element_set_state (convert2, GST_STATE_PLAYING) ==
GST_STATE_CHANGE_FAILURE) {
_notify_error_post ("Unable to set second converter to PLAYING");
return;
}
if (gst_element_set_state (snk, GST_STATE_PLAYING) ==
GST_STATE_CHANGE_FAILURE) {
_notify_error_post ("Unable to set audio_sink to PLAYING");
return;
}
if (levelOut) {
if (gst_element_set_state (levelOut, GST_STATE_PLAYING) ==
GST_STATE_CHANGE_FAILURE) {
_notify_error_post ("Unable to set audio_sink to PLAYING");
return;
}
}
}
static GstElement *
_create_video_source ()
{
GstElement *src = NULL;
GList *sources, *walk;
gchar *priority_sources[] = {"dshowvideosrc",
"ksvideosrc",
"gconfvideosrc",
"gconfv4l2src",
"v4l2src",
"v4lsrc",
NULL};
gchar **test_source = NULL;
GstElement *tee = NULL;
GstElement *colorspace = NULL;
GstElement *capsfilter = NULL;
GstElement *videoscale = NULL;
GstElement *queue = NULL;
GstCaps *caps = NULL;
GstElement *video_bin = NULL;
GstPad *bin_pad = NULL;
_notify_debug ("Creating video_source : %s --- %s -- %s",
video_source_pipeline ? video_source_pipeline : "(null)",
video_source ? video_source : "(null)",
video_source_device ? video_source_device : "(null)");
if (video_source_pipeline) {
GstPad *pad = NULL;
GstBin *bin;
gchar *desc;
GError *error = NULL;
GstStateChangeReturn state_ret;
/* parse the pipeline to a bin */
desc = g_strdup_printf ("bin.( %s ! queue )", video_source_pipeline);
bin = (GstBin *) gst_parse_launch (desc, &error);
g_free (desc);
if (bin) {
/* find pads and ghost them if necessary */
if ((pad = gst_bin_find_unlinked_pad (bin, GST_PAD_SRC))) {
gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("src", pad));
gst_object_unref (pad);
}
src = GST_ELEMENT (bin);
}
if (error) {
_notify_debug ("Error while creating video_source pipeline (%d): %s",
error->code, error->message? error->message : "(null)");
}
state_ret = gst_element_set_state (src, GST_STATE_READY);
if (state_ret == GST_STATE_CHANGE_ASYNC) {
_notify_debug ("Waiting for video_source_pipeline to go to state READY");
state_ret = gst_element_get_state (src, NULL, NULL,
GST_CLOCK_TIME_NONE);
}
if (state_ret == GST_STATE_CHANGE_FAILURE) {
gst_object_unref (src);
return NULL;
}
goto add_preview;
} else if (video_source) {
if (strcmp (video_source, "-") == 0) {
/* User disabled video */
return NULL;
} else {
GstStateChangeReturn state_ret;
src = gst_element_factory_make (video_source, NULL);
if (src && video_source_device)
g_object_set(src, get_device_property_name(video_source), video_source_device, NULL);
state_ret = gst_element_set_state (src, GST_STATE_READY);
if (state_ret == GST_STATE_CHANGE_ASYNC) {
_notify_debug ("Waiting for %s to go to state READY", video_source);
state_ret = gst_element_get_state (src, NULL, NULL,
GST_CLOCK_TIME_NONE);
}
if (state_ret == GST_STATE_CHANGE_FAILURE) {
gst_object_unref (src);
return NULL;
}
goto add_preview;
}
}
for (test_source = priority_sources; *test_source; test_source++) {
GstElement *element = _test_source (*test_source);
if (element == NULL)
continue;
_notify_debug ("Using video_source %s", *test_source);
src = element;
break;
}
if (src)
goto add_preview;
sources = get_plugins_filtered (TRUE, FALSE);
for (walk = sources; walk; walk = g_list_next (walk)) {
GstElement *element;
GstElementFactory *factory = GST_ELEMENT_FACTORY(walk->data);
element = _test_source (GST_PLUGIN_FEATURE_NAME(factory));
if (element == NULL)
continue;
_notify_debug ("Using video_source %s", GST_PLUGIN_FEATURE_NAME(factory));
src = element;
break;
}
for (walk = sources; walk; walk = g_list_next (walk)) {
if (walk->data)
gst_object_unref (GST_ELEMENT_FACTORY (walk->data));
}
g_list_free (sources);
if (src == NULL)
return NULL;
add_preview:
video_bin = gst_bin_new ("video_bin");
if (video_bin == NULL) {
_notify_debug ("Could not create video bin");
gst_element_set_state (src, GST_STATE_NULL);
gst_object_unref (src);
return NULL;
}
if (gst_bin_add (GST_BIN (video_bin), src) == FALSE) {
_notify_debug ("Could not add video source to video bin");
gst_element_set_state (src, GST_STATE_NULL);
gst_object_unref (src);
gst_object_unref (video_bin);
return NULL;
}
colorspace = gst_element_factory_make ("ffmpegcolorspace", NULL);
if (colorspace == NULL ||
gst_bin_add (GST_BIN (video_bin), colorspace) == FALSE) {
_notify_debug ("Could not add colorspace to video bin");
gst_element_set_locked_state (src, FALSE);
gst_object_unref (colorspace);
gst_element_set_state (video_bin, GST_STATE_NULL);
gst_object_unref (video_bin);
return NULL;
}
if (gst_element_link(src, colorspace) == FALSE) {
_notify_debug ("Could not link video source to colorspace");
gst_element_set_locked_state (src, FALSE);
gst_element_set_state (video_bin, GST_STATE_NULL);
gst_object_unref (video_bin);
return NULL;
}
videoscale = gst_element_factory_make ("videoscale", NULL);
if (videoscale == NULL ||
gst_bin_add (GST_BIN (video_bin), videoscale) == FALSE) {
_notify_debug ("Could not add videoscale to video bin");
gst_object_unref (videoscale);
gst_element_set_locked_state (src, FALSE);
gst_element_set_state (video_bin, GST_STATE_NULL);
gst_object_unref (video_bin);
return NULL;
}
if (gst_element_link(colorspace, videoscale) == FALSE) {
_notify_debug ("Could not link colorspace to videoscale");
gst_element_set_locked_state (src, FALSE);
gst_element_set_state (video_bin, GST_STATE_NULL);
gst_object_unref (video_bin);
return NULL;
}
capsfilter = gst_element_factory_make ("capsfilter", "capsfilter");
if (capsfilter == NULL ||
gst_bin_add (GST_BIN (video_bin), capsfilter) == FALSE) {
_notify_debug ("Could not add capsfilter to video bin");
gst_object_unref (capsfilter);
gst_element_set_locked_state (src, FALSE);
gst_element_set_state (video_bin, GST_STATE_NULL);
gst_object_unref (video_bin);
return NULL;
}
if (gst_element_link(videoscale, capsfilter) == FALSE) {
_notify_debug ("Could not link videoscale to capsfilter");
gst_element_set_locked_state (src, FALSE);
gst_element_set_state (video_bin, GST_STATE_NULL);
gst_object_unref (video_bin);
return NULL;
}
caps = gst_caps_new_simple ("video/x-raw-yuv",
"width", G_TYPE_INT, 176,
"height", G_TYPE_INT, 144,
NULL);
g_object_set (capsfilter, "caps", caps, NULL);
tee = gst_element_factory_make ("tee", NULL);
if (tee == NULL || gst_bin_add (GST_BIN (video_bin), tee) == FALSE) {
_notify_debug ("Could not add tee to video bin");
if (tee) gst_object_unref (tee);
gst_element_set_locked_state (src, FALSE);
gst_element_set_state (video_bin, GST_STATE_NULL);
gst_object_unref (video_bin);
return NULL;
}
if (gst_element_link(capsfilter, tee) == FALSE) {
_notify_debug ("Could not link capsfilter to tee");
gst_element_set_locked_state (src, FALSE);
gst_element_set_state (video_bin, GST_STATE_NULL);
gst_object_unref (video_bin);
return NULL;
}
queue = gst_element_factory_make ("queue", NULL);
if (queue == NULL ||
gst_bin_add (GST_BIN (video_bin), queue) == FALSE) {
_notify_debug ("Could not add preview queue to video bin");
gst_object_unref (queue);
gst_element_set_locked_state (src, FALSE);
gst_element_set_state (video_bin, GST_STATE_NULL);
gst_object_unref (video_bin);
return NULL;
}
if (gst_element_link(tee, queue) == FALSE) {
_notify_debug ("Could not link tee to preview queue");
gst_element_set_locked_state (src, FALSE);
gst_element_set_state (video_bin, GST_STATE_NULL);
gst_object_unref (video_bin);
return NULL;
}
colorspace = gst_element_factory_make ("ffmpegcolorspace", NULL);
if (colorspace == NULL ||
gst_bin_add (GST_BIN (video_bin), colorspace) == FALSE) {
_notify_debug ("Could not add colorspace to video bin");
gst_object_unref (colorspace);
gst_element_set_locked_state (src, FALSE);
gst_element_set_state (video_bin, GST_STATE_NULL);
gst_object_unref (video_bin);
return NULL;
}
if (gst_element_link(queue, colorspace) == FALSE) {
_notify_debug ("Could not link preview queue to colorspace");
gst_element_set_locked_state (src, FALSE);
gst_element_set_state (video_bin, GST_STATE_NULL);
gst_object_unref (video_bin);
return NULL;
}
#ifdef __APPLE__
preview = gst_element_factory_make ("osxvideosink", NULL);
if (preview) {
g_object_set (preview, "async", FALSE, NULL);
g_object_set (preview, "sync", FALSE, NULL);
}
#else
preview = gst_element_factory_make ("autovideosink", NULL);
if (preview) {
g_signal_connect (preview, "element-added",
G_CALLBACK (_sink_element_added), NULL);
}
#endif
if (preview == NULL) {
_notify_debug ("Could not create preview window");
gst_element_set_locked_state (src, FALSE);
gst_element_set_state (video_bin, GST_STATE_NULL);
gst_object_unref (video_bin);
return NULL;
}
if (gst_bin_add (GST_BIN (video_bin), preview) == FALSE) {
_notify_debug ("Could not add preview to video bin");
if (preview) gst_object_unref (preview);
preview = NULL;
gst_element_set_locked_state (src, FALSE);
gst_element_set_state (video_bin, GST_STATE_NULL);
gst_object_unref (video_bin);
return NULL;
}
gst_object_ref (preview);
if (gst_element_link(colorspace, preview) == FALSE) {
_notify_debug ("Could not link preview to video source");
if (preview) gst_object_unref (preview);
preview = NULL;
gst_element_set_locked_state (src, FALSE);
gst_element_set_state (video_bin, GST_STATE_NULL);
gst_object_unref (video_bin);
return NULL;
}
queue = gst_element_factory_make ("queue", NULL);
if (queue == NULL ||
gst_bin_add (GST_BIN (video_bin), queue) == FALSE) {
_notify_debug ("Could not add video queue to video bin");
gst_object_unref (queue);
gst_element_set_locked_state (src, FALSE);
gst_element_set_state (video_bin, GST_STATE_NULL);
gst_object_unref (video_bin);
return NULL;
}
if (gst_element_link(tee, queue) == FALSE) {
_notify_debug ("Could not link tee to video queue");
gst_element_set_locked_state (src, FALSE);
gst_element_set_state (video_bin, GST_STATE_NULL);
gst_object_unref (video_bin);
return NULL;
}
bin_pad = gst_element_get_static_pad (queue, "src");
gst_element_add_pad (GST_ELEMENT (video_bin), gst_ghost_pad_new ("src", bin_pad));
gst_object_unref (bin_pad);
GST_OBJECT_FLAG_UNSET (video_bin, GST_ELEMENT_IS_SINK);
return video_bin;
}
static GstElement *
_create_video_sink ()
{
GstElement *snk = NULL;
if (video_sink_pipeline) {
GstPad *pad = NULL;
GstBin *bin;
gchar *desc;
GError *error = NULL;
/* parse the pipeline to a bin */
desc = g_strdup_printf ("bin.( %s ! queue )", video_sink_pipeline);
bin = (GstBin *) gst_parse_launch (desc, &error);
g_free (desc);
if (bin) {
/* find pads and ghost them if necessary */
if ((pad = gst_bin_find_unlinked_pad (bin, GST_PAD_SINK))) {
gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("sink", pad));
gst_object_unref (pad);
}
snk = GST_ELEMENT (bin);
}
if (error) {
_notify_debug ("Error while creating video_sink pipeline (%d): %s",
error->code, error->message ? error->message : "(null)");
}
} else if (video_sink && strcmp (video_sink, "autovideosink") != 0) {
snk = gst_element_factory_make (video_sink, NULL);
if (snk) {
if (g_object_has_property (snk, "sync")) {
g_object_set (snk, "async", FALSE, NULL);
g_object_set (snk, "sync", FALSE, NULL);
}
}
}
if (snk == NULL) {
#ifdef __APPLE__
snk = gst_element_factory_make ("osxvideosink", NULL);
if (snk) {
g_object_set (snk, "async", FALSE, NULL);
g_object_set (snk, "sync", FALSE, NULL);
}
#else
snk = gst_element_factory_make ("autovideosink", NULL);
if (snk) {
g_signal_connect (snk, "element-added",
G_CALLBACK (_sink_element_added), NULL);
}
#endif
}
return snk;
}
static void
_video_src_pad_added (FsStream *self, GstPad *pad,
FsCodec *codec, gpointer user_data)
{
GstElement *pipeline = user_data;
GstElement *snk = NULL;
GstElement *colorspace = gst_element_factory_make ("ffmpegcolorspace", NULL);
GstPad *sink_pad = NULL;
GstPadLinkReturn ret;
snk = _create_video_sink ();
if (snk == NULL) {
_notify_error_post ("Could not create video_sink");
if (colorspace) gst_object_unref (colorspace);
return;
}
if (gst_bin_add (GST_BIN (pipeline), snk) == FALSE) {
_notify_error_post ("Could not add video_sink to pipeline");
if (snk) gst_object_unref (snk);
if (colorspace) gst_object_unref (colorspace);
return;
}
if (gst_bin_add (GST_BIN (pipeline), colorspace) == FALSE) {
_notify_error_post ("Could not add colorspace to pipeline");
if (colorspace) gst_object_unref (colorspace);
return;
}
sink_pad = gst_element_get_static_pad (colorspace, "sink");
ret = gst_pad_link (pad, sink_pad);
gst_object_unref (sink_pad);
if (ret != GST_PAD_LINK_OK) {
_notify_error_post ("Could not link colorspace to fsrtpconference sink pad");
return;
}
if (gst_element_link(colorspace, snk) == FALSE) {
_notify_error_post ("Could not link converter to resampler");
return;
}
if (gst_element_set_state (colorspace, GST_STATE_PLAYING) ==
GST_STATE_CHANGE_FAILURE) {
_notify_error_post ("Unable to set converter to PLAYING");
return;
}
if (gst_element_set_state (snk, GST_STATE_PLAYING) ==
GST_STATE_CHANGE_FAILURE) {
_notify_error_post ("Unable to set audio_sink to PLAYING");
return;
}
}
static void
_conference_element_added (FsElementAddedNotifier *notifier,
GstBin *bin,
GstElement *element,
gpointer user_data)
{
GstElementFactory *factory;
const gchar *name;
factory = gst_element_get_factory (element);
name = gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory));
if (strcmp (name, "ffenc_h263") == 0) {
/* Ensure that the encoder works with rtp */
g_object_set (element,
"rtp-payload-size", 1,
NULL);
} else if (strcmp (name, "rtph263pay") == 0) {
/* Only mode A in h263 payloading is supported by WLM */
g_object_set (element,
"modea-only", TRUE,
"mtu", 1024,
NULL);
} else if (strcmp (name, "gstrtpbin") == 0) {
/* Lower the jitterbuffer latency to make it more suitable for video
* conferencing */
g_object_set (element,
"latency", 100,
NULL);
}
}
static void
_codecs_ready (FsSession *session)
{
if (session == audio_session) {
audio_codecs_ready = TRUE;
_notify_debug ("AUDIO CODECS ARE READY");
_notify_audio_prepared ();
} else {
video_codecs_ready = TRUE;
_notify_debug ("VIDEO CODECS ARE READY");
_notify_video_prepared ();
}
}
typedef struct {
Tcl_Event header;
GstMessage *message;
} FarsightBusEvent;
static int Farsight_BusEventProc (Tcl_Event *evPtr, int flags)
{
FarsightBusEvent *ev = (FarsightBusEvent *) evPtr;
GstMessage *message = ev->message;
/* If we destroy the pipeline in an async operation, we must ignore the messages */
if (pipeline == NULL && test_pipeline == NULL)
goto done;
switch (GST_MESSAGE_TYPE (message))
{
case GST_MESSAGE_ELEMENT:
{
const GstStructure *s = gst_message_get_structure (message);
if (gst_structure_has_name (s, PREFIX "-error")) {
const GValue *errorvalue, *debugvalue, *error_no;
error_no = gst_structure_get_value (message->structure, "error-no");
errorvalue = gst_structure_get_value (message->structure, "error-msg");
debugvalue = gst_structure_get_value (message->structure, "debug-msg");
#ifdef HAVE_FARSTREAM
if (g_value_get_enum (error_no)) {
#else
if (g_value_get_enum (error_no) != FS_ERROR_UNKNOWN_CNAME) {
#endif /* HAVE_FARSTREAM */
_notify_debug ("Error on BUS (%d) %s .. %s", g_value_get_enum (error_no),
g_value_get_string (errorvalue),
g_value_get_string (debugvalue));
_notify_error (LIBNAME " error");
}
} else if (gst_structure_has_name (s, PREFIX "-new-local-candidate")) {
FsStream *stream;
FsCandidate *candidate;
const GValue *value;
value = gst_structure_get_value (s, "stream");
stream = g_value_get_object (value);
value = gst_structure_get_value (s, "candidate");
candidate = g_value_get_boxed (value);
_new_local_candidate (stream, candidate);
} else if (gst_structure_has_name (s,
PREFIX "-local-candidates-prepared")) {
FsStream *stream;
const GValue *value;
value = gst_structure_get_value (s, "stream");
stream = g_value_get_object (value);
_local_candidates_prepared (stream);
} else if (gst_structure_has_name (s, PREFIX "-codecs-changed")) {
gboolean ready;
if (!audio_codecs_ready) {
g_object_get (audio_session, "codecs-ready", &ready, NULL);
if (ready) {
_codecs_ready (audio_session);
}
}
if (video_session != NULL && !video_codecs_ready) {
g_object_get (video_session, "codecs-ready", &ready, NULL);
if (ready) {
_codecs_ready (video_session);
}
}
} else if (gst_structure_has_name (s, PREFIX "-new-active-candidate-pair")) {
FsCandidate *local;
FsCandidate *remote;
FsStream *stream;
const GValue *value;
value = gst_structure_get_value (s, "local-candidate");
local = g_value_get_boxed (value);
value = gst_structure_get_value (s, "remote-candidate");
remote = g_value_get_boxed (value);
value = gst_structure_get_value (s, "stream");
stream = g_value_get_object (value);
_notify_debug ("New active candidate pair (%s) : ",
stream == audio_stream ? "audio" : "video");
_notify_debug ("Local candidate: %s %d %s %d %s %d %s %d %s %s %s\n",
local->foundation == NULL ? "-" : local->foundation,
local->component_id,
local->ip,
local->port,
local->base_ip == NULL ? "-" : local->base_ip,
local->base_port,
local->proto == FS_NETWORK_PROTOCOL_UDP ? "UDP" : "TCP",
local->priority,
_fs_candidate_type_to_string (local->type),
local->username == NULL ? "-" : local->username,
local->password == NULL ? "-" : local->password);
_notify_debug ("Remote candidate: %s %d %s %d %s %d %s %d %s %s %s\n",
remote->foundation == NULL ? "-" : remote->foundation,
remote->component_id,
remote->ip,
remote->port,
remote->base_ip == NULL ? "-" : remote->base_ip,
remote->base_port,
remote->proto == FS_NETWORK_PROTOCOL_UDP ? "UDP" : "TCP",
remote->priority,
_fs_candidate_type_to_string (remote->type),
remote->username == NULL ? "-" : remote->username,
remote->password == NULL ? "-" : remote->password);
if (stream == audio_stream) {
if (++audio_components_selected == 2) {
_notify_active ("AUDIO_ACTIVE", local->foundation, remote->foundation);
}
} else {
if (++video_components_selected == 2) {
_notify_active ("VIDEO_ACTIVE", local->foundation, remote->foundation);
}
}
} else if (gst_structure_has_name (s, "level")) {
gint channels;
gdouble rms_dB;
gdouble rms;
const GValue *list;
const GValue *value;
gint i;
/* we can get the number of channels as the length of any of the value
* lists */
list = gst_structure_get_value (s, "rms");
channels = gst_value_list_get_size (list);
rms = 0;
for (i = 0; i < channels; ++i) {
list = gst_structure_get_value (s, "rms");
value = gst_value_list_get_value (list, i);
rms_dB = g_value_get_double (value);
rms += rms_dB;
}
if (GST_MESSAGE_SRC (message) == GST_OBJECT(levelIn)) {
_notify_level ("IN", (gfloat) (rms / channels));
} else if (GST_MESSAGE_SRC (message) == GST_OBJECT(levelOut)) {
_notify_level ("OUT", (gfloat) (rms / channels));
}
}
#ifdef __APPLE__
else if (gst_structure_has_name (s, "have-ns-view")) {
NSWindow * win = nil;
NSView *nsview = nil;
NSRect rect;
unsigned int mask = NSResizableWindowMask |
NSTexturedBackgroundWindowMask |
NSMiniaturizableWindowMask;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
nsview = (NSView *)g_value_get_pointer(gst_structure_get_value (s, "nsview"));
if (nsview) {
rect.origin.x = 100.0;
rect.origin.y = 100.0;
rect.size.width = 352.0 ;
rect.size.height = 288.0;
NSApplicationLoad();
win =[[NSWindow alloc]
initWithContentRect: rect
styleMask: mask
backing: NSBackingStoreBuffered
defer: NO
screen: nil];
[win setContentView:nsview];
[win makeKeyAndOrderFront:nil];
cocoa_windows = g_list_append(cocoa_windows, win);
}
[pool release];
}
#endif
}
break;
case GST_MESSAGE_ERROR:
{
GError *error = NULL;
gchar *debug = NULL;
gst_message_parse_error (message, &error, &debug);
_notify_debug ("Got an error on the BUS (%d): %s (%s)", error->code,
error->message, debug);
g_error_free (error);
g_free (debug);
_notify_error ("Gstreamer error");
}
break;
default:
break;
}
done:
gst_message_unref (message);
return 1;
}
struct xid_data
{
GstElement *src;
gulong window_id;
gboolean found;
};
static void
set_window_xid (gpointer data, gpointer user_data)
{
GstXOverlay *xov = GST_X_OVERLAY (data);
struct xid_data *xiddata = (struct xid_data *) user_data;
if (GST_ELEMENT_CAST(xov) == xiddata->src) {
gst_x_overlay_set_xwindow_id (xov, xiddata->window_id);
xiddata->found = TRUE;
}
}
static GstBusSyncReply
_bus_callback (GstBus *bus, GstMessage *message, gpointer user_data)
{
FarsightBusEvent *evPtr;
GstBusSyncReply ret = GST_BUS_PASS;
switch (GST_MESSAGE_TYPE (message))
{
case GST_MESSAGE_ELEMENT:
{
const GstStructure *s = gst_message_get_structure (message);
if (gst_structure_has_name (s, PREFIX "-error")) {
goto drop;
} else if (gst_structure_has_name (s, PREFIX "-new-local-candidate")) {
goto drop;
} else if (gst_structure_has_name (s,
PREFIX "-local-candidates-prepared")) {
goto drop;
} else if (gst_structure_has_name (s, PREFIX "-codecs-changed")) {
goto drop;
} else if (gst_structure_has_name (s, PREFIX "-new-active-candidate-pair")) {
goto drop;
} else if (gst_structure_has_name (s, "level")) {
goto drop;
} else if (gst_structure_has_name (s, "prepare-xwindow-id")) {
struct xid_data xiddata;
GstIterator *it = NULL;
xiddata.src = GST_ELEMENT (GST_MESSAGE_SRC (message));
xiddata.window_id = video_preview_xid;
xiddata.found = FALSE;
if (preview) {
it = gst_bin_iterate_all_by_interface (GST_BIN (preview),
GST_TYPE_X_OVERLAY);
while (gst_iterator_foreach (it, set_window_xid, &xiddata) ==
GST_ITERATOR_RESYNC)
gst_iterator_resync (it);
gst_iterator_free (it);
}
if (xiddata.found == FALSE) {
gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (xiddata.src), video_sink_xid);
}
ret = GST_BUS_DROP;
}
#ifdef __APPLE__
else if (gst_structure_has_name (s, "have-ns-view")) {
goto drop;
}
#endif
}
break;
case GST_MESSAGE_ERROR:
goto drop;
break;
default:
break;
}
return ret;
drop:
ret = GST_BUS_DROP;
evPtr = (FarsightBusEvent *)ckalloc(sizeof(FarsightBusEvent));
evPtr->header.proc = Farsight_BusEventProc;
evPtr->header.nextPtr = NULL;
evPtr->message = message;
Tcl_ThreadQueueEvent(main_tid, (Tcl_Event *)evPtr, TCL_QUEUE_TAIL);
Tcl_ThreadAlert(main_tid);
return ret;
}
static GstElement *_find_source (GstElement *src)
{
GstElement *source = NULL;
if (GST_IS_BIN (src)) {
GstIterator *it = gst_bin_iterate_sources (GST_BIN(src));
gboolean done = FALSE;
GstElement *item = NULL;
while (!done) {
switch (gst_iterator_next (it, &item)) {
case GST_ITERATOR_OK:
source = item;
gst_object_unref (item);
done = TRUE;
break;
case GST_ITERATOR_RESYNC:
gst_iterator_resync (it);
break;
case GST_ITERATOR_ERROR:
done = TRUE;
break;
case GST_ITERATOR_DONE:
done = TRUE;
break;
}
}
gst_iterator_free (it);
if (source == NULL)
return src;
} else {
return src;
}
return _find_source (source);
}
static GstElement *_find_sink (GstElement *snk)
{
GstElement *sink = NULL;
if (GST_IS_BIN (snk)) {
GstIterator *it = gst_bin_iterate_sinks (GST_BIN(snk));
gboolean done = FALSE;
GstElement *item = NULL;
while (!done) {
switch (gst_iterator_next (it, &item)) {
case GST_ITERATOR_OK:
sink = item;
gst_object_unref (item);
done = TRUE;
break;
case GST_ITERATOR_RESYNC:
gst_iterator_resync (it);
break;
case GST_ITERATOR_ERROR:
done = TRUE;
break;
case GST_ITERATOR_DONE:
done = TRUE;
break;
}
}
gst_iterator_free (it);
if (sink == NULL)
return snk;
} else {
return snk;
}
return _find_sink (sink);
}
int Farsight_TestAudio _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]))
{
GstBus *bus = NULL;
GstElement *src = NULL;
GstPad *sinkpad = NULL, *srcpad = NULL;
GstPad *tempsink;
GstElement *snk = NULL;
GstElement *src_convert = NULL;
GstElement *src_resample = NULL;
GstElement *src_convert2 = NULL;
GstElement *sink_convert = NULL;
GstElement *sink_resample = NULL;
GstElement *sink_convert2 = NULL;
GstElement *capsfilter = NULL;
GstPadLinkReturn ret;
gint state = 0;
Tcl_Obj *source = NULL;
Tcl_Obj *sink = NULL;
Tcl_Obj *result = NULL;
GstElementFactory *factory = NULL;
// We verify the arguments
if( objc != 1) {
Tcl_WrongNumArgs (interp, 1, objv, "");
return TCL_ERROR;
}
main_tid = Tcl_GetCurrentThread();
if (pipeline != NULL) {
Tcl_AppendResult (interp, "Already started" , (char *) NULL);
return TCL_ERROR;
}
if (test_pipeline != NULL) {
Tcl_AppendResult (interp, "Already testing" , (char *) NULL);
return TCL_ERROR;
}
test_pipeline = gst_pipeline_new ("pipeline");
if (test_pipeline == NULL) {
Tcl_AppendResult (interp, "Couldn't create gstreamer pipeline" ,
(char *) NULL);
goto error;
}
bus = gst_element_get_bus (test_pipeline);
gst_bus_set_sync_handler (bus, _bus_callback, NULL);
gst_object_unref (bus);
if (gst_element_set_state (test_pipeline, GST_STATE_PLAYING) ==
GST_STATE_CHANGE_FAILURE) {
Tcl_AppendResult (interp, "Unable to set pipeline to PLAYING",
(char *) NULL);
goto error;
}
src = _create_audio_source ();
if (src == NULL) {
_notify_debug ("Couldn't create audio source, using audiotestsrc");
src = gst_element_factory_make ("audiotestsrc", NULL);
}
if (gst_bin_add (GST_BIN (test_pipeline), src) == FALSE) {
_notify_debug ("Couldn't add audio_source to pipeline");
gst_object_unref (src);
src = NULL;
goto error;
}
volumeIn = gst_element_factory_make ("volume", NULL);
if (volumeIn) {
gst_object_ref (volumeIn);
if (gst_bin_add (GST_BIN (test_pipeline), volumeIn) == FALSE) {
_notify_debug ("Could not add input volume to pipeline");
gst_object_unref (volumeIn);
volumeIn = NULL;
goto no_volume_in;
}
srcpad = gst_element_get_static_pad (volumeIn, "src");
if (gst_element_link(src, volumeIn) == FALSE) {
_notify_debug ("Could not link audio_source to volume");
gst_bin_remove (GST_BIN (test_pipeline), volumeIn);
gst_object_unref (volumeIn);
volumeIn = NULL;
goto no_volume_in;
}
} else {
_notify_debug ("Couldn't create volume In elemnt");
no_volume_in:
srcpad = gst_element_get_static_pad (src, "src");
}
levelIn = gst_element_factory_make ("level", NULL);
if (levelIn) {
GstPad *levelsink;
gst_object_ref (levelIn);
if (gst_bin_add (GST_BIN (test_pipeline), levelIn) == FALSE) {
_notify_debug ("Could not add input level to pipeline");
gst_object_unref (levelIn);
levelIn = NULL;
goto no_level_in;
}
g_object_set (G_OBJECT (levelIn), "message", TRUE, NULL);
levelsink = gst_element_get_static_pad (levelIn, "sink");
if (gst_pad_link (srcpad, levelsink) != GST_PAD_LINK_OK) {
gst_object_unref (levelsink);
_notify_debug ("Couldn't link the volume/src to level");
gst_bin_remove (GST_BIN (test_pipeline), levelIn);
gst_object_unref (levelIn);
levelIn = NULL;
goto no_level_in;
}
gst_object_unref (srcpad);
srcpad = gst_element_get_static_pad (levelIn, "src");
} else {
no_level_in:
_notify_debug ("Couldn't create level In elemnt");
}
src_convert = gst_element_factory_make ("audioconvert", NULL);
if (gst_bin_add (GST_BIN (test_pipeline), src_convert) == FALSE) {
Tcl_AppendResult (interp, "Could not add src converter to pipeline",
(char *) NULL);
gst_object_unref (src_convert);
goto error;
}
src_resample = gst_element_factory_make ("audioresample", NULL);
if (gst_bin_add (GST_BIN (test_pipeline), src_resample) == FALSE) {
Tcl_AppendResult (interp, "Could not add src resampler to pipeline",
(char *) NULL);
gst_object_unref (src_resample);
goto error;
}
src_convert2 = gst_element_factory_make ("audioconvert", NULL);
if (gst_bin_add (GST_BIN (test_pipeline), src_convert2) == FALSE) {
Tcl_AppendResult (interp, "Could not add second src converter to pipeline",
(char *) NULL);
gst_object_unref (src_convert2);
goto error;
}
tempsink = gst_element_get_static_pad (src_convert, "sink");
if (gst_pad_link (srcpad, tempsink) != GST_PAD_LINK_OK) {
gst_object_unref (tempsink);
_notify_debug ("Couldn't link the src to converter");
gst_bin_remove (GST_BIN (test_pipeline), src_convert);
gst_object_unref (src_convert);
goto error;
}
gst_object_unref (srcpad);
if (gst_element_link(src_convert, src_resample) == FALSE) {
Tcl_AppendResult (interp, "Could not link converter to resampler",
(char *) NULL);
goto error;
}
if (gst_element_link(src_resample, src_convert2) == FALSE) {
Tcl_AppendResult (interp, "Could not link resampler to second converter",
(char *) NULL);
goto error;
}
srcpad = gst_element_get_static_pad (src_convert2, "src");
capsfilter = gst_element_factory_make ("capsfilter", "capsfilter");
if (capsfilter) {
GstPad *caps_sink;
GstCaps *caps;
if (gst_bin_add (GST_BIN (test_pipeline), capsfilter) == FALSE) {
_notify_debug ("Could not add capsfilter to pipeline");
gst_object_unref (capsfilter);
goto no_capsfilter;
}
caps_sink = gst_element_get_static_pad (capsfilter, "sink");
if (gst_pad_link (srcpad, caps_sink) != GST_PAD_LINK_OK) {
gst_object_unref (caps_sink);
_notify_debug ("Couldn't link the volume/level/src to capsfilter");
gst_bin_remove (GST_BIN (test_pipeline), capsfilter);
goto no_capsfilter;
}
caps = gst_caps_new_simple ("audio/x-raw-int",
"rate", G_TYPE_INT, 16000,
NULL);
g_object_set (capsfilter, "caps", caps, NULL);
gst_object_unref (srcpad);
srcpad = gst_element_get_static_pad (capsfilter, "src");
} else {
_notify_debug ("couldn't create capsfilter");
}
no_capsfilter:
snk = _create_audio_sink ();
if (snk == NULL) {
Tcl_AppendResult (interp, "Could not create audio_sink",
(char *) NULL);
goto error;
}
if (gst_bin_add (GST_BIN (test_pipeline), snk) == FALSE) {
Tcl_AppendResult (interp, "Could not add sink to pipeline",
(char *) NULL);
gst_object_unref (snk);
goto error;
}
sink_convert = gst_element_factory_make ("audioconvert", NULL);
if (gst_bin_add (GST_BIN (test_pipeline), sink_convert) == FALSE) {
Tcl_AppendResult (interp, "Could not add converter to pipeline",
(char *) NULL);
gst_object_unref (sink_convert);
goto error;
}
sink_resample = gst_element_factory_make ("audioresample", NULL);
if (gst_bin_add (GST_BIN (test_pipeline), sink_resample) == FALSE) {
Tcl_AppendResult (interp, "Could not add resampler to pipeline",
(char *) NULL);
gst_object_unref (sink_resample);
goto error;
}
sink_convert2 = gst_element_factory_make ("audioconvert", NULL);
if (gst_bin_add (GST_BIN (test_pipeline), sink_convert2) == FALSE) {
Tcl_AppendResult (interp, "Could not add second converter to pipeline",
(char *) NULL);
gst_object_unref (sink_convert2);
goto error;
}
volumeOut = gst_element_factory_make ("volume", NULL);
if (volumeOut) {
gst_object_ref (volumeOut);
if (gst_bin_add (GST_BIN (test_pipeline), volumeOut) == FALSE) {
_notify_debug ("Could not add output volume to pipeline");
gst_object_unref (volumeOut);
volumeOut = NULL;
goto no_volume_out;
}
if (gst_element_link(volumeOut, sink_convert) == FALSE) {
_notify_debug ("Could not link volume out to converter");
gst_bin_remove (GST_BIN (test_pipeline), volumeOut);
gst_object_unref (volumeOut);
volumeOut = NULL;
goto no_volume_out;
}
sinkpad = gst_element_get_static_pad (volumeOut, "sink");
} else {
_notify_debug ("Couldn't create volume OUT elemnt");
no_volume_out:
sinkpad = gst_element_get_static_pad (sink_convert, "sink");
}
ret = gst_pad_link (srcpad, sinkpad);
gst_object_unref (sinkpad);
gst_object_unref (srcpad);
if (ret != GST_PAD_LINK_OK) {
Tcl_AppendResult (interp, "Could not link src to sink",
(char *) NULL);
goto error;
}
if (gst_element_link(sink_convert, sink_resample) == FALSE) {
Tcl_AppendResult (interp, "Could not link converter to resampler",
(char *) NULL);
goto error;
}
if (gst_element_link(sink_resample, sink_convert2) == FALSE) {
Tcl_AppendResult (interp, "Could not link resampler to second converter",
(char *) NULL);
goto error;
}
levelOut = gst_element_factory_make ("level", NULL);
if (levelOut) {
gst_object_ref (levelOut);
if (gst_bin_add (GST_BIN (test_pipeline), levelOut) == FALSE) {
_notify_debug ("Could not add output level to pipeline");
gst_object_unref (levelOut);
levelOut = NULL;
goto no_level_out;
}
g_object_set (G_OBJECT (levelOut), "message", TRUE, NULL);
if (gst_element_link(sink_convert2, levelOut) == FALSE) {
_notify_debug ("Could not link level out to converter");
gst_bin_remove (GST_BIN (test_pipeline), levelOut);
gst_object_unref (levelOut);
levelOut = NULL;
goto no_level_out;
}
if (gst_element_link(levelOut, snk) == FALSE) {
_notify_debug ("Could not link audio_sink to level out");
gst_element_unlink(sink_convert2, levelOut);
gst_bin_remove (GST_BIN (test_pipeline), levelOut);
gst_object_unref (levelOut);
levelOut = NULL;
goto no_level_out;
}
} else {
_notify_debug ("Could not create level out element");
no_level_out:
if (gst_element_link(sink_convert2, snk) == FALSE) {
Tcl_AppendResult (interp, "Could not link audio_sink to converter",
(char *) NULL);
goto error;
}
}
if (gst_element_set_state (test_pipeline, GST_STATE_PLAYING) ==
GST_STATE_CHANGE_FAILURE) {
Tcl_AppendResult (interp, "Unable to set pipeline to PLAYING",
(char *) NULL);
goto error;
}
if (source_bin) {
gst_child_proxy_set (GST_OBJECT(source_bin), "hack_valve::drop", FALSE, NULL);
gst_element_set_locked_state (source_bin, FALSE);
gst_object_unref (source_bin);
source_bin = NULL;
}
result = Tcl_NewListObj (0, NULL);
factory = gst_element_get_factory (_find_source (src));
source = Tcl_NewStringObj (GST_PLUGIN_FEATURE_NAME(factory), -1);
factory = gst_element_get_factory (_find_sink (snk));
sink = Tcl_NewStringObj (GST_PLUGIN_FEATURE_NAME(factory), -1);
Tcl_ListObjAppendElement(interp, result, source);
Tcl_ListObjAppendElement(interp, result, sink);
Tcl_SetObjResult (interp, result);
return TCL_OK;
error:
Close ();
return TCL_ERROR;
}
int Farsight_TestVideo _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]))
{
GstBus *bus = NULL;
GstElement *src = NULL;
GstElement *colorspace = NULL;
GstElement *snk = NULL;
Tcl_Obj *source = NULL;
Tcl_Obj *sink = NULL;
Tcl_Obj *result = NULL;
GstElementFactory *factory = NULL;
// We verify the arguments
if( objc != 1) {
Tcl_WrongNumArgs (interp, 1, objv, "");
return TCL_ERROR;
}
main_tid = Tcl_GetCurrentThread();
if (pipeline != NULL) {
Tcl_AppendResult (interp, "Already started" , (char *) NULL);
return TCL_ERROR;
}
if (test_pipeline != NULL) {
Tcl_AppendResult (interp, "Already testing" , (char *) NULL);
return TCL_ERROR;
}
test_pipeline = gst_pipeline_new ("pipeline");
if (test_pipeline == NULL) {
Tcl_AppendResult (interp, "Couldn't create gstreamer pipeline" ,
(char *) NULL);
goto error;
}
bus = gst_element_get_bus (test_pipeline);
gst_bus_set_sync_handler (bus, _bus_callback, NULL);
gst_object_unref (bus);
if (gst_element_set_state (test_pipeline, GST_STATE_PLAYING) ==
GST_STATE_CHANGE_FAILURE) {
Tcl_AppendResult (interp, "Unable to set pipeline to PLAYING",
(char *) NULL);
goto error;
}
src = _create_video_source ();
if (src == NULL) {
_notify_debug ("Couldn't create video source, using videotestsrc");
src = gst_element_factory_make ("videotestsrc", NULL);
}
if (gst_bin_add (GST_BIN (test_pipeline), src) == FALSE) {
_notify_debug ("Couldn't add video_source to test pipeline");
gst_element_set_state (test_pipeline, GST_STATE_NULL);
gst_object_unref (src);
src = NULL;
goto error;
}
colorspace = gst_element_factory_make ("ffmpegcolorspace", NULL);
if (colorspace == NULL ||
gst_bin_add (GST_BIN (test_pipeline), colorspace) == FALSE) {
_notify_debug ("Could not add colorspace to test pipeline");
gst_object_unref (colorspace);
goto error;
}
if (gst_element_link(src, colorspace) == FALSE) {
_notify_debug ("Could not link source to colorspace");
goto error;
}
/* Uncomment once we want to have a TestView that also tests the video sink */
if (preview)
snk = gst_element_factory_make ("fakesink", NULL);
else
snk = _create_video_sink ();
if (snk == NULL) {
Tcl_AppendResult (interp, "Could not create video sink", (char *) NULL);
goto error;
}
if (gst_bin_add (GST_BIN (test_pipeline), snk) == FALSE) {
Tcl_AppendResult (interp, "Could not add video sink to pipeline", (char *) NULL);
if (snk) gst_object_unref (snk);
goto error;
}
if (gst_element_link(colorspace, snk) == FALSE) {
_notify_debug ("Could not link colorspace to sink");
goto error;
}
if (preview == NULL) {
preview = snk;
gst_object_ref (preview);
}
if (gst_element_set_state (test_pipeline, GST_STATE_PLAYING) ==
GST_STATE_CHANGE_FAILURE) {
Tcl_AppendResult (interp, "Unable to set pipeline to PLAYING",
(char *) NULL);
goto error;
}
if (source_bin) {
gst_child_proxy_set (GST_OBJECT(source_bin), "hack_valve::drop", FALSE, NULL);
gst_element_set_locked_state (source_bin, FALSE);
gst_object_unref (source_bin);
source_bin = NULL;
}
result = Tcl_NewListObj (0, NULL);
factory = gst_element_get_factory (_find_source (src));
source = Tcl_NewStringObj (GST_PLUGIN_FEATURE_NAME(factory), -1);
factory = gst_element_get_factory (_find_sink (snk));
sink = Tcl_NewStringObj (GST_PLUGIN_FEATURE_NAME(factory), -1);
Tcl_ListObjAppendElement(interp, result, source);
Tcl_ListObjAppendElement(interp, result, sink);
Tcl_SetObjResult (interp, result);
return TCL_OK;
error:
Close ();
return TCL_ERROR;
}
static int
_tcl_codecs_to_fscodecs (Tcl_Interp *interp, Tcl_Obj **tcl_remote_codecs,
int total_codecs, GList **remote_codecs, FsMediaType media_type)
{
FsCodec *codec = NULL;
int i;
for (i = 0; i < total_codecs; i++) {
int total_elements;
Tcl_Obj **elements = NULL;
codec = fs_codec_new (0, NULL, media_type, 0);
if (Tcl_ListObjGetElements(interp, tcl_remote_codecs[i],
&total_elements, &elements) != TCL_OK) {
Tcl_AppendResult (interp, "\nInvalid codec", (char *) NULL);
goto error_codec;
}
if (total_elements != 3) {
Tcl_AppendResult (interp, "\nInvalid codec : ",
Tcl_GetString (tcl_remote_codecs[i]), (char *) NULL);
goto error_codec;
}
codec->encoding_name = g_strdup (Tcl_GetStringFromObj (elements[0], NULL));
if (Tcl_GetIntFromObj (interp, elements[1], &codec->id) != TCL_OK) {
Tcl_AppendResult (interp, "\nInvalid codec : ",
Tcl_GetString (tcl_remote_codecs[i]), (char *) NULL);
goto error_codec;
}
if (Tcl_GetIntFromObj (interp, elements[2], &codec->clock_rate) != TCL_OK) {
Tcl_AppendResult (interp, "\nInvalid codec : ",
Tcl_GetString (tcl_remote_codecs[i]), (char *) NULL);
goto error_codec;
}
_notify_debug ("New remote %s codec : %d %s %d",
media_type == FS_MEDIA_TYPE_AUDIO ? "audio" : "video",
codec->id, codec->encoding_name, codec->clock_rate);
*remote_codecs = g_list_append (*remote_codecs, codec);
}
return TCL_OK;
error_codec:
fs_codec_destroy (codec);
fs_codec_list_destroy (*remote_codecs);
*remote_codecs = NULL;
return TCL_ERROR;
}
static int
_tcl_candidates_to_fscandidates (Tcl_Interp *interp, Tcl_Obj **tcl_remote_candidates,
int total_candidates, GList **remote_candidates)
{
FsCandidate *candidate = NULL;
int i;
for (i = 0; i < total_candidates; i++) {
int total_elements;
Tcl_Obj **elements = NULL;
double temp_d;
int temp_i;
char *temp_s;
candidate = fs_candidate_new (NULL, 1, 0, FS_NETWORK_PROTOCOL_UDP, NULL, 0);
if (Tcl_ListObjGetElements(interp, tcl_remote_candidates[i],
&total_elements, &elements) != TCL_OK) {
Tcl_AppendResult (interp, "\nInvalid candidate", (char *) NULL);
goto error_candidate;
}
if (total_elements != 11) {
Tcl_AppendResult (interp, "Invalid candidate : ",
Tcl_GetString (tcl_remote_candidates[i]), (char *) NULL);
goto error_candidate;
}
/* Foundation */
candidate->foundation = g_strdup (Tcl_GetString (elements[0]));
/* Component id*/
if (Tcl_GetIntFromObj (interp, elements[1], &candidate->component_id) != TCL_OK) {
Tcl_AppendResult (interp, "\nInvalid candidate : ",
Tcl_GetString (tcl_remote_candidates[i]), (char *) NULL);
goto error_candidate;
}
/* IP */
candidate->ip = g_strdup (Tcl_GetString (elements[2]));
/* port */
if (Tcl_GetIntFromObj (interp, elements[3], &temp_i) != TCL_OK) {
Tcl_AppendResult (interp, "\nInvalid candidate : ",
Tcl_GetString (tcl_remote_candidates[i]), (char *) NULL);
goto error_candidate;
}
candidate->port = temp_i;
/* base IP */
if (Tcl_GetString (elements[4]) != NULL &&
Tcl_GetString (elements[4])[0] != 0) {
candidate->base_ip = g_strdup (Tcl_GetString (elements[4]));
/* base port */
if (Tcl_GetIntFromObj (interp, elements[5], &temp_i) != TCL_OK) {
Tcl_AppendResult (interp, "\nInvalid candidate : ",
Tcl_GetString (tcl_remote_candidates[i]), (char *) NULL);
goto error_candidate;
}
candidate->base_port = temp_i;
}
/* Protocol */
candidate->proto = strcmp (Tcl_GetString (elements[6]), "UDP") == 0 ?
FS_NETWORK_PROTOCOL_UDP : FS_NETWORK_PROTOCOL_TCP;
/* Priority */
if (call_type & RTP_ICE6) {
if (Tcl_GetDoubleFromObj (interp, elements[7], &temp_d) != TCL_OK) {
Tcl_AppendResult (interp, "\nInvalid candidate : ",
Tcl_GetString (tcl_remote_candidates[i]), (char *) NULL);
goto error_candidate;
}
candidate->priority = (guint32) (temp_d * 1000);
} else {
if (Tcl_GetIntFromObj (interp, elements[7], &temp_i) != TCL_OK) {
Tcl_AppendResult (interp, "\nInvalid candidate : ",
Tcl_GetString (tcl_remote_candidates[i]), (char *) NULL);
goto error_candidate;
}
candidate->priority = temp_i;
}
/* Type */
temp_s = Tcl_GetString (elements[8]);
if (strcmp (temp_s, "host") == 0) {
candidate->type = FS_CANDIDATE_TYPE_HOST;
} else if (strcmp (temp_s, "srflx") == 0) {
candidate->type = FS_CANDIDATE_TYPE_SRFLX;
} else if (strcmp (temp_s, "prflx") == 0) {
candidate->type = FS_CANDIDATE_TYPE_PRFLX;
} else if (strcmp (temp_s, "relay") == 0) {
candidate->type = FS_CANDIDATE_TYPE_RELAY;
}
/* Username/Password */
candidate->username = g_strdup (Tcl_GetString (elements[9]));
candidate->password = g_strdup (Tcl_GetString (elements[10]));
_notify_debug ("New Remote candidate: %s %d %s %d %s %d %s %d %s %s %s\n",
candidate->foundation == NULL ? "-" : candidate->foundation,
candidate->component_id,
candidate->ip,
candidate->port,
candidate->base_ip == NULL ? "-" : candidate->base_ip,
candidate->base_port,
candidate->proto == FS_NETWORK_PROTOCOL_UDP ? "UDP" : "TCP",
candidate->priority,
_fs_candidate_type_to_string (candidate->type),
candidate->username == NULL ? "-" : candidate->username,
candidate->password == NULL ? "-" : candidate->password);
*remote_candidates = g_list_append (*remote_candidates, candidate);
}
return TCL_OK;
error_candidate:
fs_candidate_destroy (candidate);
fs_candidate_list_destroy (*remote_candidates);
*remote_candidates = NULL;
return TCL_ERROR;
}
static int
_tcl_relay_info_to_gvalue_array (Tcl_Interp *interp, Tcl_Obj **tcl_relay_info,
int total_relay_info, GValueArray **audio_relay_info, GValueArray **video_relay_info)
{
int i;
for (i = 0; i < total_relay_info; i++) {
char *turn_ip = NULL;
char *turn_hostname = NULL;
int turn_port = 1863;
int stream = 0;
int component = 0;
char *username = NULL;
char *password = NULL;
char *type = NULL;
int total_elements;
Tcl_Obj **elements = NULL;
GstStructure *turn_setup = NULL;
GValue gvalue = { 0 };
g_value_init (&gvalue, GST_TYPE_STRUCTURE);
if (Tcl_ListObjGetElements(interp, tcl_relay_info[i],
&total_elements, &elements) != TCL_OK) {
Tcl_AppendResult (interp, "\nInvalid relay info element", (char *) NULL);
return TCL_ERROR;
}
if (total_elements != 7) {
Tcl_AppendResult (interp, "\nInvalid relay info element : ",
Tcl_GetString (tcl_relay_info[i]), (char *) NULL);
return TCL_ERROR;
}
turn_hostname = Tcl_GetStringFromObj (elements[0], NULL);
turn_ip = host2ip (turn_hostname);
if (turn_ip == NULL) {
Tcl_AppendResult (interp, "TURN server invalid : Could not resolve hostname",
(char *) NULL);
return TCL_ERROR;
}
if (Tcl_GetIntFromObj (interp, elements[1], &turn_port) == TCL_ERROR) {
Tcl_AppendResult (interp, "TURN port invalid : Expected integer" , (char *) NULL);
return TCL_ERROR;
}
if (turn_port == 0) {
turn_port = 1863;
}
username = Tcl_GetStringFromObj (elements[2], NULL);
password = Tcl_GetStringFromObj (elements[3], NULL);
if (Tcl_GetIntFromObj (interp, elements[4], &stream) == TCL_ERROR) {
Tcl_AppendResult (interp, "TURN stream invalid : Expected integer" , (char *) NULL);
return TCL_ERROR;
}
if (Tcl_GetIntFromObj (interp, elements[5], &component) == TCL_ERROR) {
Tcl_AppendResult (interp, "TURN component invalid : Expected integer" , (char *) NULL);
return TCL_ERROR;
}
type = Tcl_GetStringFromObj (elements[6], NULL);
turn_setup = gst_structure_new ("relay-info",
"ip", G_TYPE_STRING, turn_ip,
"port", G_TYPE_UINT, turn_port,
"component", G_TYPE_UINT, component,
"username", G_TYPE_STRING, username,
"password", G_TYPE_STRING, password,
"relay-type", G_TYPE_STRING, type,
NULL);
if (turn_setup == NULL) {
Tcl_AppendResult (interp, "Unable to create relay info" , (char *) NULL);
return TCL_ERROR;
}
gst_value_set_structure (&gvalue, turn_setup);
if (stream == 1) {
if (*audio_relay_info == NULL) {
*audio_relay_info = g_value_array_new (0);
}
*audio_relay_info = g_value_array_append (*audio_relay_info, &gvalue);
} else if (stream == 2) {
if (*video_relay_info == NULL) {
*video_relay_info = g_value_array_new (0);
}
*video_relay_info = g_value_array_append (*video_relay_info, &gvalue);
} else {
gst_structure_free (turn_setup);
Tcl_AppendResult (interp, "Invalid stream id" , (char *) NULL);
return TCL_ERROR;
}
gst_structure_free (turn_setup);
}
return TCL_OK;
}
int Farsight_Prepare _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]))
{
GError *error = NULL;
GstBus *bus = NULL;
GstElement *src = NULL;
GstPad *sinkpad = NULL, *srcpad = NULL;
GstPad *tempsink;
GstElement *conference = NULL;
GstElement *src_convert = NULL;
GstElement *src_resample = NULL;
GstElement *src_convert2 = NULL;
GstElement *src_colorspace = NULL;
GParameter transmitter_params[6];
int controlling;
char *stun_ip = NULL;
char *stun_hostname = NULL;
int stun_port = 3478;
Tcl_Obj **tcl_relay_info = NULL;
int total_relay_info;
GValueArray *audio_relay_info = NULL;
GValueArray *video_relay_info = NULL;
int total_params;
char *mode = NULL;
// We verify the arguments
if( objc < 4 || objc > 7) {
Tcl_WrongNumArgs (interp, 1, objv, " callback controlling mode ?relay_info?"
" ?stun_ip stun_port?\n"
"Where mode can be either : "
OLD_AUDIO_CALL ", " OLD_AUDIO_VIDEO_CALL ", "
NEW_AUDIO_CALL " or " NEW_AUDIO_VIDEO_CALL "\n"
"Where relay_info is a list with each element being a list containing : "
"{turn_hostname turn_port turn_username turn_password stream component type}");
return TCL_ERROR;
}
if (Tcl_GetBooleanFromObj (interp, objv[2], &controlling) != TCL_OK) {
return TCL_ERROR;
}
mode = Tcl_GetStringFromObj (objv[3], NULL);
if (strcmp (mode, OLD_AUDIO_CALL) == 0) {
call_type = RTP_AUDIO_ICE6;
} else if (strcmp (mode, OLD_AUDIO_VIDEO_CALL) == 0) {
call_type = RTP_AUDIO_VIDEO_ICE6;
} else if (strcmp (mode, NEW_AUDIO_CALL) == 0) {
call_type = RTP_AUDIO_ICE19;
} else if (strcmp (mode, NEW_AUDIO_VIDEO_CALL) == 0) {
call_type = RTP_AUDIO_VIDEO_ICE19;
} else {
Tcl_AppendResult (interp, "Invalid call mode, must be either : ",
OLD_AUDIO_CALL, ", ", NEW_AUDIO_CALL, " or ",
NEW_AUDIO_VIDEO_CALL, (char *) NULL);
return TCL_ERROR;
}
if (pipeline != NULL) {
Tcl_AppendResult (interp, "Already prepared/in preparation" , (char *) NULL);
return TCL_ERROR;
}
if (test_pipeline != NULL) {
Close ();
}
callback = objv[1];
Tcl_IncrRefCount (callback);
callback_interp = interp;
main_tid = Tcl_GetCurrentThread();
if (objc > 4) {
if (Tcl_ListObjGetElements(interp, objv[4],
&total_relay_info, &tcl_relay_info) != TCL_OK) {
Tcl_AppendResult (interp, "\nInvalid relay info", (char *) NULL);
return TCL_ERROR;
}
if (_tcl_relay_info_to_gvalue_array (interp, tcl_relay_info,
total_relay_info, &audio_relay_info, &video_relay_info) != TCL_OK) {
goto error;
}
}
if (objc > 5) {
stun_hostname = Tcl_GetStringFromObj (objv[5], NULL);
stun_ip = host2ip (stun_hostname);
if (stun_ip == NULL) {
Tcl_AppendResult (interp, "Stun server invalid : Could not resolve hostname",
(char *) NULL);
return TCL_ERROR;
}
}
if (objc > 6) {
if (Tcl_GetIntFromObj (interp, objv[6], &stun_port) == TCL_ERROR) {
Tcl_AppendResult (interp, "Stun port invalid : Expected integer" , (char *) NULL);
return TCL_ERROR;
}
}
audio_candidates_prepared = FALSE;
audio_codecs_ready = FALSE;
video_candidates_prepared = FALSE;
video_codecs_ready = FALSE;
pipeline = gst_pipeline_new ("pipeline");
if (pipeline == NULL) {
Tcl_AppendResult (interp, "Couldn't create gstreamer pipeline" , (char *) NULL);
goto error;
}
bus = gst_element_get_bus (pipeline);
gst_bus_set_sync_handler (bus, _bus_callback, NULL);
gst_object_unref (bus);
if (gst_element_set_state (pipeline, GST_STATE_PLAYING) ==
GST_STATE_CHANGE_FAILURE) {
Tcl_AppendResult (interp, "Unable to set pipeline to PLAYING",
(char *) NULL);
goto error;
}
conference = gst_element_factory_make ("fsrtpconference", NULL);
if (conference == NULL) {
Tcl_AppendResult (interp, "Couldn't create fsrtpconference" , (char *) NULL);
goto error;
}
if (gst_bin_add (GST_BIN (pipeline), conference) == FALSE) {
Tcl_AppendResult (interp, "Couldn't add fsrtpconference to the pipeline",
(char *) NULL);
goto error;
}
g_object_set (conference, "sdes-cname", "", NULL);
fsnotifier = fs_element_added_notifier_new ();
fs_element_added_notifier_add (fsnotifier, GST_BIN (conference));
g_signal_connect (fsnotifier, "element-added",
G_CALLBACK (_conference_element_added), NULL);
participant = fs_conference_new_participant (FS_CONFERENCE (conference),
#ifdef HAVE_FARSIGHT
"",
#endif /* HAVE_FARSIGHT */
&error);
if (error) {
char temp[1000];
snprintf (temp, 1000, "Error while creating new participant (%d): %s",
error->code, error->message);
Tcl_AppendResult (interp, temp, (char *) NULL);
goto error;
}
if (participant == NULL) {
Tcl_AppendResult (interp, "Couldn't create new participant" , (char *) NULL);
goto error;
}
audio_session = fs_conference_new_session (FS_CONFERENCE (conference),
FS_MEDIA_TYPE_AUDIO, &error);
if (error) {
char temp[1000];
snprintf (temp, 1000, "Error while creating new audio_session (%d): %s",
error->code, error->message);
Tcl_AppendResult (interp, temp, (char *) NULL);
goto error;
}
if (audio_session == NULL) {
Tcl_AppendResult (interp, "Couldn't create new audio_session" , (char *) NULL);
goto error;
}
/* Set codec preferences.. if this fails, then it's no big deal.. */
{
GList *codec_preferences = NULL;
FsCodec *x_msrta_16000 = fs_codec_new (114, "x-msrta", FS_MEDIA_TYPE_AUDIO, 16000);
FsCodec *siren = fs_codec_new (111, "SIREN", FS_MEDIA_TYPE_AUDIO, 16000);
FsCodec *g7221 = fs_codec_new (112, "G7221", FS_MEDIA_TYPE_AUDIO, 16000);
FsCodec *x_msrta_8000 = fs_codec_new (115, "x-msrta", FS_MEDIA_TYPE_AUDIO, 8000);
FsCodec *aal2 = fs_codec_new (116, "AAL2-G726-32", FS_MEDIA_TYPE_AUDIO, 8000);
FsCodec *g723 = fs_codec_new (4, "G723", FS_MEDIA_TYPE_AUDIO, 8000);
FsCodec *pcma = fs_codec_new (8, "PCMA", FS_MEDIA_TYPE_AUDIO, 8000);
FsCodec *pcmu = fs_codec_new (0, "PCMU", FS_MEDIA_TYPE_AUDIO, 8000);
FsCodec *red = fs_codec_new (97, "RED", FS_MEDIA_TYPE_AUDIO, 8000);
FsCodec *telephone_event = fs_codec_new (101, "telephone-event",
FS_MEDIA_TYPE_AUDIO, 8000);
codec_preferences = g_list_append (codec_preferences, x_msrta_16000);
codec_preferences = g_list_append (codec_preferences, siren);
codec_preferences = g_list_append (codec_preferences, g7221);
codec_preferences = g_list_append (codec_preferences, x_msrta_8000);
codec_preferences = g_list_append (codec_preferences, aal2);
codec_preferences = g_list_append (codec_preferences, g723);
codec_preferences = g_list_append (codec_preferences, pcma);
codec_preferences = g_list_append (codec_preferences, pcmu);
codec_preferences = g_list_append (codec_preferences, red);
codec_preferences = g_list_append (codec_preferences, telephone_event);
fs_session_set_codec_preferences (audio_session, codec_preferences, NULL);
fs_codec_list_destroy (codec_preferences);
}
if (!audio_codecs_ready) {
gboolean ready;
g_object_get (audio_session, "codecs-ready", &ready, NULL);
if (ready) {
_codecs_ready (audio_session);
}
}
g_object_set (audio_session, "no-rtcp-timeout", 0, NULL);
g_object_get (audio_session, "sink-pad", &sinkpad, NULL);
if (sinkpad == NULL) {
Tcl_AppendResult (interp, "Couldn't get sink pad" , (char *) NULL);
goto error;
}
src = _create_audio_source ();
if (src == NULL) {
_notify_debug ("Couldn't create audio source");
goto no_audio_source;
}
if (gst_bin_add (GST_BIN (pipeline), src) == FALSE) {
_notify_debug ("Couldn't add audio_source to pipeline");
if (src) gst_object_unref (src);
goto no_audio_source;
}
volumeIn = gst_element_factory_make ("volume", NULL);
if (volumeIn) {
gst_object_ref (volumeIn);
if (gst_bin_add (GST_BIN (pipeline), volumeIn) == FALSE) {
_notify_debug ("Could not add input volume to pipeline");
gst_object_unref (volumeIn);
volumeIn = NULL;
goto no_volume;
}
srcpad = gst_element_get_static_pad (volumeIn, "src");
if (gst_element_link(src, volumeIn) == FALSE) {
_notify_debug ("Could not link audio_source to volume");
gst_bin_remove (GST_BIN (pipeline), volumeIn);
gst_object_unref (volumeIn);
volumeIn = NULL;
goto no_volume;
}
} else {
no_volume:
srcpad = gst_element_get_static_pad (src, "src");
}
levelIn = gst_element_factory_make ("level", NULL);
if (levelIn) {
GstPad *levelsink;
gst_object_ref (levelIn);
if (gst_bin_add (GST_BIN (pipeline), levelIn) == FALSE) {
_notify_debug ("Could not add input level to pipeline");
gst_object_unref (levelIn);
levelIn = NULL;
goto no_level;
}
g_object_set (G_OBJECT (levelIn), "message", TRUE, NULL);
levelsink = gst_element_get_static_pad (levelIn, "sink");
if (gst_pad_link (srcpad, levelsink) != GST_PAD_LINK_OK) {
gst_object_unref (levelsink);
gst_object_unref (srcpad);
_notify_debug ("Couldn't link the volume/src to level");
gst_bin_remove (GST_BIN (pipeline), levelIn);
gst_object_unref (levelIn);
levelIn = NULL;
goto no_level;
}
gst_object_unref (srcpad);
srcpad = gst_element_get_static_pad (levelIn, "src");
}
no_level:
src_convert = gst_element_factory_make ("audioconvert", NULL);
if (gst_bin_add (GST_BIN (pipeline), src_convert) == FALSE) {
Tcl_AppendResult (interp, "Could not add src converter to pipeline",
(char *) NULL);
gst_object_unref (src_convert);
goto error;
}
src_resample = gst_element_factory_make ("audioresample", NULL);
if (gst_bin_add (GST_BIN (pipeline), src_resample) == FALSE) {
Tcl_AppendResult (interp, "Could not add src resampler to pipeline",
(char *) NULL);
gst_object_unref (src_resample);
goto error;
}
src_convert2 = gst_element_factory_make ("audioconvert", NULL);
if (gst_bin_add (GST_BIN (pipeline), src_convert2) == FALSE) {
Tcl_AppendResult (interp, "Could not add second src converter to pipeline",
(char *) NULL);
gst_object_unref (src_convert2);
goto error;
}
tempsink = gst_element_get_static_pad (src_convert, "sink");
if (gst_pad_link (srcpad, tempsink) != GST_PAD_LINK_OK) {
gst_object_unref (tempsink);
gst_object_unref (srcpad);
_notify_debug ("Couldn't link the src to converter");
goto error;
}
gst_object_unref (srcpad);
gst_object_unref (tempsink);
if (gst_element_link(src_convert, src_resample) == FALSE) {
Tcl_AppendResult (interp, "Could not link converter to resampler",
(char *) NULL);
goto error;
}
if (gst_element_link(src_resample, src_convert2) == FALSE) {
Tcl_AppendResult (interp, "Could not link resampler to second converter",
(char *) NULL);
goto error;
}
srcpad = gst_element_get_static_pad (src_convert2, "src");
if (gst_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK) {
gst_object_unref (sinkpad);
gst_object_unref (srcpad);
_notify_debug ("Couldn't link the volume/level/src to fsrtpconference");
goto no_audio_source;
}
gst_object_unref (sinkpad);
gst_object_unref (srcpad);
no_audio_source:
memset (transmitter_params, 0, sizeof (GParameter) * 6);
total_params = 0;
transmitter_params[total_params].name = "compatibility-mode";
g_value_init (&transmitter_params[total_params].value, G_TYPE_UINT);
if (call_type & RTP_ICE6) {
g_value_set_uint (&transmitter_params[total_params].value, 2);
} else {
g_value_set_uint (&transmitter_params[total_params].value, 3);
}
total_params++;
transmitter_params[total_params].name = "controlling-mode";
g_value_init (&transmitter_params[total_params].value, G_TYPE_BOOLEAN);
g_value_set_boolean (&transmitter_params[total_params].value, controlling);
total_params++;
if (stun_ip) {
_notify_debug ("stun ip : %s : %d", stun_ip, stun_port);
transmitter_params[total_params].name = "stun-ip";
g_value_init (&transmitter_params[total_params].value, G_TYPE_STRING);
g_value_set_string (&transmitter_params[total_params].value, stun_ip);
total_params++;
transmitter_params[total_params].name = "stun-port";
g_value_init (&transmitter_params[total_params].value, G_TYPE_UINT);
g_value_set_uint (&transmitter_params[total_params].value, stun_port);
total_params++;
}
if (audio_relay_info) {
_notify_debug ("FS: relay info = %p - %d", audio_relay_info, audio_relay_info->n_values);
transmitter_params[total_params].name = "relay-info";
g_value_init (&transmitter_params[total_params].value, G_TYPE_VALUE_ARRAY);
g_value_set_boxed (&transmitter_params[total_params].value, audio_relay_info);
total_params++;
}
#ifdef HAVE_FARSTREAM
audio_stream = fs_session_new_stream (audio_session, participant, FS_DIRECTION_BOTH,
&error);
if(!fs_stream_set_transmitter(audio_stream, "nice",
transmitter_params, total_params, &error)) {
char temp[1000];
snprintf (temp, 1000, "Could not set transmitter \"nice\" (%d): %s.", error->code, error->message);
goto error;
}
#else
audio_stream = fs_session_new_stream (audio_session, participant, FS_DIRECTION_BOTH,
"nice", total_params, transmitter_params, &error);
#endif /* HAVE_FARSTREAM */
if (error) {
char temp[1000];
snprintf (temp, 1000, "Error while creating new audio_stream (%d): %s",
error->code, error->message);
Tcl_AppendResult (interp, temp, (char *) NULL);
goto error;
}
if (audio_stream == NULL) {
Tcl_AppendResult (interp, "Couldn't create new audio_stream" , (char *) NULL);
goto error;
}
g_signal_connect (audio_stream, "src-pad-added",
G_CALLBACK (_audio_src_pad_added), pipeline);
/* Setup video pipeline */
if (call_type & RTP_VIDEO) {
video_session = fs_conference_new_session (FS_CONFERENCE (conference),
FS_MEDIA_TYPE_VIDEO, &error);
if (error) {
char temp[1000];
snprintf (temp, 1000, "Error while creating new video_session (%d): %s",
error->code, error->message);
Tcl_AppendResult (interp, temp, (char *) NULL);
goto error;
}
if (video_session == NULL) {
Tcl_AppendResult (interp, "Couldn't create new video_session" , (char *) NULL);
goto error;
}
/* Set codec preferences.. if this fails, then it's no big deal.. */
{
GList *codec_preferences = NULL;
FsCodec *x_rtvc1 = fs_codec_new (121, "x-rtvc1", FS_MEDIA_TYPE_VIDEO, 90000);
FsCodec *h263 = fs_codec_new (34, "H263", FS_MEDIA_TYPE_VIDEO, 90000);
codec_preferences = g_list_append (codec_preferences, x_rtvc1);
codec_preferences = g_list_append (codec_preferences, h263);
fs_session_set_codec_preferences (video_session, codec_preferences, NULL);
fs_codec_list_destroy (codec_preferences);
}
if (!video_codecs_ready) {
gboolean ready;
g_object_get (video_session, "codecs-ready", &ready, NULL);
if (ready) {
_codecs_ready (video_session);
}
}
g_object_set (video_session, "no-rtcp-timeout", 0, NULL);
g_object_get (video_session, "sink-pad", &sinkpad, NULL);
if (sinkpad == NULL) {
Tcl_AppendResult (interp, "Couldn't get sink pad" , (char *) NULL);
goto error;
}
src = _create_video_source ();
if (src == NULL) {
_notify_debug ("Couldn't create video_source");
goto no_video_source;
}
if (gst_bin_add (GST_BIN (pipeline), src) == FALSE) {
_notify_debug ("Couldn't add video source to pipeline");
if (src) gst_object_unref (src);
if (!video_codecs_ready) {
_codecs_ready (video_session);
}
goto no_video_source;
}
src_colorspace = gst_element_factory_make ("ffmpegcolorspace", NULL);
if (gst_bin_add (GST_BIN (pipeline), src_colorspace) == FALSE) {
Tcl_AppendResult (interp, "Could not add src colorspace to pipeline",
(char *) NULL);
gst_object_unref (src_colorspace);
goto error;
}
if (gst_element_link(src, src_colorspace) == FALSE) {
Tcl_AppendResult (interp, "Could not link src to colorspace",
(char *) NULL);
goto error;
}
srcpad = gst_element_get_static_pad (src_colorspace, "src");
if (gst_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK) {
gst_object_unref (sinkpad);
gst_object_unref (srcpad);
_notify_debug ("Couldn't link the colorspace to fsrtpconference");
if (!video_codecs_ready) {
_codecs_ready (video_session);
}
goto no_video_source;
}
gst_object_unref (sinkpad);
gst_object_unref (srcpad);
no_video_source:
memset (transmitter_params, 0, sizeof (GParameter) * 6);
total_params = 0;
transmitter_params[total_params].name = "compatibility-mode";
g_value_init (&transmitter_params[total_params].value, G_TYPE_UINT);
if (call_type & RTP_ICE6) {
g_value_set_uint (&transmitter_params[total_params].value, 2);
} else {
g_value_set_uint (&transmitter_params[total_params].value, 3);
}
total_params++;
transmitter_params[total_params].name = "controlling-mode";
g_value_init (&transmitter_params[total_params].value, G_TYPE_BOOLEAN);
g_value_set_boolean (&transmitter_params[total_params].value, controlling);
total_params++;
if (stun_ip) {
_notify_debug ("stun ip : %s : %d", stun_ip, stun_port);
transmitter_params[total_params].name = "stun-ip";
g_value_init (&transmitter_params[total_params].value, G_TYPE_STRING);
g_value_set_string (&transmitter_params[total_params].value, stun_ip);
total_params++;
transmitter_params[total_params].name = "stun-port";
g_value_init (&transmitter_params[total_params].value, G_TYPE_UINT);
g_value_set_uint (&transmitter_params[total_params].value, stun_port);
total_params++;
}
if (video_relay_info) {
_notify_debug ("FS: relay info = %p - %d", video_relay_info, video_relay_info->n_values);
transmitter_params[total_params].name = "relay-info";
g_value_init (&transmitter_params[total_params].value, G_TYPE_VALUE_ARRAY);
g_value_set_boxed (&transmitter_params[total_params].value, video_relay_info);
total_params++;
}
#ifdef HAVE_FARSTREAM
video_stream = fs_session_new_stream (video_session, participant,
FS_DIRECTION_BOTH, &error);
if(!fs_stream_set_transmitter(video_stream, "nice",
transmitter_params, total_params, &error)) {
char temp[1000];
snprintf (temp, 1000, "Could not set transmitter \"nice\" (%d): %s.", error->code, error->message);
goto error;
}
#else
video_stream = fs_session_new_stream (video_session, participant,
FS_DIRECTION_BOTH, "nice", total_params, transmitter_params, &error);
#endif /* HAVE_FARSTREAM */
if (error) {
char temp[1000];
snprintf (temp, 1000, "Error while creating new video_stream (%d): %s",
error->code, error->message);
Tcl_AppendResult (interp, temp, (char *) NULL);
goto error;
}
if (video_stream == NULL) {
Tcl_AppendResult (interp, "Couldn't create new video_stream" , (char *) NULL);
goto error;
}
g_signal_connect (video_stream, "src-pad-added",
G_CALLBACK (_video_src_pad_added), pipeline);
}
if (gst_element_set_state (pipeline, GST_STATE_PLAYING) ==
GST_STATE_CHANGE_FAILURE) {
Tcl_AppendResult (interp, "Unable to set pipeline to PLAYING",
(char *) NULL);
goto error;
}
if (source_bin) {
gst_child_proxy_set (GST_OBJECT(source_bin), "hack_valve::drop", FALSE, NULL);
gst_element_set_locked_state (source_bin, FALSE);
gst_object_unref (source_bin);
source_bin = NULL;
}
if (!video_codecs_ready) {
_codecs_ready (video_session);
}
if (audio_relay_info)
g_value_array_free (audio_relay_info);
if (video_relay_info)
g_value_array_free (video_relay_info);
return TCL_OK;
error:
_notify_debug ("Error: %s", Tcl_GetStringResult(interp));
Close ();
if (audio_relay_info)
g_value_array_free (audio_relay_info);
if (video_relay_info)
g_value_array_free (video_relay_info);
return TCL_ERROR;
}
int Farsight_Start _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]))
{
GError *error = NULL;
GList *audio_remote_codecs = NULL;
GList *video_remote_codecs = NULL;
int total_codecs;
Tcl_Obj **tcl_remote_codecs = NULL;
GList *audio_remote_candidates = NULL;
GList *video_remote_candidates = NULL;
int total_candidates;
Tcl_Obj **tcl_remote_candidates = NULL;
// We verify the arguments
if( objc != 3 && objc != 5) {
Tcl_WrongNumArgs (interp, 1, objv, " remote_audio_codecs remote_audio_candidates"
" ?remote_video_codecs remote_video_candidates?\n"
"Where remote_codecs is a list with each element being a list containing : "
"{encoding_name payload_type clock_rate}\n"
"And where remote_candidates is a list with each element being a list containing : "
"{foundation component_id ip port base_ip base_port protocol "
"priority type username password}");
return TCL_ERROR;
}
if (pipeline == NULL) {
Tcl_AppendResult (interp, LIBNAME " needs to be prepared first",
(char *) NULL);
return TCL_ERROR;
}
/* Get audio codecs */
if (Tcl_ListObjGetElements(interp, objv[1],
&total_codecs, &tcl_remote_codecs) != TCL_OK) {
Tcl_AppendResult (interp, "\nInvalid codec list", (char *) NULL);
return TCL_ERROR;
}
if (_tcl_codecs_to_fscodecs (interp, tcl_remote_codecs, total_codecs,
&audio_remote_codecs, FS_MEDIA_TYPE_AUDIO) != TCL_OK) {
goto error;
}
/* Get video codecs */
if (objc == 5) {
if (Tcl_ListObjGetElements(interp, objv[3],
&total_codecs, &tcl_remote_codecs) != TCL_OK) {
Tcl_AppendResult (interp, "\nInvalid codec list", (char *) NULL);
return TCL_ERROR;
}
if (_tcl_codecs_to_fscodecs (interp, tcl_remote_codecs, total_codecs,
&video_remote_codecs, FS_MEDIA_TYPE_VIDEO) != TCL_OK) {
goto error;
}
}
/* Get audio candidates */
if (Tcl_ListObjGetElements(interp, objv[2],
&total_candidates, &tcl_remote_candidates) != TCL_OK) {
Tcl_AppendResult (interp, "\nInvalid candidates list", (char *) NULL);
return TCL_ERROR;
}
if (_tcl_candidates_to_fscandidates (interp, tcl_remote_candidates,
total_candidates, &audio_remote_candidates) != TCL_OK) {
goto error;
}
/* Get video candidates */
if (objc == 5) {
if (Tcl_ListObjGetElements(interp, objv[4],
&total_candidates, &tcl_remote_candidates) != TCL_OK) {
Tcl_AppendResult (interp, "\nInvalid candidates list", (char *) NULL);
return TCL_ERROR;
}
if (_tcl_candidates_to_fscandidates (interp, tcl_remote_candidates,
total_candidates, &video_remote_candidates) != TCL_OK) {
goto error;
}
}
/* Set audio candidates */
if (audio_remote_candidates) {
if (!fs_stream_set_remote_candidates (audio_stream, audio_remote_candidates,
&error)) {
Tcl_AppendResult (interp, "Could not set the audio remote candidates",
(char *) NULL);
goto error;
}
fs_candidate_list_destroy (audio_remote_candidates);
audio_remote_candidates = NULL;
}
/* Set video candidates */
if (video_remote_candidates && video_stream) {
if (!fs_stream_set_remote_candidates (video_stream, video_remote_candidates,
&error)) {
Tcl_AppendResult (interp, "Could not set the video remote candidates",
(char *) NULL);
goto error;
}
fs_candidate_list_destroy (video_remote_candidates);
video_remote_candidates = NULL;
}
/* Set audio codecs */
if (audio_remote_codecs) {
if (!fs_stream_set_remote_codecs (audio_stream, audio_remote_codecs, &error)) {
Tcl_AppendResult (interp, "Could not set the audio remote codecs",
(char *) NULL);
goto error;
}
fs_codec_list_destroy (audio_remote_codecs);
audio_remote_codecs = NULL;
}
/* Set video codecs */
if (video_remote_codecs && video_stream) {
if (!fs_stream_set_remote_codecs (video_stream, video_remote_codecs, &error)) {
Tcl_AppendResult (interp, "Could not set the video remote codecs",
(char *) NULL);
goto error;
}
fs_codec_list_destroy (video_remote_codecs);
video_remote_codecs = NULL;
}
return TCL_OK;
error:
fs_codec_list_destroy (audio_remote_codecs);
fs_codec_list_destroy (video_remote_codecs);
fs_candidate_list_destroy (audio_remote_candidates);
fs_candidate_list_destroy (video_remote_candidates);
return TCL_ERROR;
}
int Farsight_Stop _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]))
{
// We verify the arguments
if( objc != 1) {
Tcl_WrongNumArgs (interp, 1, objv, "");
return TCL_ERROR;
}
Close ();
return TCL_OK;
}
int Farsight_InUse _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]))
{
// We verify the arguments
if( objc != 1) {
Tcl_WrongNumArgs (interp, 1, objv, "");
return TCL_ERROR;
}
Tcl_SetObjResult (interp, Tcl_NewBooleanObj (pipeline != NULL));
return TCL_OK;
}
int Farsight_DumpPipeline _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]))
{
// We verify the arguments
if( objc != 2) {
Tcl_WrongNumArgs (interp, 1, objv, "filename");
return TCL_ERROR;
}
if (pipeline)
GST_DEBUG_BIN_TO_DOT_FILE (pipeline, GST_DEBUG_GRAPH_SHOW_ALL, Tcl_GetString (objv[1]));
if (test_pipeline)
GST_DEBUG_BIN_TO_DOT_FILE (test_pipeline, GST_DEBUG_GRAPH_SHOW_ALL, Tcl_GetString (objv[1]));
return TCL_OK;
}
static int _SetMute (GstElement *element, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[])
{
gboolean mute;
// We verify the arguments
if( objc != 2) {
Tcl_WrongNumArgs (interp, 1, objv, "mute");
return TCL_ERROR;
}
if (Tcl_GetBooleanFromObj(interp, objv[1], &mute) == TCL_ERROR) {
return TCL_ERROR;
}
if (element) {
g_object_set (element, "mute", mute, NULL);
} else {
Tcl_AppendResult (interp, LIBNAME " isn't running", (char *) NULL);
return TCL_ERROR;
}
return TCL_OK;
}
int Farsight_SetMuteIn _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]))
{
return _SetMute (volumeIn, interp, objc, objv);
}
int Farsight_SetMuteOut _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]))
{
return _SetMute (volumeOut, interp, objc, objv);
}
static int _GetMute (GstElement *element, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[])
{
gboolean mute;
// We verify the arguments
if( objc != 1) {
Tcl_WrongNumArgs (interp, 1, objv, "");
return TCL_ERROR;
}
if (element) {
g_object_get (element, "mute", &mute, NULL);
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(mute));
} else {
Tcl_AppendResult (interp, LIBNAME " isn't running", (char *) NULL);
return TCL_ERROR;
}
return TCL_OK;
}
int Farsight_GetMuteIn _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]))
{
return _GetMute (volumeIn, interp, objc, objv);
}
int Farsight_GetMuteOut _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]))
{
return _GetMute (volumeOut, interp, objc, objv);
}
static int _SetVolume (GstElement *element, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[])
{
gdouble volume;
// We verify the arguments
if( objc != 2) {
Tcl_WrongNumArgs (interp, 1, objv, "volume");
return TCL_ERROR;
}
if (Tcl_GetDoubleFromObj(interp, objv[1], &volume) == TCL_ERROR) {
return TCL_ERROR;
}
volume = pow (10, volume / 20);
if (element) {
g_object_set (element, "volume", volume, NULL);
} else {
Tcl_AppendResult (interp, LIBNAME " isn't running", (char *) NULL);
return TCL_ERROR;
}
return TCL_OK;
}
int Farsight_SetVolumeIn _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]))
{
return _SetVolume (volumeIn, interp, objc, objv);
}
int Farsight_SetVolumeOut _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]))
{
return _SetVolume (volumeOut, interp, objc, objv);
}
static int _GetVolume (GstElement *element, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[])
{
gdouble volume;
// We verify the arguments
if( objc != 1) {
Tcl_WrongNumArgs (interp, 1, objv, "");
return TCL_ERROR;
}
if (element) {
g_object_get (element, "volume", &volume, NULL);
Tcl_SetObjResult(interp, Tcl_NewDoubleObj(volume));
} else {
Tcl_AppendResult (interp, LIBNAME " isn't running", (char *) NULL);
return TCL_ERROR;
}
return TCL_OK;
}
int Farsight_GetVolumeIn _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]))
{
return _GetVolume (volumeIn, interp, objc, objv);
}
int Farsight_GetVolumeOut _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]))
{
return _GetVolume (volumeOut, interp, objc, objv);
}
static gboolean
klass_contains (const gchar *klass, const gchar *needle)
{
gchar *found = strstr (klass, needle);
if(!found)
return FALSE;
if (found != klass && *(found-1) != '/')
return FALSE;
if (found[strlen (needle)] != 0 &&
found[strlen (needle)] != '/')
return FALSE;
return TRUE;
}
static gboolean
is_audio_source (GstElementFactory *factory)
{
const gchar *klass = gst_element_factory_get_klass (factory);
/* we might have some sources that provide a non raw stream */
return (klass_contains (klass, "Audio") &&
klass_contains (klass, "Source"));
}
static gboolean
is_audio_sink (GstElementFactory *factory)
{
const gchar *klass = gst_element_factory_get_klass (factory);
/* we might have some sinks that provide decoding */
return (klass_contains (klass, "Audio") &&
klass_contains (klass, "Sink"));
}
static gboolean
is_video_source (GstElementFactory *factory)
{
const gchar *klass = gst_element_factory_get_klass (factory);
/* we might have some sources that provide a non raw stream */
return (klass_contains (klass, "Video") &&
klass_contains (klass, "Source"));
}
static gboolean
is_video_sink (GstElementFactory *factory)
{
const gchar *klass = gst_element_factory_get_klass (factory);
/* we might have some sinks that provide decoding */
return (klass_contains (klass, "Video") &&
klass_contains (klass, "Sink"));
}
/* function used to sort element features */
/* Copy-pasted from decodebin */
static gint
compare_ranks (GstPluginFeature * f1, GstPluginFeature * f2)
{
gint diff;
const gchar *rname1, *rname2;
diff = gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1);
if (diff != 0)
return diff;
rname1 = gst_plugin_feature_get_name (f1);
rname2 = gst_plugin_feature_get_name (f2);
diff = strcmp (rname2, rname1);
return diff;
}
static GList *
get_plugins_filtered (gboolean source, gboolean audio)
{
GList *walk, *registry, *result = NULL;
GstElementFactory *factory;
gchar *klass = NULL;
registry = gst_registry_get_feature_list (gst_registry_get_default (),
GST_TYPE_ELEMENT_FACTORY);
registry = g_list_sort (registry, (GCompareFunc) compare_ranks);
for (walk = registry; walk; walk = g_list_next (walk)) {
factory = GST_ELEMENT_FACTORY (walk->data);
if (audio) {
if ((source && is_audio_source (factory)) ||
(!source && is_audio_sink (factory))) {
result = g_list_append (result, factory);
gst_object_ref (factory);
}
} else {
if ((source && is_video_source (factory)) ||
(!source && is_video_sink (factory))) {
result = g_list_append (result, factory);
gst_object_ref (factory);
}
}
}
gst_plugin_feature_list_free (registry);
return result;
}
int Farsight_Probe _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]))
{
Tcl_Obj *source = NULL;
Tcl_Obj *temp = NULL;
Tcl_Obj *type = NULL;
Tcl_Obj *devices = NULL;
Tcl_Obj *result = NULL;
GList *audio_sources, *audio_sinks, *video_sources, *video_sinks, *walk, *list;
gint si;
result = Tcl_NewListObj (0, NULL);
// We verify the arguments
if( objc != 1) {
Tcl_WrongNumArgs (interp, 1, objv, "");
return TCL_ERROR;
}
audio_sources = get_plugins_filtered (TRUE, TRUE);
audio_sinks = get_plugins_filtered (FALSE, TRUE);
video_sources = get_plugins_filtered (TRUE, FALSE);
video_sinks = get_plugins_filtered (FALSE, FALSE);
for (si = 0; si < 4; si++) {
switch (si) {
case 0:
list = audio_sources;
type = Tcl_NewStringObj ("audiosource", -1);
break;
case 1:
list = audio_sinks;
type = Tcl_NewStringObj ("audiosink", -1);
break;
case 2:
list = video_sources;
type = Tcl_NewStringObj ("videosource", -1);
break;
case 3:
list = video_sinks;
type = Tcl_NewStringObj ("videosink", -1);
break;
default:
break;
}
for (walk = list; walk; walk = g_list_next (walk)) {
GstPropertyProbe *probe;
GValueArray *arr;
GstElement *element;
GstElementFactory *factory = GST_ELEMENT_FACTORY(walk->data);
element = gst_element_factory_create (factory, NULL);
if (element == NULL)
continue;
source = Tcl_NewListObj (0, NULL);
devices = Tcl_NewListObj (0, NULL);
Tcl_ListObjAppendElement(NULL, source, type);
temp = Tcl_NewStringObj (GST_PLUGIN_FEATURE_NAME(factory), -1);
Tcl_ListObjAppendElement(NULL, source, temp);
temp = Tcl_NewStringObj (gst_element_factory_get_longname (factory), -1);
Tcl_ListObjAppendElement(NULL, source, temp);
temp = Tcl_NewStringObj (gst_element_factory_get_description (factory), -1);
Tcl_ListObjAppendElement(NULL, source, temp);
if (GST_IS_PROPERTY_PROBE (element)) {
probe = GST_PROPERTY_PROBE (element);
if (probe) {
arr = gst_property_probe_probe_and_get_values_name (probe, get_device_property_name(GST_PLUGIN_FEATURE_NAME(factory)));
if (arr) {
guint i;
for (i = 0; i < arr->n_values; ++i) {
const gchar *device;
GValue *val;
val = g_value_array_get_nth (arr, i);
if (val == NULL || !G_VALUE_HOLDS_STRING (val))
continue;
device = g_value_get_string (val);
if (device == NULL)
continue;
temp = Tcl_NewStringObj (device, -1);
Tcl_ListObjAppendElement(NULL, devices, temp);
}
g_value_array_free (arr);
Tcl_ListObjAppendElement(NULL, source, devices);
} else {
/* no devices found */
_notify_debug ("No devices found for element %s",
GST_PLUGIN_FEATURE_NAME(factory));
}
} else {
_notify_debug ("Unable to cast element %s to GST_PROPERTY_PROBE",
GST_PLUGIN_FEATURE_NAME(factory));
}
} else {
_notify_debug ("Element %s doesn't implement GST_PROPERTY_PROBE",
GST_PLUGIN_FEATURE_NAME(factory));
}
Tcl_ListObjAppendElement(NULL, result, source);
gst_object_unref (element);
}
for (walk = list; walk; walk = g_list_next (walk)) {
if (walk->data)
gst_object_unref (GST_ELEMENT_FACTORY (walk->data));
}
g_list_free (list);
}
Tcl_SetObjResult (interp, result);
return TCL_OK;
}
int Farsight_Config _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]))
{
static const char *farsightOptions[] = {
"-level", "-debug", "-audio-source", "-audio-source-device",
"-audio-source-pipeline", "-audio-sink", "-audio-sink-device",
"-audio-sink-pipeline", "-video-source", "-video-source-device",
"-video-preview-xid", "-video-source-pipeline", "-video-sink",
"-video-sink-xid", "-video-sink-pipeline", NULL
};
enum farsightOptions {
FS_LEVEL, FS_DEBUG, FS_AUDIO_SOURCE, FS_AUDIO_SRC_DEVICE,
FS_AUDIO_SRC_PIPELINE, FS_AUDIO_SINK, FS_AUDIO_SINK_DEVICE,
FS_AUDIO_SINK_PIPELINE, FS_VIDEO_SOURCE, FS_VIDEO_SRC_DEVICE,
FS_VIDEO_PREVIEW_XID, FS_VIDEO_SRC_PIPELINE, FS_VIDEO_SINK,
FS_VIDEO_SINK_XID, FS_VIDEO_SINK_PIPELINE
};
int optionIndex, a;
for (a = 1; a < objc; a++) {
if (Tcl_GetIndexFromObj(interp, objv[a], farsightOptions, "option",
TCL_EXACT, &optionIndex) != TCL_OK) {
return TCL_ERROR;
}
switch ((enum farsightOptions) optionIndex) {
case FS_LEVEL:
a++;
if (a >= objc) {
Tcl_AppendResult(interp,
"no argument given for -level option", NULL);
return TCL_ERROR;
}
if (level_callback) {
Tcl_DecrRefCount (level_callback);
level_callback = NULL;
level_callback_interp = NULL;
}
if (Tcl_GetString (objv[a]) != NULL &&
Tcl_GetString (objv[a])[0] != 0) {
level_callback = objv[a];
Tcl_IncrRefCount (level_callback);
level_callback_interp = interp;
}
break;
case FS_DEBUG:
a++;
if (a >= objc) {
Tcl_AppendResult(interp,
"no argument given for -debug option", NULL);
return TCL_ERROR;
}
if (debug_callback) {
Tcl_DecrRefCount (debug_callback);
debug_callback = NULL;
debug_callback_interp = NULL;
}
if (Tcl_GetString (objv[a]) != NULL &&
Tcl_GetString (objv[a])[0] != 0) {
debug_callback = objv[a];
Tcl_IncrRefCount (debug_callback);
debug_callback_interp = interp;
}
break;
case FS_AUDIO_SOURCE:
a++;
if (a >= objc) {
Tcl_AppendResult(interp,
"no argument given for -audio-source option", NULL);
return TCL_ERROR;
}
if (audio_source) {
g_free (audio_source);
audio_source = NULL;
}
if (Tcl_GetString (objv[a]) != NULL &&
Tcl_GetString (objv[a])[0] != 0) {
audio_source = g_strdup (Tcl_GetString(objv[a]));
}
break;
case FS_AUDIO_SRC_DEVICE: {
a++;
if (a >= objc) {
Tcl_AppendResult(interp,
"no argument given for -audio-source-device option", NULL);
return TCL_ERROR;
}
if (audio_source_device) {
g_free (audio_source_device);
audio_source_device = NULL;
}
if (Tcl_GetString (objv[a]) != NULL &&
Tcl_GetString (objv[a])[0] != 0) {
audio_source_device = g_strdup (Tcl_GetString(objv[a]));
}
break;
}
case FS_AUDIO_SRC_PIPELINE:
a++;
if (a >= objc) {
Tcl_AppendResult(interp,
"no argument given for -audio-source-pipeline option", NULL);
return TCL_ERROR;
}
if (audio_source_pipeline) {
g_free (audio_source_pipeline);
audio_source_pipeline = NULL;
}
if (Tcl_GetString (objv[a]) != NULL &&
Tcl_GetString (objv[a])[0] != 0) {
audio_source_pipeline = g_strdup (Tcl_GetString(objv[a]));
}
break;
case FS_AUDIO_SINK:
a++;
if (a >= objc) {
Tcl_AppendResult(interp,
"no argument given for -audio-sink option", NULL);
return TCL_ERROR;
}
if (audio_sink) {
g_free (audio_sink);
audio_sink = NULL;
}
if (Tcl_GetString (objv[a]) != NULL &&
Tcl_GetString (objv[a])[0] != 0) {
audio_sink = g_strdup (Tcl_GetString(objv[a]));
}
break;
case FS_AUDIO_SINK_DEVICE: {
a++;
if (a >= objc) {
Tcl_AppendResult(interp,
"no argument given for -audio-sink-device option", NULL);
return TCL_ERROR;
}
if (audio_sink_device) {
g_free (audio_sink_device);
audio_sink_device = NULL;
}
if (Tcl_GetString (objv[a]) != NULL &&
Tcl_GetString (objv[a])[0] != 0) {
audio_sink_device = g_strdup (Tcl_GetString(objv[a]));
}
break;
}
case FS_AUDIO_SINK_PIPELINE:
a++;
if (a >= objc) {
Tcl_AppendResult(interp,
"no argument given for -audio-sink-pipeline option", NULL);
return TCL_ERROR;
}
if (audio_sink_pipeline) {
g_free (audio_sink_pipeline);
audio_sink_pipeline = NULL;
}
if (Tcl_GetString (objv[a]) != NULL &&
Tcl_GetString (objv[a])[0] != 0) {
audio_sink_pipeline = g_strdup (Tcl_GetString(objv[a]));
}
break;
case FS_VIDEO_SOURCE:
a++;
if (a >= objc) {
Tcl_AppendResult(interp,
"no argument given for -video-source option", NULL);
return TCL_ERROR;
}
if (video_source) {
g_free (video_source);
video_source = NULL;
}
if (Tcl_GetString (objv[a]) != NULL &&
Tcl_GetString (objv[a])[0] != 0) {
video_source = g_strdup (Tcl_GetString(objv[a]));
}
break;
case FS_VIDEO_SRC_DEVICE: {
a++;
if (a >= objc) {
Tcl_AppendResult(interp,
"no argument given for -video-source-device option", NULL);
return TCL_ERROR;
}
if (video_source_device) {
g_free (video_source_device);
video_source_device = NULL;
}
if (Tcl_GetString (objv[a]) != NULL &&
Tcl_GetString (objv[a])[0] != 0) {
video_source_device = g_strdup (Tcl_GetString(objv[a]));
}
break;
}
case FS_VIDEO_PREVIEW_XID: {
a++;
if (a >= objc) {
Tcl_AppendResult(interp,
"no argument given for -video-preview-xid option", NULL);
return TCL_ERROR;
}
if (Tcl_GetLongFromObj (interp, objv[a], &video_preview_xid) != TCL_OK) {
return TCL_ERROR;
}
break;
}
case FS_VIDEO_SRC_PIPELINE:
a++;
if (a >= objc) {
Tcl_AppendResult(interp,
"no argument given for -video-source-pipeline option", NULL);
return TCL_ERROR;
}
if (video_source_pipeline) {
g_free (video_source_pipeline);
video_source_pipeline = NULL;
}
if (Tcl_GetString (objv[a]) != NULL &&
Tcl_GetString (objv[a])[0] != 0) {
video_source_pipeline = g_strdup (Tcl_GetString(objv[a]));
}
break;
case FS_VIDEO_SINK:
a++;
if (a >= objc) {
Tcl_AppendResult(interp,
"no argument given for -video-sink option", NULL);
return TCL_ERROR;
}
if (video_sink) {
g_free (video_sink);
video_sink = NULL;
}
if (Tcl_GetString (objv[a]) != NULL &&
Tcl_GetString (objv[a])[0] != 0) {
video_sink = g_strdup (Tcl_GetString(objv[a]));
}
break;
case FS_VIDEO_SINK_XID: {
a++;
if (a >= objc) {
Tcl_AppendResult(interp,
"no argument given for -video-sink-xid option", NULL);
return TCL_ERROR;
}
if (Tcl_GetLongFromObj (interp, objv[a], &video_sink_xid) != TCL_OK) {
return TCL_ERROR;
}
break;
}
case FS_VIDEO_SINK_PIPELINE:
a++;
if (a >= objc) {
Tcl_AppendResult(interp,
"no argument given for -video-sink-pipeline option", NULL);
return TCL_ERROR;
}
if (video_sink_pipeline) {
g_free (video_sink_pipeline);
video_sink_pipeline = NULL;
}
if (Tcl_GetString (objv[a]) != NULL &&
Tcl_GetString (objv[a])[0] != 0) {
video_sink_pipeline = g_strdup (Tcl_GetString(objv[a]));
}
break;
default:
Tcl_AppendResult(interp,
"bad option to ::Farsight::Config", NULL);
return TCL_ERROR;
break;
}
}
return TCL_OK;
}
/*
Function : Farsight_Init
Description : The Init function that will be called when the extension
is loaded to your tcl shell
*/
int Farsight_Init (Tcl_Interp *interp) {
#ifdef G_OS_WIN32
WSADATA w;
#endif
//Check Tcl version is 8.4 or higher
if (Tcl_InitStubs(interp, "8.4", 0) == NULL) {
return TCL_ERROR;
}
#if defined(__APPLE__) || defined(__BSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
gst_registry_fork_set_enabled((gboolean)FALSE);
#endif
gst_init (NULL, NULL);
#ifdef G_OS_WIN32
WSAStartup(0x0202, &w);
#endif
// Create the wrapping commands in the Farsight namespace
Tcl_CreateObjCommand(interp, "::Farsight::Prepare", Farsight_Prepare,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "::Farsight::Start", Farsight_Start,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "::Farsight::Stop", Farsight_Stop,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "::Farsight::InUse", Farsight_InUse,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "::Farsight::Probe", Farsight_Probe,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "::Farsight::SetVolumeIn", Farsight_SetVolumeIn,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "::Farsight::GetVolumeIn", Farsight_GetVolumeIn,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "::Farsight::SetVolumeOut", Farsight_SetVolumeOut,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "::Farsight::GetVolumeOut", Farsight_GetVolumeOut,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "::Farsight::SetMuteIn", Farsight_SetMuteIn,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "::Farsight::GetMuteIn", Farsight_GetMuteIn,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "::Farsight::SetMuteOut", Farsight_SetMuteOut,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "::Farsight::GetMuteOut", Farsight_GetMuteOut,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "::Farsight::Config", Farsight_Config,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "::Farsight::TestAudio", Farsight_TestAudio,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "::Farsight::TestVideo", Farsight_TestVideo,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "::Farsight::DumpPipeline", Farsight_DumpPipeline,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
// end of Initialisation
return TCL_OK;
}
int Farsight_SafeInit (Tcl_Interp *interp) {
return Farsight_Init(interp);
}
int Tcl_farsight_Init (Tcl_Interp *interp) {
return Farsight_Init(interp);
}
int Tcl_farsight_SafeInit (Tcl_Interp *interp) {
return Farsight_Init(interp);
}
int Farsight_Unload (Tcl_Interp *interp) {
Close();
return TCL_OK;
}
int Farsight_SafeUnload (Tcl_Interp *interp) {
return Farsight_Unload(interp);
}
int Tcl_farsight_SafeUnload (Tcl_Interp *interp) {
return Farsight_SafeUnload(interp);
}
int Tcl_farsight_Unload (Tcl_Interp *interp) {
return Farsight_Unload(interp);
}
amsn-0.98.9/utils/farsight/src/Rules.mk 0000644 0001750 0001750 00000000615 11755433160 017561 0 ustar billiob billiob OBJS-tcl_farsight := $(tcl_farsight_dir)/src/tcl_farsight.o
TARGETS-tcl_farsight := $(tcl_farsight_dir)/src/tcl_farsight.$(SHLIB_EXTENSION)
$(OBJS-tcl_farsight): CFLAGS += ${FARSIGHT2_CFLAGS}
$(TARGETS-tcl_farsight): LDFLAGS += ${FARSIGHT2_LIBS}
all:: $(TARGETS-tcl_farsight)
clean:: clean-tcl_farsight
clean-tcl_farsight::
rm -f $(TARGETS-tcl_farsight) $(OBJS-tcl_farsight)
amsn-0.98.9/utils/farsight/src/tcl_farsight.h 0000644 0001750 0001750 00000004113 11236675310 020754 0 ustar billiob billiob /*
File : tcl_farsight.h
Description : Header file for the tcl_farsight extension for tcl.
Author : Youness El Alaoui ( KaKaRoTo - kakaroto@user.sourceforge.net)
*/
#ifndef _TCL_FARSIGHT
#define _TCL_FARSIGHT
// Include files, must include windows.h before tk.h and tcl.h before tk.h or else compiling errors
#include
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include
#endif
#include
// Defined as described in tcl.tk compiling extension help
#ifndef STATIC_BUILD
#if defined(_MSC_VER)
# define EXPORT(a,b) __declspec(dllexport) a b
# define DllEntryPoint DllMain
#else
# if defined(__BORLANDC__)
# define EXPORT(a,b) a _export b
# else
# define EXPORT(a,b) a b
# endif
#endif
#endif
#define DLL_BUILD
#define BUILD_TCL_FARSIGHT
#ifdef BUILD_TCL_FARSIGHT
# undef TCL_STORAGE_CLASS
# define TCL_STORAGE_CLASS DLLEXPORT
#endif
#ifdef __cplusplus
extern "C"
#endif
// External functions
EXTERN int Tcl_farsight_Init _ANSI_ARGS_((Tcl_Interp *interp));
EXTERN int Tcl_farsight_SafeInit _ANSI_ARGS_((Tcl_Interp *interp));
EXTERN int Farsight_Init _ANSI_ARGS_((Tcl_Interp *interp));
EXTERN int Farsight_SafeInit _ANSI_ARGS_((Tcl_Interp *interp));
EXTERN int Farsight_Prepare _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
EXTERN int Farsight_Start _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
EXTERN int Farsight_InUse _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
EXTERN int Farsight_Stop _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
EXTERN int Farsight_Probe _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
#ifdef __APPLE__
#include
@interface FarsightAppDelegate : NSObject
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
@end
#endif
# undef TCL_STORAGE_CLASS
# define TCL_STORAGE_CLASS DLLIMPORT
#endif /* _TCL_FARSIGHT */
amsn-0.98.9/utils/farsight/Rules.mk 0000644 0001750 0001750 00000000764 11755433160 016777 0 ustar billiob billiob OBJS-farsight := $(tcl_farsight_dir)/src/tcl_farsight.$(SHLIB_EXTENSION)
TARGETS-farsight := $(tcl_farsight_dir)/tcl_farsight.$(SHLIB_EXTENSION)
ifeq (${HAVE_FARSTREAM},yes)
$(OBJS-farsight): CFLAGS+=-DHAVE_FARSTREAM
else
ifeq (${HAVE_FARSIGHT},yes)
$(OBJS-farsight): CFLAGS+=-DHAVE_FARSIGHT
endif
endif
$(TARGETS-farsight): $(OBJS-farsight)
cp $< $@
all:: $(TARGETS-farsight)
clean:: clean-farsight
clean-farsight::
rm -f $(TARGETS-farsight) $(OBJS-farsight)
amsn-0.98.9/utils/drawboard/ 0000755 0001750 0001750 00000000000 11757711633 015511 5 ustar billiob billiob amsn-0.98.9/utils/drawboard/pkgIndex.tcl 0000644 0001750 0001750 00000000123 10356234135 017751 0 ustar billiob billiob package ifneeded drawboard 0.2 \
[list source [file join $dir drawboard.tcl]]
amsn-0.98.9/utils/drawboard/grid.png 0000644 0001750 0001750 00000000312 10433151545 017126 0 ustar billiob billiob PNG
IHDR ;0 bKGD C pHYs tIME 71LQ tEXtComment Created with The GIMPd%n .IDATH
CĈ;KbX,bTm+2_ IENDB` amsn-0.98.9/utils/drawboard/drawboard.tcl 0000644 0001750 0001750 00000031626 11472317214 020161 0 ustar billiob billiob ##Drawboard widget by Karel Demeyer
#
# NAME
#
# drawboard - Create and manipulate drawboard widgets
#
# SYNOPSIS
#
# drawboard pathName ?options?
#
# STANDARD OPTIONS
#
# ...
#
# WIDGET-SPECIFIC OPTIONS
#
# -grid, grid, Grid
# -drawmode, drawmode, Drawmode
# -color, color, Color
# -pencil, pencil, Pencil
# -width, width, Width
# -height, height, Height
#
# WIDGET COMMAND
#
# pathName cget option
# pathName configure ?option? ?value option value ...?
#TODO:
# -gridimg option
# provide 1 default pencil and 1 default gridimg
# Improved Saving
# Loading
# fixed dimensions (-width / -height doesn't work yet properly)
# remove amsn plus button
# review cutting .. it has bugs
package require snit
package provide drawboard 0.2
snit::widgetadaptor drawboard {
option -grid -default 1 -configuremethod SetConfig
option -drawmode -default free
option -color -default black -configuremethod SetConfig
option -pencil -default pencil1 -configuremethod SetConfig
option -width -default 100
option -height -default 100
#option -gridimg
variable buttondown
variable oldx
variable oldy
variable endx
variable endy
variable gridsourceimg
variable strokes_list
variable curStroke
variable curDrawingAttributes
variable drawAttrs_list
constructor { args } {
installhull using canvas -bg white -relief flat -highlightthickness 0 -width $options(-width) -height $options(-height)
status_log "creating drawboard widget $self"
$self configurelist $args
#if {$options(-gridimg) == ""} {
# set gridsourceimg [$self LoadImage drawboardgrid grid.png]
#} else {
# set gridsourceimg $options(-gridimg)
#}
set gridsourceimg [::skin::loadPixmap grid]
#give the grid a color
::picture::Colorize $gridsourceimg blue
#create the image where we will copy the grid on (tiled)
image create photo grid$self
#put the grid-image (initially empty) on the canvas
$hull create image 0 0 -anchor nw -image grid$self -tag grid
#create the initial drawboard img
set drawboard [image create photo] ;# -width $width -height $height]
#put the drawboard-img on the canvas
$hull create image 0 0 -anchor nw -image $drawboard -tag drawboard
#make it possible to disable coloring of pencils, for "stamps" (like using smileys as pencil)
$self SetConfig coloring 1
$self UpdatePencil
set endx 0
set endy 0
set strokes_list [list]
set curDrawingAttributes [list 7 $options(-color)]
set drawAttrs_list [list]
#bindings
bind $self "$self ButtonDown"
bind $self "$self MouseMove"
bind $self "$self ButtonRelease"
bind $self "$self Configure"
$self configurelist $args
}
method LoadImage {imagename filename} {
return [image create photo $imagename -file $filename.gif]
}
###############################################
# When mousebutton pressed #
###############################################
method ButtonDown {} {
set drawboard [$hull itemcget drawboard -image]
#change the buttondown-flag
set buttondown 1
#set initial coordinates of the mouse on the drawboard
set oldx [expr {[winfo pointerx $self] - [winfo rootx $self]}]
set oldy [expr {[winfo pointery $self] - [winfo rooty $self]}]
set curStroke [list $oldx $oldy]
$self DrawDot $oldx $oldy
$self SetEnds $oldx $oldy
}
###############################################
# When mousebutton is released #
###############################################
method ButtonRelease {} {
if { $options(-drawmode) == "line"} {
set drawboard [$hull itemcget drawboard -image]
set newx [expr {[winfo pointerx $self] - [winfo rootx $self]}]
set newy [expr {[winfo pointery $self] - [winfo rooty $self]}]
$self DrawLine $oldx $oldy $newx $newy
$self SetEnds $newx $newy
lappend curStroke $newx $newy
}
lappend strokes_list $curStroke
lappend drawAttrs_list $curDrawingAttributes
#change the buttondown-flag
set buttondown 0
unset oldx oldy
}
###############################################
# When the mouse is moved #
###############################################
method MouseMove {} {
if { $options(-drawmode) == "free" } {
#If we're dragging, draw
if {$buttondown} {
#Get the names of the items
set drawboard [$hull itemcget drawboard -image]
#find the coordinates of the mouse on the selfas (drawboard)
set posx [expr {[winfo pointerx $self] - [winfo rootx $self]}]
set posy [expr {[winfo pointery $self] - [winfo rooty $self]}]
#if the coords made a jump, draw a line between 'm, otherwise just draw a dot
if {[expr abs($oldx - $posx)] > 2 || [expr abs($oldy - $posy)] > 2} {
$self DrawLine $oldx $oldy $posx $posy
} else {
$self DrawDot $posx $posy
}
#remember where we were
set oldx $posx
set oldy $posy
lappend curStroke $oldx $oldy
$self SetEnds $posx $posy
}
}
}
###############################################
# Draws a dot with the pencil on given coords #
###############################################
method DrawDot { x y } {
set drawboard [$hull itemcget drawboard -image]
set x [expr {$x - [image width pencil_$self]/2}]
set y [expr {$y - [image height pencil_$self]/2}]
#only draw if on the drawboard
if {$x > 0 && $y > 0 && $x < [$drawboard cget width] && $y < [$drawboard cget height]} {
$drawboard copy pencil_$self -to $x $y
}
}
###############################################
# Draws a line between 2 given coord-pairs #
# with the pencil #
###############################################
method DrawLine { x1 y1 x2 y2 } {
set drawboard [$hull itemcget drawboard -image]
set xsize [$drawboard cget width]
set ysize [$drawboard cget heigth]
#if we end off the board, end on the edge
if {$x2 < 0} { set x2 0}
if {$y2 < 0} { set y2 0}
if { $x2 > $xsize } { set x2 $xsize }
if { $y2 > $ysize } { set y2 $ysize }
#calculate the x and y distance
set xdist [expr {($x1 - $x2)*1.0}]
set ydist [expr {($y1 - $y2)*1.0}]
#also get there absolute values
set absxdist [expr {abs($xdist)}]
set absydist [expr {abs($ydist)}]
#calculate the x and y diffs
if {$absxdist > $absydist} {
set absdist $absxdist
} else {
set absdist $absydist
}
if {$absdist == 0} {
set xdiff 0
set ydiff 0
} else {
set xdiff [expr {$xdist / $absdist}]
set ydiff [expr {$ydist / $absdist}]
}
set steps $absdist
#draw the line
for {set idx 0} { $idx < $steps } {incr idx } {
set x1 [expr {$x1 - $xdiff}]
set y1 [expr {$y1 - $ydiff}]
$self DrawDot [expr int($x1)] [expr int($y1)]
}
}
method Configure {} {
#get the new dimensions
set width [winfo width $self]
set height [winfo height $self]
if { $height < $endy } {
set endy $height
}
if { $width < $endx } {
set endx $width
}
set drawboard [$hull itemcget drawboard -image]
$drawboard configure -width $width -height $height
$self UpdateGrid
}
method UpdateGrid { } {
if { $options(-grid) == 1 } {
set width [winfo width $self]
set height [winfo height $self]
grid$self copy $gridsourceimg -to 0 0 $width $height -shrink
} else {
catch {grid$self blank}
}
}
method SetEnds {x y} {
set farx [expr $x + [image width pencil_$self]]
set fary [expr $y + [image height pencil_$self]]
if { $farx > $endx } {
set endx $farx
}
if { $fary > $endy } {
set endy $fary
}
}
method ClearDrawboard {} {
[$hull itemcget drawboard -image] blank
set endx 0
set endy 0
set strokes_list [list]
set curStroke_x [list]
set curStroke_y [list]
set curDrawingAttributes [list 7 $options(-color)]
set drawAttrs_list [list]
}
#TODO:
method LoadDrawing { filename } {
#$self ClearDrawboard
#draw loaded image
set drawboard [$hull itemcget drawboard -image]
set loadedimg [image create photo -file $filename]
$drawboard copy $loadedimg
$self SetEnds [image width $loadedimg] [image height $loadedimg]
$self Configure
}
method SaveDrawing {filename {gifFortified 0}} {
set drawboard [$hull itemcget drawboard -image]
#to make sure the ends are not to far and all is right
set boardh [image height $drawboard]
set boardw [image width $drawboard]
if {$boardh < $endy} {
set endy $boardh
}
if {$boardw < $endx} {
set endx $boardw
}
#only save to the most far used coordinates
image create photo temp
temp copy $drawboard -from 0 0 $endx $endy
image create photo $drawboard
$drawboard copy temp
#put the drawboard on a white background
image create photo copytosend ;# -width [image width $drawboard] -height [image height $drawboard]
#fix the "cannot save empty file" bug
if { $endx == 0 || $endy == 0 } {
copytosend put {#ffffff} -to 1 1 [image width $drawboard] [image height $drawboard]
} else {
copytosend put {#ffffff} -to 0 0 [image width $drawboard] [image height $drawboard]
}
copytosend copy $drawboard
set endx 0
set endy 0
::picture::Save copytosend $filename cxgif
# Fortify the GIF with the strokes_list
if {$gifFortified} {
if {![catch {package require tclISF 0.3}]} {
if {[catch {[tclISF save $filename $strokes_list $drawAttrs_list]} err]} {
status_log "\[SaveDrawing\] saving to file $filename. Got Error: $err" red
status_log "$strokes_list" red
status_log "$drawAttrs_list" red
}
} else {
if {![catch {package require -exact tclISF 0.2}]} {
if {[catch {[tclISF_save $filename $strokes_list $drawAttrs_list]} err]} {
status_log "\[SaveDrawing\] saving to file $filename. Got Error: $err" red
status_log "$strokes_list" red
status_log "$drawAttrs_list" red
}
}
}
}
image delete copytosend
image delete temp
}
method ToggleGrid {} {
if { $options(-grid) == 1} {
$self SetConfig -grid 0
} else {
$self SetConfig -grid 1
}
}
method SetConfig {option value} {
set options($option) $value
#actions after change of options
#the space was added so the option isn't passed to the switch command
switch " $option" {
" -grid" {
$self UpdateGrid
}
" -pencil" {
$self UpdatePencil
}
" -color" {
$self UpdatePencil
}
}
}
method UpdatePencil { } {
set pencilname $options(-pencil)
#if the pencil img already exists, delete it first before we (re)make it
catch { image delete pencil_$self }
set pencilimg [::skin::loadPixmap $pencilname]
#get the dimensions for the pencil-image
set width [image width $pencilimg]
set height [image height $pencilimg]
#create the pencil image
image create photo pencil_$self -width $width -height $height
#copy the source-img on the new (still empty) pencil image
pencil_$self copy $pencilimg
#color the pencil
::picture::Colorize pencil_$self $options(-color)
#fill the drawing attributes
if {[string first "pencil_" $pencilname] == 0} {
set width [string range $pencilname 7 end]
}
set curDrawingAttributes [list $width $options(-color)]
}
}
amsn-0.98.9/utils/contentmanager/ 0000755 0001750 0001750 00000000000 11757711633 016551 5 ustar billiob billiob amsn-0.98.9/utils/contentmanager/pkgIndex.tcl 0000644 0001750 0001750 00000000135 10364215620 021011 0 ustar billiob billiob package ifneeded contentmanager 0.1 \
[list source [file join $dir contentmanager.tcl]]
amsn-0.98.9/utils/contentmanager/contentmanager.tcl 0000644 0001750 0001750 00000054502 10406336725 022263 0 ustar billiob billiob package provide contentmanager 0.1
package require snit
package require scalable-bg
package require contentmanager
# o-------------------------------------------------------------------------------+
# Name: contentmanager |
# Description: Manager type |
# Function: Provide an easy-to-use API to groups and elements |
# o-------------------------------------------------------------------------------+
snit::type contentmanager {
pragma -hasinstances no
pragma -hastypeinfo no
pragma -hastypedestroy no
# -------------------------------------------------------------------------------
# Methods to create, destroy, configure and use groups and elements
# -------------------------------------------------------------------------------
typemethod getpath { args } {
set path {}
foreach name $args {
# strings beginning with - are options, end getting path
if { [string equal [string index $name 0] "-"] } {
break
}
if { [string equal $path {}] } {
set path $name
} else {
set path $path.$name
}
}
return $path
}
typemethod gettree { args } {
set tree {}
foreach name $args {
if { [string equal [string index $name 0] "-"] } {
break
} else {
lappend tree $name
}
}
return $tree
}
typemethod getopts { args } {
set opts {}
foreach opt $args {
if { [string equal [string index $opt 0] "-"] } {
set val [lindex $args [expr {[lsearch $args $opt] + 1}]]
lappend opts $opt $val
continue
} else {
continue
}
}
return $opts
}
typemethod add { _type args } {
set path [eval $type getpath $args]
set opts [eval $type getopts $args]
set tree [eval $type gettree $args]
# Check item doesn't already exist
if { [info command $path] != {} } {
error "$_type '$path' already exists"
return {}
}
switch $_type {
group {
eval group $path -tree [list $tree] $opts
# If this isn't a toplevel group...
if { [llength $tree] > 1 } {
# ...set it's state to its parent's state and register with its parent
set parent [eval $type getpath [lrange $tree 0 end-1]]
$path configure -state [$parent cget -state]
set id [lindex $tree end]
$parent register $id
} else {
set id $tree
}
}
element {
eval element $path -tree [list $tree] $opts
# If this isn't a toplevel element...
if { [llength $tree] > 1 } {
# ...set it's state to its parent's state and register with its parent
set parent [eval $type getpath [lrange $tree 0 end-1]]
$path configure -state [$parent cget -state]
set id [lindex $tree end]
$parent register $id
} else {
set id $tree
}
}
attachment {
eval element $path -tree [list $tree] $opts
# Set it's state to its parent's state and attach it to its parent
set parent [eval $type getpath [lrange $tree 0 end-1]]
$path configure -state [$parent cget -state]
set id [lindex $tree end]
$parent attach $id
}
default {
error "unknown item type '${_type}'"
}
}
return $id
}
typemethod insert { index _type args } {
# Check index is okay
if { ![string is integer $index] && $index != "end" } {
error "invalid insert index '$index'"
}
set path [eval $type getpath $args]
set opts [eval $type getopts $args]
set tree [eval $type gettree $args]
# Check item doesn't already exist
if { [info command $path] != {} } {
error "$_type '$path' already exists"
return {}
}
if { [string equal $_type "group"] } {
set parent [eval $type getpath [lrange $tree 0 end-1]]
eval group $path -tree [list $tree] $opts
# If this isn't a toplevel group...
if { [llength $tree] > 1 } {
# ...set it's state to its parent's state and register with its parent
set parent [eval $type getpath [lrange $tree 0 end-1]]
$path configure -state [$parent cget -state]
set id [lindex $tree end]
$parent register $id $index
} else {
set id $tree
}
} elseif { [string equal $_type "element"] } {
eval element $path -tree [list $tree] $opts
# If this isn't a toplevel element...
if { [llength $tree] > 1 } {
# ...set it's state to its parent's state and register with its parent
set parent [eval $type getpath [lrange $tree 0 end-1]]
$path configure -state [$parent cget -state]
set id [lindex $tree end]
$parent register $id $index
} else {
set id $tree
}
}
return $id
}
typemethod delete { args } {
set path [eval $type getpath $args]
set tree [eval $type gettree $args]
$path destroy
}
typemethod configure { args } {
set path [eval $type getpath $args]
set opts [eval $type getopts $args]
$path configurelist $opts
}
typemethod cget { args } {
set tree [lrange $args 0 end-1]
set opt [lindex $args end]
set path [eval $type getpath $tree]
return [$path cget $opt]
}
typemethod children { args } {
set path [eval $type getpath $args]
return [$path children]
}
typemethod coords { args } {
set tree [lrange $args 0 end-2]
set coords [lrange $args end-1 end]
foreach ord $coords {
if { ![string is integer $ord] } {
error "cant user non-numeric '$ord' value as ordinate"
}
}
set path [eval $type getpath $tree]
eval $path coords $coords
}
typemethod getcoords { args } {
set path [eval $type getpath $args]
return [eval $path coords]
}
typemethod width { args } {
set path [eval $type getpath $args]
return [eval $path cget -width]
}
typemethod height { args } {
set path [eval $type getpath $args]
return [eval $path cget -height]
}
typemethod move { args } {
set tree [lrange $args 0 end-2]
set vector [lrange $args end-1 end]
set path [eval $type getpath $tree]
eval $path move $vector
}
typemethod bind { args } {
set tree [lrange $args 0 end-2]
set path [eval $type getpath $tree]
set pattern [lindex $args end-1]
set command [lindex $args end]
eval $path bind $pattern [list $command]
}
typemethod show { args } {
set path [eval $type getpath $args]
set opts [eval $type getopts $args]
eval $path show $opts
}
typemethod hide { args } {
set path [eval $type getpath $args]
set opts [eval $type getopts $args]
eval $path hide $opts
}
typemethod toggle { args } {
set path [eval $type getpath $args]
eval $path toggle
}
typemethod sort { args } {
set lvlopt [lsearch $args -level]
if { $lvlopt == -1 } {
set level r
} else {
set level [lindex $args [expr {$lvlopt + 1}]]
}
set path [eval $type getpath $args]
eval $path sort $level
}
typemethod type { args } {
set path [eval $type getpath $args]
return [eval $path type]
}
typemethod register { args } {
set tree [eval $type gettree $args]
set path [eval $type getpath [lrange $args 0 end-1]]
set id [lindex $tree end]
$path register $id
}
typemethod unregister { args } {
set tree [eval $type gettree $args]
set path [eval $type getpath [lrange $args 0 end-1]]
set id [lindex $tree end]
$path unregister $id
}
}
snit::type group {
# Parent options
option -widget -configuremethod SetWidget
option -parent
option -id
option -tree
# Dimension options
option -align -default left
option -orient -default vertical
option -height -default 0 -configuremethod SetHeight
option -valign -default top
option -width -default 0 -configuremethod SetWidth
# Padding options
option -padx -default 0
option -pady -default 0
option -ipadx -default 0
option -ipady -default 0
# State options
option -omnipresent -default no
option -state -default normal -configuremethod SetState
# Position variables
variable xPos
variable yPos
# Children variables
variable items
variable hiddenitems
variable bboxid
# Attachment variables
variable attachments
# Afterid variables
variable afterid
# Binding variables
variable havebinding
constructor { args } {
set xPos 0
set yPos 0
set items {}
set bboxid {}
set attachments {}
array set afterid {sort {}}
set havebinding 0
$self configurelist $args
}
destructor {
catch {
foreach item $items {
set tree $options(-tree)
lappend tree $item
eval contentmanager delete $tree
}
}
catch { $options(-widget) delete $bboxid }
catch { eval contentmanager unregister $options(-tree) }
}
method type { } {
return "group"
}
method SetWidget { opt val } {
set options(-widget) $val
set bboxid [$val create rect 0 0 0 0 -fill "" -outline "" -state hidden]
}
method SetWidth { opt val } {
set options(-width) $val
if { ![string equal $bboxid ""] } {
$options(-widget) coords $bboxid $xPos $yPos [expr {$xPos + $val}] [expr {$yPos + $options(-height)}]
}
}
method SetHeight { opt val } {
set options(-height) $val
if { [$self GotWidget] } {
$options(-widget) coords $bboxid $xPos $yPos [expr {$xPos + $options(-width)}] [expr {$yPos + $val}]
}
}
method SetState { opt val } {
set options(-state) $val
switch $val {
"partlyhidden" {
$self hide
}
"hidden" {
$self hide
}
"normal" {
$self show
}
}
}
method GotWidget { } {
if { ![string equal $bboxid ""] } {
return 1
} else {
return 0
}
}
method register { id {idx ""} } {
if { [string equal $idx ""] } {
lappend items $id
} else {
set items [linsert $items $idx $id]
}
}
method unregister { id } {
set idx [lsearch $items $id]
set list1 [lrange $items 0 [expr {$idx - 1}]]
set list2 [lrange $items [expr {$idx + 1}] end]
set items [concat $list1 $list2]
}
method children { } {
return $items
}
method attach { id } {
lappend attachments $id
}
method bind { pat cmd {mode "bbox"} } {
if { [string equal $cmd {}] } {
set havebinding 0
$options(-widget) itemconfigure $bboxid -state hidden
} else {
set havebinding 1
if { $mode == "bbox" } {
$options(-widget) itemconfigure $bboxid -state normal
}
}
switch $mode {
"bbox" {
$options(-widget) bind $bboxid $pat $cmd
}
"components" {
foreach item $items {
set tree $options(-tree)
lappend tree $item
eval contentmanager bind $tree $pat [list $cmd]
}
}
}
}
method coords { {x {}} {y {}} } {
if { [string equal $x {}] } {
return "$xPos $yPos"
} elseif { $x == $xPos && $y == $yPos } {
return
}
set dx [expr {$x - $xPos}]
set dy [expr {$y - $yPos}]
$self move $dx $dy
}
method move { dx {dy {}} } {
if { $dx == 0 } {
if { $dy == 0 || [string equal $dy {}] } {
return
}
}
incr xPos $dx
if { [string equal $dy {}] } {
foreach item $items {
set tree $options(-tree)
lappend tree $item
eval contentmanager move $tree $dx
}
if { [$self GotWidget] } {
$options(-widget) move $bboxid $dx
}
} else {
incr yPos $dy
foreach item $items {
set tree $options(-tree)
lappend tree $item
eval contentmanager move $tree $dx $dy
}
if { [$self GotWidget] } {
$options(-widget) move $bboxid $dx $dy
}
}
$self PlaceAttachments
}
method show { args } {
if { [string equal $args {}] } {
set level r
} else {
set level [lindex $args 1]
}
foreach item $items {
set tree $options(-tree)
lappend tree $item
if { [eval contentmanager cget $tree -omnipresent] } {
continue
}
if { [string is integer $level] && $level > 0 } {
eval contentmanager show $tree -level [expr {$level - 1}]
} elseif { $level == "r" } {
eval contentmanager show $tree
}
}
foreach attachment $attachments {
if { [eval contentmanager cget $tree -omnipresent] } {
continue
} else {
set tree $options(-tree)
lappend tree $attachment
eval contentmanager show $tree
}
}
set options(-state) normal
if { $havebinding } {
$options(-widget) itemconfigure $bboxid -state normal
}
}
method hide { args } {
if { [string equal $args {}] } {
set force 0
} else {
set force [lindex $args 1]
}
set omnipresent 0
foreach item $items {
set tree $options(-tree)
lappend tree $item
if { [eval contentmanager cget $tree -omnipresent] && !$force } {
set omnipresent 1
continue
}
eval contentmanager hide $tree
}
foreach attachment $attachments {
if { [eval contentmanager cget $tree -omnipresent] } {
continue
} else {
set tree $options(-tree)
lappend tree $attachment
eval contentmanager hide $tree
}
}
if { $omnipresent && !$force } {
set options(-state) "partlyhidden"
} else {
set options(-state) "hidden"
}
$options(-widget) itemconfigure $bboxid -state hidden
}
method toggle { } {
switch $options(-state) {
"normal" {
$self hide
}
"hidden" {
$self show
}
"partlyhidden" {
$self show
}
}
}
method sort { {level r} } {
# Initial coords
set x [expr {$xPos + $options(-ipadx)}]
set y [expr {$yPos + $options(-ipady)}]
set width 0
set height 0
# Which way are we sorting (horizontally or vertically)
switch $options(-orient) {
"horizontal" {
set itempady 0
foreach item $items {
set tree $options(-tree)
lappend tree $item
# If the item is hidden, skip it
if { [string equal [eval contentmanager cget $tree -state] "hidden"] } {
continue
}
# Sort the item
if { [string is integer $level] && $level > 0 } {
eval contentmanager sort $tree -level [expr {$level - 1}]
} elseif { [string equal $level r] } {
eval contentmanager sort $tree -level r
}
set itempadx [eval contentmanager cget $tree -padx]
set itempady [eval contentmanager cget $tree -pady]
set itemwidth [eval contentmanager width $tree]
set itemheight [eval contentmanager height $tree]
incr x $itempadx
incr y $itempady
eval contentmanager coords $tree $x $y
incr x $itempadx
incr y -$itempady
incr x $itemwidth
# Is this the tallest item so far?
if { $itemheight > $height } {
set height $itemheight
}
}
set width [expr {$x - $xPos + $options(-ipadx)}]
incr height [expr {(2 * $options(-ipady)) + $itempady}]
$self configure -height $height
$self configure -width $width
# Align the items with each other
$self AlignItems
}
"vertical" {
set itempadx 0
foreach item $items {
set tree $options(-tree)
lappend tree $item
# If the item is hidden, skip it
if { [string equal [eval contentmanager cget $tree -state] "hidden"] } {
continue
}
if { [string is integer $level] && $level > 0 } {
eval contentmanager sort $tree -level [expr {$level - 1}]
} elseif { [string equal $level r] } {
eval contentmanager sort $tree -level r
}
set itempadx [eval contentmanager cget $tree -padx]
set itempady [eval contentmanager cget $tree -pady]
set itemwidth [eval contentmanager width $tree]
set itemheight [eval contentmanager height $tree]
incr x $itempadx
incr y $itempady
eval contentmanager coords $tree $x $y
incr x -$itempadx
incr y $itempady
incr y $itemheight
# Is this the widest item so far?
if { $itemwidth > $width } {
set width $itemwidth
}
}
set height [expr {$y - $yPos + $options(-ipady)}]
incr width [expr {(2 * $options(-ipadx)) + $itempadx}]
$self configure -width $width
$self configure -height $height
# Align the elements with each other
$self AlignItems
}
}
$options(-widget) raise $bboxid
}
method AlignItems { } {
set width $options(-width)
set height $options(-height)
switch $options(-orient) {
"horizontal" {
foreach item $items {
set tree $options(-tree)
lappend tree $item
set valign [eval contentmanager cget $tree -valign]
set h [eval contentmanager cget $tree -height]
set pady [eval contentmanager cget $tree -pady]
switch $valign {
"center" {
eval contentmanager move $tree 0 [expr {($height / 2) - ($h / 2) - $options(-ipady) - $pady}]
}
"middle" {
eval contentmanager move $tree 0 [expr {($height / 2) - ($h / 2) - $options(-ipady) - $pady}]
}
"bottom" {
eval contentmanager move $tree 0 [expr {$height - $h - $options(-ipady) - $pady}]
}
}
}
}
"vertical" {
foreach item $items {
set tree $options(-tree)
lappend tree $item
set align [eval contentmanager cget $tree -align]
set w [eval contentmanager cget $tree -width]
set padx [eval contentmanager cget $tree -padx]
switch $align {
"center" {
eval contentmanager move $tree [expr {($width / 2) - ($w / 2) - $options(-ipadx) - $padx}] 0
}
"middle" {
eval contentmanager move $tree [expr {($width / 2) - ($w / 2) - $options(-ipadx) - $padx}] 0
}
"right" {
eval contentmanager move $tree [expr {$width - $w - $options(-ipadx) - $padx}] 0
}
}
}
}
}
}
method PlaceAttachments { } {
foreach attachment $attachments {
set tree $options(-tree)
lappend tree $attachment
set attx [expr {$xPos + [eval contentmanager cget $tree -padx]}]
set atty [expr {$yPos + [eval contentmanager cget $tree -pady]}]
eval contentmanager coords $tree $attx $atty
}
}
}
snit::type element {
# Parent options
option -widget -configuremethod SetWidget
option -tag -configuremethod SetTag
option -tree
# Dimension options
option -align -default left
option -height -default 0 -configuremethod SetHeight -cgetmethod GetHeight
option -valign -default top
option -width -default 0 -configuremethod SetWidth -cgetmethod GetWidth
# Padding options
option -padx -default 0
option -pady -default 0
option -ipadx -default 0 -configuremethod Sort
option -ipady -default 0 -configuremethod Sort
# State options
option -omnipresent -default no
option -state -default normal -configuremethod SetState
# Children variables
variable bboxid
# Attachment variables
variable attachments
# Binding variables
variable havebinding
variable xPos
variable yPos
constructor { args } {
set xPos 0
set yPos 0
set bboxid {}
set attachments {}
set havebinding 0
$self configurelist $args
}
destructor {
catch {
$options(-widget) delete $bboxid
eval contentmanager unregister $options(-tree)
}
}
method type { } {
return "element"
}
method attach { id } {
lappend attachments $id
}
method SetWidget { opt val } {
set options(-widget) $val
set bboxid [$val create rect 0 0 0 0 -fill "" -outline "" -state normal]
}
method SetWidth { opt val } {
set options(-width) $val
if { [$self GotWidget] } {
$options(-widget) coords $bboxid $xPos $yPos [expr {$xPos + $val}] [expr {$yPos + $options(-height)}]
}
}
method GetWidth { opt } {
if { [string equal $options(-state) "hidden"] } {
return 0
} else {
return $options(-width)
}
}
method SetHeight { opt val } {
set options(-height) $val
if { [$self GotWidget] } {
$options(-widget) coords $bboxid $xPos $yPos [expr {$xPos + $options(-width)}] [expr {$yPos + $val}]
}
}
method SetState { opt val } {
set options(-state) $val
switch $val {
"partlyhidden" {
$self hide
}
"hidden" {
$self hide
}
"normal" {
$self show
}
}
}
method GetHeight { opt } {
if { [string equal $options(-state) "hidden"] } {
return 0
} else {
return $options(-height)
}
}
method GotWidget { } {
if { [string equal $options(-widget) ""] } {
return 0
} else {
return 1
}
}
method bind { pat cmd {mode {bbox}} } {
if { [string equal $cmd {}] } {
set havebinding 0
} else {
set havebinding 1
}
if { [$self GotWidget] } {
$options(-widget) bind $options(-tag) $pat $cmd
$options(-widget) bind $bboxid $pat $cmd
$options(-widget) itemconfigure $bboxid -state normal
}
}
method coords { {x {}} {y {}} } {
if { [string equal $x {}] } {
return "$xPos $yPos"
}
set xPos $x
set yPos $y
set tagx [expr {$x + $options(-ipadx)}]
set tagy [expr {$y + $options(-ipady)}]
$options(-widget) coords $options(-tag) $tagx $tagy
$options(-widget) coords $bboxid $xPos $yPos [expr {$xPos + $options(-width)}] [expr {$yPos + $options(-height)}]
foreach tag $attachments {
$options(-widget) coords $tag $xPos $yPos
}
}
method move { dx {dy {}} } {
#if { $dx == 0 } {
# if { $dy == 0 || [string equal $dy {}] } {
# return
# }
#}
if { [string equal $dy ""] } {
$options(-widget) move $options(-tag) $dx
$options(-widget) move $bboxid $dx
incr xPos $dx
} else {
$options(-widget) move $options(-tag) $dx $dy
$options(-widget) move $bboxid $dx $dy
incr xPos $dx
incr yPos $dy
}
$self PlaceAttachments
}
method show { args } {
if { [$self GotWidget] } {
set options(-state) "normal"
$options(-widget) itemconfigure $options(-tag) -state normal
if { $havebinding } {
$options(-widget) itemconfigure $bboxid -state normal
}
foreach attachment $attachments {
if { [eval contentmanager cget $tree -omnipresent] } {
continue
} else {
set tree $options(-tree)
lappend tree $attachment
eval contentmanager show $tree
}
}
}
}
method hide { args } {
if { [$self GotWidget] } {
if { !$options(-omnipresent) } {
set options(-state) "hidden"
$options(-widget) itemconfigure $options(-tag) -state hidden
$options(-widget) itemconfigure $bboxid -state hidden
}
foreach attachment $attachments {
if { [eval contentmanager cget $tree -omnipresent] } {
continue
} else {
set tree $options(-tree)
lappend tree $attachment
eval contentmanager hide $tree
}
}
}
}
method toggle { } {
switch $options(-state) {
"normal" {
$self hide
}
"hidden" {
$self show
}
}
}
method SetTag { opt val } {
set options(-tag) $val
$self sort
}
method Sort { {opt {}} {val {}} } {
set options($opt) $val
$self sort
}
method sort { {level {}} } {
set bbox [$options(-widget) bbox $options(-tag)]
$options(-widget) raise $bboxid
# Catch empty items
if { [string equal $bbox {}] } {
$self configure -height 0 -width 0
return
}
set bboxwidth [expr {[lindex $bbox 2] - [lindex $bbox 0] + (2 * $options(-ipadx))}]
set bboxheight [expr {[lindex $bbox 3] - [lindex $bbox 1] + (2 * $options(-ipady))}]
$self configure -height $bboxheight -width $bboxwidth
}
method PlaceAttachments { } {
foreach attachment $attachments {
set tree $options(-tree)
lappend tree $attachment
set attx [expr {$xPos + [eval contentmanager cget $tree -padx]}]
set atty [expr {$yPos + [eval contentmanager cget $tree -pady]}]
eval contentmanager coords $tree $attx $atty
}
}
}
amsn-0.98.9/utils/toolbar/ 0000755 0001750 0001750 00000000000 11757711633 015206 5 ustar billiob billiob amsn-0.98.9/utils/toolbar/toolbar.tcl 0000644 0001750 0001750 00000046474 10374654324 017370 0 ustar billiob billiob # o----------------------o
# | name: toolbar.tcl |
# | author: tom jenkins |
# | date: 07/06/06 |
# o----------------------o
# --------------------------------------------------
# toolbar - create and manipulate toolbar widgets
# --------------------------------------------------
snit::widget toolbar {
typevariable backgroundimg
typevariable buttonimg
typevariable buttondownimg
typevariable moreimg
typevariable background_border
typevariable button_border
typeconstructor {
# Load images
::skin::setPixmap toolbar_background toolbar_background.png
::skin::setPixmap toolbar_button toolbar_button.png
::skin::setPixmap toolbar_button_down toolbar_button_down.png
::skin::setPixmap toolbar_more toolbar_more.png
set backgroundimg [::skin::loadPixmap toolbar_background]
set buttonimg [::skin::loadPixmap toolbar_button]
set buttondownimg [::skin::loadPixmap toolbar_button_down]
set moreimg [::skin::loadPixmap toolbar_more]
set background_border {5 5 5 5}
set button_border {5 5 5 5}
}
# Options
option -bgimage -configuremethod SetBgImage
option -bgborder -default {5 5 5 5}
option -buttonimage -configuremethod SetButtonImage
option -buttonborder -default {5 5 5 5}
option -activeforeground -configuremethod SetActiveForeground -default black
option -activefg -configuremethod SetActiveForeground -default black
option -disabledforeground -configuremethod SetDisabledForeground -default grey
option -disabledfg -configuremethod SetDisabledForeground -default grey
option -fg -configuremethod SetForeground -default black
option -foreground -configuremethod SetForeground -default black
option -itempadx -default 2 -configuremethod SetPadding
option -itempady -default 2 -configuremethod SetPadding
option -itemipadx -default 4 -configuremethod SetPadding
option -itemipady -default 4 -configuremethod SetPadding
option -ipadx -default 2 -configuremethod SetPadding
option -ipady -default 2 -configuremethod SetPadding
option -orient -default horizontal -configuremethod SetOrient
option -viewmode -default 2 -configuremethod SetViewMode
# Let canvas handle options
delegate option * to canvas except { -bgimage -buttonimage -itempadx -itempady -orient }
# Use a frame for our base
hulltype frame
# Canvas and menu components
component canvas
component viewmenu
# Variables
variable shell ;# outer contentmanager group
variable items ;# list of items
variable itemid ;# unique id for each item
variable config ;# array to store names of config objects
variable background ;# scalable-bg for background image
variable backgroundid ;# id of background image on canvas
variable button ;# scalable-bg for toolbar button
variable buttondown ;# scalable-bg for toolbar button, pressed
variable buttonid ;# id of toolbar button on canvas
variable more ;# group to hold button to show toolbar items not visible (i.e. because toolbar is too small)
variable moreid ;# id of more button image on canvas
variable afterid ;# array used to process only the last in a batch of identical commands
constructor { args } {
$hull configure -relief flat -bd 0
# Create canvas (we will draw everything on this) and menu
install canvas using canvas $self.c -height 0 -highlightthickness 0 -relief flat -borderwidth 0
install viewmenu using menu $self.view -tearoff 0
# Add commands to view menu
$viewmenu add command -label "Icons only" -command "$self configure -viewmode 0"
$viewmenu add command -label "Text only" -command "$self configure -viewmode 1"
$viewmenu add command -label "Text and icons" -command "$self configure -viewmode 2"
# Create outer contentmanager group 'shell'
set shell [contentmanager add group $self.shell -widget $canvas -orient horizontal -ipadx $options(-ipadx) -ipady $options(-ipady)]
# Add group to hold the items, inside shell
contentmanager add group $shell items \
-widget $canvas -orient horizontal
# Create background scalable-bg
set background [scalable-bg $self.background \
-source $backgroundimg -resizemethod scale\
-border $options(-bgborder)]
# Put it on the canvas
set backgroundid [$canvas create image 0 0 -anchor nw -image [$background name]]
# Create toolbar button scalable-bg
set button [scalable-bg $self.button \
-source $buttonimg -resizemethod scale \
-border $options(-buttonborder)]
set buttondown [scalable-bg $self.buttondown \
-source $buttondownimg -resizemethod scale \
-border $options(-buttonborder)]
# Put it on the canvas (hidden for now, we aren't hovering any items)
set buttonid [$canvas create image 0 0 -anchor nw -image [$button name] -state hidden]
# Create 'more' button on canvas
set moreid [$canvas create image 0 0 -anchor nw -image $moreimg]
# Create the group and element for the 'more' button
contentmanager add group $shell more -widget $canvas -valign center
contentmanager add element $shell more button -widget $canvas -tag $moreid
# Hide it for now (no items yet!)
contentmanager hide $shell more button
# Initial values for variables
set items {}
set itemid 0
array set afterid {sort {}}
# Parse and apply arguments given at creation time
$self configurelist $args
# Pack our canvas in the frame (hull)
pack $canvas -expand true -fill both
# Bind the canvas
bind $canvas "$self Configure %w %h" ;# When resizing, we want to do things like resize background image
bind $canvas "tk_popup $viewmenu %X %Y" ;# Right mouse click on toolbar to pop up view menu
}
destructor {
catch { contentmanager delete $self.shell }
catch { after cancel $afterid(sort) } ;# Don't want it trying to do $w sort when $w doesn't exist anymore!
catch { destroy $background } ;# Get rid of background scalable-bg
catch { destroy $button } ;# Get rid of toolbar button scalable-bg
catch { destroy $buttondown } ;# Get rid of toolbar button scalable-bg
}
# -----------------------------------------------------------------------------------------------
# Configure - called when the canvas changes size. Updates size of background images and checks
# if we need to show the 'more' button
# w - width of canvas
# h - height of canvas
# -----------------------------------------------------------------------------------------------
method Configure { w h } {
# Resize the background image
$background configure -width $w -height $h
# Check if we need to show the 'more' button, and hide items that don't completely fit
set tw 0
set i 0
foreach item $items {
set iw [contentmanager cget $shell items $item -width]
set padx [contentmanager cget $shell items $item -padx]
incr tw [expr {$iw + (2 * $padx)}]
if { $tw > [expr {$w + $padx}] } {
break
}
contentmanager show $shell items $item -level 0
incr i 1
}
set outofview [lrange $items $i end]
foreach item $outofview {
contentmanager hide $shell items $item
}
# Position the 'more' button
if { [llength $outofview] > 0 } {
contentmanager show $shell more button
$self sort
contentmanager coords $shell more [expr {$w - [contentmanager cget $shell more -width] - $options(-itempadx)}] [lindex [contentmanager getcoords $shell more] 1]
} else {
contentmanager hide $shell more button
$self sort
}
}
# -------------------------------------------------
# Methods to change options
# -------------------------------------------------
method SetBgImage { option value } {
set options(-bgimage) $value
$background configure -source $value
}
method SetButtonImage { option value } {
set options(-buttonimage) $value
$button configure -source $value
}
method SetActiveForeground { option value } {
set options(-activeforeground) $value
set options(-activefg) $value
foreach item $items {
$canvas itemconfigure [$config($item) cget -textid] -fill $value
}
}
method SetDisabledForeground { option value } {
set options(-disabledforeground) $value
set options(-disabledfg) $value
}
method SetForeground { option value } {
set options(-foreground) $value
set options(-fg) $value
}
method SetOrient { option value } {
set options(-orient) $value
contentmanager configure $shell items -orient $value
}
method SetPadding { option value } {
set options($option) $value
foreach item $items {
contentmanager configure $shell items $item -padx $options(-padx) -pady $options(-pady)
contentmanager configure $shell items $item icon -padx $options(-itemipadx) -pady $options(-itemipady)
contentmanager configure $shell items $item text -padx $options(-itemipadx) -pady $options(-itemipady)
}
$self sort
}
method SetViewMode { option value } {
if { $value == $options(-viewmode) } {
return
}
set options(-viewmode) $value
$self ApplyViewMode
$self sort
}
# -----------------------------------------------------------------------------------
# ApplyViewMode - Hides/shows text/icons depending on the view mode
# -----------------------------------------------------------------------------------
method ApplyViewMode { {item "all"} } {
switch $options(-viewmode) {
0 {
# Icons only
if { $item == "all" } {
foreach item $items {
contentmanager show $shell items $item icon
contentmanager hide $shell items $item text
}
} else {
contentmanager show $shell items $item icon
contentmanager hide $shell items $item text
}
}
1 {
# Text only
if { $item == "all" } {
foreach item $items {
contentmanager show $shell items $item text
contentmanager hide $shell items $item icon
}
} else {
contentmanager show $shell items $item text
contentmanager hide $shell items $item icon
}
}
2 {
if { $item == "all" } {
# Icons and text
foreach item $items {
contentmanager show $shell items $item text
contentmanager show $shell items $item icon
}
} else {
contentmanager show $shell items $item text
contentmanager show $shell items $item icon
}
}
}
}
# --------------------------------------------------------------
# add - adds an item to the toolbar
# _type - the type of item to add. can be command or cascade
# args - arguments to pass to the item
# --------------------------------------------------------------
method add { _type args } {
lappend args -activefg $options(-activefg) -disabledfg $options(-disabledfg) -fg $options(-fg)
switch $_type {
command {
eval $self CreateCommand end $args
}
cascade {
}
}
lappend items $itemid
$self ApplyViewMode $itemid
incr itemid 1
# Sort
$self sort
}
method insert { index _type args } {
lappend args -activefg $options(-activefg) -disabledfg $options(-disabledfg) -fg $options(-fg)
switch $_type {
command {
eval $self CreateCommand $index $args
}
cascade {
}
}
set items [linsert $items $index $itemid]
$self ApplyViewMode $itemid
incr itemid 1
# Sort
$self sort
}
method CreateCommand { index args } {
contentmanager insert $index group $shell items $itemid -widget $canvas \
-ipadx $options(-itemipadx) \
-ipady $options(-itemipady) \
-valign bottom
set imgtag [$canvas create image 0 0 -anchor nw]
set txttag [$canvas create text 0 0 -anchor nw]
contentmanager add element $shell items $itemid icon -widget $canvas \
-align center \
-padx $options(-itemipadx) \
-pady $options(-itemipady) \
-tag $imgtag
contentmanager add element $shell items $itemid text -widget $canvas \
-align center \
-padx $options(-itemipadx) \
-pady $options(-itemipady) \
-tag $txttag
set config($itemid) [toolbarItemConfig $self.$itemid.config \
-canvas $canvas \
-tree [list $shell items $itemid] \
-imageid $imgtag \
-textid $txttag \
-activefg $options(-activefg) \
-disabledfg $options(-disabledfg) \
-fg $options(-fg)]
$config($itemid) configurelist $args
if { [$config($itemid) cget -text] == {} } {
contentmanager hide $shell items $itemid text
}
if { [$config($itemid) cget -image] == {} } {
contentmanager hide $shell items $itemid icon
}
# Bind for showing button on hover
contentmanager bind $shell items $itemid "+$self Enter $itemid"
contentmanager bind $shell items $itemid "+$self Enter $itemid 1"
contentmanager bind $shell items $itemid "+$self Leave $itemid"
contentmanager bind $shell items $itemid "+$self Press $itemid"
contentmanager bind $shell items $itemid "+$self Release $itemid %x %y"
}
# ------------------------------------------------------------------------------------------------------------------------
# delete - deletes an item or range of items from the toolbar
# index - the index of either the item to delete, or the start of the range of items to delete (if index2 is specified)
# index2 - the index of the end of the range of items to delete
# ------------------------------------------------------------------------------------------------------------------------
method delete { index {index2 {}} } {
if { $index == "all" } {
set index 0
set index2 end
}
if { $index2 == {} } {
set index2 $index
}
set delrange [lrange $items $index $index2]
foreach $item $delrange {
contentmanager delete $shell items $item
}
$self sort
}
# --------------------------------------------------------------
# itemconfigure - pass arguments to an existing item
# index - the index of the item to configure
# args - the set of arguments to configure it with
# --------------------------------------------------------------
method itemconfigure { index args } {
$config([lindex $items $index]) configurelist $args
$self sort
}
# --------------------------------------------------------------
# itemcget - get the value of an option from an item
# index - the index of the item to query
# option - the option of which to get the value
# --------------------------------------------------------------
method itemcget { index option } {
return [$config([lindex $items $index]) cget $option]
}
# --------------------------------------------------------------
# Select - select (show toolbar button behind) an item
# id - unique id for the item (NOT the index)
# --------------------------------------------------------------
method Enter { id {b 0} } {
if { $b == 1 } {
$canvas itemconfigure $buttonid -image [$buttondown name] -state normal
} else {
$canvas itemconfigure $buttonid -image [$button name] -state normal
}
$self Select $id
}
method Leave { id } {
$self Select none
if { [$config($id) cget -state] != "disabled" } {
$canvas itemconfigure [$config($id) cget -imageid] -image [$config($id) cget -image]
$canvas itemconfigure [$config($id) cget -textid] -fill [$config($id) cget -fg]
}
}
method Select { id } {
if { $id == "none" || [$config($id) cget -state] == "disabled" } {
$canvas itemconfigure $buttonid -state hidden
return
}
set xy [contentmanager getcoords $shell items $id]
set w [contentmanager cget $shell items $id -width]
set h [contentmanager cget $shell items $id -height]
$buttondown configure -width $w -height $h
$button configure -width $w -height $h
eval $canvas coords $buttonid $xy
}
# --------------------------------------------------------------
# Select - select (show toolbar button behind) an item
# id - unique id for the item (NOT the index)
# --------------------------------------------------------------
method Press { id } {
if { $id == "none" || [$config($id) cget -state] == "disabled" } {
$canvas itemconfigure $buttonid -state hidden
return
}
set xy [contentmanager getcoords $shell items $id]
set w [contentmanager cget $shell items $id -width]
set h [contentmanager cget $shell items $id -height]
eval $canvas coords $buttonid $xy
$buttondown configure -width $w -height $h
$canvas itemconfigure $buttonid -image [$buttondown name] -state normal
}
method Release { id x y } {
set coords [eval contentmanager getcoords $shell items $id]
set cx [$canvas canvasx $x]
set cy [$canvas canvasy $y]
set ix0 [lindex $coords 0]
set ix1 [expr {$ix0 + [eval contentmanager cget $shell items $id -width]}]
set iy0 [lindex $coords 1]
set iy1 [expr {$iy0 + [eval contentmanager cget $shell items $id -height]}]
if { $cx >= $ix0 && $cx <= $ix1 && $cy >= $iy0 && $cy <= $iy1 && [$config($id) cget -state] != "disabled" } {
$canvas itemconfigure $buttonid -image [$button name]
eval [$config($id) cget -command]
}
}
# ------------------------------------------------------------------------------------------------
# sort - wraps SortItems, stops lots of SortItems being executed at once, only runs the last one
# ------------------------------------------------------------------------------------------------
method sort { } {
after cancel $afterid(sort)
set afterid(sort) [after 1 "$self SortItems"]
}
# --------------------------------------------------------------
# SortItems - sort the items and resize the toolbar to fit
# --------------------------------------------------------------
method SortItems { } {
contentmanager sort $shell
$canvas configure -height [contentmanager cget $shell -height]
}
}
# ----------------------------------------------------------------------
# toolbarItemConfig - stores and processes options for toolbar items
# ----------------------------------------------------------------------
snit::type toolbarItemConfig {
option -activefg
option -activeimage -configuremethod SetActiveImage
option -canvas
option -command -configuremethod SetCommand
option -disabledfg
option -disabledimage
option -fg
option -image -configuremethod SetImage
option -imageid
option -state -configuremethod SetState
option -text -configuremethod SetText
option -textid
option -tree
method SetActiveImage { option value } {
set options(-activeimage) $value
eval contentmanager bind $options(-tree) [list "+$self Enter"]
}
method SetCommand { option value } {
set options(-command) $value
}
method SetImage { option value } {
set options(-image) $value
set tag [eval contentmanager cget $options(-tree) icon -tag]
$options(-canvas) itemconfigure $tag -image $value
if { $value == {} } {
eval contentmanager hide $options(-tree) icon
} else {
eval contentmanager show $options(-tree) icon
}
eval contentmanager bind $options(-tree) [list "+$self Leave"]
}
method SetState { option value } {
set options(-state) $value
switch $value {
active {
$options(-canvas) itemconfigure $options(-imageid) -image $options(-activeimage)
$options(-canvas) itemconfigure $options(-textid) -fill $options(-activefg)
}
disabled {
$options(-canvas) itemconfigure $options(-imageid) -image $options(-disabledimage)
$options(-canvas) itemconfigure $options(-textid) -fill $options(-disabledfg)
}
normal {
$options(-canvas) itemconfigure $options(-imageid) -image $options(-image)
$options(-canvas) itemconfigure $options(-textid) -fill $options(-fg)
}
}
}
method SetText { option value } {
set options(-text) $value
set tag [eval contentmanager cget $options(-tree) text -tag]
$options(-canvas) itemconfigure $tag -text $value
if { $value == {} } {
eval contentmanager hide $options(-tree) text
} else {
eval contentmanager show $options(-tree) text
}
}
method Leave { } {
if { $options(-state) != "disabled" } {
$self configure -state normal
}
}
method Enter { } {
if { $options(-state) != "disabled" } {
$self configure -state active
}
}
} amsn-0.98.9/utils/sasl/ 0000755 0001750 0001750 00000000000 11757711633 014506 5 ustar billiob billiob amsn-0.98.9/utils/sasl/ntlm.tcl 0000644 0001750 0001750 00000032452 11303021241 016142 0 ustar billiob billiob # ntlm.tcl - Copyright (C) 2005 Pat Thoyts
#
# This is an implementation of Microsoft's NTLM authentication mechanism.
#
# References:
# http://www.innovation.ch/java/ntlm.html
# http://davenport.sourceforge.net/ntlm.html
#
# -------------------------------------------------------------------------
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
# -------------------------------------------------------------------------
package require Tcl 8.2; # tcl minimum version
package require SASL 1.0; # tcllib 1.7
package require des 1.0; # tcllib 1.8
package require md4; # tcllib 1.4
namespace eval ::SASL {
namespace eval NTLM {
variable version 1.1.1
variable rcsid {$Id: ntlm.tcl,v 1.8 2007/08/26 00:36:45 patthoyts Exp $}
array set NTLMFlags {
unicode 0x00000001
oem 0x00000002
req_target 0x00000004
unknown 0x00000008
sign 0x00000010
seal 0x00000020
datagram 0x00000040
lmkey 0x00000080
netware 0x00000100
ntlm 0x00000200
unknown 0x00000400
unknown 0x00000800
domain 0x00001000
server 0x00002000
share 0x00004000
NTLM2 0x00008000
targetinfo 0x00800000
128bit 0x20000000
keyexch 0x40000000
56bit 0x80000000
}
}
}
# -------------------------------------------------------------------------
proc ::SASL::NTLM::NTLM {context challenge args} {
upvar #0 $context ctx
incr ctx(step)
switch -exact -- $ctx(step) {
1 {
set ctx(realm) [eval [linsert $ctx(callback) end $context realm]]
set ctx(hostname) [eval [linsert $ctx(callback) end $context hostname]]
set ctx(response) [CreateGreeting $ctx(realm) $ctx(hostname)]
set result 1
}
2 {
array set params [Decode $challenge]
set user [eval [linsert $ctx(callback) end $context username]]
set pass [eval [linsert $ctx(callback) end $context password]]
if {[info exists params(domain)]} {
set ctx(realm) $params(domain)
}
set ctx(response) [CreateResponse \
$ctx(realm) $ctx(hostname) \
$user $pass $params(nonce) $params(flags)]
Decode $ctx(response)
set result 0
}
default {
return -code error "invalid state \"$ctx(step)"
}
}
return $result
}
# -------------------------------------------------------------------------
# NTLM client implementation
# -------------------------------------------------------------------------
# The NMLM greeting. This is sent by the client to the server to initiate
# the challenge response handshake.
# This message contains the hostname (not domain qualified) and the
# NT domain name for authentication.
#
proc ::SASL::NTLM::CreateGreeting {domainname hostname {flags {}}} {
set domain [encoding convertto ascii $domainname]
set host [encoding convertto ascii $hostname]
set d_len [string length $domain]
set h_len [string length $host]
set d_off [expr {32 + $h_len}]
if {[llength $flags] == 0} {
set flags {unicode oem ntlm server domain req_target}
}
set msg [binary format a8iississi \
"NTLMSSP\x00" 1 [Flags $flags] \
$d_len $d_len $d_off \
$h_len $h_len 32]
append msg $host $domain
return $msg
}
# Create a NTLM server challenge. This is sent by a server in response to
# a client type 1 message. The content of the type 2 message is variable
# and depends upon the flags set by the client and server choices.
#
proc ::SASL::NTLM::CreateChallenge {domainname} {
SASL::md5_init
set target [encoding convertto ascii $domainname]
set t_len [string length $target]
set nonce [string range [binary format h* [SASL::CreateNonce]] 0 7]
set pad [string repeat \0 8]
set context [string repeat \0 8]
set msg [binary format a8issii \
"NTLMSSP\x00" 2 \
$t_len $t_len 48 \
[Flags {ntlm unicode}]]
append msg $nonce $pad $context $pad $target
return $msg
}
# Compose the final client response. This contains the encoded username
# and password, along with the server nonce value.
#
proc ::SASL::NTLM::CreateResponse {domainname hostname username passwd nonce flags} {
set lm_resp [LMhash $passwd $nonce]
set nt_resp [NThash $passwd $nonce]
set domain [string toupper $domainname]
set host [string toupper $hostname]
set user $username
set unicode [expr {$flags & 0x00000001}]
if {$unicode} {
set domain [to_unicode_le $domain]
set host [to_unicode_le $host]
set user [to_unicode_le $user]
}
set l_len [string length $lm_resp]; # LM response length
set n_len [string length $nt_resp]; # NT response length
set d_len [string length $domain]; # Domain name length
set h_len [string length $host]; # Host name length
set u_len [string length $user]; # User name length
set s_len 0 ; # Session key length
# The offsets to strings appended to the structure
set d_off [expr {0x40}]; # Fixed offset to Domain buffer
set u_off [expr {$d_off + $d_len}]; # Offset to user buffer
set h_off [expr {$u_off + $u_len}]; # Offset to host buffer
set l_off [expr {$h_off + $h_len}]; # Offset to LM hash
set n_off [expr {$l_off + $l_len}]; # Offset to NT hash
set s_off [expr {$n_off + $n_len}]; # Offset to Session key
set msg [binary format a8is4s4s4s4s4s4i \
"NTLMSSP\x00" 3 \
[list $l_len $l_len $l_off 0] \
[list $n_len $n_len $n_off 0] \
[list $d_len $d_len $d_off 0] \
[list $u_len $u_len $u_off 0] \
[list $h_len $h_len $h_off 0] \
[list $s_len $s_len $s_off 0] \
$flags]
append msg $domain $user $host $lm_resp $nt_resp
return $msg
}
proc ::SASL::NTLM::Debug {msg} {
array set d [Decode $msg]
if {[info exists d(flags)]} {
set d(flags) [list [format 0x%08x $d(flags)] [decodeflags $d(flags)]]
}
if {[info exists d(nonce)]} { set d(nonce) [base64::encode $d(nonce)] }
if {[info exists d(lmhash)]} { set d(lmhash) [base64::encode $d(lmhash)] }
if {[info exists d(nthash)]} { set d(nthash) [base64::encode $d(nthash)] }
return [array get d]
}
proc ::SASL::NTLM::Decode {msg} {
#puts [Debug $msg]
binary scan $msg a7ci protocol zero type
switch -exact -- $type {
1 {
binary scan $msg @12ississi flags dlen dlen2 doff hlen hlen2 hoff
binary scan $msg @${hoff}a${hlen} host
binary scan $msg @${doff}a${dlen} domain
return [list type $type flags [format 0x%08x $flags] \
domain $domain host $host]
}
2 {
binary scan $msg @12ssiia8a8 dlen dlen2 doff flags nonce pad
set domain {}; binary scan $msg @${doff}a${dlen} domain
set unicode [expr {$flags & 0x00000001}]
if {$unicode} {
set domain [from_unicode_le $domain]
}
binary scan $nonce H* nonce_h
binary scan $pad H* pad_h
return [list type $type flags [format 0x%08x $flags] \
domain $domain nonce $nonce]
}
3 {
binary scan $msg @12ssissississississii \
lmlen lmlen2 lmoff \
ntlen ntlen2 ntoff \
dlen dlen2 doff \
ulen ulen2 uoff \
hlen hlen2 hoff \
slen slen2 soff \
flags
set domain {}; binary scan $msg @${doff}a${dlen} domain
set user {}; binary scan $msg @${uoff}a${ulen} user
set host {}; binary scan $msg @${hoff}a${hlen} host
set unicode [expr {$flags & 0x00000001}]
if {$unicode} {
set domain [from_unicode_le $domain]
set user [from_unicode_le $user]
set host [from_unicode_le $host]
}
binary scan $msg @${ntoff}a${ntlen} ntdata
binary scan $msg @${lmoff}a${lmlen} lmdata
binary scan $ntdata H* ntdata_h
binary scan $lmdata H* lmdata_h
return [list type $type flags [format 0x%08x $flags]\
domain $domain host $host user $user \
lmhash $lmdata nthash $ntdata]
}
default {
return -code error "invalid NTLM data: type not recognised"
}
}
}
proc ::SASL::NTLM::decodeflags {value} {
variable NTLMFlags
set result {}
foreach {flag mask} [array get NTLMFlags] {
if {$value & ($mask & 0xffffffff)} {
lappend result $flag
}
}
return $result
}
proc ::SASL::NTLM::Flags {flags} {
variable NTLMFlags
set result 0
foreach flag $flags {
if {![info exists NTLMFlags($flag)]} {
return -code error "invalid ntlm flag \"$flag\""
}
set result [expr {$result | $NTLMFlags($flag)}]
}
return $result
}
# Convert a string to unicode in little endian byte order.
proc ::SASL::NTLM::to_unicode_le {str} {
set result [encoding convertto unicode $str]
if {[string equal $::tcl_platform(byteOrder) "bigEndian"]} {
set r {} ; set n 0
while {[binary scan $result @${n}cc a b] == 2} {
append r [binary format cc $b $a]
incr n 2
}
set result $r
}
return $result
}
# Convert a little-endian unicode string to utf-8.
proc ::SASL::NTLM::from_unicode_le {str} {
if {[string equal $::tcl_platform(byteOrder) "bigEndian"]} {
set r {} ; set n 0
while {[binary scan $str @${n}cc a b] == 2} {
append r [binary format cc $b $a]
incr n 2
}
set str $r
}
return [encoding convertfrom unicode $str]
}
proc ::SASL::NTLM::LMhash {password nonce} {
set magic "\x4b\x47\x53\x21\x40\x23\x24\x25"
set hash ""
set password [string range [string toupper $password][string repeat \0 14] 0 13]
foreach key [CreateDesKeys $password] {
append hash [DES::des -dir encrypt -weak -mode ecb -key $key $magic]
}
append hash [string repeat \0 5]
set res ""
foreach key [CreateDesKeys $hash] {
append res [DES::des -dir encrypt -weak -mode ecb -key $key $nonce]
}
return $res
}
proc ::SASL::NTLM::NThash {password nonce} {
set pass [to_unicode_le $password]
set hash [md4::md4 $pass]
append hash [string repeat \x00 5]
set res ""
foreach key [CreateDesKeys $hash] {
append res [DES::des -dir encrypt -weak -mode ecb -key $key $nonce]
}
return $res
}
# Convert a password into a 56 bit DES key according to the NTLM specs.
# We do NOT fix the parity of each byte. If we did, then bit 0 of each
# byte should be adjusted to give the byte odd parity.
#
proc ::SASL::NTLM::CreateDesKeys {key} {
# pad to 7 byte boundary with nuls.
set mod [expr {[string length $key] % 7}]
if {$mod != 0} {
append key [string repeat "\0" [expr {7 - $mod}]]
}
set len [string length $key]
set r ""
for {set n 0} {$n < $len} {incr n 7} {
binary scan $key @${n}c7 bytes
set b {}
lappend b [expr { [lindex $bytes 0] & 0xFF}]
lappend b [expr {(([lindex $bytes 0] & 0x01) << 7) | (([lindex $bytes 1] >> 1) & 0x7F)}]
lappend b [expr {(([lindex $bytes 1] & 0x03) << 6) | (([lindex $bytes 2] >> 2) & 0x3F)}]
lappend b [expr {(([lindex $bytes 2] & 0x07) << 5) | (([lindex $bytes 3] >> 3) & 0x1F)}]
lappend b [expr {(([lindex $bytes 3] & 0x0F) << 4) | (([lindex $bytes 4] >> 4) & 0x0F)}]
lappend b [expr {(([lindex $bytes 4] & 0x1F) << 3) | (([lindex $bytes 5] >> 5) & 0x07)}]
lappend b [expr {(([lindex $bytes 5] & 0x3F) << 2) | (([lindex $bytes 6] >> 6) & 0x03)}]
lappend b [expr {(([lindex $bytes 6] & 0x7F) << 1)}]
lappend r [binary format c* $b]
}
return $r;
}
# This is slower than the above in Tcl 8.4.9
proc ::SASL::NTLM::CreateDesKeys2 {key} {
# pad to 7 byte boundary with nuls.
append key [string repeat "\0" [expr {7 - ([string length $key] % 7)}]]
binary scan $key B* bin
set len [string length $bin]
set r ""
for {set n 0} {$n < $len} {incr n} {
append r [string range $bin $n [incr n 6]] 0
}
# needs spliting into 8 byte keys.
return [binary format B* $r]
}
# -------------------------------------------------------------------------
# Register this SASL mechanism with the Tcllib SASL package.
#
if {[llength [package provide SASL]] != 0} {
::SASL::register NTLM 50 ::SASL::NTLM::NTLM
}
package provide SASL::NTLM $::SASL::NTLM::version
# -------------------------------------------------------------------------
#
# Local variables:
# indent-tabs-mode: nil
# End:
amsn-0.98.9/utils/sasl/pkgIndex.tcl 0000644 0001750 0001750 00000001010 11303021241 016723 0 ustar billiob billiob # pkgIndex.tcl -*- tcl -*-
# Copyright (C) 2005 Pat Thoyts
# $Id: pkgIndex.tcl,v 1.11 2008/01/29 00:51:39 patthoyts Exp $
if {![package vsatisfies [package provide Tcl] 8.2]} {
# PRAGMA: returnok
return
}
package ifneeded SASL 1.3.2 [list source [file join $dir sasl.tcl]]
package ifneeded SASL::NTLM 1.1.1 [list source [file join $dir ntlm.tcl]]
package ifneeded SASL::XGoogleToken 1.0.1 [list source [file join $dir gtoken.tcl]]
amsn-0.98.9/utils/sasl/gtoken.tcl 0000644 0001750 0001750 00000006142 11303021241 016454 0 ustar billiob billiob # gtoken.tcl - Copyright (C) 2006 Pat Thoyts
#
# This is an implementation of Google's X-GOOGLE-TOKEN authentication
# mechanism. This actually passes the login details to the Google
# accounts server which gives us a short lived token that may be passed
# over an insecure link.
#
# -------------------------------------------------------------------------
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
# -------------------------------------------------------------------------
package require Tcl 8.2
package require SASL
package require http
package require tls
namespace eval ::SASL {
namespace eval XGoogleToken {
variable version 1.0.1
variable rcsid {$Id: gtoken.tcl,v 1.4 2007/08/26 00:36:45 patthoyts Exp $}
variable URLa https://www.google.com/accounts/ClientAuth
variable URLb https://www.google.com/accounts/IssueAuthToken
# Should use autoproxy and register autoproxy::tls_socket
# Leave to application author?
if {![info exists ::http::urlTypes(https)]} {
http::register https 443 tls::socket
}
}
}
proc ::SASL::XGoogleToken::client {context challenge args} {
upvar #0 $context ctx
variable URLa
variable URLb
set reply ""
set err ""
if {$ctx(step) != 0} {
return -code error "unexpected state: X-GOOGLE-TOKEN has only 1 step"
}
set username [eval $ctx(callback) [list $context username]]
set password [eval $ctx(callback) [list $context password]]
set query [http::formatQuery Email $username Passwd $password \
PersistentCookie false source googletalk]
set tok [http::geturl $URLa -query $query -timeout 30000]
if {[http::status $tok] eq "ok"} {
foreach line [split [http::data $tok] \n] {
array set g [split $line =]
}
if {![info exists g(Error)]} {
set query [http::formatQuery SID $g(SID) LSID $g(LSID) \
service mail Session true]
set tok2 [http::geturl $URLb -query $query -timeout 30000]
if {[http::status $tok2] eq "ok"} {
set reply "\0$username\0[http::data $tok2]"
} else {
set err [http::error $tok2]
}
http::cleanup $tok2
} else {
set err "Invalid username or password"
}
} else {
set err [http::error $tok]
}
http::cleanup $tok
if {[string length $err] > 0} {
return -code error $err
} else {
set ctx(response) $reply
incr ctx(step)
}
return 0
}
# -------------------------------------------------------------------------
# Register this SASL mechanism with the Tcllib SASL package.
#
if {[llength [package provide SASL]] != 0} {
::SASL::register X-GOOGLE-TOKEN 40 ::SASL::XGoogleToken::client
}
package provide SASL::XGoogleToken $::SASL::XGoogleToken::version
# -------------------------------------------------------------------------
#
# Local variables:
# indent-tabs-mode: nil
# End:
amsn-0.98.9/utils/sasl/sasl.tcl 0000644 0001750 0001750 00000052467 11303021241 016142 0 ustar billiob billiob # sasl.tcl - Copyright (C) 2005 Pat Thoyts
#
# This is an implementation of a general purpose SASL library for use in
# Tcl scripts.
#
# References:
# Myers, J., "Simple Authentication and Security Layer (SASL)",
# RFC 2222, October 1997.
# Rose, M.T., "TclSASL", "http://beepcore-tcl.sourceforge.net/tclsasl.html"
#
# -------------------------------------------------------------------------
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
# -------------------------------------------------------------------------
package require Tcl 8.2
namespace eval ::SASL {
variable version 1.3.2
variable rcsid {$Id: sasl.tcl,v 1.12 2008/01/29 00:51:39 patthoyts Exp $}
variable uid
if {![info exists uid]} { set uid 0 }
variable mechanisms
if {![info exists mechanisms]} {
set mechanisms [list]
}
}
# SASL::mechanisms --
#
# Return a list of available SASL mechanisms. By default only the
# client implementations are given but if type is set to server then
# the list of available server mechanisms is returned.
# No mechanism with a preference value less than 'minimum' will be
# returned.
# The list is sorted by the security preference with the most secure
# mechanisms given first.
#
proc ::SASL::mechanisms {{type client} {minimum 0}} {
variable mechanisms
set r [list]
foreach mech $mechanisms {
if {[lindex $mech 0] < $minimum} { continue }
switch -exact -- $type {
client {
if {[string length [lindex $mech 2]] > 0} {
lappend r [lindex $mech 1]
}
}
server {
if {[string length [lindex $mech 3]] > 0} {
lappend r [lindex $mech 1]
}
}
default {
return -code error "invalid type \"$type\":\
must be either client or server"
}
}
}
return $r
}
# SASL::register --
#
# Register a new SASL mechanism with a security preference. Higher
# preference values are chosen before lower valued mechanisms.
# If no server implementation is available then an empty string
# should be provided for the serverproc parameter.
#
proc ::SASL::register {mechanism preference clientproc {serverproc {}}} {
variable mechanisms
set ndx [lsearch -regexp $mechanisms $mechanism]
set mech [list $preference $mechanism $clientproc $serverproc]
if {$ndx == -1} {
lappend mechanisms $mech
} else {
set mechanisms [lreplace $mechanisms $ndx $ndx $mech]
}
set mechanisms [lsort -index 0 -decreasing -integer $mechanisms]
return
}
# SASL::uid --
#
# Return a unique integer.
#
proc ::SASL::uid {} {
variable uid
return [incr uid]
}
# SASL::response --
#
# Get the reponse string from the SASL state.
#
proc ::SASL::response {context} {
upvar #0 $context ctx
return $ctx(response)
}
# SASL::reset --
#
# Reset the SASL state. This permits the same instance to be reused
# for a new round of authentication.
#
proc ::SASL::reset {context {step 0}} {
upvar #0 $context ctx
array set ctx [list step $step response "" valid false count 0]
return $context
}
# SASL::cleanup --
#
# Free any resources used with the SASL state.
#
proc ::SASL::cleanup {context} {
if {[info exists $context]} {
unset $context
}
return
}
# SASL::new --
#
# Create a new SASL instance.
#
proc ::SASL::new {args} {
set context [namespace current]::[uid]
upvar #0 $context ctx
array set ctx [list mech {} callback {} proc {} service smtp server {} \
step 0 response "" valid false type client count 0]
eval [linsert $args 0 [namespace origin configure] $context]
return $context
}
# SASL::configure --
#
# Configure the SASL state.
#
proc ::SASL::configure {context args} {
variable mechanisms
upvar #0 $context ctx
while {[string match -* [set option [lindex $args 0]]]} {
switch -exact -- $option {
-service {
set ctx(service) [Pop args 1]
}
-server - -serverFQDN {
set ctx(server) [Pop args 1]
}
-mech - -mechanism {
set mech [string toupper [Pop args 1]]
set ctx(proc) {}
foreach m $mechanisms {
if {[string equal [lindex $m 1] $mech]} {
set ctx(mech) $mech
if {[string equal $ctx(type) "server"]} {
set ctx(proc) [lindex $m 3]
} else {
set ctx(proc) [lindex $m 2]
}
break
}
}
if {[string equal $ctx(proc) {}]} {
return -code error "mechanism \"$mech\" not available:\
must be one of those given by \[sasl::mechanisms\]"
}
}
-callback - -callbacks {
set ctx(callback) [Pop args 1]
}
-type {
set type [Pop args 1]
if {[lsearch -exact {server client} $type] != -1} {
set ctx(type) $type
if {![string equal $ctx(mech) ""]} {
configure $context -mechanism $ctx(mech)
}
} else {
return -code error "bad value \"$type\":\
must be either client or server"
}
}
default {
return -code error "bad option \"$option\":\
must be one of -mechanism, -service, -server -type\
or -callbacks"
}
}
Pop args
}
}
proc ::SASL::step {context challenge args} {
upvar #0 $context ctx
incr ctx(count)
return [eval [linsert $args 0 $ctx(proc) $context $challenge]]
}
proc ::SASL::Pop {varname {nth 0}} {
upvar $varname args
set r [lindex $args $nth]
set args [lreplace $args $nth $nth]
return $r
}
proc ::SASL::md5_init {} {
variable md5_inited
if {[info exists md5_inited]} {return} else {set md5_inited 1}
# Deal with either version of md5. We'd like version 2 but someone
# may have already loaded version 1.
set md5major [lindex [split [package require md5] .] 0]
if {$md5major < 2} {
# md5 v1, no options, and returns a hex string ready for us.
proc ::SASL::md5_hex {data} { return [::md5::md5 $data] }
proc ::SASL::md5_bin {data} { return [binary format H* [::md5::md5 $data]] }
proc ::SASL::hmac_hex {pass data} { return [::md5::hmac $pass $data] }
proc ::SASL::hmac_bin {pass data} { return [binary format H* [::md5::hmac $pass $data]] }
} else {
# md5 v2 requires -hex to return hash as hex-encoded non-binary string.
proc ::SASL::md5_hex {data} { return [string tolower [::md5::md5 -hex $data]] }
proc ::SASL::md5_bin {data} { return [::md5::md5 $data] }
proc ::SASL::hmac_hex {pass data} { return [::md5::hmac -hex -key $pass $data] }
proc ::SASL::hmac_bin {pass data} { return [::md5::hmac -key $pass $data] }
}
}
# -------------------------------------------------------------------------
# CRAM-MD5 SASL MECHANISM
#
# Implementation of the Challenge-Response Authentication Mechanism
# (RFC2195).
#
# Comments:
# This mechanism passes a server generated string containing
# a timestamp and has the client generate an MD5 HMAC using the
# shared secret as the key and the server string as the data.
# The downside of this protocol is that the server must have access
# to the plaintext password.
#
proc ::SASL::CRAM-MD5:client {context challenge args} {
upvar #0 $context ctx
md5_init
if {$ctx(step) != 0} {
return -code error "unexpected state: CRAM-MD5 has only 1 step"
}
if {[string length $challenge] == 0} {
set ctx(response) ""
return 1
}
set password [eval $ctx(callback) [list $context password]]
set username [eval $ctx(callback) [list $context username]]
set reply [hmac_hex $password $challenge]
set reply "$username [string tolower $reply]"
set ctx(response) $reply
incr ctx(step)
return 0
}
proc ::SASL::CRAM-MD5:server {context clientrsp args} {
upvar #0 $context ctx
md5_init
incr ctx(step)
switch -exact -- $ctx(step) {
1 {
set ctx(realm) [eval $ctx(callback) [list $context realm]]
set ctx(response) "<[pid].[clock seconds]@$ctx(realm)>"
return 1
}
2 {
foreach {user hash} $clientrsp break
set hash [string tolower $hash]
set pass [eval $ctx(callback) [list $context password $user $ctx(realm)]]
set check [hmac_bin $pass $ctx(response)]
binary scan $check H* cx
if {[string equal $cx $hash]} {
return 0
} else {
return -code error "authentication failed"
}
}
default {
return -code error "invalid state"
}
}
}
::SASL::register CRAM-MD5 30 ::SASL::CRAM-MD5:client ::SASL::CRAM-MD5:server
# -------------------------------------------------------------------------
# PLAIN SASL MECHANISM
#
# Implementation of the single step login SASL mechanism (RFC2595).
#
# Comments:
# A single step mechanism in which the authorization ID, the
# authentication ID and password are all transmitted in plain
# text. This should not be used unless the channel is secured by
# some other means (such as SSL/TLS).
#
proc ::SASL::PLAIN:client {context challenge args} {
upvar #0 $context ctx
incr ctx(step)
set authzid [eval $ctx(callback) [list $context login]]
set username [eval $ctx(callback) [list $context username]]
set password [eval $ctx(callback) [list $context password]]
set ctx(response) "$authzid\x00$username\x00$password"
return 0
}
proc ::SASL::PLAIN:server {context clientrsp args} {
upvar \#0 $context ctx
if {[string length $clientrsp] < 1} {
set ctx(response) ""
return 1
} else {
foreach {authzid authid pass} [split $clientrsp \0] break
set realm [eval $ctx(callback) [list $context realm]]
set check [eval $ctx(callback) [list $context password $authid $realm]]
if {[string equal $pass $check]} {
return 0
} else {
return -code error "authentication failed"
}
}
}
::SASL::register PLAIN 10 ::SASL::PLAIN:client ::SASL::PLAIN:server
# -------------------------------------------------------------------------
# LOGIN SASL MECHANISM
#
# Implementation of the two step login SASL mechanism.
#
# Comments:
# This is an unofficial but widely deployed SASL mechanism somewhat
# akin to the PLAIN mechanism. Both the authentication ID and password
# are transmitted in plain text in response to server prompts.
#
# NOT RECOMMENDED for use in new protocol implementations.
#
proc ::SASL::LOGIN:client {context challenge args} {
upvar #0 $context ctx
if {$ctx(step) == 0 && [string length $challenge] == 0} {
set ctx(response) ""
return 1
}
incr ctx(step)
switch -exact -- $ctx(step) {
1 {
set ctx(response) [eval $ctx(callback) [list $context username]]
set r 1
}
2 {
set ctx(response) [eval $ctx(callback) [list $context password]]
set r 0
}
default {
return -code error "unexpected state \"$ctx(step)\":\
LOGIN has only 2 steps"
}
}
return $r
}
proc ::SASL::LOGIN:server {context clientrsp args} {
upvar #0 $context ctx
incr ctx(step)
switch -exact -- $ctx(step) {
1 {
set ctx(response) "Username:"
return 1
}
2 {
set ctx(username) $clientrsp
set ctx(response) "Password:"
return 1
}
3 {
set user $ctx(username)
set realm [eval $ctx(callback) [list $context realm]]
set pass [eval $ctx(callback) [list $context password $user $realm]]
if {[string equal $clientrsp $pass]} {
return 0
} else {
return -code error "authentication failed"
}
}
default {
return -code error "invalid state"
}
}
}
::SASL::register LOGIN 20 ::SASL::LOGIN:client ::SASL::LOGIN:server
# -------------------------------------------------------------------------
# ANONYMOUS SASL MECHANISM
#
# Implementation of the ANONYMOUS SASL mechanism (RFC2245).
#
# Comments:
#
#
proc ::SASL::ANONYMOUS:client {context challenge args} {
upvar #0 $context ctx
set user [eval $ctx(callback) [list $context username]]
set realm [eval $ctx(callback) [list $context realm]]
set ctx(response) $user@$realm
return 0
}
proc ::SASL::ANONYMOUS:server {context clientrsp args} {
upvar #0 $context ctx
set ctx(response) ""
if {[string length $clientrsp] < 1} {
if {$ctx(count) > 2} {
return -code error "authentication failed"
}
return 1
} else {
set ctx(trace) $clientrsp
return 0
}
}
::SASL::register ANONYMOUS 5 ::SASL::ANONYMOUS:client ::SASL::ANONYMOUS:server
# -------------------------------------------------------------------------
# DIGEST-MD5 SASL MECHANISM
#
# Implementation of the DIGEST-MD5 SASL mechanism (RFC2831).
#
# Comments:
#
proc ::SASL::DIGEST-MD5:client {context challenge args} {
upvar #0 $context ctx
md5_init
if {$ctx(step) == 0 && [string length $challenge] == 0} {
if {[info exists ctx(challenge)]} {
set challenge $ctx(challenge)
} else {
set ctx(response) ""
return 1
}
}
incr ctx(step)
set result 0
switch -exact -- $ctx(step) {
1 {
set ctx(challenge) $challenge
array set params [DigestParameters $challenge]
if {![info exists ctx(noncecount)]} {
set ctx(noncecount) 0
}
set nonce $params(nonce)
set cnonce [CreateNonce]
set noncecount [format %08u [incr ctx(noncecount)]]
set qop auth
# support the 'charset' parameter.
set username [eval $ctx(callback) [list $context username]]
set password [eval $ctx(callback) [list $context password]]
set encoding iso8859-1
if {[info exists params(charset)]} {
set encoding $params(charset)
}
set username [encoding convertto $encoding $username]
set password [encoding convertto $encoding $password]
if {[info exists params(realm)]} {
set realm $params(realm)
} else {
set realm [eval $ctx(callback) [list $context realm]]
}
set uri "$ctx(service)/$realm"
set R [DigestResponse $username $realm $password $uri \
$qop $nonce $noncecount $cnonce]
set ctx(response) "username=\"$username\",realm=\"$realm\",nonce=\"$nonce\",nc=\"$noncecount\",cnonce=\"$cnonce\",digest-uri=\"$uri\",response=\"$R\",qop=$qop"
if {[info exists params(charset)]} {
append ctx(response) ",charset=$params(charset)"
}
set result 1
}
2 {
set ctx(response) ""
set result 0
}
default {
return -code error "invalid state"
}
}
return $result
}
proc ::SASL::DIGEST-MD5:server {context challenge args} {
upvar #0 $context ctx
md5_init
incr ctx(step)
set result 0
switch -exact -- $ctx(step) {
1 {
set realm [eval $ctx(callback) [list $context realm]]
set ctx(nonce) [CreateNonce]
set ctx(nc) 0
set ctx(response) "realm=\"$realm\",nonce=\"$ctx(nonce)\",qop=\"auth\",charset=utf-8,algorithm=md5-sess"
set result 1
}
2 {
array set params [DigestParameters $challenge]
set realm [eval $ctx(callback) [list $context realm]]
set password [eval $ctx(callback)\
[list $context password $params(username) $realm]]
set uri "$ctx(service)/$realm"
set nc [format %08u [expr {$ctx(nc) + 1}]]
set R [DigestResponse $params(username) $realm $password \
$uri auth $ctx(nonce) $nc $params(cnonce)]
if {[string equal $R $params(response)]} {
set R2 [DigestResponse $params(username) $realm $password \
$uri auth $ctx(nonce) $nc $params(cnonce)]
set ctx(response) "rspauth=$R2"
incr ctx(nc)
set result 1
} else {
return -code error "authentication failed"
}
}
3 {
set ctx(response) ""
set result 0
}
default {
return -code error "invalid state"
}
}
return $result
}
# RFC 2831 2.1
# Char categories as per spec...
# Build up a regexp for splitting the challenge into key value pairs.
proc ::SASL::DigestParameters {challenge} {
set sep "\\\]\\\[\\\\()<>@,;:\\\"\\\?=\\\{\\\} \t"
set tok {0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\-\|\~\!\#\$\%\&\*\+\.\^\_\`}
set sqot {(?:\'(?:\\.|[^\'\\])*\')}
set dqot {(?:\"(?:\\.|[^\"\\])*\")}
set parameters {}
regsub -all "(\[${tok}\]+)=(${dqot}|(?:\[${tok}\]+))(?:\[${sep}\]+|$)" $challenge {\1 \2 } parameters
return $parameters
}
# RFC 2831 2.1.2.1
#
proc ::SASL::DigestResponse {user realm pass uri qop nonce noncecount cnonce} {
set A1 [md5_bin "$user:$realm:$pass"]
set A2 "AUTHENTICATE:$uri"
if {![string equal $qop "auth"]} {
append A2 :[string repeat 0 32]
}
set A1h [md5_hex "${A1}:$nonce:$cnonce"]
set A2h [md5_hex $A2]
set R [md5_hex $A1h:$nonce:$noncecount:$cnonce:$qop:$A2h]
return $R
}
# RFC 2831 2.1.2.2
#
proc ::SASL::DigestResponse2 {user realm pass uri qop nonce noncecount cnonce} {
set A1 [md5_bin "$user:$realm:$pass"]
set A2 ":$uri"
if {![string equal $qop "auth"]} {
append A2 :[string repeat 0 32]
}
set A1h [md5_hex "${A1}:$nonce:$cnonce"]
set A2h [md5_hex $A2]
set R [md5_hex $A1h:$nonce:$noncecount:$cnonce:$qop:$A2h]
return $R
}
# Get 16 random bytes for a nonce value. If we can use /dev/random, do so
# otherwise we hash some values.
#
proc ::SASL::CreateNonce {} {
set bytes {}
if {[file readable /dev/urandom]} {
catch {
set f [open /dev/urandom r]
fconfigure $f -translation binary -buffering none
set bytes [read $f 16]
close $f
}
}
if {[string length $bytes] < 1} {
set bytes [md5_bin [clock seconds]:[pid]:[expr {rand()}]]
}
return [binary scan $bytes h* r; set r]
}
::SASL::register DIGEST-MD5 40 \
::SASL::DIGEST-MD5:client ::SASL::DIGEST-MD5:server
# -------------------------------------------------------------------------
# OTP SASL MECHANISM
#
# Implementation of the OTP SASL mechanism (RFC2444).
#
# Comments:
#
# RFC 2289: A One-Time Password System
# RFC 2444: OTP SASL Mechanism
# RFC 2243: OTP Extended Responses
# Client initializes with authid\0authzid
# Server responds with extended OTP responses
# eg: otp-md5 498 bi32123 ext
# Client responds with otp result as:
# hex:xxxxxxxxxxxxxxxx
# or
# word:WWWW WWW WWWW WWWW WWWW
#
# To support changing the otp sequence the extended commands have:
# init-hex:::
# eg: init-hex:xxxxxxxxxxxx:md5 499 seed987:xxxxxxxxxxxxxx
# or init-word
proc ::SASL::OTP:client {context challenge args} {
upvar #0 $context ctx
package require otp
incr ctx(step)
switch -exact -- $ctx(step) {
1 {
set authzid [eval $ctx(callback) [list $context login]]
set username [eval $ctx(callback) [list $context username]]
set ctx(response) "$authzid\x00$username"
set cont 1
}
2 {
foreach {type count seed ext} $challenge break
set type [lindex [split $type -] 1]
if {[lsearch -exact {md4 md5 sha1 rmd160} $type] == -1} {
return -code error "unsupported digest algorithm \"$type\":\
must be one of md4, md5, sha1 or rmd160"
}
set challenge [lrange $challenge 3 end]
set password [eval $ctx(callback) [list $context password]]
set otp [::otp::otp-$type -word -seed $seed \
-count $count $password]
if {[string match "ext*" $ext]} {
set otp word:$otp
}
set ctx(response) $otp
set cont 0
}
default {
return -code error "unexpected state \"$ctx(step)\":\
the SASL OTP mechanism only has 2 steps"
}
}
return $cont
}
::SASL::register OTP 45 ::SASL::OTP:client
# -------------------------------------------------------------------------
package provide SASL $::SASL::version
# -------------------------------------------------------------------------
#
# Local variables:
# indent-tabs-mode: nil
# End:
amsn-0.98.9/utils/voipcontrols/ 0000755 0001750 0001750 00000000000 11757711633 016305 5 ustar billiob billiob amsn-0.98.9/utils/voipcontrols/pkgIndex.tcl 0000644 0001750 0001750 00000000362 11145660457 020561 0 ustar billiob billiob package ifneeded voipcontrols 0.1 [ format {
set olddir [pwd]
cd "%s"
if {[catch {source [file join voipcontrols.tcl]} err]} {
cd $olddir
error "error while loading package voipcontrols: $err"
} else {
cd $olddir
}
} [list $dir]]
amsn-0.98.9/utils/voipcontrols/voipcontrols.tcl 0000644 0001750 0001750 00000026511 11243371757 021556 0 ustar billiob billiob
package require snit
package provide voipcontrols 0.1
snit::widget voipcontrol {
option -orient -default "vertical" -readonly yes
option -mixerframesize -default 10 -readonly yes
option -buttonframesize -default 22 -readonly yes
option -bg -default white -configuremethod SetBackground
option -state -default normal -configuremethod SetState
component mixerframe
component mutecheckbutton
component endcallbutton
delegate option -endcallimage to endcallbutton as -image
delegate option -endcallcommand to endcallbutton as -command
delegate option -endcallstate to endcallbutton as -state
delegate option -mutedimage to mutecheckbutton
delegate option -unmutedimage to mutecheckbutton
delegate option -mutevariable to mutecheckbutton
delegate option -mutecommand to mutecheckbutton
delegate option -mutestate to mutecheckbutton as -state
delegate option -volumefrom to mixerframe
delegate option -volumeto to mixerframe
delegate option -levelfrom to mixerframe
delegate option -levelto to mixerframe
delegate option -volumevariable to mixerframe as -variable
delegate option -volumecommand to mixerframe as -command
delegate option -volumestate to mixerframe as -state
delegate method setLevel to mixerframe
delegate method Mute to mutecheckbutton
delegate method UnMute to mutecheckbutton
delegate option * to hull
constructor {args} {
set mixerframe [voipmixer ${win}.mixerframe]
set buttonframe [frame ${win}.buttonframe]
set mutecheckbutton [mutecheckbutton ${buttonframe}.mute]
set endcallbutton [button ${buttonframe}.endcall -relief flat -image {}]
$self configurelist $args
#creating mixerframe again since $options(-orient) is not set yet and the component must exist when configurelist is called...
destroy $mixerframe
set mixerframe [voipmixer ${win}.mixerframe -orient $options(-orient) -mutecheckbutton $mutecheckbutton]
$self configurelist $args
if { $options(-orient) == "vertical" } {
pack $mutecheckbutton $endcallbutton
place $mixerframe -width $options(-mixerframesize) -relheight 1
place $buttonframe -x $options(-mixerframesize) -width $options(-buttonframesize) -relheight 1
} else {
pack $mutecheckbutton $endcallbutton -side right
place $mixerframe -height $options(-mixerframesize) -relwidth 1
place $buttonframe -y $options(-mixerframesize) -height $options(-buttonframesize) -relwidth 1
}
}
method SetBackground {option value} {
set options($option) $value
$win configure -background $value
$mixerframe configure -background $value
$win.buttonframe configure -background $value
$mutecheckbutton configure -background $value
$win.buttonframe.endcall configure -background $value
}
method SetState {option value} {
set options($option) $value
$mixerframe configure -state $value
$endcallbutton configure -state $value
$mutecheckbutton configure -state $value
}
method getSize {} {
set size $options(-mixerframesize)
incr size $options(-buttonframesize)
return $size
}
}
snit::widgetadaptor mutecheckbutton {
variable muted
option -mutedimage -default {} -configuremethod SetImage
option -unmutedimage -default {} -configuremethod SetImage
option -mutevariable -default {}
option -mutecommand -default {}
delegate option * to hull
delegate method * to hull
constructor {args} {
installhull using button -relief flat -image {} -command [list $self invoke]
$self configurelist $args
set muted 0
if {[info exists ::$options(-mutevariable)]} {
if {[set ::$options(-mutevariable)]} {
set muted 1
} else {
set muted 0
}
}
$self configure -image $options(-unmutedimage)
}
method SetImage {option value} {
set options($option) $value
if {$muted} {
$self configure -image $options(-mutedimage)
} else {
$self configure -image $options(-unmutedimage)
}
}
method Mute {} {
if {!$muted} {
$self configure -image $options(-mutedimage)
set muted 1
if {[info exists ::$options(-mutevariable)]} {
set ::$options(-mutevariable) $muted
}
if { $options(-mutecommand) != {} } {
eval $options(-mutecommand)
}
}
}
method UnMute {} {
if {$muted} {
$self configure -image $options(-unmutedimage)
set muted 0
if {[info exists ::$options(-mutevariable)]} {
set ::$options(-mutevariable) $muted
}
if { $options(-mutecommand) != {} } {
eval $options(-mutecommand)
}
}
}
method invoke {} {
if {$muted} {
$self configure -image $options(-unmutedimage)
set muted 0
} else {
$self configure -image $options(-mutedimage)
set muted 1
}
if {[info exists ::$options(-mutevariable)]} {
set ::$options(-mutevariable) $muted
}
if { $options(-mutecommand) != {} } {
eval $options(-mutecommand)
}
}
}
snit::widget voipmixer {
option -mutecheckbutton -readonly yes -default ""
option -volumefrom -default -25
option -volumeto -default 15
option -levelfrom -default -20
option -levelto -default 0
option -selectsize -default 5 -configuremethod SetSelectSize
option -variable -default {} -configuremethod SetVariable
option -command -default {}
option -orient -default "vertical" -readonly yes
option -state -default normal
delegate option * to hull
constructor {args} {
frame ${win}.fill
place ${win}.fill -relheight 1 -relwidth 1
frame ${win}.select -background black
$self configurelist $args
bind ${win}.select "$self Motion"
if {![catch {tk windowingsystem} wsystem] && $wsystem != "x11"} {
bind ${win} "$self MouseWheel"
bind ${win}.fill "$self MouseWheel"
bind ${win}.select "$self MouseWheel"
} else {
bind ${win} "$self MoveSelect 0"
bind ${win}.fill "$self MoveSelect 0"
bind ${win}.select "$self MoveSelect 0"
bind ${win} "$self MoveSelect 1"
bind ${win}.fill "$self MoveSelect 1"
bind ${win}.select "$self MoveSelect 1"
}
}
method MoveSelect {{up 1}} {
if { $options(-state) != "normal"} {return}
set val [expr {double([set ::$options(-variable)]) - double($options(-volumefrom))}]
set val [expr {$val / (double($options(-volumeto)) - double($options(-volumefrom)))}]
if {$up == 1} {
set val [expr {$val + 0.1}]
} else {
set val [expr {$val - 0.1}]
}
if { $options(-orient) == "vertical" } {
set size [winfo height ${win}]
set max [expr {1-double($options(-selectsize))/double(${size})}]
set rel [expr {1-$val}]
} else {
set size [winfo width ${win}]
set max [expr {1-double($options(-selectsize))/double(${size})}]
set rel $val
}
if {$rel > $max} {
set rel $max
} else {
if {$rel < 0} {
set rel 0
}
}
if { $options(-mutecheckbutton) != ""} {
if { $options(-orient) == "vertical" } {
if {$rel >= 0.95} {
$options(-mutecheckbutton) Mute
} else {
$options(-mutecheckbutton) UnMute
}
} else {
if {$rel <= 0.05} {
$options(-mutecheckbutton) Mute
} else {
$options(-mutecheckbutton) UnMute
}
}
}
if { $options(-orient) == "vertical" } {
place configure ${win}.select -rely $rel
} else {
place configure ${win}.select -relx $rel
}
if {[info exists ::$options(-variable)]} {
if { $options(-orient) == "vertical" } {
set val [expr {1-$rel/$max}]
set val [expr {$options(-volumefrom) + $val * ($options(-volumeto) - $options(-volumefrom))}]
set ::$options(-variable) $val
if { $options(-command) != {} } {
eval $options(-command) $val
}
} else {
set val [expr {$rel/$max}]
set val [expr {$options(-volumefrom) + $val * ($options(-volumeto) - $options(-volumefrom))}]
set ::$options(-variable) $val
if { $options(-command) != {} } {
eval $options(-command) $val
}
}
}
}
method MouseWheel {} {
if {%D>0} {
$self MoveSelect 1
} else {
$self MoveSelect 0
}
}
method Motion {} {
if { $options(-state) != "normal"} {return}
if { $options(-orient) == "vertical" } {
set size [winfo height ${win}]
set max [expr {1-double($options(-selectsize))/double(${size})}]
set rel [expr {double([winfo pointery ${win}] - [winfo rooty ${win}])/double(${size})}]
} else {
set size [winfo width ${win}]
set max [expr {1-double($options(-selectsize))/double(${size})}]
set rel [expr {double([winfo pointerx ${win}] - [winfo rootx ${win}])/double(${size})}]
}
if {$rel > $max} {
set rel $max
} else {
if {$rel < 0} {
set rel 0
}
}
if { $options(-mutecheckbutton) != "" } {
if { $options(-orient) == "vertical" } {
if {$rel >= 0.95} {
$options(-mutecheckbutton) Mute
} else {
$options(-mutecheckbutton) UnMute
}
} else {
if {$rel <= 0.05} {
$options(-mutecheckbutton) Mute
} else {
$options(-mutecheckbutton) UnMute
}
}
}
if { $options(-orient) == "vertical" } {
place configure ${win}.select -rely ${rel}
} else {
place configure ${win}.select -relx ${rel}
}
if {[info exists ::$options(-variable)]} {
if { $options(-orient) == "vertical" } {
set val [expr {1-$rel/$max}]
set val [expr {$options(-volumefrom) + $val * ($options(-volumeto) - $options(-volumefrom))}]
set ::$options(-variable) $val
if { $options(-command) != {} } {
eval $options(-command) $val
}
} else {
set val [expr {$rel/$max}]
set val [expr {$options(-volumefrom) + $val * ($options(-volumeto) - $options(-volumefrom))}]
set ::$options(-variable) $val
if { $options(-command) != {} } {
eval $options(-command) $val
}
}
}
}
method SetSelectSize {option value} {
set options($option) $value
if { $options(-orient) == "vertical" } {
${win}.select configure -height $value
place ${win}.select -height $value
} else {
${win}.select configure -width $value
place ${win}.select -width $value
}
}
method SetVariable { option value} {
set options($option) $value
if {![info exists ::$options(-variable)]
|| [set ::$options(-variable)] > $options(-volumeto)
|| [set ::$options(-variable)] < $options(-volumefrom)} {
set ::$options(-variable) [expr {$options(-volumefrom) + 0.5 * (double($options(-volumeto)) - double($options(-volumefrom)))}]
}
set val [expr {double([set ::$options(-variable)]) - double($options(-volumefrom))}]
set val [expr {$val / (double($options(-volumeto)) - double($options(-volumefrom)))}]
if { $options(-orient) == "vertical" } {
set val [expr {1-$val}]
place ${win}.select -relx 0 -rely ${val} -relwidth 1 -height $options(-selectsize)
} else {
place ${win}.select -rely 0 -relx ${val} -relheight 1 -width $options(-selectsize)
}
}
method setLevel {value} {
if { $options(-state) != "normal"} {return}
if {[expr {$value == "-inf"}] ||
[expr {$value == "inf"}] } {
set value $options(-levelfrom)
}
set relsize [expr {double($value) - double($options(-levelfrom))}]
set relsize [expr {$relsize / (double($options(-levelto)) - double($options(-levelfrom)))}]
if { $options(-orient) == "vertical" } {
place conf $win.fill -relheight $relsize
place conf $win.fill -rely [expr {1-$relsize}]
} else {
place conf $win.fill -relwidth $relsize
}
if {[expr $relsize > 0.5]} {
set R e1
binary scan [binary format i [expr {int(2*(1.0-$relsize)*225)}]] H2 G
} else {
set G e1
binary scan [binary format i [expr {int(2*$relsize*225)}]] H2 R
}
set B 00
${win}.fill configure -background \#${R}${G}${B}
}
}
amsn-0.98.9/utils/voipcontrols/test.tcl 0000644 0001750 0001750 00000001500 11203640746 017754 0 ustar billiob billiob #!/usr/bin/env wish
lappend auto_path "../"
package require voipcontrols
#wm attributes
wm title . "voipcontrol test"
wm geometry . 200x200
update
variable var
set var 0.75
set var2 0.15
proc showValue {value} {
puts "value=$value"
}
voipcontrol .sm -volumevariable var -volumecommand [list showValue]
voipcontrol .sm2 -orient horizontal -height 25
place .sm -width 25 -relheight 1
place .sm2 -height 25 -relwidth 1 -width -25 -x 25
update
puts "[winfo width .sm] [winfo height .sm]"
puts "============"
puts "[winfo width .sm2] [winfo height .sm2]"
proc timer {sm limit delay {value 0}} {
variable var
variable var2
puts "var=$var\tvar2=$var2"
$sm setLevel $value
incr value
if {$value >= $limit} {set value -20}
after $delay [list timer $sm $limit $delay $value]
}
timer .sm 0 200 -20
timer .sm2 0 200 -20
amsn-0.98.9/utils/webcamsn/ 0000755 0001750 0001750 00000000000 11757711723 015343 5 ustar billiob billiob amsn-0.98.9/utils/webcamsn/README 0000644 0001750 0001750 00000002552 10225230720 016205 0 ustar billiob billiob ABOUT
-----
libmimic is an open source video encoding/decoding library for Mimic V2.x-
encoded content (fourCC: ML20), which is the encoding used by MSN Messenger
for webcam conversations.
It was written because there was no third-party MSN-client that supported
this feature due to this proprietary/unknown codec involved. I didn't like
this lack of interoperability, so I decided to do something about it. After
studying the official MSN-client a little closer, it became clear that the
codec involved was statically linked into the executable, so there was no
easy way to use the codec code through Wine. So for fun, and challenge, I
reverse-engineered the original implementation by studying the massive
amount of assembly code involved, and after a lot of hard work I ended
up with this implementation in C.
It should be noted that reverse-engineering for interoperability is 100%
legal here in Norway (and in most European countries).
THANKS
------
Special thanks to Rob Taylor and the rest of the Farsight-team for all
the feedback and inspiration during development, you guys rock! :-)
BOTTOM LINE
-----------
If you like my work and decide to use it in your project, please feel free
to credit me. I put a lot of time and hard work into this, so I hope others
will find it useful.
Well, enough chit chat, enjoy! :-)
Ole André Vadla Ravnås
oleavr at gmail dot com
amsn-0.98.9/utils/webcamsn/NEWS 0000644 0001750 0001750 00000000000 10225230720 016006 0 ustar billiob billiob amsn-0.98.9/utils/webcamsn/pkgIndex.tcl 0000644 0001750 0001750 00000000750 11031756705 017614 0 ustar billiob billiob # Tcl package index file, version 1.0
if {[package vcompare [info tclversion] 8.4] < 0} return
if {[file exists [file join $dir [info tclversion] webcamsn[info shared]]]} {
package ifneeded webcamsn 0.1 "package require Tk; [list load [file join $dir [info tclversion] webcamsn[info shared]] webcamsn];package provide webcamsn 0.1"
} else {
package ifneeded webcamsn 0.1 "package require Tk; [list load [file join $dir webcamsn[info shared]] webcamsn];package provide webcamsn 0.1"
}
amsn-0.98.9/utils/webcamsn/8.5/ 0000755 0001750 0001750 00000000000 11757711723 015655 5 ustar billiob billiob amsn-0.98.9/utils/webcamsn/COPYING 0000644 0001750 0001750 00000063476 10225230720 016374 0 ustar billiob billiob GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
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 and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, 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 library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete 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 distribute a copy of this License along with the
Library.
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 Library or any portion
of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
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 Library, 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 Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you 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.
If distribution of 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 satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be 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.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library 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.
9. 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 Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
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 with
this License.
11. 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 Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library 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 Library.
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.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library 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.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser 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 Library
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 Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
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
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "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
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. 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 LIBRARY 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
LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. 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)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
amsn-0.98.9/utils/webcamsn/src/ 0000755 0001750 0001750 00000000000 11757711633 016132 5 ustar billiob billiob amsn-0.98.9/utils/webcamsn/src/encode.c 0000644 0001750 0001750 00000031064 10734050401 017516 0 ustar billiob billiob /* Copyright (C) 2005 Ole André Vadla Ravnås
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include
#include
#define _USE_MATH_DEFINES
#include
#include "mimic-private.h"
#ifndef M_LN10
//Not defined in VS6
#define M_LN10 2.30258509299404568402
#endif
#define LUMINANCE_THRESHOLD 32.0f
#define CHROMINANCE_THRESHOLD 36.0f
static void encode_main(MimCtx *ctx, guchar *out_buf, gboolean is_pframe);
/**
* Encode a MIMIC-encoded frame from RGB data.
*
* @param ctx the mimic context
* @param input_buffer buffer containing pixeldata in RGB 24-bpp packed pixel top-down format
* @param output_buffer buffer that will receive the MIMIC-encoded frame
* (use #mimic_get_property to determine the required buffer size)
* @param output_length pointer to an integer that receives the length of the encoded data
* written to output_buffer
* @param make_keyframe whether the encoder should make this frame a keyframe
* @returns #TRUE on success
*/
gboolean mimic_encode_frame(MimCtx *ctx,
const guchar *input_buffer,
guchar *output_buffer,
gint *output_length,
gboolean make_keyframe)
{
guchar *output_y, *output_cb, *output_cr;
/*
* Some sanity checks.
*/
if (ctx == NULL || input_buffer == NULL ||
output_buffer == NULL || output_length == NULL)
{
return FALSE;
}
if (!ctx->encoder_initialized)
return FALSE;
/*
* Initialize state.
*/
ctx->chunk_ptr = (guint32 *) (output_buffer + 20);
ctx->cur_chunk = 0;
ctx->cur_chunk_len = 0;
if (ctx->frame_num == 0)
make_keyframe = TRUE;
/*
* Write header.
*/
memset(output_buffer, 0, 20);
*((guint16 *) (output_buffer + 0)) = GUINT16_TO_LE(256);
*((guint16 *) (output_buffer + 2)) = GUINT16_TO_LE(ctx->quality);
*((guint16 *) (output_buffer + 4)) = GUINT16_TO_LE(ctx->frame_width);
*((guint16 *) (output_buffer + 6)) = GUINT16_TO_LE(ctx->frame_height);
*((guint32 *) (output_buffer + 12)) = GUINT32_TO_LE((make_keyframe == 0));
*(output_buffer + 16) = ctx->num_coeffs;
*(output_buffer + 17) = 0;
/*
* Perform RGB to YUV 420 conversion.
*/
output_y = ctx->cur_frame_buf;
output_cr = ctx->cur_frame_buf + ctx->y_size;
output_cb = ctx->cur_frame_buf + ctx->y_size + ctx->crcb_size;
_rgb_to_yuv(input_buffer,
output_y,
output_cb,
output_cr,
ctx->frame_width,
ctx->frame_height);
/*
* Encode frame.
*/
encode_main(ctx, output_buffer, (make_keyframe == FALSE));
/*
* Write out any pending bits to stream by zero-padding with 32 bits.
*/
_write_bits(ctx, 0, 32);
/*
* Calculate bytes written.
*/
*output_length = (guchar *) ctx->chunk_ptr - output_buffer;
/*
* Increment frame counter.
*/
ctx->frame_num++;
return TRUE;
}
static gdouble compare_blocks(const guchar *p1,
const guchar *p2,
gint stride,
gint row_count,
gboolean is_chrom);
/*
* encode_main
*
* Main encoding loop.
*/
static void encode_main(MimCtx *ctx, guchar *out_buf, gboolean is_pframe)
{
gint x, y, i, offset, chrom_ch;
gint dct_block[64];
guchar *src, *dst, *p1, *p2;
gdouble match;
gboolean encoded;
/*
* Round down small differences in luminance channel.
*/
if (is_pframe) {
p1 = ctx->cur_frame_buf;
p2 = ctx->prev_frame_buf;
for (i = 0; i < ctx->y_size; i++) {
if (abs(p2[0] - p1[0]) < 7)
p1[0] = p2[0];
p1++;
p2++;
}
}
/*
* Encode Y plane.
*/
for (y = 0; y < ctx->num_vblocks_y; y++) {
for (x = 0; x < ctx->num_hblocks_y; x++) {
/* Calculate final offset into buffer. */
offset = (ctx->y_stride * 8 * y) + (x * 8);
src = NULL;
encoded = FALSE;
if (is_pframe) {
/* Is the current block similar enough to what it was in the previous frame? */
match = compare_blocks(ctx->cur_frame_buf + offset,
ctx->prev_frame_buf + offset,
ctx->y_stride, 8,
FALSE);
if (match > LUMINANCE_THRESHOLD) {
/* Yes: write out '1' to indicate a no-change condition. */
_write_bits(ctx, 1, 1);
src = ctx->prev_frame_buf + offset;
encoded = TRUE;
} else {
/* No: Is the current block similar enough to what it was in one
* of the (up to) 15 last frames preceding the previous? */
gint best_index = 0;
gdouble best_match = 0.0;
gint num_backrefs = ctx->frame_num - 1;
if (num_backrefs > 15)
num_backrefs = 15;
for (i = 1; i <= num_backrefs; i++) {
match = compare_blocks(ctx->buf_ptrs[(ctx->ptr_index + i) % 16] + offset,
ctx->cur_frame_buf + offset,
ctx->y_stride, 8,
FALSE);
if (match > LUMINANCE_THRESHOLD && match > best_match) {
best_index = i;
best_match = match;
}
}
if (best_index != 0) {
/* Yes: write out '01' to indicate a "change but like previous"-condition,
* followed by 4 bits containing the back-reference. */
_write_bits(ctx, 0, 1);
_write_bits(ctx, 1, 1);
_write_bits(ctx, best_index, 4);
src = ctx->buf_ptrs[(ctx->ptr_index + best_index) % 16] + offset;
encoded = TRUE;
}
}
}
if (!encoded) {
/* Keyframe or in any case no? ;-) Well, encode it then. */
if (is_pframe) {
_write_bits(ctx, 0, 1);
_write_bits(ctx, 0, 1);
}
_fdct_quant_block(ctx,
dct_block,
ctx->cur_frame_buf + offset,
ctx->y_stride,
FALSE,
ctx->num_coeffs);
_vlc_encode_block(ctx,
dct_block,
ctx->num_coeffs);
}
/* And if there was some kind of no-change condition,
* we want to copy the previous block. */
if (src != NULL) {
dst = ctx->cur_frame_buf + offset;
for (i = 0; i < 8; i++) {
memcpy(dst, src, 8);
src += ctx->y_stride;
dst += ctx->y_stride;
}
}
}
}
/*
* Encode Cr and Cb planes.
*/
for (chrom_ch = 0; chrom_ch < 2; chrom_ch++) {
/* Calculate base offset into buffer. */
gint base_offset = ctx->y_size + (ctx->crcb_size * chrom_ch);
for (y = 0; y < ctx->num_vblocks_cbcr; y++) {
guchar tmp_block[64];
guint num_rows = 8;
/* The last row of blocks in chrominance for 160x120 resolution
* is half the normal height and must be accounted for. */
if (y + 1 == ctx->num_vblocks_cbcr && ctx->frame_height % 16 != 0)
num_rows = 4;
for (x = 0; x < ctx->num_hblocks_cbcr; x++) {
/* Calculate final offset into buffer. */
offset = base_offset + (ctx->crcb_stride * 8 * y) + (x * 8);
src = NULL;
encoded = FALSE;
if (is_pframe) {
/* Is the current block similar enough to what it was in the previous frame? */
match = compare_blocks(ctx->prev_frame_buf + offset,
ctx->cur_frame_buf + offset,
ctx->crcb_stride, num_rows,
TRUE);
if (match > CHROMINANCE_THRESHOLD) {
/* Yes: write out '0' to indicate a no-change condition. */
_write_bits(ctx, 0, 1);
encoded = TRUE;
src = ctx->prev_frame_buf + offset;
dst = ctx->cur_frame_buf + offset;
for (i = 0; i < num_rows; i++) {
memcpy(dst, src, 8);
src += ctx->crcb_stride;
dst += ctx->crcb_stride;
}
}
}
if (!encoded) {
/* Keyframe or just not similar enough? ;-) Well, encode it then. */
if (is_pframe)
_write_bits(ctx, 1, 1);
/* Use a temporary array to handle cases where the
* current block is not of normal height (see above). */
src = ctx->cur_frame_buf + offset;
dst = tmp_block;
for (i = 0; i < 8; i++) {
memcpy(dst, src, 8);
if (i < (num_rows - 1))
src += ctx->crcb_stride;
dst += 8;
}
_fdct_quant_block(ctx,
dct_block,
tmp_block,
8,
TRUE,
ctx->num_coeffs);
_vlc_encode_block(ctx,
dct_block,
ctx->num_coeffs);
}
}
}
}
/*
* Make a copy of the current frame and store in
* the circular pointer list of 16 entries.
*/
ctx->prev_frame_buf = ctx->buf_ptrs[ctx->ptr_index];
memcpy(ctx->prev_frame_buf, ctx->cur_frame_buf,
ctx->y_size + (ctx->crcb_size * 2));
if (--ctx->ptr_index < 0)
ctx->ptr_index = 15;
}
/*
* compare_blocks
*
* Helper-function used to compare two blocks and
* determine how similar they are.
*/
static gdouble compare_blocks(const guchar *p1,
const guchar *p2,
gint stride,
gint row_count,
gboolean is_chrom)
{
gint i, j, sum;
gdouble d;
sum = 0;
for (i = 0; i < row_count; i++) {
for (j = 0; j < 8; j++) {
gint d = p2[j] - p1[j];
sum += d * d;
}
p1 += stride;
p2 += stride;
}
if (is_chrom) {
if (row_count == 8)
d = sum * 0.015625;
else
d = sum * 0.03125;
} else {
d = sum / 64;
}
if (d == 0.0f)
return 100.0f;
else
return (10.0f * log(65025.0f / d)) / M_LN10;
}
amsn-0.98.9/utils/webcamsn/src/vlc_common.c 0000644 0001750 0001750 00000225141 10647521273 020433 0 ustar billiob billiob /* Copyright (C) 2005 Ole André Vadla Ravnås
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include
#include "mimic-private.h"
guchar _col_zag[64] = {
0, 8, 1, 2, 9, 16, 24, 17,
10, 3, 4, 11, 18, 25, 32, 40,
33, 26, 19, 12, 5, 6, 13, 20,
27, 34, 41, 48, 56, 49, 42, 35,
28, 21, 14, 7, 15, 22, 29, 36,
43, 50, 57, 58, 51, 44, 37, 30,
23, 31, 38, 45, 52, 59, 39, 46,
53, 60, 61, 54, 47, 55, 62, 63
};
VlcSymbol _vlc_alphabet[16][128] = {
/*
* base alphabet - no zeroes prefixed
*/
{
{ 3, 0x1, 0, 0 }, { 4, 0x7, 0, 0 },
{ 4, 0x5, 0, 0 }, { 6, 0x27, 0, 0 },
{ 6, 0x25, 0, 0 }, { 6, 0x23, 0, 0 },
{ 6, 0x21, 0, 0 }, { 8, 0xcf, 0, 0 },
{ 8, 0xcd, 0, 0 }, { 8, 0xcb, 0, 0 },
{ 8, 0xc9, 0, 0 }, { 8, 0xc7, 0, 0 },
{ 8, 0xc5, 0, 0 }, { 8, 0xc3, 0, 0 },
{ 8, 0xc1, 0, 0 }, { 10, 0x35f, 0, 0 },
{ 10, 0x35d, 0, 0 }, { 10, 0x35b, 0, 0 },
{ 10, 0x359, 0, 0 }, { 10, 0x357, 0, 0 },
{ 10, 0x355, 0, 0 }, { 10, 0x353, 0, 0 },
{ 10, 0x351, 0, 0 }, { 10, 0x34f, 0, 0 },
{ 10, 0x34d, 0, 0 }, { 10, 0x34b, 0, 0 },
{ 10, 0x349, 0, 0 }, { 10, 0x347, 0, 0 },
{ 10, 0x345, 0, 0 }, { 10, 0x343, 0, 0 },
{ 10, 0x341, 0, 0 }, { 12, 0xeff, 0, 0 },
{ 12, 0xefd, 0, 0 }, { 12, 0xefb, 0, 0 },
{ 12, 0xef9, 0, 0 }, { 12, 0xef7, 0, 0 },
{ 12, 0xef5, 0, 0 }, { 12, 0xef3, 0, 0 },
{ 12, 0xef1, 0, 0 }, { 12, 0xeef, 0, 0 },
{ 12, 0xeed, 0, 0 }, { 12, 0xeeb, 0, 0 },
{ 12, 0xee9, 0, 0 }, { 12, 0xee7, 0, 0 },
{ 12, 0xee5, 0, 0 }, { 12, 0xee3, 0, 0 },
{ 12, 0xee1, 0, 0 }, { 12, 0xedf, 0, 0 },
{ 12, 0xedd, 0, 0 }, { 12, 0xedb, 0, 0 },
{ 12, 0xed9, 0, 0 }, { 12, 0xed7, 0, 0 },
{ 12, 0xed5, 0, 0 }, { 12, 0xed3, 0, 0 },
{ 12, 0xed1, 0, 0 }, { 12, 0xecf, 0, 0 },
{ 12, 0xecd, 0, 0 }, { 12, 0xecb, 0, 0 },
{ 12, 0xec9, 0, 0 }, { 12, 0xec7, 0, 0 },
{ 12, 0xec5, 0, 0 }, { 12, 0xec3, 0, 0 },
{ 12, 0xec1, 0, 0 }, { 17, 0x1fd7f, 0, 0 },
{ 17, 0x1fd7d, 0, 0 }, { 17, 0x1fd7b, 0, 0 },
{ 17, 0x1fd79, 0, 0 }, { 17, 0x1fd77, 0, 0 },
{ 17, 0x1fd75, 0, 0 }, { 17, 0x1fd73, 0, 0 },
{ 17, 0x1fd71, 0, 0 }, { 17, 0x1fd6f, 0, 0 },
{ 17, 0x1fd6d, 0, 0 }, { 17, 0x1fd6b, 0, 0 },
{ 17, 0x1fd69, 0, 0 }, { 17, 0x1fd67, 0, 0 },
{ 17, 0x1fd65, 0, 0 }, { 17, 0x1fd63, 0, 0 },
{ 17, 0x1fd61, 0, 0 }, { 17, 0x1fd5f, 0, 0 },
{ 17, 0x1fd5d, 0, 0 }, { 17, 0x1fd5b, 0, 0 },
{ 17, 0x1fd59, 0, 0 }, { 17, 0x1fd57, 0, 0 },
{ 17, 0x1fd55, 0, 0 }, { 17, 0x1fd53, 0, 0 },
{ 17, 0x1fd51, 0, 0 }, { 17, 0x1fd4f, 0, 0 },
{ 17, 0x1fd4d, 0, 0 }, { 17, 0x1fd4b, 0, 0 },
{ 17, 0x1fd49, 0, 0 }, { 17, 0x1fd47, 0, 0 },
{ 17, 0x1fd45, 0, 0 }, { 17, 0x1fd43, 0, 0 },
{ 17, 0x1fd41, 0, 0 }, { 17, 0x1fd3f, 0, 0 },
{ 17, 0x1fd3d, 0, 0 }, { 17, 0x1fd3b, 0, 0 },
{ 17, 0x1fd39, 0, 0 }, { 17, 0x1fd37, 0, 0 },
{ 17, 0x1fd35, 0, 0 }, { 17, 0x1fd33, 0, 0 },
{ 17, 0x1fd31, 0, 0 }, { 17, 0x1fd2f, 0, 0 },
{ 17, 0x1fd2d, 0, 0 }, { 17, 0x1fd2b, 0, 0 },
{ 17, 0x1fd29, 0, 0 }, { 17, 0x1fd27, 0, 0 },
{ 17, 0x1fd25, 0, 0 }, { 17, 0x1fd23, 0, 0 },
{ 17, 0x1fd21, 0, 0 }, { 17, 0x1fd1f, 0, 0 },
{ 17, 0x1fd1d, 0, 0 }, { 17, 0x1fd1b, 0, 0 },
{ 17, 0x1fd19, 0, 0 }, { 17, 0x1fd17, 0, 0 },
{ 17, 0x1fd15, 0, 0 }, { 17, 0x1fd13, 0, 0 },
{ 17, 0x1fd11, 0, 0 }, { 17, 0x1fd0f, 0, 0 },
{ 17, 0x1fd0d, 0, 0 }, { 17, 0x1fd0b, 0, 0 },
{ 17, 0x1fd09, 0, 0 }, { 17, 0x1fd07, 0, 0 },
{ 17, 0x1fd05, 0, 0 }, { 17, 0x1fd03, 0, 0 },
{ 17, 0x1fd01, 0, 0 }, { 17, 0x1fd01, 0, 0 }
},
/*
* prefixed with 1 zero
*/
{
{ 5, 0x17, 0, 0 }, { 8, 0xe7, 0, 0 },
{ 8, 0xe5, 0, 0 }, { 9, 0x1d7, 0, 0 },
{ 9, 0x1d5, 0, 0 }, { 9, 0x1d3, 0, 0 },
{ 9, 0x1d1, 0, 0 }, { 12, 0xf8f, 0, 0 },
{ 12, 0xf8d, 0, 0 }, { 12, 0xf8b, 0, 0 },
{ 12, 0xf89, 0, 0 }, { 12, 0xf87, 0, 0 },
{ 12, 0xf85, 0, 0 }, { 12, 0xf83, 0, 0 },
{ 12, 0xf81, 0, 0 }, { 15, 0x7f1f, 0, 0 },
{ 15, 0x7f1d, 0, 0 }, { 15, 0x7f1b, 0, 0 },
{ 15, 0x7f19, 0, 0 }, { 15, 0x7f17, 0, 0 },
{ 15, 0x7f15, 0, 0 }, { 15, 0x7f13, 0, 0 },
{ 15, 0x7f11, 0, 0 }, { 15, 0x7f0f, 0, 0 },
{ 15, 0x7f0d, 0, 0 }, { 15, 0x7f0b, 0, 0 },
{ 15, 0x7f09, 0, 0 }, { 15, 0x7f07, 0, 0 },
{ 15, 0x7f05, 0, 0 }, { 15, 0x7f03, 0, 0 },
{ 15, 0x7f01, 0, 0 }, { 16, 0xfe7f, 0, 0 },
{ 16, 0xfe7d, 0, 0 }, { 16, 0xfe7b, 0, 0 },
{ 16, 0xfe79, 0, 0 }, { 16, 0xfe77, 0, 0 },
{ 16, 0xfe75, 0, 0 }, { 16, 0xfe73, 0, 0 },
{ 16, 0xfe71, 0, 0 }, { 16, 0xfe6f, 0, 0 },
{ 16, 0xfe6d, 0, 0 }, { 16, 0xfe6b, 0, 0 },
{ 16, 0xfe69, 0, 0 }, { 16, 0xfe67, 0, 0 },
{ 16, 0xfe65, 0, 0 }, { 16, 0xfe63, 0, 0 },
{ 16, 0xfe61, 0, 0 }, { 16, 0xfe5f, 0, 0 },
{ 16, 0xfe5d, 0, 0 }, { 16, 0xfe5b, 0, 0 },
{ 16, 0xfe59, 0, 0 }, { 16, 0xfe57, 0, 0 },
{ 16, 0xfe55, 0, 0 }, { 16, 0xfe53, 0, 0 },
{ 16, 0xfe51, 0, 0 }, { 16, 0xfe4f, 0, 0 },
{ 16, 0xfe4d, 0, 0 }, { 16, 0xfe4b, 0, 0 },
{ 16, 0xfe49, 0, 0 }, { 16, 0xfe47, 0, 0 },
{ 16, 0xfe45, 0, 0 }, { 16, 0xfe43, 0, 0 },
{ 16, 0xfe41, 0, 0 }, { 27, 0x7fffff9, 7, 0x7f },
{ 27, 0x7fffff9, 7, 0x7d }, { 27, 0x7fffff9, 7, 0x7b },
{ 27, 0x7fffff9, 7, 0x79 }, { 27, 0x7fffff9, 7, 0x77 },
{ 27, 0x7fffff9, 7, 0x75 }, { 27, 0x7fffff9, 7, 0x73 },
{ 27, 0x7fffff9, 7, 0x71 }, { 27, 0x7fffff9, 7, 0x6f },
{ 27, 0x7fffff9, 7, 0x6d }, { 27, 0x7fffff9, 7, 0x6b },
{ 27, 0x7fffff9, 7, 0x69 }, { 27, 0x7fffff9, 7, 0x67 },
{ 27, 0x7fffff9, 7, 0x65 }, { 27, 0x7fffff9, 7, 0x63 },
{ 27, 0x7fffff9, 7, 0x61 }, { 27, 0x7fffff9, 7, 0x5f },
{ 27, 0x7fffff9, 7, 0x5d }, { 27, 0x7fffff9, 7, 0x5b },
{ 27, 0x7fffff9, 7, 0x59 }, { 27, 0x7fffff9, 7, 0x57 },
{ 27, 0x7fffff9, 7, 0x55 }, { 27, 0x7fffff9, 7, 0x53 },
{ 27, 0x7fffff9, 7, 0x51 }, { 27, 0x7fffff9, 7, 0x4f },
{ 27, 0x7fffff9, 7, 0x4d }, { 27, 0x7fffff9, 7, 0x4b },
{ 27, 0x7fffff9, 7, 0x49 }, { 27, 0x7fffff9, 7, 0x47 },
{ 27, 0x7fffff9, 7, 0x45 }, { 27, 0x7fffff9, 7, 0x43 },
{ 27, 0x7fffff9, 7, 0x41 }, { 27, 0x7fffff9, 7, 0x3f },
{ 27, 0x7fffff9, 7, 0x3d }, { 27, 0x7fffff9, 7, 0x3b },
{ 27, 0x7fffff9, 7, 0x39 }, { 27, 0x7fffff9, 7, 0x37 },
{ 27, 0x7fffff9, 7, 0x35 }, { 27, 0x7fffff9, 7, 0x33 },
{ 27, 0x7fffff9, 7, 0x31 }, { 27, 0x7fffff9, 7, 0x2f },
{ 27, 0x7fffff9, 7, 0x2d }, { 27, 0x7fffff9, 7, 0x2b },
{ 27, 0x7fffff9, 7, 0x29 }, { 27, 0x7fffff9, 7, 0x27 },
{ 27, 0x7fffff9, 7, 0x25 }, { 27, 0x7fffff9, 7, 0x23 },
{ 27, 0x7fffff9, 7, 0x21 }, { 27, 0x7fffff9, 7, 0x1f },
{ 27, 0x7fffff9, 7, 0x1d }, { 27, 0x7fffff9, 7, 0x1b },
{ 27, 0x7fffff9, 7, 0x19 }, { 27, 0x7fffff9, 7, 0x17 },
{ 27, 0x7fffff9, 7, 0x15 }, { 27, 0x7fffff9, 7, 0x13 },
{ 27, 0x7fffff9, 7, 0x11 }, { 27, 0x7fffff9, 7, 0xf },
{ 27, 0x7fffff9, 7, 0xd }, { 27, 0x7fffff9, 7, 0xb },
{ 27, 0x7fffff9, 7, 0x9 }, { 27, 0x7fffff9, 7, 0x7 },
{ 27, 0x7fffff9, 7, 0x5 }, { 27, 0x7fffff9, 7, 0x3 },
{ 27, 0x7fffff9, 7, 0x1 }, { 27, 0x7fffff9, 7, 0x1 }
},
/*
* prefixed with 2 zeroes
*/
{
{ 6, 0x37, 0, 0 }, { 9, 0x1ef, 0, 0 },
{ 9, 0x1ed, 0, 0 }, { 12, 0xfd7, 0, 0 },
{ 12, 0xfd5, 0, 0 }, { 12, 0xfd3, 0, 0 },
{ 12, 0xfd1, 0, 0 }, { 13, 0x1fbf, 0, 0 },
{ 13, 0x1fbd, 0, 0 }, { 13, 0x1fbb, 0, 0 },
{ 13, 0x1fb9, 0, 0 }, { 13, 0x1fb7, 0, 0 },
{ 13, 0x1fb5, 0, 0 }, { 13, 0x1fb3, 0, 0 },
{ 13, 0x1fb1, 0, 0 }, { 25, 0x1ffff7f, 0, 0 },
{ 25, 0x1ffff7d, 0, 0 }, { 25, 0x1ffff7b, 0, 0 },
{ 25, 0x1ffff79, 0, 0 }, { 25, 0x1ffff77, 0, 0 },
{ 25, 0x1ffff75, 0, 0 }, { 25, 0x1ffff73, 0, 0 },
{ 25, 0x1ffff71, 0, 0 }, { 25, 0x1ffff6f, 0, 0 },
{ 25, 0x1ffff6d, 0, 0 }, { 25, 0x1ffff6b, 0, 0 },
{ 25, 0x1ffff69, 0, 0 }, { 25, 0x1ffff67, 0, 0 },
{ 25, 0x1ffff65, 0, 0 }, { 25, 0x1ffff63, 0, 0 },
{ 25, 0x1ffff61, 0, 0 }, { 30, 0x3ffffe3f, 0, 0 },
{ 30, 0x3ffffe3d, 0, 0 }, { 30, 0x3ffffe3b, 0, 0 },
{ 30, 0x3ffffe39, 0, 0 }, { 30, 0x3ffffe37, 0, 0 },
{ 30, 0x3ffffe35, 0, 0 }, { 30, 0x3ffffe33, 0, 0 },
{ 30, 0x3ffffe31, 0, 0 }, { 30, 0x3ffffe2f, 0, 0 },
{ 30, 0x3ffffe2d, 0, 0 }, { 30, 0x3ffffe2b, 0, 0 },
{ 30, 0x3ffffe29, 0, 0 }, { 30, 0x3ffffe27, 0, 0 },
{ 30, 0x3ffffe25, 0, 0 }, { 30, 0x3ffffe23, 0, 0 },
{ 30, 0x3ffffe21, 0, 0 }, { 30, 0x3ffffe1f, 0, 0 },
{ 30, 0x3ffffe1d, 0, 0 }, { 30, 0x3ffffe1b, 0, 0 },
{ 30, 0x3ffffe19, 0, 0 }, { 30, 0x3ffffe17, 0, 0 },
{ 30, 0x3ffffe15, 0, 0 }, { 30, 0x3ffffe13, 0, 0 },
{ 30, 0x3ffffe11, 0, 0 }, { 30, 0x3ffffe0f, 0, 0 },
{ 30, 0x3ffffe0d, 0, 0 }, { 30, 0x3ffffe0b, 0, 0 },
{ 30, 0x3ffffe09, 0, 0 }, { 30, 0x3ffffe07, 0, 0 },
{ 30, 0x3ffffe05, 0, 0 }, { 30, 0x3ffffe03, 0, 0 },
{ 30, 0x3ffffe01, 0, 0 }, { 27, 0x7fffffa, 7, 0x7f },
{ 27, 0x7fffffa, 7, 0x7d }, { 27, 0x7fffffa, 7, 0x7b },
{ 27, 0x7fffffa, 7, 0x79 }, { 27, 0x7fffffa, 7, 0x77 },
{ 27, 0x7fffffa, 7, 0x75 }, { 27, 0x7fffffa, 7, 0x73 },
{ 27, 0x7fffffa, 7, 0x71 }, { 27, 0x7fffffa, 7, 0x6f },
{ 27, 0x7fffffa, 7, 0x6d }, { 27, 0x7fffffa, 7, 0x6b },
{ 27, 0x7fffffa, 7, 0x69 }, { 27, 0x7fffffa, 7, 0x67 },
{ 27, 0x7fffffa, 7, 0x65 }, { 27, 0x7fffffa, 7, 0x63 },
{ 27, 0x7fffffa, 7, 0x61 }, { 27, 0x7fffffa, 7, 0x5f },
{ 27, 0x7fffffa, 7, 0x5d }, { 27, 0x7fffffa, 7, 0x5b },
{ 27, 0x7fffffa, 7, 0x59 }, { 27, 0x7fffffa, 7, 0x57 },
{ 27, 0x7fffffa, 7, 0x55 }, { 27, 0x7fffffa, 7, 0x53 },
{ 27, 0x7fffffa, 7, 0x51 }, { 27, 0x7fffffa, 7, 0x4f },
{ 27, 0x7fffffa, 7, 0x4d }, { 27, 0x7fffffa, 7, 0x4b },
{ 27, 0x7fffffa, 7, 0x49 }, { 27, 0x7fffffa, 7, 0x47 },
{ 27, 0x7fffffa, 7, 0x45 }, { 27, 0x7fffffa, 7, 0x43 },
{ 27, 0x7fffffa, 7, 0x41 }, { 27, 0x7fffffa, 7, 0x3f },
{ 27, 0x7fffffa, 7, 0x3d }, { 27, 0x7fffffa, 7, 0x3b },
{ 27, 0x7fffffa, 7, 0x39 }, { 27, 0x7fffffa, 7, 0x37 },
{ 27, 0x7fffffa, 7, 0x35 }, { 27, 0x7fffffa, 7, 0x33 },
{ 27, 0x7fffffa, 7, 0x31 }, { 27, 0x7fffffa, 7, 0x2f },
{ 27, 0x7fffffa, 7, 0x2d }, { 27, 0x7fffffa, 7, 0x2b },
{ 27, 0x7fffffa, 7, 0x29 }, { 27, 0x7fffffa, 7, 0x27 },
{ 27, 0x7fffffa, 7, 0x25 }, { 27, 0x7fffffa, 7, 0x23 },
{ 27, 0x7fffffa, 7, 0x21 }, { 27, 0x7fffffa, 7, 0x1f },
{ 27, 0x7fffffa, 7, 0x1d }, { 27, 0x7fffffa, 7, 0x1b },
{ 27, 0x7fffffa, 7, 0x19 }, { 27, 0x7fffffa, 7, 0x17 },
{ 27, 0x7fffffa, 7, 0x15 }, { 27, 0x7fffffa, 7, 0x13 },
{ 27, 0x7fffffa, 7, 0x11 }, { 27, 0x7fffffa, 7, 0xf },
{ 27, 0x7fffffa, 7, 0xd }, { 27, 0x7fffffa, 7, 0xb },
{ 27, 0x7fffffa, 7, 0x9 }, { 27, 0x7fffffa, 7, 0x7 },
{ 27, 0x7fffffa, 7, 0x5 }, { 27, 0x7fffffa, 7, 0x3 },
{ 27, 0x7fffffa, 7, 0x1 }, { 27, 0x7fffffa, 7, 0x1 }
},
/*
* prefixed with 3 zeroes
*/
{
{ 7, 0x71, 0, 0 }, { 10, 0x3ef, 0, 0 },
{ 10, 0x3ed, 0, 0 }, { 17, 0x1ffdf, 0, 0 },
{ 17, 0x1ffdd, 0, 0 }, { 17, 0x1ffdb, 0, 0 },
{ 17, 0x1ffd9, 0, 0 }, { 21, 0x1fffbf, 0, 0 },
{ 21, 0x1fffbd, 0, 0 }, { 21, 0x1fffbb, 0, 0 },
{ 21, 0x1fffb9, 0, 0 }, { 21, 0x1fffb7, 0, 0 },
{ 21, 0x1fffb5, 0, 0 }, { 21, 0x1fffb3, 0, 0 },
{ 21, 0x1fffb1, 0, 0 }, { 26, 0x3ffff1f, 0, 0 },
{ 26, 0x3ffff1d, 0, 0 }, { 26, 0x3ffff1b, 0, 0 },
{ 26, 0x3ffff19, 0, 0 }, { 26, 0x3ffff17, 0, 0 },
{ 26, 0x3ffff15, 0, 0 }, { 26, 0x3ffff13, 0, 0 },
{ 26, 0x3ffff11, 0, 0 }, { 26, 0x3ffff0f, 0, 0 },
{ 26, 0x3ffff0d, 0, 0 }, { 26, 0x3ffff0b, 0, 0 },
{ 26, 0x3ffff09, 0, 0 }, { 26, 0x3ffff07, 0, 0 },
{ 26, 0x3ffff05, 0, 0 }, { 26, 0x3ffff03, 0, 0 },
{ 26, 0x3ffff01, 0, 0 }, { 30, 0x3ffffe7f, 0, 0 },
{ 30, 0x3ffffe7d, 0, 0 }, { 30, 0x3ffffe7b, 0, 0 },
{ 30, 0x3ffffe79, 0, 0 }, { 30, 0x3ffffe77, 0, 0 },
{ 30, 0x3ffffe75, 0, 0 }, { 30, 0x3ffffe73, 0, 0 },
{ 30, 0x3ffffe71, 0, 0 }, { 30, 0x3ffffe6f, 0, 0 },
{ 30, 0x3ffffe6d, 0, 0 }, { 30, 0x3ffffe6b, 0, 0 },
{ 30, 0x3ffffe69, 0, 0 }, { 30, 0x3ffffe67, 0, 0 },
{ 30, 0x3ffffe65, 0, 0 }, { 30, 0x3ffffe63, 0, 0 },
{ 30, 0x3ffffe61, 0, 0 }, { 30, 0x3ffffe5f, 0, 0 },
{ 30, 0x3ffffe5d, 0, 0 }, { 30, 0x3ffffe5b, 0, 0 },
{ 30, 0x3ffffe59, 0, 0 }, { 30, 0x3ffffe57, 0, 0 },
{ 30, 0x3ffffe55, 0, 0 }, { 30, 0x3ffffe53, 0, 0 },
{ 30, 0x3ffffe51, 0, 0 }, { 30, 0x3ffffe4f, 0, 0 },
{ 30, 0x3ffffe4d, 0, 0 }, { 30, 0x3ffffe4b, 0, 0 },
{ 30, 0x3ffffe49, 0, 0 }, { 30, 0x3ffffe47, 0, 0 },
{ 30, 0x3ffffe45, 0, 0 }, { 30, 0x3ffffe43, 0, 0 },
{ 30, 0x3ffffe41, 0, 0 }, { 27, 0x7fffffb, 7, 0x7f },
{ 27, 0x7fffffb, 7, 0x7d }, { 27, 0x7fffffb, 7, 0x7b },
{ 27, 0x7fffffb, 7, 0x79 }, { 27, 0x7fffffb, 7, 0x77 },
{ 27, 0x7fffffb, 7, 0x75 }, { 27, 0x7fffffb, 7, 0x73 },
{ 27, 0x7fffffb, 7, 0x71 }, { 27, 0x7fffffb, 7, 0x6f },
{ 27, 0x7fffffb, 7, 0x6d }, { 27, 0x7fffffb, 7, 0x6b },
{ 27, 0x7fffffb, 7, 0x69 }, { 27, 0x7fffffb, 7, 0x67 },
{ 27, 0x7fffffb, 7, 0x65 }, { 27, 0x7fffffb, 7, 0x63 },
{ 27, 0x7fffffb, 7, 0x61 }, { 27, 0x7fffffb, 7, 0x5f },
{ 27, 0x7fffffb, 7, 0x5d }, { 27, 0x7fffffb, 7, 0x5b },
{ 27, 0x7fffffb, 7, 0x59 }, { 27, 0x7fffffb, 7, 0x57 },
{ 27, 0x7fffffb, 7, 0x55 }, { 27, 0x7fffffb, 7, 0x53 },
{ 27, 0x7fffffb, 7, 0x51 }, { 27, 0x7fffffb, 7, 0x4f },
{ 27, 0x7fffffb, 7, 0x4d }, { 27, 0x7fffffb, 7, 0x4b },
{ 27, 0x7fffffb, 7, 0x49 }, { 27, 0x7fffffb, 7, 0x47 },
{ 27, 0x7fffffb, 7, 0x45 }, { 27, 0x7fffffb, 7, 0x43 },
{ 27, 0x7fffffb, 7, 0x41 }, { 27, 0x7fffffb, 7, 0x3f },
{ 27, 0x7fffffb, 7, 0x3d }, { 27, 0x7fffffb, 7, 0x3b },
{ 27, 0x7fffffb, 7, 0x39 }, { 27, 0x7fffffb, 7, 0x37 },
{ 27, 0x7fffffb, 7, 0x35 }, { 27, 0x7fffffb, 7, 0x33 },
{ 27, 0x7fffffb, 7, 0x31 }, { 27, 0x7fffffb, 7, 0x2f },
{ 27, 0x7fffffb, 7, 0x2d }, { 27, 0x7fffffb, 7, 0x2b },
{ 27, 0x7fffffb, 7, 0x29 }, { 27, 0x7fffffb, 7, 0x27 },
{ 27, 0x7fffffb, 7, 0x25 }, { 27, 0x7fffffb, 7, 0x23 },
{ 27, 0x7fffffb, 7, 0x21 }, { 27, 0x7fffffb, 7, 0x1f },
{ 27, 0x7fffffb, 7, 0x1d }, { 27, 0x7fffffb, 7, 0x1b },
{ 27, 0x7fffffb, 7, 0x19 }, { 27, 0x7fffffb, 7, 0x17 },
{ 27, 0x7fffffb, 7, 0x15 }, { 27, 0x7fffffb, 7, 0x13 },
{ 27, 0x7fffffb, 7, 0x11 }, { 27, 0x7fffffb, 7, 0xf },
{ 27, 0x7fffffb, 7, 0xd }, { 27, 0x7fffffb, 7, 0xb },
{ 27, 0x7fffffb, 7, 0x9 }, { 27, 0x7fffffb, 7, 0x7 },
{ 27, 0x7fffffb, 7, 0x5 }, { 27, 0x7fffffb, 7, 0x3 },
{ 27, 0x7fffffb, 7, 0x1 }, { 27, 0x7fffffb, 7, 0x1 }
},
/*
* prefixed with 4 zeroes
*/
{
{ 8, 0xf1, 0, 0 }, { 11, 0x7e3, 0, 0 },
{ 11, 0x7e1, 0, 0 }, { 18, 0x3ffc7, 0, 0 },
{ 18, 0x3ffc5, 0, 0 }, { 18, 0x3ffc3, 0, 0 },
{ 18, 0x3ffc1, 0, 0 }, { 22, 0x3fff8f, 0, 0 },
{ 22, 0x3fff8d, 0, 0 }, { 22, 0x3fff8b, 0, 0 },
{ 22, 0x3fff89, 0, 0 }, { 22, 0x3fff87, 0, 0 },
{ 22, 0x3fff85, 0, 0 }, { 22, 0x3fff83, 0, 0 },
{ 22, 0x3fff81, 0, 0 }, { 26, 0x3ffff3f, 0, 0 },
{ 26, 0x3ffff3d, 0, 0 }, { 26, 0x3ffff3b, 0, 0 },
{ 26, 0x3ffff39, 0, 0 }, { 26, 0x3ffff37, 0, 0 },
{ 26, 0x3ffff35, 0, 0 }, { 26, 0x3ffff33, 0, 0 },
{ 26, 0x3ffff31, 0, 0 }, { 26, 0x3ffff2f, 0, 0 },
{ 26, 0x3ffff2d, 0, 0 }, { 26, 0x3ffff2b, 0, 0 },
{ 26, 0x3ffff29, 0, 0 }, { 26, 0x3ffff27, 0, 0 },
{ 26, 0x3ffff25, 0, 0 }, { 26, 0x3ffff23, 0, 0 },
{ 26, 0x3ffff21, 0, 0 }, { 30, 0x3ffffebf, 0, 0 },
{ 30, 0x3ffffebd, 0, 0 }, { 30, 0x3ffffebb, 0, 0 },
{ 30, 0x3ffffeb9, 0, 0 }, { 30, 0x3ffffeb7, 0, 0 },
{ 30, 0x3ffffeb5, 0, 0 }, { 30, 0x3ffffeb3, 0, 0 },
{ 30, 0x3ffffeb1, 0, 0 }, { 30, 0x3ffffeaf, 0, 0 },
{ 30, 0x3ffffead, 0, 0 }, { 30, 0x3ffffeab, 0, 0 },
{ 30, 0x3ffffea9, 0, 0 }, { 30, 0x3ffffea7, 0, 0 },
{ 30, 0x3ffffea5, 0, 0 }, { 30, 0x3ffffea3, 0, 0 },
{ 30, 0x3ffffea1, 0, 0 }, { 30, 0x3ffffe9f, 0, 0 },
{ 30, 0x3ffffe9d, 0, 0 }, { 30, 0x3ffffe9b, 0, 0 },
{ 30, 0x3ffffe99, 0, 0 }, { 30, 0x3ffffe97, 0, 0 },
{ 30, 0x3ffffe95, 0, 0 }, { 30, 0x3ffffe93, 0, 0 },
{ 30, 0x3ffffe91, 0, 0 }, { 30, 0x3ffffe8f, 0, 0 },
{ 30, 0x3ffffe8d, 0, 0 }, { 30, 0x3ffffe8b, 0, 0 },
{ 30, 0x3ffffe89, 0, 0 }, { 30, 0x3ffffe87, 0, 0 },
{ 30, 0x3ffffe85, 0, 0 }, { 30, 0x3ffffe83, 0, 0 },
{ 30, 0x3ffffe81, 0, 0 }, { 28, 0xffffff8, 7, 0x7f },
{ 28, 0xffffff8, 7, 0x7d }, { 28, 0xffffff8, 7, 0x7b },
{ 28, 0xffffff8, 7, 0x79 }, { 28, 0xffffff8, 7, 0x77 },
{ 28, 0xffffff8, 7, 0x75 }, { 28, 0xffffff8, 7, 0x73 },
{ 28, 0xffffff8, 7, 0x71 }, { 28, 0xffffff8, 7, 0x6f },
{ 28, 0xffffff8, 7, 0x6d }, { 28, 0xffffff8, 7, 0x6b },
{ 28, 0xffffff8, 7, 0x69 }, { 28, 0xffffff8, 7, 0x67 },
{ 28, 0xffffff8, 7, 0x65 }, { 28, 0xffffff8, 7, 0x63 },
{ 28, 0xffffff8, 7, 0x61 }, { 28, 0xffffff8, 7, 0x5f },
{ 28, 0xffffff8, 7, 0x5d }, { 28, 0xffffff8, 7, 0x5b },
{ 28, 0xffffff8, 7, 0x59 }, { 28, 0xffffff8, 7, 0x57 },
{ 28, 0xffffff8, 7, 0x55 }, { 28, 0xffffff8, 7, 0x53 },
{ 28, 0xffffff8, 7, 0x51 }, { 28, 0xffffff8, 7, 0x4f },
{ 28, 0xffffff8, 7, 0x4d }, { 28, 0xffffff8, 7, 0x4b },
{ 28, 0xffffff8, 7, 0x49 }, { 28, 0xffffff8, 7, 0x47 },
{ 28, 0xffffff8, 7, 0x45 }, { 28, 0xffffff8, 7, 0x43 },
{ 28, 0xffffff8, 7, 0x41 }, { 28, 0xffffff8, 7, 0x3f },
{ 28, 0xffffff8, 7, 0x3d }, { 28, 0xffffff8, 7, 0x3b },
{ 28, 0xffffff8, 7, 0x39 }, { 28, 0xffffff8, 7, 0x37 },
{ 28, 0xffffff8, 7, 0x35 }, { 28, 0xffffff8, 7, 0x33 },
{ 28, 0xffffff8, 7, 0x31 }, { 28, 0xffffff8, 7, 0x2f },
{ 28, 0xffffff8, 7, 0x2d }, { 28, 0xffffff8, 7, 0x2b },
{ 28, 0xffffff8, 7, 0x29 }, { 28, 0xffffff8, 7, 0x27 },
{ 28, 0xffffff8, 7, 0x25 }, { 28, 0xffffff8, 7, 0x23 },
{ 28, 0xffffff8, 7, 0x21 }, { 28, 0xffffff8, 7, 0x1f },
{ 28, 0xffffff8, 7, 0x1d }, { 28, 0xffffff8, 7, 0x1b },
{ 28, 0xffffff8, 7, 0x19 }, { 28, 0xffffff8, 7, 0x17 },
{ 28, 0xffffff8, 7, 0x15 }, { 28, 0xffffff8, 7, 0x13 },
{ 28, 0xffffff8, 7, 0x11 }, { 28, 0xffffff8, 7, 0xf },
{ 28, 0xffffff8, 7, 0xd }, { 28, 0xffffff8, 7, 0xb },
{ 28, 0xffffff8, 7, 0x9 }, { 28, 0xffffff8, 7, 0x7 },
{ 28, 0xffffff8, 7, 0x5 }, { 28, 0xffffff8, 7, 0x3 },
{ 28, 0xffffff8, 7, 0x1 }, { 0, 0, 0, 0 }
},
/*
* prefixed with 5 zeroes
*/
{
{ 8, 0xf3, 0, 0 }, { 11, 0x7e7, 0, 0 },
{ 11, 0x7e5, 0, 0 }, { 18, 0x3ffcf, 0, 0 },
{ 18, 0x3ffcd, 0, 0 }, { 18, 0x3ffcb, 0, 0 },
{ 18, 0x3ffc9, 0, 0 }, { 22, 0x3fff9f, 0, 0 },
{ 22, 0x3fff9d, 0, 0 }, { 22, 0x3fff9b, 0, 0 },
{ 22, 0x3fff99, 0, 0 }, { 22, 0x3fff97, 0, 0 },
{ 22, 0x3fff95, 0, 0 }, { 22, 0x3fff93, 0, 0 },
{ 22, 0x3fff91, 0, 0 }, { 26, 0x3ffff5f, 0, 0 },
{ 26, 0x3ffff5d, 0, 0 }, { 26, 0x3ffff5b, 0, 0 },
{ 26, 0x3ffff59, 0, 0 }, { 26, 0x3ffff57, 0, 0 },
{ 26, 0x3ffff55, 0, 0 }, { 26, 0x3ffff53, 0, 0 },
{ 26, 0x3ffff51, 0, 0 }, { 26, 0x3ffff4f, 0, 0 },
{ 26, 0x3ffff4d, 0, 0 }, { 26, 0x3ffff4b, 0, 0 },
{ 26, 0x3ffff49, 0, 0 }, { 26, 0x3ffff47, 0, 0 },
{ 26, 0x3ffff45, 0, 0 }, { 26, 0x3ffff43, 0, 0 },
{ 26, 0x3ffff41, 0, 0 }, { 30, 0x3ffffeff, 0, 0 },
{ 30, 0x3ffffefd, 0, 0 }, { 30, 0x3ffffefb, 0, 0 },
{ 30, 0x3ffffef9, 0, 0 }, { 30, 0x3ffffef7, 0, 0 },
{ 30, 0x3ffffef5, 0, 0 }, { 30, 0x3ffffef3, 0, 0 },
{ 30, 0x3ffffef1, 0, 0 }, { 30, 0x3ffffeef, 0, 0 },
{ 30, 0x3ffffeed, 0, 0 }, { 30, 0x3ffffeeb, 0, 0 },
{ 30, 0x3ffffee9, 0, 0 }, { 30, 0x3ffffee7, 0, 0 },
{ 30, 0x3ffffee5, 0, 0 }, { 30, 0x3ffffee3, 0, 0 },
{ 30, 0x3ffffee1, 0, 0 }, { 30, 0x3ffffedf, 0, 0 },
{ 30, 0x3ffffedd, 0, 0 }, { 30, 0x3ffffedb, 0, 0 },
{ 30, 0x3ffffed9, 0, 0 }, { 30, 0x3ffffed7, 0, 0 },
{ 30, 0x3ffffed5, 0, 0 }, { 30, 0x3ffffed3, 0, 0 },
{ 30, 0x3ffffed1, 0, 0 }, { 30, 0x3ffffecf, 0, 0 },
{ 30, 0x3ffffecd, 0, 0 }, { 30, 0x3ffffecb, 0, 0 },
{ 30, 0x3ffffec9, 0, 0 }, { 30, 0x3ffffec7, 0, 0 },
{ 30, 0x3ffffec5, 0, 0 }, { 30, 0x3ffffec3, 0, 0 },
{ 30, 0x3ffffec1, 0, 0 }, { 28, 0xffffff9, 7, 0x7f },
{ 28, 0xffffff9, 7, 0x7d }, { 28, 0xffffff9, 7, 0x7b },
{ 28, 0xffffff9, 7, 0x79 }, { 28, 0xffffff9, 7, 0x77 },
{ 28, 0xffffff9, 7, 0x75 }, { 28, 0xffffff9, 7, 0x73 },
{ 28, 0xffffff9, 7, 0x71 }, { 28, 0xffffff9, 7, 0x6f },
{ 28, 0xffffff9, 7, 0x6d }, { 28, 0xffffff9, 7, 0x6b },
{ 28, 0xffffff9, 7, 0x69 }, { 28, 0xffffff9, 7, 0x67 },
{ 28, 0xffffff9, 7, 0x65 }, { 28, 0xffffff9, 7, 0x63 },
{ 28, 0xffffff9, 7, 0x61 }, { 28, 0xffffff9, 7, 0x5f },
{ 28, 0xffffff9, 7, 0x5d }, { 28, 0xffffff9, 7, 0x5b },
{ 28, 0xffffff9, 7, 0x59 }, { 28, 0xffffff9, 7, 0x57 },
{ 28, 0xffffff9, 7, 0x55 }, { 28, 0xffffff9, 7, 0x53 },
{ 28, 0xffffff9, 7, 0x51 }, { 28, 0xffffff9, 7, 0x4f },
{ 28, 0xffffff9, 7, 0x4d }, { 28, 0xffffff9, 7, 0x4b },
{ 28, 0xffffff9, 7, 0x49 }, { 28, 0xffffff9, 7, 0x47 },
{ 28, 0xffffff9, 7, 0x45 }, { 28, 0xffffff9, 7, 0x43 },
{ 28, 0xffffff9, 7, 0x41 }, { 28, 0xffffff9, 7, 0x3f },
{ 28, 0xffffff9, 7, 0x3d }, { 28, 0xffffff9, 7, 0x3b },
{ 28, 0xffffff9, 7, 0x39 }, { 28, 0xffffff9, 7, 0x37 },
{ 28, 0xffffff9, 7, 0x35 }, { 28, 0xffffff9, 7, 0x33 },
{ 28, 0xffffff9, 7, 0x31 }, { 28, 0xffffff9, 7, 0x2f },
{ 28, 0xffffff9, 7, 0x2d }, { 28, 0xffffff9, 7, 0x2b },
{ 28, 0xffffff9, 7, 0x29 }, { 28, 0xffffff9, 7, 0x27 },
{ 28, 0xffffff9, 7, 0x25 }, { 28, 0xffffff9, 7, 0x23 },
{ 28, 0xffffff9, 7, 0x21 }, { 28, 0xffffff9, 7, 0x1f },
{ 28, 0xffffff9, 7, 0x1d }, { 28, 0xffffff9, 7, 0x1b },
{ 28, 0xffffff9, 7, 0x19 }, { 28, 0xffffff9, 7, 0x17 },
{ 28, 0xffffff9, 7, 0x15 }, { 28, 0xffffff9, 7, 0x13 },
{ 28, 0xffffff9, 7, 0x11 }, { 28, 0xffffff9, 7, 0xf },
{ 28, 0xffffff9, 7, 0xd }, { 28, 0xffffff9, 7, 0xb },
{ 28, 0xffffff9, 7, 0x9 }, { 28, 0xffffff9, 7, 0x7 },
{ 28, 0xffffff9, 7, 0x5 }, { 28, 0xffffff9, 7, 0x3 },
{ 28, 0xffffff9, 7, 0x1 }, { 0, 0, 0, 0 }
},
/*
* prefixed with 6 zeroes
*/
{
{ 8, 0xf5, 0, 0 }, { 14, 0x3feb, 0, 0 },
{ 14, 0x3fe9, 0, 0 }, { 18, 0x3ffd7, 0, 0 },
{ 18, 0x3ffd5, 0, 0 }, { 18, 0x3ffd3, 0, 0 },
{ 18, 0x3ffd1, 0, 0 }, { 22, 0x3fffaf, 0, 0 },
{ 22, 0x3fffad, 0, 0 }, { 22, 0x3fffab, 0, 0 },
{ 22, 0x3fffa9, 0, 0 }, { 22, 0x3fffa7, 0, 0 },
{ 22, 0x3fffa5, 0, 0 }, { 22, 0x3fffa3, 0, 0 },
{ 22, 0x3fffa1, 0, 0 }, { 26, 0x3ffff7f, 0, 0 },
{ 26, 0x3ffff7d, 0, 0 }, { 26, 0x3ffff7b, 0, 0 },
{ 26, 0x3ffff79, 0, 0 }, { 26, 0x3ffff77, 0, 0 },
{ 26, 0x3ffff75, 0, 0 }, { 26, 0x3ffff73, 0, 0 },
{ 26, 0x3ffff71, 0, 0 }, { 26, 0x3ffff6f, 0, 0 },
{ 26, 0x3ffff6d, 0, 0 }, { 26, 0x3ffff6b, 0, 0 },
{ 26, 0x3ffff69, 0, 0 }, { 26, 0x3ffff67, 0, 0 },
{ 26, 0x3ffff65, 0, 0 }, { 26, 0x3ffff63, 0, 0 },
{ 26, 0x3ffff61, 0, 0 }, { 31, 0x7ffffe3f, 0, 0 },
{ 31, 0x7ffffe3d, 0, 0 }, { 31, 0x7ffffe3b, 0, 0 },
{ 31, 0x7ffffe39, 0, 0 }, { 31, 0x7ffffe37, 0, 0 },
{ 31, 0x7ffffe35, 0, 0 }, { 31, 0x7ffffe33, 0, 0 },
{ 31, 0x7ffffe31, 0, 0 }, { 31, 0x7ffffe2f, 0, 0 },
{ 31, 0x7ffffe2d, 0, 0 }, { 31, 0x7ffffe2b, 0, 0 },
{ 31, 0x7ffffe29, 0, 0 }, { 31, 0x7ffffe27, 0, 0 },
{ 31, 0x7ffffe25, 0, 0 }, { 31, 0x7ffffe23, 0, 0 },
{ 31, 0x7ffffe21, 0, 0 }, { 31, 0x7ffffe1f, 0, 0 },
{ 31, 0x7ffffe1d, 0, 0 }, { 31, 0x7ffffe1b, 0, 0 },
{ 31, 0x7ffffe19, 0, 0 }, { 31, 0x7ffffe17, 0, 0 },
{ 31, 0x7ffffe15, 0, 0 }, { 31, 0x7ffffe13, 0, 0 },
{ 31, 0x7ffffe11, 0, 0 }, { 31, 0x7ffffe0f, 0, 0 },
{ 31, 0x7ffffe0d, 0, 0 }, { 31, 0x7ffffe0b, 0, 0 },
{ 31, 0x7ffffe09, 0, 0 }, { 31, 0x7ffffe07, 0, 0 },
{ 31, 0x7ffffe05, 0, 0 }, { 31, 0x7ffffe03, 0, 0 },
{ 31, 0x7ffffe01, 0, 0 }, { 28, 0xffffffa, 7, 0x7f },
{ 28, 0xffffffa, 7, 0x7d }, { 28, 0xffffffa, 7, 0x7b },
{ 28, 0xffffffa, 7, 0x79 }, { 28, 0xffffffa, 7, 0x77 },
{ 28, 0xffffffa, 7, 0x75 }, { 28, 0xffffffa, 7, 0x73 },
{ 28, 0xffffffa, 7, 0x71 }, { 28, 0xffffffa, 7, 0x6f },
{ 28, 0xffffffa, 7, 0x6d }, { 28, 0xffffffa, 7, 0x6b },
{ 28, 0xffffffa, 7, 0x69 }, { 28, 0xffffffa, 7, 0x67 },
{ 28, 0xffffffa, 7, 0x65 }, { 28, 0xffffffa, 7, 0x63 },
{ 28, 0xffffffa, 7, 0x61 }, { 28, 0xffffffa, 7, 0x5f },
{ 28, 0xffffffa, 7, 0x5d }, { 28, 0xffffffa, 7, 0x5b },
{ 28, 0xffffffa, 7, 0x59 }, { 28, 0xffffffa, 7, 0x57 },
{ 28, 0xffffffa, 7, 0x55 }, { 28, 0xffffffa, 7, 0x53 },
{ 28, 0xffffffa, 7, 0x51 }, { 28, 0xffffffa, 7, 0x4f },
{ 28, 0xffffffa, 7, 0x4d }, { 28, 0xffffffa, 7, 0x4b },
{ 28, 0xffffffa, 7, 0x49 }, { 28, 0xffffffa, 7, 0x47 },
{ 28, 0xffffffa, 7, 0x45 }, { 28, 0xffffffa, 7, 0x43 },
{ 28, 0xffffffa, 7, 0x41 }, { 28, 0xffffffa, 7, 0x3f },
{ 28, 0xffffffa, 7, 0x3d }, { 28, 0xffffffa, 7, 0x3b },
{ 28, 0xffffffa, 7, 0x39 }, { 28, 0xffffffa, 7, 0x37 },
{ 28, 0xffffffa, 7, 0x35 }, { 28, 0xffffffa, 7, 0x33 },
{ 28, 0xffffffa, 7, 0x31 }, { 28, 0xffffffa, 7, 0x2f },
{ 28, 0xffffffa, 7, 0x2d }, { 28, 0xffffffa, 7, 0x2b },
{ 28, 0xffffffa, 7, 0x29 }, { 28, 0xffffffa, 7, 0x27 },
{ 28, 0xffffffa, 7, 0x25 }, { 28, 0xffffffa, 7, 0x23 },
{ 28, 0xffffffa, 7, 0x21 }, { 28, 0xffffffa, 7, 0x1f },
{ 28, 0xffffffa, 7, 0x1d }, { 28, 0xffffffa, 7, 0x1b },
{ 28, 0xffffffa, 7, 0x19 }, { 28, 0xffffffa, 7, 0x17 },
{ 28, 0xffffffa, 7, 0x15 }, { 28, 0xffffffa, 7, 0x13 },
{ 28, 0xffffffa, 7, 0x11 }, { 28, 0xffffffa, 7, 0xf },
{ 28, 0xffffffa, 7, 0xd }, { 28, 0xffffffa, 7, 0xb },
{ 28, 0xffffffa, 7, 0x9 }, { 28, 0xffffffa, 7, 0x7 },
{ 28, 0xffffffa, 7, 0x5 }, { 28, 0xffffffa, 7, 0x3 },
{ 28, 0xffffffa, 7, 0x1 }, { 0, 0, 0, 0 }
},
/*
* prefixed with 7 zeroes
*/
{
{ 9, 0x1f3, 0, 0 }, { 14, 0x3fef, 0, 0 },
{ 14, 0x3fed, 0, 0 }, { 18, 0x3ffdf, 0, 0 },
{ 18, 0x3ffdd, 0, 0 }, { 18, 0x3ffdb, 0, 0 },
{ 18, 0x3ffd9, 0, 0 }, { 22, 0x3fffbf, 0, 0 },
{ 22, 0x3fffbd, 0, 0 }, { 22, 0x3fffbb, 0, 0 },
{ 22, 0x3fffb9, 0, 0 }, { 22, 0x3fffb7, 0, 0 },
{ 22, 0x3fffb5, 0, 0 }, { 22, 0x3fffb3, 0, 0 },
{ 22, 0x3fffb1, 0, 0 }, { 27, 0x7ffff1f, 0, 0 },
{ 27, 0x7ffff1d, 0, 0 }, { 27, 0x7ffff1b, 0, 0 },
{ 27, 0x7ffff19, 0, 0 }, { 27, 0x7ffff17, 0, 0 },
{ 27, 0x7ffff15, 0, 0 }, { 27, 0x7ffff13, 0, 0 },
{ 27, 0x7ffff11, 0, 0 }, { 27, 0x7ffff0f, 0, 0 },
{ 27, 0x7ffff0d, 0, 0 }, { 27, 0x7ffff0b, 0, 0 },
{ 27, 0x7ffff09, 0, 0 }, { 27, 0x7ffff07, 0, 0 },
{ 27, 0x7ffff05, 0, 0 }, { 27, 0x7ffff03, 0, 0 },
{ 27, 0x7ffff01, 0, 0 }, { 31, 0x7ffffe7f, 0, 0 },
{ 31, 0x7ffffe7d, 0, 0 }, { 31, 0x7ffffe7b, 0, 0 },
{ 31, 0x7ffffe79, 0, 0 }, { 31, 0x7ffffe77, 0, 0 },
{ 31, 0x7ffffe75, 0, 0 }, { 31, 0x7ffffe73, 0, 0 },
{ 31, 0x7ffffe71, 0, 0 }, { 31, 0x7ffffe6f, 0, 0 },
{ 31, 0x7ffffe6d, 0, 0 }, { 31, 0x7ffffe6b, 0, 0 },
{ 31, 0x7ffffe69, 0, 0 }, { 31, 0x7ffffe67, 0, 0 },
{ 31, 0x7ffffe65, 0, 0 }, { 31, 0x7ffffe63, 0, 0 },
{ 31, 0x7ffffe61, 0, 0 }, { 31, 0x7ffffe5f, 0, 0 },
{ 31, 0x7ffffe5d, 0, 0 }, { 31, 0x7ffffe5b, 0, 0 },
{ 31, 0x7ffffe59, 0, 0 }, { 31, 0x7ffffe57, 0, 0 },
{ 31, 0x7ffffe55, 0, 0 }, { 31, 0x7ffffe53, 0, 0 },
{ 31, 0x7ffffe51, 0, 0 }, { 31, 0x7ffffe4f, 0, 0 },
{ 31, 0x7ffffe4d, 0, 0 }, { 31, 0x7ffffe4b, 0, 0 },
{ 31, 0x7ffffe49, 0, 0 }, { 31, 0x7ffffe47, 0, 0 },
{ 31, 0x7ffffe45, 0, 0 }, { 31, 0x7ffffe43, 0, 0 },
{ 31, 0x7ffffe41, 0, 0 }, { 28, 0xffffffb, 7, 0x7f },
{ 28, 0xffffffb, 7, 0x7d }, { 28, 0xffffffb, 7, 0x7b },
{ 28, 0xffffffb, 7, 0x79 }, { 28, 0xffffffb, 7, 0x77 },
{ 28, 0xffffffb, 7, 0x75 }, { 28, 0xffffffb, 7, 0x73 },
{ 28, 0xffffffb, 7, 0x71 }, { 28, 0xffffffb, 7, 0x6f },
{ 28, 0xffffffb, 7, 0x6d }, { 28, 0xffffffb, 7, 0x6b },
{ 28, 0xffffffb, 7, 0x69 }, { 28, 0xffffffb, 7, 0x67 },
{ 28, 0xffffffb, 7, 0x65 }, { 28, 0xffffffb, 7, 0x63 },
{ 28, 0xffffffb, 7, 0x61 }, { 28, 0xffffffb, 7, 0x5f },
{ 28, 0xffffffb, 7, 0x5d }, { 28, 0xffffffb, 7, 0x5b },
{ 28, 0xffffffb, 7, 0x59 }, { 28, 0xffffffb, 7, 0x57 },
{ 28, 0xffffffb, 7, 0x55 }, { 28, 0xffffffb, 7, 0x53 },
{ 28, 0xffffffb, 7, 0x51 }, { 28, 0xffffffb, 7, 0x4f },
{ 28, 0xffffffb, 7, 0x4d }, { 28, 0xffffffb, 7, 0x4b },
{ 28, 0xffffffb, 7, 0x49 }, { 28, 0xffffffb, 7, 0x47 },
{ 28, 0xffffffb, 7, 0x45 }, { 28, 0xffffffb, 7, 0x43 },
{ 28, 0xffffffb, 7, 0x41 }, { 28, 0xffffffb, 7, 0x3f },
{ 28, 0xffffffb, 7, 0x3d }, { 28, 0xffffffb, 7, 0x3b },
{ 28, 0xffffffb, 7, 0x39 }, { 28, 0xffffffb, 7, 0x37 },
{ 28, 0xffffffb, 7, 0x35 }, { 28, 0xffffffb, 7, 0x33 },
{ 28, 0xffffffb, 7, 0x31 }, { 28, 0xffffffb, 7, 0x2f },
{ 28, 0xffffffb, 7, 0x2d }, { 28, 0xffffffb, 7, 0x2b },
{ 28, 0xffffffb, 7, 0x29 }, { 28, 0xffffffb, 7, 0x27 },
{ 28, 0xffffffb, 7, 0x25 }, { 28, 0xffffffb, 7, 0x23 },
{ 28, 0xffffffb, 7, 0x21 }, { 28, 0xffffffb, 7, 0x1f },
{ 28, 0xffffffb, 7, 0x1d }, { 28, 0xffffffb, 7, 0x1b },
{ 28, 0xffffffb, 7, 0x19 }, { 28, 0xffffffb, 7, 0x17 },
{ 28, 0xffffffb, 7, 0x15 }, { 28, 0xffffffb, 7, 0x13 },
{ 28, 0xffffffb, 7, 0x11 }, { 28, 0xffffffb, 7, 0xf },
{ 28, 0xffffffb, 7, 0xd }, { 28, 0xffffffb, 7, 0xb },
{ 28, 0xffffffb, 7, 0x9 }, { 28, 0xffffffb, 7, 0x7 },
{ 28, 0xffffffb, 7, 0x5 }, { 28, 0xffffffb, 7, 0x3 },
{ 28, 0xffffffb, 7, 0x1 }, { 0, 0, 0, 0 }
},
/*
* prefixed with 8 zeroes
*/
{
{ 9, 0x1f5, 0, 0 }, { 15, 0x7fe3, 0, 0 },
{ 15, 0x7fe1, 0, 0 }, { 19, 0x7ffc7, 0, 0 },
{ 19, 0x7ffc5, 0, 0 }, { 19, 0x7ffc3, 0, 0 },
{ 19, 0x7ffc1, 0, 0 }, { 23, 0x7fff8f, 0, 0 },
{ 23, 0x7fff8d, 0, 0 }, { 23, 0x7fff8b, 0, 0 },
{ 23, 0x7fff89, 0, 0 }, { 23, 0x7fff87, 0, 0 },
{ 23, 0x7fff85, 0, 0 }, { 23, 0x7fff83, 0, 0 },
{ 23, 0x7fff81, 0, 0 }, { 27, 0x7ffff3f, 0, 0 },
{ 27, 0x7ffff3d, 0, 0 }, { 27, 0x7ffff3b, 0, 0 },
{ 27, 0x7ffff39, 0, 0 }, { 27, 0x7ffff37, 0, 0 },
{ 27, 0x7ffff35, 0, 0 }, { 27, 0x7ffff33, 0, 0 },
{ 27, 0x7ffff31, 0, 0 }, { 27, 0x7ffff2f, 0, 0 },
{ 27, 0x7ffff2d, 0, 0 }, { 27, 0x7ffff2b, 0, 0 },
{ 27, 0x7ffff29, 0, 0 }, { 27, 0x7ffff27, 0, 0 },
{ 27, 0x7ffff25, 0, 0 }, { 27, 0x7ffff23, 0, 0 },
{ 27, 0x7ffff21, 0, 0 }, { 31, 0x7ffffebf, 0, 0 },
{ 31, 0x7ffffebd, 0, 0 }, { 31, 0x7ffffebb, 0, 0 },
{ 31, 0x7ffffeb9, 0, 0 }, { 31, 0x7ffffeb7, 0, 0 },
{ 31, 0x7ffffeb5, 0, 0 }, { 31, 0x7ffffeb3, 0, 0 },
{ 31, 0x7ffffeb1, 0, 0 }, { 31, 0x7ffffeaf, 0, 0 },
{ 31, 0x7ffffead, 0, 0 }, { 31, 0x7ffffeab, 0, 0 },
{ 31, 0x7ffffea9, 0, 0 }, { 31, 0x7ffffea7, 0, 0 },
{ 31, 0x7ffffea5, 0, 0 }, { 31, 0x7ffffea3, 0, 0 },
{ 31, 0x7ffffea1, 0, 0 }, { 31, 0x7ffffe9f, 0, 0 },
{ 31, 0x7ffffe9d, 0, 0 }, { 31, 0x7ffffe9b, 0, 0 },
{ 31, 0x7ffffe99, 0, 0 }, { 31, 0x7ffffe97, 0, 0 },
{ 31, 0x7ffffe95, 0, 0 }, { 31, 0x7ffffe93, 0, 0 },
{ 31, 0x7ffffe91, 0, 0 }, { 31, 0x7ffffe8f, 0, 0 },
{ 31, 0x7ffffe8d, 0, 0 }, { 31, 0x7ffffe8b, 0, 0 },
{ 31, 0x7ffffe89, 0, 0 }, { 31, 0x7ffffe87, 0, 0 },
{ 31, 0x7ffffe85, 0, 0 }, { 31, 0x7ffffe83, 0, 0 },
{ 31, 0x7ffffe81, 0, 0 }, { 29, 0x1ffffff8, 7, 0x7f },
{ 29, 0x1ffffff8, 7, 0x7d }, { 29, 0x1ffffff8, 7, 0x7b },
{ 29, 0x1ffffff8, 7, 0x79 }, { 29, 0x1ffffff8, 7, 0x77 },
{ 29, 0x1ffffff8, 7, 0x75 }, { 29, 0x1ffffff8, 7, 0x73 },
{ 29, 0x1ffffff8, 7, 0x71 }, { 29, 0x1ffffff8, 7, 0x6f },
{ 29, 0x1ffffff8, 7, 0x6d }, { 29, 0x1ffffff8, 7, 0x6b },
{ 29, 0x1ffffff8, 7, 0x69 }, { 29, 0x1ffffff8, 7, 0x67 },
{ 29, 0x1ffffff8, 7, 0x65 }, { 29, 0x1ffffff8, 7, 0x63 },
{ 29, 0x1ffffff8, 7, 0x61 }, { 29, 0x1ffffff8, 7, 0x5f },
{ 29, 0x1ffffff8, 7, 0x5d }, { 29, 0x1ffffff8, 7, 0x5b },
{ 29, 0x1ffffff8, 7, 0x59 }, { 29, 0x1ffffff8, 7, 0x57 },
{ 29, 0x1ffffff8, 7, 0x55 }, { 29, 0x1ffffff8, 7, 0x53 },
{ 29, 0x1ffffff8, 7, 0x51 }, { 29, 0x1ffffff8, 7, 0x4f },
{ 29, 0x1ffffff8, 7, 0x4d }, { 29, 0x1ffffff8, 7, 0x4b },
{ 29, 0x1ffffff8, 7, 0x49 }, { 29, 0x1ffffff8, 7, 0x47 },
{ 29, 0x1ffffff8, 7, 0x45 }, { 29, 0x1ffffff8, 7, 0x43 },
{ 29, 0x1ffffff8, 7, 0x41 }, { 29, 0x1ffffff8, 7, 0x3f },
{ 29, 0x1ffffff8, 7, 0x3d }, { 29, 0x1ffffff8, 7, 0x3b },
{ 29, 0x1ffffff8, 7, 0x39 }, { 29, 0x1ffffff8, 7, 0x37 },
{ 29, 0x1ffffff8, 7, 0x35 }, { 29, 0x1ffffff8, 7, 0x33 },
{ 29, 0x1ffffff8, 7, 0x31 }, { 29, 0x1ffffff8, 7, 0x2f },
{ 29, 0x1ffffff8, 7, 0x2d }, { 29, 0x1ffffff8, 7, 0x2b },
{ 29, 0x1ffffff8, 7, 0x29 }, { 29, 0x1ffffff8, 7, 0x27 },
{ 29, 0x1ffffff8, 7, 0x25 }, { 29, 0x1ffffff8, 7, 0x23 },
{ 29, 0x1ffffff8, 7, 0x21 }, { 29, 0x1ffffff8, 7, 0x1f },
{ 29, 0x1ffffff8, 7, 0x1d }, { 29, 0x1ffffff8, 7, 0x1b },
{ 29, 0x1ffffff8, 7, 0x19 }, { 29, 0x1ffffff8, 7, 0x17 },
{ 29, 0x1ffffff8, 7, 0x15 }, { 29, 0x1ffffff8, 7, 0x13 },
{ 29, 0x1ffffff8, 7, 0x11 }, { 29, 0x1ffffff8, 7, 0xf },
{ 29, 0x1ffffff8, 7, 0xd }, { 29, 0x1ffffff8, 7, 0xb },
{ 29, 0x1ffffff8, 7, 0x9 }, { 29, 0x1ffffff8, 7, 0x7 },
{ 29, 0x1ffffff8, 7, 0x5 }, { 29, 0x1ffffff8, 7, 0x3 },
{ 29, 0x1ffffff8, 7, 0x1 }, { 0, 0, 0, 0 }
},
/*
* prefixed with 9 zeroes
*/
{
{ 11, 0x7f7, 0, 0 }, { 15, 0x7fe7, 0, 0 },
{ 15, 0x7fe5, 0, 0 }, { 19, 0x7ffcf, 0, 0 },
{ 19, 0x7ffcd, 0, 0 }, { 19, 0x7ffcb, 0, 0 },
{ 19, 0x7ffc9, 0, 0 }, { 23, 0x7fff9f, 0, 0 },
{ 23, 0x7fff9d, 0, 0 }, { 23, 0x7fff9b, 0, 0 },
{ 23, 0x7fff99, 0, 0 }, { 23, 0x7fff97, 0, 0 },
{ 23, 0x7fff95, 0, 0 }, { 23, 0x7fff93, 0, 0 },
{ 23, 0x7fff91, 0, 0 }, { 27, 0x7ffff5f, 0, 0 },
{ 27, 0x7ffff5d, 0, 0 }, { 27, 0x7ffff5b, 0, 0 },
{ 27, 0x7ffff59, 0, 0 }, { 27, 0x7ffff57, 0, 0 },
{ 27, 0x7ffff55, 0, 0 }, { 27, 0x7ffff53, 0, 0 },
{ 27, 0x7ffff51, 0, 0 }, { 27, 0x7ffff4f, 0, 0 },
{ 27, 0x7ffff4d, 0, 0 }, { 27, 0x7ffff4b, 0, 0 },
{ 27, 0x7ffff49, 0, 0 }, { 27, 0x7ffff47, 0, 0 },
{ 27, 0x7ffff45, 0, 0 }, { 27, 0x7ffff43, 0, 0 },
{ 27, 0x7ffff41, 0, 0 }, { 31, 0x7ffffeff, 0, 0 },
{ 31, 0x7ffffefd, 0, 0 }, { 31, 0x7ffffefb, 0, 0 },
{ 31, 0x7ffffef9, 0, 0 }, { 31, 0x7ffffef7, 0, 0 },
{ 31, 0x7ffffef5, 0, 0 }, { 31, 0x7ffffef3, 0, 0 },
{ 31, 0x7ffffef1, 0, 0 }, { 31, 0x7ffffeef, 0, 0 },
{ 31, 0x7ffffeed, 0, 0 }, { 31, 0x7ffffeeb, 0, 0 },
{ 31, 0x7ffffee9, 0, 0 }, { 31, 0x7ffffee7, 0, 0 },
{ 31, 0x7ffffee5, 0, 0 }, { 31, 0x7ffffee3, 0, 0 },
{ 31, 0x7ffffee1, 0, 0 }, { 31, 0x7ffffedf, 0, 0 },
{ 31, 0x7ffffedd, 0, 0 }, { 31, 0x7ffffedb, 0, 0 },
{ 31, 0x7ffffed9, 0, 0 }, { 31, 0x7ffffed7, 0, 0 },
{ 31, 0x7ffffed5, 0, 0 }, { 31, 0x7ffffed3, 0, 0 },
{ 31, 0x7ffffed1, 0, 0 }, { 31, 0x7ffffecf, 0, 0 },
{ 31, 0x7ffffecd, 0, 0 }, { 31, 0x7ffffecb, 0, 0 },
{ 31, 0x7ffffec9, 0, 0 }, { 31, 0x7ffffec7, 0, 0 },
{ 31, 0x7ffffec5, 0, 0 }, { 31, 0x7ffffec3, 0, 0 },
{ 31, 0x7ffffec1, 0, 0 }, { 29, 0x1ffffff9, 7, 0x7f },
{ 29, 0x1ffffff9, 7, 0x7d }, { 29, 0x1ffffff9, 7, 0x7b },
{ 29, 0x1ffffff9, 7, 0x79 }, { 29, 0x1ffffff9, 7, 0x77 },
{ 29, 0x1ffffff9, 7, 0x75 }, { 29, 0x1ffffff9, 7, 0x73 },
{ 29, 0x1ffffff9, 7, 0x71 }, { 29, 0x1ffffff9, 7, 0x6f },
{ 29, 0x1ffffff9, 7, 0x6d }, { 29, 0x1ffffff9, 7, 0x6b },
{ 29, 0x1ffffff9, 7, 0x69 }, { 29, 0x1ffffff9, 7, 0x67 },
{ 29, 0x1ffffff9, 7, 0x65 }, { 29, 0x1ffffff9, 7, 0x63 },
{ 29, 0x1ffffff9, 7, 0x61 }, { 29, 0x1ffffff9, 7, 0x5f },
{ 29, 0x1ffffff9, 7, 0x5d }, { 29, 0x1ffffff9, 7, 0x5b },
{ 29, 0x1ffffff9, 7, 0x59 }, { 29, 0x1ffffff9, 7, 0x57 },
{ 29, 0x1ffffff9, 7, 0x55 }, { 29, 0x1ffffff9, 7, 0x53 },
{ 29, 0x1ffffff9, 7, 0x51 }, { 29, 0x1ffffff9, 7, 0x4f },
{ 29, 0x1ffffff9, 7, 0x4d }, { 29, 0x1ffffff9, 7, 0x4b },
{ 29, 0x1ffffff9, 7, 0x49 }, { 29, 0x1ffffff9, 7, 0x47 },
{ 29, 0x1ffffff9, 7, 0x45 }, { 29, 0x1ffffff9, 7, 0x43 },
{ 29, 0x1ffffff9, 7, 0x41 }, { 29, 0x1ffffff9, 7, 0x3f },
{ 29, 0x1ffffff9, 7, 0x3d }, { 29, 0x1ffffff9, 7, 0x3b },
{ 29, 0x1ffffff9, 7, 0x39 }, { 29, 0x1ffffff9, 7, 0x37 },
{ 29, 0x1ffffff9, 7, 0x35 }, { 29, 0x1ffffff9, 7, 0x33 },
{ 29, 0x1ffffff9, 7, 0x31 }, { 29, 0x1ffffff9, 7, 0x2f },
{ 29, 0x1ffffff9, 7, 0x2d }, { 29, 0x1ffffff9, 7, 0x2b },
{ 29, 0x1ffffff9, 7, 0x29 }, { 29, 0x1ffffff9, 7, 0x27 },
{ 29, 0x1ffffff9, 7, 0x25 }, { 29, 0x1ffffff9, 7, 0x23 },
{ 29, 0x1ffffff9, 7, 0x21 }, { 29, 0x1ffffff9, 7, 0x1f },
{ 29, 0x1ffffff9, 7, 0x1d }, { 29, 0x1ffffff9, 7, 0x1b },
{ 29, 0x1ffffff9, 7, 0x19 }, { 29, 0x1ffffff9, 7, 0x17 },
{ 29, 0x1ffffff9, 7, 0x15 }, { 29, 0x1ffffff9, 7, 0x13 },
{ 29, 0x1ffffff9, 7, 0x11 }, { 29, 0x1ffffff9, 7, 0xf },
{ 29, 0x1ffffff9, 7, 0xd }, { 29, 0x1ffffff9, 7, 0xb },
{ 29, 0x1ffffff9, 7, 0x9 }, { 29, 0x1ffffff9, 7, 0x7 },
{ 29, 0x1ffffff9, 7, 0x5 }, { 29, 0x1ffffff9, 7, 0x3 },
{ 29, 0x1ffffff9, 7, 0x1 }, { 0, 0, 0, 0 }
},
/*
* prefixed with 10 zeroes
*/
{
{ 12, 0xff1, 0, 0 }, { 15, 0x7feb, 0, 0 },
{ 15, 0x7fe9, 0, 0 }, { 19, 0x7ffd7, 0, 0 },
{ 19, 0x7ffd5, 0, 0 }, { 19, 0x7ffd3, 0, 0 },
{ 19, 0x7ffd1, 0, 0 }, { 23, 0x7fffaf, 0, 0 },
{ 23, 0x7fffad, 0, 0 }, { 23, 0x7fffab, 0, 0 },
{ 23, 0x7fffa9, 0, 0 }, { 23, 0x7fffa7, 0, 0 },
{ 23, 0x7fffa5, 0, 0 }, { 23, 0x7fffa3, 0, 0 },
{ 23, 0x7fffa1, 0, 0 }, { 27, 0x7ffff7f, 0, 0 },
{ 27, 0x7ffff7d, 0, 0 }, { 27, 0x7ffff7b, 0, 0 },
{ 27, 0x7ffff79, 0, 0 }, { 27, 0x7ffff77, 0, 0 },
{ 27, 0x7ffff75, 0, 0 }, { 27, 0x7ffff73, 0, 0 },
{ 27, 0x7ffff71, 0, 0 }, { 27, 0x7ffff6f, 0, 0 },
{ 27, 0x7ffff6d, 0, 0 }, { 27, 0x7ffff6b, 0, 0 },
{ 27, 0x7ffff69, 0, 0 }, { 27, 0x7ffff67, 0, 0 },
{ 27, 0x7ffff65, 0, 0 }, { 27, 0x7ffff63, 0, 0 },
{ 27, 0x7ffff61, 0, 0 }, { 32, 0xfffffe3f, 0, 0 },
{ 32, 0xfffffe3d, 0, 0 }, { 32, 0xfffffe3b, 0, 0 },
{ 32, 0xfffffe39, 0, 0 }, { 32, 0xfffffe37, 0, 0 },
{ 32, 0xfffffe35, 0, 0 }, { 32, 0xfffffe33, 0, 0 },
{ 32, 0xfffffe31, 0, 0 }, { 32, 0xfffffe2f, 0, 0 },
{ 32, 0xfffffe2d, 0, 0 }, { 32, 0xfffffe2b, 0, 0 },
{ 32, 0xfffffe29, 0, 0 }, { 32, 0xfffffe27, 0, 0 },
{ 32, 0xfffffe25, 0, 0 }, { 32, 0xfffffe23, 0, 0 },
{ 32, 0xfffffe21, 0, 0 }, { 32, 0xfffffe1f, 0, 0 },
{ 32, 0xfffffe1d, 0, 0 }, { 32, 0xfffffe1b, 0, 0 },
{ 32, 0xfffffe19, 0, 0 }, { 32, 0xfffffe17, 0, 0 },
{ 32, 0xfffffe15, 0, 0 }, { 32, 0xfffffe13, 0, 0 },
{ 32, 0xfffffe11, 0, 0 }, { 32, 0xfffffe0f, 0, 0 },
{ 32, 0xfffffe0d, 0, 0 }, { 32, 0xfffffe0b, 0, 0 },
{ 32, 0xfffffe09, 0, 0 }, { 32, 0xfffffe07, 0, 0 },
{ 32, 0xfffffe05, 0, 0 }, { 32, 0xfffffe03, 0, 0 },
{ 32, 0xfffffe01, 0, 0 }, { 29, 0x1ffffffa, 7, 0x7f },
{ 29, 0x1ffffffa, 7, 0x7d }, { 29, 0x1ffffffa, 7, 0x7b },
{ 29, 0x1ffffffa, 7, 0x79 }, { 29, 0x1ffffffa, 7, 0x77 },
{ 29, 0x1ffffffa, 7, 0x75 }, { 29, 0x1ffffffa, 7, 0x73 },
{ 29, 0x1ffffffa, 7, 0x71 }, { 29, 0x1ffffffa, 7, 0x6f },
{ 29, 0x1ffffffa, 7, 0x6d }, { 29, 0x1ffffffa, 7, 0x6b },
{ 29, 0x1ffffffa, 7, 0x69 }, { 29, 0x1ffffffa, 7, 0x67 },
{ 29, 0x1ffffffa, 7, 0x65 }, { 29, 0x1ffffffa, 7, 0x63 },
{ 29, 0x1ffffffa, 7, 0x61 }, { 29, 0x1ffffffa, 7, 0x5f },
{ 29, 0x1ffffffa, 7, 0x5d }, { 29, 0x1ffffffa, 7, 0x5b },
{ 29, 0x1ffffffa, 7, 0x59 }, { 29, 0x1ffffffa, 7, 0x57 },
{ 29, 0x1ffffffa, 7, 0x55 }, { 29, 0x1ffffffa, 7, 0x53 },
{ 29, 0x1ffffffa, 7, 0x51 }, { 29, 0x1ffffffa, 7, 0x4f },
{ 29, 0x1ffffffa, 7, 0x4d }, { 29, 0x1ffffffa, 7, 0x4b },
{ 29, 0x1ffffffa, 7, 0x49 }, { 29, 0x1ffffffa, 7, 0x47 },
{ 29, 0x1ffffffa, 7, 0x45 }, { 29, 0x1ffffffa, 7, 0x43 },
{ 29, 0x1ffffffa, 7, 0x41 }, { 29, 0x1ffffffa, 7, 0x3f },
{ 29, 0x1ffffffa, 7, 0x3d }, { 29, 0x1ffffffa, 7, 0x3b },
{ 29, 0x1ffffffa, 7, 0x39 }, { 29, 0x1ffffffa, 7, 0x37 },
{ 29, 0x1ffffffa, 7, 0x35 }, { 29, 0x1ffffffa, 7, 0x33 },
{ 29, 0x1ffffffa, 7, 0x31 }, { 29, 0x1ffffffa, 7, 0x2f },
{ 29, 0x1ffffffa, 7, 0x2d }, { 29, 0x1ffffffa, 7, 0x2b },
{ 29, 0x1ffffffa, 7, 0x29 }, { 29, 0x1ffffffa, 7, 0x27 },
{ 29, 0x1ffffffa, 7, 0x25 }, { 29, 0x1ffffffa, 7, 0x23 },
{ 29, 0x1ffffffa, 7, 0x21 }, { 29, 0x1ffffffa, 7, 0x1f },
{ 29, 0x1ffffffa, 7, 0x1d }, { 29, 0x1ffffffa, 7, 0x1b },
{ 29, 0x1ffffffa, 7, 0x19 }, { 29, 0x1ffffffa, 7, 0x17 },
{ 29, 0x1ffffffa, 7, 0x15 }, { 29, 0x1ffffffa, 7, 0x13 },
{ 29, 0x1ffffffa, 7, 0x11 }, { 29, 0x1ffffffa, 7, 0xf },
{ 29, 0x1ffffffa, 7, 0xd }, { 29, 0x1ffffffa, 7, 0xb },
{ 29, 0x1ffffffa, 7, 0x9 }, { 29, 0x1ffffffa, 7, 0x7 },
{ 29, 0x1ffffffa, 7, 0x5 }, { 29, 0x1ffffffa, 7, 0x3 },
{ 29, 0x1ffffffa, 7, 0x1 }, { 0, 0, 0, 0 }
},
/*
* prefixed with 11 zeroes
*/
{
{ 12, 0xff3, 0, 0 }, { 15, 0x7fef, 0, 0 },
{ 15, 0x7fed, 0, 0 }, { 19, 0x7ffdf, 0, 0 },
{ 19, 0x7ffdd, 0, 0 }, { 19, 0x7ffdb, 0, 0 },
{ 19, 0x7ffd9, 0, 0 }, { 23, 0x7fffbf, 0, 0 },
{ 23, 0x7fffbd, 0, 0 }, { 23, 0x7fffbb, 0, 0 },
{ 23, 0x7fffb9, 0, 0 }, { 23, 0x7fffb7, 0, 0 },
{ 23, 0x7fffb5, 0, 0 }, { 23, 0x7fffb3, 0, 0 },
{ 23, 0x7fffb1, 0, 0 }, { 28, 0xfffff1f, 0, 0 },
{ 28, 0xfffff1d, 0, 0 }, { 28, 0xfffff1b, 0, 0 },
{ 28, 0xfffff19, 0, 0 }, { 28, 0xfffff17, 0, 0 },
{ 28, 0xfffff15, 0, 0 }, { 28, 0xfffff13, 0, 0 },
{ 28, 0xfffff11, 0, 0 }, { 28, 0xfffff0f, 0, 0 },
{ 28, 0xfffff0d, 0, 0 }, { 28, 0xfffff0b, 0, 0 },
{ 28, 0xfffff09, 0, 0 }, { 28, 0xfffff07, 0, 0 },
{ 28, 0xfffff05, 0, 0 }, { 28, 0xfffff03, 0, 0 },
{ 28, 0xfffff01, 0, 0 }, { 32, 0xfffffe7f, 0, 0 },
{ 32, 0xfffffe7d, 0, 0 }, { 32, 0xfffffe7b, 0, 0 },
{ 32, 0xfffffe79, 0, 0 }, { 32, 0xfffffe77, 0, 0 },
{ 32, 0xfffffe75, 0, 0 }, { 32, 0xfffffe73, 0, 0 },
{ 32, 0xfffffe71, 0, 0 }, { 32, 0xfffffe6f, 0, 0 },
{ 32, 0xfffffe6d, 0, 0 }, { 32, 0xfffffe6b, 0, 0 },
{ 32, 0xfffffe69, 0, 0 }, { 32, 0xfffffe67, 0, 0 },
{ 32, 0xfffffe65, 0, 0 }, { 32, 0xfffffe63, 0, 0 },
{ 32, 0xfffffe61, 0, 0 }, { 32, 0xfffffe5f, 0, 0 },
{ 32, 0xfffffe5d, 0, 0 }, { 32, 0xfffffe5b, 0, 0 },
{ 32, 0xfffffe59, 0, 0 }, { 32, 0xfffffe57, 0, 0 },
{ 32, 0xfffffe55, 0, 0 }, { 32, 0xfffffe53, 0, 0 },
{ 32, 0xfffffe51, 0, 0 }, { 32, 0xfffffe4f, 0, 0 },
{ 32, 0xfffffe4d, 0, 0 }, { 32, 0xfffffe4b, 0, 0 },
{ 32, 0xfffffe49, 0, 0 }, { 32, 0xfffffe47, 0, 0 },
{ 32, 0xfffffe45, 0, 0 }, { 32, 0xfffffe43, 0, 0 },
{ 32, 0xfffffe41, 0, 0 }, { 29, 0x1ffffffb, 7, 0x7f },
{ 29, 0x1ffffffb, 7, 0x7d }, { 29, 0x1ffffffb, 7, 0x7b },
{ 29, 0x1ffffffb, 7, 0x79 }, { 29, 0x1ffffffb, 7, 0x77 },
{ 29, 0x1ffffffb, 7, 0x75 }, { 29, 0x1ffffffb, 7, 0x73 },
{ 29, 0x1ffffffb, 7, 0x71 }, { 29, 0x1ffffffb, 7, 0x6f },
{ 29, 0x1ffffffb, 7, 0x6d }, { 29, 0x1ffffffb, 7, 0x6b },
{ 29, 0x1ffffffb, 7, 0x69 }, { 29, 0x1ffffffb, 7, 0x67 },
{ 29, 0x1ffffffb, 7, 0x65 }, { 29, 0x1ffffffb, 7, 0x63 },
{ 29, 0x1ffffffb, 7, 0x61 }, { 29, 0x1ffffffb, 7, 0x5f },
{ 29, 0x1ffffffb, 7, 0x5d }, { 29, 0x1ffffffb, 7, 0x5b },
{ 29, 0x1ffffffb, 7, 0x59 }, { 29, 0x1ffffffb, 7, 0x57 },
{ 29, 0x1ffffffb, 7, 0x55 }, { 29, 0x1ffffffb, 7, 0x53 },
{ 29, 0x1ffffffb, 7, 0x51 }, { 29, 0x1ffffffb, 7, 0x4f },
{ 29, 0x1ffffffb, 7, 0x4d }, { 29, 0x1ffffffb, 7, 0x4b },
{ 29, 0x1ffffffb, 7, 0x49 }, { 29, 0x1ffffffb, 7, 0x47 },
{ 29, 0x1ffffffb, 7, 0x45 }, { 29, 0x1ffffffb, 7, 0x43 },
{ 29, 0x1ffffffb, 7, 0x41 }, { 29, 0x1ffffffb, 7, 0x3f },
{ 29, 0x1ffffffb, 7, 0x3d }, { 29, 0x1ffffffb, 7, 0x3b },
{ 29, 0x1ffffffb, 7, 0x39 }, { 29, 0x1ffffffb, 7, 0x37 },
{ 29, 0x1ffffffb, 7, 0x35 }, { 29, 0x1ffffffb, 7, 0x33 },
{ 29, 0x1ffffffb, 7, 0x31 }, { 29, 0x1ffffffb, 7, 0x2f },
{ 29, 0x1ffffffb, 7, 0x2d }, { 29, 0x1ffffffb, 7, 0x2b },
{ 29, 0x1ffffffb, 7, 0x29 }, { 29, 0x1ffffffb, 7, 0x27 },
{ 29, 0x1ffffffb, 7, 0x25 }, { 29, 0x1ffffffb, 7, 0x23 },
{ 29, 0x1ffffffb, 7, 0x21 }, { 29, 0x1ffffffb, 7, 0x1f },
{ 29, 0x1ffffffb, 7, 0x1d }, { 29, 0x1ffffffb, 7, 0x1b },
{ 29, 0x1ffffffb, 7, 0x19 }, { 29, 0x1ffffffb, 7, 0x17 },
{ 29, 0x1ffffffb, 7, 0x15 }, { 29, 0x1ffffffb, 7, 0x13 },
{ 29, 0x1ffffffb, 7, 0x11 }, { 29, 0x1ffffffb, 7, 0xf },
{ 29, 0x1ffffffb, 7, 0xd }, { 29, 0x1ffffffb, 7, 0xb },
{ 29, 0x1ffffffb, 7, 0x9 }, { 29, 0x1ffffffb, 7, 0x7 },
{ 29, 0x1ffffffb, 7, 0x5 }, { 29, 0x1ffffffb, 7, 0x3 },
{ 29, 0x1ffffffb, 7, 0x1 }, { 0, 0, 0, 0 }
},
/*
* prefixed with 12 zeroes
*/
{
{ 12, 0xff5, 0, 0 }, { 16, 0xffe3, 0, 0 },
{ 16, 0xffe1, 0, 0 }, { 20, 0xfffc7, 0, 0 },
{ 20, 0xfffc5, 0, 0 }, { 20, 0xfffc3, 0, 0 },
{ 20, 0xfffc1, 0, 0 }, { 24, 0xffff8f, 0, 0 },
{ 24, 0xffff8d, 0, 0 }, { 24, 0xffff8b, 0, 0 },
{ 24, 0xffff89, 0, 0 }, { 24, 0xffff87, 0, 0 },
{ 24, 0xffff85, 0, 0 }, { 24, 0xffff83, 0, 0 },
{ 24, 0xffff81, 0, 0 }, { 28, 0xfffff3f, 0, 0 },
{ 28, 0xfffff3d, 0, 0 }, { 28, 0xfffff3b, 0, 0 },
{ 28, 0xfffff39, 0, 0 }, { 28, 0xfffff37, 0, 0 },
{ 28, 0xfffff35, 0, 0 }, { 28, 0xfffff33, 0, 0 },
{ 28, 0xfffff31, 0, 0 }, { 28, 0xfffff2f, 0, 0 },
{ 28, 0xfffff2d, 0, 0 }, { 28, 0xfffff2b, 0, 0 },
{ 28, 0xfffff29, 0, 0 }, { 28, 0xfffff27, 0, 0 },
{ 28, 0xfffff25, 0, 0 }, { 28, 0xfffff23, 0, 0 },
{ 28, 0xfffff21, 0, 0 }, { 32, 0xfffffebf, 0, 0 },
{ 32, 0xfffffebd, 0, 0 }, { 32, 0xfffffebb, 0, 0 },
{ 32, 0xfffffeb9, 0, 0 }, { 32, 0xfffffeb7, 0, 0 },
{ 32, 0xfffffeb5, 0, 0 }, { 32, 0xfffffeb3, 0, 0 },
{ 32, 0xfffffeb1, 0, 0 }, { 32, 0xfffffeaf, 0, 0 },
{ 32, 0xfffffead, 0, 0 }, { 32, 0xfffffeab, 0, 0 },
{ 32, 0xfffffea9, 0, 0 }, { 32, 0xfffffea7, 0, 0 },
{ 32, 0xfffffea5, 0, 0 }, { 32, 0xfffffea3, 0, 0 },
{ 32, 0xfffffea1, 0, 0 }, { 32, 0xfffffe9f, 0, 0 },
{ 32, 0xfffffe9d, 0, 0 }, { 32, 0xfffffe9b, 0, 0 },
{ 32, 0xfffffe99, 0, 0 }, { 32, 0xfffffe97, 0, 0 },
{ 32, 0xfffffe95, 0, 0 }, { 32, 0xfffffe93, 0, 0 },
{ 32, 0xfffffe91, 0, 0 }, { 32, 0xfffffe8f, 0, 0 },
{ 32, 0xfffffe8d, 0, 0 }, { 32, 0xfffffe8b, 0, 0 },
{ 32, 0xfffffe89, 0, 0 }, { 32, 0xfffffe87, 0, 0 },
{ 32, 0xfffffe85, 0, 0 }, { 32, 0xfffffe83, 0, 0 },
{ 32, 0xfffffe81, 0, 0 }, { 30, 0x1fff7400, 7, 0x7f },
{ 30, 0x1fff7400, 7, 0x7d }, { 30, 0x1fff7400, 7, 0x7b },
{ 30, 0x1fff7400, 7, 0x79 }, { 30, 0x1fff7400, 7, 0x77 },
{ 30, 0x1fff7400, 7, 0x75 }, { 30, 0x1fff7400, 7, 0x73 },
{ 30, 0x1fff7400, 7, 0x71 }, { 30, 0x1fff7400, 7, 0x6f },
{ 30, 0x1fff7400, 7, 0x6d }, { 30, 0x1fff7400, 7, 0x6b },
{ 30, 0x1fff7400, 7, 0x69 }, { 30, 0x1fff7400, 7, 0x67 },
{ 30, 0x1fff7400, 7, 0x65 }, { 30, 0x1fff7400, 7, 0x63 },
{ 30, 0x1fff7400, 7, 0x61 }, { 30, 0x1fff7400, 7, 0x5f },
{ 30, 0x1fff7400, 7, 0x5d }, { 30, 0x1fff7400, 7, 0x5b },
{ 30, 0x1fff7400, 7, 0x59 }, { 30, 0x1fff7400, 7, 0x57 },
{ 30, 0x1fff7400, 7, 0x55 }, { 30, 0x1fff7400, 7, 0x53 },
{ 30, 0x1fff7400, 7, 0x51 }, { 30, 0x1fff7400, 7, 0x4f },
{ 30, 0x1fff7400, 7, 0x4d }, { 30, 0x1fff7400, 7, 0x4b },
{ 30, 0x1fff7400, 7, 0x49 }, { 30, 0x1fff7400, 7, 0x47 },
{ 30, 0x1fff7400, 7, 0x45 }, { 30, 0x1fff7400, 7, 0x43 },
{ 30, 0x1fff7400, 7, 0x41 }, { 30, 0x1fff7400, 7, 0x3f },
{ 30, 0x1fff7400, 7, 0x3d }, { 30, 0x1fff7400, 7, 0x3b },
{ 30, 0x1fff7400, 7, 0x39 }, { 30, 0x1fff7400, 7, 0x37 },
{ 30, 0x1fff7400, 7, 0x35 }, { 30, 0x1fff7400, 7, 0x33 },
{ 30, 0x1fff7400, 7, 0x31 }, { 30, 0x1fff7400, 7, 0x2f },
{ 30, 0x1fff7400, 7, 0x2d }, { 30, 0x1fff7400, 7, 0x2b },
{ 30, 0x1fff7400, 7, 0x29 }, { 30, 0x1fff7400, 7, 0x27 },
{ 30, 0x1fff7400, 7, 0x25 }, { 30, 0x1fff7400, 7, 0x23 },
{ 30, 0x1fff7400, 7, 0x21 }, { 30, 0x1fff7400, 7, 0x1f },
{ 30, 0x1fff7400, 7, 0x1d }, { 30, 0x1fff7400, 7, 0x1b },
{ 30, 0x1fff7400, 7, 0x19 }, { 30, 0x1fff7400, 7, 0x17 },
{ 30, 0x1fff7400, 7, 0x15 }, { 30, 0x1fff7400, 7, 0x13 },
{ 30, 0x1fff7400, 7, 0x11 }, { 30, 0x1fff7400, 7, 0xf },
{ 30, 0x1fff7400, 7, 0xd }, { 30, 0x1fff7400, 7, 0xb },
{ 30, 0x1fff7400, 7, 0x9 }, { 30, 0x1fff7400, 7, 0x7 },
{ 30, 0x1fff7400, 7, 0x5 }, { 30, 0x1fff7400, 7, 0x3 },
{ 30, 0x1fff7400, 7, 0x1 }, { 0, 0, 0, 0 }
},
/*
* prefixed with 13 zeroes
*/
{
{ 12, 0xff7, 0, 0 }, { 16, 0xffe7, 0, 0 },
{ 16, 0xffe5, 0, 0 }, { 20, 0xfffcf, 0, 0 },
{ 20, 0xfffcd, 0, 0 }, { 20, 0xfffcb, 0, 0 },
{ 20, 0xfffc9, 0, 0 }, { 24, 0xffff9f, 0, 0 },
{ 24, 0xffff9d, 0, 0 }, { 24, 0xffff9b, 0, 0 },
{ 24, 0xffff99, 0, 0 }, { 24, 0xffff97, 0, 0 },
{ 24, 0xffff95, 0, 0 }, { 24, 0xffff93, 0, 0 },
{ 24, 0xffff91, 0, 0 }, { 28, 0xfffff5f, 0, 0 },
{ 28, 0xfffff5d, 0, 0 }, { 28, 0xfffff5b, 0, 0 },
{ 28, 0xfffff59, 0, 0 }, { 28, 0xfffff57, 0, 0 },
{ 28, 0xfffff55, 0, 0 }, { 28, 0xfffff53, 0, 0 },
{ 28, 0xfffff51, 0, 0 }, { 28, 0xfffff4f, 0, 0 },
{ 28, 0xfffff4d, 0, 0 }, { 28, 0xfffff4b, 0, 0 },
{ 28, 0xfffff49, 0, 0 }, { 28, 0xfffff47, 0, 0 },
{ 28, 0xfffff45, 0, 0 }, { 28, 0xfffff43, 0, 0 },
{ 28, 0xfffff41, 0, 0 }, { 32, 0xfffffeff, 0, 0 },
{ 32, 0xfffffefd, 0, 0 }, { 32, 0xfffffefb, 0, 0 },
{ 32, 0xfffffef9, 0, 0 }, { 32, 0xfffffef7, 0, 0 },
{ 32, 0xfffffef5, 0, 0 }, { 32, 0xfffffef3, 0, 0 },
{ 32, 0xfffffef1, 0, 0 }, { 32, 0xfffffeef, 0, 0 },
{ 32, 0xfffffeed, 0, 0 }, { 32, 0xfffffeeb, 0, 0 },
{ 32, 0xfffffee9, 0, 0 }, { 32, 0xfffffee7, 0, 0 },
{ 32, 0xfffffee5, 0, 0 }, { 32, 0xfffffee3, 0, 0 },
{ 32, 0xfffffee1, 0, 0 }, { 32, 0xfffffedf, 0, 0 },
{ 32, 0xfffffedd, 0, 0 }, { 32, 0xfffffedb, 0, 0 },
{ 32, 0xfffffed9, 0, 0 }, { 32, 0xfffffed7, 0, 0 },
{ 32, 0xfffffed5, 0, 0 }, { 32, 0xfffffed3, 0, 0 },
{ 32, 0xfffffed1, 0, 0 }, { 32, 0xfffffecf, 0, 0 },
{ 32, 0xfffffecd, 0, 0 }, { 32, 0xfffffecb, 0, 0 },
{ 32, 0xfffffec9, 0, 0 }, { 32, 0xfffffec7, 0, 0 },
{ 32, 0xfffffec5, 0, 0 }, { 32, 0xfffffec3, 0, 0 },
{ 32, 0xfffffec1, 0, 0 }, { 30, 0x3ffffff9, 7, 0x7f },
{ 30, 0x3ffffff9, 7, 0x7d }, { 30, 0x3ffffff9, 7, 0x7b },
{ 30, 0x3ffffff9, 7, 0x79 }, { 30, 0x3ffffff9, 7, 0x77 },
{ 30, 0x3ffffff9, 7, 0x75 }, { 30, 0x3ffffff9, 7, 0x73 },
{ 30, 0x3ffffff9, 7, 0x71 }, { 30, 0x3ffffff9, 7, 0x6f },
{ 30, 0x3ffffff9, 7, 0x6d }, { 30, 0x3ffffff9, 7, 0x6b },
{ 30, 0x3ffffff9, 7, 0x69 }, { 30, 0x3ffffff9, 7, 0x67 },
{ 30, 0x3ffffff9, 7, 0x65 }, { 30, 0x3ffffff9, 7, 0x63 },
{ 30, 0x3ffffff9, 7, 0x61 }, { 30, 0x3ffffff9, 7, 0x5f },
{ 30, 0x3ffffff9, 7, 0x5d }, { 30, 0x3ffffff9, 7, 0x5b },
{ 30, 0x3ffffff9, 7, 0x59 }, { 30, 0x3ffffff9, 7, 0x57 },
{ 30, 0x3ffffff9, 7, 0x55 }, { 30, 0x3ffffff9, 7, 0x53 },
{ 30, 0x3ffffff9, 7, 0x51 }, { 30, 0x3ffffff9, 7, 0x4f },
{ 30, 0x3ffffff9, 7, 0x4d }, { 30, 0x3ffffff9, 7, 0x4b },
{ 30, 0x3ffffff9, 7, 0x49 }, { 30, 0x3ffffff9, 7, 0x47 },
{ 30, 0x3ffffff9, 7, 0x45 }, { 30, 0x3ffffff9, 7, 0x43 },
{ 30, 0x3ffffff9, 7, 0x41 }, { 30, 0x3ffffff9, 7, 0x3f },
{ 30, 0x3ffffff9, 7, 0x3d }, { 30, 0x3ffffff9, 7, 0x3b },
{ 30, 0x3ffffff9, 7, 0x39 }, { 30, 0x3ffffff9, 7, 0x37 },
{ 30, 0x3ffffff9, 7, 0x35 }, { 30, 0x3ffffff9, 7, 0x33 },
{ 30, 0x3ffffff9, 7, 0x31 }, { 30, 0x3ffffff9, 7, 0x2f },
{ 30, 0x3ffffff9, 7, 0x2d }, { 30, 0x3ffffff9, 7, 0x2b },
{ 30, 0x3ffffff9, 7, 0x29 }, { 30, 0x3ffffff9, 7, 0x27 },
{ 30, 0x3ffffff9, 7, 0x25 }, { 30, 0x3ffffff9, 7, 0x23 },
{ 30, 0x3ffffff9, 7, 0x21 }, { 30, 0x3ffffff9, 7, 0x1f },
{ 30, 0x3ffffff9, 7, 0x1d }, { 30, 0x3ffffff9, 7, 0x1b },
{ 30, 0x3ffffff9, 7, 0x19 }, { 30, 0x3ffffff9, 7, 0x17 },
{ 30, 0x3ffffff9, 7, 0x15 }, { 30, 0x3ffffff9, 7, 0x13 },
{ 30, 0x3ffffff9, 7, 0x11 }, { 30, 0x3ffffff9, 7, 0xf },
{ 30, 0x3ffffff9, 7, 0xd }, { 30, 0x3ffffff9, 7, 0xb },
{ 30, 0x3ffffff9, 7, 0x9 }, { 30, 0x3ffffff9, 7, 0x7 },
{ 30, 0x3ffffff9, 7, 0x5 }, { 30, 0x3ffffff9, 7, 0x3 },
{ 30, 0x3ffffff9, 7, 0x1 }, { 0, 0, 0, 0 }
},
/*
* prefixed with 14 zeroes
*/
{
{ 13, 0x1ff1, 0, 0 }, { 16, 0xffeb, 0, 0 },
{ 16, 0xffe9, 0, 0 }, { 20, 0xfffd7, 0, 0 },
{ 20, 0xfffd5, 0, 0 }, { 20, 0xfffd3, 0, 0 },
{ 20, 0xfffd1, 0, 0 }, { 24, 0xffffaf, 0, 0 },
{ 24, 0xffffad, 0, 0 }, { 24, 0xffffab, 0, 0 },
{ 24, 0xffffa9, 0, 0 }, { 24, 0xffffa7, 0, 0 },
{ 24, 0xffffa5, 0, 0 }, { 24, 0xffffa3, 0, 0 },
{ 24, 0xffffa1, 0, 0 }, { 28, 0xfffff7f, 0, 0 },
{ 28, 0xfffff7d, 0, 0 }, { 28, 0xfffff7b, 0, 0 },
{ 28, 0xfffff79, 0, 0 }, { 28, 0xfffff77, 0, 0 },
{ 28, 0xfffff75, 0, 0 }, { 28, 0xfffff73, 0, 0 },
{ 28, 0xfffff71, 0, 0 }, { 28, 0xfffff6f, 0, 0 },
{ 28, 0xfffff6d, 0, 0 }, { 28, 0xfffff6b, 0, 0 },
{ 28, 0xfffff69, 0, 0 }, { 28, 0xfffff67, 0, 0 },
{ 28, 0xfffff65, 0, 0 }, { 28, 0xfffff63, 0, 0 },
{ 28, 0xfffff61, 0, 0 }, { 27, 0x7fffff8, 6, 0x3f },
{ 27, 0x7fffff8, 6, 0x3d }, { 27, 0x7fffff8, 6, 0x3b },
{ 27, 0x7fffff8, 6, 0x39 }, { 27, 0x7fffff8, 6, 0x37 },
{ 27, 0x7fffff8, 6, 0x35 }, { 27, 0x7fffff8, 6, 0x33 },
{ 27, 0x7fffff8, 6, 0x31 }, { 27, 0x7fffff8, 6, 0x2f },
{ 27, 0x7fffff8, 6, 0x2d }, { 27, 0x7fffff8, 6, 0x2b },
{ 27, 0x7fffff8, 6, 0x29 }, { 27, 0x7fffff8, 6, 0x27 },
{ 27, 0x7fffff8, 6, 0x25 }, { 27, 0x7fffff8, 6, 0x23 },
{ 27, 0x7fffff8, 6, 0x21 }, { 27, 0x7fffff8, 6, 0x1f },
{ 27, 0x7fffff8, 6, 0x1d }, { 27, 0x7fffff8, 6, 0x1b },
{ 27, 0x7fffff8, 6, 0x19 }, { 27, 0x7fffff8, 6, 0x17 },
{ 27, 0x7fffff8, 6, 0x15 }, { 27, 0x7fffff8, 6, 0x13 },
{ 27, 0x7fffff8, 6, 0x11 }, { 27, 0x7fffff8, 6, 0xf },
{ 27, 0x7fffff8, 6, 0xd }, { 27, 0x7fffff8, 6, 0xb },
{ 27, 0x7fffff8, 6, 0x9 }, { 27, 0x7fffff8, 6, 0x7 },
{ 27, 0x7fffff8, 6, 0x5 }, { 27, 0x7fffff8, 6, 0x3 },
{ 27, 0x7fffff8, 6, 0x1 }, { 30, 0x3ffffffa, 7, 0x7f },
{ 30, 0x3ffffffa, 7, 0x7d }, { 30, 0x3ffffffa, 7, 0x7b },
{ 30, 0x3ffffffa, 7, 0x79 }, { 30, 0x3ffffffa, 7, 0x77 },
{ 30, 0x3ffffffa, 7, 0x75 }, { 30, 0x3ffffffa, 7, 0x73 },
{ 30, 0x3ffffffa, 7, 0x71 }, { 30, 0x3ffffffa, 7, 0x6f },
{ 30, 0x3ffffffa, 7, 0x6d }, { 30, 0x3ffffffa, 7, 0x6b },
{ 30, 0x3ffffffa, 7, 0x69 }, { 30, 0x3ffffffa, 7, 0x67 },
{ 30, 0x3ffffffa, 7, 0x65 }, { 30, 0x3ffffffa, 7, 0x63 },
{ 30, 0x3ffffffa, 7, 0x61 }, { 30, 0x3ffffffa, 7, 0x5f },
{ 30, 0x3ffffffa, 7, 0x5d }, { 30, 0x3ffffffa, 7, 0x5b },
{ 30, 0x3ffffffa, 7, 0x59 }, { 30, 0x3ffffffa, 7, 0x57 },
{ 30, 0x3ffffffa, 7, 0x55 }, { 30, 0x3ffffffa, 7, 0x53 },
{ 30, 0x3ffffffa, 7, 0x51 }, { 30, 0x3ffffffa, 7, 0x4f },
{ 30, 0x3ffffffa, 7, 0x4d }, { 30, 0x3ffffffa, 7, 0x4b },
{ 30, 0x3ffffffa, 7, 0x49 }, { 30, 0x3ffffffa, 7, 0x47 },
{ 30, 0x3ffffffa, 7, 0x45 }, { 30, 0x3ffffffa, 7, 0x43 },
{ 30, 0x3ffffffa, 7, 0x41 }, { 30, 0x3ffffffa, 7, 0x3f },
{ 30, 0x3ffffffa, 7, 0x3d }, { 30, 0x3ffffffa, 7, 0x3b },
{ 30, 0x3ffffffa, 7, 0x39 }, { 30, 0x3ffffffa, 7, 0x37 },
{ 30, 0x3ffffffa, 7, 0x35 }, { 30, 0x3ffffffa, 7, 0x33 },
{ 30, 0x3ffffffa, 7, 0x31 }, { 30, 0x3ffffffa, 7, 0x2f },
{ 30, 0x3ffffffa, 7, 0x2d }, { 30, 0x3ffffffa, 7, 0x2b },
{ 30, 0x3ffffffa, 7, 0x29 }, { 30, 0x3ffffffa, 7, 0x27 },
{ 30, 0x3ffffffa, 7, 0x25 }, { 30, 0x3ffffffa, 7, 0x23 },
{ 30, 0x3ffffffa, 7, 0x21 }, { 30, 0x3ffffffa, 7, 0x1f },
{ 30, 0x3ffffffa, 7, 0x1d }, { 30, 0x3ffffffa, 7, 0x1b },
{ 30, 0x3ffffffa, 7, 0x19 }, { 30, 0x3ffffffa, 7, 0x17 },
{ 30, 0x3ffffffa, 7, 0x15 }, { 30, 0x3ffffffa, 7, 0x13 },
{ 30, 0x3ffffffa, 7, 0x11 }, { 30, 0x3ffffffa, 7, 0xf },
{ 30, 0x3ffffffa, 7, 0xd }, { 30, 0x3ffffffa, 7, 0xb },
{ 30, 0x3ffffffa, 7, 0x9 }, { 30, 0x3ffffffa, 7, 0x7 },
{ 30, 0x3ffffffa, 7, 0x5 }, { 30, 0x3ffffffa, 7, 0x3 },
{ 30, 0x3ffffffa, 7, 0x1 }, { 0, 0, 0, 0 }
},
/*
* prefixed with 15 zeroes
*/
{
{ 13, 0x1ff3, 0, 0 }, { 2, 0x3, 0, 0 },
{ 2, 0x1, 0, 0 }, { 3, 0x7, 0, 0 },
{ 3, 0x5, 0, 0 }, { 3, 0x3, 0, 0 },
{ 3, 0x1, 0, 0 }, { 31, 0x7ffffffb, 4, 0xf },
{ 31, 0x7ffffffb, 4, 0xd }, { 31, 0x7ffffffb, 4, 0xb },
{ 31, 0x7ffffffb, 4, 0x9 }, { 31, 0x7ffffffb, 4, 0x7 },
{ 31, 0x7ffffffb, 4, 0x5 }, { 31, 0x7ffffffb, 4, 0x3 },
{ 31, 0x7ffffffb, 4, 0x1 }, { 5, 0x1f, 0, 0 },
{ 5, 0x1d, 0, 0 }, { 5, 0x1b, 0, 0 },
{ 5, 0x19, 0, 0 }, { 5, 0x17, 0, 0 },
{ 5, 0x15, 0, 0 }, { 5, 0x13, 0, 0 },
{ 5, 0x11, 0, 0 }, { 5, 0xf, 0, 0 },
{ 5, 0xd, 0, 0 }, { 5, 0xb, 0, 0 },
{ 5, 0x9, 0, 0 }, { 5, 0x7, 0, 0 },
{ 5, 0x5, 0, 0 }, { 5, 0x3, 0, 0 },
{ 5, 0x1, 0, 0 }, { 6, 0x3f, 0, 0 },
{ 6, 0x3d, 0, 0 }, { 6, 0x3b, 0, 0 },
{ 6, 0x39, 0, 0 }, { 6, 0x37, 0, 0 },
{ 6, 0x35, 0, 0 }, { 6, 0x33, 0, 0 },
{ 6, 0x31, 0, 0 }, { 6, 0x2f, 0, 0 },
{ 6, 0x2d, 0, 0 }, { 6, 0x2b, 0, 0 },
{ 6, 0x29, 0, 0 }, { 6, 0x27, 0, 0 },
{ 6, 0x25, 0, 0 }, { 6, 0x23, 0, 0 },
{ 6, 0x21, 0, 0 }, { 6, 0x1f, 0, 0 },
{ 6, 0x1d, 0, 0 }, { 6, 0x1b, 0, 0 },
{ 6, 0x19, 0, 0 }, { 6, 0x17, 0, 0 },
{ 6, 0x15, 0, 0 }, { 6, 0x13, 0, 0 },
{ 6, 0x11, 0, 0 }, { 6, 0xf, 0, 0 },
{ 6, 0xd, 0, 0 }, { 6, 0xb, 0, 0 },
{ 6, 0x9, 0, 0 }, { 6, 0x7, 0, 0 },
{ 6, 0x5, 0, 0 }, { 6, 0x3, 0, 0 },
{ 6, 0x1, 0, 0 }, { 7, 0x7f, 0, 0 },
{ 7, 0x7d, 0, 0 }, { 7, 0x7b, 0, 0 },
{ 7, 0x79, 0, 0 }, { 7, 0x77, 0, 0 },
{ 7, 0x75, 0, 0 }, { 7, 0x73, 0, 0 },
{ 7, 0x71, 0, 0 }, { 7, 0x6f, 0, 0 },
{ 7, 0x6d, 0, 0 }, { 7, 0x6b, 0, 0 },
{ 7, 0x69, 0, 0 }, { 7, 0x67, 0, 0 },
{ 7, 0x65, 0, 0 }, { 7, 0x63, 0, 0 },
{ 7, 0x61, 0, 0 }, { 7, 0x5f, 0, 0 },
{ 7, 0x5d, 0, 0 }, { 7, 0x5b, 0, 0 },
{ 7, 0x59, 0, 0 }, { 7, 0x57, 0, 0 },
{ 7, 0x55, 0, 0 }, { 7, 0x53, 0, 0 },
{ 7, 0x51, 0, 0 }, { 7, 0x4f, 0, 0 },
{ 7, 0x4d, 0, 0 }, { 7, 0x4b, 0, 0 },
{ 7, 0x49, 0, 0 }, { 7, 0x47, 0, 0 },
{ 7, 0x45, 0, 0 }, { 7, 0x43, 0, 0 },
{ 7, 0x41, 0, 0 }, { 7, 0x3f, 0, 0 },
{ 7, 0x3d, 0, 0 }, { 7, 0x3b, 0, 0 },
{ 7, 0x39, 0, 0 }, { 7, 0x37, 0, 0 },
{ 7, 0x35, 0, 0 }, { 7, 0x33, 0, 0 },
{ 7, 0x31, 0, 0 }, { 7, 0x2f, 0, 0 },
{ 7, 0x2d, 0, 0 }, { 7, 0x2b, 0, 0 },
{ 7, 0x29, 0, 0 }, { 7, 0x27, 0, 0 },
{ 7, 0x25, 0, 0 }, { 7, 0x23, 0, 0 },
{ 7, 0x21, 0, 0 }, { 7, 0x1f, 0, 0 },
{ 7, 0x1d, 0, 0 }, { 7, 0x1b, 0, 0 },
{ 7, 0x19, 0, 0 }, { 7, 0x17, 0, 0 },
{ 7, 0x15, 0, 0 }, { 7, 0x13, 0, 0 },
{ 7, 0x11, 0, 0 }, { 7, 0xf, 0, 0 },
{ 7, 0xd, 0, 0 }, { 7, 0xb, 0, 0 },
{ 7, 0x9, 0, 0 }, { 7, 0x7, 0, 0 },
{ 7, 0x5, 0, 0 }, { 7, 0x3, 0, 0 },
{ 7, 0x1, 0, 0 }, { 0, 0, 0, 0 }
}
};
VlcMagic _magic_values[] = {
{ 0x0, 0, 1 },
{ 0x1, 0, 2 },
{ 0x4, 0, 3 },
{ 0xB, 1, 1 },
{ 0xC, 0, 4 },
{ 0x1A, 0, 5 },
{ 0x1B, 2, 1 },
{ 0x38, 3, 1 },
{ 0x39, 1, 2 },
{ 0x3A, 1, 3 },
{ 0x3B, 0, 6 },
{ 0x78, 4, 1 },
{ 0x79, 5, 1 },
{ 0x7A, 6, 1 },
{ 0x7B, 2, 2 },
{ 0xF8, 1, 4 },
{ 0xF9, 7, 1 },
{ 0xFA, 8, 1 },
{ 0xFB, 3, 2 },
{ 0x1F8, 4, 2 },
{ 0x1F9, 5, 2 },
{ 0x1FA, 2, 3 },
{ 0x1FB, 2, 4 },
{ 0x3F8, 1, 5 },
{ 0x3F9, 1, 6 },
{ 0x3FA, 0, 7 },
{ 0x3FB, 9, 1 },
{ 0x7F8, 10, 1 },
{ 0x7F9, 11, 1 },
{ 0x7FA, 12, 1 },
{ 0x7FB, 13, 1 },
{ 0xFF8, 14, 1 },
{ 0xFF9, 15, 1 },
{ 0xFFA, 6, 2 },
{ 0xFFB, 7, 2 },
{ 0x1FF8, 8, 2 },
{ 0x1FF9, 9, 2 },
{ 0x1FFA, 10, 2 },
{ 0x1FFB, 11, 2 },
{ 0x3FF8, 12, 2 },
{ 0x3FF9, 13, 2 },
{ 0x3FFA, 14, 2 },
{ 0x3FFB, 3, 3 },
{ 0x7FF8, 4, 3 },
{ 0x7FF9, 5, 3 },
{ 0x7FFA, 6, 3 },
{ 0x7FFB, 7, 3 },
{ 0xFFF8, 8, 3 },
{ 0xFFF9, 9, 3 },
{ 0xFFFA, 10, 3 },
{ 0xFFFB, 11, 3 },
{ 0x1FFF8, 12, 3 },
{ 0x1FFF9, 13, 3 },
{ 0x1FFFA, 14, 3 },
{ 0x1FFFB, 3, 4 },
{ 0x3FFF8, 4, 4 },
{ 0x3FFF9, 5, 4 },
{ 0x3FFFA, 6, 4 },
{ 0x3FFFB, 7, 4 },
{ 0x7FFF8, 8, 4 },
{ 0x7FFF9, 9, 4 },
{ 0x7FFFA, 10, 4 },
{ 0x7FFFB, 11, 4 },
{ 0xFFFF8, 12, 4 },
{ 0xFFFF9, 13, 4 },
{ 0xFFFFA, 14, 4 },
{ 0xFFFFB, 2, 5 },
{ 0x1FFFF8, 3, 5 },
{ 0x1FFFF9, 4, 5 },
{ 0x1FFFFA, 5, 5 },
{ 0x1FFFFB, 6, 5 },
{ 0x3FFFF8, 7, 5 },
{ 0x3FFFF9, 8, 5 },
{ 0x3FFFFA, 9, 5 },
{ 0x3FFFFB, 10, 5 },
{ 0x7FFFF8, 11, 5 },
{ 0x7FFFF9, 12, 5 },
{ 0x7FFFFA, 13, 5 },
{ 0x7FFFFB, 14, 5 },
{ 0xFFFFF8, 2, 6 },
{ 0xFFFFF9, 3, 6 },
{ 0xFFFFFA, 4, 6 },
{ 0xFFFFFB, 5, 6 },
{ 0x1FFFFF8, 6, 6 },
{ 0x1FFFFF9, 7, 6 },
{ 0x1FFFFFA, 8, 6 },
{ 0x1FFFFFB, 9, 6 },
{ 0x3FFFFF8, 10, 6 },
{ 0x3FFFFF9, 11, 6 },
{ 0x3FFFFFA, 12, 6 },
{ 0x3FFFFFB, 13, 6 },
{ 0x7FFFFF8, 14, 6 },
{ 0x7FFFFF9, 1, 7 },
{ 0x7FFFFFA, 2, 7 },
{ 0x7FFFFFB, 3, 7 },
{ 0xFFFFFF8, 4, 7 },
{ 0xFFFFFF9, 5, 7 },
{ 0xFFFFFFA, 6, 7 },
{ 0xFFFFFFB, 7, 7 },
{ 0x1FFFFFF8, 8, 7 },
{ 0x1FFFFFF9, 9, 7 },
{ 0x1FFFFFFA, 10, 7 },
{ 0x1FFFFFFB, 11, 7 },
{ 0x3FFFFFF8, 12, 7 },
{ 0x3FFFFFF9, 13, 7 },
{ 0x3FFFFFFA, 14, 7 }
};
/*
* _find_magic
*
* Internal helper-function used to locate a given
* VlcMagic entry.
*/
VlcMagic *_find_magic(guint magic)
{
gint low = 0;
gint high = sizeof(_magic_values) / sizeof(VlcMagic) - 1;
gint mid;
while (low <= high) {
mid = (low + high) / 2;
if (_magic_values[mid].magic < magic)
low = mid + 1;
else if (_magic_values[mid].magic > magic)
high = mid - 1;
else
return &_magic_values[mid];
}
return NULL;
}
/*
* _initialize_vlcdec_lookup
*
* Internal helper-function used to initialize
* the lookup-table used by the VLC-decoder.
*/
void _initialize_vlcdec_lookup(gint8 *lookup_tbl)
{
gint8 util_buf[3072];
gint v1_start, v1_end, v1_dec, util_buf_offset;
gint util_buf_offset_inc, buf1_val, samples_offset;
gint v1, v2;
gint8 *p, *p1, *p2, *p3;
util_buf[0] = 0;
util_buf[1] = 0;
util_buf[2] = 0;
util_buf[3] = 1;
util_buf[4] = 1;
util_buf[5] = 1;
util_buf[765] = 1;
util_buf[766] = 0;
util_buf[767] = 1;
lookup_tbl[255] = 255;
lookup_tbl[256] = 1;
v1_start = -3;
v1_dec = 4;
util_buf_offset = 11;
util_buf_offset_inc = 12;
buf1_val = 2;
samples_offset = 509;
do {
v1 = v1_start;
v1_end = -(abs(v1_start) + 1) / 2;
v2 = 0;
p2 = util_buf + util_buf_offset - 3;
do {
p1 = util_buf + ((v1 & 0xff) * 3);
p1[0] = buf1_val;
p1[1] = v2;
p1[2] = buf1_val;
p2[1] = buf1_val;
p2[2] = v2 + 1;
p2[3] = buf1_val;
p3 = lookup_tbl + samples_offset + v2 + 1;
p3[0] = v1 & 0xff;
p3[1] = -(v1 & 0xff);
v1++;
v2 += 2;
p2 -= 3;
} while (v1 <= v1_end);
v1_start -= v1_dec;
v1_dec *= 2;
util_buf_offset += util_buf_offset_inc;
util_buf_offset_inc *= 2;
buf1_val++;
samples_offset += 255;
} while (buf1_val <= 7);
p = lookup_tbl + 1785 + util_buf[388];
p[0] = 129;
}
amsn-0.98.9/utils/webcamsn/src/colorspace.c 0000644 0001750 0001750 00000011120 10225230720 020401 0 ustar billiob billiob /* Copyright (C) 2005 Ole André Vadla Ravnås
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "mimic-private.h"
#define RED_INDEX_1 0
#define GREEN_INDEX_1 1
#define BLUE_INDEX_1 2
#define RED_INDEX_2 3
#define GREEN_INDEX_2 4
#define BLUE_INDEX_2 5
/*
* _rgb_to_yuv
*
* Internal helper-function used to convert an image
* from RGB 24-bpp packed-pixel to YUV420 planar.
*/
void _rgb_to_yuv(const guchar *input_rgb,
guchar *output_y,
guchar *output_cb,
guchar *output_cr,
gint width,
gint height)
{
gint y, x;
for (y = 0; y < height; y += 2) {
const guchar *src1, *src2;
guchar *dst1, *dst2, *dst3, *dst4;
gint num_cols;
src1 = input_rgb + ((height - 1 - y) * width * 3);
src2 = input_rgb + ((height - 2 - y) * width * 3);
dst1 = output_y + (y * width);
dst2 = output_y + ((y + 1) * width);
dst3 = output_cb + ((y / 2) * (width / 2));
dst4 = output_cr + ((y / 2) * (width / 2));
num_cols = width / 2;
for (x = 0; x < num_cols; x++) {
gint expr1, expr2, expr3, expr4, expr5, v;
expr1 = (src1[BLUE_INDEX_1] * 19595) + (src1[GREEN_INDEX_1] * 38470) + (src1[RED_INDEX_1] * 7471);
expr2 = (src1[BLUE_INDEX_2] * 19595) + (src1[GREEN_INDEX_2] * 38470) + (src1[RED_INDEX_2] * 7471);
expr3 = (src2[BLUE_INDEX_1] * 19595) + (src2[GREEN_INDEX_1] * 38470) + (src2[RED_INDEX_1] * 7471);
expr4 = (src2[BLUE_INDEX_2] * 19595) + (src2[GREEN_INDEX_2] * 38470) + (src2[RED_INDEX_2] * 7471);
expr5 = expr1 + expr2 + expr3 + expr4;
dst1[0] = expr1 >> 16;
dst1[1] = expr2 >> 16;
dst2[0] = expr3 >> 16;
dst2[1] = expr4 >> 16;
v = (((src1[BLUE_INDEX_1] + src1[BLUE_INDEX_2] + src2[BLUE_INDEX_1] + src2[BLUE_INDEX_2]) << 16) - expr5 + 131071) >> 16;
dst3[0] = _clamp_value(((v * 57475) >> 18) + 128);
v = (((src1[RED_INDEX_1] + src1[RED_INDEX_2] + src2[RED_INDEX_1] + src2[RED_INDEX_2]) << 16) - expr5 + 131071) >> 16;
dst4[0] = ((v * 32244) >> 18) + 128;
src1 += 6;
src2 += 6;
dst1 += 2;
dst2 += 2;
dst3++;
dst4++;
}
}
}
/*
* _yuv_to_rgb
*
* Internal helper-function used to convert an image
* from YUV420 planar to RGB 24-bpp packed-pixel.
*/
void _yuv_to_rgb(const guchar *input_y,
const guchar *input_cb,
const guchar *input_cr,
guchar *output_rgb,
guint width,
guint height)
{
const guchar *src_y, *src_cb, *src_cr;
guchar *dst_rgb;
guint i, j, rgb_stride;
src_y = input_y;
src_cb = input_cb;
src_cr = input_cr;
rgb_stride = width * 3;
dst_rgb = output_rgb + (rgb_stride * (height - 1));
for (i = 0; i < height; i++) {
const guchar *p_y, *p_cb, *p_cr;
guchar *p_rgb;
p_y = src_y;
p_cb = src_cb;
p_cr = src_cr;
p_rgb = dst_rgb;
for (j = 0; j < width; j++) {
gint v;
v = ((p_y[0] * 65536) + ((p_cr[0] - 128) * 133169)) / 65536;
p_rgb[0] = _clamp_value(v);
v = ((p_y[0] * 65536) - ((p_cr[0] - 128) * 25821) - ((p_cb[0] - 128) * 38076)) / 65536;
p_rgb[1] = _clamp_value(v);
v = ((p_y[0] * 65536) + ((p_cb[0] - 128) * 74711)) / 65536;
p_rgb[2] = _clamp_value(v);
p_y++;
if ((j + 1) % 2 == 0) {
p_cb++;
p_cr++;
}
p_rgb += 3;
}
src_y += width;
if ((i + 1) % 2 == 0) {
src_cb += (width + 1) / 2;
src_cr += (width + 1) / 2;
}
dst_rgb -= rgb_stride;
}
}
amsn-0.98.9/utils/webcamsn/src/libmimic.dsp 0000755 0001750 0001750 00000007254 10734050401 020421 0 ustar billiob billiob # Microsoft Developer Studio Project File - Name="libmimic" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Static Library" 0x0104
CFG=libmimic - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "libmimic.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "libmimic.mak" CFG="libmimic - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "libmimic - Win32 Release" (based on "Win32 (x86) Static Library")
!MESSAGE "libmimic - Win32 Debug" (based on "Win32 (x86) Static Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "libmimic - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD BASE RSC /l 0x40c /d "NDEBUG"
# ADD RSC /l 0x40c /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ELSEIF "$(CFG)" == "libmimic - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
# ADD BASE RSC /l 0x40c /d "_DEBUG"
# ADD RSC /l 0x40c /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ENDIF
# Begin Target
# Name "libmimic - Win32 Release"
# Name "libmimic - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\bitstring.c
# End Source File
# Begin Source File
SOURCE=.\colorspace.c
# End Source File
# Begin Source File
SOURCE=.\deblock.c
# End Source File
# Begin Source File
SOURCE=.\decode.c
# End Source File
# Begin Source File
SOURCE=.\encode.c
# End Source File
# Begin Source File
SOURCE=.\fdct_quant.c
# End Source File
# Begin Source File
SOURCE=.\idct_dequant.c
# End Source File
# Begin Source File
SOURCE=.\mimic.c
# End Source File
# Begin Source File
SOURCE=.\vlc_common.c
# End Source File
# Begin Source File
SOURCE=.\vlc_decode.c
# End Source File
# Begin Source File
SOURCE=.\vlc_encode.c
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\constants.h
# End Source File
# Begin Source File
SOURCE=.\glib_replacement.h
# End Source File
# Begin Source File
SOURCE=".\mimic-private.h"
# End Source File
# Begin Source File
SOURCE=.\mimic.h
# End Source File
# End Group
# End Target
# End Project
amsn-0.98.9/utils/webcamsn/src/fdct_quant.c 0000644 0001750 0001750 00000011424 10225230720 020406 0 ustar billiob billiob /* Copyright (C) 2005 Ole André Vadla Ravnås
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "mimic-private.h"
extern guchar _col_zag[64];
void _fdct_quant_block(MimCtx *ctx, gint *block, const guchar *src,
gint stride, gboolean is_chrom, gint num_coeffs)
{
gint sum1, sum2, sum3, sum4;
gint diff1, diff2, diff3, diff4;
gint ex1, ex2, ex3, ex4, ex5;
gint i, j;
const guchar *p1;
gint *iptr;
/*
* Forward DCT, first pass (horizontal).
*/
p1 = src;
iptr = block;
for (i = 0; i < 8; i++) {
sum1 = p1[0] + p1[7];
sum2 = p1[1] + p1[6];
sum3 = p1[2] + p1[5];
sum4 = p1[3] + p1[4];
diff1 = p1[0] - p1[7];
diff2 = p1[1] - p1[6];
diff3 = p1[2] - p1[5];
diff4 = p1[3] - p1[4];
ex1 = ((diff1 + diff4) * 851) - (diff1 * 282);
ex2 = ((diff2 + diff3) * 1004) - (diff2 * 804);
ex3 = ((diff2 + diff3) * 1004) - (diff3 * 1204);
ex4 = ((diff1 + diff4) * 851) - (diff4 * 1420);
iptr[0] = sum1 + sum2 + sum3 + sum4;
iptr[2] = (((sum1 - sum4) * 1337) + ((sum2 - sum3) * 554)) >> 10;
iptr[4] = sum1 - sum2 - sum3 + sum4;
iptr[1] = (ex1 + ex2 + ex3 + ex4) >> 10;
iptr[3] = ((ex4 - ex2) * 181) >> 17;
iptr[5] = ((ex1 - ex3) * 181) >> 17;
p1 += stride;
iptr += 8;
}
p1 = src;
iptr = block;
/*
* Forward DCT, first pass (vertical).
*
* This is only known to be correct for i == 0, though it seems to be ...
*/
for (i = 0; i < 6; i++) {
sum1 = iptr[ 0 + i] + iptr[56 + i];
sum2 = iptr[ 8 + i] + iptr[48 + i];
sum3 = iptr[16 + i] + iptr[40 + i];
sum4 = iptr[24 + i] + iptr[32 + i];
diff1 = iptr[ 0 + i] - iptr[56 + i];
diff2 = iptr[ 8 + i] - iptr[48 + i];
diff3 = iptr[16 + i] - iptr[40 + i];
diff4 = iptr[24 + i] - iptr[32 + i];
ex1 = ((diff1 + diff4) * 851) - (diff1 * 282);
ex2 = ((diff2 + diff3) * 1004) - (diff2 * 804);
ex3 = ((diff2 + diff3) * 1004) - (diff3 * 1204);
ex4 = ((diff1 + diff4) * 851) - (diff4 * 1420);
ex5 = (sum1 + sum2 - sum3 - sum4) * 554;
for (j = 0; j < 7 - i; j++) {
switch (j) {
case 0:
iptr[ 0 + i] = (16 + sum1 + sum2 + sum3 + sum4) >> 5;
break;
case 1:
iptr[ 8 + i] = (16384 + ex1 + ex2 + ex3 + ex4) >> 15;
break;
case 2:
iptr[16 + i] = (16384 + ((sum1 - sum4) * 783) + ex5) >> 15;
break;
case 3:
iptr[24 + i] = (8192 + (((ex4 - ex2) >> 8) * 181)) >> 14;
break;
case 4:
iptr[32 + i] = (16 + sum1 - sum2 - sum3 + sum4) >> 5;
break;
case 5:
iptr[40 + i] = (8192 + (((ex1 - ex3) >> 8) * 181)) >> 14;
break;
case 6:
iptr[48 + i] = (16384 - ((sum2 - sum3) * 1891) + ex5) >> 15;
break;
}
}
}
/*
* Quantize.
*/
block[0] /= 2;
block[8] /= 4;
block[1] /= 4;
block[6] = 0;
if (num_coeffs > 3) {
gdouble s = (10000 - ctx->quality) * 10.0 * (gfloat) 9.9999997e-5;
if (s > 10.0)
s = 10.0;
else if (is_chrom != 0 && s < 1.0)
s = 1.0;
else if (s < 2.0)
s = 2.0;
s = 1.0 / s;
for (i = 3; i < num_coeffs; i++) {
gdouble coeff, r;
coeff = block[_col_zag[i]] * s;
r = coeff - (gint) coeff;
if (r >= 0.6)
block[_col_zag[i]] = (gint) (coeff + 1.0);
else if (r <= -0.6)
block[_col_zag[i]] = (gint) (coeff - 1.0);
else
block[_col_zag[i]] = (gint) coeff;
if (block[_col_zag[i]] > 120)
block[_col_zag[i]] = 120;
else if (block[_col_zag[i]] < -120)
block[_col_zag[i]] = -120;
}
}
if (block[8] > 120)
block[8] = 120;
else if (block[8] < -120)
block[8] = -120;
if (block[1] > 120)
block[1] = 120;
else if (block[1] < -120)
block[1] = -120;
for (i = num_coeffs; i < 64; i++)
block[_col_zag[i]] = 0;
}
amsn-0.98.9/utils/webcamsn/src/vlc_decode.c 0000644 0001750 0001750 00000006756 10225230720 020361 0 ustar billiob billiob /* Copyright (C) 2005 Ole Andr Vadla Ravns
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include
#include "mimic-private.h"
extern guchar _col_zag[64];
/*
* _vlc_decode_block
*
* De-serialize (reconstruct) a variable length coded 8x8 block.
*/
gboolean _vlc_decode_block(MimCtx *ctx, gint *block, gint num_coeffs)
{
guint pos;
memset(block, 0, 64 * sizeof(gint));
/* The DC-value is read in as is. */
block[0] = _read_bits(ctx, 8);
for (pos = 1; pos < num_coeffs; pos++) {
guint prev_data_index, prev_cur_chunk_len, prev_chunk;
guint value, num_bits;
gboolean prev_read_odd, found_magic;
/* Save context. */
prev_data_index = ctx->data_index;
prev_cur_chunk_len = ctx->cur_chunk_len;
prev_chunk = ctx->cur_chunk;
prev_read_odd = ctx->read_odd;
/* Grab 16 bits. */
value = _read_bits(ctx, 16) << 16;
/* Restore context. */
ctx->data_index = prev_data_index;
ctx->cur_chunk_len = prev_cur_chunk_len;
ctx->cur_chunk = prev_chunk;
ctx->read_odd = prev_read_odd;
/* Analyze and determine number of bits to read initially. */
num_bits = 3;
if ((value >> 30) == 0 || (value >> 30) == 1) {
num_bits = 2;
} else if ((value & 0xE0000000) != 0x80000000) {
guint nibble = value >> 28;
if (nibble == 11 || nibble == 12) {
num_bits = 4;
} else if (nibble == 10) {
_read_bits(ctx, 4);
return TRUE;
} else {
if (((value << 2) & 0x8000000) == 0)
num_bits = 2;
num_bits += 2;
}
}
/* Read that number of bits. */
value = _read_bits(ctx, num_bits);
/*
* Look up the current value against the magic ones,
* and continue extending it bit by bit from the input
* stream until the magic value is found or we have
* read 32 bits (in which case we give up).
*/
found_magic = FALSE;
while (!found_magic) {
VlcMagic *magic;
if (num_bits > 32)
return FALSE;
magic = _find_magic(value);
if (magic != NULL) {
pos += magic->pos_add;
num_bits = magic->num_bits;
found_magic = TRUE;
} else {
value <<= 1;
value |= _read_bits(ctx, 1);
num_bits++;
}
}
/* Read the number of bits given by magic value entry. */
value = _read_bits(ctx, num_bits);
/* Gotcha! :-) */
block[_col_zag[pos]] = ctx->vlcdec_lookup[(num_bits * 255) + value];
}
return TRUE;
}
amsn-0.98.9/utils/webcamsn/src/decode.c 0000644 0001750 0001750 00000021503 10225230720 017500 0 ustar billiob billiob /* Copyright (C) 2005 Ole Andr Vadla Ravns
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include
#include "mimic-private.h"
static gboolean decode(MimCtx *ctx, gboolean is_pframe);
/**
* Decode a MIMIC-encoded frame into RGB data.
*
* @param ctx the mimic context
* @param input_buffer buffer containing the MIMIC-encoded frame to decode
* @param output_buffer buffer that will receive the decoded frame in RGB 24-bpp packed pixel top-down format
* (use #mimic_get_property to determine the required buffer size, as well as frame width and height)
* @returns #TRUE on success
*/
gboolean mimic_decode_frame(MimCtx *ctx,
const guchar *input_buffer,
guchar *output_buffer)
{
gboolean result, is_pframe;
guchar *input_y, *input_cr, *input_cb;
gint width, height;
/*
* Some sanity checks.
*/
if (ctx == NULL || input_buffer == NULL || output_buffer == NULL)
{
return FALSE;
}
if (!ctx->decoder_initialized)
return FALSE;
/*
* Get frame dimensions.
*/
width = GUINT16_FROM_LE(*((guint16 *) (input_buffer + 4)));
height = GUINT16_FROM_LE(*((guint16 *) (input_buffer + 6)));
/*
* Resolution changing is not supported.
*/
if (width != ctx->frame_width ||
height != ctx->frame_height)
{
return FALSE;
}
/*
* Increment frame counter.
*/
ctx->frame_num++;
/*
* Initialize state.
*/
ctx->quality = GUINT16_FROM_LE(*((guint16 *) (input_buffer + 2)));
is_pframe = GUINT32_FROM_LE(*((guint32 *) (input_buffer + 12)));
ctx->num_coeffs = input_buffer[16];
ctx->data_buffer = (gchar *) (input_buffer + 20);
ctx->data_index = 0;
ctx->cur_chunk_len = 16;
ctx->read_odd = FALSE;
/*
* Decode frame.
*/
if (!(is_pframe && ctx->prev_frame_buf == NULL))
result = decode(ctx, is_pframe);
else
result = FALSE;
/*
* Perform YUV 420 to RGB conversion.
*/
input_y = ctx->cur_frame_buf;
input_cr = ctx->cur_frame_buf + ctx->y_size;
input_cb = ctx->cur_frame_buf + ctx->y_size + ctx->crcb_size;
_yuv_to_rgb(input_y,
input_cb,
input_cr,
output_buffer,
ctx->frame_width,
ctx->frame_height);
return result;
}
/*
* decode_main
*
* Main decoding loop.
*/
static gboolean decode(MimCtx *ctx, gboolean is_pframe)
{
gint y, x, i, j, chrom_ch, *bptr, base_offset, offset;
gint dct_block[64];
guchar *src, *dst, *p;
guint32 bit;
/*
* Clear Cr and Cb planes.
*/
p = ctx->cur_frame_buf + ctx->y_size;
memset(p, 128, 2 * ctx->crcb_size);
/*
* Decode Y plane.
*/
for (y = 0; y < ctx->num_vblocks_y; y++) {
base_offset = ctx->y_stride * 8 * y;
src = ctx->prev_frame_buf + base_offset;
dst = ctx->cur_frame_buf + base_offset;
for (x = 0; x < ctx->num_hblocks_y; x++) {
/* Check for a change condition in the current block. */
if (is_pframe)
bit = _read_bits(ctx, 1);
else
bit = 0;
if (bit == 0) {
/* Yes: Is the new content the same as it was in one of
* the 15 last frames preceding the previous? */
if (is_pframe)
bit = _read_bits(ctx, 1);
if (bit == 0) {
/* No: decode it. */
if (_vlc_decode_block(ctx, dct_block, ctx->num_coeffs) == FALSE) {
/* Corruped frame, return. */
return FALSE;
}
_idct_dequant_block(ctx, dct_block, 0);
bptr = dct_block;
for (i = 0; i < 8; i++) {
offset = ctx->y_stride * i;
for (j = 0; j < 8; j++) {
guint v;
if (bptr[j] <= 255)
v = (bptr[j] >= 0) ? bptr[j] : 0;
else
v = 255;
*(dst + offset + j) = v;
}
bptr += 8;
}
} else {
guint32 backref;
/* Yes: read the backreference (4 bits) and copy. */
backref = _read_bits(ctx, 4);
p = ctx->buf_ptrs[(ctx->ptr_index + backref) % 16];
p += base_offset + (x * 8);
for (i = 0; i < 8; i++) {
offset = ctx->y_stride * i;
memcpy(dst + offset, p + offset, 8);
}
}
} else {
/* No change no worries: just copy from the previous frame. */
for (i = 0; i < 8; i++) {
offset = ctx->y_stride * i;
memcpy(dst + offset, src + offset, 8);
}
}
src += 8;
dst += 8;
}
}
/*
* Decode Cr and Cb planes.
*/
for (chrom_ch = 0; chrom_ch < 2; chrom_ch++) {
base_offset = ctx->y_size + (ctx->crcb_size * chrom_ch);
for (y = 0; y < ctx->num_vblocks_cbcr; y++) {
guint num_rows = 8;
/* The last row of blocks in chrominance for 160x120 resolution
* is half the normal height and must be accounted for. */
if (y + 1 == ctx->num_vblocks_cbcr && ctx->frame_height % 16 != 0)
num_rows = 4;
offset = base_offset + (ctx->crcb_stride * 8 * y);
src = ctx->prev_frame_buf + offset;
dst = ctx->cur_frame_buf + offset;
for (x = 0; x < ctx->num_hblocks_cbcr; x++) {
/* Check for a change condition in the current block. */
if (is_pframe)
bit = _read_bits(ctx, 1);
else
bit = 1;
if (bit == 1) {
/* Yes: decode it. */
if (_vlc_decode_block(ctx, dct_block, ctx->num_coeffs) == FALSE) {
/* Corrupted frame: clear Cr and Cb planes and return. */
p = ctx->cur_frame_buf + ctx->y_size;
memset(p, 128, ctx->crcb_size * 2);
return FALSE;
}
_idct_dequant_block(ctx, dct_block, 1);
for (i = 0; i < num_rows; i++) {
p = dst + (ctx->crcb_stride * i);
for (j = 0; j < 8; j++)
p[j] = dct_block[(i * 8) + j];
}
} else {
/* No change no worries: just copy from the previous frame. */
for (i = 0; i < num_rows; i++) {
offset = ctx->crcb_stride * i;
memcpy(dst + offset, src + offset, 8);
}
}
src += 8;
dst += 8;
}
}
}
/*
* Make a copy of the current frame and store in
* the circular pointer list of 16 entries.
*/
ctx->prev_frame_buf = ctx->buf_ptrs[ctx->ptr_index];
memcpy(ctx->prev_frame_buf, ctx->cur_frame_buf,
ctx->y_size + (ctx->crcb_size * 2));
if (--ctx->ptr_index < 0)
ctx->ptr_index = 15;
/*
* Perform deblocking on all planes.
*/
_deblock(ctx->cur_frame_buf,
ctx->y_stride, ctx->y_row_count);
_deblock(ctx->cur_frame_buf + ctx->y_size,
ctx->crcb_stride, ctx->crcb_row_count);
_deblock(ctx->cur_frame_buf + ctx->y_size + ctx->crcb_size,
ctx->crcb_stride, ctx->crcb_row_count);
return TRUE;
}
amsn-0.98.9/utils/webcamsn/src/constants.h 0000644 0001750 0001750 00000150311 10250007176 020303 0 ustar billiob billiob int shifts_right[] = {
25,
20,
15,
10,
27,
23,
18,
12,
28,
21,
16,
9,
26,
22,
17,
11
};
int shifts_left[] = {
7,
12,
17,
22,
5,
9,
14,
20,
4,
11,
16,
23,
6,
10,
15,
21
};
int choose_data_idx[] = {
0,
7,
14,
5,
12,
3,
10,
1,
8,
15,
6,
13,
4,
11,
2,
9
};
int const_mult[] = {
-1,
-1,
+1,
-1,
-1,
+1,
-1,
-1,
+1,
-1,
-1,
-1,
+1,
-1,
-1,
+1,
-1,
-1,
+1,
-1,
-1,
+1,
-1,
-1,
+1,
-1,
-1,
+1,
-1,
-1,
+1,
-1,
-1,
-1,
+1,
-1,
-1,
+1,
-1,
-1,
+1,
-1,
-1,
+1,
-1,
-1,
+1,
-1,
-1,
+1,
-1,
-1,
+1,
-1,
-1,
-1,
+1,
-1,
-1,
+1,
-1,
-1,
+1,
-1,
};
int const_values[] = {
0x28955B88,
0x173848AA,
0x242070DB,
0x3E423112,
0x0A83F051,
0x4787C62A,
0x57CFB9ED,
0x2B96AFF,
0x698098D8,
0x74BB0851,
0x0A44F,
0x76A32842,
0x6B901122,
0x2678E6D,
0x5986BC72,
0x49B40821,
0x9E1DA9E,
0x3FBF4CC0,
0x265E5A51,
0x16493856,
0x29D0EFA3,
0x2441453,
0x275E197F,
0x182C0438,
0x21E1CDE6,
0x3CC8F82A,
0x0B2AF279,
0x455A14ED,
0x561C16FB,
0x3105C08,
0x676F02D9,
0x72D5B376,
0x5C6BE,
0x788E097F,
0x6D9D6122,
0x21AC7F4,
0x5B4115BC,
0x4BDECFA9,
0x944B4A0,
0x41404390,
0x289B7EC6,
0x155ED806,
0x2B10CF7B,
0x4881D05,
0x262B2FC7,
0x1924661B,
0x1FA27CF8,
0x3B53A99B,
0x0BD6DDBC,
0x432AFF97,
0x546BDC59,
0x36C5FC7,
0x655B59C3,
0x70F3336E,
0x100B83,
0x7A7BA22F,
0x6FA87E4F,
0x1D31920,
0x5CFEBCEC,
0x4E0811A1,
0x8AC817E,
0x42C50DCB,
0x2AD7D2BB,
0x14792C6F
};
static int append_size = 16;
static int key_append[] = {
0x7CF1DC2C, 0x57A3C467, 0x16DE0737, 0x5AF79D21,
0x1E020846, 0x0A8C89907, 0x216BE734, 0x1FF75D58,
0x9B9197A, 0x4C0F074F, 0x760BF742, 0x416CCB1F,
0x36BB041F, 0x0B532FC6E, 0x2D778922, 0x0F8548D07,
0x978C7807, 0x6292C537, 0x9F364930, 0x0C28BF77C,
0x0A7BD6244, 0x6772C34F, 0x65C47E56, 0x8D9CE01F,
0x22D06933, 0x0F5E40729, 0x80EF8448, 0x7761C03C,
0x1E95114F, 0x2767BBE, 0x10B491B7, 0x25B4F277,
0x4474CAC0, 0x6CA5F2C8, 0x56261D13, 0x1C9098F6,
0x5A989670, 0x0B084C431, 0x16A75876, 0x6351B06A,
0x0FC93CB00, 0x8CB24F39, 0x0A4BD7B0A, 0x324FD01F,
0x41E54B28, 0x0D134052D, 0x2AA45D27, 0x0D871C42F,
0x33C7CA64, 0x0C9DAA657, 0x9AFDBB2C, 0x0DB842D29,
0x314D6A27, 0x0C23A03, 0x68210E49, 0x531DD45A,
0x0F5A6422C, 0x0E8109311, 0x0CA7E9417, 0x0ADD7A45A,
0x691BC101, 0x65708949, 0x0E2F9E335, 0x41C9B359,
0x16408632, 0x7113C132, 0x3879AE77, 0x70D81C23,
0x21988564, 0x4E20076E, 0x0D329CD0D, 0x1D2C5165,
0x0DAD25627, 0x78E74818, 0x507B2105, 0x1BB8A24F,
0x491C4E45, 0x7A1F7F2C, 0x0F329677F, 0x7DE3182A,
0x44FA2504, 0x8E27232C, 0x58684653, 0x7547902B,
0x8EE95D2F, 0x0C089541C, 0x0C8646406, 0x8390A05B,
0x0A89AE72D, 0x92E3F81D, 0x30684536, 0x11B6A82F,
0x0F7538267, 0x1262296C, 0x527F5C09, 0x0D94081A,
0x8375EA1E, 0x8AF80A01, 0x7E6C253D, 0x0A40D7003,
0x0D818126F, 0x5196F24A, 0x0C239C168, 0x0B2EB6816,
0x4DBD36D, 0x1E2AD595, 0x2FF01C9A, 0x46355255,
0x713F1209, 0x67294722, 0x739FC0E0, 0x1D6F30D9,
0x4FF59511, 0x0E8E5E825, 0x4516184A, 0x0DDDEF340,
0x0A86F3D42, 0x0D7B7C50, 0x606F941C, 0x500A2570,
0x9F5E756E, 0x90D7D952, 0x61C0CD1F, 0x96B2F755,
0x0A339033F, 0x0B33F2A29, 0x0A4460070, 0x26AFED5D,
0x3E38352A, 0x22B3252D, 0x0CBBC5D61, 0x16514719,
0x73491878, 0x8DF61E4A, 0x0C93CB02F, 0x3DC7535B,
0x9FAB0138, 0x96E0BB15, 0x5061DD03, 0x2B806352,
0x4065FD94, 0x1C53F61D, 0x0E8BFF29, 0x720EE35A,
0x77617F2, 0x748CA63A, 0x5A3A3B0F, 0x8D73FEF,
0x4FE07F0B, 0x0E3F14C6A, 0x0C03ECB2E, 0x0EE3EF579,
0x3F5E8FC5, 0x2695CBCB, 0x1062C762, 0x3C76F926,
0x0D43EC377, 0x2938ED3F, 0x3DB2175A, 0x1277F821,
0x7E11198, 0x51E7CE90, 0x6E87ABC4, 0x60F42887,
0x95659405, 0x0F204F06A, 0x0FBFB7E40, 0x3411963D,
0x88E5AB00, 0x4B5D5C44, 0x6091F90F, 0x0E093DA7B,
0x2B3CDC1A, 0x5CE0E400, 0x86379F08, 0x0F3004517,
0x9D45E83B, 0x0ABA5756, 0x6335EB55, 0x0EC256847,
0x0EDABA440, 0x2374B604, 0x0DB645D41, 0x6175CB7D,
0x44734F53, 0x60564A11, 0x7878F579, 0x19B2124B,
0x4B64A19A, 0x7126B6A7, 0x4E7283BB, 0x587C840,
0x0BE99820F, 0x54F14A28, 0x92AE7523, 0x54FF1615,
0x355901F4, 0x77DCAA71, 0x65812158, 0x588BF36,
0x0D9075128, 0x0E8A1A662, 0x0AF6FC10F, 0x5442D43,
0x44828B63, 0x35A76018, 0x0F844725A, 0x0E2C7731F,
0x3F61B86E, 0x5C7A5D30, 0x0CEEDDB66, 0x2D0D5D2F,
0x7FEE1335, 0x0A9523928, 0x8E82282D, 0x0C4616308,
0x9A98339, 0x7FB1D27, 0x0DD137653, 0x9237BB0A,
0x3CE4F397, 0x2F917E1F, 0x11340243, 0x6A8D5D9E,
0x533CDE8C, 0x233EDF91, 0x482C1D41, 0x19B8FF0E,
0x870A7050, 0x58CF7172, 0x7200EE0F, 0x6012C178,
0x40711855, 0x2170AF1F, 0x6556EE3B, 0x85F3A338,
0x57171038, 0x5E9B6016, 0x67BB1758, 0x9678C826,
0x0BA15BE46, 0x35A9F33E, 0x0C3852556, 0x3904D27B,
0x0DFFB2C67, 0x52084E03, 0x0FD653504, 0x0E8A4B020,
0x59036C2A, 0x0DA79AB57, 0x7BDC6B2B, 0x16299725,
0x0E3B62C18, 0x0E18D7174, 0x91E84430, 0x40E5F800,
0x0DAEDEC60, 0x61A70950, 0x0E309007D, 0x61F85C31,
0x0B9767B42, 0x560AEE0C, 0x0C20A1E2A, 0x0F9E79317,
0x0D2429AC, 0x1A8B7DC9, 0x23C53AAF, 0x54F6BB51,
0x85FC6C7C, 0x0E5964F28, 0x650A760B, 0x3F122B43,
0x1C2A10BF, 0x745FD9F3, 0x635FDCED, 0x25BFDAF4,
0x7A98E964, 0x767C3243, 0x0E2E0206F, 0x0D39B550F,
0x217C7136, 0x202AAD48, 0x2B137203, 0x272EC36A,
0x3F4BFE0E, 0x7BAD3165, 0x74920334, 0x1939EB6F,
0x0DC543B35, 0x579C0331, 0x7B314821, 0x95CBB677,
0x0ADA6F13D, 0x3D3C664B, 0x8EB34A0F, 0x25218F6A,
0x649D7231, 0x0D8F825F, 0x0F3B23C4F, 0x0EA99DF2D,
0x0F225D207, 0x58BDB25A, 0x29AC0A71, 0x0D66156F,
0x32B9FBC9, 0x27974E36, 0x6CD9C3AE, 0x29F77886,
0x193F3A73, 0x0EA82A62C, 0x0CF818D30, 0x6A35180E,
0x47403347, 0x0B8467A65, 0x9EE22241, 0x868B3156,
0x33F4AB4A, 0x12752675, 0x0A0C41C46, 0x0F49E77F,
0x69112A26, 0x1BF66467, 0x0A4149E77, 0x17B81B64,
0x5832CB32, 0x33C8E806, 0x3CD9AA4E, 0x0BCCF3D64,
0x40576B66, 0x2F8CE71D, 0x0A6691D12, 0x327D3D6E,
0x88499A78, 0x0D0152803, 0x40E3525D, 0x997E834,
0x72D82F33, 0x4785D81A, 0x47D2056, 0x8B176A26,
0x31087F47, 0x0D3FEAD06, 0x0F54C8234, 0x7948B20E,
0x8C45286C, 0x932FA575, 0x0FFD3E364, 0x0BF39D436,
0x0A5A4CB6A, 0x9F98002B, 0x0CF82BB36, 0x0FB6F510,
0x0BA8E6512, 0x7397592E, 0x266E1175, 0x12C13045,
0x0A65F4235, 0x6247BC43, 0x0CF906E29, 0x0E6B6AD1B,
0x1CA3FF31, 0x7FEB2E53, 0x7F398F82, 0x134EF25D,
0x4510B43E, 0x59173E67, 0x22B4260F, 0x0B8E8E371,
0x0A09C1602, 0x27314765, 0x43004E18, 0x0D2A49549,
0x0FA2FF56B, 0x394DD04C, 0x4BED4758, 0x86751D58,
0x0CC7C7542, 0x4AC12B3D, 0x46AFF10E, 0x7221412D,
0x0EA592C68, 0x1532AD45, 0x81D7363E, 0x0A4E8917A,
0x347EEFC2, 0x3B056C76, 0x3A5030C6, 0x3BD5B048,
0x98D0477, 0x863A3169, 0x15E0F644, 0x9A60A858,
0x0FB34BD24, 0x2E14E24E, 0x0B47DE632, 0x41457163,
0x872B2036, 0x0D6310D42, 0x0F92D5555, 0x28C83638,
0x0FD625427, 0x3C2EA36D, 0x0FA6CCC01, 0x0F8924913,
0x757B733A, 0x455A145A, 0x7E08676B, 0x42F8E87C,
0x8F1B4017, 0x0C4B7587A, 0x0B4192A2A, 0x79756C7F,
0x0D9E90540, 0x35F16068, 0x1E5EFE79, 0x62B30C34,
0x0DC36A91B, 0x0D507C139, 0x91DC555D, 0x0E5C3AD12,
0x5B42F222, 0x0A6BC4C22, 0x7F24566B, 0x5677AF47,
0x0D5D02E71, 0x33A23C1E, 0x97BC202B, 0x5CFC4E27,
0x0AD44960, 0x90EA7500, 0x84C4855F, 0x7379E07,
0x0CD18196E, 0x7E315261, 0x0FFC9E71A, 0x42948C28,
0x0C38B663B, 0x7ED24E06, 0x848C7525, 0x53A7A652,
0x428AA700, 0x38A69F4F, 0x0CC1C1352, 0x1C74AD40,
0x6D970038, 0x0EA7A114C, 0x7E27BA74, 0x49CEA953,
0x0BF82D205, 0x0F041052, 0x2E925766, 0x1AC5C428,
0x0B5C05C74, 0x0AEB6AD51, 0x713C7470, 0x8A918B65,
0x0E158EA6F, 0x8F9941B, 0x0E78DDA0C, 0x0EB2C3450,
0x99E30A1C, 0x6B52606C, 0x0F363D257, 0x66FC230A,
0x0EA83B24D, 0x0F22DBA72, 0x0A890B032, 0x0AD0F1909,
0x70000979, 0x2D1D2658, 0x0B7BF5B, 0x0B38AB079,
0x65C3C527, 0x0CDD3D22D, 0x0CFFE5D3A, 0x0D35AC65F,
0x0B74EE479, 0x4D26182F, 0x1C297033, 0x77D1B67F,
0x5C2A2801, 0x4BBBC719, 0x91967B28, 0x11EB8475,
0x0F971756B, 0x2D3EF18, 0x9C7C105B, 0x0DACA5F5B,
0x0BCC8434, 0x830AEB67, 0x0C6F7932B, 0x0A4AF8F50,
0x0EE5C4B54, 0x0B95B6603, 0x0AACB35A, 0x0D8E0FD21,
0x0AB892076, 0x0B23C640D, 0x86F0162B, 0x1C8A296F,
0x0DF598A65, 0x86A7D606, 0x0CF14DA68, 0x451D500D,
0x537BA934, 0x9E133823, 0x1878166D, 0x0BCA8D2E,
0x0EB395052, 0x34A18620, 0x829B442E, 0x47647853,
0x7F5C4E3A, 0x1332C056, 0x584FFD48, 0x78CEC325,
0x1605B06F, 0x0F4CB0D24, 0x53992301, 0x21D13424,
0x77D6F80B, 0x1991B72C, 0x0C580C474, 0x66334460,
0x0D2EC1D30, 0x0CF2C784F, 0x3E144202, 0x7D763E26,
0x8169DC5C, 0x0C404592D, 0x99006815, 0x61C36642,
0x4BAC2F34, 0x6815427E, 0x0A6E0B64F, 0x9E27D968,
0x6297A21, 0x0BE58CD3C, 0x0A9F16617, 0x0F162CA73,
0x0F2F9535D, 0x2B8DAB45, 0x38C74247, 0x7256A217,
0x3FBF6B1C, 0x91164010, 0x0EA24663D, 0x55C41B0C,
0x85E24D34, 0x3DBE893E, 0x76955030, 0x0FDB84640,
0x564F416B, 0x3B161525, 0x63EC8A20, 0x283C5F1B,
0x0A438D74, 0x0A100CD22, 0x0A6B29D41, 0x8BAC6951,
0x66052650, 0x3FB30557, 0x0EC6FD013, 0x0B1B15504,
0x0A8C84755, 0x92508763, 0x4FD92E6D, 0x0AEF1C176,
0x50A95420, 0x0F9CA9504, 0x0A0548C6A, 0x43A3A87D,
0x2458414A, 0x0D81BCF31, 0x0B5F94A15, 0x6317AD66,
0x28C1C503, 0x7A9F959D, 0x731C7C51, 0x162A3DBF,
0x0DDDC3A11, 0x2E711923, 0x0ECCDA336, 0x332C7C7C,
0x69872E48, 0x4FBA2E57, 0x5C68DB17, 0x73CABB3C,
0x0F0BAFB79, 0x21B7959, 0x0FF76250E, 0x56C0214A,
0x41CE7E30, 0x0EBE6F521, 0x772774E, 0x0E996C605,
0x7E377D05, 0x574BA63B, 0x9888887C, 0x0CEE0D125,
0x50163C40, 0x38DD1467, 0x11847A23, 0x746E7D0A,
0x1CCDE544, 0x36F81567, 0x28B6E831, 0x3672427D,
0x669C760B, 0x9061F363, 0x69405051, 0x4379B11C,
0x0BFD20C07, 0x550EF407, 0x76A52D19, 0x285A3B4F,
0x0A4C8225F, 0x0D20D0931, 0x9C24F70B, 0x94831E59,
0x0D428820A, 0x9B9B1C1A, 0x0EB434023, 0x16F7003B,
0x8682123C, 0x0F2B5B771, 0x0FF8DC740, 0x4BA8F41,
0x49015E2D, 0x9716503D, 0x0D39A6167, 0x99179A6D,
0x0CFF36424, 0x0E41EDC0A, 0x0E861778, 0x0E0EC483D,
0x0AB9CA143, 0x0E60B4269, 0x5A183C18, 0x1139184F,
0x766D354D, 0x0C3588C69, 0x54B2C96B, 0x35404254,
0x18678071, 0x0CA57F704, 0x5E9A7D23, 0x0BC2FA350,
0x9D650036, 0x0FABE742F, 0x50B3C129, 0x718E8240,
0x955A9149, 0x3BF7014D, 0x8785837B, 0x1BDDA305,
0x2EADB93E, 0x87134B3C, 0x20973347, 0x77AE176C,
0x1E2A9B79, 0x0F331952E, 0x11C6B159, 0x0EE1D001E,
0x0D7507139, 0x1F4CC951, 0x0CE0A495B, 0x82ED127D,
0x5580B3B, 0x28238573, 0x93262B4C, 0x7BC54008,
0x0EB7B115D, 0x0E7D8F437, 0x0B105835C, 0x3E3914E,
0x0B230EC3C, 0x0FA00000, 0x0BF12351F, 0x4F96EC72,
0x95F752F, 0x0FC6F648, 0x0C0246F33, 0x9EB90679,
0x4BBDF815, 0x48AAF22E, 0x0B996AA7E, 0x796AB254,
0x0CFBD3D6B, 0x0D92DDE45, 0x0F018CA40, 0x0EDE7D864,
0x0CC5F7374, 0x1DF7B1A, 0x0DB05D902, 0x0A4B0E42D,
0x0AA6C8E, 0x5557C67F, 0x7426E5D7, 0x6AFE2A4D,
0x0D133A751, 0x0BAC42277, 0x0A148912F, 0x0BCAFB82E,
0x0A19D172F, 0x524E140C, 0x0BF924A7D, 0x53CE036C,
0x61EE140C, 0x7EA57F1C, 0x0A264F05E, 0x6A4D8A3B,
0x8E6B7665, 0x63895F12, 0x8079134, 0x0D9286F7B,
0x0AB335241, 0x0C19D3B33, 0x52932150, 0x7AF18F2C,
0x9BCB1979, 0x42ACEB10, 0x67D96811, 0x672B8D6D,
0x448B672B, 0x43DF4114, 0x0BDC711B, 0x64B6AC17,
0x0ECEF6372, 0x327A6946, 0x8A39FD3E, 0x0BE230B44,
0x0EC3E8C3D, 0x2B828E6E, 0x7AD3C372, 0x8DDCA36C,
0x7DD0A27A, 0x3A660E70, 0x0E1AAA758, 0x0DEBEB706,
0x0B80B8E0C, 0x830F9837, 0x480C4242, 0x46770472,
0x0E698F749, 0x5013D376, 0x1FA0736D, 0x91CC490B,
0x11B10E2A, 0x7133953D, 0x0BBED937, 0x0AC7C2823,
0x0B4DF804E, 0x73974249, 0x14A8B510, 0x0F86AE879,
0x0B676845D, 0x1F84272C, 0x5C219511, 0x0A266E84F,
0x558F3B68, 0x2A1F517E, 0x5DD4478, 0x1DF2B6A5,
0x11DD203F, 0x0DB5DB706, 0x0CB19C11C, 0x8EADC339,
0x15C4C576, 0x0ACC46875, 0x6C6C7B40, 0x0CDCF5303,
0x2FD4002D, 0x0B478BD02, 0x14475875, 0x166DF876,
0x48C9079, 0x33E7CB62, 0x0A7394202, 0x163D9F23,
0x0A51A6120, 0x0B3F71B3A, 0x0C2B9C746, 0x59FAE16E,
0x4B81B6D7, 0x2225D215, 0x710855B9, 0x0C04D7C7,
0x0F6E5A403, 0x0AD865F7A, 0x7E6CCB30, 0x47E43576,
0x94E1F14A, 0x0DFF6BE44, 0x85215326, 0x0A5BE120A,
0x0BA54764B, 0x503B1443, 0x346CD643, 0x0CF183C42,
0x0FCFF7C38, 0x0A0D85104, 0x9CE88F45, 0x2BD47D65,
0x33B77714, 0x4A99DE4E, 0x7362F998, 0x183BB70,
0x0E416B41D, 0x0E97AB85E, 0x6F1A3F24, 0x8931153E,
0x9C72D418, 0x32D4066B, 0x0E22BF72C, 0x0C201331C,
0x8368442, 0x3391C115, 0x9E07167D, 0x0FE1B2946,
0x10D2F8DD, 0x19B12FD, 0x7D71AAF6, 0x579940E8,
0x0FB6AA072, 0x0CB21B262, 0x1AB82565, 0x0B5BF163E,
0x1B5DC625, 0x4E24FC28, 0x84D85200, 0x175D435E,
0x0EEFC4D2D, 0x21C1E245, 0x4231C143, 0x434E5D34,
0x0D1F0CA00, 0x84723720, 0x9D2BFD34, 0x0B5077F1E,
0x6DEDEF7E, 0x0C463C59, 0x3E39945C, 0x960C417,
0x3E1A4344, 0x20658B09, 0x0CB61F733, 0x4750C706,
0x53F64C1F, 0x69690D31, 0x456CF04C, 0x340E6E2F,
0x85DDEE5E, 0x8B6C4F09, 0x0A807810A, 0x81488F51,
0x568E016C, 0x0C2BFA66F, 0x3608A60F, 0x71EBC711,
0x10E4A218, 0x0BBE0F80F, 0x88480B70, 0x0FFE0F045,
0x0DCA1DB55, 0x0CB79CC33, 0x422F4E7A, 0x0AD92A656,
0x4FEC0354, 0x0DF5A4B2F, 0x639A2575, 0x0BCD9F352,
0x0ECA08708, 0x0A1D3B951, 0x0C539B86A, 0x2ABBCA4C,
0x0C238455B, 0x909BAF1E, 0x710B9253, 0x152F927A,
0x0F904BD4F, 0x0B7778220, 0x493D002A, 0x7EE2AB2E,
0x42E4D129, 0x0F2448134, 0x0FF2A3B00, 0x9972D315,
0x0B4042824, 0x3633E10F, 0x0A5E9B27, 0x0C5E8CA3C,
0x0F113DA1F, 0x93A6A617, 0x0C4C9BB02, 0x0CDB5B575,
0x5E20734B, 0x6F9097D, 0x7A485C4C, 0x0AD0C771F,
0x0E653552C, 0x0DDE28141, 0x69E66A72, 0x0D2F4DC34,
0x7FB63B13, 0x2E20235D, 0x0FCAFA701, 0x41EF806E,
0x0BEBBD27B, 0x6EBB3955, 0x561E1369, 0x0B7C08F4B,
0x2533BC75, 0x0A05B1313, 0x35A33B7A, 0x67178E1F,
0x92A09447, 0x35CE767A, 0x8A6135, 0x46A5BC6B,
0x6B01580A, 0x0BE8FC5C, 0x0B8E8728, 0x5C15322A,
0x9E8EA374, 0x0CF57432B, 0x29CBE71F, 0x0FCAE1640,
0x0D6504D28, 0x0A313446C, 0x0A9BB8D5F, 0x0BCA4A254,
0x81F6C52D, 0x12A2F851, 0x8E997F09, 0x0AD0141,
0x40C21B2F, 0x8A49270B, 0x419C822F, 0x0FE7DEE2A,
0x0F8046160, 0x97BA9518, 0x0B53E7E76, 0x1D381D56,
0x3716A92B, 0x0EAE1B970, 0x854FAB75, 0x0C9B63D73,
0x1FB0306B, 0x85D90C2B, 0x105CFA5E, 0x8AB18875,
0x90C10908, 0x1BEA8107, 0x0E6C6BA1F, 0x2E50AD7C,
0x0EB41C532, 0x0F92A23F, 0x2AFFC33C, 0x0C192125B,
0x0B3A5E62B, 0x0D3BA511C, 0x7D37B52F, 0x349CAC59,
0x0E55C4A6E, 0x0BD13439, 0x3449AE1A, 0x251F661D,
0x951A5C44, 0x75E5304A, 0x239D5448, 0x8E1FBD24,
0x0CA0C662, 0x0D8DBD23E, 0x0AB57DA7A, 0x44B66F0E,
0x0C3BD8C2F, 0x30A78570, 0x0D6DAD01, 0x0E26DBD1A,
0x0B680921B, 0x1DC9A760, 0x6D1F4610, 0x46429C23,
0x39B32968, 0x53E60030, 0x75924920, 0x24F5EE1A,
0x6378A36F, 0x9F910D5D, 0x0E5870176, 0x161E8A1B,
0x734C5F79, 0x62BFB625, 0x4ABA3675, 0x58A9A967,
0x6D90EB5E, 0x7E03E50F, 0x7EC80F05, 0x2AB4723,
0x0F3E8155A, 0x0A165644D, 0x90CA0448, 0x0FF88DC3C,
0x7A41370C, 0x3C22DF42, 0x433F4C4B, 0x3DFFC33B,
0x345AEA2F, 0x7A766A3C, 0x55CDBE6B, 0x4D13CFB5,
0x6E75A12D, 0x8C8CC766, 0x698C9372, 0x0A728CB15,
0x0E072C816, 0x0DE1EDD12, 0x0CB1DBA30, 0x43EB6B06,
0x7DB0EA6F, 0x0B0A5BB26, 0x5909F621, 0x0F0FC4969,
0x1265724C, 0x0A3C32C17, 0x49A6F350, 0x7FF55D2B,
0x21C71127, 0x0C76E0356, 0x82A0A54E, 0x14B02701,
0x68D46723, 0x126BAA16, 0x1339043E, 0x0E2159F2F,
0x668FA6FB, 0x2C5694B1, 0x2D596884, 0x717198FF,
0x0A8244A56, 0x3F82E441, 0x0DDA0E55B, 0x169AEB03,
0x0CB0EAC28, 0x462D794E, 0x0BEC2B619, 0x0AB81743F,
0x244C5661, 0x89E0704A, 0x0EE6CE045, 0x0A2FC4051,
0x4D0662F1, 0x1E06DA4B, 0x3D9D7964, 0x35F715A9,
0x0EA39037F, 0x0DB9F7E0B, 0x0CCE0FC68, 0x0B011526,
0x0A20E8261, 0x4E81A237, 0x1FB13C27, 0x0BE3E904,
0x60EC4C4E, 0x33EA4065, 0x0EDF88834, 0x0AF79D627,
0x8A62916E, 0x0D0EEC1F, 0x6AD0C434, 0x3287DB44,
0x4C90D061, 0x4771AA10, 0x4821C748, 0x179F7C0A,
0x8E9E235F, 0x6E47D62, 0x0C320F149, 0x0B2EA7940,
0x90C4EE2C, 0x0B18DD10F, 0x54E7BA11, 0x0CA4A1B1E,
0x6A0C23A0, 0x58241F43, 0x6C9B9FE1, 0x4A7E504A,
0x0C280C457, 0x0E216B744, 0x0EF3EC01C, 0x658F4639,
0x3098597C, 0x0EF0FC43, 0x7072303E, 0x9184A64A,
0x41DA3D29, 0x5D6BB972, 0x40FE7C72, 0x0CB3CCF17,
0x6A79A512, 0x0AACE4127, 0x0FDC3AA5C, 0x0B6097674,
0x58AAA16A, 0x5FA419DF, 0x62DD1531, 0x7EDD9EA4,
0x4CC9EF07, 0x91C9E348, 0x32C98957, 0x0DC8DDE34,
0x4257B558, 0x86B04469, 0x0A6D8F952, 0x3B5B5D50,
0x6D918A35, 0x0BD0EB42E, 0x1F990847, 0x30124F0D,
0x9F256B73, 0x0ED8C863, 0x95A19546, 0x0D0BDC46F,
0x1CC8C527, 0x514C604, 0x61426B3A, 0x5EA20351,
0x627F7F77, 0x0A140E82C, 0x29DFD268, 0x0CDF8240A,
0x4B0F2A54, 0x27A37D45, 0x83029B7E, 0x3C4F160C,
0x6D88EF6A, 0x51AB8D7D, 0x0BC2D2623, 0x0B951DF72,
0x0E2747146, 0x0EEF6AF7A, 0x96DFBD27, 0x25CC261F,
0x74A7F463, 0x3CB8B77A, 0x6027846F, 0x0E2387F19,
0x0F9C66B29, 0x7FC08C36, 0x124BCE26, 0x99ECD61C,
0x8D98551A, 0x0A7EC636D, 0x69AA9B0C, 0x0AA601B42,
0x0AC002A72, 0x0CAEC0647, 0x8031F13, 0x0E80A969,
0x6B2DEF73, 0x31E2F17B, 0x0DB78CE73, 0x0B63C1948,
0x58856F41, 0x5F7B6972, 0x0F28B2F54, 0x0C50D5F2C,
0x0B026F76F, 0x0AEB95577, 0x7F5F3E1F, 0x939B6836,
0x9CB00572, 0x153FFC46, 0x0B8678F55, 0x1158FA55,
0x51F7B341, 0x188F1345, 0x0F390796F, 0x4BBE1F6B,
0x984FA07B, 0x5DC4716, 0x0E4AAF607, 0x25E8F515,
0x0ACC8AB03, 0x4D559214, 0x0CF481158, 0x58C9D575,
0x1742995B, 0x0D74B306B, 0x66497F5F, 0x826F884F,
0x92E2267, 0x42C24D53, 0x38ACA117, 0x61B39128,
0x6D67365D, 0x49C6BBD7, 0x3C3AB4C, 0x1A77F083,
0x0D9F12663, 0x0A6202F74, 0x0E4FF166C, 0x75A22C55,
0x0BB5F2B3B, 0x9C67A641, 0x86FA262B, 0x0C57DF7C,
0x0B5F6B906, 0x798BA01A, 0x5715FF67, 0x4D465A02,
0x7E67E830, 0x3BC0F56F, 0x722E5018, 0x2A309434,
0x88158804, 0x42776170, 0x82F9692A, 0x9F572160,
0x19C3915B, 0x0E942E909, 0x21C7A92F, 0x22F1B342,
0x2B05375D, 0x59734B47, 0x84A4456B, 0x0CC42EE22,
0x84AB1C33, 0x0AB653640, 0x1DA79C58, 0x5D9D4316,
0x4C07480, 0x360A3D4D, 0x4211363F, 0x38DC5AFB,
0x9E0E5A06, 0x593A9716, 0x183D706C, 0x5305140D,
0x0D2C53731, 0x70526F54, 0x0A04B6E0F, 0x512D2062,
0x0AB126544, 0x137ABE27, 0x7B5DB416, 0x3428ED48,
0x55F11F18, 0x0FE561E41, 0x0D37F0E29, 0x6EB4B173,
0x0E799074B, 0x0F546B858, 0x91A56536, 0x129F3E28,
0x4EBA0320, 0x154AAB21, 0x0DEE12C4B, 0x0D2652053,
0x0C0AFE161, 0x0FB88C923, 0x2F036469, 0x11364716,
0x0FD2F7D68, 0x243D454, 0x1D1CD805, 0x9C3ED76E,
0x5B7D6B6B, 0x35594872, 0x0EF43EB7B, 0x2D43A31C,
0x0A5ABB746, 0x908F590B, 0x7E70C37E, 0x51BE1C0B,
0x5AA2767A, 0x2B4FAE3, 0x7F474047, 0x7E520363,
0x0F8249656, 0x5866187D, 0x66AFE93E, 0x0DFBE9D21,
0x4DADD055, 0x0F7544F75, 0x0F15DDC49, 0x9C67D475,
0x0C9FFA16, 0x0CF3F0915, 0x6ECDF448, 0x0CC4EDC78,
0x35548F9E, 0x1F620E29, 0x3F53C974, 0x791C3A28,
0x0A0132D07, 0x0FAA0FB14, 0x64372710, 0x0FB909872,
0x30FA4307, 0x537B120C, 0x28D43B0F, 0x0D5A5FB4D,
0x0E30A6C17, 0x0A744FF0D, 0x26641859, 0x8614844A,
0x6A6A19B8, 0x56AEB4B9, 0x56743C8F, 0x1BBAD20E,
0x4B13A2A, 0x0E5BEA554, 0x78F6AA1B, 0x515E0B00,
0x0DC13F549, 0x69548765, 0x0EDC5DF75, 0x0E9B2EF60,
0x3894907A, 0x5C93D43E, 0x0B501CC59, 0x25D6333,
0x0FA632D71, 0x9386EF68, 0x0CA55B354, 0x9A775A78,
0x8D27EB7D, 0x2E8DDA64, 0x9508F36A, 0x0BD212F05,
0x8208ED70, 0x0BDDC2E7A, 0x93C72A53, 0x65135908,
0x64212E08, 0x0B92B432C, 0x0EC27DD52, 0x534A52B,
0x65766559, 0x6A379968, 0x9E6BB225, 0x6927A003,
0x4FF63E3D, 0x16625D41, 0x0BA85AB03, 0x2C0A3407,
0x7FB6E426, 0x0A84B8B79, 0x15BD2368, 0x0B74A7521,
0x4DF5F38, 0x0CABEEF41, 0x0BAA7D854, 0x0FE428D29,
0x5D45DF2A, 0x84FD8B29, 0x98BAE721, 0x0EB6CCA28,
0x0B38A660E, 0x2DC3DA0C, 0x0A88EF92D, 0x3593537F,
0x0EA9F0907, 0x3B562401, 0x9AA6AC07, 0x4FC1370F,
0x0F581672D, 0x86CE895A, 0x54F5DC3A, 0x5AF8CC06,
0x0F1052343, 0x0F3608F60, 0x0C31F6D0A, 0x40FC6100,
0x9C3EC21, 0x7DA5180E, 0x6C069607, 0x8979D148,
0x25F1A307, 0x81C3B96F, 0x40C4466A, 0x29D00340,
0x4C82A931, 0x0FA6B1F3F, 0x27139169, 0x0A9C7885C,
0x7F69AB68, 0x0BFCD780B, 0x94345305, 0x32F41177,
0x0EC905318, 0x3DC34C33, 0x67876576, 0x0D7305D1F,
0x78197134, 0x12E127E, 0x26F2942E, 0x6D9BD861,
0x88FC9B58, 0x7AE77169, 0x0C793A568, 0x7902BF1B,
0x6D48014A, 0x8AB31273, 0x0B9FE201C, 0x770BEE6B,
0x49ECE0AC, 0x2165C0AB, 0x21692DF3, 0x7840F990,
0x0A7C87013, 0x4049061F, 0x571AD348, 0x0F34A1A45,
0x549D4C1D, 0x6AE05CA5, 0x29F0C7C1, 0x628EECC4,
0x3EFBDC3D, 0x3147F626, 0x0EC12E33D, 0x2A8C3056,
0x6E0A435A, 0x539A4834, 0x1BD8D75, 0x0E723B40E,
0x54C85A32, 0x27AF2224, 0x54BF8C70, 0x0DCC4F60A,
0x0A296940D, 0x1C533259, 0x55C7B526, 0x0FDF9557,
0x0A606454C, 0x0FC6D642, 0x86EA8343, 0x0AE5F704D,
0x35CB8D66, 0x866F4378, 0x0DCA93F56, 0x0DC93FE79,
0x0C7B84917, 0x33C4121F, 0x0D0DE183F, 0x26E6F75,
0x0B1F17651, 0x6DF1BB60, 0x0BC8C403C, 0x0EFEC530F,
0x9E38B207, 0x0A89F237A, 0x1A798465, 0x0D43F561,
0x7C347AD1, 0x0DB6D67E, 0x4771EA82, 0x0B782F18,
0x43E5347F, 0x48263661, 0x2CC7BD6B, 0x0E57BC90C,
0x6479683A, 0x818E7312, 0x0F45A5F64, 0x0B80AD06,
0x90544A55, 0x7B45E327, 0x0B9DF1D54, 0x0C51FD83B,
0x1B52620, 0x95895D2A, 0x0A2B3D635, 0x0C86D7037,
0x0C84D7049, 0x7292EF74, 0x0CADBDF2C, 0x7A3FE71A,
0x0DF83AB55, 0x86682069, 0x692C3B2A, 0x7DBC5D5D,
0x2E084463, 0x83A5BF0F, 0x8AFF523F, 0x2942B011,
0x9FDBD16A, 0x7E66FC2F, 0x79447772, 0x0E2C0066A,
0x3C87F474, 0x74C30225, 0x15FD0271, 0x123F7D7F,
0x269AA870, 0x0BB972F5B, 0x36864852, 0x0B7EEF245,
0x36DD1203, 0x0F0656626, 0x7C0ECB01, 0x38923923,
0x85EFC350, 0x1EC2A137, 0x0AA5A, 0x4E3D341A,
0x9054912C, 0x0CBDB8907, 0x0C87C1B35, 0x6FD83C02,
0x5144AA70, 0x31A9565F, 0x0ED949A5F, 0x804CEE53,
0x2F66190E, 0x6E42ADFC, 0x6143807A, 0x400891C4,
0x0F6FAE94E, 0x22D31558, 0x36EBEE43, 0x0BD871C60,
0x0C7DE4A36, 0x0FD27BF3A, 0x0E88DB72B, 0x0EE78F326,
0x0B8BFEE15, 0x1F14007E, 0x0A567E66C, 0x0EF9C0119,
0x0F7A6624, 0x2176B16E, 0x272F3B3C, 0x94692A75,
0x40385326, 0x272FE516, 0x0E2A65E0F, 0x0D08CE452,
0x0F20A6F1E, 0x0AA237A44, 0x40652155, 0x444F190F,
0x0DCCCD023, 0x2DFABB34, 0x0C49B0763, 0x911BE712,
0x0A48EA953, 0x6D2AA648, 0x0E545CF6C, 0x9A899322,
0x90FDBB20, 0x1B31BE30, 0x5711B002, 0x57DC0657,
0x18597D6B, 0x409F672E, 0x4555FA7D, 0x0D0186C01,
0x5FB3672C, 0x0EABCE06A, 0x0BFB56D1A, 0x6E2DCE50,
0x0C339259, 0x0E6E4A856, 0x297F845, 0x4C6BE57F,
0x0E148E6D, 0x0E53D5755, 0x1CF8C952, 0x1FFD0B,
0x8F61D119, 0x5C5DEB27, 0x446E161B, 0x6B2EA23D,
0x8957A75C, 0x80A1E7E, 0x0FC498950, 0x2EE65030,
0x7634C446, 0x0E18F583D, 0x0C86FE452, 0x6328067,
0x0FCC0166E, 0x20819455, 0x5D0E873E, 0x141A9459,
0x6020FC03, 0x0A363813C, 0x0E532005B, 0x0BFD36330,
0x8D206227, 0x0A4E86D75, 0x2D013201, 0x9953F400,
0x8BCD164C, 0x2F982A47, 0x0E5BED900, 0x99E1A439,
0x14D6811C, 0x2B7A353, 0x9900A245, 0x0A4375336,
0x5E148F7B, 0x0DE6EB860, 0x0F66F573, 0x0E86B3658,
0x0E678D65E, 0x0CB07E44, 0x16528708, 0x5CAD9A25,
0x0ED3FD701, 0x0DEC16B5B, 0x62DF1A0D, 0x0EA00EE6F,
0x0FE420031, 0x0C0EDA14B, 0x0FE1A8249, 0x5E63FC34,
0x63512308, 0x0E34D8224, 0x1D376065, 0x0F071852F,
0x8836F019, 0x4A389266, 0x8AC57930, 0x13040766,
0x7AD0BC2D, 0x6F845331, 0x0ACE5AB1F, 0x8EA63E4A,
0x713BF704, 0x45E64D65, 0x32DE9100, 0x0D04F8600,
0x23550646, 0x42448774, 0x0B8BBBC58, 0x0ACEDC24,
0x4EF40539, 0x0CE0D4461, 0x667B774A, 0x3B34DD3A,
0x4461B7FC, 0x33ECD6D8, 0x3262A55C, 0x0B0E1E4A,
0x89483423, 0x24504D74, 0x976AC22, 0x0EC99572B,
0x79ECF18, 0x27AD0C08, 0x0DC0BDD5A, 0x8FD4BF32,
0x71E59E6E, 0x66D1560B, 0x0A2D8C618, 0x0EBB55B1C,
0x0D655AA3C, 0x4EBE7238, 0x7A5C9A66, 0x4791A141,
0x94A4C01D, 0x0AC3A2C67, 0x17E12742, 0x0B7F9C663,
0x0EE7EB35B, 0x0CF9CE41A, 0x0C1C7A308, 0x3C73B914,
0x9DAA287C, 0x28431B53, 0x78A7964F, 0x4A7AD838,
0x2881F1EC, 0x19FB97A4, 0x5CBA44B3, 0x5BFF119C,
0x0C12CAF6E, 0x0FE023549, 0x66803979, 0x0C9CA7E07,
0x25B04151, 0x428C1654, 0x589F3E3A, 0x9795E03F,
0x0A95D6D5F, 0x0FB770553, 0x824B3C5C, 0x7FB3171C,
0x4936780B, 0x0FCA7D642, 0x0C644B95D, 0x0DDDA3829,
0x0A9E2022A, 0x0DE25E11F, 0x95D4FF0C, 0x9761B605,
0x0ADC2C53A, 0x569CA315, 0x0D4D46F1A, 0x4B6DEE36,
0x7EDFBE68, 0x4C7C066A, 0x95E7C66F, 0x6F7D6C13,
0x0E9586864, 0x8A744F16, 0x0E9634E61, 0x0AB851753,
0x8877845F, 0x4FE4875A, 0x7450965A, 0x0AE27C630,
0x92709E2E, 0x0CCEFD414, 0x45BDA670, 0x3BCE0B0E,
0x0C767DA67, 0x0C708E34C, 0x0BA81232A, 0x119E5273,
0x0C4B0B90F, 0x80C6DC07, 0x0EE788B1C, 0x6D93BC39,
0x5EECBD27, 0x834D8B29, 0x4F5723F, 0x0CAF8362,
0x0DAE92E3F, 0x0D8C9E259, 0x571C7219, 0x58C9ED27,
0x2446E943, 0x0EC033909, 0x0C8465A3B, 0x0E9F5128,
0x1BC4395A, 0x35D115B4, 0x3AEE6A18, 0x0A5881A8,
0x18F3077, 0x2D75FF55, 0x0AC17D32F, 0x93FFCE25,
0x0F964D46A, 0x0F1D47920, 0x0CECDDA33, 0x0C1CCAE52,
0x0B9DD5C6D, 0x884FFE5D, 0x0D26A0146, 0x7D8E167D,
0x816DB65, 0x0C0E38C62, 0x0EA21D336, 0x6702990D,
0x4431180C, 0x0EE164676, 0x73B11C70, 0x1E1B474B,
0x0C7E02850, 0x0CACD8E09, 0x76E43473, 0x0EB261214,
0x0B6D1C712, 0x3E2B8F2E, 0x0F9C5633C, 0x2C4A5032,
0x0F0D5374B, 0x0B2EACC37, 0x2A3A5D31, 0x0F1646842,
0x5F3C3742, 0x305EB03B, 0x6F051933, 0x4A83B8CF,
0x0C826AA01, 0x5232121C, 0x9A914F4B, 0x8104076F,
0x0DA81107A, 0x6CFC5011, 0x0FE921D6C, 0x0E297EB5F,
0x2CE0DD73, 0x0E8B4F022, 0x499A846D, 0x7011F67F,
0x0D7CB3619, 0x0BC4BA15D, 0x8E2C3D4B, 0x9EAC5F69,
0x86193067, 0x511723E, 0x89D3717D, 0x3CEBF779,
0x433C016D, 0x8399D539, 0x6835482C, 0x33123938,
0x3584A271, 0x936FA55D, 0x2477A17A, 0x15E46E7F,
0x6AC1D53E, 0x0A8DBD862, 0x0EEA80F78, 0x32E87F40,
0x0FA0DEB7E, 0x883A5F43, 0x0B4EC862F, 0x0D48FFB78,
0x0F436B054, 0x0B27FA41B, 0x0B727E758, 0x20178E48,
0x9B34953E, 0x0C26B46, 0x91288448, 0x7200CC57,
0x0BD0D0D24, 0x1F55C113, 0x10AD2B41, 0x43273D0B,
0x24663352, 0x99809D3E, 0x80123505, 0x68A2343F,
0x1C1A7378, 0x0E8477D31, 0x9BB46D77, 0x529E156A,
0x7BB7220F, 0x0C02B0F72, 0x67828469, 0x0E578F84D,
0x6807E854, 0x552B9461, 0x1861780E, 0x6315D353,
0x0DD65F324, 0x0CC4DFF3D, 0x37A5CE4C, 0x0D19CA379,
0x7ECDA359, 0x0EECCB525, 0x0F1B33142, 0x19023918,
0x0EF8E216C, 0x82DCB50A, 0x8B020570, 0x0AC9C2E10,
0x0A231771E, 0x9BAF3031, 0x0EFC36B1B, 0x0C697AA70,
0x3530CE6F, 0x6FD6A020, 0x2E3ADF2F, 0x514A4168,
0x581E1E52, 0x0CAEE4C27, 0x0A3E85652, 0x0D3D54061,
0x8A1A5C19, 0x0A6BDB3B, 0x0B94E392F, 0x0F221446E,
0x5F966F1D, 0x0D1AFB13D, 0x55371742, 0x3CFC6242,
0x9DFDB07B, 0x8DDCE50E, 0x0D99063C, 0x1BCB5455,
0x7BA99B34, 0x0FF4C387E, 0x35CD8D6D, 0x6A38BD20,
0x8129EE08, 0x0C0CF925D, 0x16D5EB30, 0x235B6527,
0x5C7FC30E, 0x699574C, 0x0EAF20F18, 0x91AF917E,
0x756FF86C, 0x182DEF47, 0x0E2F9D266, 0x0CD8D163F,
0x0E21B3C6F, 0x86E22939, 0x0A1635720, 0x6C369808,
0x6A23B22D, 0x78FF3024, 0x37A7237A, 0x44CE01B1,
0x2B62420D, 0x0B48FF338, 0x2CE0D754, 0x0C85FF308,
0x416CD947, 0x3A79DE10, 0x0E32A485E, 0x0BD15757C,
0x39C6160F, 0x18F8D54B, 0x274E321D, 0x0BAEF0418,
0x0D9C76829, 0x3E231E4E, 0x0DE4A6A3F, 0x35472C38,
0x44BC751A, 0x0C83D7A57, 0x0C6F6BD36, 0x0B92B6E07,
0x0E06A691F, 0x0A8F0901D, 0x87B98446, 0x0C386A50E,
0x2ED3BA56, 0x281DDC66, 0x2FBD3D17, 0x0BF20C04B,
0x82CF6C36, 0x8E151A0E, 0x0AF04355E, 0x0AD31AF43,
0x43A50D47, 0x0DBE40C33, 0x7591A24C, 0x8411E70E,
0x155EEB43, 0x58BCEA2A, 0x41275C0B, 0x4E240253,
0x71B4C076, 0x69758E28, 0x914076B, 0x4A7C2920,
0x0A798AC76, 0x0E75E712A, 0x7FC35558, 0x0EB542211,
0x0AF9CEB01, 0x45BA130F, 0x0A4809018, 0x8F075521,
0x0EDAAA42C, 0x2B3A155F, 0x528EFA2F, 0x1C7E5F03,
0x5357F145, 0x824B3847, 0x0DB9E1F4F, 0x0D5265E7C,
0x6D60D29F, 0x6F5891FE, 0x3900600, 0x1567C1CA,
0x65886160, 0x0F7E9AF0C, 0x0D817472B, 0x7BE64C24,
0x50A69A37, 0x193FA336, 0x0C90A4F77, 0x0C15A5B2E,
0x82B4315F, 0x0D21E5662, 0x0BD7844E, 0x294DDE55,
0x0B97DC70C, 0x8A9ADA26, 0x14A20067, 0x681AB30E,
0x0CF54EE35, 0x0B922917F, 0x0F8210830, 0x0BCFF9262,
0x6F8D9E3B, 0x7E9F3187, 0x25E4675C, 0x351F8D33,
0x0CCFB3A27, 0x0B31C1235, 0x0DDBF520, 0x0DD5C8D7C,
0x3DC06662, 0x90330361, 0x3063ED18, 0x0A348C842,
0x871DB36D, 0x87B3444, 0x1E2F1567, 0x0D7C34D25,
0x22BAD77A, 0x0E739645E, 0x981EA953, 0x0A46E095A,
0x0BA58BA40, 0x0A3F52D22, 0x0CEBBE72F, 0x73D6814D,
0x2D900849, 0x0E25DE816, 0x0DCF0345C, 0x0FCE4F67E,
0x9B807916, 0x0D4123D0C, 0x0B9E48961, 0x80DD1F75,
0x1EC33F6C, 0x91627C47, 0x0B891B719, 0x0EBBE7A13,
0x457F8E7C, 0x0C56CAD3A, 0x0C81B0810, 0x823FF55E,
0x4E5B4CC8, 0x124C4517, 0x2F338D38, 0x152D88DE,
0x1FA296D, 0x43B7D208, 0x0B481B12E, 0x23B40168,
0x2BF13667, 0x4DA05A02, 0x0C7220B42, 0x0E549F127,
0x0F0958824, 0x95DEF271, 0x58207375, 0x1E26916D,
0x783CDB08, 0x3411A851, 0x1A0B886C, 0x13BD541F,
0x824E55D, 0x0D3EF114E, 0x939A7414, 0x27E7244A,
0x65528E15, 0x4B2C2C2E, 0x12A69F5D, 0x0AAD11C12,
0x1199D968, 0x0DAC1A76D, 0x2C111271, 0x66398A04,
0x0D2409D16, 0x5299CF12, 0x43F7ED0D, 0x0D33AC703,
0x9550A21B, 0x0F8789F3C, 0x0F6EEC86B, 0x0C041D902,
0x4519FA3E, 0x0BE11D42D, 0x0A58BCA2A, 0x35AF8263,
0x53F0C61F, 0x0FEAB3D20, 0x53D51351, 0x0CB2CA228,
0x32BDE571, 0x6EE09B3D, 0x0DFE9F647, 0x3BE1CA4F,
0x41D0AD0B, 0x72846B5C, 0x62C8EF19, 0x0A6223C21,
0x0BEB0970A, 0x746E8F77, 0x50F45833, 0x0CF497173,
0x4E303765, 0x7D056B24, 0x3583FB77, 0x2071D47B,
0x0CF9E3A37, 0x797AE905, 0x0F4AB9B7F, 0x64EFDC52,
0x71F38842, 0x0EA9A646B, 0x2531B655, 0x0B60C8301,
0x0A8AC3819, 0x0CABC8000, 0x0EBBB0565, 0x0FC9CFF38,
0x0C868BE20, 0x3F911936, 0x0C7C9A161, 0x0FB25A412,
0x0AD71B573, 0x0A6B39829, 0x36076F62, 0x0EE41637F,
0x19380406, 0x98CF5E7C, 0x95649F20, 0x0D7E89B10,
0x0C3EEE73, 0x0E558F853, 0x0A6320D04, 0x5A6E2559,
0x625E6378, 0x0DBB5087C, 0x7ADFF954, 0x31FD9D2F,
0x5430F201, 0x6E8B9554, 0x96EC7A02, 0x0C5237B44,
0x5926FA3F, 0x0BB1D3158, 0x7B30FE45, 0x1D33259,
0x85DAB158, 0x67EC032B, 0x0FD6F3212, 0x4E437079,
0x0A67D1D61, 0x0C539D473, 0x4969140C, 0x53EFD254,
0x6BED6C1D, 0x7F70836E, 0x41313654, 0x84257123,
0x52DD97D0, 0x4014F6DB, 0x6C2326AF, 0x4DDD47A3,
0x0BCEECD48, 0x1411A38, 0x7DECF537, 0x1E4D3141,
0x0DDF62234, 0x0F7CBEF0C, 0x504ACF70, 0x31271536,
0x66578561, 0x0E6364A73, 0x0F74A907A, 0x0BF7D7F21,
0x47CE63F, 0x9676368, 0x6F1E4833, 0x7F5DF003,
0x0D967926B, 0x0BEC0E40C, 0x74729D1D, 0x7FE5AF4C,
0x83FAB800, 0x0BDDBB129, 0x0D2D48221, 0x0EEE7251E,
0x3C4C3518, 0x1406B975, 0x730D9741, 0x538C1703,
0x0EA9B8E6A, 0x0CE1BA475, 0x760AE861, 0x0A68A5C33,
0x0D05CBE2D, 0x0F3F6DD19, 0x0C5D78D74, 0x0AD53E161,
0x0EBC2CD26, 0x15225D65, 0x0DE7AF617, 0x511A5308,
0x0FB58A758, 0x0D5C58612, 0x1098D229, 0x9CAD2224,
0x48411553, 0x0D0E88424, 0x0C2DC4F48, 0x21A9A73E,
0x8EA96931, 0x374FED65, 0x0A18E570B, 0x11A42232,
0x0F42A9F0F, 0x7363DA2C, 0x8C4850, 0x3177D427,
0x87699322, 0x7399DF11, 0x8403EC2A, 0x7205220D,
0x4DDF4283, 0x52A2C7B6, 0x2BC34B4D, 0x72B8C500,
0x0EE04B226, 0x0DD670C35, 0x0BE652317, 0x0D9C77F4D,
0x0F289691A, 0x9DE0192F, 0x2AE2D255, 0x0EDE21073,
0x72A6A041, 0x3A7AA57F, 0x89903317, 0x0BAE7B514,
0x0B632A24, 0x4C6D835F, 0x0DC905D53, 0x990C9455,
0x83BC7045, 0x7D1FB55E, 0x0ABB0B607, 0x77E70F55,
0x0F0828F0B, 0x0AB3CFF57, 0x0A85EE47C, 0x78EC222E,
0x1ED6DE69, 0x2D62D027, 0x0EAF1443B, 0x5F8B6271,
0x2870A434, 0x282C37B, 0x719DA426, 0x1675565B,
0x0E0E9CF30, 0x2F03C83D, 0x0F03CD628, 0x0D273394B,
0x0CCE3E16C, 0x1A1FA97E, 0x0C0564A3E, 0x3F8A822E,
0x55994E7E, 0x49E77D55, 0x0F9713843, 0x60FC7822,
0x95540135, 0x0D5029616, 0x0F9080D78, 0x1811727A,
0x52224B75, 0x0A4B9C37F, 0x90F8814F, 0x43A5DA00,
0x4FF6C257, 0x3857664C, 0x0BB91FD2E, 0x6DCCA141,
0x31084709, 0x6F5244D6, 0x7FE57A0E, 0x66FDFD56,
0x4DBAF33F, 0x6E9F2DF9, 0x62423705, 0x190A1571,
0x6DF87017, 0x94DB072D, 0x5A630F62, 0x3ADC5204,
0x0AEFAB02B, 0x1ABA5920, 0x7966D532, 0x394FF29,
0x40260F59, 0x7D00DF34, 0x714FD4F0, 0x744368D3,
0x48DBA30C, 0x5D998544, 0x11074B25, 0x9AFDEE01,
0x1534944, 0x0A1FFCC74, 0x0DDA2C902, 0x51490C1C,
0x0DA563341, 0x9834C731, 0x0BE15AE5D, 0x3F106A35,
0x3DB8091C, 0x8B6DB210, 0x0CD39455E, 0x0E5BD0F02,
0x0C9625B6A, 0x71D87662, 0x6CADE518, 0x375BCC01,
0x5B47E0F, 0x0C610F57A, 0x71371F06, 0x0B3AE2F3B,
0x0E0CA4E1B, 0x0EA9DF438, 0x0B7422F65, 0x446C2611,
0x5C76022F, 0x1AD3A731, 0x3D62FF3B, 0x0A451A63B,
0x776C2D76, 0x4E694A61, 0x3F4F953D, 0x79BF763A,
0x0F0681756, 0x1CF25E40, 0x0CA088356, 0x0CABF4A17,
0x0B5262672, 0x881E3134, 0x9D0B44C, 0x0F2DE2F0E,
0x5CE8E64A, 0x75C6DA10, 0x53858358, 0x36F298DE,
0x47E2700D, 0x444A2529, 0x144A0B31, 0x4C96EF1C,
0x0A5B1A24, 0x85812A37, 0x451F58, 0x0EB25693F,
0x6F1F1F70, 0x0B7874E3D, 0x2F928F50, 0x0CC95211F,
0x0D15AF66E, 0x6CF48E0C, 0x70E7C75A, 0x49C72365,
0x0F409E49, 0x60C4561C, 0x501B573F, 0x15F46F93,
0x0CC28BC58, 0x8C8F1D76, 0x74863B5B, 0x814FE24A,
0x14AE4E2A, 0x7E56F027, 0x732E1259, 0x283A326F,
0x5460EA52, 0x4BCB5169, 0x629711E, 0x9C425B60,
0x8F157712, 0x1A737C4F, 0x0E8D84A7D, 0x99709136,
0x0A0F4A606, 0x0E81D6A55, 0x8496FA75, 0x0F14C676,
0x9FA5B812, 0x0B3288A46, 0x0DBA9E715, 0x7100AF01,
0x4E5852DA, 0x24D4B216, 0x37D84D1, 0x1E50B1EE,
0x0FBC70C09, 0x7C4E6D06, 0x8441E304, 0x0C7F0C861,
0x8DE8A7C, 0x0F9C71E60, 0x4840AB2C, 0x1C8CD926,
0x771E0F08, 0x0BC6EBD05, 0x45C60B16, 0x0CB7EF95A,
0x73A0F6F, 0x4BEF7C34, 0x67C1543B, 0x964F8601,
0x6562F903, 0x509A9F38, 0x2FC01738, 0x557A00A,
0x38B8090E, 0x0B456122E, 0x156B6601, 0x0D85DC220,
0x677F9C74, 0x0F0144E17, 0x495E7122, 0x879CB547,
0x1A2637EA, 0x1709E823, 0x77A791D1, 0x2913569,
0x46EF551, 0x324953A5, 0x5998AA27, 0x735463D7,
0x0DE20AA6D, 0x489F7E1F, 0x0A3DE1533, 0x553FB975,
0x40E3C25, 0x0E8A42149, 0x21BEB250, 0x0B484B14,
0x48EDF0B7, 0x6E6AC7AE, 0x3929693F, 0x4FEECCA2,
0x0D819A744, 0x0D057E94D, 0x9E4D380C, 0x11D2B052,
0x84AEFB7B, 0x0B3B89E0D, 0x0E92F7373, 0x0EC2D9870,
0x0A4CDEC24, 0x328EE415, 0x73CA4D38, 0x0E073EA2C,
0x35B4281F, 0x0D4E1F540, 0x18E2F43D, 0x0B428DA2E,
0x0B93A814E, 0x1841C830, 0x3B7B163B, 0x985B2B3C,
0x2CEC6283, 0x5B069FED, 0x51F59901, 0x13BC9618,
0x0C7FE4D37, 0x0E599702, 0x6F36CE09, 0x0FA92EC34,
0x0E06A185, 0x790915C7, 0x55C3319F, 0x3FDB85A6,
0x0E025896D, 0x32D7BC42, 0x80C4F625, 0x65D48469,
0x0E58F5B50, 0x69F46919, 0x51021D5A, 0x895D4875,
0x9B824E2F, 0x0C4CC6A12, 0x6AD13222, 0x0D036774E,
0x98AE6053, 0x82B32760, 0x845F517D, 0x51E9E121,
0x9AF4EF10, 0x0BFDA6738, 0x0E9440D5E, 0x0FAD43661,
0x9E349426, 0x0D7DFF10F, 0x5EC3B956, 0x6533E25D,
0x0E5388912, 0x0CDF98760, 0x5FC6CE12, 0x7C112821,
0x369A6C02, 0x73D70821, 0x5EC02CD0, 0x5203378E,
0x2527100C, 0x6CC8641A, 0x23C23557, 0x0AB76B5C,
0x0D6BCCE33, 0x74C45231, 0x9414B451, 0x713F1D63,
0x3891BD43, 0x0FEE5E673, 0x42769431, 0x0D03F1E17,
0x80990E54, 0x0C6D5E52E, 0x21290039, 0x1B8EFE64,
0x86B04D67, 0x0B6E0D17, 0x15633546, 0x24E5E10D,
0x0E24DFF26, 0x7426EF1C, 0x8918C46B, 0x0C7868839,
0x4120777D, 0x0E8DE927E, 0x4498B05A, 0x1FE89E7D,
0x0DB2EE647, 0x309C1E4F, 0x0DDD54F6B, 0x56F653,
0x9C648369, 0x988542, 0x0B0D6230, 0x7221521D,
0x745CD873, 0x9F211602, 0x0E4606F00, 0x0ACED9537,
0x9D07FD75, 0x26D70332, 0x7C2DB44E, 0x1DA10B4A,
0x0ECACE960, 0x9D56B407, 0x382F0A2F, 0x725D3748,
0x0A8C4C11E, 0x4E923F75, 0x96421956, 0x8A12C145,
0x0C2B82E12, 0x1F5BDD41, 0x5299497F, 0x3D9A50F,
0x83A7040, 0x9631FA59, 0x22C1440D, 0x0E3685608,
0x0C6CD1829, 0x0FF969478, 0x0E4BE4C5C, 0x62329C12,
0x0FF2E1A3B, 0x0EFCBAE0C, 0x0D553EE2F, 0x738BF22E,
0x8EEDC40E, 0x0B9B45D30, 0x1F798866, 0x2BF5C104,
0x0DF8B6162, 0x9BA63C35, 0x4896CD4E, 0x0CB384B43,
0x4E037000, 0x166B8E14, 0x4E580FF3, 0x6F8B1DBE,
0x0CF571773, 0x0D4D89B61, 0x6CD47321, 0x91104605,
0x0F4337923, 0x0BE6DBD20, 0x94E9EB14, 0x0FC6DE963,
0x549FB77A, 0x0B7AA3022, 0x0DFD63F6C, 0x1A6DD023,
0x0B641C51A, 0x0C3958C48, 0x7C9F6C36, 0x0B670DF55,
0x0B2613B55, 0x51F35A66, 0x29FCD104, 0x404F0064,
0x0AA8B816, 0x49755A6B, 0x6B44C268, 0x0E9331A79,
0x0E41B9720, 0x0B4DA8F37, 0x0B56C653C, 0x1D19885D,
0x35A06735, 0x0F302E847, 0x0FFDA3A39, 0x4F87E28,
0x0C7DB8329, 0x6BAFAE5A, 0x9508C52D, 0x0BB0FFD4C,
0x291D6C7B, 0x29F2B042, 0x0B77DE630, 0x7DBC2376,
0x0E09CE164, 0x9754261D, 0x9729F419, 0x97DEA67F,
0x5AEAB265, 0x13C96050, 0x4D4F8655, 0x0D4CEE3A,
0x65BCBB36, 0x764B585A, 0x4D9BEE1E, 0x6F64744D,
0x0BFC0B245, 0x0B9DFB007, 0x59988E46, 0x0A4DC4966,
0x6DBA403F, 0x0E05F402, 0x0C1F5D143, 0x0A25AA874,
0x108DC4A, 0x0C0D00C7D, 0x0A652271D, 0x0C8E35F74,
0x2B80BB57, 0x3B5BEC4A, 0x84F35C41, 0x549D2753,
0x644D9D0D, 0x3B714372, 0x0D1594B49, 0x45EA7E72,
0x0D2C5690F, 0x68833F63, 0x0DCC82572, 0x2DB01C75,
0x7C4CA033, 0x2918AC47, 0x3AFC0A30, 0x0E1085C6A,
0x9F630422, 0x8797F94E, 0x506DD037, 0x5F24B767,
0x4077AA56, 0x0A9055F7E, 0x301014E, 0x0AD31EB15,
0x0B70A5301, 0x0C4F6D211, 0x4F8C930A, 0x0B8122F4C,
0x85C7DF0E, 0x0F5DEBA27, 0x81F68E40, 0x0B0479B66,
0x303AA772, 0x5EAEB01, 0x5E5C239, 0x95874400,
0x405B2F74, 0x0D63E0E03, 0x0DA71C372, 0x13219903,
0x3FC24D66, 0x0B63AE964, 0x40D1B578, 0x0BB0EEE19,
0x0DF52952C, 0x7ACDC028, 0x9C174A04, 0x7EB6994E,
0x165BA77, 0x0EC841A3C, 0x0DDDA5036, 0x42DC644E,
0x968A793A, 0x0E0DB5104, 0x0EF0D5064, 0x4D95CC3B,
0x0A5D22416, 0x3F9AE36E, 0x6A8FB07, 0x2A9A0425,
0x34799E16, 0x879E8A48, 0x0DAE19F0B, 0x65B34509,
0x8C88764A, 0x0DFC66245, 0x0FA3A8A09, 0x0CCE3A53E,
0x0B6057148, 0x0D4AC4D7C, 0x0DF043F42, 0x0F5C7BE2E,
0x8AE73661, 0x1FD6F43A, 0x0B0D6AC48, 0x693ACC0D,
0x99A3B563, 0x4CEEF64C, 0x0E7F0655C, 0x9B08705B,
0x38731109, 0x0C5CBB612, 0x0DDE4D429, 0x0CEFD8A43,
0x0A5A70817, 0x0CCF2240E, 0x1C93577F, 0x4A7A2D2D,
0x21DC3AB0, 0x73B5D4CE, 0x16360A86, 0x210D61B0,
0x0A9D9DD4F, 0x4FF6D15D, 0x0A5B9EC1C, 0x3562541A,
0x2EBD3423, 0x9FF47626, 0x146FA58, 0x0E4C2A56B,
0x73A1C422, 0x0E14A391B, 0x0D98A641A, 0x0FD88FB03,
0x212E56, 0x89611163, 0x66C3C711, 0x9AC4E339,
0x0B47061F, 0x72F5B3B6, 0x36C01945, 0x5C988DAE,
0x1280E400, 0x12B2283F, 0x0DCC0A47C, 0x0B827ED17,
0x0DEA44D4D, 0x0F853FC7B, 0x2A21A45, 0x0EA31564A,
0x1A8F4F03, 0x77B64C17, 0x2A38FD5D, 0x0C3682D53,
0x0C6AC1E75, 0x0CFF1E97A, 0x0F8CA816D, 0x0F4695318,
0x6EE66021, 0x0FA107C46, 0x0D92CF903, 0x0E1872544,
0x0DB5BB561, 0x0B2B75D1E, 0x0DE102148, 0x0DB7CE337,
0x3C196F01, 0x44D4E859, 0x7541C771, 0x11697731,
0x91881648, 0x0AA0E1B07, 0x1F2C916A, 0x0A408FB48,
0x0BCC04346, 0x0FCEC3567, 0x5C30E860, 0x9B659113,
0x0F4403263, 0x5ED20226, 0x8597E75D, 0x0FD08166,
0x0D5884F3D, 0x0AFCFE43B, 0x0D238AF39, 0x9B356E32,
0x7EC1CE36, 0x0CB033127, 0x909FC14A, 0x0ECA72F58,
0x0C514AD6D, 0x69CCBA4E, 0x0CD2F551C, 0x0A070624F,
0x1B84186D, 0x0AB407664, 0x7BED4507, 0x579D876E,
0x0EF145F3E, 0x0F12E0D79, 0x6906FF1F, 0x809D7506,
0x9B3D2800, 0x8832900A, 0x24A6704F, 0x58FE6B46,
0x841FC671, 0x80D65830, 0x0F363FD59, 0x7960F854,
0x0DFA85B56, 0x78FBE437, 0x88307A3B, 0x0B431AB13,
0x27CBC973, 0x5A692975, 0x50671946, 0x0A58C982A,
0x256D5A1C, 0x0E006DB10, 0x9134C802, 0x0EA81070A,
0x2E6AFF49, 0x4045FF1C, 0x6A54F329, 0x0D8B3D1D,
0x9A59303, 0x6E0AF60, 0x0BCF4353B, 0x0F8B9F241,
0x0F70EBD59, 0x25FB345B, 0x78576848, 0x924CE559,
0x7462D0E4, 0x21EDF5EF, 0x522D87FD, 0x2484D56A,
0x1DD43148, 0x0DDAE4E7A, 0x0ABAD832C, 0x0FC7C8D1E,
0x55AA3332, 0x33DEFD67, 0x0B1AE3832, 0x7C75FD25,
0x8D47275D, 0x1165278, 0x21029650, 0x0B3B48179,
0x0E11C2D09, 0x0B2365E53, 0x9D368903, 0x2AF0C268,
0x109B7B72, 0x2829F35C, 0x8E477135, 0x19400F76,
0x2E09A33D, 0x4A3CA770, 0x11FA0138, 0x25186017,
0x6F37DC4B, 0x8A516A00, 0x0B7644571, 0x1D65A131,
0x274F4318, 0x0A2AF9611, 0x4FB22C09, 0x44237560,
0x7F5EE50B, 0x0FA5FB035, 0x41A0027F, 0x0D508193E,
0x1508B9FD, 0x26F43182, 0x752E5700, 0x1E33D9D3,
0x0F3648D29, 0x7380AC34, 0x6D3A5774, 0x0D481BA32,
0x25B70A08, 0x0B71E077, 0x0FE717D1B, 0x3652867A,
0x339AD354, 0x8CB9EE50, 0x4F929570, 0x61A37612,
0x0D7F59541, 0x618C9728, 0x86BBD629, 0x462D720D,
0x0EBDD0129, 0x3D201C1B, 0x6392133F, 0x122D4541,
0x4761C14C, 0x6409BCFF, 0x6DD3D930, 0x11DE11A4,
0x0ACA4F07D, 0x97F0BC20, 0x3437B176, 0x0D9E29E1B,
0x893FF851, 0x85B5C75A, 0x94687416, 0x7CA4857B,
0x0F835740F, 0x1A3CB0A, 0x5026402E, 0x1EED7E17,
0x0C14AC02, 0x4E98BD49, 0x543F0512, 0x3FAE7F57,
0x1CBAEE15, 0x51F335D4, 0x57E8755E, 0x40AF0085,
0x45E322B, 0x260DCD13, 0x0F874B469, 0x0EF3B3454,
0x642DE92E, 0x5C07C828, 0x1697915, 0x43FD9B5B,
0x0E4C0871, 0x58B93337, 0x0A22B3414, 0x0BBF0F86E,
0x0EFA9F057, 0x0D662E50A, 0x94D3970A, 0x79E9E829,
0x5C18AD65, 0x283C0C21, 0x0F58D6E25, 0x544E2175,
0x2ADFD72B, 0x46B4AE53, 0x723BA00C, 0x36F3832E,
0x944C6C1D, 0x0C67AA51E, 0x76A10306, 0x6F9E1838,
0x6A4C4021, 0x16F3F96F, 0x21E65A14, 0x6EAA724C,
0x3D00C703, 0x1A5B0F7E, 0x5EE6A620, 0x0A12DB032,
0x7662D726, 0x5F4F2036, 0x0E42A4C0E, 0x84AEDF17,
0x0B708546D, 0x87568022, 0x3F9FD806, 0x0A7B24445,
0x5DB9652D, 0x0D4727011, 0x209C2D6F, 0x0B9D11213,
0x0FCAE7C32, 0x152A9C14, 0x0E203408, 0x268E545E,
0x5BDE4A68, 0x805BD414, 0x5D81D80C, 0x0F02AB705,
0x47D67933, 0x0D322DC12, 0x5FC9CF3D, 0x0B122BA54,
0x0E915D602, 0x81AF2A52, 0x1FCD2C21, 0x26169D06,
0x9B0A3A50, 0x7DB3D341, 0x0C7434D39, 0x116D1177,
0x0DD02F477, 0x0AC6E9947, 0x951BF10E, 0x940B4865,
0x33C5196A, 0x0D5BAC915, 0x3BBE8C2A, 0x907E7F17,
0x0A92D3A27, 0x5B5ABA19, 0x4A50922A, 0x0A5DCB659,
0x7184562E, 0x5870C632, 0x0CC6A0B38, 0x0CC62A116,
0x0D8CB9A47, 0x29ECE344, 0x0BC8D581C, 0x1FA2147B,
0x3D79F15F, 0x30E45B8A, 0x5058B41F, 0x6C821EE1,
0x16DE34B5, 0x7897DC6, 0x3CF9DEEE, 0x2CFB00A7,
0x6D45CF32, 0x0D37E801A, 0x497E9E73, 0x4A48C32A,
0x7FED1962, 0x0DE998F02, 0x0DF530B10, 0x0B2B2334C,
0x0B3545918, 0x1A12983A, 0x4331B363, 0x5C82933F,
0x766C5254, 0x8D81450E, 0x25F4A19, 0x0E7F0A802,
0x0E5F10B41, 0x0CEC95551, 0x0B3534A19, 0x0BDBDA608,
0x0F7B53916, 0x70E1A235, 0x0DD5FBB03, 0x0F3C4F96D,
0x8C38CB0F, 0x0AD248A53, 0x0D8E98F48, 0x293F1E3C,
0x9DB68544, 0x0E424C329, 0x6150AB38, 0x0BFC5477,
0x0B8A34344, 0x0AACE492C, 0x55441822, 0x37915D26,
0x8868D92E, 0x34982332, 0x0EA439172, 0x3CBD3247,
0x4FAABB6C, 0x2D754456, 0x983FC606, 0x0C5160E41,
0x0BAF68964, 0x9A9E1020, 0x0AC07B743, 0x9FE89525,
0x68686671, 0x5F5B015D, 0x5CA63C2E, 0x5F1EA007,
0x2B7A2127, 0x6DA60039, 0x337B43C0, 0x642E9FDE,
0x0E72A8205, 0x2BCD293E, 0x84B48D5E, 0x84E1074A,
0x0FF2EC67, 0x0E5043917, 0x8FDD5C41, 0x0C795302C,
0x8FD38243, 0x0E5217563, 0x0FF268E52, 0x183C5C72,
0x19BA9815, 0x0E96A1F45, 0x54F98E39, 0x68645402,
0x16E0631B, 0x0EC385540, 0x2D7B6243, 0x0D0D6ED7F,
0x2ACC778, 0x4E9394E6, 0x2F042BB4, 0x208CF258,
0x39DE1A64, 0x0CB65C053, 0x4F5E6C59, 0x81BBF76,
0x56CB805, 0x0A141064F, 0x64902E19, 0x0EC963A0B,
0x0C969766, 0x480F2FD3, 0x5F3BE605, 0x3657B648,
0x0CE49F50E, 0x569F16, 0x0A3964D21, 0x5D1D7852,
0x0E577147A, 0x0A2BDDB73, 0x7559D444, 0x0FE31AD0F,
0x5CBC2DCE, 0x48A6AF5F, 0x321C6C2B, 0x0AA62556,
0x0B68BB83E, 0x94116455, 0x71DF4C54, 0x3D631E1F,
0x6E947D5C, 0x0E09ED079, 0x2CA3EA70, 0x0A7729840,
0x0AC04914D, 0x7B01574A, 0x0AF8D5737, 0x0B1704953,
0x1D435D19, 0x131E8650, 0x9D07845E, 0x0E9518D26,
0x0FC624248, 0x0D80C633, 0x0C552AA1B, 0x0CAAC3757,
0x0DD6654A, 0x69E9F73C, 0x27CAAF29, 0x0F24D7A44,
0x0BA7D330, 0x9D23846E, 0x0F17F2754, 0x97CFCE69,
0x6676E76C, 0x58162966, 0x38D82D3E, 0x1C02A02B,
0x0EC278D3B, 0x0AAB77A12, 0x5965BE4A, 0x5ABC0A18,
0x8A564B0C, 0x8608A93B, 0x12FA358, 0x365BDC59,
0x51D20D6C, 0x2DF696FC, 0x5B2F3C49, 0x73CAB4FC,
0x0C4DA8060, 0x84D3A90B, 0x89FEA45, 0x0C03DC328,
0x9253703F, 0x0CDF19461, 0x8AEAFA7F, 0x9F29D609,
0x36DB8C1E, 0x0B2B4AA29, 0x9277504E, 0x4282604F,
0x4FD82E18, 0x83F77722, 0x0D9512F39, 0x0B54E1605,
0x0DB0DA108, 0x112A5D77, 0x0D250B630, 0x0C7352E44,
0x0BBE1D709, 0x2BB6747B, 0x22F2385C, 0x46382316,
0x0B1BE1D37, 0x2321DC34, 0x7C93FF6F, 0x0B3C81D3D,
0x0D4DDD644, 0x645F251D, 0x0D1157B5C, 0x99B85725,
0x0E832CF28, 0x0D9B46522, 0x59F61A4E, 0x7A863F68,
0x0A7A6FA03, 0x0E4E0154E, 0x1AB01572, 0x0DD818722,
0x9695C077, 0x0AC276640, 0x1F04E871, 0x0E56DEF0F,
0x2F1FDE62, 0x0F855172B, 0x9ABC0515, 0x0A2D7F6B,
0x0A807422, 0x6C0DBC45, 0x0D162AD2F, 0x0C5614C2C,
0x98C33041, 0x0F354E60B, 0x0B9A6F42, 0x49824E78,
0x1776C240, 0x882D6F32, 0x0FC4A6C35, 0x0EB539905,
0x0EC8C944F, 0x0CE60E711, 0x840CF12A, 0x0D4BF6378,
0x0A7154D34, 0x0DE020C79, 0x4F46A360, 0x4EBC4738,
0x5D9A87D9, 0x25D0B3F, 0x5A744C74, 0x5BE5A855,
0x151E1F13, 0x4B42B74C, 0x3DE7D14E, 0x443DFD75,
0x4498CE77, 0x0D7A3D763, 0x4E6A7C61, 0x4E18431A,
0x44B19329, 0x1FCD2911, 0x137A8F46, 0x0DC74C46A,
0x1322101D, 0x1F14FF08, 0x25F71263, 0x2A98D25D,
0x0A7416E3B, 0x22427F18, 0x15EC6B63, 0x93CE020B,
0x51C5C3AB, 0x3836A421, 0x627C0AF6, 0x15A906EB,
0x78FB6807, 0x0B6D40964, 0x0E674FB16, 0x3ADF8A4E,
0x507B6A26, 0x4DFACA91, 0x30941D2, 0x5CB36513,
0x5DF5813E, 0x0CF3F3F5C, 0x7826DF3F, 0x0A18D5036,
0x0A6E31640, 0x0C6905B21, 0x0EFA59350, 0x0EA94AA69,
0x0E65D8532, 0x3202317, 0x0C6096F54, 0x0F97F954F,
0x22342220, 0x0EC008237, 0x2318682D, 0x0C975905B,
0x0E430150, 0x3804D410, 0x5C449366, 0x0FEE5677A,
0x0D2FC301F, 0x0C3D2F969, 0x959E1B59, 0x4AF89926,
0x7AA7034E, 0x7B131770, 0x84D72475, 0x9972C604,
0x8DC6E161, 0x16309202, 0x0CE5BA84E, 0x0EBBB6320,
0x0E56FD15E, 0x4682870E, 0x8C49B456, 0x8C53E81E,
0x0D13E32F, 0x7CEF4727, 0x76E89208, 0x0F3706862,
0x7F0F6B3E, 0x3DF2015D, 0x0ECF0FD31, 0x0A1438D5E,
0x29F38314, 0x0F09665F, 0x6AB91D3A, 0x37368564,
0x470D3A70, 0x0C6FDB020, 0x351CED5E, 0x1A0A6B0F,
0x89D0AA0A, 0x0CABA0838, 0x64020536, 0x378AE58,
0x46CE1F28, 0x0E9D9292B, 0x9DEA745D, 0x0D394010A,
0x0FF09BC2D, 0x6B461D2C, 0x0BE50652A, 0x0E5798D0C,
0x0B1C8A43A, 0x4B9A1901, 0x71CD752B, 0x0BEDB876A,
0x0C7896128, 0x0E7B50834, 0x0B14CF04C, 0x4699CC66,
0x24A80A11, 0x9D3DEE7E, 0x0E7DC5945, 0x4D9B8E25,
0x0AC46545E, 0x5196777F, 0x84D1130A, 0x0F4538E4E,
0x17942820, 0x0B9ED0069, 0x0E5EF95D, 0x0A064D32A,
0x84A80921, 0x7260FE13, 0x0A4DC8103, 0x0CA762949,
0x5B3A283F, 0x41C7F660, 0x9D0B2B53, 0x5B44E46C,
0x0AC0D140D, 0x5C5C907D, 0x40BE7179, 0x5DD6B847,
0x0A7F6A97E, 0x0B18BE724, 0x1CB24032, 0x6E800B27,
0x9841F058, 0x0CDFE307F, 0x0B419D80D, 0x0BDE9FA69,
0x6B3C1F7E, 0x9BF63153, 0x0A85890F, 0x1783735C,
0x0EC8CA952, 0x8F569D19, 0x0BD7012B, 0x321D272,
0x48449E02, 0x1935FB08, 0x0A385A51D, 0x0CCECA723,
0x8C95F91C, 0x47622721, 0x9663D16C, 0x0E7CF215C,
0x88291E02, 0x346FFC3F, 0x42140649, 0x3437320F,
0x90CB8C3D, 0x82D27742, 0x920DEB56, 0x37C2363C,
0x335E5F67, 0x0AEBF2B09, 0x0A5424263, 0x0CC9F4F40,
0x7BBE5C08, 0x595C1A71, 0x89894A2A, 0x0E6FA7B06,
0x0F4524C44, 0x930ED439, 0x0FE7DEF62, 0x0E0DFF516,
0x22657153, 0x955F10D, 0x0E300C809, 0x6BA90F56,
0x33492E48, 0x38EDC807, 0x1AF75F76, 0x16A603F9,
0x0CEE89448, 0x0CEF98866, 0x96EF0710, 0x5612B34A,
0x2698526, 0x0D9030E59, 0x8B49E559, 0x92341264,
0x5BD6851B, 0x1D57D030, 0x0C9F64820, 0x8F34E502,
0x0CB16FC39, 0x6E398B03, 0x5BD43443, 0x46D55842,
0x0C795A574, 0x0E45D7F6D, 0x2DD0D448, 0x0BBE8F138,
0x776C5327, 0x2B4EC42B, 0x9BC8E74F, 0x9AD1C47A,
0x9C2DED7, 0x47EBC365, 0x186BC083, 0x2CD44485,
0x4501D01, 0x3C118C4A, 0x64D8804, 0x0D238B249,
0x1403F224, 0x7AB1BFA2, 0x79B5A21A, 0x294DC7C1,
0x76409E6D, 0x0B4944A6E, 0x9EA8AC3B, 0x0D1162409,
0x0D1EB1A1F, 0x679FF55B, 0x604B090C, 0x9C021759,
0x0D5D8805F, 0x0BB1F3E4F, 0x0E2D76F1B, 0x9C6E2654,
0x6F1653D3, 0x58E808E, 0x72C54CA4, 0x421E6816,
0x3AF60810, 0x0F21F005D, 0x0B1BBD55E, 0x6F99BE49,
0x70E9AF36, 0x0B636AA2F, 0x0C6C6601A, 0x7539CD37,
0x0F247367A, 0x0CD13E91E, 0x47727F01, 0x0FD524B2B,
0x6A507933, 0x70BDE415, 0x9C7E502, 0x0E0901721,
0x24522F04, 0x0A86F923E, 0x0B1A73B2A, 0x0F53D4A23,
0x0F0F881A, 0x12F34436, 0x9140617C, 0x0E5E7087A,
0x0CD128305, 0x7418D117, 0x81562F4E, 0x6D904042,
0x83C0157C, 0x0D9AD475B, 0x847A5126, 0x0BEB61E0C,
0x0CBCD4738, 0x35362705, 0x2D50DD55, 0x3CB7F76E,
0x0EB6CD134, 0x0F3163E70, 0x0B1F0C426, 0x0DDB4072F,
0x0C02A270F, 0x0F8624428, 0x0DA07535A, 0x2A7BA042,
0x6920293E, 0x0E4CE385D, 0x0A0CB863, 0x8D725842,
0x8C3ECB1B, 0x0BCB3F30D, 0x83B0A265, 0x9B4D5336,
0x0CEA63844, 0x14F10362, 0x80355C30, 0x9BB9BB49,
0x8809D579, 0x28C8B7E, 0x84AFC0B, 0x0CCAEA75,
0x0DB39D359, 0x8CC44D32, 0x0CA800902, 0x0A6071B12,
0x0C1FA7437, 0x0F7D0E657, 0x0E2BE1201, 0x0AC67466C,
0x0EAE72448, 0x93AFD727, 0x8A1C4E1B, 0x0AB124C57,
0x8C121C50, 0x6424A175, 0x0D58DEC19, 0x0F532450E,
0x48F3D952, 0x0E099A47D, 0x82A59D50, 0x0D431A56E,
0x9C4D980B, 0x5564036, 0x707FF824, 0x6AF4D04F,
0x1A474418, 0x0F0B45455, 0x5AE8C19, 0x0A2501912,
0x0F240E053, 0x0EF88825, 0x0AE1A0408, 0x0CD7AB32D,
0x9ABCD657, 0x789B0D0A, 0x7482CE3F, 0x5CB74B0F,
0x6F6CF461, 0x5641E140, 0x81F927B, 0x5A54192A,
0x0EAF0B868, 0x923BE016, 0x5676501, 0x7603D538,
0x0F75F810C, 0x0DAF4511B, 0x6B361A47, 0x3F535B5F,
0x0BA8EF618, 0x0EDDBB717, 0x1485004E, 0x56DC8E24,
0x0F331F84D, 0x8404F972, 0x0C0D05F74, 0x0D793C66,
0x74B94D48, 0x0C67EEC0D, 0x0AFC95578, 0x67FA2D1C,
0x0D4767533, 0x5EE45900, 0x3475E149, 0x6E334C0B,
0x0D67F670A, 0x0A8F7AF09, 0x0CAEA971A, 0x46EC5B6C,
0x0FF38914A, 0x0D3092A16, 0x0A0407516, 0x0E9294A33,
0x65450A2D, 0x0A5A7DA17, 0x5F2D1F6C, 0x5CA58B39,
0x7F9C2C33, 0x0CA633933, 0x9CF8E618, 0x3A2B234C,
0x0B73FF14A, 0x0B07DE766, 0x9007B270, 0x0AA71E918,
0x651F1C1E, 0x26BAD541, 0x3BB54E34, 0x1808FEB5,
0x1757FE72, 0x67B47B77, 0x0F365C3E, 0x0EBCD7326,
0x0C598D577, 0x44AB3D08, 0x5901C031, 0x9B183D02,
0x0ECA2ED11, 0x24EC574C, 0x0E104996E, 0x0EBDB7E5C,
0x0F7F58162, 0x81450E05, 0x0D405C90F, 0x5C3B8C0F,
0x26EDE81C, 0x3333E87B, 0x0B9E01749, 0x0A6891550,
0x379DF767, 0x25F74426, 0x56BCA7E, 0x506B7E85,
0x557E648, 0x70BCEA0C, 0x5F48FC12, 0x39D9C622,
0x0C194FC71, 0x17332212, 0x0E114F544, 0x0D8EBFA64,
0x7EE79D09, 0x0F14A5103, 0x0C3B96E0B, 0x43807301,
0x35F68E0B, 0x1DBB2E3D, 0x0DE98B003, 0x21997C1D,
0x41A78609, 0x0C09D4972, 0x0D75FB79, 0x389D086C,
0x41E35777, 0x0E17AC409, 0x94D8947B, 0x68D04014,
0x15AEAC05, 0x4DB9AC44, 0x0E5A5664, 0x1245CE34,
0x0A292AB26, 0x0EE0E8F00, 0x0C71BE12E, 0x0A7E9916F,
0x661BB411, 0x22141736, 0x759DCAB4, 0x0C96738C,
0x3E97FF53, 0x0C2D74D57, 0x0F84B7164, 0x0BC7E9D5D,
0x0B3229F5A, 0x0BC05E06F, 0x0FFFE105F, 0x0E8182E66,
0x0D9C00E2D, 0x0DD97C162, 0x9B2AA03, 0x1A689536,
0x9D350B55, 0x1627A67D, 0x52059E22, 0x0DF18634C,
0x45B29845, 0x33707F31, 0x7D2A391A, 0x121830EF,
0x404E787, 0x1C6E6D0, 0x5102FAD8, 0x6BFF20FE,
0x43528945, 0x0E7B0C670, 0x7E131D79, 0x0A11D0353,
0x3DD5639C, 0x506219F3, 0x72461551, 0x4C3DA71E,
0x20AEC362, 0x0BAC9EA36, 0x82B4164, 0x0D3D0623D,
0x76CFCA26, 0x72A5243, 0x0BBE99023, 0x4F90D953,
0x0E4C11326, 0x0C59B3B27, 0x69F86E0A, 0x82F71E7B,
0x0DBC2E124, 0x0BBFD0C2D, 0x61108247, 0x0D3644C2C,
0x0A1DB3F4B, 0x0A8F92528, 0x0E0B46339, 0x0D5721F2E,
0x0FD3C206D, 0x4A497B, 0x0AC9CAA37, 0x408FA932,
0x0E7FA0F6C, 0x2AB0C730, 0x0E1ACAC05, 0x0F50FB41E,
0x88863D3C, 0x0A32A2658, 0x41BC5725, 0x0A934011F,
0x5DF4100F, 0x49E79809, 0x7C05645C, 0x0D3C3DB35,
0x5011EB4C, 0x38EFF47F, 0x2254B509, 0x34D3FE72,
0x0FD8A3027, 0x8B4C2414, 0x0B6CA1D6E, 0x0D84D124C,
0x5D1461FF, 0x663F3D06, 0x372DED1B, 0x0E875F28,
0x0BFD4C55D, 0x8C67C231, 0x0BD98903A, 0x0BC11E64A,
0x8CB10B2D, 0x69353B72, 0x0FCA08F7D, 0x73AC1B19,
0x93E50223, 0x0DE4D3C03, 0x68BCCF37, 0x1B6C405F,
0x8178625B, 0x0A978275D, 0x0C4A0417E, 0x0DE6C736A,
0x0F25FC066, 0x41A6A55A, 0x0B1304F20, 0x4271AB33,
0x79959A5A, 0x0D384042A, 0x7744AA26, 0x7620CB01,
0x5E4F198, 0x63938F5C, 0x1551A865, 0x98C9E55,
0x45EA674A, 0x0FA203C46, 0x8B41CB0B, 0x4BF2D28,
0x8788FE77, 0x48DA5B46, 0x0C1D01373, 0x133A0A25,
0x0B10F9738, 0x0BD71A370, 0x87E6253E, 0x44F5995B,
0x9BBFDF73, 0x0EFA2F575, 0x6061DA3A, 0x1C38424F,
0x991B1D53, 0x24021C39, 0x0FAA4B539, 0x8B7BDD39,
0x21FDE62, 0x15694DC9, 0x7690AA57, 0x8ABEAA2,
0x7E5A0904, 0x45313314, 0x545E2770, 0x0DC2B3242,
0x7240FB28, 0x0A3CC043E, 0x80478C41, 0x0B72A6373,
0x9DED4004, 0x0C89574D, 0x0BCE9901B, 0x24763F7C,
0x5463B313, 0x7DBAA40E, 0x38B04921, 0x6734A4C,
0x3A2C487F, 0x0BF966F5F, 0x4A68E427, 0x0D6EB2773,
0x0AE396555, 0x0AAC9BE62, 0x0F2236A42, 0x47558228,
0x0CFCBDA1B, 0x0EDC81F7C, 0x0D3D05F62, 0x34749C2F,
0x989E2456, 0x0A1BDE84F, 0x13B2F81D, 0x17F92D5A,
0x0E6EE1B64, 0x6710200E, 0x0F324601C, 0x582F170D,
0x0ADD244C, 0x746CEC5D, 0x105A7A00, 0x0A8CA6550,
0x80F5432B, 0x0CC430B1C, 0x0CC40A54C, 0x0D458F73E,
0x49FEAF2A, 0x4F1EE6D, 0x0DACB410B, 0x832AF829,
0x0C3875E4D, 0x25342633, 0x5916201D, 0x72C1C322,
0x0CFFDE415, 0x4C3A8A5F, 0x0B916464B, 0x9EC9BF31,
0x3903AA5B, 0x8CE7A52D, 0x0D33D5C61, 0x0D1A1CE31,
0x2DA58E7D, 0x0E6EF547F, 0x0E89AFC0B, 0x1394AA61,
0x4D00750D, 0x0DCBF5C28, 0x6CC3C16E, 0x58DD9959,
0x502C4906, 0x7C1D3C6F, 0x0A8FF29, 0x0D0218D31,
0x4861470B, 0x0CCE8A476, 0x0A47A8470, 0x915FF735,
0x0D1D99364, 0x7F46C67B, 0x148AEF5F, 0x9461F231,
0x0A47AEC2E, 0x6EA00F7D, 0x623B654, 0x7378D144,
0x0BADA995C, 0x0C039FC1F, 0x12429176, 0x0F3DD4338,
0x4C21A24D, 0x0E57FED57, 0x0C47F126A, 0x7AC6304B,
0x0CB6F4257, 0x0AD1A0F76, 0x8D5ADB2C, 0x1870B764,
0x89DA6B1E, 0x0F91D9D1B, 0x704D513E, 0x0D906B524,
0x753BD90A, 0x70F55068, 0x0A9284256, 0x0BD9C2016,
0x3DDEF55E, 0x4DA3C646, 0x4EFC174C, 0x0EB88943,
0x3F3E0774, 0x3FC4E8FE, 0x3535FFF7, 0x67EFA479,
0x0D1261729, 0x0A93C324A, 0x0E4DC4A36, 0x8B01B105,
0x69762E6A, 0x0F61EDC2C, 0x7EDFF43D, 0x0B597D037,
0x1E7FC078, 0x55DDE79B, 0x3ECE9111, 0x1CC0FFF3,
0x0EF79161E, 0x0BDB8DC2F, 0x0BE7EC340, 0x7854823C,
0x0B6D6794B, 0x2FCC147F, 0x515B3761, 0x2C125356,
0x9FC16567, 0x0FA837937, 0x0E9AE736C, 0x0DC9F5B46,
0x4827407E, 0x38AB8B38, 0x0EA57E509, 0x1411CD40,
0x9B319364, 0x8D71617F, 0x85754632, 0x6C58AA0D };
amsn-0.98.9/utils/webcamsn/src/kidhash.h 0000644 0001750 0001750 00000000152 10253461533 017703 0 ustar billiob billiob #ifndef KIDHASH_H
#define KIDHASH_H
int MakeKidHash(char *a, int *a_size, int kid, char * sid);
#endif
amsn-0.98.9/utils/webcamsn/src/Rules.mk 0000644 0001750 0001750 00000001473 10750446030 017546 0 ustar billiob billiob OBJS-webcamsn := $(webcamsn_dir)/src/webcamsn.o $(webcamsn_dir)/src/kidhash.o $(webcamsn_dir)/src/libmimic.a
TARGETS-webcamsn := $(webcamsn_dir)/src/webcamsn.$(SHLIB_EXTENSION)
OBJS-mimic := $(webcamsn_dir)/src/bitstring.o $(webcamsn_dir)/src/deblock.o $(webcamsn_dir)/src/encode.o \
$(webcamsn_dir)/src/idct_dequant.o $(webcamsn_dir)/src/mimic.o \
$(webcamsn_dir)/src/vlc_decode.o $(webcamsn_dir)/src/colorspace.o $(webcamsn_dir)/src/decode.o \
$(webcamsn_dir)/src/fdct_quant.o $(webcamsn_dir)/src/vlc_common.o $(webcamsn_dir)/src/vlc_encode.o
TARGETS-mimic := $(webcamsn_dir)/src/libmimic.a
$(TARGETS-mimic): $(OBJS-mimic)
@$(echo_ar_lib)
@$(ar_lib)
$(TARGETS-webcamsn): $(OBJS-webcamsn)
all:: $(TARGETS-webcamsn)
clean:: clean-webcamsn
clean-webcamsn::
rm -f $(TARGETS-webcamsn) $(OBJS-webcamsn)
amsn-0.98.9/utils/webcamsn/src/mimic-private.h 0000644 0001750 0001750 00000005711 10647521273 021051 0 ustar billiob billiob /* Copyright (C) 2005 Ole André Vadla Ravnås
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef MIMIC_PRIVATE_H
#define MIMIC_PRIVATE_H
#include "mimic.h"
#define MIMIC_ENCODER_DEFAULT_QUALITY 0
struct _MimCtx {
gboolean encoder_initialized;
gboolean decoder_initialized;
gint frame_width;
gint frame_height;
gint quality;
gint num_coeffs;
gint y_stride;
gint y_row_count;
gint y_size;
gint crcb_stride;
gint crcb_row_count;
gint crcb_size;
gint num_vblocks_y;
gint num_hblocks_y;
gint num_vblocks_cbcr;
gint num_hblocks_cbcr;
guchar *cur_frame_buf;
guchar *prev_frame_buf;
gint8 vlcdec_lookup[2296];
gchar *data_buffer;
guint data_index;
guint32 cur_chunk;
gint cur_chunk_len;
guint32 *chunk_ptr;
gboolean read_odd;
gint frame_num;
gint ptr_index;
guchar *buf_ptrs[16];
};
typedef struct {
guchar length1;
guint32 part1;
guchar length2;
guint32 part2;
} VlcSymbol;
typedef struct {
guint32 magic;
guchar pos_add;
guchar num_bits;
} VlcMagic;
void _mimic_init(MimCtx *ctx, gint width, gint height);
guchar _clamp_value(gint value);
guint32 _read_bits(MimCtx *ctx, gint num_bits);
void _write_bits(MimCtx *ctx, guint32 bits, gint length);
void _vlc_encode_block(MimCtx *ctx, const gint *block, gint num_coeffs);
gboolean _vlc_decode_block(MimCtx *ctx, gint *block, gint num_coeffs);
void _fdct_quant_block(MimCtx *ctx, gint *block, const guchar *src,
gint stride, gboolean is_chrom, gint num_coeffs);
void _idct_dequant_block(MimCtx *ctx, gint *block, gboolean is_chrom);
VlcMagic *_find_magic(guint magic);
void _initialize_vlcdec_lookup(gint8 *lookup_tbl);
void _rgb_to_yuv(const guchar *input_rgb,
guchar *output_y,
guchar *output_cb,
guchar *output_cr,
gint width,
gint height);
void _yuv_to_rgb(const guchar *input_y,
const guchar *input_cb,
const guchar *input_cr,
guchar *output_rgb,
guint width,
guint height);
void _deblock(guchar *blocks, guint stride, guint row_count);
#endif // MIMIC_PRIVATE_H
amsn-0.98.9/utils/webcamsn/src/kidhash.c 0000644 0001750 0001750 00000014164 10516043025 017700 0 ustar billiob billiob #include
#include
#include "kidhash.h"
#include "constants.h"
#include "glib_replacement.h"
const double append_multiplicator = 4.614703357219696e-7;
const char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789./";
const int init_variable = 0x0FE0637B1;
int init_table[31];
int init_table_size = 31;
int *init_table_ptr = NULL;
int *init_table_end = NULL;
int *init_table_idx2 = NULL;
int *init_table_idx1 = NULL;
int init_table_idx_diff = 3;
const int fixed_value_3 = 3;
int key[26];
void crazy_algorithm(int *table,int *temp_data) {
unsigned int i, temp = 0;
// Initialize the 4 temp variables
int P = table[1],
PP = table[2],
PPP = table[3],
PPPP = table[0];
// four loops made into one
for (i = 0; i < 16*4; i++) {
temp = PPPP + const_mult[i] * const_values[i]; // Common to all loops
if(i/16 == 0) temp += GUINT32_FROM_LE(temp_data[i]) + (PPP ^ (P & (PP ^ PPP))); // add this for first loop i =[0..15]
else if(i/16 == 1) temp += GUINT32_FROM_LE(temp_data[((i-16)*5 + 1)%16]) + (PP ^ (PPP & (P ^ PP))); // add for second i = [16..31]
else if(i/16 == 2) temp += GUINT32_FROM_LE(temp_data[((i-32)*3 + 5)%16]) + (P ^ (PP ^ PPP)); // add for second i = [31..47]
else if(i/16 == 3) temp += GUINT32_FROM_LE(temp_data[choose_data_idx[i-48]]) + (PP ^ ((PPP ^ 0xFFFFFFFF) | P)); // add for the last loop
PPPP = PPP; PPP = PP; PP = P;
P += (temp >> shifts_right[(i%4) + 4*(i/16)]) | (temp << shifts_left[(i%4) + 4*(i/16)]); // look for the shifts in the table
}
// store in the output variables
table[0] += PPPP;
table[1] += P;
table[2] += PP;
table[3] += PPP;
return;
}
int alter_table() {
int ret;
if (fixed_value_3 != 0 ) {
*init_table_idx2 = *init_table_idx1 + *init_table_idx2;
ret = *init_table_idx2 >> 1 & 0x7fffffff;
if (init_table_idx2 + 1 < init_table_end) {
if(init_table_idx1 + 1 >= init_table_end)
init_table_idx1 = init_table_ptr;
else
init_table_idx1++;
init_table_idx2++;
} else {
init_table_idx2 = init_table_ptr;
init_table_idx1++;
}
} else {
init_table_ptr[0] = init_table_ptr[0] % 0x1f31d * 0x41a7 -
init_table_ptr[0] / 0x1f31d * 0xb14;
if ( init_table_ptr[0] <= 0)
init_table_ptr[0] += 0x7fffffff;
init_table_ptr[0] &= 0x7fffffff;
ret = init_table_ptr[0];
}
return ret;
}
void init(int value) {
int i = 0;
*init_table_ptr = value;
if(fixed_value_3) {
for (i = 1; i < init_table_size; i++) {
init_table_ptr[i] = init_table_ptr[i-1] % 0x1f31d * 0x41a7 -
init_table_ptr[i-1] / 0x1f31d * 0xb14;
if ( init_table_ptr[i] <= 0)
init_table_ptr[i] += 0x7fffffff;
}
init_table_idx1 = init_table_ptr;
init_table_idx2 = init_table_ptr + init_table_idx_diff;
for(i = init_table_size * 10; i > 0; i--) alter_table();
}
return;
}
void set_result (int *table, char * temp_data, int * result) {
char * temp_data_ptr = temp_data;
int idx;
idx = (table[4] / 8) & 63;
temp_data_ptr = temp_data + idx;
*temp_data_ptr = 0x80;
temp_data_ptr++;
idx = 55 - idx;
if ( idx < 0) {
memset(temp_data_ptr, 0, idx + 8);
crazy_algorithm(table, (int *)temp_data);
memset(temp_data, 0, 56);
} else
memset(temp_data_ptr, 0, idx);
temp_data_ptr += idx;
// The last 2 dwords are size / 8 and a bool for if size > 64
*((int *)temp_data_ptr) = GUINT32_TO_LE(table[4]);
temp_data_ptr+=4;
*((int *)temp_data_ptr) = GUINT32_TO_LE(table[5]);
crazy_algorithm(table, (int *)temp_data);
result[0] = table[0];
result[1] = table[1];
result[2] = table[2];
result[3] = table[3];
result[4] = 0;
}
void Hash(char * a, int key_size) {
int result[5],
table[] = {0x67452301,
0x0EFCDAB89,
0x98BADCFE,
0x10325476,
8*key_size,
key_size >> 29};
char temp_data[64];
int *key_ptr = key;
char *a_ptr = a;
int i, temp;
if(key_size >= 64) {
for(i = key_size / 64; i > 0 ; i--) {
memcpy(temp_data, key_ptr, 64);
crazy_algorithm(table, (int *)temp_data);
key_ptr += 16;
}
key_size &= 63;
}
memcpy(temp_data, key_ptr, key_size);
set_result(table, temp_data, result);
result[0] = GUINT32_TO_LE(result[0]);
result[1] = GUINT32_TO_LE(result[1]);
result[2] = GUINT32_TO_LE(result[2]);
result[3] = GUINT32_TO_LE(result[3]);
result[4] = GUINT32_TO_LE(result[4]);
for (i = 0 ; i < 18; i += 3) {
temp = (0x000000ff &((char *) result)[i]) << 16 |
(0x000000ff & ((char *) result)[i+1]) << 8 |
(0x000000ff & ((char *) result)[i+2]);
a_ptr[0] = alphabet[temp >> 6 >> 6 >> 6 & 0x3F];
a_ptr[1] = alphabet[temp >> 6 >> 6 & 0x3F];
a_ptr[2] = alphabet[temp >> 6 & 0x3F];
a_ptr[3] = alphabet[temp & 0x3F];
a_ptr+=4;
}
*(a_ptr - 2) = 0;
}
int MakeKidHash(char *a, int *a_size, int kid, char * sid) {
int i;
char * sid_ptr = sid;
char *key_ptr = (char *) key;
char *append_char;
char *append_ptr;
if(kid < 0 || kid > 100) return 0;
if (*a_size < 25) return 0;
memset(key, 0, 26 * sizeof(int));
init_table_ptr = init_table;
init_table_idx1 = init_table_ptr;
init_table_idx2 = init_table_ptr + init_table_idx_diff;
init_table_end = init_table_ptr + init_table_size;
for (i = 0 ; i < 100; i++) {
if(*sid_ptr == 0) break;
*key_ptr = *sid_ptr;
key_ptr++;
sid_ptr++;
}
if (sid_ptr - sid + append_size > 100) return 0;
init(init_variable);
while(kid > 0) {
alter_table();
kid--;
}
append_char = (char *) (key_append + (long) (alter_table() * append_multiplicator) * 4);
append_ptr = append_char;
for (i = 0 ; i < append_size; i++) {
#ifdef __BIG_ENDIAN__
*key_ptr = append_char[3 - ((append_ptr - append_char)%4) + 4*((append_ptr - append_char)/4)];
#else
*key_ptr = *append_ptr;
#endif
key_ptr++;
append_ptr++;
}
Hash(a, (int) (sid_ptr - sid) + append_size);
return 1;
}
int test () {
char sid[] = "sid=aD4ENXNY3Q";
char sid2[] = "sid=KCSwrDFrVg";
char a[30];
int kid = 64;
int kid2 = 98;
int a_size = 30;
printf("\n");
if (MakeKidHash(a, &a_size, kid2, sid2)) {
printf("Computed hash is : %s\n", a);
printf("Should be : hHQbVkZ/eApiRzPiTg6jyw\n\n\n");
}
if(MakeKidHash(a, &a_size, kid, sid)) {
printf("Computed hash is : %s\n", a);
printf("Should be : HlyPs6/kiWhr0JxmMO1A4Q\n");
}
printf("\n\n");
return 0;
}
amsn-0.98.9/utils/webcamsn/src/Webcamsn.dsw 0000644 0001750 0001750 00000001407 10455541227 020404 0 ustar billiob billiob Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "Webcamsn"=.\Webcamsn.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name libmimic
End Project Dependency
}}}
###############################################################################
Project: "libmimic"=.\libmimic.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################
amsn-0.98.9/utils/webcamsn/src/bitstring.c 0000644 0001750 0001750 00000005162 10225230720 020265 0 ustar billiob billiob /* Copyright (C) 2005 Ole André Vadla Ravnås
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "mimic-private.h"
/*
* _read_bits
*
* Internal helper-function used to read num_bits
* from stream.
*/
guint32 _read_bits(MimCtx *ctx, gint num_bits)
{
guint32 bits;
if (ctx->cur_chunk_len >= 16) {
guchar *input_buf = (guchar *) ctx->data_buffer + ctx->data_index;
if (!ctx->read_odd) {
ctx->read_odd = TRUE;
ctx->cur_chunk = (input_buf[3] << 24) |
(input_buf[2] << 16) |
(input_buf[1] << 8) |
input_buf[0];
} else {
ctx->read_odd = FALSE;
ctx->cur_chunk = (input_buf[1] << 24) |
(input_buf[0] << 16) |
(input_buf[7] << 8) |
input_buf[6];
ctx->data_index += 4;
}
ctx->cur_chunk_len -= 16;
}
bits = (ctx->cur_chunk << ctx->cur_chunk_len) >> (32 - num_bits);
ctx->cur_chunk_len += num_bits;
return bits;
}
/*
* _write_bits
*
* Internal helper-function used to write "length"
* bits of "bits" to stream.
*/
void _write_bits(MimCtx *ctx, guint32 bits, gint length)
{
/* Left-align the bit string within its 32-bit container. */
bits <<= (32 - length);
/* Append the bit string (one or more of the trailing bits might not fit, but that's ok). */
ctx->cur_chunk |= bits >> ctx->cur_chunk_len;
ctx->cur_chunk_len += length;
/* Is it full? */
if (ctx->cur_chunk_len >= 32) {
/* Add the full 32-bit chunk to the stream and update counter. */
ctx->chunk_ptr[0] = GUINT32_TO_LE(ctx->cur_chunk);
ctx->chunk_ptr++;
ctx->cur_chunk_len -= 32;
/* Add any trailing bits that didn't fit. */
ctx->cur_chunk = bits << (length - ctx->cur_chunk_len);
}
}
amsn-0.98.9/utils/webcamsn/src/idct_dequant.c 0000644 0001750 0001750 00000007325 10225230720 020727 0 ustar billiob billiob /* Copyright (C) 2005 Ole Andr Vadla Ravns
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "mimic-private.h"
void _idct_dequant_block(MimCtx *ctx, gint *block, gboolean is_chrom)
{
gdouble f;
gint i, *p;
/*
* De-quantize.
*/
f = (10000 - ctx->quality) * 10.0 * (gfloat) 9.9999997e-5;
if (f > 10.0)
f = 10.0;
if (!is_chrom) {
if (f < 2.0)
f = 2.0;
} else {
if (f < 1.0)
f = 1.0;
}
block[0] <<= 1;
block[1] <<= 2;
block[8] <<= 2;
for (i = 2; i < 64; i++) {
if (i == 8)
continue;
block[i] *= f;
}
/*
* Inverse DCT, first pass (horizontal).
*/
p = block;
for (i = 0; i < 8; i++) {
gint v1, v2, v3, v4, v5, v6, v7, v8;
gint va, vb;
va = (p[0] << 11) + (p[4] << 11);
vb = ((p[2] << 2) * 392) + (((p[2] << 2) + (p[6] << 2)) * 277);
v1 = va + vb + 512;
v2 = va - vb + 512;
va = (p[0] << 11) - (p[4] << 11);
vb = (((p[2] << 2) + (p[6] << 2)) * 277) - ((p[6] << 2) * 946);
v3 = va + vb + 512;
v4 = va - vb + 512;
va = (p[1] << 9) + (p[3] * 724) + (p[7] << 9);
vb = (p[1] << 9) + (p[5] * 724) - (p[7] << 9);
v5 = (((va + vb) * 213) - (vb * 71)) >> 6;
v6 = (((va + vb) * 213) - (va * 355)) >> 6;
va = (p[1] << 9) - (p[3] * 724) + (p[7] << 9);
vb = (p[1] << 9) - (p[5] * 724) - (p[7] << 9);
v7 = (((va + vb) * 251) - (va * 201)) >> 6;
v8 = (((va + vb) * 251) - (vb * 301)) >> 6;
p[0] = (v1 + v5) >> 10;
p[1] = (v3 + v7) >> 10;
p[2] = (v4 + v8) >> 10;
p[3] = (v2 + v6) >> 10;
p[4] = (v2 - v6) >> 10;
p[5] = (v4 - v8) >> 10;
p[6] = (v3 - v7) >> 10;
p[7] = (v1 - v5) >> 10;
p += 8;
}
/*
* Inverse dct, second pass (vertical).
*/
p = block;
for (i = 0; i < 8; i++) {
gint v1, v2, v3, v4, v5, v6, v7, v8;
gint va, vb;
va = (p[0] << 9) + (p[32] << 9);
vb = ((p[16] + p[48]) * 277) + (p[16] * 392);
v1 = va + vb + 1024;
v2 = va - vb + 1024;
va = (p[0] << 9) - (p[32] << 9);
vb = ((p[16] + p[48]) * 277) - (p[48] * 946);
v3 = va + vb + 1024;
v4 = va - vb + 1024;
va = ((p[8] << 7) + (p[24] * 181) + (p[56] << 7)) >> 6;
vb = ((p[8] << 7) + (p[40] * 181) - (p[56] << 7)) >> 6;
v5 = ((va + vb) * 213) - (vb * 71);
v6 = ((va + vb) * 213) - (va * 355);
va = ((p[8] << 7) - (p[24] * 181) + (p[56] << 7)) >> 6;
vb = ((p[8] << 7) - (p[40] * 181) - (p[56] << 7)) >> 6;
v7 = ((va + vb) * 251) - (va * 201);
v8 = ((va + vb) * 251) - (vb * 301);
p[0] = (v1 + v5) >> 11;
p[8] = (v3 + v7) >> 11;
p[16] = (v4 + v8) >> 11;
p[24] = (v2 + v6) >> 11;
p[32] = (v2 - v6) >> 11;
p[40] = (v4 - v8) >> 11;
p[48] = (v3 - v7) >> 11;
p[56] = (v1 - v5) >> 11;
p++;
}
}
amsn-0.98.9/utils/webcamsn/src/webcamsn.h 0000644 0001750 0001750 00000006447 11231467240 020102 0 ustar billiob billiob /*
File : webcamsn.h
Description : Header file for the webcamsn extension for tk. A wrapper for libmimdec
Author : Youness El Alaoui ( KaKaRoTo - kakaroto@user.sourceforge.net)
*/
#ifndef _WEBCAMSN
#define _WEBCAMSN
// Include files, must include windows.h before tk.h and tcl.h before tk.h or else compiling errors
#include
#include "mimic.h"
#ifdef WIN32
#include
#endif
#include "string.h"
#include
#include
// Defined as described in tcl.tk compiling extension help
#ifndef STATIC_BUILD
#if defined(_MSC_VER)
# define EXPORT(a,b) __declspec(dllexport) a b
# define DllEntryPoint DllMain
#else
# if defined(__BORLANDC__)
# define EXPORT(a,b) a _export b
# else
# define EXPORT(a,b) a b
# endif
#endif
#endif
#define DLL_BUILD
#define BUILD_WEBCAMSN
#ifdef BUILD_WEBCAMSN
# undef TCL_STORAGE_CLASS
# define TCL_STORAGE_CLASS DLLEXPORT
#endif
#ifdef __cplusplus
extern "C"
#endif
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned int DWORD;
typedef struct mimic_header {
WORD header_size;
WORD width;
WORD height;
WORD reserved1;
DWORD payload_size;
DWORD fourcc;
DWORD reserved2;
DWORD reserved3;
} MimicHeader;
enum codec_types {ENCODER, DECODER_UNINITIALIZED, DECODER_INITIALIZED};
struct CodecInfo {
MimCtx * codec;
enum codec_types type;
char name[30];
unsigned int frames;
};
typedef struct CodecInfo CodecInfo;
#define MAX_INTERFRAMES 15
EXTERN BYTE * RGBA2RGB(Tk_PhotoImageBlock data);
// External functions
EXTERN int Webcamsn_Init _ANSI_ARGS_((Tcl_Interp *interp));
EXTERN int Webcamsn_SafeInit _ANSI_ARGS_((Tcl_Interp *interp));
EXTERN int Webcamsn_NewDecoder _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]));
EXTERN int Webcamsn_NewEncoder _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]));
EXTERN int Webcamsn_Decode _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]));
EXTERN int Webcamsn_Encode _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]));
EXTERN int Webcamsn_SetQuality _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]));
EXTERN int Webcamsn_GetWidth _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]));
EXTERN int Webcamsn_GetHeight _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]));
EXTERN int Webcamsn_GetQuality _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]));
EXTERN int Webcamsn_Close _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]));
EXTERN int Webcamsn_Count _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]));
EXTERN int Webcamsn_Frames _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]));
# undef TCL_STORAGE_CLASS
# define TCL_STORAGE_CLASS DLLIMPORT
#endif /* _TKCXIMAGE */
amsn-0.98.9/utils/webcamsn/src/deblock.c 0000644 0001750 0001750 00000025050 10225230720 017661 0 ustar billiob billiob /* Copyright (C) 2005 Ole Andr Vadla Ravns
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include
#include
#include "mimic-private.h"
static void deblock_horizontal(guchar *blocks, guint stride, guint row_count);
static void deblock_vertical(guchar *blocks, guint stride, guint row_count);
static gboolean deblock_h_consider_entire(guchar *blocks, guint stride);
static void deblock_h_do_entire(guchar *blocks, guint stride);
static void deblock_h_do_boundaries(guchar *blocks, guint stride);
static gboolean deblock_v_consider_entire(guchar *blocks, guint stride);
static void deblock_v_do_entire(guchar *blocks, guint stride);
static void deblock_v_do_boundaries(guchar *blocks, guint stride);
/*
* _deblock
*
* Internal helper-function used for de-blocking.
*/
void _deblock(guchar *blocks, guint stride, guint row_count)
{
deblock_horizontal(blocks, stride, row_count);
deblock_vertical(blocks, stride, row_count);
}
static void deblock_horizontal(guchar *blocks, guint stride, guint row_count)
{
guchar *p1;
gint i, j, n1, n2;
if (stride <= 8 || row_count == 0)
return;
p1 = blocks + 4;
n1 = ((row_count - 1) >> 2) + 1;
n2 = ((stride - 9) >> 3) + 1;
for (i = 0; i < n1; i++) {
guchar *p;
p = p1;
for (j = 0; j < n2; j++) {
if (deblock_h_consider_entire(p - 1, stride) == TRUE) {
gint v1, v2, v;
v1 = p[0];
v2 = p[7];
v = v1 - v2;
if (v <= 0)
v = v2 - v1;
if (v < 20)
deblock_h_do_entire(p - 1, stride);
} else {
deblock_h_do_boundaries(p - 1, stride);
}
p += 8;
}
p1 += stride * 4;
}
}
static void deblock_vertical(guchar *blocks, guint stride, guint row_count)
{
gint i, j, k, n1, n2;
guchar *p1, *p2;
if (stride == 0 || row_count <= 8)
return;
p1 = blocks + (stride * 3);
p2 = blocks + (stride * 4);
n1 = ((row_count - 9) >> 3) + 1;
n2 = ((stride - 1) >> 3) + 1;
for (i = 0; i < n1; i++) {
guchar *p3, *p4;
p3 = p1;
p4 = p2;
for (j = 0; j < n2; j++) {
if (deblock_v_consider_entire(p3, stride) == TRUE) {
guchar *p5;
gboolean do_entire;
p5 = p3 + (stride * 8);
do_entire = TRUE;
for (k = 0; k < 8; k++) {
gint v1, v2, v;
v1 = p4[k];
v2 = p5[k];
v = v1 - v2;
if (v <= 0)
v = v2 - v1;
if (v > 20) {
do_entire = FALSE;
break;
}
}
if (do_entire)
deblock_v_do_entire(p3, stride);
} else {
deblock_v_do_boundaries(p3, stride);
}
p3 += 8;
p4 += 8;
}
p1 += stride * 8;
p2 += stride * 8;
}
}
static gboolean deblock_h_consider_entire(guchar *blocks, guint stride)
{
guchar *p;
gint i, j, count;
count = 0;
p = blocks;
for (i = 0; i < 4; i++) {
for (j = 1; j <= 7; j++) {
gint v1, v2, v;
v1 = p[j];
v2 = p[j+1];
v = v1 - v2;
if (v <= 0)
v = v2 - v1;
if (v <= 1)
count--;
}
p += stride;
}
return (count <= -20);
}
static void deblock_h_do_entire(guchar *blocks, guint stride)
{
guchar buf[8], *p;
gint i;
p = blocks;
for (i = 0; i < 4; i++) {
gint v, low, high;
v = p[0] - p[1];
if (v <= 0)
v = p[1] - p[0];
if (v < 10)
low = p[0];
else
low = p[1];
v = p[8] - p[9];
if (v <= 0)
v = p[9] - p[8];
if (v >= 10)
high = p[8];
else
high = p[9];
v = (low * 3) + p[1] + p[2] + p[3] + p[4] + 4;
buf[0] = (((p[1] + v) << 1) - p[4] + p[5]) >> 4;
v += p[5] - low;
buf[1] = (((p[2] + v) << 1) - p[5] + p[6]) >> 4;
v += p[6] - low;
buf[2] = (((p[3] + v) << 1) - p[6] + p[7]) >> 4;
v += p[7] - low;
buf[3] = (((p[4] + v) << 1) - p[1] - p[7] + p[8] + low) >> 4;
v += p[8] - p[1];
buf[4] = (((p[5] + v) << 1) + p[1] - p[2] - p[8] + high) >> 4;
v += high - p[2];
buf[5] = (((p[6] + v) << 1) + p[2] - p[3]) >> 4;
v += high - p[3];
buf[6] = (((p[7] + v) << 1) + p[3] - p[4]) >> 4;
v += high;
buf[7] = (((p[8] + v) << 1) - p[4] - p[5]) >> 4;
memcpy(p + 1, buf, 8);
p += stride;
}
}
static void deblock_h_do_boundaries(guchar *blocks, guint stride)
{
guchar *p;
gint i;
p = blocks;
for (i = 0; i < 4; i++) {
gint v, v1, v2, v3;
v = p[4] - p[5];
if ((v / 2) != 0) {
v1 = ((p[3] - p[6]) * 2) - (v * 5);
if (abs(v1) < 80) {
v2 = ((p[3] - p[2]) * 5) + ((p[1] - p[4]) * 2);
v3 = (p[5] * 2) + (p[7] * 5) - (p[8] * 7);
v = abs(v1) - MIN(abs(v2), abs(v3));
if (v > 0) {
v = ((v * 5) + 32) >> 6;
if (v > 0) {
v2 = (p[4] - p[5]) / 2;
v3 = (((v1 < 0) * 2) - 1) * v;
if (v2 > 0)
v = MIN(v2, ((v3 < 0) - 1) & v3);
else
v = MAX(v2, ((v3 > 0) - 1) & v3);
p[4] -= v;
p[5] += v;
}
}
}
}
p += stride;
}
}
static gboolean deblock_v_consider_entire(guchar *blocks, guint stride)
{
gint count, i, j;
guchar *p1, *p2;
count = 0;
p1 = blocks + stride;
p2 = blocks + (stride * 2);
for (i = 0; i < 7; i++) {
for (j = 0; j < 8; j++) {
gint v1, v2, v;
v1 = p1[j];
v2 = p2[j];
v = v1 - v2;
if (v <= 0)
v = v2 - v1;
if (v <= 1)
count++;
}
p1 += stride;
p2 += stride;
}
return (count > 40);
}
static void deblock_v_do_entire(guchar *blocks, guint stride)
{
gint offset0, offset1, offset2, offset3;
gint offset4, offset5, offset6, offset7;
gint offset8, i;
guchar *p, buf[8];
offset0 = stride - (stride * 6);
offset1 = (stride * 2) - (stride * 6);
offset2 = (stride * 3) - (stride * 6);
offset3 = (stride * 4) - (stride * 6);
offset4 = (stride * 5) - (stride * 6);
offset5 = 0;
offset6 = (stride * 7) - (stride * 6);
offset7 = (stride * 8) - (stride * 6);
offset8 = (stride * 9) - (stride * 6);
p = blocks + (stride * 6);
for (i = 0; i < 8; i++) {
gint v, low, high;
v = blocks[i] - p[offset0];
if (v <= 0)
v = p[offset0] - blocks[i];
if (v < 10)
low = blocks[i];
else
low = p[offset0];
v = p[offset7] - p[offset8];
if (v <= 0)
v = p[offset8] - p[offset7];
if (v < 10)
high = p[offset8];
else
high = p[offset7];
v = p[offset0] + (low * 3) + p[offset1] + p[offset2] + p[offset3] + 4;
buf[0] = (((p[offset0] + v) << 1) - p[offset3] + p[offset4]) >> 4;
v += p[offset4] - low;
buf[1] = (((p[offset1] + v) << 1) - p[offset4] + p[0]) >> 4;
v += p[0] - low;
buf[2] = (((p[offset2] + v) << 1) - p[0] + p[offset6]) >> 4;
v += p[offset6] - low;
buf[3] = (((p[offset3] + v) << 1) - p[offset0] - p[offset6] + p[offset7] + low) >> 4;
v += p[offset7] - p[offset0];
buf[4] = (((p[offset4] + v) << 1) - p[offset7] - p[offset1] + p[offset0] + high) >> 4;
v += high - p[offset1];
buf[5] = (((p[0] + v) << 1) - p[offset2] + p[offset1]) >> 4;
v += high - p[offset2];
buf[6] = (((p[offset6] + v) << 1) - p[offset3] + p[offset2]) >> 4;
v += high;
buf[7] = (((p[offset7] + v) << 1) - p[offset4] - p[offset3]) >> 4;
p[offset0] = buf[0];
p[offset1] = buf[1];
p[offset2] = buf[2];
p[offset3] = buf[3];
p[offset4] = buf[4];
p[offset5] = buf[5];
p[offset6] = buf[6];
p[offset7] = buf[7];
p++;
}
}
static void deblock_v_do_boundaries(guchar *blocks, guint stride)
{
guchar *p;
gint offset0, offset1, offset2, offset3;
gint offset4, offset5, offset6, offset7;
gint i;
p = blocks + (stride * 3);
offset0 = stride - (stride * 3);
offset1 = (stride * 2) - (stride * 3);
offset2 = 0;
offset3 = (stride * 4) - (stride * 3);
offset4 = (stride * 5) - (stride * 3);
offset5 = (stride * 6) - (stride * 3);
offset6 = (stride * 7) - (stride * 3);
offset7 = (stride * 8) - (stride * 3);
for (i = 0; i < 8; i++) {
gint v1, v2, v3, v;
v1 = ((p[offset4] - p[offset3]) * 5) + ((p[offset2] - p[offset5]) * 2);
if (abs(v1) < 80) {
v2 = ((p[offset2] - p[offset1]) * 5) + ((p[offset0] - p[offset3]) * 2);
v3 = ((p[offset6] - p[offset5]) * 5) + ((p[offset4] - p[offset7]) * 2);
v = abs(v1) - MIN(abs(v2), abs(v3));
if (v < 0)
v = 0;
v2 = (p[offset3] - p[offset4]) / 2;
v3 = (((v * 5) + 32) >> 6) * (((v1 < 0) * 2) - 1);
if (v2 > 0)
v = MIN(v2, ((v3 < 0) - 1) & v3);
else
v = MAX(v2, ((v3 > 0) - 1) & v3);
} else {
v = 0;
}
p[offset3] -= v;
p[offset4] += v;
p++;
}
}
amsn-0.98.9/utils/webcamsn/src/Webcamsn.dsp 0000644 0001750 0001750 00000007716 11244666345 020414 0 ustar billiob billiob # Microsoft Developer Studio Project File - Name="Webcamsn" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=Webcamsn - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "Webcamsn.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "Webcamsn.mak" CFG="Webcamsn - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "Webcamsn - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "Webcamsn - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "Webcamsn - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WEBCAMSN_EXPORTS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WEBCAMSN_EXPORTS" /D "USE_TCL_STUBS" /D "USE_TK_STUBS" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x40c /d "NDEBUG"
# ADD RSC /l 0x40c /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
# ADD LINK32 tclstub85.lib tkstub85.lib /nologo /dll /machine:I386
!ELSEIF "$(CFG)" == "Webcamsn - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Webcamsn___Win32_Debug"
# PROP BASE Intermediate_Dir "Webcamsn___Win32_Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WEBCAMSN_EXPORTS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "USE_TCL_STUBS" /D "USE_TK_STUBS" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WEBCAMSN_EXPORTS" /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x40c /d "_DEBUG"
# ADD RSC /l 0x40c /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 /nologo /dll /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "Webcamsn - Win32 Release"
# Name "Webcamsn - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\kidhash.c
# End Source File
# Begin Source File
SOURCE=.\webcamsn.c
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\kidhash.h
# End Source File
# Begin Source File
SOURCE=.\webcamsn.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project
amsn-0.98.9/utils/webcamsn/src/mimic.h 0000644 0001750 0001750 00000004405 10225230720 017362 0 ustar billiob billiob /* Copyright (C) 2005 Ole André Vadla Ravnås
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef MIMIC_H
#define MIMIC_H
//#include
#include "glib_replacement.h"
/**
* @defgroup libmimic libmimic public API
* @brief The public API of the libmimic library
*
* libmimic provides the API required for encoding and decoding
* MIMIC v2.x-encoded content.
*
* @{
*/
#ifdef __cplusplus
#define EXTERN extern "C"
#else
#define EXTERN
#endif
/**
* The mimic encoding/decoding context returned by #mimic_open
* and used for all further API calls until #mimic_close.
*/
typedef struct _MimCtx MimCtx;
typedef enum {
MIMIC_RES_LOW, /**< 160x120 resolution */
MIMIC_RES_HIGH /**< 320x240 resolution */
} MimicResEnum;
EXTERN MimCtx *mimic_open();
EXTERN void mimic_close(MimCtx *ctx);
EXTERN gboolean mimic_encoder_init(MimCtx *ctx, const MimicResEnum resolution);
EXTERN gboolean mimic_decoder_init(MimCtx *ctx, const guchar *frame_buffer);
EXTERN gboolean mimic_get_property(MimCtx *ctx, const gchar *name, gpointer data);
EXTERN gboolean mimic_set_property(MimCtx *ctx, const gchar *name, gpointer data);
EXTERN gboolean mimic_encode_frame(MimCtx *ctx,
const guchar *input_buffer,
guchar *output_buffer,
gint *output_length,
gboolean make_keyframe);
EXTERN gboolean mimic_decode_frame(MimCtx *ctx,
const guchar *input_buffer,
guchar *output_buffer);
/** @} */
#endif // MIMIC_H
amsn-0.98.9/utils/webcamsn/src/glib_replacement.h 0000644 0001750 0001750 00000004567 10733262326 021604 0 ustar billiob billiob /* No need for this file if glib.h was already included from somewhere else */
#ifndef __G_TYPES_H__
#ifndef GLIB_REPLACEMENT_H
#define GLIB_REPLACEMENT_H
#include
typedef char gchar;
typedef short gshort;
typedef long glong;
typedef int gint;
typedef gint gboolean;
typedef unsigned char guchar;
typedef unsigned short gushort;
typedef unsigned long gulong;
typedef unsigned int guint;
typedef float gfloat;
typedef double gdouble;
typedef void* gpointer;
typedef const void *gconstpointer;
typedef signed char gint8;
typedef unsigned char guint8;
typedef signed short gint16;
typedef unsigned short guint16;
typedef signed int gint32;
typedef unsigned int guint32;
#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif
#undef MAX
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#undef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#undef GUINT16_FROM_LE
#undef GUINT32_FROM_LE
#undef GUINT16_TO_LE
#undef GUINT32_TO_LE
#ifdef __BIG_ENDIAN__
#define POW_2_8 256
#define POW_2_16 65536
#define POW_2_24 16777216
#define IDX(val, i) ((unsigned int) ((unsigned char *) &val)[i])
#define GUINT16_FROM_LE(val) ( (unsigned short) ( IDX(val, 0) + IDX(val, 1) * 256 ))
#define GUINT32_FROM_LE(val) ( (int) (IDX(val, 0) + IDX(val, 1) * 256 + \
IDX(val, 2) * 65536 + IDX(val, 3) * 16777216))
#define GUINT16_TO_LE(val) ( (unsigned short) (\
(((unsigned short)val % 256) & 0xff) << 8 | \
((((unsigned short)val / POW_2_8) % 256) & 0xff) ))
#define GUINT32_TO_LE(val) ( (int) (\
((((unsigned int) val ) % 256) & 0xff) << 24 | \
((((unsigned int) val / POW_2_8 ) % 256) & 0xff) << 16| \
((((unsigned int) val / POW_2_16) % 256) & 0xff) << 8 | \
((((unsigned int) val / POW_2_24) % 256) & 0xff) ))
#else
#define GUINT16_TO_LE(val) ( (unsigned short) (val))
#define GUINT32_TO_LE(val) ( (unsigned int) (val))
#define GUINT16_FROM_LE(val) ( (unsigned short) (val))
#define GUINT32_FROM_LE(val) ( (unsigned int) (val))
#endif
#undef g_new
#undef g_new0
#undef g_free
#undef g_realloc
#define g_new(struct_type, n_structs) \
((struct_type *) malloc (sizeof (struct_type) * n_structs))
#define g_new0(struct_type, n_structs) \
((struct_type *) memset(malloc (sizeof (struct_type) * n_structs), 0, sizeof (struct_type) * n_structs))
#define g_free free
#endif
#endif
amsn-0.98.9/utils/webcamsn/src/vlc_encode.c 0000644 0001750 0001750 00000005043 10225230720 020357 0 ustar billiob billiob /* Copyright (C) 2005 Ole André Vadla Ravnås
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include
#include "mimic-private.h"
extern guchar _col_zag[64];
extern VlcSymbol _vlc_alphabet[16][128];
/*
* _vlc_encode_block
*
* Serialize an 8x8 block using variable length coding.
*/
void _vlc_encode_block(MimCtx *ctx, const gint *block, gint num_coeffs)
{
gint i, num_zeroes;
/* The DC value is written out as is. */
_write_bits(ctx, block[0], 8);
/* Number of zeroes prefixing the next non-zero value. */
num_zeroes = 0;
for (i = 1; i < num_coeffs && num_zeroes <= 14; i++) {
/* Fetch AC coefficients from block in zig-zag order. */
gint value = block[_col_zag[i]];
if (value != 0) {
VlcSymbol sym;
/* Clip input values to [-128, +128]. */
if (value < -128)
value = -128;
else if (value > 128)
value = 128;
/* Look up symbol for the current non-zero value. */
sym = _vlc_alphabet[num_zeroes][abs(value) - 1];
/* No symbol? very rare... */
if (sym.length1 <= 0)
break;
/* The symbols for negative values are the same as for positives, minus one. */
if (value < 0) {
if (sym.length2 > 0)
sym.part2 -= 1;
else
sym.part1 -= 1;
}
/* Write out the full symbol. */
_write_bits(ctx, sym.part1, sym.length1);
if (sym.length2 > 0)
_write_bits(ctx, sym.part2, sym.length2);
/* Start counting zeroes again. */
num_zeroes = 0;
} else {
num_zeroes++;
}
}
/* Write out EOB if necessary. */
if (num_zeroes > 0)
_write_bits(ctx, 0xA, 4);
}
amsn-0.98.9/utils/webcamsn/src/webcamsn.c 0000644 0001750 0001750 00000044773 11234130207 020072 0 ustar billiob billiob /*
File : Webcamsn.c
Description : Contains all functions for the Webcamsn extension
Author : Youness El Alaoui (KaKaRoTo - kakaroto@users.sourceforge.net)
*/
// Include the header file
#include "webcamsn.h"
#include "kidhash.h"
static int encoder_counter = 0;
static int decoder_counter = 0;
static Tcl_HashTable *Codecs = NULL;
BYTE * RGBA2RGB(Tk_PhotoImageBlock data) {
int i;
int size = data.height * data.width * data.pixelSize;
BYTE * FrameData = (BYTE *) malloc(data.height * data.width * 3);
BYTE * pixelPtr = FrameData;
for (i = 0; i < size; i+= data.pixelSize) {
*(pixelPtr++) = *(data.pixelPtr + i + data.offset[0]);
*(pixelPtr++) = *(data.pixelPtr + i + data.offset[1]);
*(pixelPtr++) = *(data.pixelPtr + i + data.offset[2]);
}
return FrameData;
}
int Webcamsn_NewDecoder _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]))
{
CodecInfo *new_decoder;
char name[30];
char *req_name = NULL;
Tcl_HashEntry *hPtr = NULL;
int newHash;
// We verify the arguments
if( objc > 2) {
Tcl_AppendResult (interp, "Wrong number of args.\nShould be \"::Webcamsn::NewDecoder ?name?\"" , (char *) NULL);
return TCL_ERROR;
}
new_decoder = (struct CodecInfo *) malloc(sizeof(struct CodecInfo));
if ( objc == 2) {
// Set the requested name and see if it exists...
req_name = Tcl_GetStringFromObj(objv[1], NULL);
if (Tcl_FindHashEntry(Codecs, req_name) == NULL) {
strcpy(name, req_name );
}else {
sprintf(name, "decoder%d", ++decoder_counter);
}
} else {
sprintf(name, "decoder%d", ++decoder_counter);
}
new_decoder->codec = mimic_open();
strcpy(new_decoder->name, name);
new_decoder->type = DECODER_UNINITIALIZED;
new_decoder->frames = 0;
hPtr = Tcl_CreateHashEntry(Codecs, name, &newHash);
Tcl_SetHashValue(hPtr, (ClientData) new_decoder);
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, name, NULL);
return TCL_OK;
}
int Webcamsn_NewEncoder _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]))
{
CodecInfo *new_encoder;
MimCtx * encoder = NULL;
char name[15];
char * req_name = NULL;
char * strResolution = NULL;
MimicResEnum resolution;
Tcl_HashEntry *hPtr = NULL;
int newHash;
// We verify the arguments
if( objc < 2 || objc > 3) {
Tcl_AppendResult (interp, "Wrong number of args.\nShould be \"::Webcamsn::NewEncoder resolution ?name?\" " ,
"where the resolution is either \"LOW\" or \"HIGH\"", (char *) NULL);
return TCL_ERROR;
}
strResolution = Tcl_GetStringFromObj(objv[1], NULL);
if (!strcmp(strResolution, "LOW")) {
resolution = MIMIC_RES_LOW;
} else if (!strcmp(strResolution, "HIGH")) {
resolution = MIMIC_RES_HIGH;
} else {
Tcl_ResetResult(interp);
Tcl_AppendResult (interp, "Invalid resolution. The resolution is either \"LOW\" or \"HIGH\"", (char *) NULL);
return TCL_ERROR;
}
new_encoder = (struct CodecInfo *) malloc(sizeof(struct CodecInfo));
if ( objc == 3) {
// Set the requested name and see if it exists...
req_name = Tcl_GetStringFromObj(objv[2], NULL);
if (Tcl_FindHashEntry(Codecs, req_name) == NULL) {
strcpy(name, req_name);
}else {
sprintf(name, "encoder%d", ++encoder_counter);
}
} else {
sprintf(name, "encoder%d", ++encoder_counter);
}
new_encoder->codec = mimic_open();
strcpy(new_encoder->name, name);
new_encoder->type = ENCODER;
new_encoder->frames = 0;
mimic_encoder_init(new_encoder->codec, resolution);
hPtr = Tcl_CreateHashEntry(Codecs, name, &newHash);
Tcl_SetHashValue(hPtr, (ClientData) new_encoder);
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, name, NULL);
return TCL_OK;
}
int Webcamsn_Decode _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]))
{
char * name = NULL;
CodecInfo * decoder;
char * image_name = NULL;
Tk_PhotoHandle Photo;
Tk_PhotoImageBlock block;
MimicHeader *header;
BYTE * buffer = NULL;
BYTE * FrameData = NULL;
BYTE * output = NULL;
Tcl_HashEntry *hPtr = NULL;
int length = 0;
int width = 0;
int height = 0;
// We verify the arguments
if( objc != 4) {
Tcl_AppendResult (interp, "Wrong number of args.\nShould be \"::Webcamsn::Decode decoder to_image data\"" , (char *) NULL);
return TCL_ERROR;
}
name = Tcl_GetStringFromObj(objv[1], NULL);
hPtr = Tcl_FindHashEntry(Codecs, name);
if (hPtr != NULL) {
decoder = (CodecInfo *) Tcl_GetHashValue(hPtr);
}
if (!decoder) {
Tcl_AppendResult (interp, "Invalid decoder : " , name, (char *) NULL);
return TCL_ERROR;
}
if (decoder->type == ENCODER) {
Tcl_AppendResult (interp, name, " is an encoder, not a decoder" , (char *) NULL);
return TCL_ERROR;
}
image_name = Tcl_GetStringFromObj(objv[2], NULL);
if ( (Photo = Tk_FindPhoto(interp, image_name)) == NULL) {
Tcl_AppendResult(interp, "The image you specified is not a valid photo image", NULL);
return TCL_ERROR;
}
buffer = Tcl_GetByteArrayFromObj(objv[3], &length);
header = (MimicHeader *) buffer;
header->header_size = GUINT16_FROM_LE(header->header_size);
header->fourcc = GUINT32_FROM_LE(header->fourcc);
header->payload_size = GUINT32_FROM_LE(header->payload_size);
if (!(header->header_size == 24 && header->fourcc == 0x30324C4D
&& length >= (header->header_size + header->payload_size)))
{
Tcl_AppendResult(interp, "Wrong format or not enough data", NULL);
return TCL_ERROR;
}
FrameData = buffer + header->header_size;
if (decoder->type == DECODER_UNINITIALIZED) {
if (!mimic_decoder_init(decoder->codec, FrameData)) {
Tcl_AppendResult(interp, "Unable to initialize the decoder, the data you supplied is not valid", (char *) NULL);
return TCL_ERROR;
} else {
decoder->type = DECODER_INITIALIZED;
}
}
mimic_get_property(decoder->codec, "buffer_size", &length);
mimic_get_property(decoder->codec, "width", &width);
mimic_get_property(decoder->codec, "height", &height);
output = (BYTE *) malloc(length);
if (mimic_decode_frame(decoder->codec, FrameData, output)) {
decoder->frames++;
Tk_PhotoSetSize(
#if TK_MINOR_VERSION >= 5
interp,
#endif
Photo, width, height);
block.pixelPtr = output; // pixel ptr
block.width = width;
block.height = height;
block.pitch = width*3;
block.pixelSize = 3;
block.offset[0] = 0;
block.offset[1] = 1;
block.offset[2] = 2;
block.offset[3] = -1;
Tk_PhotoPutBlock(
#if TK_MINOR_VERSION >= 5
interp,
#endif
Photo, &block, 0, 0, width, height
#if TK_MINOR_VERSION > 3
,TK_PHOTO_COMPOSITE_OVERLAY
#endif
);
free(output);
return TCL_OK;
} else {
Tcl_AppendResult(interp, "Unable to decode current frame, the data you supplied is not valid", (char *) NULL);
return TCL_ERROR;
}
}
int Webcamsn_Encode _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]))
{
char * name = NULL;
CodecInfo * encoder;
char * image_name = NULL;
Tk_PhotoHandle Photo;
Tk_PhotoImageBlock photoData;
BYTE * buffer = NULL;
BYTE * FrameData = NULL;
BYTE * output = NULL;
Tcl_HashEntry *hPtr = NULL;
int length = 0;
int width = 0;
int height = 0;
// We verify the arguments
if( objc != 3) {
Tcl_AppendResult (interp, "Wrong number of args.\nShould be \"::Webcamsn::Encode encoder from_image\"" , (char *) NULL);
return TCL_ERROR;
}
name = Tcl_GetStringFromObj(objv[1], NULL);
hPtr = Tcl_FindHashEntry(Codecs, name);
if (hPtr != NULL) {
encoder = (CodecInfo *) Tcl_GetHashValue(hPtr);
}
if (!encoder) {
Tcl_AppendResult (interp, "Invalid encoder : " , name, (char *) NULL);
return TCL_ERROR;
}
if (encoder->type != ENCODER) {
Tcl_AppendResult (interp, name, " is a decoder, not an encoder" , (char *) NULL);
return TCL_ERROR;
}
image_name = Tcl_GetStringFromObj(objv[2], NULL);
if ( (Photo = Tk_FindPhoto(interp, image_name)) == NULL) {
Tcl_AppendResult(interp, "The image you specified is not a valid photo image", NULL);
return TCL_ERROR;
}
Tk_PhotoGetImage(Photo, &photoData);
mimic_get_property(encoder->codec, "buffer_size", &length);
mimic_get_property(encoder->codec, "width", &width);
mimic_get_property(encoder->codec, "height", &height);
output = (BYTE *) malloc(length*5);
FrameData = RGBA2RGB(photoData);
if (mimic_encode_frame(encoder->codec, FrameData, output,
&length, ((encoder->frames % MAX_INTERFRAMES) == 0? TRUE : FALSE) )) {
encoder->frames++;
Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(output, length));
free(output);
free(FrameData);
return TCL_OK;
} else {
free(output);
free(FrameData);
Tcl_AppendResult(interp, "Unable to encode the image", (char *) NULL);
return TCL_ERROR;
}
}
int Webcamsn_SetQuality _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]))
{
int quality = 0;
char * name = NULL;
CodecInfo * encoder;
Tcl_HashEntry *hPtr = NULL;
// We verify the arguments
if( objc != 3) {
Tcl_AppendResult (interp, "Wrong number of args.\nShould be \"::Webcamsn::SetQuality encoder quality\"" , (char *) NULL);
return TCL_ERROR;
}
name = Tcl_GetStringFromObj(objv[1], NULL);
hPtr = Tcl_FindHashEntry(Codecs, name);
if (hPtr != NULL) {
encoder = (CodecInfo *) Tcl_GetHashValue(hPtr);
}
if (!encoder) {
Tcl_AppendResult (interp, "Invalid encoder : " , name, (char *) NULL);
return TCL_ERROR;
}
if (encoder->type != ENCODER) {
Tcl_AppendResult (interp, name, " is a decoder, not an encoder" , (char *) NULL);
return TCL_ERROR;
}
if( Tcl_GetIntFromObj(interp, objv[2], &quality) == TCL_ERROR)
return TCL_ERROR;
if (mimic_set_property(encoder->codec, "quality", &quality)) {
return TCL_OK;
} else {
Tcl_AppendResult(interp, "unable to change quality of encoder : ", name, (char *) NULL);
return TCL_ERROR;
}
}
int Webcamsn_GetWidth _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]))
{
int width = 0;
char * name = NULL;
CodecInfo * codec;
Tcl_HashEntry *hPtr = NULL;
// We verify the arguments
if( objc != 2) {
Tcl_AppendResult (interp, "Wrong number of args.\nShould be \"::Webcamsn::GetWidth codec\"" , (char *) NULL);
return TCL_ERROR;
}
name = Tcl_GetStringFromObj(objv[1], NULL);
hPtr = Tcl_FindHashEntry(Codecs, name);
if (hPtr != NULL) {
codec = (CodecInfo *) Tcl_GetHashValue(hPtr);
}
if (!codec) {
Tcl_AppendResult (interp, "Invalid encoder/decoder : " , name, (char *) NULL);
return TCL_ERROR;
}
if(codec->type == DECODER_UNINITIALIZED) {
Tcl_AppendResult (interp, "Before requesting this data, the decoder must have been initialized ",
"with at least one chunk of data" , (char *) NULL);
return TCL_ERROR;
}
if (mimic_get_property(codec->codec, "width", &width)) {
Tcl_SetObjResult(interp, Tcl_NewIntObj(width));
return TCL_OK;
} else {
Tcl_AppendResult(interp, "unable to get width for codec : ", name, (char *) NULL);
return TCL_ERROR;
}
}
int Webcamsn_GetHeight _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]))
{
int height = 0;
char * name = NULL;
CodecInfo * codec;
Tcl_HashEntry *hPtr = NULL;
// We verify the arguments
if( objc != 2) {
Tcl_AppendResult (interp, "Wrong number of args.\nShould be \"::Webcamsn::GetHeight codec\"" , (char *) NULL);
return TCL_ERROR;
}
name = Tcl_GetStringFromObj(objv[1], NULL);
hPtr = Tcl_FindHashEntry(Codecs, name);
if (hPtr != NULL) {
codec = (CodecInfo *) Tcl_GetHashValue(hPtr);
}
if (!codec) {
Tcl_AppendResult (interp, "Invalid encoder/decoder : " , name, (char *) NULL);
return TCL_ERROR;
}
if(codec->type == DECODER_UNINITIALIZED) {
Tcl_AppendResult (interp, "Before requesting this data, the decoder must have been initialized ",
"with at least one chunk of data" , (char *) NULL);
return TCL_ERROR;
}
if (mimic_get_property(codec->codec, "height", &height)) {
Tcl_SetObjResult(interp, Tcl_NewIntObj(height));
return TCL_OK;
} else {
Tcl_AppendResult(interp, "unable to get height for codec : ", name, (char *) NULL);
return TCL_ERROR;
}
return TCL_OK;
}
int Webcamsn_GetQuality _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]))
{
int quality = 0;
char * name = NULL;
CodecInfo * codec;
Tcl_HashEntry *hPtr = NULL;
// We verify the arguments
if( objc != 2) {
Tcl_AppendResult (interp, "Wrong number of args.\nShould be \"::Webcamsn::GetQuality codec\"" , (char *) NULL);
return TCL_ERROR;
}
name = Tcl_GetStringFromObj(objv[1], NULL);
hPtr = Tcl_FindHashEntry(Codecs, name);
if (hPtr != NULL) {
codec = (CodecInfo *) Tcl_GetHashValue(hPtr);
}
if (!codec) {
Tcl_AppendResult (interp, "Invalid encoder/decoder : " , name, (char *) NULL);
return TCL_ERROR;
}
if(codec->type == DECODER_UNINITIALIZED) {
Tcl_AppendResult (interp, "Before requesting this data, the decoder must have been initialized ",
"with at least one chunk of data" , (char *) NULL);
return TCL_ERROR;
}
if (mimic_get_property(codec->codec, "quality", &quality)) {
Tcl_SetObjResult(interp, Tcl_NewIntObj(quality));
return TCL_OK;
} else {
Tcl_AppendResult(interp, "Unable to get the quality of the codec : ", name, (char *) NULL);
return TCL_ERROR;
}
return TCL_OK;
}
int Webcamsn_Close _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]))
{
char * name = NULL;
CodecInfo * codec;
Tcl_HashEntry *hPtr = NULL;
// We verify the arguments
if( objc != 2) {
Tcl_AppendResult (interp, "Wrong number of args.\nShould be \"::Webcamsn::Close codec\"" , (char *) NULL);
return TCL_ERROR;
}
name = Tcl_GetStringFromObj(objv[1], NULL);
hPtr = Tcl_FindHashEntry(Codecs, name);
if (hPtr != NULL) {
codec = (CodecInfo *) Tcl_GetHashValue(hPtr);
}
if (!codec) {
Tcl_AppendResult (interp, "Invalid encoder/decoder : " , name, (char *) NULL);
return TCL_ERROR;
}
mimic_close(codec->codec);
Tcl_DeleteHashEntry(hPtr);
free(codec);
return TCL_OK;
}
int Webcamsn_Count _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]))
{
Tcl_HashSearch searchPtr;
Tcl_HashEntry *hPtr = NULL;
int count = 0;
for (hPtr = Tcl_FirstHashEntry(Codecs, &searchPtr); hPtr;
hPtr = Tcl_NextHashEntry(&searchPtr)) {
count++;
}
Tcl_SetObjResult(interp, Tcl_NewIntObj(count));
return TCL_OK;
}
int Webcamsn_Frames _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]))
{
char * name = NULL;
CodecInfo * codec;
Tcl_HashEntry *hPtr = NULL;
// We verify the arguments
if( objc != 2) {
Tcl_AppendResult (interp, "Wrong number of args.\nShould be \"::Webcamsn::NbFrames codec\"" , (char *) NULL);
return TCL_ERROR;
}
name = Tcl_GetStringFromObj(objv[1], NULL);
hPtr = Tcl_FindHashEntry(Codecs, name);
if (hPtr != NULL) {
codec = (CodecInfo *) Tcl_GetHashValue(hPtr);
}
if (!codec) {
Tcl_AppendResult (interp, "Invalid encoder/decoder : " , name, (char *) NULL);
return TCL_ERROR;
}
Tcl_SetObjResult(interp, Tcl_NewIntObj((int) codec->frames));
return TCL_OK;
}
int Webcamsn_KidHash _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[])) {
char * sid = NULL;
char * key = NULL;
int kid;
char a[30];
int a_size = 30;
// We verify the arguments
if( objc != 3) {
Tcl_AppendResult (interp, "Wrong number of args.\nShould be "
"\"::Webcamsn::CreateHashFromKid kid sid\"" , (char *) NULL);
return TCL_ERROR;
}
Tcl_GetIntFromObj(interp, objv[1], &kid);
sid = Tcl_GetStringFromObj(objv[2], NULL);
key = (char *) malloc (strlen(sid) + 10);
sprintf(key, "sid=%s", sid);
if (MakeKidHash(a, &a_size, kid, key)) {
Tcl_ResetResult(interp);
Tcl_AppendResult (interp, a, (char *) NULL);
free(key);
return TCL_OK;
} else {
Tcl_ResetResult(interp);
free(key);
return TCL_OK;
}
}
/*
Function : Webcamsn_Init
Description : The Init function that will be called when the extension is loaded to your tk shell
Arguments : Tcl_Interp *interp : This is the interpreter from which the load was made and to
which we'll add the new command
Return value : TCL_OK in case everything is ok, or TCL_ERROR in case there is an error (Tk version < 8.3)
Comments : hummmm... not much, it's simple :)
*/
int Webcamsn_Init (Tcl_Interp *interp ) {
//Check Tcl version is 8.3 or higher
if (Tcl_InitStubs(interp, TCL_VERSION, 1) == NULL) {
return TCL_ERROR;
}
//Check TK version is 8.3 or higher
if (Tk_InitStubs(interp, TK_VERSION, 1) == NULL) {
return TCL_ERROR;
}
Codecs = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
Tcl_InitHashTable(Codecs, TCL_STRING_KEYS);
// Create the wrapping commands in the Webcamsn namespace linked to custom functions with a NULL clientdata and
// no deleteproc inside the current interpreter
Tcl_CreateObjCommand(interp, "::Webcamsn::NewEncoder", Webcamsn_NewEncoder,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "::Webcamsn::NewDecoder", Webcamsn_NewDecoder,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "::Webcamsn::Decode", Webcamsn_Decode,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "::Webcamsn::Encode", Webcamsn_Encode,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "::Webcamsn::SetQuality", Webcamsn_SetQuality,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "::Webcamsn::GetWidth", Webcamsn_GetWidth,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "::Webcamsn::GetHeight", Webcamsn_GetHeight,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "::Webcamsn::GetQuality", Webcamsn_GetQuality,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "::Webcamsn::Close", Webcamsn_Close,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "::Webcamsn::NumberOfOpenCodecs", Webcamsn_Count,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "::Webcamsn::NbFrames", Webcamsn_Frames,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_CreateObjCommand(interp, "::Webcamsn::CreateHashFromKid", Webcamsn_KidHash,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
// end of Initialisation
return TCL_OK;
}
int Webcamsn_SafeInit (Tcl_Interp *interp) {
return Webcamsn_Init(interp);
}
amsn-0.98.9/utils/webcamsn/src/mimic.c 0000644 0001750 0001750 00000021250 10225230720 017352 0 ustar billiob billiob /* Copyright (C) 2005 Ole André Vadla Ravnås
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include
#include "mimic-private.h"
/**
* Creates a new instance and returns a pointer to the new context
* that can be used for either encoding or decoding by calling
* #mimic_encoder_init or #mimic_decoder_init.
*
* #mimic_close is called to free any resources associated with
* the context once done.
*
* @returns a new mimic context
*/
MimCtx *mimic_open()
{
MimCtx *ctx;
ctx = g_new0(MimCtx, 1);
ctx->encoder_initialized = FALSE;
ctx->decoder_initialized = FALSE;
return ctx;
}
/**
* Frees any resources associated with the given context.
*
* @param ctx the mimic context to free
*/
void mimic_close(MimCtx *ctx)
{
if (ctx->encoder_initialized || ctx->decoder_initialized) {
gint i;
g_free(ctx->cur_frame_buf);
for (i = 0; i < 16; i++)
g_free(ctx->buf_ptrs[i]);
}
g_free(ctx);
}
/*
* mimic_init
*
* Internal helper-function used to initialize
* a given context.
*/
static void mimic_init(MimCtx *ctx, gint width, gint height)
{
gint bufsize, i;
/*
* Dimensions-related.
*/
ctx->frame_width = width;
ctx->frame_height = height;
ctx->y_stride = ctx->frame_width;
ctx->y_row_count = ctx->frame_height;
ctx->y_size = ctx->y_stride * ctx->y_row_count;
ctx->crcb_stride = ctx->y_stride / 2;
ctx->crcb_row_count = ctx->y_row_count / 2;
ctx->crcb_size = ctx->crcb_stride * ctx->crcb_row_count;
ctx->num_vblocks_y = ctx->frame_height / 8;
ctx->num_hblocks_y = ctx->frame_width / 8;
ctx->num_vblocks_cbcr = ctx->frame_height / 16;
ctx->num_hblocks_cbcr = ctx->frame_width / 16;
if (ctx->frame_height % 16 != 0)
ctx->num_vblocks_cbcr++;
/*
* Initialize state.
*/
ctx->frame_num = 0;
ctx->ptr_index = 15;
ctx->num_coeffs = 28;
/*
* Allocate memory for buffers.
*/
ctx->cur_frame_buf = g_new(guchar, (320 * 240 * 3) / 2);
bufsize = ctx->y_size + (ctx->crcb_size * 2);
for (i = 0; i < 16; i++)
ctx->buf_ptrs[i] = g_new(guchar, bufsize);
/*
* Initialize vlc lookup used by decoder.
*/
_initialize_vlcdec_lookup(ctx->vlcdec_lookup);
}
/**
* Initialize the mimic encoder and prepare for encoding by
* initializing internal state and allocating resources as
* needed.
*
* After initializing use #mimic_get_property to determine
* the size of the output buffer needed for calls to
* #mimic_encode_frame. Use #mimic_set_property to set
* encoding quality.
*
* Note that once a given context has been initialized
* for either encoding or decoding it is not possible
* to initialize it again.
*
* @param ctx the mimic context to initialize
* @param resolution a #MimicResEnum used to specify the resolution
* @returns #TRUE on success
*/
gboolean mimic_encoder_init(MimCtx *ctx, const MimicResEnum resolution)
{
gint width, height;
/* Check if we've been initialized before. */
if (ctx->encoder_initialized || ctx->decoder_initialized)
return FALSE;
/* Check resolution. */
if (resolution == MIMIC_RES_LOW) {
width = 160;
height = 120;
} else if (resolution == MIMIC_RES_HIGH) {
width = 320;
height = 240;
} else {
return FALSE;
}
/* Initialize! */
mimic_init(ctx, width, height);
/* Set a default quality setting. */
ctx->quality = MIMIC_ENCODER_DEFAULT_QUALITY;
ctx->encoder_initialized = TRUE;
return TRUE;
}
/**
* Initialize the mimic decoder. The frame passed in frame_buffer
* is used to determine the resolution so that the internal state
* can be prepared and resources allocated accordingly. Note that
* the frame passed has to be a keyframe.
*
* After initializing use #mimic_get_property to determine required
* buffer-size, resolution, quality, etc.
*
* Note that once a given context has been initialized
* for either encoding or decoding it is not possible
* to initialize it again.
*
* @param ctx the mimic context to initialize
* @param frame_buffer buffer containing the first frame to decode
* @returns #TRUE on success
*/
gboolean mimic_decoder_init(MimCtx *ctx, const guchar *frame_buffer)
{
gint width, height;
gboolean is_keyframe;
/* Check if we've been initialized before and that
* frame_buffer is not NULL. */
if (ctx->encoder_initialized || ctx->decoder_initialized ||
frame_buffer == NULL)
{
return FALSE;
}
/* Check resolution. */
width = GUINT16_FROM_LE(*((guint16 *) (frame_buffer + 4)));
height = GUINT16_FROM_LE(*((guint16 *) (frame_buffer + 6)));
if (!(width == 160 && height == 120) && !(width == 320 && height == 240))
return FALSE;
/* Check that we're initialized with a keyframe. */
is_keyframe = (GUINT32_FROM_LE(*((guint32 *) (frame_buffer + 12))) == 0);
if (!is_keyframe)
return FALSE;
/* Get quality setting (in case we get queried for it before decoding). */
ctx->quality = GUINT16_FROM_LE(*((guint16 *) (frame_buffer + 2)));
/* Initialize! */
mimic_init(ctx, width, height);
ctx->decoder_initialized = TRUE;
return TRUE;
}
/**
* Get a property from a given mimic context. The context
* has to be initialized.
*
* Currently the following properties are defined:
* - "buffer_size"
* - Required output buffer size
* - "width"
* - Frame width
* - "height"
* - Frame height
* - "quality"
* - Encoder: Encoding quality used
* - Decoder: Decoding quality of the last known frame
*
* @param ctx the mimic context to retrieve the property from
* @param name of the property to retrieve the current value of
* @param data pointer to the data that will receive the retrieved value
* @returns #TRUE on success
*/
gboolean mimic_get_property(MimCtx *ctx, const gchar *name, gpointer data)
{
/* Either the encoder or the decoder has to be initialized. */
if (!ctx->encoder_initialized && !ctx->decoder_initialized)
return FALSE;
if (ctx->encoder_initialized) {
if (strcmp(name, "buffer_size") == 0) {
*((gint *) data) = (ctx->frame_width == 160) ? 3840 : 7680;
return TRUE;
}
} else { /* decoder_initialized */
if (strcmp(name, "buffer_size") == 0) {
*((gint *) data) = ctx->frame_width * ctx->frame_height * 3;
return TRUE;
}
}
if (strcmp(name, "width") == 0) {
*((gint *) data) = ctx->frame_width;
return TRUE;
} else if (strcmp(name, "height") == 0) {
*((gint *) data) = ctx->frame_height;
return TRUE;
} else if (strcmp(name, "quality") == 0) {
*((gint *) data) = ctx->quality;
return TRUE;
}
return FALSE;
}
/**
* Set a property in a given mimic context. The context
* has to be initialized.
*
* Currently the following properties are defined:
* - "quality"
* - Encoding quality used by encoder.
*
* @param ctx the mimic context to set a property in
* @param name of the property to set to a new value
* @param data pointer to the data that contains the new value
* @returns #TRUE on success
*/
gboolean mimic_set_property(MimCtx *ctx, const gchar *name, gpointer data)
{
/* Either the encoder or the decoder has to be initialized. */
if (!ctx->encoder_initialized && !ctx->decoder_initialized)
return FALSE;
if (ctx->encoder_initialized) {
if (strcmp(name, "quality") == 0) {
ctx->quality = *((gint *) data);
return TRUE;
}
} else { /* decoder_initialized */ }
return FALSE;
}
/*
* _clamp_value
*
* Internal helper-function used to clamp a given
* value to the range [ 0, 255 ].
*/
guchar _clamp_value(gint value)
{
if (value < 0)
return 0;
else if (value > 255)
return 255;
else
return value;
}
amsn-0.98.9/utils/webcamsn/ChangeLog 0000644 0001750 0001750 00000000000 10225230720 017061 0 ustar billiob billiob amsn-0.98.9/utils/webcamsn/INSTALL 0000644 0001750 0001750 00000022030 10225230720 016347 0 ustar billiob billiob Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
Foundation, Inc.
This file is free documentation; the Free Software Foundation gives
unlimited permission to copy, distribute and modify it.
Basic Installation
==================
These are generic installation instructions.
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 compiler output (useful mainly 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 file `configure.ac' (or `configure.in') is used to create
`configure' by a program called `autoconf'. You only need
`configure.ac' if you want to change it or regenerate `configure' using
a newer version of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system. If you're
using `csh' on an old version of System V, you might need to type
`sh ./configure' instead to prevent `csh' from trying to execute
`configure' itself.
Running `configure' takes awhile. While running, it prints some
messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package.
4. Type `make install' to install the programs and any data files and
documentation.
5. 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 get
all sorts of other programs in order to regenerate files that came
with the distribution.
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=c89 CFLAGS=-O2 LIBS=-lposix
*Note 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 architecture in their
own directory. To do this, you must use a version of `make' that
supports the `VPATH' variable, such as 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 `..'.
If you have to use a `make' that does not support the `VPATH'
variable, you have to compile the package for one architecture at a
time in the source code directory. After you have installed the
package for one architecture, use `make distclean' before reconfiguring
for another architecture.
Installation Names
==================
By default, `make install' will install the package's files in
`/usr/local/bin', `/usr/local/man', etc. You can specify an
installation prefix other than `/usr/local' by giving `configure' the
option `--prefix=PATH'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
give `configure' the option `--exec-prefix=PATH', the package will use
PATH as the prefix for installing programs and libraries.
Documentation and other data files will still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=PATH' 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.
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'.
Optional Features
=================
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Specifying the System Type
==========================
There may be some features `configure' cannot figure out
automatically, but needs to determine by the type of machine the package
will run on. Usually, assuming the package is built to be run on the
_same_ architectures, `configure' can figure that out, but if it prints
a message saying it cannot guess the machine type, give it the
`--build=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name which has the form:
CPU-COMPANY-SYSTEM
where SYSTEM can have one of these forms:
OS KERNEL-OS
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the machine type.
If you are _building_ compiler tools for cross-compiling, you should
use the `--target=TYPE' option to select the type of system they will
produce code for.
If you want to _use_ a cross compiler, that generates code for a
platform different from the build platform, you should specify the
"host" platform (i.e., that on which the generated programs will
eventually be run) with `--host=TYPE'.
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
will cause the specified gcc to be used as the C compiler (unless it is
overridden in the site shell script).
`configure' Invocation
======================
`configure' recognizes the following options to control how it
operates.
`--help'
`-h'
Print a summary of the options to `configure', and exit.
`--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'.
`--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).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.
amsn-0.98.9/utils/webcamsn/doc/ 0000755 0001750 0001750 00000000000 11757711632 016107 5 ustar billiob billiob amsn-0.98.9/utils/webcamsn/doc/Makefile.am 0000644 0001750 0001750 00000000200 10225236340 020116 0 ustar billiob billiob EXTRA_DIST = Doxyfile.in
if LIBMIMIC_DOXYGEN_DOCS_ENABLED
all-local: dox
dox: Doxyfile
-rm -rf api/
doxygen Doxyfile
endif
amsn-0.98.9/utils/webcamsn/doc/Doxyfile.in 0000644 0001750 0001750 00000020127 10225236340 020207 0 ustar billiob billiob # Doxyfile 1.4.0
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
PROJECT_NAME = libmimic
PROJECT_NUMBER = @VERSION@
OUTPUT_DIRECTORY = api
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English
USE_WINDOWS_ENCODING = NO
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF =
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = YES
STRIP_FROM_PATH =
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
DETAILS_AT_TOP = NO
INHERIT_DOCS = YES
DISTRIBUTE_GROUP_DOC = NO
TAB_SIZE = 8
ALIASES =
OPTIMIZE_OUTPUT_FOR_C = NO
OPTIMIZE_OUTPUT_JAVA = NO
SUBGROUPING = YES
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = NO
EXTRACT_PRIVATE = NO
EXTRACT_STATIC = NO
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = NO
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = YES
HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = YES
INLINE_INFO = YES
SORT_MEMBER_DOCS = NO
SORT_BRIEF_DOCS = NO
SORT_BY_SCOPE_NAME = NO
GENERATE_TODOLIST = YES
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
SHOW_DIRECTORIES = YES
FILE_VERSION_FILTER =
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = ../src
FILE_PATTERNS = *.c *.h
RECURSIVE = YES
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS =
EXAMPLE_RECURSIVE = NO
IMAGE_PATH =
INPUT_FILTER =
FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = NO
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
REFERENCED_BY_RELATION = YES
REFERENCES_RELATION = YES
VERBATIM_HEADERS = YES
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = NO
COLS_IN_ALPHA_INDEX = 5
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
HTML_ALIGN_MEMBERS = YES
GENERATE_HTMLHELP = NO
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
BINARY_TOC = NO
TOC_EXPAND = NO
DISABLE_INDEX = NO
ENUM_VALUES_PER_LINE = 4
GENERATE_TREEVIEW = NO
TREEVIEW_WIDTH = 250
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
GENERATE_LATEX = YES
LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = a4wide
EXTRA_PACKAGES =
LATEX_HEADER =
PDF_HYPERLINKS = NO
USE_PDFLATEX = NO
LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
#---------------------------------------------------------------------------
# configuration options related to the RTF output
#---------------------------------------------------------------------------
GENERATE_RTF = NO
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = NO
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_LINKS = NO
#---------------------------------------------------------------------------
# configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = NO
XML_OUTPUT = xml
XML_SCHEMA =
XML_DTD =
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# configuration options related to the Perl module output
#---------------------------------------------------------------------------
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
PERLMOD_PRETTY = YES
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
PREDEFINED =
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration::additions related to external references
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE =
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = YES
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = NO
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
UML_LOOK = NO
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
CALL_GRAPH = NO
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
DOT_IMAGE_FORMAT = png
DOT_PATH =
DOTFILE_DIRS =
MAX_DOT_GRAPH_WIDTH = 1024
MAX_DOT_GRAPH_HEIGHT = 1024
MAX_DOT_GRAPH_DEPTH = 0
DOT_TRANSPARENT = NO
DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
DOT_CLEANUP = YES
#---------------------------------------------------------------------------
# Configuration::additions related to the search engine
#---------------------------------------------------------------------------
SEARCHENGINE = NO
amsn-0.98.9/utils/webcamsn/doc/Makefile.in 0000644 0001750 0001750 00000014104 10225236340 020137 0 ustar billiob billiob # Makefile.in generated by automake 1.6.3 from Makefile.am.
# @configure_input@
# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
# Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
SHELL = @SHELL@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
sbindir = @sbindir@
libexecdir = @libexecdir@
datadir = @datadir@
sysconfdir = @sysconfdir@
sharedstatedir = @sharedstatedir@
localstatedir = @localstatedir@
libdir = @libdir@
infodir = @infodir@
mandir = @mandir@
includedir = @includedir@
oldincludedir = /usr/include
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
top_builddir = ..
ACLOCAL = @ACLOCAL@
AUTOCONF = @AUTOCONF@
AUTOMAKE = @AUTOMAKE@
AUTOHEADER = @AUTOHEADER@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_HEADER = $(INSTALL_DATA)
transform = @program_transform_name@
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
host_alias = @host_alias@
host_triplet = @host@
EXEEXT = @EXEEXT@
OBJEXT = @OBJEXT@
PATH_SEPARATOR = @PATH_SEPARATOR@
AMTAR = @AMTAR@
AR = @AR@
AS = @AS@
AWK = @AWK@
CC = @CC@
CXX = @CXX@
CXXCPP = @CXXCPP@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
DOXYGEN = @DOXYGEN@
ECHO = @ECHO@
EGREP = @EGREP@
F77 = @F77@
GCJ = @GCJ@
GCJFLAGS = @GCJFLAGS@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LIBTOOL = @LIBTOOL@
LN_S = @LN_S@
MAINT = @MAINT@
MIMIC_AGE = @MIMIC_AGE@
MIMIC_CURRENT = @MIMIC_CURRENT@
MIMIC_REVISION = @MIMIC_REVISION@
OBJDUMP = @OBJDUMP@
PACKAGE = @PACKAGE@
PKG_CONFIG = @PKG_CONFIG@
RANLIB = @RANLIB@
RC = @RC@
STRIP = @STRIP@
VERSION = @VERSION@
am__include = @am__include@
am__quote = @am__quote@
install_sh = @install_sh@
EXTRA_DIST = Doxyfile.in
subdir = doc
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES = Doxyfile
DIST_SOURCES =
DIST_COMMON = Doxyfile.in Makefile.am Makefile.in
all: all-am
.SUFFIXES:
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4)
cd $(top_srcdir) && \
$(AUTOMAKE) --gnu doc/Makefile
Makefile: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
Doxyfile: $(top_builddir)/config.status Doxyfile.in
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
distclean-libtool:
-rm -f libtool
uninstall-info-am:
tags: TAGS
TAGS:
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
top_distdir = ..
distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
distdir: $(DISTFILES)
@list='$(DISTFILES)'; for file in $$list; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
if test "$$dir" != "$$file" && test "$$dir" != "."; then \
dir="/$$dir"; \
$(mkinstalldirs) "$(distdir)$$dir"; \
else \
dir=''; \
fi; \
if test -d $$d/$$file; then \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
fi; \
cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
else \
test -f $(distdir)/$$file \
|| cp -p $$d/$$file $(distdir)/$$file \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile all-local
installdirs:
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
mostlyclean-generic:
clean-generic:
distclean-generic:
-rm -f Makefile $(CONFIG_CLEAN_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic clean-libtool mostlyclean-am
distclean: distclean-am
distclean-am: clean-am distclean-generic distclean-libtool
dvi: dvi-am
dvi-am:
info: info-am
info-am:
install-data-am:
install-exec-am:
install-info: install-info-am
install-man:
installcheck-am:
maintainer-clean: maintainer-clean-am
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-generic mostlyclean-libtool
uninstall-am: uninstall-info-am
.PHONY: all all-am all-local check check-am clean clean-generic \
clean-libtool distclean distclean-generic distclean-libtool \
distdir dvi dvi-am info info-am install install-am install-data \
install-data-am install-exec install-exec-am install-info \
install-info-am install-man install-strip installcheck \
installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-generic \
mostlyclean-libtool uninstall uninstall-am uninstall-info-am
@LIBMIMIC_DOXYGEN_DOCS_ENABLED_TRUE@all-local: dox
@LIBMIMIC_DOXYGEN_DOCS_ENABLED_TRUE@dox: Doxyfile
@LIBMIMIC_DOXYGEN_DOCS_ENABLED_TRUE@ -rm -rf api/
@LIBMIMIC_DOXYGEN_DOCS_ENABLED_TRUE@ doxygen Doxyfile
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
amsn-0.98.9/utils/webcamsn/AUTHORS 0000644 0001750 0001750 00000000055 10225230720 016371 0 ustar billiob billiob Ole André Vadla Ravnås
amsn-0.98.9/utils/webcamsn/webcamsn.tcl 0000644 0001750 0001750 00000014642 10630227077 017646 0 ustar billiob billiob #!/usr/bin/wish
proc GetDataSize { data } {
binary scan $data ssssiiii h_size w h r1 p_size fcc r2 r3
binary scan "\x30\x32\x4C\x4D" I r_fcc
if { [string length $data] < 24 } {
return 0
}
if { $h_size != 24 } {
puts "invalid - $h_size"
return -1
}
if { $fcc != $r_fcc} {
puts "fcc invalide - $fcc - $r_fcc"
return -1
}
#puts "resolution : $w x $h - $h_size $p_size - frame : $::frame - data size : [string length $data]"
if { $::frame == 271 } {
set fd [open khra w]
fconfigure $fd -encoding binary -translation binary
puts $fd $data
close $fd
}
return [expr $h_size + $p_size]
}
proc DecodeFile { filename } {
if { ![file readable $filename] } { error "Can't find the specified file" }
set debug [open debug.log w]
fconfigure $debug -buffering none
puts $debug "Start :\n"
set fd [open $filename]
fconfigure $fd -encoding binary -translation binary
set data [read $fd]
close $fd
puts $debug "Creating widgets :\n"
set img [image create photo]
catch {destroy .webcam}
toplevel .webcam
label .webcam.l -image $img
pack .webcam.l
set ::sem 0
set ::frame 0
puts $debug "Creating decoder"
set decoder [::Webcamsn::NewDecoder]
puts $debug "$decoder - [::Webcamsn::NumberOfOpenCodecs]"
while { [set size [GetDataSize $data] ] > 0 } {
puts $debug "decoding frame [::Webcamsn::NbFrames $decoder]"
if { ![winfo exists .webcam] } {
break
}
::Webcamsn::Decode $decoder $img $data
set data [string range $data $size end]
after 100 "incr ::sem"
tkwait variable ::sem
incr ::frame
}
puts $debug "$decoder - [::Webcamsn::NumberOfOpenCodecs]"
::Webcamsn::Close $decoder
puts $debug "$decoder - [::Webcamsn::NumberOfOpenCodecs]"
}
proc Switch { cmd1 time1 cmd2 time2 } {
eval $cmd1
after $time1 "Switch $cmd2 $time2 $cmd1 $time1"
}
proc EncodeToFile { filename } {
if { $::tkcx == 0 } { error "Unable to find TkCximage" }
if { $::file_to_test == "" || ![file readable $::file_to_test] } { error "Can't find movie2.gif" }
set debug [open debug.log w]
fconfigure $debug -buffering none
puts $debug "Start :\n"
set fd [open $filename w]
fconfigure $fd -encoding binary -translation binary -buffering none
puts $debug "Creating widgets :\n"
set img [image create photo -file $::file_to_test]
#Switch ::CxImage::DisableAnimated 1000 ::CxImage::EnableAnimated 1000
catch {destroy .webcam}
toplevel .webcam
label .webcam.l -image $img
pack .webcam.l
set ::sem 0
set ::frame 0
puts $debug "creating encoder"
set encoder [::Webcamsn::NewEncoder LOW]
puts $debug "$encoder - [::Webcamsn::NumberOfOpenCodecs]"
for {set i 0 } { $i < 1000 } { incr i} {
if { ![winfo exists .webcam] } {
break
}
puts $debug "encoding frame [::Webcamsn::NbFrames $encoder]"
if { [catch {set data [::Webcamsn::Encode $encoder $img]} res] } {
puts $debug "ERROR : $res\n"
} else {
set header "[binary format ssssi 24 160 120 0 [string length $data]]"
set header "$header\x4D\x4C\x32\x30\x00\x00\x00\x00\x00\x00\x00\x00"
puts -nonewline $fd $header
puts -nonewline $fd $data
}
after 10 "incr ::sem"
tkwait variable ::sem
incr ::frame
}
close $fd
puts $debug "$encoder - [::Webcamsn::NumberOfOpenCodecs]"
::Webcamsn::Close $encoder
puts $debug "$encoder - [::Webcamsn::NumberOfOpenCodecs]"
}
proc EncodeFromWebcam { filename } {
if { $::qttcl == 0 } { error "unable to find QuickTimeTcl AND tkvideo AND capture" }
set debug [open debug.log w]
fconfigure $debug -buffering none
puts $debug "Start :\n"
set fd [open $filename w]
fconfigure $fd -encoding binary -translation binary -buffering none
puts $debug "Creating widgets and sequencer :\n"
catch {destroy .webcam}
toplevel .webcam
seqgrabber .webcam.seq -width 160
pack .webcam.seq
set img [image create photo]
#If you want to see the pictures you shot, uncomment the 2 next lines
# label .webcam.l -image $img
# pack .webcam.l
set ::sem 0
set ::frame 0
puts $debug "Creating encoder"
set encoder [::Webcamsn::NewEncoder LOW]
puts $debug "$encoder - [::Webcamsn::NumberOfOpenCodecs]"
for {set i 0 } { $i < 1000 } { incr i} {
if { ![winfo exists .webcam] } {
break
}
puts $debug "encoding frame [::Webcamsn::NbFrames $encoder]"
if {![catch {tk windowingsystem} wsystem] && $wsystem == "aqua"} {
.webcam.seq image shot $img
#shot .webcam.seq $img
} else {
.webcam.seq picture $img
}
if { [catch {set data [::Webcamsn::Encode $encoder $img]} res] } {
puts $debug "ERROR : $res\n"
} else {
set header "[binary format ssssi 24 160 120 0 [string length $data]]"
set header "$header\x4D\x4C\x32\x30\x00\x00\x00\x00\x00\x00\x00\x00"
puts -nonewline $fd $header
puts -nonewline $fd $data
}
after 10 "incr ::sem"
tkwait variable ::sem
incr ::frame
}
close $fd
puts $debug "$encoder - [::Webcamsn::NumberOfOpenCodecs]"
::Webcamsn::Close $encoder
puts $debug "$encoder - [::Webcamsn::NumberOfOpenCodecs]"
}
proc shot {w img} {
}
lappend ::auto_path [pwd]
lappend ::auto_path "utils/"
lappend ::auto_path "utils/webcamsn"
lappend ::auto_path "utils/webcamsn/src"
lappend ::auto_path "utils/linux/capture"
lappend ::auto_path "utils/TkCximage"
lappend ::auto_path "utils/windows"
if { [catch { package require webcamsn} res] } {
error "Can't load Webcamsn package : $res"
}
set ::qttcl 1
set ::tkcx 1
set ::capture 1
set ::tkvideo 1
catch {console show}
if { [catch { package require QuickTimeTcl} ] } {
set ::qttcl 0
}
if { [catch { package require capture} ] } {
set ::capture 0
}
if { [catch { package require tkvideo} ] } {
set ::tkvideo 0
}
if { [catch { package require TkCximage }] } {
set ::tkcx 0
}
if { $::qttcl == 0 && $::tkcx == 0 && $::capture == 0 && $::tkvideo == 0 } {
error "You must have at least TkCximage OR QuickTimeTcl OR Capture OR Tkvideo extensions to test the application"
}
proc GetMovieFile { } {
foreach lib [info loaded] {
if { [lindex $lib 1] == "Tkcximage" } {
set dir [file dirname [lindex $lib 0]]
return "[file join $dir demos movie2.gif]"
}
}
return ""
}
set ::file_to_test [GetMovieFile]
amsn-0.98.9/utils/webcamsn/Rules.mk 0000644 0001750 0001750 00000000563 10750446030 016756 0 ustar billiob billiob OBJS-webcamsn := $(webcamsn_dir)/src/webcamsn.$(SHLIB_EXTENSION)
TARGETS-webcamsn := $(webcamsn_dir)/webcamsn.$(SHLIB_EXTENSION)
$(TARGETS-webcamsn): $(OBJS-webcamsn)
cp $< $@
all:: $(TARGETS-webcamsn)
check:: check-webcamsn
check-webcamsn:
wish $(webcamsn_dir)/webcamsn.tcl
clean:: clean-webcamsn
clean-webcamsn::
rm -f $(TARGETS-webcamsn) $(OBJS-webcamsn)
amsn-0.98.9/utils/linux/ 0000755 0001750 0001750 00000000000 11757711632 014702 5 ustar billiob billiob amsn-0.98.9/utils/linux/capture/ 0000755 0001750 0001750 00000000000 11757711632 016345 5 ustar billiob billiob amsn-0.98.9/utils/linux/capture/libng/ 0000755 0001750 0001750 00000000000 11757711632 017440 5 ustar billiob billiob amsn-0.98.9/utils/linux/capture/libng/videodev2.h 0000644 0001750 0001750 00000062073 10574640152 021502 0 ustar billiob billiob #ifndef __LINUX_VIDEODEV2_H
#define __LINUX_VIDEODEV2_H
/*
* Video for Linux Two
*
* Header file for v4l or V4L2 drivers and applications, for
* Linux kernels 2.2.x or 2.4.x.
*
* See http://www.thedirks.org/v4l2/ for API specs and other
* v4l2 documentation.
*
* Author: Bill Dirks
* Justin Schoeman
* et al.
*/
/*
* M I S C E L L A N E O U S
*/
/* Four-character-code (FOURCC) */
#define v4l2_fourcc(a,b,c,d)\
(((__u32)(a)<<0)|((__u32)(b)<<8)|((__u32)(c)<<16)|((__u32)(d)<<24))
/*
* E N U M S
*/
enum v4l2_field {
V4L2_FIELD_ANY = 0, /* driver can choose from none,
top, bottom, interlaced
depending on whatever it thinks
is approximate ... */
V4L2_FIELD_NONE = 1, /* this device has no fields ... */
V4L2_FIELD_TOP = 2, /* top field only */
V4L2_FIELD_BOTTOM = 3, /* bottom field only */
V4L2_FIELD_INTERLACED = 4, /* both fields interlaced */
V4L2_FIELD_SEQ_TB = 5, /* both fields sequential into one
buffer, top-bottom order */
V4L2_FIELD_SEQ_BT = 6, /* same as above + bottom-top order */
V4L2_FIELD_ALTERNATE = 7, /* both fields alternating into
separate buffers */
};
#define V4L2_FIELD_HAS_TOP(field) \
((field) == V4L2_FIELD_TOP ||\
(field) == V4L2_FIELD_INTERLACED ||\
(field) == V4L2_FIELD_SEQ_TB ||\
(field) == V4L2_FIELD_SEQ_BT)
#define V4L2_FIELD_HAS_BOTTOM(field) \
((field) == V4L2_FIELD_BOTTOM ||\
(field) == V4L2_FIELD_INTERLACED ||\
(field) == V4L2_FIELD_SEQ_TB ||\
(field) == V4L2_FIELD_SEQ_BT)
#define V4L2_FIELD_HAS_BOTH(field) \
((field) == V4L2_FIELD_INTERLACED ||\
(field) == V4L2_FIELD_SEQ_TB ||\
(field) == V4L2_FIELD_SEQ_BT)
enum v4l2_buf_type {
V4L2_BUF_TYPE_VIDEO_CAPTURE = 1,
V4L2_BUF_TYPE_VIDEO_OUTPUT = 2,
V4L2_BUF_TYPE_VIDEO_OVERLAY = 3,
V4L2_BUF_TYPE_VBI_CAPTURE = 4,
V4L2_BUF_TYPE_VBI_OUTPUT = 5,
V4L2_BUF_TYPE_PRIVATE = 0x80,
};
enum v4l2_ctrl_type {
V4L2_CTRL_TYPE_INTEGER = 1,
V4L2_CTRL_TYPE_BOOLEAN = 2,
V4L2_CTRL_TYPE_MENU = 3,
V4L2_CTRL_TYPE_BUTTON = 4,
};
enum v4l2_tuner_type {
V4L2_TUNER_RADIO = 1,
V4L2_TUNER_ANALOG_TV = 2,
};
enum v4l2_memory {
V4L2_MEMORY_MMAP = 1,
V4L2_MEMORY_USERPTR = 2,
V4L2_MEMORY_OVERLAY = 3,
};
/* see also http://vektor.theorem.ca/graphics/ycbcr/ */
enum v4l2_colorspace {
/* ITU-R 601 -- broadcast NTSC/PAL */
V4L2_COLORSPACE_SMPTE170M = 1,
/* 1125-Line (US) HDTV */
V4L2_COLORSPACE_SMPTE240M = 2,
/* HD and modern captures. */
V4L2_COLORSPACE_REC709 = 3,
/* broken BT878 extents (601, luma range 16-253 instead of 16-235) */
V4L2_COLORSPACE_BT878 = 4,
/* These should be useful. Assume 601 extents. */
V4L2_COLORSPACE_470_SYSTEM_M = 5,
V4L2_COLORSPACE_470_SYSTEM_BG = 6,
/* I know there will be cameras that send this. So, this is
* unspecified chromaticities and full 0-255 on each of the
* Y'CbCr components
*/
V4L2_COLORSPACE_JPEG = 7,
/* For RGB colourspaces, this is probably a good start. */
V4L2_COLORSPACE_SRGB = 8,
};
struct v4l2_rect {
__s32 left;
__s32 top;
__s32 width;
__s32 height;
};
struct v4l2_fract {
__u32 numerator;
__u32 denominator;
};
/*
* D R I V E R C A P A B I L I T I E S
*/
struct v4l2_capability
{
__u8 driver[16]; /* i.e. "bttv" */
__u8 card[32]; /* i.e. "Hauppauge WinTV" */
__u8 bus_info[32]; /* "PCI:" + pci_dev->slot_name */
__u32 version; /* should use KERNEL_VERSION() */
__u32 capabilities; /* Device capabilities */
__u32 reserved[4];
};
/* Values for 'capabilities' field */
#define V4L2_CAP_VIDEO_CAPTURE 0x00000001 /* Is a video capture device */
#define V4L2_CAP_VIDEO_OUTPUT 0x00000002 /* Is a video output device */
#define V4L2_CAP_VIDEO_OVERLAY 0x00000004 /* Can do video overlay */
#define V4L2_CAP_VBI_CAPTURE 0x00000010 /* Is a VBI capture device */
#define V4L2_CAP_VBI_OUTPUT 0x00000020 /* Is a VBI output device */
#define V4L2_CAP_RDS_CAPTURE 0x00000100 /* RDS data capture */
#define V4L2_CAP_TUNER 0x00010000 /* Has a tuner */
#define V4L2_CAP_AUDIO 0x00020000 /* has audio support */
#define V4L2_CAP_READWRITE 0x01000000 /* read/write systemcalls */
#define V4L2_CAP_ASYNCIO 0x02000000 /* async I/O */
#define V4L2_CAP_STREAMING 0x04000000 /* streaming I/O ioctls */
/*
* V I D E O I M A G E F O R M A T
*/
struct v4l2_pix_format
{
__u32 width;
__u32 height;
__u32 pixelformat;
enum v4l2_field field;
__u32 bytesperline; /* for padding, zero if unused */
__u32 sizeimage;
enum v4l2_colorspace colorspace;
__u32 priv; /* private data, depends on pixelformat */
};
/* Pixel format FOURCC depth Description */
#define V4L2_PIX_FMT_RGB332 v4l2_fourcc('R','G','B','1') /* 8 RGB-3-3-2 */
#define V4L2_PIX_FMT_RGB555 v4l2_fourcc('R','G','B','O') /* 16 RGB-5-5-5 */
#define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R','G','B','P') /* 16 RGB-5-6-5 */
#define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R','G','B','Q') /* 16 RGB-5-5-5 BE */
#define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R','G','B','R') /* 16 RGB-5-6-5 BE */
#define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B','G','R','3') /* 24 BGR-8-8-8 */
#define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R','G','B','3') /* 24 RGB-8-8-8 */
#define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B','G','R','4') /* 32 BGR-8-8-8-8 */
#define V4L2_PIX_FMT_RGB32 v4l2_fourcc('R','G','B','4') /* 32 RGB-8-8-8-8 */
#define V4L2_PIX_FMT_GREY v4l2_fourcc('G','R','E','Y') /* 8 Greyscale */
#define V4L2_PIX_FMT_YVU410 v4l2_fourcc('Y','V','U','9') /* 9 YVU 4:1:0 */
#define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y','V','1','2') /* 12 YVU 4:2:0 */
#define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y','U','Y','V') /* 16 YUV 4:2:2 */
#define V4L2_PIX_FMT_UYVY v4l2_fourcc('U','Y','V','Y') /* 16 YUV 4:2:2 */
#define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4','2','2','P') /* 16 YVU422 planar */
#define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4','1','1','P') /* 16 YVU411 planar */
#define V4L2_PIX_FMT_Y41P v4l2_fourcc('Y','4','1','P') /* 12 YUV 4:1:1 */
/* two planes -- one Y, one Cr + Cb interleaved */
#define V4L2_PIX_FMT_NV12 v4l2_fourcc('N','V','1','2') /* 12 Y/CbCr 4:2:0 */
#define V4L2_PIX_FMT_NV21 v4l2_fourcc('N','V','2','1') /* 12 Y/CrCb 4:2:0 */
/* The following formats are not defined in the V4L2 specification */
#define V4L2_PIX_FMT_YUV410 v4l2_fourcc('Y','U','V','9') /* 9 YUV 4:1:0 */
#define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y','U','1','2') /* 12 YUV 4:2:0 */
#define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y','Y','U','V') /* 16 YUV 4:2:2 */
#define V4L2_PIX_FMT_HI240 v4l2_fourcc('H','I','2','4') /* 8 8-bit color */
/* compressed formats */
#define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M','J','P','G') /* Motion-JPEG */
#define V4L2_PIX_FMT_JPEG v4l2_fourcc('J','P','E','G') /* JFIF JPEG */
#define V4L2_PIX_FMT_DV v4l2_fourcc('d','v','s','d') /* 1394 */
#define V4L2_PIX_FMT_MPEG v4l2_fourcc('M','P','E','G') /* MPEG */
/* Vendor-specific formats */
#define V4L2_PIX_FMT_WNVA v4l2_fourcc('W','N','V','A') /* Winnov hw compres */
#define V4L2_PIX_FMT_BA81 v4l2_fourcc('B','A','8','1') /* Bayer */
#define V4L2_PIX_FMT_S910 v4l2_fourcc('S','9','1','0') /* SN9C102 Driver Compressed Format */
/*
* F O R M A T E N U M E R A T I O N
*/
struct v4l2_fmtdesc
{
__u32 index; /* Format number */
enum v4l2_buf_type type; /* buffer type */
__u32 flags;
__u8 description[32]; /* Description string */
__u32 pixelformat; /* Format fourcc */
__u32 reserved[4];
};
#define V4L2_FMT_FLAG_COMPRESSED 0x0001
/*
* T I M E C O D E
*/
struct v4l2_timecode
{
__u32 type;
__u32 flags;
__u8 frames;
__u8 seconds;
__u8 minutes;
__u8 hours;
__u8 userbits[4];
};
/* Type */
#define V4L2_TC_TYPE_24FPS 1
#define V4L2_TC_TYPE_25FPS 2
#define V4L2_TC_TYPE_30FPS 3
#define V4L2_TC_TYPE_50FPS 4
#define V4L2_TC_TYPE_60FPS 5
/* Flags */
#define V4L2_TC_FLAG_DROPFRAME 0x0001 /* "drop-frame" mode */
#define V4L2_TC_FLAG_COLORFRAME 0x0002
#define V4L2_TC_USERBITS_field 0x000C
#define V4L2_TC_USERBITS_USERDEFINED 0x0000
#define V4L2_TC_USERBITS_8BITCHARS 0x0008
/* The above is based on SMPTE timecodes */
/*
* C O M P R E S S I O N P A R A M E T E R S
*/
#if 0
/* ### generic compression settings don't work, there is too much
* ### codec-specific stuff. Maybe reuse that for MPEG codec settings
* ### later ... */
struct v4l2_compression
{
__u32 quality;
__u32 keyframerate;
__u32 pframerate;
__u32 reserved[5];
};
#endif
struct v4l2_jpegcompression
{
int quality;
int APPn; /* Number of APP segment to be written,
* must be 0..15 */
int APP_len; /* Length of data in JPEG APPn segment */
char APP_data[60]; /* Data in the JPEG APPn segment. */
int COM_len; /* Length of data in JPEG COM segment */
char COM_data[60]; /* Data in JPEG COM segment */
__u32 jpeg_markers; /* Which markers should go into the JPEG
* output. Unless you exactly know what
* you do, leave them untouched.
* Inluding less markers will make the
* resulting code smaller, but there will
* be fewer aplications which can read it.
* The presence of the APP and COM marker
* is influenced by APP_len and COM_len
* ONLY, not by this property! */
#define V4L2_JPEG_MARKER_DHT (1<<3) /* Define Huffman Tables */
#define V4L2_JPEG_MARKER_DQT (1<<4) /* Define Quantization Tables */
#define V4L2_JPEG_MARKER_DRI (1<<5) /* Define Restart Interval */
#define V4L2_JPEG_MARKER_COM (1<<6) /* Comment segment */
#define V4L2_JPEG_MARKER_APP (1<<7) /* App segment, driver will
* allways use APP0 */
};
/*
* M E M O R Y - M A P P I N G B U F F E R S
*/
struct v4l2_requestbuffers
{
__u32 count;
enum v4l2_buf_type type;
enum v4l2_memory memory;
__u32 reserved[2];
};
struct v4l2_buffer
{
__u32 index;
enum v4l2_buf_type type;
__u32 bytesused;
__u32 flags;
enum v4l2_field field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
/* memory location */
enum v4l2_memory memory;
union {
__u32 offset;
unsigned long userptr;
} m;
__u32 length;
__u32 reserved[2];
};
/* Flags for 'flags' field */
#define V4L2_BUF_FLAG_MAPPED 0x0001 /* Buffer is mapped (flag) */
#define V4L2_BUF_FLAG_QUEUED 0x0002 /* Buffer is queued for processing */
#define V4L2_BUF_FLAG_DONE 0x0004 /* Buffer is ready */
#define V4L2_BUF_FLAG_KEYFRAME 0x0008 /* Image is a keyframe (I-frame) */
#define V4L2_BUF_FLAG_PFRAME 0x0010 /* Image is a P-frame */
#define V4L2_BUF_FLAG_BFRAME 0x0020 /* Image is a B-frame */
#define V4L2_BUF_FLAG_TIMECODE 0x0100 /* timecode field is valid */
/*
* O V E R L A Y P R E V I E W
*/
struct v4l2_framebuffer
{
__u32 capability;
__u32 flags;
/* FIXME: in theory we should pass something like PCI device + memory
* region + offset instead of some physical address */
void* base;
struct v4l2_pix_format fmt;
};
/* Flags for the 'capability' field. Read only */
#define V4L2_FBUF_CAP_EXTERNOVERLAY 0x0001
#define V4L2_FBUF_CAP_CHROMAKEY 0x0002
#define V4L2_FBUF_CAP_LIST_CLIPPING 0x0004
#define V4L2_FBUF_CAP_BITMAP_CLIPPING 0x0008
/* Flags for the 'flags' field. */
#define V4L2_FBUF_FLAG_PRIMARY 0x0001
#define V4L2_FBUF_FLAG_OVERLAY 0x0002
#define V4L2_FBUF_FLAG_CHROMAKEY 0x0004
struct v4l2_clip
{
struct v4l2_rect c;
struct v4l2_clip *next;
};
struct v4l2_window
{
struct v4l2_rect w;
enum v4l2_field field;
__u32 chromakey;
struct v4l2_clip *clips;
__u32 clipcount;
void *bitmap;
};
/*
* C A P T U R E P A R A M E T E R S
*/
struct v4l2_captureparm
{
__u32 capability; /* Supported modes */
__u32 capturemode; /* Current mode */
struct v4l2_fract timeperframe; /* Time per frame in .1us units */
__u32 extendedmode; /* Driver-specific extensions */
__u32 readbuffers; /* # of buffers for read */
__u32 reserved[4];
};
/* Flags for 'capability' and 'capturemode' fields */
#define V4L2_MODE_HIGHQUALITY 0x0001 /* High quality imaging mode */
#define V4L2_CAP_TIMEPERFRAME 0x1000 /* timeperframe field is supported */
struct v4l2_outputparm
{
__u32 capability; /* Supported modes */
__u32 outputmode; /* Current mode */
struct v4l2_fract timeperframe; /* Time per frame in seconds */
__u32 extendedmode; /* Driver-specific extensions */
__u32 writebuffers; /* # of buffers for write */
__u32 reserved[4];
};
/*
* I N P U T I M A G E C R O P P I N G
*/
struct v4l2_cropcap {
enum v4l2_buf_type type;
struct v4l2_rect bounds;
struct v4l2_rect defrect;
struct v4l2_fract pixelaspect;
};
struct v4l2_crop {
enum v4l2_buf_type type;
struct v4l2_rect c;
};
/*
* A N A L O G V I D E O S T A N D A R D
*/
typedef __u64 v4l2_std_id;
/* one bit for each */
#define V4L2_STD_PAL_B ((v4l2_std_id)0x00000001)
#define V4L2_STD_PAL_B1 ((v4l2_std_id)0x00000002)
#define V4L2_STD_PAL_G ((v4l2_std_id)0x00000004)
#define V4L2_STD_PAL_H ((v4l2_std_id)0x00000008)
#define V4L2_STD_PAL_I ((v4l2_std_id)0x00000010)
#define V4L2_STD_PAL_D ((v4l2_std_id)0x00000020)
#define V4L2_STD_PAL_D1 ((v4l2_std_id)0x00000040)
#define V4L2_STD_PAL_K ((v4l2_std_id)0x00000080)
#define V4L2_STD_PAL_M ((v4l2_std_id)0x00000100)
#define V4L2_STD_PAL_N ((v4l2_std_id)0x00000200)
#define V4L2_STD_PAL_Nc ((v4l2_std_id)0x00000400)
#define V4L2_STD_PAL_60 ((v4l2_std_id)0x00000800)
#define V4L2_STD_NTSC_M ((v4l2_std_id)0x00001000)
#define V4L2_STD_NTSC_M_JP ((v4l2_std_id)0x00002000)
#define V4L2_STD_SECAM_B ((v4l2_std_id)0x00010000)
#define V4L2_STD_SECAM_D ((v4l2_std_id)0x00020000)
#define V4L2_STD_SECAM_G ((v4l2_std_id)0x00040000)
#define V4L2_STD_SECAM_H ((v4l2_std_id)0x00080000)
#define V4L2_STD_SECAM_K ((v4l2_std_id)0x00100000)
#define V4L2_STD_SECAM_K1 ((v4l2_std_id)0x00200000)
#define V4L2_STD_SECAM_L ((v4l2_std_id)0x00400000)
/* ATSC/HDTV */
#define V4L2_STD_ATSC_8_VSB ((v4l2_std_id)0x01000000)
#define V4L2_STD_ATSC_16_VSB ((v4l2_std_id)0x02000000)
/* some common needed stuff */
#define V4L2_STD_PAL_BG (V4L2_STD_PAL_B |\
V4L2_STD_PAL_B1 |\
V4L2_STD_PAL_G)
#define V4L2_STD_PAL_DK (V4L2_STD_PAL_D |\
V4L2_STD_PAL_D1 |\
V4L2_STD_PAL_K)
#define V4L2_STD_PAL (V4L2_STD_PAL_BG |\
V4L2_STD_PAL_DK |\
V4L2_STD_PAL_H |\
V4L2_STD_PAL_I)
#define V4L2_STD_NTSC (V4L2_STD_NTSC_M |\
V4L2_STD_NTSC_M_JP)
#define V4L2_STD_SECAM (V4L2_STD_SECAM_B |\
V4L2_STD_SECAM_D |\
V4L2_STD_SECAM_G |\
V4L2_STD_SECAM_H |\
V4L2_STD_SECAM_K |\
V4L2_STD_SECAM_K1 |\
V4L2_STD_SECAM_L)
#define V4L2_STD_525_60 (V4L2_STD_PAL_M |\
V4L2_STD_PAL_60 |\
V4L2_STD_NTSC)
#define V4L2_STD_625_50 (V4L2_STD_PAL |\
V4L2_STD_PAL_N |\
V4L2_STD_PAL_Nc |\
V4L2_STD_SECAM)
#define V4L2_STD_UNKNOWN 0
#define V4L2_STD_ALL (V4L2_STD_525_60 |\
V4L2_STD_625_50)
struct v4l2_standard
{
__u32 index;
v4l2_std_id id;
__u8 name[24];
struct v4l2_fract frameperiod; /* Frames, not fields */
__u32 framelines;
__u32 reserved[4];
};
/*
* V I D E O I N P U T S
*/
struct v4l2_input
{
__u32 index; /* Which input */
__u8 name[32]; /* Label */
__u32 type; /* Type of input */
__u32 audioset; /* Associated audios (bitfield) */
__u32 tuner; /* Associated tuner */
v4l2_std_id std;
__u32 status;
__u32 reserved[4];
};
/* Values for the 'type' field */
#define V4L2_INPUT_TYPE_TUNER 1
#define V4L2_INPUT_TYPE_CAMERA 2
/* field 'status' - general */
#define V4L2_IN_ST_NO_POWER 0x00000001 /* Attached device is off */
#define V4L2_IN_ST_NO_SIGNAL 0x00000002
#define V4L2_IN_ST_NO_COLOR 0x00000004
/* field 'status' - analog */
#define V4L2_IN_ST_NO_H_LOCK 0x00000100 /* No horizontal sync lock */
#define V4L2_IN_ST_COLOR_KILL 0x00000200 /* Color killer is active */
/* field 'status' - digital */
#define V4L2_IN_ST_NO_SYNC 0x00010000 /* No synchronization lock */
#define V4L2_IN_ST_NO_EQU 0x00020000 /* No equalizer lock */
#define V4L2_IN_ST_NO_CARRIER 0x00040000 /* Carrier recovery failed */
/* field 'status' - VCR and set-top box */
#define V4L2_IN_ST_MACROVISION 0x01000000 /* Macrovision detected */
#define V4L2_IN_ST_NO_ACCESS 0x02000000 /* Conditional access denied */
#define V4L2_IN_ST_VTR 0x04000000 /* VTR time constant */
/*
* V I D E O O U T P U T S
*/
struct v4l2_output
{
__u32 index; /* Which output */
__u8 name[32]; /* Label */
__u32 type; /* Type of output */
__u32 audioset; /* Associated audios (bitfield) */
__u32 modulator; /* Associated modulator */
v4l2_std_id std;
__u32 reserved[4];
};
/* Values for the 'type' field */
#define V4L2_OUTPUT_TYPE_MODULATOR 1
#define V4L2_OUTPUT_TYPE_ANALOG 2
#define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY 3
/*
* C O N T R O L S
*/
struct v4l2_control
{
__u32 id;
__s32 value;
};
/* Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
struct v4l2_queryctrl
{
__u32 id;
enum v4l2_ctrl_type type;
__u8 name[32]; /* Whatever */
__s32 minimum; /* Note signedness */
__s32 maximum;
__s32 step;
__s32 default_value;
__u32 flags;
__u32 reserved[2];
};
/* Used in the VIDIOC_QUERYMENU ioctl for querying menu items */
struct v4l2_querymenu
{
__u32 id;
__u32 index;
__u8 name[32]; /* Whatever */
__u32 reserved;
};
/* Control flags */
#define V4L2_CTRL_FLAG_DISABLED 0x0001
#define V4L2_CTRL_FLAG_GRABBED 0x0002
/* Control IDs defined by V4L2 */
#define V4L2_CID_BASE 0x00980900
/* IDs reserved for driver specific controls */
#define V4L2_CID_PRIVATE_BASE 0x08000000
#define V4L2_CID_BRIGHTNESS (V4L2_CID_BASE+0)
#define V4L2_CID_CONTRAST (V4L2_CID_BASE+1)
#define V4L2_CID_SATURATION (V4L2_CID_BASE+2)
#define V4L2_CID_HUE (V4L2_CID_BASE+3)
#define V4L2_CID_AUDIO_VOLUME (V4L2_CID_BASE+5)
#define V4L2_CID_AUDIO_BALANCE (V4L2_CID_BASE+6)
#define V4L2_CID_AUDIO_BASS (V4L2_CID_BASE+7)
#define V4L2_CID_AUDIO_TREBLE (V4L2_CID_BASE+8)
#define V4L2_CID_AUDIO_MUTE (V4L2_CID_BASE+9)
#define V4L2_CID_AUDIO_LOUDNESS (V4L2_CID_BASE+10)
#define V4L2_CID_BLACK_LEVEL (V4L2_CID_BASE+11)
#define V4L2_CID_AUTO_WHITE_BALANCE (V4L2_CID_BASE+12)
#define V4L2_CID_DO_WHITE_BALANCE (V4L2_CID_BASE+13)
#define V4L2_CID_RED_BALANCE (V4L2_CID_BASE+14)
#define V4L2_CID_BLUE_BALANCE (V4L2_CID_BASE+15)
#define V4L2_CID_GAMMA (V4L2_CID_BASE+16)
#define V4L2_CID_WHITENESS (V4L2_CID_GAMMA) /* ? Not sure */
#define V4L2_CID_EXPOSURE (V4L2_CID_BASE+17)
#define V4L2_CID_AUTOGAIN (V4L2_CID_BASE+18)
#define V4L2_CID_GAIN (V4L2_CID_BASE+19)
#define V4L2_CID_HFLIP (V4L2_CID_BASE+20)
#define V4L2_CID_VFLIP (V4L2_CID_BASE+21)
#define V4L2_CID_HCENTER (V4L2_CID_BASE+22)
#define V4L2_CID_VCENTER (V4L2_CID_BASE+23)
#define V4L2_CID_LASTP1 (V4L2_CID_BASE+24) /* last CID + 1 */
/*
* T U N I N G
*/
struct v4l2_tuner
{
__u32 index;
__u8 name[32];
enum v4l2_tuner_type type;
__u32 capability;
__u32 rangelow;
__u32 rangehigh;
__u32 rxsubchans;
__u32 audmode;
__s32 signal;
__s32 afc;
__u32 reserved[4];
};
struct v4l2_modulator
{
__u32 index;
__u8 name[32];
__u32 capability;
__u32 rangelow;
__u32 rangehigh;
__u32 txsubchans;
__u32 reserved[4];
};
/* Flags for the 'capability' field */
#define V4L2_TUNER_CAP_LOW 0x0001
#define V4L2_TUNER_CAP_NORM 0x0002
#define V4L2_TUNER_CAP_STEREO 0x0010
#define V4L2_TUNER_CAP_LANG2 0x0020
#define V4L2_TUNER_CAP_SAP 0x0020
#define V4L2_TUNER_CAP_LANG1 0x0040
/* Flags for the 'rxsubchans' field */
#define V4L2_TUNER_SUB_MONO 0x0001
#define V4L2_TUNER_SUB_STEREO 0x0002
#define V4L2_TUNER_SUB_LANG2 0x0004
#define V4L2_TUNER_SUB_SAP 0x0004
#define V4L2_TUNER_SUB_LANG1 0x0008
/* Values for the 'audmode' field */
#define V4L2_TUNER_MODE_MONO 0x0000
#define V4L2_TUNER_MODE_STEREO 0x0001
#define V4L2_TUNER_MODE_LANG2 0x0002
#define V4L2_TUNER_MODE_SAP 0x0002
#define V4L2_TUNER_MODE_LANG1 0x0003
struct v4l2_frequency
{
__u32 tuner;
enum v4l2_tuner_type type;
__u32 frequency;
__u32 reserved[8];
};
/*
* A U D I O
*/
struct v4l2_audio
{
__u32 index;
__u8 name[32];
__u32 capability;
__u32 mode;
__u32 reserved[2];
};
/* Flags for the 'capability' field */
#define V4L2_AUDCAP_STEREO 0x00001
#define V4L2_AUDCAP_AVL 0x00002
/* Flags for the 'mode' field */
#define V4L2_AUDMODE_AVL 0x00001
struct v4l2_audioout
{
__u32 index;
__u8 name[32];
__u32 capability;
__u32 mode;
__u32 reserved[2];
};
/*
* D A T A S E R V I C E S ( V B I )
*
* Data services API by Michael Schimek
*/
struct v4l2_vbi_format
{
__u32 sampling_rate; /* in 1 Hz */
__u32 offset;
__u32 samples_per_line;
__u32 sample_format; /* V4L2_PIX_FMT_* */
__s32 start[2];
__u32 count[2];
__u32 flags; /* V4L2_VBI_* */
__u32 reserved[2]; /* must be zero */
};
/* VBI flags */
#define V4L2_VBI_UNSYNC (1<< 0)
#define V4L2_VBI_INTERLACED (1<< 1)
/*
* A G G R E G A T E S T R U C T U R E S
*/
/* Stream data format
*/
struct v4l2_format
{
enum v4l2_buf_type type;
union
{
struct v4l2_pix_format pix; // V4L2_BUF_TYPE_VIDEO_CAPTURE
struct v4l2_window win; // V4L2_BUF_TYPE_VIDEO_OVERLAY
struct v4l2_vbi_format vbi; // V4L2_BUF_TYPE_VBI_CAPTURE
__u8 raw_data[200]; // user-defined
} fmt;
};
/* Stream type-dependent parameters
*/
struct v4l2_streamparm
{
enum v4l2_buf_type type;
union
{
struct v4l2_captureparm capture;
struct v4l2_outputparm output;
__u8 raw_data[200]; /* user-defined */
} parm;
};
/*
* I O C T L C O D E S F O R V I D E O D E V I C E S
*
*/
#define VIDIOC_QUERYCAP _IOR ('V', 0, struct v4l2_capability)
#define VIDIOC_RESERVED _IO ('V', 1)
#define VIDIOC_ENUM_FMT _IOWR ('V', 2, struct v4l2_fmtdesc)
#define VIDIOC_G_FMT _IOWR ('V', 4, struct v4l2_format)
#define VIDIOC_S_FMT _IOWR ('V', 5, struct v4l2_format)
#if 0
#define VIDIOC_G_COMP _IOR ('V', 6, struct v4l2_compression)
#define VIDIOC_S_COMP _IOW ('V', 7, struct v4l2_compression)
#endif
#define VIDIOC_REQBUFS _IOWR ('V', 8, struct v4l2_requestbuffers)
#define VIDIOC_QUERYBUF _IOWR ('V', 9, struct v4l2_buffer)
#define VIDIOC_G_FBUF _IOR ('V', 10, struct v4l2_framebuffer)
#define VIDIOC_S_FBUF _IOW ('V', 11, struct v4l2_framebuffer)
#define VIDIOC_OVERLAY _IOWR ('V', 14, int)
#define VIDIOC_QBUF _IOWR ('V', 15, struct v4l2_buffer)
#define VIDIOC_DQBUF _IOWR ('V', 17, struct v4l2_buffer)
#define VIDIOC_STREAMON _IOW ('V', 18, int)
#define VIDIOC_STREAMOFF _IOW ('V', 19, int)
#define VIDIOC_G_PARM _IOWR ('V', 21, struct v4l2_streamparm)
#define VIDIOC_S_PARM _IOW ('V', 22, struct v4l2_streamparm)
#define VIDIOC_G_STD _IOR ('V', 23, v4l2_std_id)
#define VIDIOC_S_STD _IOW ('V', 24, v4l2_std_id)
#define VIDIOC_ENUMSTD _IOWR ('V', 25, struct v4l2_standard)
#define VIDIOC_ENUMINPUT _IOWR ('V', 26, struct v4l2_input)
#define VIDIOC_G_CTRL _IOWR ('V', 27, struct v4l2_control)
#define VIDIOC_S_CTRL _IOW ('V', 28, struct v4l2_control)
#define VIDIOC_G_TUNER _IOWR ('V', 29, struct v4l2_tuner)
#define VIDIOC_S_TUNER _IOW ('V', 30, struct v4l2_tuner)
#define VIDIOC_G_AUDIO _IOWR ('V', 33, struct v4l2_audio)
#define VIDIOC_S_AUDIO _IOW ('V', 34, struct v4l2_audio)
#define VIDIOC_QUERYCTRL _IOWR ('V', 36, struct v4l2_queryctrl)
#define VIDIOC_QUERYMENU _IOWR ('V', 37, struct v4l2_querymenu)
#define VIDIOC_G_INPUT _IOR ('V', 38, int)
#define VIDIOC_S_INPUT _IOWR ('V', 39, int)
#define VIDIOC_G_OUTPUT _IOR ('V', 46, int)
#define VIDIOC_S_OUTPUT _IOWR ('V', 47, int)
#define VIDIOC_ENUMOUTPUT _IOWR ('V', 48, struct v4l2_output)
#define VIDIOC_G_AUDOUT _IOWR ('V', 49, struct v4l2_audioout)
#define VIDIOC_S_AUDOUT _IOW ('V', 50, struct v4l2_audioout)
#define VIDIOC_G_MODULATOR _IOWR ('V', 54, struct v4l2_modulator)
#define VIDIOC_S_MODULATOR _IOW ('V', 55, struct v4l2_modulator)
#define VIDIOC_G_FREQUENCY _IOWR ('V', 56, struct v4l2_frequency)
#define VIDIOC_S_FREQUENCY _IOW ('V', 57, struct v4l2_frequency)
#define VIDIOC_CROPCAP _IOR ('V', 58, struct v4l2_cropcap)
#define VIDIOC_G_CROP _IOWR ('V', 59, struct v4l2_crop)
#define VIDIOC_S_CROP _IOW ('V', 60, struct v4l2_crop)
#define VIDIOC_G_JPEGCOMP _IOR ('V', 61, struct v4l2_jpegcompression)
#define VIDIOC_S_JPEGCOMP _IOW ('V', 62, struct v4l2_jpegcompression)
#define VIDIOC_QUERYSTD _IOR ('V', 63, v4l2_std_id)
#define VIDIOC_TRY_FMT _IOWR ('V', 64, struct v4l2_format)
#define BASE_VIDIOC_PRIVATE 192 /* 192-255 are private */
#endif /* __LINUX_VIDEODEV2_H */
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
amsn-0.98.9/utils/linux/capture/libng/Makefile 0000644 0001750 0001750 00000000031 10246003435 021055 0 ustar billiob billiob default:
cd ..; $(MAKE)
amsn-0.98.9/utils/linux/capture/libng/misc.c 0000644 0001750 0001750 00000001554 10246003435 020527 0 ustar billiob billiob #include "config.h"
#include
#include
#include "grab-ng.h"
#include "misc.h"
/* ------------------------------------------------------------------------ */
/* prehistoric libc ;) */
#ifndef HAVE_STRCASESTR
char* __used strcasestr(char *haystack, char *needle)
{
int hlen = strlen(haystack);
int nlen = strlen(needle);
int offset;
for (offset = 0; offset <= hlen - nlen; offset++)
if (0 == strncasecmp(haystack+offset,needle,nlen))
return haystack+offset;
return NULL;
}
#endif
#ifndef HAVE_MEMMEM
void __used *memmem(unsigned char *haystack, size_t haystacklen,
unsigned char *needle, size_t needlelen)
{
int i;
for (i = 0; i < haystacklen - needlelen; i++)
if (0 == memcmp(haystack+i,needle,needlelen))
return haystack+i;
return NULL;
}
#endif
amsn-0.98.9/utils/linux/capture/libng/writefile.c 0000644 0001750 0001750 00000036256 10246003435 021575 0 ustar billiob billiob /*
* save pictures to disk (ppm,pgm,jpeg)
*
* (c) 1998-2000 Gerd Knorr
*
*/
#define NG_PRIVATE
#include "config.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "byteswap.h"
#include "grab-ng.h"
#include "writefile.h"
/* ---------------------------------------------------------------------- */
/*
* count up the latest block of digits in the passed string
* (used for filename numbering
*/
int
patch_up(char *name)
{
char *ptr;
for (ptr = name+strlen(name); ptr >= name; ptr--)
if (isdigit(*ptr))
break;
if (ptr < name)
return 0;
while (*ptr == '9' && ptr >= name)
*(ptr--) = '0';
if (ptr < name)
return 0;
if (isdigit(*ptr)) {
(*ptr)++;
return 1;
}
return 0;
}
char*
snap_filename(char *base, char *channel, char *ext)
{
static time_t last = 0;
static int count = 0;
static char *filename = NULL;
time_t now;
struct tm* tm;
char timestamp[32];
time(&now);
tm = localtime(&now);
if (last != now)
count = 0;
last = now;
count++;
if (filename != NULL)
free(filename);
filename = malloc(strlen(base)+strlen(channel)+strlen(ext)+32);
strftime(timestamp,31,"%Y%m%d-%H%M%S",tm);
sprintf(filename,"%s-%s-%s-%d.%s",
base,channel,timestamp,count,ext);
return filename;
}
/* ---------------------------------------------------------------------- */
static int do_write_jpeg(FILE *fp, struct ng_video_buf *buf,
int quality, int gray)
{
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
unsigned int i;
unsigned char *line;
int line_length;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, fp);
cinfo.image_width = buf->fmt.width;
cinfo.image_height = buf->fmt.height;
cinfo.input_components = gray ? 1: 3;
cinfo.in_color_space = gray ? JCS_GRAYSCALE: JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, quality, TRUE);
jpeg_start_compress(&cinfo, TRUE);
line_length = gray ? buf->fmt.width : buf->fmt.width * 3;
for (i = 0, line = buf->data; i < buf->fmt.height;
i++, line += line_length)
jpeg_write_scanlines(&cinfo, &line, 1);
jpeg_finish_compress(&(cinfo));
jpeg_destroy_compress(&(cinfo));
fclose(fp);
return 0;
}
int write_jpeg(char *filename, struct ng_video_buf *buf,
int quality, int gray)
{
FILE *fp;
if (NULL == (fp = fopen(filename,"w"))) {
fprintf(stderr,"grab: can't open %s: %s\n",filename,strerror(errno));
return -1;
}
return do_write_jpeg(fp,buf,quality,gray);
}
#if 0
int write_jpeg_fd(int fd, struct ng_video_buf *buf,
int quality, int gray)
{
FILE *fp;
if (NULL == (fp = fdopen(fd,"w"))) {
fprintf(stderr,"grab: can't fdopen(%d): %s\n",fd,strerror(errno));
return -1;
}
return do_write_jpeg(fp,buf,quality,gray);
}
#endif
int write_ppm(char *filename, struct ng_video_buf *buf)
{
FILE *fp;
if (NULL == (fp = fopen(filename,"w"))) {
fprintf(stderr,"grab: can't open %s: %s\n",filename,strerror(errno));
return -1;
}
fprintf(fp,"P6\n%d %d\n255\n",
buf->fmt.width,buf->fmt.height);
fwrite(buf->data, buf->fmt.height, 3*buf->fmt.width,fp);
fclose(fp);
return 0;
}
int write_pgm(char *filename, struct ng_video_buf *buf)
{
FILE *fp;
if (NULL == (fp = fopen(filename,"w"))) {
fprintf(stderr,"grab: can't open %s: %s\n",filename,strerror(errno));
return -1;
}
fprintf(fp,"P5\n%d %d\n255\n",
buf->fmt.width, buf->fmt.height);
fwrite(buf->data, buf->fmt.height, buf->fmt.width, fp);
fclose(fp);
return 0;
}
/* ---------------------------------------------------------------------- */
/* *.wav I/O stolen from cdda2wav */
/* Copyright (C) by Heiko Eissfeldt */
typedef uint8_t BYTE;
typedef uint16_t WORD;
typedef uint32_t DWORD;
typedef uint32_t FOURCC; /* a four character code */
/* flags for 'wFormatTag' field of WAVEFORMAT */
#define WAVE_FORMAT_PCM 1
/* MMIO macros */
#define mmioFOURCC(ch0, ch1, ch2, ch3) \
((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
#define FOURCC_RIFF mmioFOURCC ('R', 'I', 'F', 'F')
#define FOURCC_LIST mmioFOURCC ('L', 'I', 'S', 'T')
#define FOURCC_WAVE mmioFOURCC ('W', 'A', 'V', 'E')
#define FOURCC_FMT mmioFOURCC ('f', 'm', 't', ' ')
#define FOURCC_DATA mmioFOURCC ('d', 'a', 't', 'a')
typedef struct CHUNKHDR {
FOURCC ckid; /* chunk ID */
DWORD dwSize; /* chunk size */
} CHUNKHDR;
/* simplified Header for standard WAV files */
typedef struct WAVEHDR {
CHUNKHDR chkRiff;
FOURCC fccWave;
CHUNKHDR chkFmt;
WORD wFormatTag; /* format type */
WORD nChannels; /* number of channels (i.e. mono, stereo, etc.) */
DWORD nSamplesPerSec; /* sample rate */
DWORD nAvgBytesPerSec; /* for buffer estimation */
WORD nBlockAlign; /* block size of data */
WORD wBitsPerSample;
CHUNKHDR chkData;
} WAVEHDR;
#if BYTE_ORDER == BIG_ENDIAN
# define cpu_to_le32(x) SWAP4((x))
# define cpu_to_le16(x) SWAP2((x))
# define le32_to_cpu(x) SWAP4((x))
# define le16_to_cpu(x) SWAP2((x))
#else
# define cpu_to_le32(x) (x)
# define cpu_to_le16(x) (x)
# define le32_to_cpu(x) (x)
# define le16_to_cpu(x) (x)
#endif
static void
wav_init_header(WAVEHDR *fileheader, struct ng_audio_fmt *audio)
{
/* stolen from cdda2wav */
int nBitsPerSample = ng_afmt_to_bits[audio->fmtid];
int channels = ng_afmt_to_channels[audio->fmtid];
int rate = audio->rate;
unsigned long nBlockAlign = channels * ((nBitsPerSample + 7) / 8);
unsigned long nAvgBytesPerSec = nBlockAlign * rate;
unsigned long temp = /* data length */ 0 +
sizeof(WAVEHDR) - sizeof(CHUNKHDR);
fileheader->chkRiff.ckid = cpu_to_le32(FOURCC_RIFF);
fileheader->fccWave = cpu_to_le32(FOURCC_WAVE);
fileheader->chkFmt.ckid = cpu_to_le32(FOURCC_FMT);
fileheader->chkFmt.dwSize = cpu_to_le32(16);
fileheader->wFormatTag = cpu_to_le16(WAVE_FORMAT_PCM);
fileheader->nChannels = cpu_to_le16(channels);
fileheader->nSamplesPerSec = cpu_to_le32(rate);
fileheader->nAvgBytesPerSec = cpu_to_le32(nAvgBytesPerSec);
fileheader->nBlockAlign = cpu_to_le16(nBlockAlign);
fileheader->wBitsPerSample = cpu_to_le16(nBitsPerSample);
fileheader->chkData.ckid = cpu_to_le32(FOURCC_DATA);
fileheader->chkRiff.dwSize = cpu_to_le32(temp);
fileheader->chkData.dwSize = cpu_to_le32(0 /* data length */);
}
static void
wav_start_write(int fd, WAVEHDR *fileheader, struct ng_audio_fmt *audio)
{
wav_init_header(fileheader,audio);
write(fd,fileheader,sizeof(WAVEHDR));
}
static void
wav_stop_write(int fd, WAVEHDR *fileheader, int wav_size)
{
unsigned long temp = wav_size + sizeof(WAVEHDR) - sizeof(CHUNKHDR);
fileheader->chkRiff.dwSize = cpu_to_le32(temp);
fileheader->chkData.dwSize = cpu_to_le32(wav_size);
lseek(fd,0,SEEK_SET);
write(fd,fileheader,sizeof(WAVEHDR));
}
/* ---------------------------------------------------------------------- */
struct files_handle {
/* file name */
char file[MAXPATHLEN];
/* format */
struct ng_video_fmt video;
struct ng_audio_fmt audio;
/* *.wav file */
int wav_fd;
WAVEHDR wav_header;
int wav_size;
/* misc */
int gotcha;
};
static void*
files_open(char *filesname, char *audioname,
struct ng_video_fmt *video, const void *priv_video, int fps,
struct ng_audio_fmt *audio, const void *priv_audio)
{
struct files_handle *h;
if (video->fmtid != VIDEO_NONE && NULL == filesname)
return NULL;
if (NULL == (h = malloc(sizeof(*h))))
return NULL;
/* init */
memset(h,0,sizeof(*h));
h->video = *video;
h->audio = *audio;
if (filesname)
strcpy(h->file,filesname);
if (h->audio.fmtid != AUDIO_NONE) {
h->wav_fd = open(audioname, O_CREAT | O_RDWR | O_TRUNC, 0666);
if (-1 == h->wav_fd) {
fprintf(stderr,"open %s: %s\n",audioname,strerror(errno));
free(h);
return NULL;
}
wav_start_write(h->wav_fd,&h->wav_header,&h->audio);
}
return h;
}
static int
files_video(void *handle, struct ng_video_buf *buf)
{
struct files_handle *h = handle;
int rc = -1;
FILE *fp;
if (h->gotcha) {
fprintf(stderr,"Oops: can't count up file names any more\n");
return -1;
}
switch (h->video.fmtid) {
case VIDEO_RGB24:
rc = write_ppm(h->file, buf);
break;
case VIDEO_GRAY:
rc = write_pgm(h->file, buf);
break;
case VIDEO_JPEG:
if (NULL == (fp = fopen(h->file,"w"))) {
fprintf(stderr,"grab: can't open %s: %s\n",h->file,strerror(errno));
rc = -1;
} else {
fwrite(buf->data,buf->size,1,fp);
fclose(fp);
rc = 0;
}
}
if (1 != patch_up(h->file))
h->gotcha = 1;
return rc;
}
static int
files_audio(void *handle, struct ng_audio_buf *buf)
{
struct files_handle *h = handle;
if (buf->size != write(h->wav_fd,buf->data,buf->size))
return -1;
h->wav_size += buf->size;
return 0;
}
static int
files_close(void *handle)
{
struct files_handle *h = handle;
if (h->audio.fmtid != AUDIO_NONE) {
wav_stop_write(h->wav_fd,&h->wav_header,h->wav_size);
close(h->wav_fd);
}
free(h);
return 0;
}
/* ---------------------------------------------------------------------- */
struct raw_priv {
int yuv4mpeg;
};
struct raw_handle {
/* format */
struct ng_video_fmt video;
struct ng_audio_fmt audio;
const struct raw_priv *vpriv;
/* video file*/
int fd;
/* *.wav file */
int wav_fd;
WAVEHDR wav_header;
int wav_size;
};
static void*
raw_open(char *videoname, char *audioname,
struct ng_video_fmt *video, const void *priv_video, int fps,
struct ng_audio_fmt *audio, const void *priv_audio)
{
struct raw_handle *h;
int frame_rate_code = 0;
int frame_rate_mul = fps;
int frame_rate_div = 1000;
if (NULL == (h = malloc(sizeof(*h))))
return NULL;
/* init */
memset(h,0,sizeof(*h));
h->video = *video;
h->audio = *audio;
h->vpriv = priv_video;
/* audio */
if (h->audio.fmtid != AUDIO_NONE) {
h->wav_fd = open(audioname, O_CREAT | O_RDWR | O_TRUNC, 0666);
if (-1 == h->wav_fd) {
fprintf(stderr,"open %s: %s\n",audioname,strerror(errno));
free(h);
return NULL;
}
wav_start_write(h->wav_fd,&h->wav_header,&h->audio);
}
/* video */
if (h->video.fmtid != VIDEO_NONE) {
if (h->vpriv && h->vpriv->yuv4mpeg) {
switch (fps) {
case 23976: frame_rate_code = 1; /* 24000 / 1001 */
frame_rate_mul = 24000;
frame_rate_div = 1001;
break;
case 29970: frame_rate_code = 4; /* 30000 / 1001 */
frame_rate_mul = 30000;
frame_rate_div = 1001;
break;
case 59940: frame_rate_code = 7; /* 60000 / 1001 */
frame_rate_mul = 60000;
frame_rate_div = 1001;
break;
case 24000: frame_rate_code = 2; break;
case 25000: frame_rate_code = 3; break;
case 30000: frame_rate_code = 5; break;
case 50000: frame_rate_code = 6; break;
case 60000: frame_rate_code = 8; break;
default:
fprintf(stderr,"illegal frame rate\n");
free(h);
return NULL;
}
}
if (NULL != videoname) {
h->fd = open(videoname, O_CREAT | O_RDWR | O_TRUNC, 0666);
if (-1 == h->fd) {
fprintf(stderr,"open %s: %s\n",videoname,strerror(errno));
if (h->wav_fd)
close(h->wav_fd);
free(h);
return NULL;
}
} else {
h->fd = 1; /* use stdout */
}
if (h->vpriv && h->vpriv->yuv4mpeg) {
char header[64];
switch (h->vpriv->yuv4mpeg) {
case 1:
sprintf(header, "YUV4MPEG %d %d %d\n",
h->video.width, h->video.height,frame_rate_code);
break;
case 2:
sprintf(header, "YUV4MPEG2 W%d H%d F%d:%d\n",
h->video.width, h->video.height,
frame_rate_mul, frame_rate_div);
break;
}
write(h->fd, header, strlen(header));
}
}
return h;
}
static int
raw_video(void *handle, struct ng_video_buf *buf)
{
struct raw_handle *h = handle;
if (h->vpriv && h->vpriv->yuv4mpeg)
switch (h->vpriv->yuv4mpeg) {
case 1:
if (6 != write(h->fd, "FRAME\n", 6))
return -1;
break;
case 2:
if (7 != write(h->fd, "FRAME \n", 7))
return -1;
break;
}
if (buf->size != write(h->fd,buf->data,buf->size))
return -1;
return 0;
}
static int
raw_audio(void *handle, struct ng_audio_buf *buf)
{
struct raw_handle *h = handle;
if (buf->size != write(h->wav_fd,buf->data,buf->size))
return -1;
h->wav_size += buf->size;
return 0;
}
static int
raw_close(void *handle)
{
struct raw_handle *h = handle;
if (h->audio.fmtid != AUDIO_NONE) {
wav_stop_write(h->wav_fd,&h->wav_header,h->wav_size);
close(h->wav_fd);
}
if (h->video.fmtid != VIDEO_NONE && 1 != h->fd)
close(h->fd);
free(h);
return 0;
}
/* ----------------------------------------------------------------------- */
/* data structures describing our capabilities */
static const struct ng_format_list files_vformats[] = {
{
name: "ppm",
ext: "ppm",
fmtid: VIDEO_RGB24,
},{
name: "pgm",
ext: "pgm",
fmtid: VIDEO_GRAY,
},{
name: "jpeg",
ext: "jpeg",
fmtid: VIDEO_JPEG,
},{
/* EOF */
}
};
static struct raw_priv yuv4mpeg = {
yuv4mpeg: 1
};
static struct raw_priv yuv4mpeg2 = {
yuv4mpeg: 2
};
static const struct ng_format_list raw_vformats[] = {
{
name: "rgb",
ext: "raw",
fmtid: VIDEO_RGB24,
},{
name: "gray",
ext: "raw",
fmtid: VIDEO_GRAY,
},{
name: "422",
ext: "raw",
fmtid: VIDEO_YUYV,
},{
name: "422p",
ext: "raw",
fmtid: VIDEO_YUV422P,
},{
name: "4mpeg",
desc: "yuv4mpeg (mpeg2enc >= 1.6)",
ext: "yuv",
fmtid: VIDEO_YUV420P,
priv: &yuv4mpeg2,
},{
name: "4mpeg-o",
desc: "yuv4mpeg (old mpeg2enc)",
ext: "yuv",
fmtid: VIDEO_YUV420P,
priv: &yuv4mpeg,
},{
/* EOF */
}
};
static const struct ng_format_list wav_aformats[] = {
{
name: "mono8",
ext: "wav",
fmtid: AUDIO_U8_MONO,
},{
name: "mono16",
ext: "wav",
fmtid: AUDIO_S16_LE_MONO,
},{
name: "stereo",
ext: "wav",
fmtid: AUDIO_S16_LE_STEREO,
},{
/* EOF */
}
};
struct ng_writer files_writer = {
name: "files",
desc: "multiple image files",
video: files_vformats,
audio: wav_aformats,
wr_open: files_open,
wr_video: files_video,
wr_audio: files_audio,
wr_close: files_close,
};
struct ng_writer raw_writer = {
name: "raw",
desc: "single file, raw video data",
video: raw_vformats,
audio: wav_aformats,
wr_open: raw_open,
wr_video: raw_video,
wr_audio: raw_audio,
wr_close: raw_close,
};
/* ------------------------------------------------------------------- */
static void __init writefile_init(void)
{
ng_writer_register(NG_PLUGIN_MAGIC,__FILE__,&files_writer);
ng_writer_register(NG_PLUGIN_MAGIC,__FILE__,&raw_writer);
}
amsn-0.98.9/utils/linux/capture/libng/devices.h 0000644 0001750 0001750 00000000372 10246003435 021220 0 ustar billiob billiob
struct ng_device_config {
char *video;
char *radio;
char *vbi;
char *dsp;
char *mixer;
char *video_scan[32];
char *vbi_scan[32];
char *mixer_scan[32];
char *dsp_scan[32];
};
extern struct ng_device_config ng_dev;
amsn-0.98.9/utils/linux/capture/libng/color_common.c 0000644 0001750 0001750 00000002475 10246003435 022265 0 ustar billiob billiob #define NG_PRIVATE
#include "config.h"
#include
#include
#include
#include
#include
#include
#include "grab-ng.h"
/* ------------------------------------------------------------------- */
void*
ng_packed_init(struct ng_video_fmt *out, void *priv)
{
return priv;
}
void
ng_packed_frame(void *handle, struct ng_video_buf *out,
struct ng_video_buf *in)
{
int (*func)(unsigned char *dest, unsigned char *src, int p) = handle;
unsigned char *sp,*dp;
unsigned int i,sw,dw;
dw = (out->fmt.width * ng_vfmt_to_depth[out->fmt.fmtid]) >> 3;
sw = (in->fmt.width * ng_vfmt_to_depth[in->fmt.fmtid]) >> 3;
if (in->fmt.bytesperline == sw && out->fmt.bytesperline == dw) {
/* can convert in one go */
func(out->data, in->data, in->fmt.width * in->fmt.height);
} else {
/* convert line by line */
dp = out->data;
sp = in->data;
for (i = 0; i < in->fmt.height; i++) {
func(dp,sp,in->fmt.width);
dp += out->fmt.bytesperline;
sp += in->fmt.bytesperline;
}
}
out->info = in->info;
}
/* ------------------------------------------------------------------- */
void*
ng_conv_nop_init(struct ng_video_fmt *out, void *priv)
{
/* nothing */
return NULL;
}
void
ng_conv_nop_fini(void *handle)
{
/* nothing */
}
amsn-0.98.9/utils/linux/capture/libng/OVERVIEW 0000644 0001750 0001750 00000015663 10246003435 020627 0 ustar billiob billiob
libng overview
==============
some general notes
------------------
The text below is not a complete reference (yet?), it just tries to
give a overview and explain the design of the library. Have a look at
grab-ng.h, this is the header file where everything is defined.
If you are looking for some simple sample code check out
console/webcam.c. More complex usages of libng can be found everythere
in the xawtv source code: In common/capture.c for example, where most of
the threaded movie recording code for xawtv+streamer is.
There are two types of structs: Those which carrying some data (like
ng_video_fmt or ng_video_buf) and those which define a interface (like
ng_driver).
The interfaces all have a initialization function which returns a void
pointer as handle. All other interface functions expect getting that
handle passed in. The complete state information is kept there.
Global variables are a no-no, the interfaces need to be reentrant (so
you can use multiple instances of them at the same time).
video buffers (struct ng_video_buf)
-----------------------------------
One video buffer holds one frame. There are some rules for video
frames:
(1) Multiple instances (threads for example) may hold a pointer to
the buffer. The refcount variable is used to keep track of the
number of references. If you hand out a pointer to the buffer to
someone else *and* keep a pointer to the buffer yourself to use
it later refcount must be increased by one. If you don't need
the buffer any more, just free it with ng_release_video_buf().
That function will take care about count down the reference
counter and freeing the buffer if refcount is zero.
(2) The above implies you should not write to ng_video_buf->data
because another thread might use the image data while you are
modifying it. Allocate a new buffer and put the new data in there
instead if you want process the image data. You can use
ng_malloc_video_buf() to get a buffer. Don't forget to copy the
frame meta data to the new buffer (ng_video_buf->info).
Within the current implementation two types of buffers exist: Those
malloc()ed ones which are returned by ng_malloc_video_buf() and
buffers provided by the hardware drivers, where ng_video_buf->data is
a pointer directly to the mmap()ed buffer(s).
video capture / overlay drivers (struct ng_vid_driver)
------------------------------------------------------
This is a interface to a capture driver. Right now three different
ones exist:
(1) video4linux (current linux API, see plugins/drv1-v4l.c).
(2) video4linux two (work in progress - new API for linux, see
plugins/drv0-v4l2.c).
(3) bktr (bt848/878 driver for FreeBSD + OpenBSD, see
plugins/drv0-bsd.c).
xawtv uses struct ng_vid_driver for Xvideo support too (see x11/xv.c).
open()/close() should be clear. The capabilities() function returns a
bitfield which specifies the capabilities of the driver. The *attr*
functions can be used to control several (hardware) settings (see
below for more on attributes).
To for a overlay use setupfb() and overlay(). For linux setupfb()
just verifies the driver parameters, it expects the setup is done with
a extern utility like v4l-conf (because one needs root priviliges for
that).
To capture frames you have to configure the format with setformat()
first. Be aware that the image size might have changed on return,
depending on the capabilities of the underlying hardware. For video
recording use startvideo(), multiple nextframe() calls and
stopvideo(), for single frames use getimage().
output drivers (struct ng_writer)
---------------------------------
This is a interface for movie writer code. Four different ones exist:
(1) Microsoft's AVI
(2) Apple Quicktime (using the libquicktime library).
(3) raw, uncompressed data (one big file).
(4) one image file/frame (jpeg or ppm).
The first two write audio and video data into the same stream, the
last two can write audio data to a separate wav file.
The audio/video args hold a list of supported formats. Usage should
be pretty straight forward: wr_open(), write data with wr_video() +
wr_audio(), then wr_close(). You can write both audio-only and
video-only streams if you want.
attributes (struct ng_attribute)
--------------------------------
Attributes can be used to control properties attributes. Right now
they are only used for video drivers (struct ng_driver), but that
might change in the future. There are a number of standard attributes
defined (tv norm, volume and the like), but it is also possible to
specify non-standard attributes.
struct ng_attribute also has functions to list/read/modify the given
attribute. A number of helper functions to search a attribute list by
id / name and for multiple choice attribute handling are available
too.
audio recording + mixer control
-------------------------------
There are only some structs for audio formats and audio data chunks.
The movie writers use these. There are also interfaces for sound
recording and mixer control (struct ng_dsp_driver + struct
ng_mix_driver) and a implementation for the OSS API (in
plugins/snd-oss.c).
I'm not that happy with the current design of the mixer stuff, it
likely will change in the future.
color space conversion and compression
--------------------------------------
struct ng_video_conv describes a converter. There are plenty built-in
into libng, but it is also possible to add more using plugins. These
converters handle (a) color space conversion (yuv -> rgb), (b) convert
rgb with different color depths, (c) handle compression.
image filtering
---------------
I've recently added a interfaces for image filtering (i.e. on-the-fly
image processing). struct ng_filter is it, in plugins/flt-*.c is some
sample code. There is no complex stuff yet.
For now filters are limited: They work on a frame-by-frame base,
i.e. for one frame which gets passed in one is expected to come out.
Read: you can't (yet?) merge multiple frames into one. The input and
output format is expected to be the same.
Filters should be able to handle as much formats as possible, neither
xawtv nor libng attempt to do any conversions (i.e. do yuv->rgb ->
filter -> rgb->yuv for you because the filter works in RGB space
only). ng_filter->fmts lists the supported formats of a given filter,
and if the required format isn't supported by some filter it is simply
skipped and no filtering takes place.
Most frequently formats are:
* RGB (various depts), to display images on the X11 screen, for ppm
capture, ...
* packed pixel yuv (If xawtv/motv blits images using the Xvideo
extension instead of normal X11 ximages).
* planar yuv (for recording compressed video, libjpeg can be feeded
directly with planar yuv to save some CPU cycles for rgb->yuv color
space conversion).
misc
----
There are some helper functions for various stuff, see grab-ng.[ch].
There are also some arrays with text descriptions and other
informations about audio/video formats: ng_[va]fmt_to_*.
amsn-0.98.9/utils/linux/capture/libng/color_packed.c 0000644 0001750 0001750 00000013041 11755523031 022220 0 ustar billiob billiob /*
* colorspace conversion functions
* -- packed pixel formats (rgb/gray right now)
*
* (c) 1998-2001 Gerd Knorr
*
*/
#define NG_PRIVATE
#include "config.h"
#include
#include
#include
#include
#include
#include
#include "grab-ng.h"
/* ------------------------------------------------------------------- */
/* RGB conversions */
static void
redblue_swap(unsigned char *dest, unsigned char *src, int p)
{
register unsigned char *s = src;
register unsigned char *d = dest;
while (p--) {
*(d++) = s[2];
*(d++) = s[1];
*(d++) = s[0];
s += 3;
}
}
static void
bgr24_to_bgr32(unsigned char* restrict dest, unsigned char* restrict src,
int p)
{
register unsigned char* restrict s = src;
register unsigned char* restrict d = dest;
while (p--) {
*(d++) = *(s++);
*(d++) = *(s++);
*(d++) = *(s++);
*(d++) = 0;
}
}
static void
bgr24_to_rgb32(unsigned char* restrict dest, unsigned char* restrict src,
int p)
{
register unsigned char* restrict s = src;
register unsigned char* restrict d = dest;
while (p--) {
*(d++) = 0;
*(d++) = s[2];
*(d++) = s[1];
*(d++) = s[0];
s +=3;
}
}
static void
rgb32_to_rgb24(unsigned char* restrict dest, unsigned char* restrict src,
int p)
{
register unsigned char* restrict s = src;
register unsigned char* restrict d = dest;
while (p--) {
s++;
*(d++) = *(s++);
*(d++) = *(s++);
*(d++) = *(s++);
}
}
static void
rgb32_to_bgr24(unsigned char* restrict dest, unsigned char* restrict src,
int p)
{
register unsigned char* restrict s = src;
register unsigned char* restrict d = dest;
while (p--) {
s++;
d[2] = *(s++);
d[1] = *(s++);
d[0] = *(s++);
d += 3;
}
}
/* 15+16 bpp LE <=> BE */
static void
byteswap_short(unsigned char* restrict dest, unsigned char* restrict src,
int p)
{
register unsigned char* restrict s = src;
register unsigned char* restrict d = dest;
while (--p) {
*(d++) = s[1];
*(d++) = s[0];
s += 2;
}
}
/* ------------------------------------------------------------------- */
/* color => grayscale */
static void
rgb15_native_gray(unsigned char* restrict dest, unsigned char *s,
int p)
{
int r,g,b;
unsigned short* restrict src = (unsigned short*)s;
while (p--) {
r = (src[0] & 0x7c00) >> 10;
g = (src[0] & 0x03e0) >> 5;
b = src[0] & 0x001f;
*(dest++) = ((3*r + 6*g + b)/10) << 3;
src++;
}
}
#if BYTE_ORDER == LITTLE_ENDIAN
static void
rgb15_be_gray(unsigned char* restrict dest, unsigned char* restrict src,
int p)
{
int r,g,b;
register unsigned char* restrict d = dest;
while (p--) {
r = (src[0] & 0x7c) >> 2;
g = (src[0] & 0x03) << 3 | (src[1] & 0xe0) >> 5;
b = src[1] & 0x1f;
*(d++) = ((3*r + 6*g + b)/10) << 3;
src += 2;
}
}
#endif
#if BYTE_ORDER == BIG_ENDIAN
static void
rgb15_le_gray(unsigned char* restrict dest, unsigned char* restrict src, int p)
{
int r,g,b;
register unsigned char* restrict d = dest;
while (p--) {
r = (src[1] & 0x7c) >> 2;
g = (src[1] & 0x03) << 3 | (src[0] & 0xe0) >> 5;
b = src[0] & 0x1f;
*(d++) = ((3*r + 6*g + b)/10) << 3;
src += 2;
}
}
#endif
/* ------------------------------------------------------------------- */
static struct ng_video_conv conv_list[] = {
{
/* ----------------------------------- write GRAY -- */
#if BYTE_ORDER == BIG_ENDIAN
NG_GENERIC_PACKED,
.fmtid_in = VIDEO_RGB15_BE,
.fmtid_out = VIDEO_GRAY,
.priv = rgb15_native_gray,
}, {
NG_GENERIC_PACKED,
.fmtid_in = VIDEO_RGB15_LE,
.fmtid_out = VIDEO_GRAY,
.priv = rgb15_le_gray,
}, {
#else
NG_GENERIC_PACKED,
.fmtid_in = VIDEO_RGB15_BE,
.fmtid_out = VIDEO_GRAY,
.priv = rgb15_be_gray,
}, {
NG_GENERIC_PACKED,
.fmtid_in = VIDEO_RGB15_LE,
.fmtid_out = VIDEO_GRAY,
.priv = rgb15_native_gray,
}, {
#endif
/* ----------------------------------- write RGB15 -- */
NG_GENERIC_PACKED,
.fmtid_in = VIDEO_RGB15_LE,
.fmtid_out = VIDEO_RGB15_BE,
.priv = byteswap_short,
}, {
NG_GENERIC_PACKED,
.fmtid_in = VIDEO_RGB15_BE,
.fmtid_out = VIDEO_RGB15_LE,
.priv = byteswap_short,
}, {
/* ----------------------------------- write RGB16 -- */
NG_GENERIC_PACKED,
.fmtid_in = VIDEO_RGB16_LE,
.fmtid_out = VIDEO_RGB16_BE,
.priv = byteswap_short,
}, {
NG_GENERIC_PACKED,
.fmtid_in = VIDEO_RGB16_BE,
.fmtid_out = VIDEO_RGB16_LE,
.priv = byteswap_short,
}, {
/* ----------------------------------- write RGB24 -- */
NG_GENERIC_PACKED,
.fmtid_in = VIDEO_BGR24,
.fmtid_out = VIDEO_RGB24,
.priv = redblue_swap,
}, {
NG_GENERIC_PACKED,
.fmtid_in = VIDEO_RGB24,
.fmtid_out = VIDEO_BGR24,
.priv = redblue_swap,
}, {
NG_GENERIC_PACKED,
.fmtid_in = VIDEO_RGB32,
.fmtid_out = VIDEO_RGB24,
.priv = rgb32_to_rgb24,
}, {
NG_GENERIC_PACKED,
.fmtid_in = VIDEO_RGB32,
.fmtid_out = VIDEO_BGR24,
.priv = rgb32_to_bgr24,
}, {
/* ----------------------------------- write RGB32 -- */
NG_GENERIC_PACKED,
.fmtid_in = VIDEO_BGR24,
.fmtid_out = VIDEO_BGR32,
.priv = bgr24_to_bgr32,
}, {
NG_GENERIC_PACKED,
.fmtid_in = VIDEO_BGR24,
.fmtid_out = VIDEO_RGB32,
.priv = bgr24_to_rgb32,
}
};
static const int nconv = sizeof(conv_list)/sizeof(struct ng_video_conv);
/* ------------------------------------------------------------------- */
void packed_init (void)
{
ng_conv_register(NG_PLUGIN_MAGIC,__FILE__,conv_list,nconv);
}
amsn-0.98.9/utils/linux/capture/libng/parse-dvb.c 0000644 0001750 0001750 00000020213 10246003435 021450 0 ustar billiob billiob /*
* parse various TV stuff out of DVB TS streams.
*
*/
#include
#include
#include
#include
#include
#include
#include
#include "grab-ng.h"
#include "parse-mpeg.h"
/* ----------------------------------------------------------------------- */
static unsigned int unbcd(unsigned int bcd)
{
unsigned int factor = 1;
unsigned int ret = 0;
unsigned int digit;
while (bcd) {
digit = bcd & 0x0f;
ret += digit * factor;
bcd /= 16;
factor *= 10;
}
return ret;
}
static int iconv_string(char *from, char *to,
char *src, size_t len,
char *dst, size_t max)
{
size_t ilen = (-1 != len) ? len : strlen(src);
size_t olen = max-1;
iconv_t ic;
ic = iconv_open(to,from);
if (NULL == ic)
return 0;
while (ilen > 0) {
if (-1 == iconv(ic,&src,&ilen,&dst,&olen)) {
/* skip + quote broken byte unless we are out of space */
if (E2BIG == errno)
break;
if (olen < 4)
break;
sprintf(dst,"\\x%02x",(int)(unsigned char)src[0]);
src += 1;
dst += 4;
ilen -= 1;
olen -= 4;
}
}
dst[0] = 0;
iconv_close(ic);
return max-1 - olen;
}
static int handle_control_8(unsigned char *src, int slen,
unsigned char *dest, int dlen)
{
int s,d;
for (s = 0, d = 0; s < slen && d < dlen;) {
if (src[s] >= 0x80 && src[s] <= 0x9f) {
switch (src[s]) {
case 0x86: /* */
case 0x87: /* */
s++;
break;
case 0x1a: /* ^Z */
dest[d++] = ' ';
s++;
break;
case 0x8a: /*
*/
dest[d++] = '\n';
s++;
break;
default:
s++;
}
} else {
dest[d++] = src[s++];
}
}
return d;
}
void mpeg_parse_psi_string(unsigned char *src, int slen,
unsigned char *dest, int dlen)
{
unsigned char *tmp;
int tlen,ch = 0;
if (src[0] < 0x20) {
ch = src[0];
src++;
slen--;
}
memset(dest,0,dlen);
if (ch < 0x10) {
/* 8bit charset */
tmp = malloc(slen);
tlen = handle_control_8(src, slen, tmp, slen);
iconv_string(psi_charset[ch], "UTF-8", tmp, tlen, dest, dlen);
free(tmp);
} else {
/* 16bit charset */
iconv_string(psi_charset[ch], "UTF-8", src, slen, dest, dlen);
}
}
static void parse_nit_desc_1(unsigned char *desc, int dlen,
char *dest, int max)
{
int i,t,l;
for (i = 0; i < dlen; i += desc[i+1] +2) {
t = desc[i];
l = desc[i+1];
switch (t) {
case 0x40:
mpeg_parse_psi_string(desc+i+2,l,dest,max);
break;
}
}
}
static void parse_nit_desc_2(unsigned char *desc, int dlen,
struct psi_stream *stream)
{
static char *bw[4] = {
[ 0 ] = "8",
[ 1 ] = "7",
[ 2 ] = "6",
};
static char *co_t[4] = {
[ 0 ] = "0",
[ 1 ] = "16",
[ 2 ] = "64",
};
static char *co_c[16] = {
[ 0 ] = "0",
[ 1 ] = "16",
[ 2 ] = "32",
[ 3 ] = "64",
[ 4 ] = "128",
[ 5 ] = "256",
};
static char *hi[4] = {
[ 0 ] = "0",
[ 1 ] = "1",
[ 2 ] = "2",
[ 3 ] = "4",
};
static char *ra_t[8] = {
[ 0 ] = "12",
[ 1 ] = "23",
[ 2 ] = "34",
[ 3 ] = "56",
[ 4 ] = "78",
};
static char *ra_sc[8] = {
[ 1 ] = "12",
[ 2 ] = "23",
[ 3 ] = "34",
[ 4 ] = "56",
[ 5 ] = "78",
};
static char *gu[4] = {
[ 0 ] = "32",
[ 1 ] = "16",
[ 2 ] = "8",
[ 3 ] = "4",
};
static char *tr[2] = {
[ 0 ] = "2",
[ 1 ] = "8",
};
static char *po[4] = {
[ 0 ] = "H",
[ 1 ] = "V",
[ 2 ] = "L", // circular left
[ 3 ] = "R", // circular right
};
unsigned int freq,rate,fec;
int i,t,l;
for (i = 0; i < dlen; i += desc[i+1] +2) {
t = desc[i];
l = desc[i+1];
switch (t) {
case 0x43: /* dvb-s */
freq = mpeg_getbits(desc+i+2, 0, 32);
rate = mpeg_getbits(desc+i+2, 56, 28);
fec = mpeg_getbits(desc+i+2, 85, 3);
stream->frequency = unbcd(freq) * 10;
stream->symbol_rate = unbcd(rate*16) * 10;
stream->fec_inner = ra_sc[fec];
stream->polarization = po[ mpeg_getbits(desc+i+2, 49, 2) ];
break;
case 0x44: /* dvb-c */
freq = mpeg_getbits(desc+i+2, 0, 32);
rate = mpeg_getbits(desc+i+2, 56, 28);
fec = mpeg_getbits(desc+i+2, 85, 3);
stream->frequency = unbcd(freq) * 100;
stream->symbol_rate = unbcd(rate*16) * 10;
stream->fec_inner = ra_sc[fec];
stream->constellation = co_c[ mpeg_getbits(desc+i+2, 52, 4) ];
break;
case 0x5a: /* dvb-t */
stream->frequency = mpeg_getbits(desc+i+2, 0, 32) * 10;
stream->bandwidth = bw[ mpeg_getbits(desc+i+2, 33, 2) ];
stream->constellation = co_t[ mpeg_getbits(desc+i+2, 40, 2) ];
stream->hierarchy = hi[ mpeg_getbits(desc+i+2, 43, 2) ];
stream->code_rate_hp = ra_t[ mpeg_getbits(desc+i+2, 45, 3) ];
stream->code_rate_lp = ra_t[ mpeg_getbits(desc+i+2, 48, 3) ];
stream->guard = gu[ mpeg_getbits(desc+i+2, 51, 2) ];
stream->transmission = tr[ mpeg_getbits(desc+i+2, 54, 1) ];
break;
}
}
return;
}
static void parse_sdt_desc(unsigned char *desc, int dlen,
struct psi_program *pr)
{
int i,t,l;
char *name,*net;
for (i = 0; i < dlen; i += desc[i+1] +2) {
t = desc[i];
l = desc[i+1];
switch (t) {
case 0x48:
pr->type = desc[i+2];
pr->updated = 1;
net = desc + i+3;
name = net + net[0] + 1;
mpeg_parse_psi_string(net+1, net[0], pr->net, sizeof(pr->net));
mpeg_parse_psi_string(name+1, name[0], pr->name, sizeof(pr->name));
break;
}
}
}
/* ----------------------------------------------------------------------- */
int mpeg_parse_psi_sdt(struct psi_info *info, unsigned char *data, int verbose)
{
static const char *running[] = {
[ 0 ] = "undefined",
[ 1 ] = "not running",
[ 2 ] = "starts soon",
[ 3 ] = "pausing",
[ 4 ] = "running",
[ 5 ... 8 ] = "reserved",
};
struct psi_program *pr;
int tsid,pnr,version,current;
int j,len,dlen,run,ca;
len = mpeg_getbits(data,12,12) + 3 - 4;
tsid = mpeg_getbits(data,24,16);
version = mpeg_getbits(data,42,5);
current = mpeg_getbits(data,47,1);
if (!current)
return len+4;
if (info->tsid == tsid && info->sdt_version == version)
return len+4;
info->sdt_version = version;
if (verbose)
fprintf(stderr,
"ts [sdt]: tsid %d ver %2d [%d/%d]\n",
tsid, version,
mpeg_getbits(data,48, 8),
mpeg_getbits(data,56, 8));
j = 88;
while (j < len*8) {
pnr = mpeg_getbits(data,j,16);
run = mpeg_getbits(data,j+24,3);
ca = mpeg_getbits(data,j+27,1);
dlen = mpeg_getbits(data,j+28,12);
if (verbose > 1) {
fprintf(stderr," pnr %3d ca %d %s #",
pnr, ca, running[run]);
mpeg_dump_desc(data+j/8+5,dlen);
fprintf(stderr,"\n");
}
pr = psi_program_get(info, tsid, pnr, 1);
parse_sdt_desc(data+j/8+5,dlen,pr);
pr->running = run;
pr->ca = ca;
j += 40 + dlen*8;
}
if (verbose > 1)
fprintf(stderr,"\n");
return len+4;
}
int mpeg_parse_psi_nit(struct psi_info *info, unsigned char *data, int verbose)
{
struct psi_stream *stream;
char network[PSI_STR_MAX] = "";
int id,version,current,len;
int j,dlen,tsid;
len = mpeg_getbits(data,12,12) + 3 - 4;
id = mpeg_getbits(data,24,16);
version = mpeg_getbits(data,42,5);
current = mpeg_getbits(data,47,1);
if (!current)
return len+4;
if (0 /* info->id == id */ && info->nit_version == version)
return len+4;
info->nit_version = version;
j = 80;
dlen = mpeg_getbits(data,68,12);
parse_nit_desc_1(data + j/8, dlen, network, sizeof(network));
if (verbose) {
fprintf(stderr,
"ts [nit]: id %3d ver %2d [%d/%d] #",
id, version,
mpeg_getbits(data,48, 8),
mpeg_getbits(data,56, 8));
mpeg_dump_desc(data + j/8, dlen);
fprintf(stderr,"\n");
}
j += 16 + 8*dlen;
while (j < len*8) {
tsid = mpeg_getbits(data,j,16);
dlen = mpeg_getbits(data,j+36,12);
j += 48;
stream = psi_stream_get(info, tsid, 1);
stream->updated = 1;
if (network)
strcpy(stream->net, network);
parse_nit_desc_2(data + j/8, dlen, stream);
if (verbose > 1) {
fprintf(stderr," tsid %3d #", tsid);
mpeg_dump_desc(data + j/8, dlen);
fprintf(stderr,"\n");
}
j += 8*dlen;
}
if (verbose > 1)
fprintf(stderr,"\n");
return len+4;
}
amsn-0.98.9/utils/linux/capture/libng/devices.c 0000644 0001750 0001750 00000004626 10733772533 021236 0 ustar billiob billiob /*
* default devices names
*/
#include
#include
#include
#include
#include
#include
#include "devices.h"
#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
struct ng_device_config ng_dev = {
video: "/dev/bktr0",
radio: NULL,
vbi: "/dev/vbi0",
dsp: "/dev/dsp",
mixer: "/dev/mixer",
video_scan: {
"/dev/bktr0",
"/dev/bktr1",
"/dev/cxm0",
"/dev/cxm1",
NULL
},
vbi_scan: {
"/dev/vbi0",
"/dev/vbi1",
NULL
},
mixer_scan: {
"/dev/mixer",
"/dev/mixer1",
"/dev/mixer2",
"/dev/mixer3",
NULL
},
dsp_scan: {
"/dev/dsp",
"/dev/dsp1",
"/dev/dsp2",
"/dev/dsp3",
NULL
},
};
#endif
#if defined(__linux__) || defined(__sun)
struct ng_device_config ng_dev = {
video: "/dev/video0", /* thank you redhat breaking
* /dev/video as symbolic link to the
* default video device ... */
radio: "/dev/radio",
vbi: "/dev/vbi",
dsp: "/dev/dsp",
mixer: "/dev/mixer",
video_scan: {
"/dev/video0",
"/dev/video1",
"/dev/video2",
"/dev/video3",
NULL
},
vbi_scan: {
"/dev/vbi0",
"/dev/vbi1",
"/dev/vbi2",
"/dev/vbi3",
NULL
},
mixer_scan: {
"/dev/mixer",
"/dev/mixer1",
"/dev/mixer2",
"/dev/mixer3",
NULL
},
dsp_scan: {
"/dev/dsp",
"/dev/adsp",
"/dev/dsp1",
"/dev/adsp1",
"/dev/dsp2",
"/dev/adsp2",
"/dev/dsp3",
"/dev/adsp3",
NULL
},
};
struct ng_device_config ng_dev_devfs = {
video: "/dev/v4l/video0",
radio: "/dev/v4l/radio0",
vbi: "/dev/v4l/vbi0",
dsp: "/dev/sound/dsp",
mixer: "/dev/sound/mixer",
video_scan: {
"/dev/v4l/video0",
"/dev/v4l/video1",
"/dev/v4l/video2",
"/dev/v4l/video3",
NULL
},
vbi_scan: {
"/dev/v4l/vbi0",
"/dev/v4l/vbi1",
"/dev/v4l/vbi2",
"/dev/v4l/vbi3",
NULL
},
mixer_scan: {
"/dev/sound/mixer",
"/dev/sound/mixer1",
"/dev/sound/mixer2",
"/dev/sound/mixer3",
NULL
},
dsp_scan: {
"/dev/sound/dsp",
"/dev/sound/adsp",
"/dev/sound/dsp1",
"/dev/sound/adsp1",
"/dev/sound/dsp2",
"/dev/sound/adsp2",
"/dev/sound/dsp3",
"/dev/sound/adsp3",
NULL
},
};
#endif
#if defined(__linux__)
static void __attribute__ ((constructor)) device_init(void)
{
struct stat st;
if (-1 == lstat("/dev/.devfsd",&st))
return;
if (!S_ISCHR(st.st_mode))
return;
ng_dev = ng_dev_devfs;
}
#endif
amsn-0.98.9/utils/linux/capture/libng/grab-ng.h 0000644 0001750 0001750 00000053043 11755523031 021123 0 ustar billiob billiob /*
* next generation[tm] xawtv capture interfaces
*
* (c) 2001-03 Gerd Knorr
*
*/
#include
#include
#include "devices.h"
#include "list.h"
extern int ng_debug;
extern int ng_log_bad_stream;
extern int ng_log_resync;
extern int ng_chromakey;
extern int ng_ratio_x;
extern int ng_ratio_y;
extern char ng_v4l_conf[256];
extern int ng_jpeg_quality;
extern int ng_mpeg_vpid;
extern int ng_mpeg_apid;
#undef BUG_ON
#undef BUG
#define BUG_ON(condition,message,arg...) if (condition) {\
fprintf(stderr,"BUG: " message " [%s:%s:%d]\n",\
## arg, __FILE__, __FUNCTION__, __LINE__);\
abort();}
#define BUG(message,arg...) if (1) {\
fprintf(stderr,"BUG: " message " [%s:%s:%d]\n",\
## arg, __FILE__, __FUNCTION__, __LINE__);\
abort();}
#define OOPS_ON(condition,message,arg...) if (condition) {\
fprintf(stderr,"Oops: " message " [%s:%s:%d]\n",\
## arg, __FILE__, __FUNCTION__, __LINE__);}
#define OOPS(message,arg...) if (1) {\
fprintf(stderr,"Oops: " message " [%s:%s:%d]\n",\
## arg, __FILE__, __FUNCTION__, __LINE__);}
#if !defined(__cplusplus) && __STDC_VERSION__ < 199901
# undef bool
# define bool int
#endif
#if __STDC_VERSION__ < 199901
# define restrict
#endif
#define UNSET (-1U)
#define DIMOF(array) (sizeof(array)/sizeof(array[0]))
#define SDIMOF(array) ((signed int)(sizeof(array)/sizeof(array[0])))
#define GETELEM(array,index,default) \
(index < sizeof(array)/sizeof(array[0]) ? array[index] : default)
#ifdef __sun
#include /* For major() */
#define __u32 uint32_t
#define __u16 uint16_t
#define __u8 uint8_t
#endif
/* --------------------------------------------------------------------- */
/* defines */
#define VIDEO_NONE 0
#define VIDEO_RGB08 1 /* bt848 dithered */
#define VIDEO_GRAY 2
#define VIDEO_RGB15_LE 3 /* 15 bpp little endian */
#define VIDEO_RGB16_LE 4 /* 16 bpp little endian */
#define VIDEO_RGB15_BE 5 /* 15 bpp big endian */
#define VIDEO_RGB16_BE 6 /* 16 bpp big endian */
#define VIDEO_BGR24 7 /* bgrbgrbgrbgr (LE) */
#define VIDEO_BGR32 8 /* bgr-bgr-bgr- (LE) */
#define VIDEO_RGB24 9 /* rgbrgbrgbrgb (BE) */
#define VIDEO_RGB32 10 /* -rgb-rgb-rgb (BE) */
#define VIDEO_LUT2 11 /* lookup-table 2 byte depth */
#define VIDEO_LUT4 12 /* lookup-table 4 byte depth */
#define VIDEO_YUYV 13 /* 4:2:2 */
#define VIDEO_YUV422P 14 /* YUV 4:2:2 (planar) */
#define VIDEO_YUV420P 15 /* YUV 4:2:0 (planar) */
#define VIDEO_MJPEG 16 /* MJPEG (AVI) */
#define VIDEO_JPEG 17 /* JPEG (JFIF) */
#define VIDEO_UYVY 18 /* 4:2:2 */
#define VIDEO_MPEG 19 /* MPEG1/2 */
#define VIDEO_BAYER 20
#define VIDEO_S910 21
#define VIDEO_FMT_COUNT 22
#define AUDIO_NONE 0
#define AUDIO_U8_MONO 1
#define AUDIO_U8_STEREO 2
#define AUDIO_S16_LE_MONO 3
#define AUDIO_S16_LE_STEREO 4
#define AUDIO_S16_BE_MONO 5
#define AUDIO_S16_BE_STEREO 6
#define AUDIO_MP3 7
#define AUDIO_FMT_COUNT 8
#if BYTE_ORDER == BIG_ENDIAN
# define AUDIO_S16_NATIVE_MONO AUDIO_S16_BE_MONO
# define AUDIO_S16_NATIVE_STEREO AUDIO_S16_BE_STEREO
# define VIDEO_RGB15_NATIVE VIDEO_RGB15_BE
# define VIDEO_RGB16_NATIVE VIDEO_RGB16_BE
#endif
#if BYTE_ORDER == LITTLE_ENDIAN
# define AUDIO_S16_NATIVE_MONO AUDIO_S16_LE_MONO
# define AUDIO_S16_NATIVE_STEREO AUDIO_S16_LE_STEREO
# define VIDEO_RGB15_NATIVE VIDEO_RGB15_LE
# define VIDEO_RGB16_NATIVE VIDEO_RGB16_LE
#endif
#define ATTR_TYPE_INTEGER 1 /* range 0 - 65535 */
#define ATTR_TYPE_CHOICE 2 /* multiple choice */
#define ATTR_TYPE_BOOL 3 /* yes/no */
#define ATTR_ID_NORM 1
#define ATTR_ID_INPUT 2
#define ATTR_ID_VOLUME 3
#define ATTR_ID_MUTE 4
#define ATTR_ID_AUDIO_MODE 5
#define ATTR_ID_COLOR 6
#define ATTR_ID_BRIGHT 7
#define ATTR_ID_HUE 8
#define ATTR_ID_CONTRAST 9
#define ATTR_ID_COUNT 10
#define CAN_OVERLAY 1
#define CAN_CAPTURE 2
#define CAN_TUNE 4
#define NEEDS_CHROMAKEY 8
#define CAN_MPEG_PS 16
#define CAN_MPEG_TS 32
#define MPEG_FLAGS_PS 1
#define MPEG_FLAGS_TS 2
/* --------------------------------------------------------------------- */
extern const unsigned int ng_vfmt_to_depth[VIDEO_FMT_COUNT];
extern const char* ng_vfmt_to_desc[VIDEO_FMT_COUNT];
extern const unsigned int ng_afmt_to_channels[AUDIO_FMT_COUNT];
extern const unsigned int ng_afmt_to_bits[AUDIO_FMT_COUNT];
extern const char* ng_afmt_to_desc[AUDIO_FMT_COUNT];
extern const char* ng_attr_to_desc[ATTR_ID_COUNT];
/* --------------------------------------------------------------------- */
struct STRTAB {
long nr;
char *str;
};
struct OVERLAY_CLIP {
int x1,x2,y1,y2;
};
/* fwd decl */
struct ng_devinfo;
struct ng_devstate;
/* --------------------------------------------------------------------- */
/* video data structures */
struct ng_video_fmt {
unsigned int fmtid; /* VIDEO_* */
unsigned int width;
unsigned int height;
unsigned int bytesperline; /* zero for compressed formats */
};
enum ng_video_frame {
NG_FRAME_UNKNOWN = 0,
NG_FRAME_I_FRAME = 1,
NG_FRAME_P_FRAME = 2,
NG_FRAME_B_FRAME = 3,
};
enum ng_video_ratio {
// same numbers mpeg2 uses
NG_RATIO_UNSPEC = 0,
NG_RATIO_SQUARE = 1,
NG_RATIO_3_4 = 2,
NG_RATIO_9_16 = 3,
NG_RATIO_2dot21 = 4,
};
struct ng_video_buf {
struct ng_video_fmt fmt;
size_t size;
unsigned char *data;
/* meta info for frame */
struct {
int64_t ts; /* time stamp */
int file_seq;
int play_seq;
int twice;
enum ng_video_frame frame;
enum ng_video_ratio ratio;
int broken;
int slowdown;
} info;
/*
* the lock is for the reference counter.
* if the reference counter goes down to zero release()
* should be called. priv is for the owner of the
* buffer (can be used by the release callback)
*/
pthread_mutex_t lock;
pthread_cond_t cond;
int refcount;
void (*release)(struct ng_video_buf *buf);
void *priv;
};
struct ng_video_fifo {
struct list_head next;
struct ng_video_buf *buf;
};
void ng_init_video_buf(struct ng_video_buf *buf);
void ng_release_video_buf(struct ng_video_buf *buf);
void ng_print_video_buf(char *tag, struct ng_video_buf *buf);
void ng_copy_video_buf(struct ng_video_buf *dst, struct ng_video_buf *src);
struct ng_video_buf* ng_malloc_video_buf(void *handle, struct ng_video_fmt *fmt);
void ng_wakeup_video_buf(struct ng_video_buf *buf);
void ng_waiton_video_buf(struct ng_video_buf *buf);
/* --------------------------------------------------------------------- */
/* audio data structures */
struct ng_audio_fmt {
unsigned int fmtid; /* AUDIO_* */
unsigned int rate;
};
struct ng_audio_buf {
struct ng_audio_fmt fmt;
int size;
int written; /* for partial writes */
char *data;
struct {
int64_t ts;
int broken;
int slowdown;
} info;
};
struct ng_audio_buf* ng_malloc_audio_buf(struct ng_audio_fmt *fmt,
int size);
void ng_free_audio_buf(struct ng_audio_buf *buf);
/* --------------------------------------------------------------------- */
/* someone who receives video and/or audio data (writeavi, ...) */
struct ng_format_list {
char *name;
char *desc; /* if standard fmtid description doesn't work
because it's converted somehow */
char *ext;
unsigned int fmtid;
void *priv;
};
struct ng_writer {
const char *name;
const char *desc;
const struct ng_format_list *video;
const struct ng_format_list *audio;
const int combined; /* both audio + video in one file */
void* (*wr_open)(char *moviename, char *audioname,
struct ng_video_fmt *video, const void *priv_video, int fps,
struct ng_audio_fmt *audio, const void *priv_audio);
int (*wr_video)(void *handle, struct ng_video_buf *buf);
int (*wr_audio)(void *handle, struct ng_audio_buf *buf);
int (*wr_close)(void *handle);
struct list_head list;
};
struct ng_reader {
const char *name;
const char *desc;
char *magic[8];
int moff[8];
int mlen[8];
void* (*rd_open)(char *moviename);
struct ng_video_fmt* (*rd_vfmt)(void *handle, int *vfmt, int vn);
struct ng_audio_fmt* (*rd_afmt)(void *handle);
struct ng_video_buf* (*rd_vdata)(void *handle, unsigned int *drop);
struct ng_audio_buf* (*rd_adata)(void *handle);
int64_t (*frame_time)(void *handle);
int (*rd_close)(void *handle);
struct list_head list;
};
/* --------------------------------------------------------------------- */
/* attributes */
struct ng_attribute {
/* attribute name + identity */
int id;
int priority;
const char *name;
const char *group;
/* attribute properties */
int type;
int defval;
struct STRTAB *choices; /* ATTR_TYPE_CHOICE */
int min,max; /* ATTR_TYPE_INTEGER */
int points; /* ATTR_TYPE_INTEGER -- fixed point */
int (*read)(struct ng_attribute*);
void (*write)(struct ng_attribute*, int val);
/* attribute owner's data */
void *handle;
const void *priv;
/* attribute user's data */
struct list_head device_list;
struct ng_devstate *dev;
struct list_head global_list;
void *app;
};
struct ng_attribute* ng_attr_byid(struct ng_devstate *dev, int id);
struct ng_attribute* ng_attr_byname(struct ng_devstate *dev, char *name);
const char* ng_attr_getstr(struct ng_attribute *attr, int value);
int ng_attr_getint(struct ng_attribute *attr, char *value);
void ng_attr_listchoices(struct ng_attribute *attr);
int ng_attr_int2percent(struct ng_attribute *attr, int value);
int ng_attr_percent2int(struct ng_attribute *attr, int percent);
int ng_attr_parse_int(struct ng_attribute *attr, char *str);
/* --------------------------------------------------------------------- */
void ng_ratio_fixup(int *width, int *height, int *xoff, int *yoff);
void ng_ratio_fixup2(int *width, int *height, int *xoff, int *yoff,
int ratio_x, int ratio_y, int up);
/* --------------------------------------------------------------------- */
/* capture/overlay + sound interface drivers */
struct ng_vid_driver {
const char *name;
int priority;
/* open/close */
struct ng_devinfo* (*probe)(int debug);
void* (*init)(char *device);
int (*open)(void *handle);
int (*close)(void *handle);
int (*fini)(void *handle);
char* (*devname)(void *handle);
char* (*busname)(void *handle);
/* attributes */
int (*capabilities)(void *handle);
struct ng_attribute* (*list_attrs)(void *handle);
#if 0
/* overlay */
int (*setupfb)(void *handle, struct ng_video_fmt *fmt, void *base);
int (*overlay)(void *handle, struct ng_video_fmt *fmt, int x, int y,
struct OVERLAY_CLIP *oc, int count, int aspect);
#else
int (*overlay)(void *handle, int enable, int aspect,
long window, int dw, int dh);
#endif
/* capture */
int (*setformat)(void *handle, struct ng_video_fmt *fmt);
int (*startvideo)(void *handle, int fps, unsigned int buffers);
void (*stopvideo)(void *handle);
struct ng_video_buf* (*nextframe)(void *handle); /* video frame */
struct ng_video_buf* (*getimage)(void *handle); /* single image */
/* read MPEG stream */
char* (*setup_mpeg)(void *handle, int flags);
/* tuner */
unsigned long (*getfreq)(void *handle);
void (*setfreq)(void *handle, unsigned long freq);
int (*is_tuned)(void *handle);
struct list_head list;
};
struct ng_dsp_driver {
const char *name;
int priority;
/* open/close */
struct ng_devinfo* (*probe)(int record, int debug);
void* (*init)(char *device, int record);
int (*open)(void *handle);
int (*close)(void *handle);
int (*fini)(void *handle);
char* (*devname)(void *handle);
/* record/playback */
int (*setformat)(void *handle, struct ng_audio_fmt *fmt);
int (*fd)(void *handle);
int (*startrec)(void *handle);
int (*startplay)(void *handle);
struct ng_audio_buf* (*read)(void *handle, int64_t stopby);
struct ng_audio_buf* (*write)(void *handle, struct ng_audio_buf *buf);
int64_t (*latency)(void *handle);
struct list_head list;
};
struct ng_mix_driver {
const char *name;
int priority;
struct ng_devinfo* (*probe)(int debug);
struct ng_devinfo* (*channels)(char *device);
void* (*init)(char *device, char *control);
int (*open)(void *handle);
int (*close)(void *handle);
int (*fini)(void *handle);
char* (*devname)(void *handle);
struct ng_attribute* (*list_attrs)(void *handle);
struct list_head list;
};
struct ng_devinfo {
char device[32];
char name[32];
char bus[32];
int flags;
};
struct ng_devstate {
enum {
NG_DEV_NONE = 0,
NG_DEV_VIDEO = 1,
NG_DEV_DSP = 2,
NG_DEV_MIX = 3,
} type;
union {
struct ng_vid_driver *v;
struct ng_dsp_driver *a;
struct ng_mix_driver *m;
};
char *device;
void *handle;
struct list_head attrs;
int flags;
int refcount;
};
/* --------------------------------------------------------------------- */
/* frame processing (color space conversion / compression / filtering) */
typedef struct ng_video_buf* (*ng_get_video_buf)
(void *handle, struct ng_video_fmt *fmt);
typedef struct ng_audio_buf* (*ng_get_audio_buf)
(void *handle);
enum ng_process_mode {
NG_MODE_UNDEF = 0,
NG_MODE_TRIVIAL = 1,
NG_MODE_COMPLEX = 2,
};
struct ng_video_process {
enum ng_process_mode mode;
/* trivial filters -- one frame in, one frame out */
void (*frame)(void *handle,
struct ng_video_buf *out,
struct ng_video_buf *in);
/* complex filters -- anything trivial can't handle */
void (*setup)(void *handle, ng_get_video_buf get, void *ghandle);
void (*put_frame)(void *handle, struct ng_video_buf* buf);
struct ng_video_buf* (*get_frame)(void *handle);
/* cleanup */
void (*fini)(void *handle);
};
struct ng_video_conv {
void* (*init)(struct ng_video_fmt *out,
void *priv);
struct ng_video_process p;
unsigned int fmtid_in;
unsigned int fmtid_out;
void *priv;
struct list_head list;
};
struct ng_video_filter {
void* (*init)(struct ng_video_fmt *fmt);
struct ng_video_process p;
char *name;
int fmts;
struct ng_attribute* attrs;
struct list_head list;
};
struct ng_process_handle;
struct ng_process_handle* ng_conv_init(struct ng_video_conv *conv,
struct ng_video_fmt *i,
struct ng_video_fmt *o);
struct ng_process_handle* ng_filter_init(struct ng_video_filter *filter,
struct ng_video_fmt *fmt);
void ng_process_setup(struct ng_process_handle*, ng_get_video_buf get, void *ghandle);
void ng_process_put_frame(struct ng_process_handle*, struct ng_video_buf*);
struct ng_video_buf* ng_process_get_frame(struct ng_process_handle*);
void ng_process_fini(struct ng_process_handle*);
#if 0
struct ng_convert_handle* ng_convert_alloc(struct ng_video_conv *conv,
struct ng_video_fmt *i,
struct ng_video_fmt *o);
void ng_convert_init(struct ng_convert_handle *h);
struct ng_video_buf* ng_convert_frame(struct ng_convert_handle *h,
struct ng_video_buf *dest,
struct ng_video_buf *buf);
void ng_convert_fini(struct ng_convert_handle *h);
struct ng_video_buf* ng_convert_single(struct ng_convert_handle *h,
struct ng_video_buf *in);
#endif
/* --------------------------------------------------------------------- */
/* audio converters */
struct ng_audio_conv {
unsigned int fmtid_in;
unsigned int fmtid_out;
void* (*init)(void *priv);
struct ng_audio_buf* (*data)(void *handle,
struct ng_audio_buf *in);
void (*fini)(void *handle);
void *priv;
struct list_head list;
};
/* --------------------------------------------------------------------- */
/* must be changed if we break compatibility */
#define NG_PLUGIN_MAGIC 0x20041201
#define __init __attribute__ ((constructor))
#define __fini __attribute__ ((destructor))
#ifndef __used
#define __used __attribute__ ((used))
#endif
extern struct list_head ng_conv;
extern struct list_head ng_aconv;
extern struct list_head ng_filters;
extern struct list_head ng_writers;
extern struct list_head ng_readers;
extern struct list_head ng_vid_drivers;
extern struct list_head ng_dsp_drivers;
extern struct list_head ng_mix_drivers;
int ng_conv_register(int magic, char *plugname,
struct ng_video_conv *list, int count);
int ng_aconv_register(int magic, char *plugname,
struct ng_audio_conv *list, int count);
int ng_filter_register(int magic, char *plugname,
struct ng_video_filter *filter);
int ng_writer_register(int magic, char *plugname,
struct ng_writer *writer);
int ng_reader_register(int magic, char *plugname,
struct ng_reader *reader);
int ng_vid_driver_register(int magic, char *plugname,
struct ng_vid_driver *driver);
int ng_dsp_driver_register(int magic, char *plugname,
struct ng_dsp_driver *driver);
int ng_mix_driver_register(int magic, char *plugname,
struct ng_mix_driver *driver);
struct ng_video_conv* ng_conv_find_to(unsigned int out, int *i);
struct ng_video_conv* ng_conv_find_from(unsigned int out, int *i);
struct ng_video_conv* ng_conv_find_match(unsigned int in, unsigned int out);
struct ng_devinfo* ng_vid_probe(char *driver);
int ng_vid_init(struct ng_devstate *dev, char *device);
int ng_dsp_init(struct ng_devstate *dev, char *device, int record);
int ng_mix_init(struct ng_devstate *dev, char *device, char *control);
int ng_dev_fini(struct ng_devstate *dev);
int ng_dev_open(struct ng_devstate *dev);
int ng_dev_close(struct ng_devstate *dev);
int ng_dev_users(struct ng_devstate *dev);
int ng_chardev_open(char *device, int flags, int major, int complain, int is_v4l2);
struct ng_reader* ng_find_reader_magic(char *filename);
struct ng_reader* ng_find_reader_name(char *name);
struct ng_writer* ng_find_writer_name(char *name);
int64_t ng_tofday_to_timestamp(struct timeval *tv);
int64_t ng_get_timestamp(void);
void ng_check_clipping(int width, int height, int xadjust, int yadjust,
struct OVERLAY_CLIP *oc, int *count);
struct ng_video_buf* ng_filter_single(struct ng_video_filter *filter,
struct ng_video_buf *in);
/* --------------------------------------------------------------------- */
void ng_init(void);
void ng_print_stacktrace(void);
void ng_lut_init(unsigned long red_mask, unsigned long green_mask,
unsigned long blue_mask, unsigned int fmtid, int swap);
void ng_rgb24_to_lut2(unsigned char *dest, unsigned char *src, int p);
void ng_rgb24_to_lut4(unsigned char *dest, unsigned char *src, int p);
/* --------------------------------------------------------------------- */
/* internal stuff starts here */
#ifdef NG_PRIVATE
/* for yuv2rgb using lookup tables (color_lut.c, color_yuv2rgb.c) */
extern int32_t ng_lut_red[256];
extern int32_t ng_lut_green[256];
extern int32_t ng_lut_blue[256];
void ng_yuv422_to_lut2(unsigned char *dest, unsigned char *s, int p);
void ng_yuv422_to_lut4(unsigned char *dest, unsigned char *s, int p);
void ng_yuv420p_to_lut2(void *h, struct ng_video_buf *out,
struct ng_video_buf *in);
void ng_yuv420p_to_lut4(void *h, struct ng_video_buf *out,
struct ng_video_buf *in);
void ng_yuv422p_to_lut2(void *h, struct ng_video_buf *out,
struct ng_video_buf *in);
void ng_yuv422p_to_lut4(void *h, struct ng_video_buf *out,
struct ng_video_buf *in);
void yuv2rgb_init(void);
void packed_init(void);
/* color_common.c stuff */
void* ng_packed_init(struct ng_video_fmt *out, void *priv);
void ng_packed_frame(void *handle, struct ng_video_buf *out,
struct ng_video_buf *in);
void* ng_conv_nop_init(struct ng_video_fmt *out, void *priv);
void ng_conv_nop_fini(void *handle);
#define NG_GENERIC_PACKED \
.init = ng_packed_init, \
.p.mode = NG_MODE_TRIVIAL, \
.p.frame = ng_packed_frame, \
.p.fini = ng_conv_nop_fini
#endif /* NG_PRIVATE */
/* --------------------------------------------------------------------- */
/*
* Local variables:
* compile-command: "(cd ..; make)"
* End:
*/
amsn-0.98.9/utils/linux/capture/libng/list.h 0000644 0001750 0001750 00000010454 10246003435 020553 0 ustar billiob billiob #ifndef _LIST_H
#define _LIST_H 1
/*
* Simple doubly linked list implementation.
* -- shameless stolen from the linux kernel sources
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/
struct list_head {
struct list_head *next, *prev;
};
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
/*
* Insert a item entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static __inline__ void __list_add(struct list_head * item,
struct list_head * prev,
struct list_head * next)
{
next->prev = item;
item->next = next;
item->prev = prev;
prev->next = item;
}
/**
* list_add - add a item entry
* @item: item entry to be added
* @head: list head to add it after
*
* Insert a item entry after the specified head.
* This is good for implementing stacks.
*/
static __inline__ void list_add(struct list_head *item, struct list_head *head)
{
__list_add(item, head, head->next);
}
/**
* list_add_tail - add a item entry
* @item: item entry to be added
* @head: list head to add it before
*
* Insert a item entry before the specified head.
* This is useful for implementing queues.
*/
static __inline__ void list_add_tail(struct list_head *item, struct list_head *head)
{
__list_add(item, head->prev, head);
}
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static __inline__ void __list_del(struct list_head * prev,
struct list_head * next)
{
next->prev = prev;
prev->next = next;
}
/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty on entry does not return true after this, the entry is in an undefined state.
*/
static __inline__ void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}
/**
* list_del_init - deletes entry from list and reinitialize it.
* @entry: the element to delete from the list.
*/
static __inline__ void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
INIT_LIST_HEAD(entry);
}
/**
* list_empty - tests whether a list is empty
* @head: the list to test.
*/
static __inline__ int list_empty(struct list_head *head)
{
return head->next == head;
}
/**
* list_splice - join two lists
* @list: the item list to add.
* @head: the place to add it in the first list.
*/
static __inline__ void list_splice(struct list_head *list, struct list_head *head)
{
struct list_head *first = list->next;
if (first != list) {
struct list_head *last = list->prev;
struct list_head *at = head->next;
first->prev = head;
head->next = first;
last->next = at;
at->prev = last;
}
}
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
/**
* list_for_each_safe - iterate over a list safe against removal of list entry
* @pos: the &struct list_head to use as a loop counter.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*/
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
/**
* list_for_each_prev - iterate over a list in reverse order
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
#define list_for_each_prev(pos, head) \
for (pos = (head)->prev; pos != (head); pos = pos->prev)
#endif /* _LIST_H */
amsn-0.98.9/utils/linux/capture/libng/convert.c 0000644 0001750 0001750 00000007725 10246003435 021262 0 ustar billiob billiob #include "config.h"
#include
#include
#include
#include
#include "grab-ng.h"
struct ng_process_handle {
struct ng_video_fmt ifmt;
struct ng_video_fmt ofmt;
ng_get_video_buf get;
void *ghandle;
struct ng_video_process *p;
void *phandle;
struct ng_video_buf *in;
};
/*-------------------------------------------------------------------------*/
/* color space conversion / compression helper functions */
static int processes;
struct ng_process_handle* ng_conv_init(struct ng_video_conv *conv,
struct ng_video_fmt *i,
struct ng_video_fmt *o)
{
struct ng_process_handle *h;
h = malloc(sizeof(*h));
if (NULL == h)
return NULL;
memset(h,0,sizeof(*h));
/* fixup output image size to match incoming */
if (0 == i->bytesperline)
i->bytesperline = i->width * ng_vfmt_to_depth[i->fmtid] / 8;
o->width = i->width;
o->height = i->height;
if (0 == o->bytesperline)
o->bytesperline = o->width * ng_vfmt_to_depth[o->fmtid] / 8;
h->ifmt = *i;
h->ofmt = *o;
h->p = &conv->p;
h->phandle = conv->init(&h->ofmt,conv->priv);
switch (h->p->mode) {
case NG_MODE_TRIVIAL:
case NG_MODE_COMPLEX:
break;
default:
BUG_ON(1,"mode not initialited");
break;
}
if (ng_debug) {
fprintf(stderr,"convert-in : %dx%d %s\n",
h->ifmt.width, h->ifmt.height,
ng_vfmt_to_desc[h->ifmt.fmtid]);
fprintf(stderr,"convert-out: %dx%d %s\n",
h->ofmt.width, h->ofmt.height,
ng_vfmt_to_desc[h->ofmt.fmtid]);
}
processes++;
return h;
}
struct ng_process_handle* ng_filter_init(struct ng_video_filter *filter,
struct ng_video_fmt *fmt)
{
struct ng_process_handle *h;
if (!(filter->fmts & (1 << fmt->fmtid))) {
fprintf(stderr,"filter \"%s\" doesn't support video format \"%s\"\n",
filter->name, ng_vfmt_to_desc[fmt->fmtid]);
return NULL;
}
h = malloc(sizeof(*h));
if (NULL == h)
return NULL;
memset(h,0,sizeof(*h));
h->ifmt = *fmt;
h->ofmt = *fmt;
h->p = &filter->p;
h->phandle = filter->init(fmt);
switch (h->p->mode) {
case NG_MODE_TRIVIAL:
case NG_MODE_COMPLEX:
break;
default:
BUG_ON(1,"mode not initialited");
break;
}
if (ng_debug)
fprintf(stderr,"filtering: %s\n", filter->name);
processes++;
return h;
}
void ng_process_setup(struct ng_process_handle *h, ng_get_video_buf get, void *ghandle)
{
switch (h->p->mode) {
case NG_MODE_TRIVIAL:
BUG_ON(NULL != h->in, "already have frame");
h->get = get;
h->ghandle = ghandle;
break;
case NG_MODE_COMPLEX:
h->p->setup(h->phandle,get,ghandle);
break;
default:
BUG_ON(1,"mode not implemented yet");
break;
}
}
void ng_process_put_frame(struct ng_process_handle *h, struct ng_video_buf* buf)
{
switch (h->p->mode) {
case NG_MODE_TRIVIAL:
BUG_ON(NULL != h->in, "already have frame");
h->in = buf;
break;
case NG_MODE_COMPLEX:
h->p->put_frame(h->phandle,buf);
break;
default:
BUG_ON(1,"mode not implemented yet");
break;
}
}
struct ng_video_buf* ng_process_get_frame(struct ng_process_handle *h)
{
struct ng_video_buf *buf = NULL;
switch (h->p->mode) {
case NG_MODE_TRIVIAL:
BUG_ON(NULL == h->get, "no setup");
if (NULL != h->in) {
buf = h->get(h->ghandle, &h->ofmt);
#if 0
ng_print_video_buf("in",h->in);
ng_print_video_buf("out",buf);
#endif
h->p->frame(h->phandle, buf, h->in);
buf->info = h->in->info;
ng_release_video_buf(h->in);
h->in = NULL;
}
break;
case NG_MODE_COMPLEX:
buf = h->p->get_frame(h->phandle);
break;
default:
BUG_ON(1,"mode not implemented yet");
break;
}
return buf;
}
void ng_process_fini(struct ng_process_handle *h)
{
h->p->fini(h->phandle);
free(h);
processes--;
}
static void __fini process_check(void)
{
OOPS_ON(processes > 0, "processes is %d (expected 0)",processes);
}
amsn-0.98.9/utils/linux/capture/libng/Rules.mk 0000644 0001750 0001750 00000001527 11755465524 021074 0 ustar billiob billiob OBJS-libng := \
$(capture_dir)/libng/grab-ng.o \
$(capture_dir)/libng/devices.o \
$(capture_dir)/libng/writefile.o \
$(capture_dir)/libng/parse-mpeg.o \
$(capture_dir)/libng/parse-dvb.o \
$(capture_dir)/libng/color_common.o \
$(capture_dir)/libng/color_packed.o \
$(capture_dir)/libng/color_lut.o \
$(capture_dir)/libng/color_yuv2rgb.o \
$(capture_dir)/libng/convert.o \
$(capture_dir)/libng/misc.o
TARGET-libng := $(capture_dir)/libng/libng.so
V4L_CFLAGS=
ifeq ($(HAVE_LIBV4L),yes)
V4L_CFLAGS += -DHAVE_LIBV4L
endif
$(OBJS-libng): CFLAGS+=-I$(capture_dir) $(V4L_CFLAGS) $(if $(strip ${LIBDIR}),-DLIBDIR=\"${LIBDIR}/$(capture_dir)/libng/plugins\",)
$(TARGET-libng): MORE_LIBS=-ldl
$(TARGET-libng): $(OBJS-libng)
@$(echo_link_so)
@$(link_so)
all:: $(TARGET-libng)
clean:: clean-libng
clean-libng:
rm -f $(TARGET-libng) $(OBJS-libng)
amsn-0.98.9/utils/linux/capture/libng/grab-ng.c 0000644 0001750 0001750 00000066102 11755465524 021132 0 ustar billiob billiob /*
* next generation[tm] xawtv capture interfaces
*
* (c) 2001 Gerd Knorr
*
*/
#define NG_PRIVATE
#include "config.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifndef RTLD_NOW
# define RTLD_NOW RTLD_LAZY
#endif
#include "grab-ng.h"
#ifdef HAVE_LIBV4L
#include
#else
#define v4l2_open open
#define v4l2_close close
#endif
int ng_debug = 0;
int ng_log_bad_stream = 0;
int ng_log_resync = 0;
int ng_chromakey = 0x00ff00ff;
int ng_ratio_x = 4;
int ng_ratio_y = 3;
int ng_jpeg_quality = 75;
char ng_v4l_conf[256] = "v4l-conf";
/* --------------------------------------------------------------------- */
const unsigned int ng_vfmt_to_depth[VIDEO_FMT_COUNT] = {
0, /* unused */
8, /* RGB8 */
8, /* GRAY8 */
16, /* RGB15 LE */
16, /* RGB16 LE */
16, /* RGB15 BE */
16, /* RGB16 BE */
24, /* BGR24 */
32, /* BGR32 */
24, /* RGB24 */
32, /* RGB32 */
16, /* LUT2 */
32, /* LUT4 */
16, /* YUYV */
16, /* YUV422P */
12, /* YUV420P */
0, /* MJPEG */
0, /* JPEG */
16, /* UYVY */
0, /* MPEG */
24, /* BAYER */
24, /* S910 */
};
const char* ng_vfmt_to_desc[VIDEO_FMT_COUNT] = {
"none",
"8 bit PseudoColor (dithering)",
"8 bit StaticGray",
"15 bit TrueColor (LE)",
"16 bit TrueColor (LE)",
"15 bit TrueColor (BE)",
"16 bit TrueColor (BE)",
"24 bit TrueColor (LE: bgr)",
"32 bit TrueColor (LE: bgr-)",
"24 bit TrueColor (BE: rgb)",
"32 bit TrueColor (BE: -rgb)",
"16 bit TrueColor (lut)",
"32 bit TrueColor (lut)",
"16 bit YUV 4:2:2 (packed, YUYV)",
"16 bit YUV 4:2:2 (planar)",
"12 bit YUV 4:2:0 (planar)",
"MJPEG (AVI)",
"JPEG (JFIF)",
"16 bit YUV 4:2:2 (packed, UYVY)",
"MPEG video",
"Sequential Bayer (BA81)",
"SN9C102 Driver Compressed Format (S910)",
};
/* --------------------------------------------------------------------- */
const unsigned int ng_afmt_to_channels[AUDIO_FMT_COUNT] = {
0, 1, 2, 1, 2, 1, 2, 0
};
const unsigned int ng_afmt_to_bits[AUDIO_FMT_COUNT] = {
0, 8, 8, 16, 16, 16, 16, 0
};
const char* ng_afmt_to_desc[AUDIO_FMT_COUNT] = {
"none",
"8bit mono",
"8bit stereo",
"16bit mono (LE)",
"16bit stereo (LE)",
"16bit mono (BE)",
"16bit stereo (BE)",
"MPEG audio",
};
/* --------------------------------------------------------------------- */
const char* ng_attr_to_desc[] = {
"none",
"norm",
"input",
"volume",
"mute",
"audio mode",
"color",
"bright",
"hue",
"contrast",
};
/* --------------------------------------------------------------------- */
void ng_init_video_buf(struct ng_video_buf *buf)
{
memset(buf,0,sizeof(*buf));
pthread_mutex_init(&buf->lock,NULL);
pthread_cond_init(&buf->cond,NULL);
}
void ng_release_video_buf(struct ng_video_buf *buf)
{
int release;
pthread_mutex_lock(&buf->lock);
buf->refcount--;
release = (buf->refcount == 0);
pthread_mutex_unlock(&buf->lock);
if (release && NULL != buf->release)
buf->release(buf);
}
void ng_print_video_buf(char *tag, struct ng_video_buf *buf)
{
fprintf(stderr,"buf %5s: %dx%d [%s]\n",
tag, buf->fmt.width, buf->fmt.height,
ng_vfmt_to_desc[buf->fmt.fmtid]);
}
void ng_copy_video_buf(struct ng_video_buf *dst, struct ng_video_buf *src)
{
memcpy(dst->data, src->data, src->size);
dst->size = src->size;
dst->info = src->info;
}
void ng_wakeup_video_buf(struct ng_video_buf *buf)
{
pthread_cond_signal(&buf->cond);
}
void ng_waiton_video_buf(struct ng_video_buf *buf)
{
pthread_mutex_lock(&buf->lock);
while (buf->refcount)
pthread_cond_wait(&buf->cond, &buf->lock);
pthread_mutex_unlock(&buf->lock);
}
static int malloc_video_bufs;
static int malloc_audio_bufs;
static void ng_free_video_buf(struct ng_video_buf *buf)
{
free(buf->data);
free(buf);
malloc_video_bufs--;
}
struct ng_video_buf*
ng_malloc_video_buf(void *handle, struct ng_video_fmt *fmt)
{
struct ng_video_buf *buf;
buf = malloc(sizeof(*buf));
if (NULL == buf)
return NULL;
ng_init_video_buf(buf);
buf->fmt = *fmt;
buf->size = fmt->height * fmt->bytesperline;
if (0 == buf->size)
buf->size = fmt->width * fmt->height * 3;
buf->data = malloc(buf->size);
if (NULL == buf->data) {
free(buf);
return NULL;
}
buf->refcount = 1;
buf->release = ng_free_video_buf;
malloc_video_bufs++;
return buf;
}
struct ng_audio_buf*
ng_malloc_audio_buf(struct ng_audio_fmt *fmt, int size)
{
struct ng_audio_buf *buf;
buf = malloc(sizeof(*buf)+size);
memset(buf,0,sizeof(*buf));
buf->fmt = *fmt;
buf->size = size;
buf->data = (char*)buf + sizeof(*buf);
malloc_audio_bufs++;
return buf;
}
void ng_free_audio_buf(struct ng_audio_buf *buf)
{
malloc_audio_bufs--;
free(buf);
}
static void __fini malloc_bufs_check(void)
{
OOPS_ON(malloc_video_bufs > 0, "malloc_video_bufs is %d (expected 0)",
malloc_video_bufs);
OOPS_ON(malloc_audio_bufs > 0, "malloc_audio_bufs is %d (expected 0)",
malloc_audio_bufs);
}
/* --------------------------------------------------------------------- */
struct ng_attribute*
ng_attr_byid(struct ng_devstate *dev, int id)
{
struct list_head *item;
struct ng_attribute *attr;
list_for_each(item, &dev->attrs) {
attr = list_entry(item, struct ng_attribute, device_list);
if (attr->id == id)
return attr;
}
return NULL;
}
struct ng_attribute*
ng_attr_byname(struct ng_devstate *dev, char *name)
{
struct list_head *item;
struct ng_attribute *attr;
list_for_each(item, &dev->attrs) {
attr = list_entry(item, struct ng_attribute, device_list);
if (0 == strcasecmp(attr->name,name))
return attr;
}
return NULL;
}
const char*
ng_attr_getstr(struct ng_attribute *attr, int value)
{
int i;
if (NULL == attr)
return NULL;
if (attr->type != ATTR_TYPE_CHOICE)
return NULL;
for (i = 0; attr->choices[i].str != NULL; i++)
if (attr->choices[i].nr == value)
return attr->choices[i].str;
return NULL;
}
int
ng_attr_getint(struct ng_attribute *attr, char *value)
{
int i,val;
if (NULL == attr)
return -1;
if (attr->type != ATTR_TYPE_CHOICE)
return -1;
for (i = 0; attr->choices[i].str != NULL; i++) {
if (0 == strcasecmp(attr->choices[i].str,value))
return attr->choices[i].nr;
}
if (isdigit(value[0])) {
/* Hmm. String not found, but starts with a digit.
Check if this is a valid number ... */
val = atoi(value);
for (i = 0; attr->choices[i].str != NULL; i++)
if (val == attr->choices[i].nr)
return attr->choices[i].nr;
}
return -1;
}
void
ng_attr_listchoices(struct ng_attribute *attr)
{
int i;
fprintf(stderr,"valid choices for \"%s\": ",attr->name);
for (i = 0; attr->choices[i].str != NULL; i++)
fprintf(stderr,"%s\"%s\"",
i ? ", " : "",
attr->choices[i].str);
fprintf(stderr,"\n");
}
int
ng_attr_int2percent(struct ng_attribute *attr, int value)
{
int range,percent;
range = attr->max - attr->min;
percent = (value - attr->min) * 100 / range;
if (percent < 0)
percent = 0;
if (percent > 100)
percent = 100;
return percent;
}
int
ng_attr_percent2int(struct ng_attribute *attr, int percent)
{
int range,value;
range = attr->max - attr->min;
value = percent * range / 100 + attr->min;
if (value < attr->min)
value = attr->min;
if (value > attr->max)
value = attr->max;
return value;
}
int
ng_attr_parse_int(struct ng_attribute *attr, char *str)
{
int value,n;
if (0 == sscanf(str,"%d%n",&value,&n))
/* parse error */
return attr->defval;
if (str[n] == '%')
value = ng_attr_percent2int(attr,value);
if (value < attr->min)
value = attr->min;
if (value > attr->max)
value = attr->max;
return value;
}
/* --------------------------------------------------------------------- */
void
ng_ratio_fixup(int *width, int *height, int *xoff, int *yoff)
{
int h = *height;
int w = *width;
if (0 == ng_ratio_x || 0 == ng_ratio_y)
return;
if (w * ng_ratio_y < h * ng_ratio_x) {
*height = *width * ng_ratio_y / ng_ratio_x;
if (yoff)
*yoff += (h-*height)/2;
} else if (w * ng_ratio_y > h * ng_ratio_x) {
*width = *height * ng_ratio_x / ng_ratio_y;
if (yoff)
*xoff += (w-*width)/2;
}
}
void
ng_ratio_fixup2(int *width, int *height, int *xoff, int *yoff,
int ratio_x, int ratio_y, int up)
{
int h = *height;
int w = *width;
if (0 == ratio_x || 0 == ratio_y)
return;
if ((!up && w * ratio_y < h * ratio_x) ||
(up && w * ratio_y > h * ratio_x)) {
*height = *width * ratio_y / ratio_x;
if (yoff)
*yoff += (h-*height)/2;
} else if ((!up && w * ratio_y > h * ratio_x) ||
(up && w * ratio_y < h * ratio_x)) {
*width = *height * ratio_x / ratio_y;
if (yoff)
*xoff += (w-*width)/2;
}
}
/* --------------------------------------------------------------------- */
LIST_HEAD(ng_conv);
LIST_HEAD(ng_aconv);
LIST_HEAD(ng_filters);
LIST_HEAD(ng_writers);
LIST_HEAD(ng_readers);
LIST_HEAD(ng_vid_drivers);
LIST_HEAD(ng_dsp_drivers);
LIST_HEAD(ng_mix_drivers);
static int ng_check_magic(int magic, char *plugname, char *type)
{
char *h;
h=strrchr(plugname,'/');
if (h)
h++;
else
h=plugname;
if (magic != NG_PLUGIN_MAGIC) {
fprintf(stderr, "ERROR: plugin magic mismatch [me=%x,%s=%x]\n",
NG_PLUGIN_MAGIC,h,magic);
return -1;
}
#if 0
if (ng_debug)
fprintf(stderr,"plugins: %s registered by %s\n",type,plugname);
#endif
return 0;
}
int
ng_conv_register(int magic, char *plugname,
struct ng_video_conv *list, int count)
{
int n;
if (0 != ng_check_magic(magic,plugname,"video converters"))
return -1;
for (n = 0; n < count; n++)
list_add_tail(&(list[n].list),&ng_conv);
return 0;
}
int
ng_aconv_register(int magic, char *plugname,
struct ng_audio_conv *list, int count)
{
int n;
if (0 != ng_check_magic(magic,plugname,"audio converters"))
return -1;
for (n = 0; n < count; n++)
list_add_tail(&(list[n].list),&ng_aconv);
return 0;
}
int
ng_filter_register(int magic, char *plugname, struct ng_video_filter *filter)
{
if (0 != ng_check_magic(magic,plugname,"filter"))
return -1;
list_add_tail(&filter->list,&ng_filters);
return 0;
}
int
ng_writer_register(int magic, char *plugname, struct ng_writer *writer)
{
if (0 != ng_check_magic(magic,plugname,"writer"))
return -1;
list_add_tail(&writer->list,&ng_writers);
return 0;
}
int
ng_reader_register(int magic, char *plugname, struct ng_reader *reader)
{
if (0 != ng_check_magic(magic,plugname,"reader"))
return -1;
list_add_tail(&reader->list,&ng_readers);
return 0;
}
int
ng_vid_driver_register(int magic, char *plugname, struct ng_vid_driver *driver)
{
struct list_head *item;
struct ng_vid_driver *drv;
if (0 != ng_check_magic(magic,plugname,"video drv"))
return -1;
list_for_each(item,&ng_vid_drivers) {
drv = list_entry(item, struct ng_vid_driver, list);
if (drv->priority > driver->priority) {
list_add_tail(&driver->list,&drv->list);
return 0;
}
}
list_add_tail(&driver->list,&ng_vid_drivers);
return 0;
}
int
ng_dsp_driver_register(int magic, char *plugname, struct ng_dsp_driver *driver)
{
struct list_head *item;
struct ng_dsp_driver *drv;
if (0 != ng_check_magic(magic,plugname,"dsp drv"))
return -1;
list_for_each(item,&ng_dsp_drivers) {
drv = list_entry(item, struct ng_dsp_driver, list);
if (drv->priority > driver->priority) {
list_add_tail(&driver->list,&drv->list);
return 0;
}
}
list_add_tail(&driver->list,&ng_dsp_drivers);
return 0;
}
int
ng_mix_driver_register(int magic, char *plugname, struct ng_mix_driver *driver)
{
struct list_head *item;
struct ng_mix_driver *drv;
if (0 != ng_check_magic(magic,plugname,"mixer drv"))
return -1;
list_for_each(item,&ng_mix_drivers) {
drv = list_entry(item, struct ng_mix_driver, list);
if (drv->priority > driver->priority) {
list_add_tail(&driver->list,&drv->list);
return 0;
}
}
list_add_tail(&driver->list,&ng_mix_drivers);
return 0;
}
struct ng_video_conv*
ng_conv_find_to(unsigned int out, int *i)
{
struct list_head *item;
struct ng_video_conv *ret;
int j = 0;
list_for_each(item,&ng_conv) {
if (j < *i) {
j++;
continue;
}
ret = list_entry(item, struct ng_video_conv, list);
#if 0
fprintf(stderr,"\tconv to: %-28s => %s\n",
ng_vfmt_to_desc[ret->fmtid_in],
ng_vfmt_to_desc[ret->fmtid_out]);
#endif
if (ret->fmtid_out == out) {
(*i)++;
return ret;
}
(*i)++;
j++;
}
return NULL;
}
struct ng_video_conv*
ng_conv_find_from(unsigned int in, int *i)
{
struct list_head *item;
struct ng_video_conv *ret;
int j = 0;
list_for_each(item,&ng_conv) {
if (j < *i) {
j++;
continue;
}
ret = list_entry(item, struct ng_video_conv, list);
#if 0
fprintf(stderr,"\tconv from: %-28s => %s\n",
ng_vfmt_to_desc[ret->fmtid_in],
ng_vfmt_to_desc[ret->fmtid_out]);
#endif
if (ret->fmtid_in == in) {
(*i)++;
return ret;
}
}
return NULL;
}
struct ng_video_conv*
ng_conv_find_match(unsigned int in, unsigned int out)
{
struct list_head *item;
struct ng_video_conv *ret = NULL;
list_for_each(item,&ng_conv) {
ret = list_entry(item, struct ng_video_conv, list);
if (ret->fmtid_in == in && ret->fmtid_out == out)
return ret;
}
return NULL;
}
/* --------------------------------------------------------------------- */
int ng_vid_init(struct ng_devstate *dev, char *device)
{
struct list_head *item;
struct ng_vid_driver *drv;
struct ng_attribute *attr;
void *handle;
int i, err = ENODEV;
/* check all grabber drivers */
memset(dev,0,sizeof(*dev));
list_for_each(item,&ng_vid_drivers) {
drv = list_entry(item, struct ng_vid_driver, list);
if (ng_debug)
fprintf(stderr,"vid-open: trying: %s... \n", drv->name);
if (NULL != (handle = drv->init(device)))
break;
if (errno)
err = errno;
if (ng_debug)
fprintf(stderr,"vid-open: failed: %s\n",drv->name);
}
if (item == &ng_vid_drivers)
return err;
if (ng_debug)
fprintf(stderr,"vid-open: ok: %s\n", drv->name);
dev->type = NG_DEV_VIDEO;
dev->v = drv;
dev->handle = handle;
dev->device = dev->v->devname(dev->handle);
dev->flags = dev->v->capabilities(dev->handle);
if (ng_debug)
fprintf(stderr,"vid-open: flags: %x\n", dev->flags);
INIT_LIST_HEAD(&dev->attrs);
attr = dev->v->list_attrs(dev->handle);
for (i = 0; attr && attr[i].name; i++) {
attr[i].dev = dev;
attr[i].group = dev->device;
list_add_tail(&attr[i].device_list,&dev->attrs);
}
return 0;
}
struct ng_devinfo* ng_vid_probe(char *driver)
{
struct list_head *item;
struct ng_vid_driver *drv;
/* check all grabber drivers */
list_for_each(item,&ng_vid_drivers) {
drv = list_entry(item, struct ng_vid_driver, list);
if (ng_debug)
fprintf(stderr,"vid-probe: trying: %s... \n", drv->name);
if (strcmp(driver, drv->name))
continue;
return drv->probe(ng_debug);
}
return NULL;
}
int ng_dsp_init(struct ng_devstate *dev, char *device, int record)
{
struct list_head *item;
struct ng_dsp_driver *drv;
void *handle;
int err = ENODEV;
/* check all dsp drivers */
list_for_each(item,&ng_dsp_drivers) {
drv = list_entry(item, struct ng_dsp_driver, list);
if (record && NULL == drv->read)
continue;
if (!record && NULL == drv->write)
continue;
if (ng_debug)
fprintf(stderr, "dsp-open: trying: %s... \n", drv->name);
if (NULL != (handle = drv->init(device, record)))
break;
if (errno)
err = errno;
if (ng_debug)
fprintf(stderr,"dsp-open: failed: %s\n", drv->name);
}
if (item == &ng_dsp_drivers)
return err;
if (ng_debug)
fprintf(stderr,"dsp-open: ok: %s\n",drv->name);
memset(dev,0,sizeof(*dev));
dev->type = NG_DEV_DSP;
dev->a = drv;
dev->handle = handle;
dev->device = dev->a->devname(dev->handle);
//dev->flags = dev->a->capabilities(dev->handle);
INIT_LIST_HEAD(&dev->attrs);
return 0;
}
int ng_mix_init(struct ng_devstate *dev, char *device, char *control)
{
struct list_head *item;
struct ng_mix_driver *drv;
struct ng_attribute *attr;
void *handle;
int i, err = ENODEV;
/* check all dsp drivers */
list_for_each(item,&ng_mix_drivers) {
drv = list_entry(item, struct ng_mix_driver, list);
if (ng_debug)
fprintf(stderr, "mix-open: trying: %s... \n", drv->name);
if (NULL != (handle = drv->init(device, control)))
break;
if (errno)
err = errno;
if (ng_debug)
fprintf(stderr,"mix-open: failed: %s\n", drv->name);
}
if (item == &ng_mix_drivers)
return err;
if (ng_debug)
fprintf(stderr,"mix-open: ok: %s\n",drv->name);
memset(dev,0,sizeof(*dev));
dev->type = NG_DEV_MIX;
dev->m = drv;
dev->handle = handle;
dev->device = dev->m->devname(dev->handle);
INIT_LIST_HEAD(&dev->attrs);
attr = dev->m->list_attrs(dev->handle);
for (i = 0; attr && attr[i].name; i++) {
attr[i].dev = dev;
attr[i].group = dev->device;
list_add_tail(&attr[i].device_list,&dev->attrs);
}
return 0;
}
int ng_dev_fini(struct ng_devstate *dev)
{
switch (dev->type) {
case NG_DEV_NONE:
/* nothing */
break;
case NG_DEV_VIDEO:
dev->v->fini(dev->handle);
break;
case NG_DEV_DSP:
dev->a->fini(dev->handle);
break;
case NG_DEV_MIX:
dev->m->fini(dev->handle);
break;
}
memset(dev,0,sizeof(*dev));
return 0;
}
int ng_dev_open(struct ng_devstate *dev)
{
int rc = 0;
if (0 == dev->refcount) {
switch (dev->type) {
case NG_DEV_NONE:
BUG_ON(1,"dev type NONE");
break;
case NG_DEV_VIDEO:
rc = dev->v->open(dev->handle);
break;
case NG_DEV_DSP:
rc = dev->a->open(dev->handle);
break;
case NG_DEV_MIX:
rc = dev->m->open(dev->handle);
break;
}
}
if (0 == rc) {
dev->refcount++;
if (ng_debug)
fprintf(stderr,"%s: opened %s [refcount %d]\n",
__FUNCTION__, dev->device, dev->refcount);
}
return rc;
}
int ng_dev_close(struct ng_devstate *dev)
{
dev->refcount--;
BUG_ON(dev->refcount < 0, "refcount below 0");
if (0 == dev->refcount) {
switch (dev->type) {
case NG_DEV_NONE:
BUG_ON(1,"dev type NONE");
break;
case NG_DEV_VIDEO:
dev->v->close(dev->handle);
break;
case NG_DEV_DSP:
dev->a->close(dev->handle);
break;
case NG_DEV_MIX:
dev->m->close(dev->handle);
break;
}
}
if (ng_debug)
fprintf(stderr,"%s: closed %s [refcount %d]\n",
__FUNCTION__, dev->device, dev->refcount);
return 0;
}
int ng_dev_users(struct ng_devstate *dev)
{
return dev->refcount;
}
int ng_chardev_open(char *device, int flags, int major, int complain, int is_v4l2)
{
struct stat st;
int fd = -1;
if (strncmp(device, "/dev/", 5)) {
if (complain)
fprintf(stderr,"%s: not below /dev\n",device);
goto err;
}
if (1 == is_v4l2) {
if (-1 == (fd = v4l2_open(device, flags))) {
if (complain)
fprintf(stderr,"open(%s): %s\n",device,strerror(errno));
goto err;
}
} else {
if (-1 == (fd = open(device, flags))) {
if (complain)
fprintf(stderr,"open(%s): %s\n",device,strerror(errno));
goto err;
}
}
if (-1 == fstat(fd,&st)) {
if (complain)
fprintf(stderr,"fstat(%s): %s\n",device,strerror(errno));
goto err;
}
if (!S_ISCHR(st.st_mode)) {
if (complain)
fprintf(stderr,"%s: not a charcter device\n",device);
goto err;
}
if (major(st.st_rdev) != major) {
if (complain)
fprintf(stderr,"%s: wrong major number (expected %d, got %d)\n",
device, major, major(st.st_rdev));
goto err;
}
fcntl(fd,F_SETFD,FD_CLOEXEC);
return fd;
err:
if (-1 != fd)
if (1 == is_v4l2)
v4l2_close(fd);
else
close(fd);
return -1;
}
/* --------------------------------------------------------------------- */
struct ng_reader* ng_find_reader_magic(char *filename)
{
struct list_head *item;
struct ng_reader *reader;
char blk[512];
FILE *fp;
int m;
if (NULL == (fp = fopen(filename, "r"))) {
fprintf(stderr,"open %s: %s\n",filename,strerror(errno));
return NULL;
}
memset(blk,0,sizeof(blk));
fread(blk,1,sizeof(blk),fp);
fclose(fp);
list_for_each(item,&ng_readers) {
reader = list_entry(item, struct ng_reader, list);
for (m = 0; m < 8 && reader->mlen[m] > 0; m++) {
if (0 == memcmp(blk+reader->moff[m],reader->magic[m],
reader->mlen[m]))
return reader;
}
}
if (ng_debug)
fprintf(stderr,"%s: no reader found [magic]\n",filename);
return NULL;
}
struct ng_reader* ng_find_reader_name(char *name)
{
struct list_head *item;
struct ng_reader *reader;
list_for_each(item,&ng_readers) {
reader = list_entry(item, struct ng_reader, list);
if (0 == strcasecmp(reader->name,name))
return reader;
}
if (ng_debug)
fprintf(stderr,"%s: no reader found [name]\n",name);
return NULL;
}
struct ng_writer* ng_find_writer_name(char *name)
{
struct list_head *item;
struct ng_writer *writer;
list_for_each(item,&ng_writers) {
writer = list_entry(item, struct ng_writer, list);
if (0 == strcasecmp(writer->name,name))
return writer;
}
if (ng_debug)
fprintf(stderr,"%s: no writer found [name]\n",name);
return NULL;
}
int64_t
ng_tofday_to_timestamp(struct timeval *tv)
{
long long ts;
ts = tv->tv_sec;
ts *= 1000000;
ts += tv->tv_usec;
ts *= 1000;
return ts;
}
int64_t
ng_get_timestamp()
{
struct timeval tv;
gettimeofday(&tv,NULL);
return ng_tofday_to_timestamp(&tv);
}
struct ng_video_buf*
ng_filter_single(struct ng_video_filter *filter, struct ng_video_buf *in)
{
struct ng_video_buf *out = in;
void *handle;
if (NULL != filter && filter->fmts & (1 << in->fmt.fmtid)) {
handle = filter->init(&in->fmt);
#if 0
BUG_ON(1,"not fixed yet");
out = filter->frame(handle,in);
filter->fini(handle);
#endif
}
return out;
}
/* --------------------------------------------------------------------- */
static void clip_dump(char *state, struct OVERLAY_CLIP *oc, int count)
{
int i;
fprintf(stderr,"clip: %s - %d clips\n",state,count);
for (i = 0; i < count; i++)
fprintf(stderr,"clip: %d: %dx%d+%d+%d\n",i,
oc[i].x2 - oc[i].x1,
oc[i].y2 - oc[i].y1,
oc[i].x1, oc[i].y1);
}
static void clip_drop(struct OVERLAY_CLIP *oc, int n, int *count)
{
(*count)--;
memmove(oc+n, oc+n+1, sizeof(struct OVERLAY_CLIP) * (*count-n));
}
void ng_check_clipping(int width, int height, int xadjust, int yadjust,
struct OVERLAY_CLIP *oc, int *count)
{
int i,j;
if (ng_debug > 1) {
fprintf(stderr,"clip: win=%dx%d xa=%d ya=%d\n",
width,height,xadjust,yadjust);
clip_dump("init",oc,*count);
}
for (i = 0; i < *count; i++) {
/* fixup coordinates */
oc[i].x1 += xadjust;
oc[i].x2 += xadjust;
oc[i].y1 += yadjust;
oc[i].y2 += yadjust;
}
if (ng_debug > 1)
clip_dump("fixup adjust",oc,*count);
for (i = 0; i < *count; i++) {
/* fixup borders */
if (oc[i].x1 < 0)
oc[i].x1 = 0;
if (oc[i].x2 < 0)
oc[i].x2 = 0;
if (oc[i].x1 > width)
oc[i].x1 = width;
if (oc[i].x2 > width)
oc[i].x2 = width;
if (oc[i].y1 < 0)
oc[i].y1 = 0;
if (oc[i].y2 < 0)
oc[i].y2 = 0;
if (oc[i].y1 > height)
oc[i].y1 = height;
if (oc[i].y2 > height)
oc[i].y2 = height;
}
if (ng_debug > 1)
clip_dump("fixup range",oc,*count);
/* drop zero-sized clips */
for (i = 0; i < *count;) {
if (oc[i].x1 == oc[i].x2 || oc[i].y1 == oc[i].y2) {
clip_drop(oc,i,count);
continue;
}
i++;
}
if (ng_debug > 1)
clip_dump("zerosize done",oc,*count);
/* try to merge clips */
restart_merge:
for (j = *count - 1; j >= 0; j--) {
for (i = 0; i < *count; i++) {
if (i == j)
continue;
if (oc[i].x1 == oc[j].x1 &&
oc[i].x2 == oc[j].x2 &&
oc[i].y1 <= oc[j].y1 &&
oc[i].y2 >= oc[j].y1) {
if (ng_debug > 1)
fprintf(stderr,"clip: merge y %d,%d\n",i,j);
if (oc[i].y2 < oc[j].y2)
oc[i].y2 = oc[j].y2;
clip_drop(oc,j,count);
if (ng_debug > 1)
clip_dump("merge y done",oc,*count);
goto restart_merge;
}
if (oc[i].y1 == oc[j].y1 &&
oc[i].y2 == oc[j].y2 &&
oc[i].x1 <= oc[j].x1 &&
oc[i].x2 >= oc[j].x1) {
if (ng_debug > 1)
fprintf(stderr,"clip: merge x %d,%d\n",i,j);
if (oc[i].x2 < oc[j].x2)
oc[i].x2 = oc[j].x2;
clip_drop(oc,j,count);
if (ng_debug > 1)
clip_dump("merge x done",oc,*count);
goto restart_merge;
}
}
}
if (ng_debug)
clip_dump("final",oc,*count);
}
/* --------------------------------------------------------------------- */
#if 0
void ng_print_stacktrace(void)
{
void *array[16];
size_t size;
char **strings;
size_t i;
size = backtrace(array, DIMOF(array));
strings = backtrace_symbols(array, size);
for (i = 0; i < size; i++)
fprintf(stderr, "\t%s\n", strings[i]);
free(strings);
}
#endif
static int ng_plugins(char *dirname)
{
struct dirent **list;
char filename[1024];
void *plugin;
#if 1
void (*initcall)(void);
#endif
int i,n = 0,l = 0;
n = scandir(dirname,&list,NULL,alphasort);
if (n <= 0)
return 0;
for (i = 0; i < n; i++) {
if (0 != fnmatch("*.so",list[i]->d_name,0))
continue;
sprintf(filename,"%s/%s",dirname,list[i]->d_name);
if (NULL == (plugin = dlopen(filename,RTLD_NOW))) {
fprintf(stderr,"dlopen: %s\n",dlerror());
continue;
}
if (NULL == (initcall = dlsym(plugin,"ng_plugin_init"))) {
if (NULL == (initcall = dlsym(plugin,"_ng_plugin_init"))) {
continue;
}
}
#if 0
initcall();
#endif
l++;
}
for (i = 0; i < n; i++)
free(list[i]);
free(list);
return l;
}
void
ng_init(void)
{
static int once=0;
int count=0;
if (once++) {
fprintf(stderr,"panic: ng_init called twice\n");
return;
}
yuv2rgb_init();
packed_init();
/* dirty hack: touch ng_dev to make ld _not_ drop devices.o, it is
* needed by various plugins */
if (!ng_dev.video[0])
return;
#ifdef LIBDIR
count += ng_plugins(LIBDIR);
#endif
count += ng_plugins("./libng/plugins");
count += ng_plugins("./libng/contrib-plugins");
count += ng_plugins("../libng/plugins");
count += ng_plugins("../libng/contrib-plugins");
count += ng_plugins("./utils/linux/capture/libng/plugins");
count += ng_plugins("./utils/linux/capture/libng/contrib-plugins");
/*
if (0 == count)
fprintf(stderr,"WARNING: no plugins found [%s]\n",LIBDIR);
*/
}
amsn-0.98.9/utils/linux/capture/libng/README 0000644 0001750 0001750 00000001125 10246003435 020302 0 ustar billiob billiob
WARNING: This is work-in-progress.
In the long run I plan to turn this into a v4l capture library. But
that isn't finished yet and probably will not for some time. Some
documentation can be found in OVERVIEW. Complete reference is not
available.
I don't care (yet) about backward compatibility. I neither can nor
will stop you from using the code. But if you do don't complain if I
break your applications with incompatible changes. You have been
warned.
Please don't distribute this code as shared library. This is just
asking for trouble.
Gerd
--
Gerd Knorr
amsn-0.98.9/utils/linux/capture/libng/videodev.h 0000644 0001750 0001750 00000027055 10246003435 021412 0 ustar billiob billiob #ifndef __LINUX_VIDEODEV_H
#define __LINUX_VIDEODEV_H
#include
#define VID_TYPE_CAPTURE 1 /* Can capture */
#define VID_TYPE_TUNER 2 /* Can tune */
#define VID_TYPE_TELETEXT 4 /* Does teletext */
#define VID_TYPE_OVERLAY 8 /* Overlay onto frame buffer */
#define VID_TYPE_CHROMAKEY 16 /* Overlay by chromakey */
#define VID_TYPE_CLIPPING 32 /* Can clip */
#define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */
#define VID_TYPE_SCALES 128 /* Scalable */
#define VID_TYPE_MONOCHROME 256 /* Monochrome only */
#define VID_TYPE_SUBCAPTURE 512 /* Can capture subareas of the image */
#define VID_TYPE_MPEG_DECODER 1024 /* Can decode MPEG streams */
#define VID_TYPE_MPEG_ENCODER 2048 /* Can encode MPEG streams */
#define VID_TYPE_MJPEG_DECODER 4096 /* Can decode MJPEG streams */
#define VID_TYPE_MJPEG_ENCODER 8192 /* Can encode MJPEG streams */
struct video_capability
{
char name[32];
unsigned int type;
unsigned int channels; /* Num channels */
unsigned int audios; /* Num audio devices */
unsigned int maxwidth; /* Supported width */
unsigned int maxheight; /* And height */
unsigned int minwidth; /* Supported width */
unsigned int minheight; /* And height */
};
struct video_channel
{
int channel;
char name[32];
int tuners;
__u32 flags;
#define VIDEO_VC_TUNER 1 /* Channel has a tuner */
#define VIDEO_VC_AUDIO 2 /* Channel has audio */
__u16 type;
#define VIDEO_TYPE_TV 1
#define VIDEO_TYPE_CAMERA 2
__u16 norm; /* Norm set by channel */
};
struct video_tuner
{
int tuner;
char name[32];
unsigned long rangelow, rangehigh; /* Tuner range */
__u32 flags;
#define VIDEO_TUNER_PAL 1
#define VIDEO_TUNER_NTSC 2
#define VIDEO_TUNER_SECAM 4
#define VIDEO_TUNER_LOW 8 /* Uses KHz not MHz */
#define VIDEO_TUNER_NORM 16 /* Tuner can set norm */
#define VIDEO_TUNER_STEREO_ON 128 /* Tuner is seeing stereo */
#define VIDEO_TUNER_RDS_ON 256 /* Tuner is seeing an RDS datastream */
#define VIDEO_TUNER_MBS_ON 512 /* Tuner is seeing an MBS datastream */
__u16 mode; /* PAL/NTSC/SECAM/OTHER */
#define VIDEO_MODE_PAL 0
#define VIDEO_MODE_NTSC 1
#define VIDEO_MODE_SECAM 2
#define VIDEO_MODE_AUTO 3
__u16 signal; /* Signal strength 16bit scale */
};
struct video_picture
{
__u16 brightness;
__u16 hue;
__u16 colour;
__u16 contrast;
__u16 whiteness; /* Black and white only */
__u16 depth; /* Capture depth */
__u16 palette; /* Palette in use */
#define VIDEO_PALETTE_GREY 1 /* Linear greyscale */
#define VIDEO_PALETTE_HI240 2 /* High 240 cube (BT848) */
#define VIDEO_PALETTE_RGB565 3 /* 565 16 bit RGB */
#define VIDEO_PALETTE_RGB24 4 /* 24bit RGB */
#define VIDEO_PALETTE_RGB32 5 /* 32bit RGB */
#define VIDEO_PALETTE_RGB555 6 /* 555 15bit RGB */
#define VIDEO_PALETTE_YUV422 7 /* YUV422 capture */
#define VIDEO_PALETTE_YUYV 8
#define VIDEO_PALETTE_UYVY 9 /* The great thing about standards is ... */
#define VIDEO_PALETTE_YUV420 10
#define VIDEO_PALETTE_YUV411 11 /* YUV411 capture */
#define VIDEO_PALETTE_RAW 12 /* RAW capture (BT848) */
#define VIDEO_PALETTE_YUV422P 13 /* YUV 4:2:2 Planar */
#define VIDEO_PALETTE_YUV411P 14 /* YUV 4:1:1 Planar */
#define VIDEO_PALETTE_YUV420P 15 /* YUV 4:2:0 Planar */
#define VIDEO_PALETTE_YUV410P 16 /* YUV 4:1:0 Planar */
#define VIDEO_PALETTE_PLANAR 13 /* start of planar entries */
#define VIDEO_PALETTE_COMPONENT 7 /* start of component entries */
};
struct video_audio
{
int audio; /* Audio channel */
__u16 volume; /* If settable */
__u16 bass, treble;
__u32 flags;
#define VIDEO_AUDIO_MUTE 1
#define VIDEO_AUDIO_MUTABLE 2
#define VIDEO_AUDIO_VOLUME 4
#define VIDEO_AUDIO_BASS 8
#define VIDEO_AUDIO_TREBLE 16
#define VIDEO_AUDIO_BALANCE 32
char name[16];
#define VIDEO_SOUND_MONO 1
#define VIDEO_SOUND_STEREO 2
#define VIDEO_SOUND_LANG1 4
#define VIDEO_SOUND_LANG2 8
__u16 mode;
__u16 balance; /* Stereo balance */
__u16 step; /* Step actual volume uses */
};
struct video_clip
{
__s32 x,y;
__s32 width, height;
struct video_clip *next; /* For user use/driver use only */
};
struct video_window
{
__u32 x,y; /* Position of window */
__u32 width,height; /* Its size */
__u32 chromakey;
__u32 flags;
struct video_clip *clips; /* Set only */
int clipcount;
#define VIDEO_WINDOW_INTERLACE 1
#define VIDEO_WINDOW_CHROMAKEY 16 /* Overlay by chromakey */
#define VIDEO_CLIP_BITMAP -1
/* bitmap is 1024x625, a '1' bit represents a clipped pixel */
#define VIDEO_CLIPMAP_SIZE (128 * 625)
};
struct video_capture
{
__u32 x,y; /* Offsets into image */
__u32 width, height; /* Area to capture */
__u16 decimation; /* Decimation divider */
__u16 flags; /* Flags for capture */
#define VIDEO_CAPTURE_ODD 0 /* Temporal */
#define VIDEO_CAPTURE_EVEN 1
};
struct video_buffer
{
void *base;
unsigned int height,width;
unsigned int depth;
unsigned int bytesperline;
};
struct video_mmap
{
unsigned int frame; /* Frame (0 - n) for double buffer */
int height,width;
unsigned int format; /* should be VIDEO_PALETTE_* */
};
struct video_key
{
__u8 key[8];
__u32 flags;
};
#define VIDEO_MAX_FRAME 32
struct video_mbuf
{
int size; /* Total memory to map */
int frames; /* Frames */
int offsets[VIDEO_MAX_FRAME];
};
#define VIDEO_NO_UNIT (-1)
struct video_unit
{
int video; /* Video minor */
int vbi; /* VBI minor */
int radio; /* Radio minor */
int audio; /* Audio minor */
int teletext; /* Teletext minor */
};
struct vbi_format {
__u32 sampling_rate; /* in Hz */
__u32 samples_per_line;
__u32 sample_format; /* VIDEO_PALETTE_RAW only (1 byte) */
__s32 start[2]; /* starting line for each frame */
__u32 count[2]; /* count of lines for each frame */
__u32 flags;
#define VBI_UNSYNC 1 /* can distingues between top/bottom field */
#define VBI_INTERLACED 2 /* lines are interlaced */
};
/* video_info is biased towards hardware mpeg encode/decode */
/* but it could apply generically to any hardware compressor/decompressor */
struct video_info
{
__u32 frame_count; /* frames output since decode/encode began */
__u32 h_size; /* current unscaled horizontal size */
__u32 v_size; /* current unscaled veritcal size */
__u32 smpte_timecode; /* current SMPTE timecode (for current GOP) */
__u32 picture_type; /* current picture type */
__u32 temporal_reference; /* current temporal reference */
__u8 user_data[256]; /* user data last found in compressed stream */
/* user_data[0] contains user data flags, user_data[1] has count */
};
/* generic structure for setting playback modes */
struct video_play_mode
{
int mode;
int p1;
int p2;
};
/* for loading microcode / fpga programming */
struct video_code
{
char loadwhat[16]; /* name or tag of file being passed */
int datasize;
__u8 *data;
};
#define VIDIOCGCAP _IOR('v',1,struct video_capability) /* Get capabilities */
#define VIDIOCGCHAN _IOWR('v',2,struct video_channel) /* Get channel info (sources) */
#define VIDIOCSCHAN _IOW('v',3,struct video_channel) /* Set channel */
#define VIDIOCGTUNER _IOWR('v',4,struct video_tuner) /* Get tuner abilities */
#define VIDIOCSTUNER _IOW('v',5,struct video_tuner) /* Tune the tuner for the current channel */
#define VIDIOCGPICT _IOR('v',6,struct video_picture) /* Get picture properties */
#define VIDIOCSPICT _IOW('v',7,struct video_picture) /* Set picture properties */
#define VIDIOCCAPTURE _IOW('v',8,int) /* Start, end capture */
#define VIDIOCGWIN _IOR('v',9, struct video_window) /* Get the video overlay window */
#define VIDIOCSWIN _IOW('v',10, struct video_window) /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */
#define VIDIOCGFBUF _IOR('v',11, struct video_buffer) /* Get frame buffer */
#define VIDIOCSFBUF _IOW('v',12, struct video_buffer) /* Set frame buffer - root only */
#define VIDIOCKEY _IOR('v',13, struct video_key) /* Video key event - to dev 255 is to all - cuts capture on all DMA windows with this key (0xFFFFFFFF == all) */
#define VIDIOCGFREQ _IOR('v',14, unsigned long) /* Set tuner */
#define VIDIOCSFREQ _IOW('v',15, unsigned long) /* Set tuner */
#define VIDIOCGAUDIO _IOR('v',16, struct video_audio) /* Get audio info */
#define VIDIOCSAUDIO _IOW('v',17, struct video_audio) /* Audio source, mute etc */
#define VIDIOCSYNC _IOW('v',18, int) /* Sync with mmap grabbing */
#define VIDIOCMCAPTURE _IOW('v',19, struct video_mmap) /* Grab frames */
#define VIDIOCGMBUF _IOR('v',20, struct video_mbuf) /* Memory map buffer info */
#define VIDIOCGUNIT _IOR('v',21, struct video_unit) /* Get attached units */
#define VIDIOCGCAPTURE _IOR('v',22, struct video_capture) /* Get subcapture */
#define VIDIOCSCAPTURE _IOW('v',23, struct video_capture) /* Set subcapture */
#define VIDIOCSPLAYMODE _IOW('v',24, struct video_play_mode) /* Set output video mode/feature */
#define VIDIOCSWRITEMODE _IOW('v',25, int) /* Set write mode */
#define VIDIOCGPLAYINFO _IOR('v',26, struct video_info) /* Get current playback info from hardware */
#define VIDIOCSMICROCODE _IOW('v',27, struct video_code) /* Load microcode into hardware */
#define VIDIOCGVBIFMT _IOR('v',28, struct vbi_format) /* Get VBI information */
#define VIDIOCSVBIFMT _IOW('v',29, struct vbi_format) /* Set VBI information */
#define BASE_VIDIOCPRIVATE 192 /* 192-255 are private */
/* VIDIOCSWRITEMODE */
#define VID_WRITE_MPEG_AUD 0
#define VID_WRITE_MPEG_VID 1
#define VID_WRITE_OSD 2
#define VID_WRITE_TTX 3
#define VID_WRITE_CC 4
#define VID_WRITE_MJPEG 5
/* VIDIOCSPLAYMODE */
#define VID_PLAY_VID_OUT_MODE 0
/* p1: = VIDEO_MODE_PAL, VIDEO_MODE_NTSC, etc ... */
#define VID_PLAY_GENLOCK 1
/* p1: 0 = OFF, 1 = ON */
/* p2: GENLOCK FINE DELAY value */
#define VID_PLAY_NORMAL 2
#define VID_PLAY_PAUSE 3
#define VID_PLAY_SINGLE_FRAME 4
#define VID_PLAY_FAST_FORWARD 5
#define VID_PLAY_SLOW_MOTION 6
#define VID_PLAY_IMMEDIATE_NORMAL 7
#define VID_PLAY_SWITCH_CHANNELS 8
#define VID_PLAY_FREEZE_FRAME 9
#define VID_PLAY_STILL_MODE 10
#define VID_PLAY_MASTER_MODE 11
/* p1: see below */
#define VID_PLAY_MASTER_NONE 1
#define VID_PLAY_MASTER_VIDEO 2
#define VID_PLAY_MASTER_AUDIO 3
#define VID_PLAY_ACTIVE_SCANLINES 12
/* p1 = first active; p2 = last active */
#define VID_PLAY_RESET 13
#define VID_PLAY_END_MARK 14
#define VID_HARDWARE_BT848 1
#define VID_HARDWARE_QCAM_BW 2
#define VID_HARDWARE_PMS 3
#define VID_HARDWARE_QCAM_C 4
#define VID_HARDWARE_PSEUDO 5
#define VID_HARDWARE_SAA5249 6
#define VID_HARDWARE_AZTECH 7
#define VID_HARDWARE_SF16MI 8
#define VID_HARDWARE_RTRACK 9
#define VID_HARDWARE_ZOLTRIX 10
#define VID_HARDWARE_SAA7146 11
#define VID_HARDWARE_VIDEUM 12 /* Reserved for Winnov videum */
#define VID_HARDWARE_RTRACK2 13
#define VID_HARDWARE_PERMEDIA2 14 /* Reserved for Permedia2 */
#define VID_HARDWARE_RIVA128 15 /* Reserved for RIVA 128 */
#define VID_HARDWARE_PLANB 16 /* PowerMac motherboard video-in */
#define VID_HARDWARE_BROADWAY 17 /* Broadway project */
#define VID_HARDWARE_GEMTEK 18
#define VID_HARDWARE_TYPHOON 19
#define VID_HARDWARE_VINO 20 /* SGI Indy Vino */
#define VID_HARDWARE_CADET 21 /* Cadet radio */
#define VID_HARDWARE_TRUST 22 /* Trust FM Radio */
#define VID_HARDWARE_TERRATEC 23 /* TerraTec ActiveRadio */
#define VID_HARDWARE_CPIA 24
#define VID_HARDWARE_ZR36120 25 /* Zoran ZR36120/ZR36125 */
#define VID_HARDWARE_ZR36067 26 /* Zoran ZR36067/36060 */
#define VID_HARDWARE_OV511 27
#define VID_HARDWARE_ZR356700 28 /* Zoran 36700 series */
#define VID_HARDWARE_W9966 29
#define VID_HARDWARE_SE401 30 /* SE401 USB webcams */
#define VID_HARDWARE_PWC 31 /* Philips webcams */
#define VID_HARDWARE_MEYE 32 /* Sony Vaio MotionEye cameras */
#define VID_HARDWARE_CPIA2 33
#define VID_HARDWARE_VICAM 34
#endif /* __LINUX_VIDEODEV_H */
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
amsn-0.98.9/utils/linux/capture/libng/videodev2-old.h 0000644 0001750 0001750 00000064540 10246003435 022250 0 ustar billiob billiob #ifndef __LINUX_VIDEODEV2_H
#define __LINUX_VIDEODEV2_H
/*
* Video for Linux Two
*
* Header file for v4l or V4L2 drivers and applications, for
* Linux kernels 2.2.x or 2.4.x.
*
* See http://www.thedirks.org/v4l2/ for API specs and other
* v4l2 documentation.
*
* Author: Bill Dirks
* Justin Schoeman
* et al.
*/
#define V4L2_MAJOR_VERSION 0
#define V4L2_MINOR_VERSION 20
/*
* M I S C E L L A N E O U S
*/
/* Four-character-code (FOURCC) */
#define v4l2_fourcc(a,b,c,d)\
(((__u32)(a)<<0)|((__u32)(b)<<8)|((__u32)(c)<<16)|((__u32)(d)<<24))
/* Open flag for non-capturing opens on capture devices */
#define O_NONCAP O_TRUNC
#define O_NOIO O_TRUNC
/* Timestamp data type, 64-bit signed integer, in nanoseconds */
#ifndef STAMP_T
#define STAMP_T
typedef __s64 stamp_t;
#endif
/*
* D R I V E R C A P A B I L I T I E S
*/
struct v4l2_capability
{
char name[32]; /* Descriptive, and unique */
unsigned int type; /* Device type, see below */
unsigned int inputs; /* Num video inputs */
unsigned int outputs; /* Num video outputs */
unsigned int audios; /* Num audio devices */
unsigned int maxwidth;
unsigned int maxheight;
unsigned int minwidth;
unsigned int minheight;
unsigned int maxframerate;
__u32 flags; /* Feature flags, see below */
__u32 reserved[4];
};
/* Values for 'type' field */
#define V4L2_TYPE_CAPTURE 0 /* Is a video capture device */
#define V4L2_TYPE_CODEC 1 /* Is a CODEC device */
#define V4L2_TYPE_OUTPUT 2 /* Is a video output device */
#define V4L2_TYPE_FX 3 /* Is a video effects device */
#define V4L2_TYPE_VBI 4 /* Is a VBI capture device */
#define V4L2_TYPE_VTR 5 /* Is a tape recorder controller */
#define V4L2_TYPE_VTX 6 /* Is a teletext device */
#define V4L2_TYPE_RADIO 7 /* Is a radio device */
#define V4L2_TYPE_VBI_INPUT 4 /* Is a VBI capture device */
#define V4L2_TYPE_VBI_OUTPUT 9 /* Is a VBI output device */
#define V4L2_TYPE_PRIVATE 1000 /* Start of driver private types */
/* Flags for 'flags' field */
#define V4L2_FLAG_READ 0x00001 /* Can capture via read() call */
#define V4L2_FLAG_WRITE 0x00002 /* Can accept data via write() */
#define V4L2_FLAG_STREAMING 0x00004 /* Can capture streaming video */
#define V4L2_FLAG_PREVIEW 0x00008 /* Can do automatic preview */
#define V4L2_FLAG_SELECT 0x00010 /* Supports the select() call */
#define V4L2_FLAG_TUNER 0x00020 /* Can tune */
#define V4L2_FLAG_MONOCHROME 0x00040 /* Monochrome only */
#define V4L2_FLAG_DATA_SERVICE 0x00080 /* Has a related data service dev. */
/*
* V I D E O I M A G E F O R M A T
*/
struct v4l2_pix_format
{
__u32 width;
__u32 height;
__u32 depth;
__u32 pixelformat;
__u32 flags;
__u32 bytesperline; /* only used when there are pad bytes */
__u32 sizeimage;
__u32 priv; /* private data, depends on pixelformat */
};
/* Pixel format FOURCC depth Description */
#define V4L2_PIX_FMT_RGB332 v4l2_fourcc('R','G','B','1') /* 8 RGB-3-3-2 */
#define V4L2_PIX_FMT_RGB555 v4l2_fourcc('R','G','B','O') /* 16 RGB-5-5-5 */
#define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R','G','B','P') /* 16 RGB-5-6-5 */
#define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R','G','B','Q') /* 16 RGB-5-5-5 BE */
#define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R','G','B','R') /* 16 RGB-5-6-5 BE */
#define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B','G','R','3') /* 24 BGR-8-8-8 */
#define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R','G','B','3') /* 24 RGB-8-8-8 */
#define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B','G','R','4') /* 32 BGR-8-8-8-8 */
#define V4L2_PIX_FMT_RGB32 v4l2_fourcc('R','G','B','4') /* 32 RGB-8-8-8-8 */
#define V4L2_PIX_FMT_GREY v4l2_fourcc('G','R','E','Y') /* 8 Greyscale */
#define V4L2_PIX_FMT_YVU410 v4l2_fourcc('Y','V','U','9') /* 9 YVU 4:1:0 */
#define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y','V','1','2') /* 12 YVU 4:2:0 */
#define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y','U','Y','V') /* 16 YUV 4:2:2 */
#define V4L2_PIX_FMT_UYVY v4l2_fourcc('U','Y','V','Y') /* 16 YUV 4:2:2 */
#if 0
#define V4L2_PIX_FMT_YVU422P v4l2_fourcc('4','2','2','P') /* 16 YVU422 planar */
#define V4L2_PIX_FMT_YVU411P v4l2_fourcc('4','1','1','P') /* 16 YVU411 planar */
#endif
#define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4','2','2','P') /* 16 YVU422 planar */
#define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4','1','1','P') /* 16 YVU411 planar */
#define V4L2_PIX_FMT_Y41P v4l2_fourcc('Y','4','1','P') /* 12 YUV 4:1:1 */
/* two planes -- one Y, one Cr + Cb interleaved */
#define V4L2_PIX_FMT_NV12 v4l2_fourcc('N','V','1','2') /* 12 Y/CbCr 4:2:0 */
#define V4L2_PIX_FMT_NV21 v4l2_fourcc('N','V','2','1') /* 12 Y/CrCb 4:2:0 */
/* The following formats are not defined in the V4L2 specification */
#define V4L2_PIX_FMT_YUV410 v4l2_fourcc('Y','U','V','9') /* 9 YUV 4:1:0 */
#define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y','U','1','2') /* 12 YUV 4:2:0 */
#define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y','Y','U','V') /* 16 YUV 4:2:2 */
#define V4L2_PIX_FMT_HI240 v4l2_fourcc('H','I','2','4') /* 8 8-bit color */
/* Vendor-specific formats */
#define V4L2_PIX_FMT_WNVA v4l2_fourcc('W','N','V','A') /* Winnov hw compres */
/* Flags */
#define V4L2_FMT_FLAG_COMPRESSED 0x0001 /* Compressed format */
#define V4L2_FMT_FLAG_BYTESPERLINE 0x0002 /* bytesperline field valid */
#define V4L2_FMT_FLAG_NOT_INTERLACED 0x0000
#define V4L2_FMT_FLAG_INTERLACED 0x0004 /* Image is interlaced */
#define V4L2_FMT_FLAG_TOPFIELD 0x0008 /* is a top field only */
#define V4L2_FMT_FLAG_BOTFIELD 0x0010 /* is a bottom field only */
#define V4L2_FMT_FLAG_ODDFIELD V4L2_FMT_FLAG_TOPFIELD
#define V4L2_FMT_FLAG_EVENFIELD V4L2_FMT_FLAG_BOTFIELD
#define V4L2_FMT_FLAG_COMBINED V4L2_FMT_FLAG_INTERLACED
#define V4L2_FMT_FLAG_FIELD_field 0x001C
#define V4L2_FMT_CS_field 0xF000 /* Color space field mask */
#define V4L2_FMT_CS_601YUV 0x1000 /* ITU YCrCb color space */
#define V4L2_FMT_FLAG_SWCONVERSION 0x0800 /* used only in format enum. */
/* SWCONVERSION indicates the format is not natively supported by the */
/* driver and the driver uses software conversion to support it */
/*
* F O R M A T E N U M E R A T I O N
*/
struct v4l2_fmtdesc
{
int index; /* Format number */
char description[32]; /* Description string */
__u32 pixelformat; /* Format fourcc */
__u32 flags; /* Format flags */
__u32 depth; /* Bits per pixel */
__u32 reserved[2];
};
struct v4l2_cvtdesc
{
int index;
struct
{
__u32 pixelformat;
__u32 flags;
__u32 depth;
__u32 reserved[2];
} in, out;
};
struct v4l2_fxdesc
{
int index;
char name[32];
__u32 flags;
__u32 inputs;
__u32 controls;
__u32 reserved[2];
};
/*
* T I M E C O D E
*/
struct v4l2_timecode
{
__u8 frames;
__u8 seconds;
__u8 minutes;
__u8 hours;
__u8 userbits[4];
__u32 flags;
__u32 type;
};
/* Type */
#define V4L2_TC_TYPE_24FPS 1
#define V4L2_TC_TYPE_25FPS 2
#define V4L2_TC_TYPE_30FPS 3
#define V4L2_TC_TYPE_50FPS 4
#define V4L2_TC_TYPE_60FPS 5
/* Flags */
#define V4L2_TC_FLAG_DROPFRAME 0x0001 /* "drop-frame" mode */
#define V4L2_TC_FLAG_COLORFRAME 0x0002
#define V4L2_TC_USERBITS_field 0x000C
#define V4L2_TC_USERBITS_USERDEFINED 0x0000
#define V4L2_TC_USERBITS_8BITCHARS 0x0008
/* The above is based on SMPTE timecodes */
/*
* C O M P R E S S I O N P A R A M E T E R S
*/
struct v4l2_compression
{
int quality;
int keyframerate;
int pframerate;
__u32 reserved[5];
};
/*
* M E M O R Y - M A P P I N G B U F F E R S
*/
struct v4l2_requestbuffers
{
int count;
__u32 type;
__u32 reserved[2];
};
struct v4l2_buffer
{
int index;
__u32 type;
__u32 offset;
__u32 length;
__u32 bytesused;
__u32 flags;
stamp_t timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
__u32 reserved[3];
};
/* Buffer type codes and flags for 'type' field */
#define V4L2_BUF_TYPE_field 0x00001FFF /* Type field mask */
#define V4L2_BUF_TYPE_CAPTURE 0x00000001
#define V4L2_BUF_TYPE_CODECIN 0x00000002
#define V4L2_BUF_TYPE_CODECOUT 0x00000003
#define V4L2_BUF_TYPE_EFFECTSIN 0x00000004
#define V4L2_BUF_TYPE_EFFECTSIN2 0x00000005
#define V4L2_BUF_TYPE_EFFECTSOUT 0x00000006
#define V4L2_BUF_TYPE_VIDEOOUT 0x00000007
#define V4L2_BUF_TYPE_FXCONTROL 0x00000008
#define V4L2_BUF_TYPE_VBI 0x00000009
/* Starting value of driver private buffer types */
#define V4L2_BUF_TYPE_PRIVATE 0x00001000
#define V4L2_BUF_ATTR_DEVICEMEM 0x00010000 /* Buffer is on device (flag) */
/* Flags used only in VIDIOC_REQBUFS */
#define V4L2_BUF_REQ_field 0xF0000000
#define V4L2_BUF_REQ_CONTIG 0x10000000 /* Map all buffers in one
contiguous mmap(). This flag
only used in VIDIOC_REQBUFS */
/* Flags for 'flags' field */
#define V4L2_BUF_FLAG_MAPPED 0x0001 /* Buffer is mapped (flag) */
#define V4L2_BUF_FLAG_QUEUED 0x0002 /* Buffer is queued for processing */
#define V4L2_BUF_FLAG_DONE 0x0004 /* Buffer is ready */
#define V4L2_BUF_FLAG_KEYFRAME 0x0008 /* Image is a keyframe (I-frame) */
#define V4L2_BUF_FLAG_PFRAME 0x0010 /* Image is a P-frame */
#define V4L2_BUF_FLAG_BFRAME 0x0020 /* Image is a B-frame */
#define V4L2_BUF_FLAG_TOPFIELD 0x0040 /* Image is a top field only */
#define V4L2_BUF_FLAG_BOTFIELD 0x0080 /* Image is a bottom field only */
#define V4L2_BUF_FLAG_ODDFIELD V4L2_BUF_FLAG_TOPFIELD
#define V4L2_BUF_FLAG_EVENFIELD V4L2_BUF_FLAG_BOTFIELD
#define V4L2_BUF_FLAG_TIMECODE 0x0100 /* timecode field is valid */
/*
* O V E R L A Y P R E V I E W
*/
struct v4l2_framebuffer
{
__u32 capability;
__u32 flags;
void *base[3];
struct v4l2_pix_format fmt;
};
/* Flags for the 'capability' field. Read only */
#define V4L2_FBUF_CAP_EXTERNOVERLAY 0x0001
#define V4L2_FBUF_CAP_CHROMAKEY 0x0002
#define V4L2_FBUF_CAP_CLIPPING 0x0004
#define V4L2_FBUF_CAP_SCALEUP 0x0008
#define V4L2_FBUF_CAP_SCALEDOWN 0x0010
#define V4L2_FBUF_CAP_BITMAP_CLIPPING 0x0020
/* Flags for the 'flags' field. */
#define V4L2_FBUF_FLAG_PRIMARY 0x0001
#define V4L2_FBUF_FLAG_OVERLAY 0x0002
#define V4L2_FBUF_FLAG_CHROMAKEY 0x0004
struct v4l2_clip
{
int x;
int y;
int width;
int height;
struct v4l2_clip *next;
};
struct v4l2_window
{
int x;
int y;
unsigned int width;
unsigned int height;
__u32 chromakey;
struct v4l2_clip *clips;
int clipcount;
void *bitmap;
};
/*
* D E V I C E P E R F O R M A N C E
*/
struct v4l2_performance
{
int frames;
int framesdropped;
__u64 bytesin;
__u64 bytesout;
__u32 reserved[4];
};
/*
* C A P T U R E P A R A M E T E R S
*/
struct v4l2_captureparm
{
__u32 capability; /* Supported modes */
__u32 capturemode; /* Current mode */
unsigned long timeperframe; /* Time per frame in .1us units */
__u32 extendedmode; /* Driver-specific extensions */
__u32 reserved[4];
};
/* Flags for 'capability' and 'capturemode' fields */
#define V4L2_MODE_HIGHQUALITY 0x0001 /* High quality imaging mode */
//#define V4L2_MODE_VFLIP 0x0002 /* Flip image vertically */
//#define V4L2_MODE_HFLIP 0x0004 /* Flip image horizontally */
#define V4L2_CAP_TIMEPERFRAME 0x1000 /* timeperframe field is supported */
struct v4l2_outputparm
{
__u32 capability; /* Supported modes */
__u32 outputmode; /* Current mode */
unsigned long timeperframe; /* Time per frame in .1us units */
__u32 extendedmode; /* Driver-specific extensions */
__u32 reserved[4];
};
/*
* I N P U T I M A G E C R O P P I N G
*/
struct v4l2_cropcap
{
__u32 capability;
int min_x;
int min_y;
int max_x;
int max_y;
int default_left;
int default_top;
int default_right;
int default_bottom;
__u32 reserved[2];
};
struct v4l2_crop
{
int left;
int top;
int right;
int bottom;
__u32 reserved;
};
/*
* D I G I T A L Z O O M
*/
struct v4l2_zoomcap
{
__u32 capability;
__u32 maxwidth;
__u32 maxheight;
__u32 minwidth;
__u32 minheight;
__u32 reserved[2];
};
/* Flags for the capability field */
#define V4L2_ZOOM_NONCAP 0x0001
#define V4L2_ZOOM_WHILESTREAMING 0x0002
struct v4l2_zoom
{
__u32 x;
__u32 y;
__u32 width;
__u32 height;
__u32 reserved;
};
/*
* A N A L O G V I D E O S T A N D A R D
*/
struct v4l2_standard
{
__u8 name[24];
struct {
__u32 numerator;
__u32 denominator; /* >= 1 */
} framerate; /* Frames, not fields */
__u32 framelines;
__u32 reserved1;
__u32 colorstandard;
union {
struct {
__u32 colorsubcarrier; /* Hz */
} pal;
struct {
__u32 colorsubcarrier; /* Hz */
} ntsc;
struct {
__u32 f0b; /* Hz (blue) */
__u32 f0r; /* Hz (red) */
} secam;
__u8 reserved[12];
} colorstandard_data;
__u32 transmission; /* Bit field. Must be zero for
non-modulators/demodulators. */
__u32 reserved2; /* Must be set to zero */
};
/* Values for the 'colorstandard' field */
#define V4L2_COLOR_STD_PAL 1
#define V4L2_COLOR_STD_NTSC 2
#define V4L2_COLOR_STD_SECAM 3
/* Values for the color subcarrier fields */
#define V4L2_COLOR_SUBC_PAL 4433619 /* PAL BGHI, NTSC-44 */
#define V4L2_COLOR_SUBC_PAL_M 3575611 /* PAL M (Brazil) */
#define V4L2_COLOR_SUBC_PAL_N 3582056 /* PAL N */
#define V4L2_COLOR_SUBC_NTSC 3579545 /* NTSC M, NTSC-Japan */
#define V4L2_COLOR_SUBC_SECAMB 4250000 /* SECAM B - Y carrier */
#define V4L2_COLOR_SUBC_SECAMR 4406250 /* SECAM R - Y carrier */
/* Flags for the 'transmission' field */
#define V4L2_TRANSM_STD_B (1<<1)
#define V4L2_TRANSM_STD_D (1<<3)
#define V4L2_TRANSM_STD_G (1<<6)
#define V4L2_TRANSM_STD_H (1<<7)
#define V4L2_TRANSM_STD_I (1<<8)
#define V4L2_TRANSM_STD_K (1<<10)
#define V4L2_TRANSM_STD_K1 (1<<11)
#define V4L2_TRANSM_STD_L (1<<12)
#define V4L2_TRANSM_STD_M (1<<13)
#define V4L2_TRANSM_STD_N (1<<14)
/* Used in the VIDIOC_ENUMSTD ioctl for querying supported standards */
struct v4l2_enumstd
{
int index;
struct v4l2_standard std;
__u32 inputs; /* set of inputs that */
/* support this standard */
__u32 outputs; /* set of outputs that */
/* support this standard */
__u32 reserved[2];
};
/*
* V I D E O I N P U T S
*/
struct v4l2_input
{
int index; /* Which input */
char name[32]; /* Label */
int type; /* Type of input */
__u32 capability; /* Capability flags */
int assoc_audio; /* Associated audio input */
__u32 reserved[4];
};
/* Values for the 'type' field */
#define V4L2_INPUT_TYPE_TUNER 1
#define V4L2_INPUT_TYPE_CAMERA 2
/* Flags for the 'capability' field */
#define V4L2_INPUT_CAP_AUDIO 0x0001 /* assoc_audio */
/*
* V I D E O O U T P U T S
*/
struct v4l2_output
{
int index; /* Which output */
char name[32]; /* Label */
int type; /* Type of output */
__u32 capability; /* Capability flags */
int assoc_audio; /* Associated audio */
__u32 reserved[4];
};
/* Values for the 'type' field */
#define V4L2_OUTPUT_TYPE_MODULATOR 1
#define V4L2_OUTPUT_TYPE_ANALOG 2
#define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY 3
/* Flags for the 'capability' field */
#define V4L2_OUTPUT_CAP_AUDIO 0x0001 /* assoc_audio */
/*
* C O N T R O L S
*/
struct v4l2_control
{
__u32 id;
int value;
};
/* Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
struct v4l2_queryctrl
{
__u32 id;
__u8 name[32]; /* Whatever */
int minimum; /* Note signedness */
int maximum;
unsigned int step;
int default_value;
__u32 type;
__u32 flags;
__u32 category; /* Automatically filled in by V4L2 */
__u8 group[32]; /* for pre-defined controls */
__u32 reserved[2];
};
/* Used in the VIDIOC_QUERYMENU ioctl for querying menu items */
struct v4l2_querymenu
{
__u32 id;
int index;
__u8 name[32]; /* Whatever */
int reserved;
};
/* Used in V4L2_BUF_TYPE_FXCONTROL buffers */
struct v4l2_fxcontrol
{
__u32 id;
__u32 value;
};
/* Control types */
#define V4L2_CTRL_TYPE_INTEGER 0
#define V4L2_CTRL_TYPE_BOOLEAN 1
#define V4L2_CTRL_TYPE_MENU 2
#define V4L2_CTRL_TYPE_BUTTON 3
/* Control flags */
#define V4L2_CTRL_FLAG_DISABLED 0x0001
#define V4L2_CTRL_FLAG_GRABBED 0x0002
/* Control categories */
#define V4L2_CTRL_CAT_VIDEO 1 /* "Video" */
#define V4L2_CTRL_CAT_AUDIO 2 /* "Audio" */
#define V4L2_CTRL_CAT_EFFECT 3 /* "Effect" */
/* Control IDs defined by V4L2 */
#define V4L2_CID_BASE 0x00980900
/* IDs reserved for driver specific controls */
#define V4L2_CID_PRIVATE_BASE 0x08000000
/* IDs reserved for effect-specific controls on effects devices */
#define V4L2_CID_EFFECT_BASE 0x0A00B000
#define V4L2_CID_BRIGHTNESS (V4L2_CID_BASE+0)
#define V4L2_CID_CONTRAST (V4L2_CID_BASE+1)
#define V4L2_CID_SATURATION (V4L2_CID_BASE+2)
#define V4L2_CID_HUE (V4L2_CID_BASE+3)
#define V4L2_CID_AUDIO_VOLUME (V4L2_CID_BASE+5)
#define V4L2_CID_AUDIO_BALANCE (V4L2_CID_BASE+6)
#define V4L2_CID_AUDIO_BASS (V4L2_CID_BASE+7)
#define V4L2_CID_AUDIO_TREBLE (V4L2_CID_BASE+8)
#define V4L2_CID_AUDIO_MUTE (V4L2_CID_BASE+9)
#define V4L2_CID_AUDIO_LOUDNESS (V4L2_CID_BASE+10)
#define V4L2_CID_BLACK_LEVEL (V4L2_CID_BASE+11)
#define V4L2_CID_AUTO_WHITE_BALANCE (V4L2_CID_BASE+12)
#define V4L2_CID_DO_WHITE_BALANCE (V4L2_CID_BASE+13)
#define V4L2_CID_RED_BALANCE (V4L2_CID_BASE+14)
#define V4L2_CID_BLUE_BALANCE (V4L2_CID_BASE+15)
#define V4L2_CID_GAMMA (V4L2_CID_BASE+16)
#define V4L2_CID_WHITENESS (V4L2_CID_GAMMA) /* ? Not sure */
#define V4L2_CID_EXPOSURE (V4L2_CID_BASE+17)
#define V4L2_CID_AUTOGAIN (V4L2_CID_BASE+18)
#define V4L2_CID_GAIN (V4L2_CID_BASE+19)
#define V4L2_CID_HFLIP (V4L2_CID_BASE+20)
#define V4L2_CID_VFLIP (V4L2_CID_BASE+21)
#define V4L2_CID_HCENTER (V4L2_CID_BASE+22)
#define V4L2_CID_VCENTER (V4L2_CID_BASE+23)
#define V4L2_CID_LASTP1 (V4L2_CID_BASE+24) /* last CID + 1 */
/* Remember to change fill_ctrl_category() in videodev.c */
/*
* T U N I N G
*/
struct v4l2_tuner
{
int input;
char name[32];
struct v4l2_standard std;
__u32 capability;
__u32 rangelow;
__u32 rangehigh;
__u32 rxsubchans;
__u32 audmode;
int signal;
int afc;
__u32 reserved[4];
};
struct v4l2_modulator
{
int output;
char name[32];
struct v4l2_standard std;
__u32 capability;
__u32 rangelow;
__u32 rangehigh;
__u32 txsubchans;
__u32 reserved[4];
};
/* Flags for the 'capability' field */
#define V4L2_TUNER_CAP_LOW 0x0001
#define V4L2_TUNER_CAP_NORM 0x0002
#define V4L2_TUNER_CAP_STEREO 0x0010
#define V4L2_TUNER_CAP_LANG2 0x0020
#define V4L2_TUNER_CAP_SAP 0x0020
#define V4L2_TUNER_CAP_LANG1 0x0040
/* Flags for the 'rxsubchans' field */
#define V4L2_TUNER_SUB_MONO 0x0001
#define V4L2_TUNER_SUB_STEREO 0x0002
#define V4L2_TUNER_SUB_LANG2 0x0004
#define V4L2_TUNER_SUB_SAP 0x0004
#define V4L2_TUNER_SUB_LANG1 0x0008
/* Values for the 'audmode' field */
#define V4L2_TUNER_MODE_MONO 0x0000
#define V4L2_TUNER_MODE_STEREO 0x0001
#define V4L2_TUNER_MODE_LANG2 0x0002
#define V4L2_TUNER_MODE_SAP 0x0002
#define V4L2_TUNER_MODE_LANG1 0x0003
struct v4l2_frequency
{
int input;
__u32 frequency;
__u32 reserved[2];
};
/*
* A U D I O
*/
struct v4l2_audio
{
int audio;
char name[32];
__u32 capability;
__u32 mode;
__u32 reserved[2];
};
/* Flags for the 'capability' field */
#define V4L2_AUDCAP_EFFECTS 0x0020
#define V4L2_AUDCAP_LOUDNESS 0x0040
#define V4L2_AUDCAP_AVL 0x0080
/* Flags for the 'mode' field */
#define V4L2_AUDMODE_LOUDNESS 0x00002
#define V4L2_AUDMODE_AVL 0x00004
#define V4L2_AUDMODE_STEREO_field 0x0FF00
#define V4L2_AUDMODE_STEREO_LINEAR 0x00100
#define V4L2_AUDMODE_STEREO_PSEUDO 0x00200
#define V4L2_AUDMODE_STEREO_SPATIAL30 0x00300
#define V4L2_AUDMODE_STEREO_SPATIAL50 0x00400
struct v4l2_audioout
{
int audio;
char name[32];
__u32 capability;
__u32 mode;
__u32 reserved[2];
};
/*
* D A T A S E R V I C E S ( V B I )
*
* Data services API by Michael Schimek
*/
struct v4l2_vbi_format
{
__u32 sampling_rate; /* in 1 Hz */
__u32 offset;
__u32 samples_per_line;
__u32 sample_format; /* V4L2_VBI_SF_* */
__s32 start[2];
__u32 count[2];
__u32 flags; /* V4L2_VBI_* */
__u32 reserved2; /* must be zero */
};
/* VBI sampling formats */
#define V4L2_VBI_SF_UBYTE 1
/* VBI flags */
#define V4L2_VBI_UNSYNC (1<< 0)
#define V4L2_VBI_INTERLACED (1<< 1)
/*
* A G G R E G A T E S T R U C T U R E S
*/
/* Stream data format
*/
struct v4l2_format
{
__u32 type;
union
{
struct v4l2_pix_format pix; /* image format */
struct v4l2_vbi_format vbi; /* VBI data */
/* add more */
__u8 raw_data[200]; /* user-defined */
} fmt;
};
/* Stream type-dependent parameters
*/
struct v4l2_streamparm
{
__u32 type;
union
{
struct v4l2_captureparm capture;
struct v4l2_outputparm output;
/* add more */
__u8 raw_data[200]; /* user-defined */
} parm;
};
/*
* I O C T L C O D E S F O R V I D E O D E V I C E S
*
*/
#define VIDIOC_QUERYCAP _IOR ('V', 0, struct v4l2_capability)
#define VIDIOC_RESERVED _IO ('V', 1)
#define VIDIOC_ENUM_PIXFMT _IOWR ('V', 2, struct v4l2_fmtdesc)
#define VIDIOC_ENUM_FBUFFMT _IOWR ('V', 3, struct v4l2_fmtdesc)
#define VIDIOC_G_FMT _IOWR ('V', 4, struct v4l2_format)
#define VIDIOC_S_FMT _IOWR ('V', 5, struct v4l2_format)
#define VIDIOC_G_COMP _IOR ('V', 6, struct v4l2_compression)
#define VIDIOC_S_COMP _IOW ('V', 7, struct v4l2_compression)
#define VIDIOC_REQBUFS _IOWR ('V', 8, struct v4l2_requestbuffers)
#define VIDIOC_QUERYBUF _IOWR ('V', 9, struct v4l2_buffer)
#define VIDIOC_G_FBUF _IOR ('V', 10, struct v4l2_framebuffer)
#define VIDIOC_S_FBUF _IOW ('V', 11, struct v4l2_framebuffer)
#define VIDIOC_G_WIN _IOR ('V', 12, struct v4l2_window)
#define VIDIOC_S_WIN _IOW ('V', 13, struct v4l2_window)
#define VIDIOC_PREVIEW _IOWR ('V', 14, int)
#define VIDIOC_QBUF _IOWR ('V', 15, struct v4l2_buffer)
#define VIDIOC_DQBUF _IOWR ('V', 17, struct v4l2_buffer)
#define VIDIOC_STREAMON _IOW ('V', 18, int)
#define VIDIOC_STREAMOFF _IOW ('V', 19, int)
#define VIDIOC_G_PERF _IOR ('V', 20, struct v4l2_performance)
#define VIDIOC_G_PARM _IOWR ('V', 21, struct v4l2_streamparm)
#define VIDIOC_S_PARM _IOW ('V', 22, struct v4l2_streamparm)
#define VIDIOC_G_STD _IOR ('V', 23, struct v4l2_standard)
#define VIDIOC_S_STD _IOW ('V', 24, struct v4l2_standard)
#define VIDIOC_ENUMSTD _IOWR ('V', 25, struct v4l2_enumstd)
#define VIDIOC_ENUMINPUT _IOWR ('V', 26, struct v4l2_input)
#define VIDIOC_G_CTRL _IOWR ('V', 27, struct v4l2_control)
#define VIDIOC_S_CTRL _IOW ('V', 28, struct v4l2_control)
#define VIDIOC_G_TUNER _IOWR ('V', 29, struct v4l2_tuner)
#define VIDIOC_S_TUNER _IOW ('V', 30, struct v4l2_tuner)
#define VIDIOC_G_FREQ _IOR ('V', 31, int)
#define VIDIOC_S_FREQ _IOWR ('V', 32, int)
#define VIDIOC_G_AUDIO _IOWR ('V', 33, struct v4l2_audio)
#define VIDIOC_S_AUDIO _IOW ('V', 34, struct v4l2_audio)
#define VIDIOC_QUERYCTRL _IOWR ('V', 36, struct v4l2_queryctrl)
#define VIDIOC_QUERYMENU _IOWR ('V', 37, struct v4l2_querymenu)
#define VIDIOC_G_INPUT _IOR ('V', 38, int)
#define VIDIOC_S_INPUT _IOWR ('V', 39, int)
#define VIDIOC_ENUMCVT _IOWR ('V', 40, struct v4l2_cvtdesc)
#define VIDIOC_G_OUTPUT _IOR ('V', 46, int)
#define VIDIOC_S_OUTPUT _IOWR ('V', 47, int)
#define VIDIOC_ENUMOUTPUT _IOWR ('V', 48, struct v4l2_output)
#define VIDIOC_G_AUDOUT _IOWR ('V', 49, struct v4l2_audioout)
#define VIDIOC_S_AUDOUT _IOW ('V', 50, struct v4l2_audioout)
#define VIDIOC_ENUMFX _IOWR ('V', 51, struct v4l2_fxdesc)
#define VIDIOC_G_EFFECT _IOR ('V', 52, int)
#define VIDIOC_S_EFFECT _IOWR ('V', 53, int)
#define VIDIOC_G_MODULATOR _IOWR ('V', 54, struct v4l2_modulator)
#define VIDIOC_S_MODULATOR _IOW ('V', 55, struct v4l2_modulator)
#define VIDIOC_G_FREQUENCY _IOWR ('V', 56, struct v4l2_frequency)
#define VIDIOC_S_FREQUENCY _IOW ('V', 57, struct v4l2_frequency)
#define VIDIOC_ENUM_CAPFMT VIDIOC_ENUM_PIXFMT
#define VIDIOC_ENUM_OUTFMT VIDIOC_ENUM_PIXFMT
#define VIDIOC_ENUM_SRCFMT VIDIOC_ENUM_PIXFMT
#define VIDIOC_ENUMFMT VIDIOC_ENUM_PIXFMT
#define BASE_VIDIOC_PRIVATE 192 /* 192-255 are private */
#ifdef __KERNEL__
/*
*
* V 4 L 2 D R I V E R H E L P E R A P I
*
* Some commonly needed functions for drivers.
*/
extern void v4l2_version(int *major, int *minor);
extern int v4l2_major_number(void);
extern void v4l2_fill_ctrl_category(struct v4l2_queryctrl *qc);
/* Memory management */
extern unsigned long v4l2_vmalloc_to_bus(void *virt);
extern struct page *v4l2_vmalloc_to_page(void *virt);
/* Simple queue management */
struct v4l2_q_node
{
struct v4l2_q_node *forw, *back;
};
struct v4l2_queue
{
struct v4l2_q_node *forw, *back;
rwlock_t qlock;
};
extern void v4l2_q_init(struct v4l2_queue *q);
extern void v4l2_q_add_head(struct v4l2_queue *q, struct v4l2_q_node *node);
extern void v4l2_q_add_tail(struct v4l2_queue *q, struct v4l2_q_node *node);
extern void *v4l2_q_del_head(struct v4l2_queue *q);
extern void *v4l2_q_del_tail(struct v4l2_queue *q);
extern void *v4l2_q_peek_head(struct v4l2_queue *q);
extern void *v4l2_q_peek_tail(struct v4l2_queue *q);
extern void *v4l2_q_yank_node(struct v4l2_queue *q, struct v4l2_q_node *node);
extern int v4l2_q_last(struct v4l2_queue *q);
/* Math functions */
extern u32 v4l2_math_div6432(u64 a, u32 d, u32 *r);
/* Time functions */
extern unsigned long v4l2_timestamp_divide(stamp_t t,
unsigned long p_100ns);
extern unsigned long v4l2_timestamp_correct(stamp_t *t,
unsigned long p_100ns);
/* Master Clock functions */
struct v4l2_clock
{
void (*gettime)(stamp_t *);
};
extern int v4l2_masterclock_register(struct v4l2_clock *clock);
extern void v4l2_masterclock_unregister(struct v4l2_clock *clock);
extern void v4l2_masterclock_gettime(stamp_t *curr);
/* Video standard functions */
extern unsigned int v4l2_video_std_fps(struct v4l2_standard *vs);
extern unsigned long v4l2_video_std_tpf(struct v4l2_standard *vs);
extern int v4l2_video_std_confirm(struct v4l2_standard *vs);
extern int v4l2_video_std_construct(struct v4l2_standard *vs,
int id, __u32 transmission);
#define V4L2_STD_PAL 1 /* PAL B, G, H, I (...) */
#define V4L2_STD_PAL_M 5 /* (Brazil) */
#define V4L2_STD_PAL_N 6 /* (Argentina, Paraguay, Uruguay) */
#define V4L2_STD_PAL_60 10 /* PAL/NTSC hybrid */
#define V4L2_STD_NTSC 11 /* NTSC M (USA, ...) */
#define V4L2_STD_NTSC_N 12 /* (Barbados, Bolivia, Colombia,
S. Korea) */
#define V4L2_STD_NTSC_44 15 /* PAL/NTSC hybrid */
#define V4L2_STD_SECAM 21 /* SECAM B, D, G, K, K1 (...) */
//#define V4L2_STD_SECAM_H 27 /* (Greece, Iran, Morocco) */
//#define V4L2_STD_SECAM_L 28 /* (France, Luxembourg, Monaco) */
//#define V4L2_STD_SECAM_M 29 /* (Jamaica) */
/* Size of kernel ioctl arg buffer used in ioctl handler */
#define V4L2_MAX_IOCTL_SIZE 256
/* Compatibility layer interface */
typedef int (*v4l2_ioctl_compat)(struct inode *inode, struct file *file,
int cmd, void *arg);
int v4l2_compat_register(v4l2_ioctl_compat hook);
void v4l2_compat_unregister(v4l2_ioctl_compat hook);
#endif /* __KERNEL__ */
#endif /* __LINUX_VIDEODEV2_H */
amsn-0.98.9/utils/linux/capture/libng/parse-mpeg.h 0000644 0001750 0001750 00000013607 10246003435 021643 0 ustar billiob billiob /*
* MPEG1/2 transport and program stream parser and demuxer code.
*
* (c) 2003 Gerd Knorr
*
*/
#include
#define TS_SIZE 188
extern int mpeg_rate_n[16];
extern int mpeg_rate_d[16];
extern const char *mpeg_frame_s[];
extern char *psi_charset[0x20];
char *psi_service_type[0x100];
/* ----------------------------------------------------------------------- */
#define PSI_NEW 42 // initial version, valid range is 0 ... 32
#define PSI_STR_MAX 64
struct psi_stream {
struct list_head next;
int tsid;
/* network */
int netid;
char net[PSI_STR_MAX];
int frequency;
int symbol_rate;
char *bandwidth;
char *constellation;
char *hierarchy;
char *code_rate_hp;
char *code_rate_lp;
char *fec_inner;
char *guard;
char *transmission;
char *polarization;
/* status info */
int updated;
};
struct psi_program {
struct list_head next;
int tsid;
int pnr;
int version;
int running;
int ca;
/* program data */
int type;
int p_pid; // program
int v_pid; // video
int a_pid; // audio
int t_pid; // teletext
char audio[PSI_STR_MAX];
char net[PSI_STR_MAX];
char name[PSI_STR_MAX];
/* status info */
int updated;
int seen;
/* hmm ... */
int fd;
};
struct psi_info {
int tsid;
struct list_head streams;
struct list_head programs;
/* status info */
int pat_updated;
/* hmm ... */
struct psi_program *pr;
int pat_version;
int sdt_version;
int nit_version;
};
/* ----------------------------------------------------------------------- */
struct ts_packet {
unsigned int pid;
unsigned int cont;
unsigned int tei :1;
unsigned int payload :1;
unsigned int scramble :2;
unsigned int adapt :2;
unsigned char *data;
unsigned int size;
};
struct psc_info {
int temp_ref;
enum ng_video_frame frame;
uint64_t pts;
int gop_seen;
int dec_seq;
int play_seq;
};
struct mpeg_handle {
int fd;
/* file buffer */
int pgsize;
unsigned char *buffer;
off_t boff;
size_t bsize;
size_t balloc;
int beof;
int slowdown;
/* error stats */
int errors;
int error_out;
/* libng format info */
struct ng_video_fmt vfmt;
struct ng_audio_fmt afmt;
int rate, ratio;
/* video frame fifo */
struct list_head vfifo;
struct ng_video_buf *vbuf;
/* TS packet / PIDs */
struct ts_packet ts;
int p_pid;
int v_pid;
int a_pid;
/* parser state */
int init;
uint64_t video_pts;
uint64_t video_pts_last;
uint64_t audio_pts;
uint64_t audio_pts_last;
off_t video_offset;
off_t audio_offset;
off_t init_offset;
int frames;
int gop_seen;
int psc_seen;
struct psc_info psc; /* current picture */
struct psc_info pts_ref;
struct psc_info gop_ref;
};
/* ----------------------------------------------------------------------- */
/* handle psi_* */
struct psi_info* psi_info_alloc(void);
void psi_info_free(struct psi_info *info);
struct psi_stream* psi_stream_get(struct psi_info *info, int tsid, int alloc);
struct psi_program* psi_program_get(struct psi_info *info, int tsid,
int pnr, int alloc);
/* misc */
void hexdump(char *prefix, unsigned char *data, size_t size);
void mpeg_dump_desc(unsigned char *desc, int dlen);
/* common */
unsigned int mpeg_getbits(unsigned char *buf, int start, int count);
struct mpeg_handle* mpeg_init(void);
void mpeg_fini(struct mpeg_handle *h);
unsigned char* mpeg_get_data(struct mpeg_handle *h, off_t pos, size_t size);
size_t mpeg_parse_pes_packet(struct mpeg_handle *h, unsigned char *packet,
uint64_t *ts, int *al);
int mpeg_get_audio_rate(unsigned char *header);
int mpeg_get_video_fmt(struct mpeg_handle *h, unsigned char *header);
int mpeg_check_video_fmt(struct mpeg_handle *h, unsigned char *header);
unsigned char* mpeg_find_audio_hdr(unsigned char *buf, int off, int size);
/* program stream */
size_t mpeg_find_ps_packet(struct mpeg_handle *h, int packet, int mask, off_t *pos);
/* transport stream */
void mpeg_parse_psi_string(unsigned char *src, int slen,
unsigned char *dest, int dlen);
int mpeg_parse_psi_pat(struct psi_info *info, unsigned char *data, int verbose);
int mpeg_parse_psi_pmt(struct psi_program *program, unsigned char *data, int verbose);
int mpeg_parse_psi(struct psi_info *info, struct mpeg_handle *h, int verbose);
int mpeg_find_ts_packet(struct mpeg_handle *h, int wanted, off_t *pos);
/* DVB stuff */
int mpeg_parse_psi_sdt(struct psi_info *info, unsigned char *data, int verbose);
int mpeg_parse_psi_nit(struct psi_info *info, unsigned char *data, int verbose);
amsn-0.98.9/utils/linux/capture/libng/byteswap.h 0000644 0001750 0001750 00000001141 10733772533 021444 0 ustar billiob billiob #ifndef BYTEORDER_H
#define BYTEORDER_H
#include
#ifdef __sun
#include
#define BIG_ENDIAN 4321
#define LITTLE_ENDIAN 1234
#ifdef _BIG_ENDIAN
#define BYTE_ORDER BIG_ENDIAN
#else
#define BYTE_ORDER LITTLE_ENDIAN
#endif
#endif
#ifndef BYTE_ORDER
# error "Aiee: BYTE_ORDER not defined\n";
#endif
#define SWAP2(x) (((x>>8) & 0x00ff) |\
((x<<8) & 0xff00))
#define SWAP4(x) (((x>>24) & 0x000000ff) |\
((x>>8) & 0x0000ff00) |\
((x<<8) & 0x00ff0000) |\
((x<<24) & 0xff000000))
#endif /* BYTEORDER_H */
amsn-0.98.9/utils/linux/capture/libng/color_lut.c 0000644 0001750 0001750 00000015302 10246003435 021572 0 ustar billiob billiob /*
* colorspace conversion functions
* -- translate RGB using lookup tables
*
* (c) 1998-2001 Gerd Knorr
*
*/
#define NG_PRIVATE
#include "config.h"
#include
#include
#include
#include
#include
#include
#include
#include "grab-ng.h"
#include "byteswap.h"
int32_t ng_lut_red[256];
int32_t ng_lut_green[256];
int32_t ng_lut_blue[256];
/* ------------------------------------------------------------------- */
void
ng_rgb24_to_lut2(unsigned char* restrict dest, unsigned char* restrict src,
int p)
{
uint16_t* restrict d = (uint16_t*)dest;
while (p-- > 0) {
*(d++) = ng_lut_red[src[0]] | ng_lut_green[src[1]] |
ng_lut_blue[src[2]];
src += 3;
}
}
static void
bgr24_to_lut2(unsigned char* restrict dest, unsigned char* restrict src,
int p)
{
uint16_t* restrict d = (uint16_t*)dest;
while (p-- > 0) {
*(d++) = ng_lut_red[src[2]] | ng_lut_green[src[1]] |
ng_lut_blue[src[0]];
src += 3;
}
}
static void
rgb32_to_lut2(unsigned char* restrict dest, unsigned char* restrict src,
int p)
{
uint16_t* restrict d = (uint16_t*)dest;
while (p-- > 0) {
*(d++) = ng_lut_red[src[1]] | ng_lut_green[src[2]] |
ng_lut_blue[src[3]];
src += 4;
}
}
static void
bgr32_to_lut2(unsigned char* restrict dest, unsigned char* restrict src,
int p)
{
uint16_t* restrict d = (uint16_t*)dest;
while (p-- > 0) {
*(d++) = ng_lut_red[src[2]] | ng_lut_green[src[1]] |
ng_lut_blue[src[0]];
src += 4;
}
}
static void
gray_to_lut2(unsigned char* restrict dest, unsigned char* restrict src,
int p)
{
uint16_t* restrict d = (uint16_t*)dest;
while (p-- > 0) {
*(d++) = ng_lut_red[*src] | ng_lut_green[*src] | ng_lut_blue[*src];
src++;
}
}
/* ------------------------------------------------------------------- */
void
ng_rgb24_to_lut4(unsigned char* restrict dest, unsigned char* restrict src,
int p)
{
unsigned int* restrict d = (unsigned int*)dest;
while (p-- > 0) {
*(d++) = ng_lut_red[src[0]] | ng_lut_green[src[1]] |
ng_lut_blue[src[2]];
src += 3;
}
}
static void
bgr24_to_lut4(unsigned char* restrict dest, unsigned char* restrict src,
int p)
{
unsigned int* restrict d = (unsigned int*)dest;
while (p-- > 0) {
*(d++) = ng_lut_red[src[2]] | ng_lut_green[src[1]] |
ng_lut_blue[src[0]];
src += 3;
}
}
static void
rgb32_to_lut4(unsigned char* restrict dest, unsigned char* restrict src,
int p)
{
unsigned int* restrict d = (unsigned int*)dest;
while (p-- > 0) {
*(d++) = ng_lut_red[src[1]] | ng_lut_green[src[2]] |
ng_lut_blue[src[3]];
src += 4;
}
}
static void
bgr32_to_lut4(unsigned char* restrict dest, unsigned char* restrict src,
int p)
{
unsigned int* restrict d = (unsigned int*)dest;
while (p-- > 0) {
*(d++) = ng_lut_red[src[2]] | ng_lut_green[src[1]] |
ng_lut_blue[src[0]];
src += 4;
}
}
static void
gray_to_lut4(unsigned char* restrict dest, unsigned char* restrict src,
int p)
{
unsigned int* restrict d = (unsigned int*)dest;
while (p-- > 0) {
*(d++) = ng_lut_red[*src] | ng_lut_green[*src] | ng_lut_blue[*src];
src++;
}
}
/* ------------------------------------------------------------------- */
static struct ng_video_conv lut2_list[] = {
{
NG_GENERIC_PACKED,
.fmtid_in = VIDEO_RGB24,
.priv = ng_rgb24_to_lut2,
}, {
NG_GENERIC_PACKED,
.fmtid_in = VIDEO_BGR24,
.priv = bgr24_to_lut2,
}, {
NG_GENERIC_PACKED,
.fmtid_in = VIDEO_RGB32,
.priv = rgb32_to_lut2,
}, {
NG_GENERIC_PACKED,
.fmtid_in = VIDEO_BGR32,
.priv = bgr32_to_lut2,
}, {
NG_GENERIC_PACKED,
.fmtid_in = VIDEO_GRAY,
.priv = gray_to_lut2,
}, {
NG_GENERIC_PACKED,
.fmtid_in = VIDEO_YUYV,
.priv = ng_yuv422_to_lut2,
},{
.init = ng_conv_nop_init,
.p.mode = NG_MODE_TRIVIAL,
.p.fini = ng_conv_nop_fini,
.p.frame = ng_yuv422p_to_lut2,
.fmtid_in = VIDEO_YUV422P,
},{
.init = ng_conv_nop_init,
.p.mode = NG_MODE_TRIVIAL,
.p.fini = ng_conv_nop_fini,
.p.frame = ng_yuv420p_to_lut2,
.fmtid_in = VIDEO_YUV420P,
}
};
static struct ng_video_conv lut4_list[] = {
{
NG_GENERIC_PACKED,
.fmtid_in = VIDEO_RGB24,
.priv = ng_rgb24_to_lut4,
}, {
NG_GENERIC_PACKED,
.fmtid_in = VIDEO_BGR24,
.priv = bgr24_to_lut4,
}, {
NG_GENERIC_PACKED,
.fmtid_in = VIDEO_RGB32,
.priv = rgb32_to_lut4,
}, {
NG_GENERIC_PACKED,
.fmtid_in = VIDEO_BGR32,
.priv = bgr32_to_lut4,
}, {
NG_GENERIC_PACKED,
.fmtid_in = VIDEO_GRAY,
.priv = gray_to_lut4,
}, {
NG_GENERIC_PACKED,
.fmtid_in = VIDEO_YUYV,
.priv = ng_yuv422_to_lut4,
},{
.init = ng_conv_nop_init,
.p.mode = NG_MODE_TRIVIAL,
.p.fini = ng_conv_nop_fini,
.p.frame = ng_yuv422p_to_lut4,
.fmtid_in = VIDEO_YUV422P,
},{
.init = ng_conv_nop_init,
.p.mode = NG_MODE_TRIVIAL,
.p.fini = ng_conv_nop_fini,
.p.frame = ng_yuv420p_to_lut4,
.fmtid_in = VIDEO_YUV420P,
}
};
static const unsigned int nconv2 = sizeof(lut2_list)/sizeof(lut2_list[0]);
static const unsigned int nconv4 = sizeof(lut4_list)/sizeof(lut4_list[0]);
static void init_one(int32_t *lut, int32_t mask)
{
int bits = 0;
int shift = 0;
int i;
for (i = 0; i < 32; i++) {
if (mask & ((int32_t)1 << i))
bits++;
else if (!bits)
shift++;
}
if (bits > 8)
for (i = 0; i < 256; i++)
lut[i] = (i << (bits + shift - 8));
else
for (i = 0; i < 256; i++)
lut[i] = (i >> (8 - bits)) << shift;
}
void
ng_lut_init(unsigned long red_mask, unsigned long green_mask,
unsigned long blue_mask, unsigned int fmtid, int swap)
{
static int once=0;
unsigned int i;
if (once++) {
fprintf(stderr,"panic: ng_lut_init called twice\n");
return;
}
init_one(ng_lut_red, red_mask);
init_one(ng_lut_green, green_mask);
init_one(ng_lut_blue, blue_mask);
switch (ng_vfmt_to_depth[fmtid]) {
case 16:
if (swap) {
for (i = 0; i < 256; i++) {
ng_lut_red[i] = SWAP2(ng_lut_red[i]);
ng_lut_green[i] = SWAP2(ng_lut_green[i]);
ng_lut_blue[i] = SWAP2(ng_lut_blue[i]);
}
}
for (i = 0; i < nconv2; i++)
lut2_list[i].fmtid_out = fmtid;
ng_conv_register(NG_PLUGIN_MAGIC,"built-in",lut2_list,nconv2);
break;
case 32:
if (swap) {
for (i = 0; i < 256; i++) {
ng_lut_red[i] = SWAP4(ng_lut_red[i]);
ng_lut_green[i] = SWAP4(ng_lut_green[i]);
ng_lut_blue[i] = SWAP4(ng_lut_blue[i]);
}
}
for (i = 0; i < nconv4; i++)
lut4_list[i].fmtid_out = fmtid;
ng_conv_register(NG_PLUGIN_MAGIC,"built-in",lut4_list,nconv4);
break;
}
}
amsn-0.98.9/utils/linux/capture/libng/color_unused.c 0000644 0001750 0001750 00000002175 10246003435 022275 0 ustar billiob billiob /* ------------------------------------------------------------------- */
/* YUV conversions */
int
packed422_to_planar422(unsigned char *d, unsigned char *s, int p)
{
int i;
unsigned char *y,*u,*v;
i = p/2;
y = d;
u = y + p;
v = u + p / 2;
while (--i) {
*(y++) = *(s++);
*(u++) = *(s++);
*(y++) = *(s++);
*(v++) = *(s++);
}
return p*2;
}
/* y only, no chroma */
int
packed422_to_planar420(unsigned char *d, unsigned char *s, int p)
{
int i;
unsigned char *y;
i = p/2;
y = d;
while (--i) {
*(y++) = *(s++);
s++;
*(y++) = *(s++);
s++;
}
return p*3/2;
}
#if 0
void
x_packed422_to_planar420(unsigned char *d, unsigned char *s, int w, int h)
{
int a,b;
unsigned char *y,*u,*v;
y = d;
u = y + w * h;
v = u + w * h / 4;
for (a = h; a > 0; a -= 2) {
for (b = w; b > 0; b -= 2) {
*(y++) = *(s++);
*(u++) = *(s++);
*(y++) = *(s++);
*(v++) = *(s++);
}
for (b = w; b > 0; b -= 2) {
*(y++) = *(s++);
s++;
*(y++) = *(s++);
s++;
}
}
}
#endif
amsn-0.98.9/utils/linux/capture/libng/misc.h 0000644 0001750 0001750 00000000556 10246003435 020535 0 ustar billiob billiob /* --------------------------------------------------------------------- */
/* misc stuff some libc versions have and some don't ... */
#ifndef HAVE_STRCASESTR
char* strcasestr(char *haystack, char *needle);
#endif
#ifndef HAVE_MEMMEM
void *memmem(unsigned char *haystack, size_t haystacklen,
unsigned char *needle, size_t needlelen);
#endif
amsn-0.98.9/utils/linux/capture/libng/parse-mpeg.c 0000644 0001750 0001750 00000063702 10246003435 021637 0 ustar billiob billiob /*
* parse mpeg program + transport streams.
*
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include "grab-ng.h"
#include "parse-mpeg.h"
#define FILE_BUF_MIN (512*1024)
#define FILE_BUF_MAX (8*1024*1024)
#define FILE_BLKSIZE (16*1024)
#ifndef PRId64
# warning Hmm, your C99 support is incomplete, will guess (should be ok for 32bit archs)
# define PRId64 "lld"
# define PRIx64 "llx"
# define PRIu64 "llu"
#endif
int ng_mpeg_vpid = 0;
int ng_mpeg_apid = 0;
int ng_read_timeout = 3; /* seconds */
/* ----------------------------------------------------------------------- */
/* static data */
int mpeg_rate_n[16] = {
[ 1 ] = 24000,
[ 2 ] = 24000,
[ 3 ] = 25000,
[ 4 ] = 30000,
[ 5 ] = 30000,
[ 6 ] = 50000,
[ 7 ] = 60000,
[ 8 ] = 60000,
};
int mpeg_rate_d[16] = {
[ 1 ] = 1001,
[ 2 ] = 1000,
[ 3 ] = 1000,
[ 4 ] = 1001,
[ 5 ] = 1000,
[ 6 ] = 1000,
[ 7 ] = 1001,
[ 8 ] = 1000,
};
static char *rate_s[16] = {
[ 0 ] = "illegal",
[ 1 ] = "24000/1001",
[ 2 ] = "24",
[ 3 ] = "25",
[ 4 ] = "30000/1001",
[ 5 ] = "30",
[ 6 ] = "50",
[ 7 ] = "60000/1001",
[ 8 ] = "60",
[ 9 ... 15 ] = "reserved",
};
static char *ratio_s[] = {
[ 0 ] = "illegal",
[ 1 ] = "square sample",
[ 2 ] = "3:4",
[ 3 ] = "9:16",
[ 4 ] = "1:2,21",
[ 5 ... 15 ] = "reserved",
};
const char *mpeg_frame_s[] = {
[ NG_FRAME_UNKNOWN ] = "unknown",
[ NG_FRAME_I_FRAME ] = "I frame",
[ NG_FRAME_P_FRAME ] = "P frame",
[ NG_FRAME_B_FRAME ] = "B frame",
};
static const char *pes_s[] = {
[ 0x00 ... 0xff ] = "*UNKNOWN* stream",
[ 0xbc ] = "program stream map",
[ 0xbd ] = "private stream 1",
[ 0xbe ] = "padding stream",
[ 0xbf ] = "private stream 2",
[ 0xc0 ... 0xdf ] = "audio stream",
[ 0xe0 ... 0xef ] = "video stream",
[ 0xf0 ] = "ECM stream",
[ 0xf1 ] = "EMM stream",
[ 0xf2 ] = "DSMCC stream",
[ 0xf3 ] = "13522 stream",
[ 0xf4 ] = "H.222.1 type A",
[ 0xf5 ] = "H.222.1 type B",
[ 0xf6 ] = "H.222.1 type C",
[ 0xf7 ] = "H.222.1 type D",
[ 0xf8 ] = "H.222.1 type E",
[ 0xf9 ] = "ancillary stream",
[ 0xfa ... 0xfe ] = "reserved data stream",
[ 0xff ] = "program stream directory",
};
static const char *stream_type_s[] = {
[ 0x00 ] = "reserved",
[ 0x01 ] = "ISO 11172 Video",
[ 0x02 ] = "ISO 13818-2 Video",
[ 0x03 ] = "ISO 11172 Audio",
[ 0x04 ] = "ISO 13818-3 Audio",
[ 0x05 ] = "ISO 13818-1 private sections",
[ 0x06 ] = "ISO 13818-1 private data",
[ 0x07 ] = "ISO 13522 MHEG",
[ 0x08 ] = "ISO 13818-1 Annex A DSS CC",
[ 0x09 ] = "ITU-T H.222.1",
[ 0x0a ] = "ISO 13818-6 type A",
[ 0x0b ] = "ISO 13818-6 type B",
[ 0x0c ] = "ISO 13818-6 type C",
[ 0x0d ] = "ISO 13818-6 type D",
[ 0x0e ] = "ISO 13818-6 auxiliary",
[ 0x0f ... 0x7f ] = "reserved",
[ 0x80 ... 0xff ] = "user private",
};
/* ----------------------------------------------------------------------- */
char *psi_charset[0x20] = {
[ 0x00 ... 0x1f ] = "reserved",
[ 0x00 ] = "ISO-8859-1",
[ 0x01 ] = "ISO-8859-5",
[ 0x02 ] = "ISO-8859-6",
[ 0x03 ] = "ISO-8859-7",
[ 0x04 ] = "ISO-8859-8",
[ 0x05 ] = "ISO-8859-9",
[ 0x06 ] = "ISO-8859-10",
[ 0x07 ] = "ISO-8859-11",
[ 0x08 ] = "ISO-8859-12",
[ 0x09 ] = "ISO-8859-13",
[ 0x0a ] = "ISO-8859-14",
[ 0x0b ] = "ISO-8859-15",
[ 0x10 ] = "fixme",
[ 0x11 ] = "UCS-2BE", // correct?
[ 0x12 ] = "EUC-KR",
[ 0x13 ] = "GB2312",
[ 0x14 ] = "BIG5"
};
char *psi_service_type[0x100] = {
[ 0x00 ... 0xff ] = "reserved",
[ 0x80 ... 0xfe ] = "user defined",
[ 0x01 ] = "digital television service",
[ 0x02 ] = "digital radio sound service",
[ 0x03 ] = "teletext service",
[ 0x04 ] = "NVOD reference service",
[ 0x05 ] = "NVOD time-shifted service",
[ 0x06 ] = "mosaic service",
[ 0x07 ] = "PAL coded signal",
[ 0x08 ] = "SECAM coded signal",
[ 0x09 ] = "D/D2-MAC",
[ 0x0a ] = "FM Radio",
[ 0x0b ] = "NTSC coded signal",
[ 0x0c ] = "data broadcast service",
[ 0x0d ] = "reserved for CI",
[ 0x0e ] = "RCS Map",
[ 0x0f ] = "RCS FLS",
[ 0x10 ] = "DVB MHP service",
};
/* ----------------------------------------------------------------------- */
/* handle psi_ structs */
struct psi_info* psi_info_alloc(void)
{
struct psi_info *info;
info = malloc(sizeof(*info));
memset(info,0,sizeof(*info));
INIT_LIST_HEAD(&info->streams);
INIT_LIST_HEAD(&info->programs);
info->pat_version = PSI_NEW;
info->sdt_version = PSI_NEW;
info->nit_version = PSI_NEW;
return info;
}
void psi_info_free(struct psi_info *info)
{
struct psi_program *program;
struct psi_stream *stream;
struct list_head *item,*safe;
list_for_each_safe(item,safe,&info->streams) {
stream = list_entry(item, struct psi_stream, next);
list_del(&stream->next);
free(stream);
}
list_for_each_safe(item,safe,&info->programs) {
program = list_entry(item, struct psi_program, next);
list_del(&program->next);
free(program);
}
free(info);
}
struct psi_stream* psi_stream_get(struct psi_info *info, int tsid, int alloc)
{
struct psi_stream *stream;
struct list_head *item;
list_for_each(item,&info->streams) {
stream = list_entry(item, struct psi_stream, next);
if (stream->tsid == tsid)
return stream;
}
if (!alloc)
return NULL;
stream = malloc(sizeof(*stream));
memset(stream,0,sizeof(*stream));
stream->tsid = tsid;
stream->updated = 1;
list_add_tail(&stream->next,&info->streams);
return stream;
}
struct psi_program* psi_program_get(struct psi_info *info, int tsid,
int pnr, int alloc)
{
struct psi_program *program;
struct list_head *item;
list_for_each(item,&info->programs) {
program = list_entry(item, struct psi_program, next);
if (program->tsid == tsid &&
program->pnr == pnr)
return program;
}
if (!alloc)
return NULL;
program = malloc(sizeof(*program));
memset(program,0,sizeof(*program));
program->tsid = tsid;
program->pnr = pnr;
program->version = PSI_NEW;
program->updated = 1;
list_add_tail(&program->next,&info->programs);
return program;
}
/* ----------------------------------------------------------------------- */
/* bit fiddeling */
unsigned int mpeg_getbits(unsigned char *buf, int start, int count)
{
unsigned int result = 0;
unsigned char bit;
while (count) {
result <<= 1;
bit = 1 << (7 - (start % 8));
result |= (buf[start/8] & bit) ? 1 : 0;
start++;
count--;
}
return result;
}
void hexdump(char *prefix, unsigned char *data, size_t size)
{
char ascii[17];
int i;
for (i = 0; i < size; i++) {
if (0 == (i%16)) {
fprintf(stderr,"%s%s%04x:",
prefix ? prefix : "",
prefix ? ": " : "",
i);
memset(ascii,0,sizeof(ascii));
}
if (0 == (i%4))
fprintf(stderr," ");
fprintf(stderr," %02x",data[i]);
ascii[i%16] = isprint(data[i]) ? data[i] : '.';
if (15 == (i%16))
fprintf(stderr," %s\n",ascii);
}
if (0 != (i%16)) {
while (0 != (i%16)) {
if (0 == (i%4))
fprintf(stderr," ");
fprintf(stderr," ");
i++;
};
fprintf(stderr," %s\n",ascii);
}
}
/* ----------------------------------------------------------------------- */
/* common code */
struct mpeg_handle* mpeg_init(void)
{
struct mpeg_handle *h;
h = malloc(sizeof(*h));
if (NULL == h)
return NULL;
memset(h,0,sizeof(*h));
h->fd = -1;
h->pgsize = getpagesize();
h->init = 1;
return h;
}
void mpeg_fini(struct mpeg_handle *h)
{
if (h->vbuf)
ng_release_video_buf(h->vbuf);
if (-1 != h->fd)
close(h->fd);
if (h->buffer)
free(h->buffer);
free(h);
}
unsigned char* mpeg_get_data(struct mpeg_handle *h, off_t pos, size_t size)
{
fd_set set;
struct timeval tv;
off_t low;
size_t rdbytes;
int rc;
if (pos < h->boff) {
/* shouldn't happen */
fprintf(stderr,"mpeg: panic: seek backwards [pos=%ld,boff=%ld]\n",
(long)pos,(long)h->boff);
exit(1);
}
low = 0;
if (!h->init && pos > h->init_offset*6) {
if (h->video_offset > h->init_offset &&
h->audio_offset > h->init_offset)
low = (h->video_offset < h->audio_offset)
? h->video_offset : h->audio_offset;
else if (h->audio_offset > h->init_offset)
low = h->audio_offset;
else if (h->video_offset > h->init_offset)
low = h->video_offset;
}
if (low > h->boff + h->balloc*3/4 &&
low < h->boff + h->bsize &&
!h->beof) {
/* move data window */
rdbytes = (low - h->boff) & ~(h->pgsize - 1);
memmove(h->buffer, h->buffer + rdbytes, h->balloc - rdbytes);
h->boff += rdbytes;
h->bsize -= rdbytes;
if (ng_debug)
fprintf(stderr,"mpeg: %dk file buffer shift\n", (int)(rdbytes >> 10));
}
while (pos+size + 2*TS_SIZE > h->boff + h->balloc && !h->beof) {
/* enlarge buffer */
if (0 == h->bsize) {
h->balloc = FILE_BUF_MIN;
h->buffer = malloc(h->balloc);
} else {
h->balloc *= 2;
if (h->balloc > FILE_BUF_MAX) {
fprintf(stderr,"mpeg: panic: file buffer limit exceeded "
"(l=%d,b=%d,v=%d,a=%d)\n",
FILE_BUF_MAX,(int)h->balloc,
(int)h->video_offset,(int)h->audio_offset);
exit(1);
}
h->buffer = realloc(h->buffer,h->balloc);
}
if (ng_debug)
fprintf(stderr,"mpeg: %dk file buffer\n",(int)(h->balloc >> 10));
}
while (pos+size > h->boff + h->bsize) {
if (h->beof)
return NULL;
/* read data */
rdbytes = h->balloc - h->bsize;
if (rdbytes > FILE_BLKSIZE)
rdbytes = FILE_BLKSIZE;
rdbytes -= rdbytes % TS_SIZE;
rc = read(h->fd, h->buffer + h->bsize, rdbytes);
switch (rc) {
case -1:
switch (errno) {
case EAGAIN:
/* must wait for data ... */
if (!h->init) {
if (ng_log_resync)
fprintf(stderr,"mpeg: sync: must wait for data\n");
h->slowdown++;
}
FD_ZERO(&set);
FD_SET(h->fd,&set);
tv.tv_sec = ng_read_timeout;
tv.tv_usec = 0;
switch (select(h->fd+1,&set,NULL,NULL,&tv)) {
case -1:
fprintf(stderr,"mpeg: select: %s\n",strerror(errno));
h->beof = 1;
break;
case 0:
fprintf(stderr,"mpeg: select: timeout (%d sec)\n",
ng_read_timeout);
h->beof = 1;
break;
}
break;
case EOVERFLOW:
if (ng_log_resync)
fprintf(stderr,"mpeg: sync: kernel buffer overflow\n");
break;
default:
fprintf(stderr,"mpeg: read: %s [%d]\n",strerror(errno),errno);
h->beof = 1;
break;
}
break;
case 0:
if (ng_debug)
fprintf(stderr,"mpeg: EOF\n");
h->beof = 1;
break;
default:
h->bsize += rc;
break;
}
}
return h->buffer + (pos - h->boff);
}
size_t mpeg_parse_pes_packet(struct mpeg_handle *h, unsigned char *packet,
uint64_t *ts, int *al)
{
uint64_t pts, dts;
int id;
size_t size;
int i, val;
pts = 0;
dts = 0;
id = 0;
*al = 0;
for (i = 48; i < 48 + 8*16; i += 8)
if (0xff != mpeg_getbits(packet,i,8))
break;
if (mpeg_getbits(packet,i,2) == 0x02) {
/* MPEG 2 */
id = mpeg_getbits(packet, i-24, 8);
*al = mpeg_getbits(packet, i+ 5, 1);
size = mpeg_getbits(packet, i+16, 8);
size += i/8 + 3;
switch (mpeg_getbits(packet, i+8, 2)) {
case 3:
dts = (uint64_t)mpeg_getbits(packet, i + 68, 3) << 30;
dts |= (uint64_t)mpeg_getbits(packet, i + 72, 15) << 15;
dts |= (uint64_t)mpeg_getbits(packet, i + 88, 15);
/* fall */
case 2:
pts = (uint64_t)mpeg_getbits(packet, i + 28, 3) << 30;
pts |= (uint64_t)mpeg_getbits(packet, i + 32, 15) << 15;
pts |= (uint64_t)mpeg_getbits(packet, i + 48, 15);
break;
}
if (ng_debug > 2)
fprintf(stderr,"mpeg2 pes: pl=%d al=%d copy=%d orig=%d ts=%d hl=%d | "
" pts=%" PRIx64 " dts=%" PRIx64 " size=%d\n",
mpeg_getbits(packet, i - 16, 16),
mpeg_getbits(packet, i + 5, 1),
mpeg_getbits(packet, i + 6, 1),
mpeg_getbits(packet, i + 7, 1),
mpeg_getbits(packet, i + 8, 2),
mpeg_getbits(packet, i + 16, 8),
pts, dts, (int)size);
if (ng_debug > 3) {
hexdump("mpeg2 pes",packet,32);
fprintf(stderr,"--\n");
}
} else {
/* MPEG 1 */
if (mpeg_getbits(packet,i,2) == 0x01)
i += 16;
val = mpeg_getbits(packet,i,8);
if ((val & 0xf0) == 0x20) {
pts = (uint64_t)mpeg_getbits(packet, i + 4, 3) << 30;
pts |= (uint64_t)mpeg_getbits(packet, i + 8, 15) << 15;
pts |= (uint64_t)mpeg_getbits(packet, i + 24, 15);
i += 40;
} else if ((val & 0xf0) == 0x30) {
pts = (uint64_t)mpeg_getbits(packet, i + 4, 3) << 30;
pts |= (uint64_t)mpeg_getbits(packet, i + 8, 15) << 15;
pts |= (uint64_t)mpeg_getbits(packet, i + 24, 15);
i += 80;
} else if (val == 0x0f)
i += 8;
size = i/8;
}
if (pts) {
if (ng_debug > 1)
fprintf(stderr,"pts: %8.3f | id 0x%02x %s\n",
pts/90000.0,id,pes_s[id]);
if (ts)
*ts = pts;
}
return size;
}
int mpeg_get_audio_rate(unsigned char *header)
{
int rate = 44100;
if (mpeg_getbits(header,12,1) == 1) {
/* MPEG 1.0 */
switch (mpeg_getbits(header,20,2)) {
case 0: rate = 44100; break;
case 1: rate = 48000; break;
case 2: rate = 32000; break;
}
if (ng_debug)
fprintf(stderr,"mpeg: MPEG1 audio, rate %d\n",rate);
} else {
/* MPEG 2.0 */
switch (mpeg_getbits(header,20,2)) {
case 0: rate = 22050; break;
case 1: rate = 24000; break;
case 2: rate = 16000; break;
}
if (ng_debug)
fprintf(stderr,"mpeg: MPEG2 audio, rate %d\n",rate);
}
return rate;
}
unsigned char* mpeg_find_audio_hdr(unsigned char *buf, int off, int size)
{
int i;
for (i = off; i < size-1; i++) {
if (0xff != buf[i])
continue;
if (0xf0 == (buf[i+1] & 0xf0))
return buf+i;
}
return NULL;
}
int mpeg_get_video_fmt(struct mpeg_handle *h, unsigned char *header)
{
if (header[0] != 0x00 || header[1] != 0x00 ||
header[2] != 0x01 || header[3] != 0xb3)
return -1;
h->vfmt.fmtid = VIDEO_MPEG;
h->vfmt.width = (mpeg_getbits(header,32,12) + 15) & ~15;
h->vfmt.height = (mpeg_getbits(header,44,12) + 15) & ~15;
h->ratio = mpeg_getbits(header,56,4);
h->rate = mpeg_getbits(header,60,4);
if (ng_debug)
fprintf(stderr,"mpeg: MPEG video, %dx%d [ratio=%s,rate=%s]\n",
h->vfmt.width, h->vfmt.height,
ratio_s[h->ratio], rate_s[h->rate]);
return 0;
}
int mpeg_check_video_fmt(struct mpeg_handle *h, unsigned char *header)
{
int width, height, ratio;
int change = 0;
if (header[0] != 0x00 || header[1] != 0x00 ||
header[2] != 0x01 || header[3] != 0xb3)
return 0;
width = (mpeg_getbits(header,32,12) + 15) & ~15;
height = (mpeg_getbits(header,44,12) + 15) & ~15;
ratio = mpeg_getbits(header,56,4);
if (width != h->vfmt.width || height != h->vfmt.height) {
if (ng_debug)
fprintf(stderr,"mpeg: size change: %dx%d => %dx%d\n",
h->vfmt.width, h->vfmt.height, width, height);
change++;
}
if (ratio != h->ratio) {
if (ng_debug)
fprintf(stderr,"mpeg: ratio change: %s => %s\n",
ratio_s[h->ratio], ratio_s[ratio]);
change++;
}
h->vfmt.height = height;
h->vfmt.width = width;
h->ratio = ratio;
return change;
}
/* ----------------------------------------------------------------------- */
/* program streams */
size_t mpeg_find_ps_packet(struct mpeg_handle *h, int packet, int mask, off_t *pos)
{
unsigned char *buf;
size_t size;
off_t start = *pos;
/* read header */
for (;;) {
buf = mpeg_get_data(h,*pos,16);
if (NULL == buf)
return 0;
if (buf[0] != 0x00 ||
buf[1] != 0x00 ||
buf[2] != 0x01)
return 0;
size = mpeg_getbits(buf,32,16) + 6;
/* handle special cases */
switch (buf[3]) {
case 0xba:
/* packet start code */
if (0x01 == mpeg_getbits(buf,32,2)) {
/* MPEG 2 */
size = 14 + mpeg_getbits(buf,109,3);
} else if (0x02 == mpeg_getbits(buf,32,4)) {
/* MPEG 1 */
size = 12;
} else {
/* Huh? */
return 0;
}
break;
case 0xb9:
/* mpeg program end code */
return 0;
}
if (ng_debug > 1)
fprintf(stderr,"mpeg: packet 0x%x at 0x%08" PRIx64 "+%d [need 0x%x]\n",
(int)buf[3],(int64_t)*pos,(int)size,packet);
/* our packet ? */
if ((buf[3] & mask) == packet)
return size;
*pos += size;
/* don't search unlimited ... */
if (*pos - start > FILE_BUF_MIN)
return 0;
}
}
/* ----------------------------------------------------------------------- */
/* transport streams */
static void parse_pmt_desc(unsigned char *desc, int dlen,
struct psi_program *program, int pid)
{
int i,t,l;
for (i = 0; i < dlen; i += desc[i+1] +2) {
t = desc[i];
l = desc[i+1];
switch (t) {
case 0x56:
if (!program->t_pid)
program->t_pid = pid;
break;
}
}
}
static char* get_lang_tag(unsigned char *desc, int dlen)
{
int i,t,l;
for (i = 0; i < dlen; i += desc[i+1] +2) {
t = desc[i];
l = desc[i+1];
if (0x0a == t)
return desc+i+2;
}
return NULL;
}
static void dump_data(unsigned char *data, int len)
{
int i;
for (i = 0; i < len; i++) {
if (isprint(data[i]))
fprintf(stderr,"%c", data[i]);
else
fprintf(stderr,"\\x%02x", (int)data[i]);
}
}
void mpeg_dump_desc(unsigned char *desc, int dlen)
{
int i,j,t,l,l2,l3;
for (i = 0; i < dlen; i += desc[i+1] +2) {
t = desc[i];
l = desc[i+1];
switch (t) {
case 0x0a: /* ??? (pmt) */
fprintf(stderr," lang=%3.3s",desc+i+2);
break;
case 0x45: /* vbi data (pmt) */
fprintf(stderr," vbidata=");
dump_data(desc+i+2,l);
break;
case 0x52: /* stream identifier */
fprintf(stderr," sid=%d",(int)desc[i+2]);
break;
case 0x56: /* teletext (pmt) */
fprintf(stderr," teletext=%3.3s",desc+i+2);
break;
case 0x59: /* subtitles (pmt) */
fprintf(stderr," subtitles=%3.3s",desc+i+2);
break;
case 0x6a: /* ac3 (pmt) */
fprintf(stderr," ac3");
break;
case 0x40: /* network name (nit) */
fprintf(stderr," name=");
dump_data(desc+i+2,l);
break;
case 0x43: /* satellite delivery system (nit) */
fprintf(stderr," dvb-s");
break;
case 0x44: /* cable delivery system (nit) */
fprintf(stderr," dvb-c");
break;
case 0x5a: /* terrestrial delivery system (nit) */
fprintf(stderr," dvb-t");
break;
case 0x48: /* service (sdt) */
fprintf(stderr," service=%d,",desc[i+2]);
l2 = desc[i+3];
dump_data(desc+i+4,desc[i+3]);
fprintf(stderr,",");
dump_data(desc+i+l2+5,desc[i+l2+4]);
break;
case 0x4d: /* event (eid) */
fprintf(stderr," short=[%3.3s|",desc+i+2);
l2 = desc[i+5];
l3 = desc[i+6+l2];
dump_data(desc+i+6,l2);
fprintf(stderr,"|");
dump_data(desc+i+7+l2,l3);
fprintf(stderr,"]");
break;
case 0x4e: /* event (eid) */
fprintf(stderr," *ext event");
break;
case 0x4f: /* event (eid) */
fprintf(stderr," *time shift event");
break;
case 0x50: /* event (eid) */
fprintf(stderr," *component");
break;
case 0x54: /* event (eid) */
fprintf(stderr," content=");
for (j = 0; j < l; j+=2)
fprintf(stderr,"%s0x%02x", j ? "," : "", desc[i+j+2]);
break;
case 0x55: /* event (eid) */
fprintf(stderr," *parental rating");
break;
default:
fprintf(stderr," %02x[",desc[i]);
dump_data(desc+i+2,l);
fprintf(stderr,"]");
}
}
}
int mpeg_parse_psi_pat(struct psi_info *info, unsigned char *data, int verbose)
{
struct list_head *item;
struct psi_program *pr;
int tsid,pnr,version,current;
int j,len,pid;
len = mpeg_getbits(data,12,12) + 3 - 4;
tsid = mpeg_getbits(data,24,16);
version = mpeg_getbits(data,42,5);
current = mpeg_getbits(data,47,1);
if (!current)
return len+4;
if (info->tsid == tsid && info->pat_version == version)
return len+4;
info->tsid = tsid;
info->pat_version = version;
info->pat_updated = 1;
if (verbose)
fprintf(stderr, "ts [pat]: tsid %d ver %2d [%d/%d]\n",
tsid, version,
mpeg_getbits(data,48, 8),
mpeg_getbits(data,56, 8));
for (j = 64; j < len*8; j += 32) {
pnr = mpeg_getbits(data,j+0,16);
pid = mpeg_getbits(data,j+19,13);
if (0 == pnr) {
/* network */
if (verbose > 1)
fprintf(stderr," pid 0x%04x [network]\n",
pid);
} else {
/* program */
pr = psi_program_get(info, tsid, pnr, 1);
pr->p_pid = pid;
pr->updated = 1;
pr->seen = 1;
if (NULL == info->pr)
info->pr = pr;
}
}
if (verbose > 1) {
list_for_each(item,&info->programs) {
pr = list_entry(item, struct psi_program, next);
if (pr->tsid != tsid)
continue;
fprintf(stderr," pid 0x%04x => pnr %2d [program map%s]\n",
pr->p_pid, pr->pnr,
pr->seen ? ",seen" : "");
}
fprintf(stderr,"\n");
}
return len+4;
}
int mpeg_parse_psi_pmt(struct psi_program *program, unsigned char *data, int verbose)
{
int pnr,version,current;
int j,len,dlen,type,pid,slen;
char *lang;
len = mpeg_getbits(data,12,12) + 3 - 4;
pnr = mpeg_getbits(data,24,16);
version = mpeg_getbits(data,42,5);
current = mpeg_getbits(data,47,1);
if (!current)
return len+4;
if (program->pnr == pnr && program->version == version)
return len+4;
program->version = version;
program->updated = 1;
dlen = mpeg_getbits(data,84,12);
/* TODO: decode descriptor? */
if (verbose) {
fprintf(stderr,
"ts [pmt]: pnr %d ver %2d [%d/%d] pcr 0x%04x "
"pid 0x%04x type %2d #",
pnr, version,
mpeg_getbits(data,48, 8),
mpeg_getbits(data,56, 8),
mpeg_getbits(data,69,13),
program->p_pid, program->type);
mpeg_dump_desc(data + 96/8, dlen);
fprintf(stderr,"\n");
}
j = 96 + dlen*8;
program->v_pid = 0;
program->a_pid = 0;
program->t_pid = 0;
memset(program->audio,0,sizeof(program->audio));
while (j < len*8) {
type = mpeg_getbits(data,j,8);
pid = mpeg_getbits(data,j+11,13);
dlen = mpeg_getbits(data,j+28,12);
switch (type) {
case 1:
case 2:
/* video */
if (!program->v_pid)
program->v_pid = pid;
break;
case 3:
case 4:
/* audio */
if (!program->a_pid)
program->a_pid = pid;
lang = get_lang_tag(data + (j+40)/8, dlen);
slen = strlen(program->audio);
snprintf(program->audio + slen, sizeof(program->audio) - slen,
"%s%.3s:%d", slen ? " " : "", lang ? lang : "xxx", pid);
break;
case 6:
/* private data */
parse_pmt_desc(data + (j+40)/8, dlen, program, pid);
break;
}
if (verbose > 1) {
fprintf(stderr, " pid 0x%04x => %-32s #",
pid, stream_type_s[type]);
mpeg_dump_desc(data + (j+40)/8, dlen);
fprintf(stderr,"\n");
}
j += 40 + dlen*8;
}
if (verbose > 1)
fprintf(stderr,"\n");
return len+4;
}
int mpeg_parse_psi(struct psi_info *info, struct mpeg_handle *h, int verbose)
{
int i,tid;
if (h->ts.payload) {
for (i = h->ts.data[0]+1; i < h->ts.size;) {
tid = mpeg_getbits(h->ts.data,i*8,8);
switch (tid) {
case 0:
i += mpeg_parse_psi_pat(info, h->ts.data+i, verbose);
break;
case 1:
fprintf(stderr, "ts: conditional access\n");
return 0;
case 2:
i += mpeg_parse_psi_pmt(info->pr, h->ts.data+i, verbose);
break;
case 3:
fprintf(stderr, "ts: description\n");
return 0;
case 0xff:
/* end of data */
return 0;
default:
fprintf(stderr, "ts: unknown table id %d\n",tid);
return 0;
}
}
}
return 0;
}
/* ----------------------------------------------------------------------- */
int mpeg_find_ts_packet(struct mpeg_handle *h, int wanted, off_t *pos)
{
unsigned char *packet;
int asize = 0;
off_t start;
for (start = *pos; *pos - start < FILE_BUF_MIN; *pos += TS_SIZE) {
memset(&h->ts, 0, sizeof(h->ts));
packet = mpeg_get_data(h, *pos, TS_SIZE);
if (NULL == packet) {
fprintf(stderr,"mpeg ts: no more data\n");
return -1;
}
if (packet[0] != 0x47) {
if (ng_log_bad_stream)
fprintf(stderr,"mpeg ts: warning %d: packet id mismatch\n",
h->errors);
h->errors++;
continue;
}
h->ts.tei = mpeg_getbits(packet, 8,1);
h->ts.payload = mpeg_getbits(packet, 9,1);
h->ts.pid = mpeg_getbits(packet,11,13);
h->ts.scramble = mpeg_getbits(packet,24,2);
h->ts.adapt = mpeg_getbits(packet,26,2);
h->ts.cont = mpeg_getbits(packet,28,4);
if (0 == h->ts.adapt)
/* reserved -- should discard */
continue;
if (0x1fff == h->ts.pid)
/* NULL packet -- discard */
continue;
if (h->ts.pid != wanted)
/* need something else */
continue;
switch (h->ts.adapt) {
case 3:
/* adaptation + payload */
asize = mpeg_getbits(packet,32,8) +1;
h->ts.data = packet + (4 + asize);
h->ts.size = TS_SIZE - (4 + asize);
if (h->ts.size > TS_SIZE) {
if (ng_log_bad_stream)
fprintf(stderr,"mpeg ts: warning %d: broken adaptation"
" size [%lx]\n",h->errors,(unsigned long)(*pos));
h->errors++;
continue;
}
/* fall throuth */
case 2:
/* adaptation only */
/* TODO: parse adaptation field */
break;
case 1:
/* payload only */
h->ts.data = packet + 4;
h->ts.size = TS_SIZE - 4;
break;
}
if (ng_debug > 2)
fprintf(stderr,"mpeg ts: pl=%d pid=%d adapt=%d cont=%d size=%d [%d]\n",
h->ts.payload, h->ts.pid, h->ts.adapt,
h->ts.cont, h->ts.size, asize);
return 0;
}
return -1;
}
amsn-0.98.9/utils/linux/capture/libng/plugins/ 0000755 0001750 0001750 00000000000 11757711632 021121 5 ustar billiob billiob amsn-0.98.9/utils/linux/capture/libng/plugins/drv0-v4l2-old.c 0000644 0001750 0001750 00000102532 10246003435 023467 0 ustar billiob billiob /*
* interface to the v4l2 driver
*
* (c) 1998-2002 Gerd Knorr
*
*/
#include "config.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include /* XXX glibc */
#include "videodev2-old.h"
#include "grab-ng.h"
/* ---------------------------------------------------------------------- */
/* open+close */
static void* v4l2_open(char *device);
static int v4l2_close(void *handle);
/* attributes */
static char* v4l2_devname(void *handle);
static int v4l2_flags(void *handle);
static struct ng_attribute* v4l2_attrs(void *handle);
static int v4l2_read_attr(struct ng_attribute*);
static void v4l2_write_attr(struct ng_attribute*, int val);
/* overlay */
static int v4l2_setupfb(void *handle, struct ng_video_fmt *fmt, void *base);
static int v4l2_overlay(void *handle, struct ng_video_fmt *fmt, int x, int y,
struct OVERLAY_CLIP *oc, int count, int aspect);
/* capture video */
static int v4l2_setformat(void *handle, struct ng_video_fmt *fmt);
static int v4l2_startvideo(void *handle, int fps, unsigned int buffers);
static void v4l2_stopvideo(void *handle);
static struct ng_video_buf* v4l2_nextframe(void *handle);
static struct ng_video_buf* v4l2_getimage(void *handle);
/* tuner */
static unsigned long v4l2_getfreq(void *handle);
static void v4l2_setfreq(void *handle, unsigned long freq);
static int v4l2_tuned(void *handle);
/* ---------------------------------------------------------------------- */
#define WANTED_BUFFERS 32
#define MAX_INPUT 16
#define MAX_NORM 16
#define MAX_FORMAT 32
#define MAX_CTRL 32
struct v4l2_handle {
int fd;
/* device descriptions */
unsigned int ninputs,nstds,nfmts;
struct v4l2_capability cap;
struct v4l2_streamparm streamparm;
struct v4l2_input inp[MAX_INPUT];
struct v4l2_enumstd std[MAX_NORM];
struct v4l2_fmtdesc fmt[MAX_FORMAT];
struct v4l2_queryctrl ctl[MAX_CTRL*2];
/* attributes */
int nattr;
struct ng_attribute *attr;
/* capture */
int fps,first;
long long start;
struct v4l2_format fmt_v4l2;
struct ng_video_fmt fmt_me;
struct v4l2_requestbuffers reqbufs;
struct v4l2_buffer buf_v4l2[WANTED_BUFFERS];
struct ng_video_buf buf_me[WANTED_BUFFERS];
int queue,waiton;
/* overlay */
struct v4l2_framebuffer ov_fb;
struct v4l2_window ov_win;
struct v4l2_clip ov_clips[256];
int ov_error;
int ov_enabled;
int ov_on;
};
/* ---------------------------------------------------------------------- */
struct ng_vid_driver v4l2_driver = {
name: "v4l2-old",
open: v4l2_open,
close: v4l2_close,
get_devname: v4l2_devname,
capabilities: v4l2_flags,
list_attrs: v4l2_attrs,
setupfb: v4l2_setupfb,
overlay: v4l2_overlay,
setformat: v4l2_setformat,
startvideo: v4l2_startvideo,
stopvideo: v4l2_stopvideo,
nextframe: v4l2_nextframe,
getimage: v4l2_getimage,
getfreq: v4l2_getfreq,
setfreq: v4l2_setfreq,
is_tuned: v4l2_tuned,
};
static __u32 xawtv_pixelformat[VIDEO_FMT_COUNT] = {
0, /* unused */
V4L2_PIX_FMT_HI240, /* RGB8 */
V4L2_PIX_FMT_GREY, /* GRAY8 */
V4L2_PIX_FMT_RGB555, /* RGB15_LE */
V4L2_PIX_FMT_RGB565, /* RGB16_LE */
V4L2_PIX_FMT_RGB555X, /* RGB15_BE */
V4L2_PIX_FMT_RGB565X, /* RGB16_BE */
V4L2_PIX_FMT_BGR24, /* BGR24 */
V4L2_PIX_FMT_BGR32, /* BGR32 */
V4L2_PIX_FMT_RGB24, /* RGB24 */
0, /* RGB32 */
0, /* LUT 2 */
0, /* LUT 4 */
V4L2_PIX_FMT_YUYV, /* YUV422 */
V4L2_PIX_FMT_YUV422P, /* YUV422P */
V4L2_PIX_FMT_YUV420, /* YUV420P */
};
static struct STRTAB stereo[] = {
{ V4L2_TUNER_MODE_MONO, "mono" },
{ V4L2_TUNER_MODE_STEREO, "stereo" },
{ V4L2_TUNER_MODE_LANG1, "lang1" },
{ V4L2_TUNER_MODE_LANG2, "lang2" },
{ -1, NULL },
};
/* ---------------------------------------------------------------------- */
/* debug output */
#define PREFIX "ioctl: "
static const char *io_names[] = {
"QUERYCAP", "1", "ENUM_PIXFMT", "ENUM_FBUFFMT", "G_FMT", "S_FMT",
"G_COMP", "S_COMP", "REQBUFS", "QUERYBUF", "G_FBUF", "S_FBUF",
"G_WIN", "S_WIN", "PREVIEW", "QBUF", "16", "DQBUF", "STREAMON",
"STREAMOFF", "G_PERF", "G_PARM", "S_PARM", "G_STD", "S_STD",
"ENUMSTD", "ENUMINPUT", "G_CTRL", "S_CTRL", "G_TUNER", "S_TUNER",
"G_FREQ", "S_FREQ", "G_AUDIO", "S_AUDIO", "35", "QUERYCTRL",
"QUERYMENU", "G_INPUT", "S_INPUT", "ENUMCVT", "41", "42", "43",
"44", "45", "G_OUTPUT", "S_OUTPUT", "ENUMOUTPUT", "G_AUDOUT",
"S_AUDOUT", "ENUMFX", "G_EFFECT", "S_EFFECT", "G_MODULATOR",
"S_MODULATOR"
};
static const int io_count = (sizeof(io_names)/sizeof(char*));
#define IONAME(cmd) ((cmd & 0xff) < io_count ? \
io_names[cmd & 0xff] : "UNKNOWN")
static int
xioctl(int fd, int cmd, void *arg, int mayfail)
{
int rc;
rc = ioctl(fd,cmd,arg);
if (0 == rc && ng_debug < 2)
return rc;
if (mayfail && errno == mayfail && ng_debug < 2)
return rc;
switch (cmd) {
case VIDIOC_QUERYCAP:
{
struct v4l2_capability *a = arg;
fprintf(stderr,PREFIX "VIDIOC_QUERYCAP(%s,type=0x%x,in=%d,out=%d,"
"audio=%d,size=%dx%d-%dx%d,fps=%d,flags=0x%x)",
a->name,a->type,a->inputs,a->outputs,a->audios,
a->minwidth,a->minheight,a->maxwidth,a->maxheight,
a->maxframerate,a->flags);
break;
}
case VIDIOC_G_FMT:
case VIDIOC_S_FMT:
{
struct v4l2_format *a = arg;
fprintf(stderr,PREFIX "VIDIOC_%s(type=%d,",IONAME(cmd),a->type);
switch (a->type) {
case V4L2_BUF_TYPE_CAPTURE:
fprintf(stderr,
"%dx%d,depth=%d,%c%c%c%c,flags=0x%x,bpl=%d,size=%d)",
a->fmt.pix.width,a->fmt.pix.height,a->fmt.pix.depth,
a->fmt.pix.pixelformat & 0xff,
(a->fmt.pix.pixelformat >> 8) & 0xff,
(a->fmt.pix.pixelformat >> 16) & 0xff,
(a->fmt.pix.pixelformat >> 24) & 0xff,
a->fmt.pix.depth,a->fmt.pix.bytesperline,
a->fmt.pix.sizeimage);
break;
default:
fprintf(stderr,"??" "?)"); /* break trigraph */
break;
}
break;
}
case VIDIOC_REQBUFS:
{
struct v4l2_requestbuffers *a = arg;
fprintf(stderr,PREFIX "VIDIOC_REQBUFS(count=%d,type=%d)",
a->count,a->type);
break;
}
case VIDIOC_QBUF:
case VIDIOC_DQBUF:
{
struct v4l2_buffer *a = arg;
fprintf(stderr,PREFIX "VIDIOC_%s(%d,type=%d,off=%d,len=%d,used=%d,"
"flags=0x%x,ts=%Ld,seq=%d)",
IONAME(cmd),a->index,a->type,a->offset,a->length,
a->bytesused,a->flags,a->timestamp,a->sequence);
break;
}
case VIDIOC_G_WIN:
case VIDIOC_S_WIN:
{
struct v4l2_window *a = arg;
fprintf(stderr,PREFIX "VIDIOC_%s(%dx%d+%d+%d,key=0x%x,clips=%d)",
IONAME(cmd), a->width, a->height, a->x, a->y,
a->chromakey,a->clipcount);
break;
}
case VIDIOC_PREVIEW:
{
int *a = arg;
fprintf(stderr,PREFIX "VIDIOC_PREVIEW(%s)",*a ? "on" : "off");
break;
}
case VIDIOC_QUERYCTRL:
{
struct v4l2_queryctrl *a = arg;
fprintf(stderr,PREFIX "VIDIOC_QUERYCTRL(id=%d,%s,%d-%d/%d,def=%d,"
"type=%d,flags=0x%x)",
a->id,a->name,a->minimum,a->maximum,a->step,
a->default_value,a->type,a->flags);
break;
}
case VIDIOC_QUERYMENU:
{
struct v4l2_querymenu *a = arg;
fprintf(stderr,PREFIX "VIDIOC_QUERYMENU(id=%d,index=%d,%s)",
a->id,a->index,a->name);
break;
}
case VIDIOC_G_CTRL:
case VIDIOC_S_CTRL:
{
struct v4l2_control *a = arg;
fprintf(stderr,PREFIX "VIDIOC_%s(id=%d,value=%d)",
IONAME(cmd),a->id,a->value);
break;
}
default:
fprintf(stderr,PREFIX "VIDIOC_%s(cmd=0x%x)",IONAME(cmd),cmd);
break;
}
fprintf(stderr,": %s\n",(rc == 0) ? "ok" : strerror(errno));
return rc;
}
static void
print_bits(char *title, char **names, int count, int value)
{
int i;
fprintf(stderr,"%s: ",title);
for (i = 0; i < count; i++) {
if (value & (1 << i))
fprintf(stderr,"%s ",names[i]);
}
fprintf(stderr,"\n");
}
static void
print_device_capabilities(struct v4l2_handle *h)
{
static char *cap_type[] = {
"capture",
"codec",
"output",
"fx",
"vbi",
"vtr",
"vtx",
"radio",
};
static char *cap_flags[] = {
"read",
"write",
"streaming",
"preview",
"select",
"tuner",
"monochrome",
"teletext"
};
static char *ctl_type[] = {
"integer",
"boolean",
"menu"
};
static char *cap_parm[] = {
"highquality",
"vflip",
"hflip"
};
unsigned int i;
fprintf(stderr,"\n*** v4l2: video device capabilities ***\n");
/* capabilities */
fprintf(stderr, "type: %s\n", h->cap.type < SDIMOF(cap_type)
? cap_type[h->cap.type] : "unknown");
print_bits("flags",cap_flags,DIMOF(cap_flags),h->cap.flags);
fprintf(stderr,"\n");
fprintf(stderr,"inputs: %d\naudios: %d\n",h->cap.inputs,h->cap.audios);
fprintf(stderr,"size: %dx%d => %dx%d\n",
h->cap.minwidth,h->cap.minheight,h->cap.maxwidth,h->cap.maxheight);
fprintf(stderr,"fps: %d max\n",h->cap.maxframerate);
/* inputs */
fprintf(stderr,"video inputs:\n");
for (i = 0; i < h->ninputs; i++) {
printf(" %d: \"%s\", tuner: %s, audio: %s\n", i, h->inp[i].name,
(h->inp[i].type == V4L2_INPUT_TYPE_TUNER) ? "yes" : "no",
(h->inp[i].capability & V4L2_INPUT_CAP_AUDIO) ? "yes" : "no");
}
/* video standards */
fprintf(stderr,"video standards:\n");
for (i = 0; i < h->nstds; i++) {
printf(" %d: \"%s\"\n", i, h->std[i].std.name);
}
/* capture formats */
fprintf(stderr,"capture formats:\n");
for (i = 0; i < h->nfmts; i++) {
fprintf(stderr," %d: %c%c%c%c, depth=%d,%s \"%s\"\n", i,
h->fmt[i].pixelformat & 0xff,
(h->fmt[i].pixelformat >> 8) & 0xff,
(h->fmt[i].pixelformat >> 16) & 0xff,
(h->fmt[i].pixelformat >> 24) & 0xff,
h->fmt[i].depth,
(h->fmt[i].flags & V4L2_FMT_FLAG_COMPRESSED) ? " compressed" : "",
h->fmt[i].description);
}
/* capture parameters */
fprintf(stderr,"capture parameters:\n");
print_bits(" cap",cap_parm,sizeof(cap_parm)/sizeof(char*),
h->streamparm.parm.capture.capability);
print_bits(" cur",cap_parm,sizeof(cap_parm)/sizeof(char*),
h->streamparm.parm.capture.capturemode);
fprintf(stderr," timeperframe=%ld\n",
h->streamparm.parm.capture.timeperframe);
/* controls */
fprintf(stderr,"supported controls:\n");
for (i = 0; i < MAX_CTRL*2; i++) {
if (h->ctl[i].id == UNSET)
continue;
fprintf(stderr," %2d: \"%s\", [%d .. %d], step=%d, def=%d, type=%s\n",
i, h->ctl[i].name,
h->ctl[i].minimum,h->ctl[i].maximum,
h->ctl[i].step,h->ctl[i].default_value,
ctl_type[h->ctl[i].type]);
}
fprintf(stderr,"\n");
}
static void
print_bufinfo(struct v4l2_buffer *buf)
{
static char *type[] = {
"",
"capture",
"codec in",
"codec out",
"effects in1",
"effects in2",
"effects out",
"video out"
};
fprintf(stderr,"v4l2: buf %d: %s 0x%x+%d, used %d\n",
buf->index,
buf->type < sizeof(type)/sizeof(char*) ?
type[buf->type] : "unknown",
buf->offset,buf->length,buf->bytesused);
}
static void
print_fbinfo(struct v4l2_framebuffer *fb)
{
static char *fb_cap[] = {
"extern",
"chromakey",
"clipping",
"scale-up",
"scale-down"
};
static char *fb_flags[] = {
"primary",
"overlay",
"chromakey"
};
/* capabilities */
fprintf(stderr,"v4l2: framebuffer info\n");
print_bits(" cap",fb_cap,sizeof(fb_cap)/sizeof(char*),fb->capability);
print_bits(" flags",fb_cap,sizeof(fb_flags)/sizeof(char*),fb->flags);
fprintf(stderr," base: %p %p %p\n",fb->base[0],fb->base[1],fb->base[2]);
fprintf(stderr," format: %dx%d, %c%c%c%c, %d byte\n",
fb->fmt.width, fb->fmt.height,
fb->fmt.pixelformat & 0xff,
(fb->fmt.pixelformat >> 8) & 0xff,
(fb->fmt.pixelformat >> 16) & 0xff,
(fb->fmt.pixelformat >> 24) & 0xff,
fb->fmt.sizeimage);
}
/* ---------------------------------------------------------------------- */
/* helpers */
static void
get_device_capabilities(struct v4l2_handle *h)
{
unsigned int i;
for (h->ninputs = 0; h->ninputs < h->cap.inputs; h->ninputs++) {
h->inp[h->ninputs].index = h->ninputs;
if (-1 == xioctl(h->fd, VIDIOC_ENUMINPUT, &h->inp[h->ninputs], 0))
break;
}
for (h->nstds = 0; h->nstds < MAX_NORM; h->nstds++) {
h->std[h->nstds].index = h->nstds;
if (-1 == xioctl(h->fd, VIDIOC_ENUMSTD, &h->std[h->nstds], EINVAL))
break;
}
for (h->nfmts = 0; h->nfmts < MAX_FORMAT; h->nfmts++) {
h->fmt[h->nfmts].index = h->nfmts;
if (-1 == xioctl(h->fd, VIDIOC_ENUM_PIXFMT, &h->fmt[h->nfmts], EINVAL))
break;
}
h->streamparm.type = V4L2_BUF_TYPE_CAPTURE;
ioctl(h->fd,VIDIOC_G_PARM,&h->streamparm);
/* controls */
for (i = 0; i < MAX_CTRL; i++) {
h->ctl[i].id = V4L2_CID_BASE+i;
if (-1 == xioctl(h->fd, VIDIOC_QUERYCTRL, &h->ctl[i], EINVAL) ||
(h->ctl[i].flags & V4L2_CTRL_FLAG_DISABLED))
h->ctl[i].id = -1;
}
for (i = 0; i < MAX_CTRL; i++) {
h->ctl[i+MAX_CTRL].id = V4L2_CID_PRIVATE_BASE+i;
if (-1 == xioctl(h->fd, VIDIOC_QUERYCTRL, &h->ctl[i+MAX_CTRL], EINVAL) ||
(h->ctl[i+MAX_CTRL].flags & V4L2_CTRL_FLAG_DISABLED))
h->ctl[i+MAX_CTRL].id = -1;
}
}
static struct STRTAB *
build_norms(struct v4l2_handle *h)
{
struct STRTAB *norms;
unsigned int i;
norms = malloc(sizeof(struct STRTAB) * (h->nstds+1));
for (i = 0; i < h->nstds; i++) {
norms[i].nr = i;
norms[i].str = h->std[i].std.name;
}
norms[i].nr = -1;
norms[i].str = NULL;
return norms;
}
static struct STRTAB *
build_inputs(struct v4l2_handle *h)
{
struct STRTAB *inputs;
unsigned int i;
inputs = malloc(sizeof(struct STRTAB) * (h->ninputs+1));
for (i = 0; i < h->ninputs; i++) {
inputs[i].nr = i;
inputs[i].str = h->inp[i].name;
}
inputs[i].nr = -1;
inputs[i].str = NULL;
return inputs;
}
/* ---------------------------------------------------------------------- */
static struct V4L2_ATTR {
unsigned int id;
unsigned int v4l2;
} v4l2_attr[] = {
{ ATTR_ID_VOLUME, V4L2_CID_AUDIO_VOLUME },
{ ATTR_ID_MUTE, V4L2_CID_AUDIO_MUTE },
{ ATTR_ID_COLOR, V4L2_CID_SATURATION },
{ ATTR_ID_BRIGHT, V4L2_CID_BRIGHTNESS },
{ ATTR_ID_HUE, V4L2_CID_HUE },
{ ATTR_ID_CONTRAST, V4L2_CID_CONTRAST },
};
#define NUM_ATTR (sizeof(v4l2_attr)/sizeof(struct V4L2_ATTR))
static struct STRTAB*
v4l2_menu(int fd, const struct v4l2_queryctrl *ctl)
{
struct STRTAB *menu;
struct v4l2_querymenu item;
int i;
menu = malloc(sizeof(struct STRTAB) * (ctl->maximum-ctl->minimum+2));
for (i = ctl->minimum; i <= ctl->maximum; i++) {
item.id = ctl->id;
item.index = i;
if (-1 == xioctl(fd, VIDIOC_QUERYMENU, &item, 0)) {
free(menu);
return NULL;
}
menu[i-ctl->minimum].nr = i;
menu[i-ctl->minimum].str = strdup(item.name);
}
menu[i-ctl->minimum].nr = -1;
menu[i-ctl->minimum].str = NULL;
return menu;
}
static void
v4l2_add_attr(struct v4l2_handle *h, struct v4l2_queryctrl *ctl,
int id, struct STRTAB *choices)
{
static int private_ids = ATTR_ID_COUNT;
unsigned int i;
h->attr = realloc(h->attr,(h->nattr+2) * sizeof(struct ng_attribute));
memset(h->attr+h->nattr,0,sizeof(struct ng_attribute)*2);
if (ctl) {
for (i = 0; i < NUM_ATTR; i++)
if (v4l2_attr[i].v4l2 == ctl->id)
break;
if (i != NUM_ATTR) {
h->attr[h->nattr].id = v4l2_attr[i].id;
} else {
h->attr[h->nattr].id = private_ids++;
}
h->attr[h->nattr].name = ctl->name;
h->attr[h->nattr].priv = ctl;
h->attr[h->nattr].defval = ctl->default_value;
switch (ctl->type) {
case V4L2_CTRL_TYPE_INTEGER:
h->attr[h->nattr].type = ATTR_TYPE_INTEGER;
h->attr[h->nattr].defval = ctl->default_value;
h->attr[h->nattr].min = ctl->minimum;
h->attr[h->nattr].max = ctl->maximum;
break;
case V4L2_CTRL_TYPE_BOOLEAN:
h->attr[h->nattr].type = ATTR_TYPE_BOOL;
break;
case V4L2_CTRL_TYPE_MENU:
h->attr[h->nattr].type = ATTR_TYPE_CHOICE;
h->attr[h->nattr].choices = v4l2_menu(h->fd, ctl);
break;
default:
return;
}
} else {
/* for norms + inputs */
h->attr[h->nattr].id = id;
h->attr[h->nattr].defval = 0;
h->attr[h->nattr].type = ATTR_TYPE_CHOICE;
h->attr[h->nattr].choices = choices;
}
if (h->attr[h->nattr].id < ATTR_ID_COUNT)
h->attr[h->nattr].name = ng_attr_to_desc[h->attr[h->nattr].id];
h->attr[h->nattr].read = v4l2_read_attr;
h->attr[h->nattr].write = v4l2_write_attr;
h->attr[h->nattr].handle = h;
h->nattr++;
}
static int v4l2_read_attr(struct ng_attribute *attr)
{
struct v4l2_handle *h = attr->handle;
const struct v4l2_queryctrl *ctl = attr->priv;
struct v4l2_control c;
struct v4l2_tuner tuner;
int value = 0;
if (NULL != ctl) {
c.id = ctl->id;
xioctl(h->fd,VIDIOC_G_CTRL,&c,0);
value = c.value;
} else if (attr->id == ATTR_ID_NORM) {
value = -1; /* FIXME */
} else if (attr->id == ATTR_ID_INPUT) {
xioctl(h->fd,VIDIOC_G_INPUT,&value,0);
} else if (attr->id == ATTR_ID_AUDIO_MODE) {
memset(&tuner,0,sizeof(tuner));
xioctl(h->fd,VIDIOC_G_TUNER,&tuner,0);
value = tuner.audmode;
#if 1
if (ng_debug) {
fprintf(stderr,"v4l2: tuner cap:%s%s%s\n",
(tuner.capability&V4L2_TUNER_CAP_STEREO) ? " STEREO" : "",
(tuner.capability&V4L2_TUNER_CAP_LANG1) ? " LANG1" : "",
(tuner.capability&V4L2_TUNER_CAP_LANG2) ? " LANG2" : "");
fprintf(stderr,"v4l2: tuner rxs:%s%s%s%s\n",
(tuner.rxsubchans&V4L2_TUNER_SUB_MONO) ? " MONO" : "",
(tuner.rxsubchans&V4L2_TUNER_SUB_STEREO) ? " STEREO" : "",
(tuner.rxsubchans&V4L2_TUNER_SUB_LANG1) ? " LANG1" : "",
(tuner.rxsubchans&V4L2_TUNER_SUB_LANG2) ? " LANG2" : "");
fprintf(stderr,"v4l2: tuner cur:%s%s%s%s\n",
(tuner.audmode==V4L2_TUNER_MODE_MONO) ? " MONO" : "",
(tuner.audmode==V4L2_TUNER_MODE_STEREO) ? " STEREO" : "",
(tuner.audmode==V4L2_TUNER_MODE_LANG1) ? " LANG1" : "",
(tuner.audmode==V4L2_TUNER_MODE_LANG2) ? " LANG2" : "");
}
#endif
}
return value;
}
static void v4l2_write_attr(struct ng_attribute *attr, int value)
{
struct v4l2_handle *h = attr->handle;
const struct v4l2_queryctrl *ctl = attr->priv;
struct v4l2_control c;
struct v4l2_tuner tuner;
if (NULL != ctl) {
c.id = ctl->id;
c.value = value;
xioctl(h->fd,VIDIOC_S_CTRL,&c,0);
} else if (attr->id == ATTR_ID_NORM) {
xioctl(h->fd,VIDIOC_S_STD,&h->std[value].std,0);
} else if (attr->id == ATTR_ID_INPUT) {
xioctl(h->fd,VIDIOC_S_INPUT,&value,0);
} else if (attr->id == ATTR_ID_AUDIO_MODE) {
memset(&tuner,0,sizeof(tuner));
xioctl(h->fd,VIDIOC_G_TUNER,&tuner,0);
tuner.audmode = value;
xioctl(h->fd,VIDIOC_S_TUNER,&tuner,0);
}
}
/* ---------------------------------------------------------------------- */
static void*
v4l2_open(char *device)
{
struct v4l2_handle *h;
int i;
h = malloc(sizeof(*h));
if (NULL == h)
return NULL;
memset(h,0,sizeof(*h));
if (-1 == (h->fd = open(device, O_RDWR))) {
fprintf(stderr,"v4l2: open %s: %s\n",device,strerror(errno));
goto err;
}
if (-1 == ioctl(h->fd,VIDIOC_QUERYCAP,&h->cap))
goto err;
if (ng_debug)
fprintf(stderr, "v4l2: open\n");
fcntl(h->fd,F_SETFD,FD_CLOEXEC);
if (ng_debug)
fprintf(stderr,"v4l2: device is %s\n",h->cap.name);
get_device_capabilities(h);
if (ng_debug)
print_device_capabilities(h);
/* attributes */
v4l2_add_attr(h, NULL, ATTR_ID_NORM, build_norms(h));
v4l2_add_attr(h, NULL, ATTR_ID_INPUT, build_inputs(h));
if (h->cap.flags & V4L2_FLAG_TUNER)
v4l2_add_attr(h, NULL, ATTR_ID_AUDIO_MODE, stereo);
for (i = 0; i < MAX_CTRL*2; i++) {
if (h->ctl[i].id == UNSET)
continue;
v4l2_add_attr(h, &h->ctl[i], 0, NULL);
}
/* capture buffers */
for (i = 0; i < WANTED_BUFFERS; i++) {
ng_init_video_buf(h->buf_me+i);
h->buf_me[i].release = ng_wakeup_video_buf;
}
return h;
err:
if (h->fd != -1)
close(h->fd);
if (h)
free(h);
return NULL;
}
static int
v4l2_close(void *handle)
{
struct v4l2_handle *h = handle;
if (ng_debug)
fprintf(stderr, "v4l2: close\n");
close(h->fd);
free(h);
return 0;
}
static char*
v4l2_devname(void *handle)
{
struct v4l2_handle *h = handle;
return h->cap.name;
}
static int v4l2_flags(void *handle)
{
struct v4l2_handle *h = handle;
int ret = 0;
if (h->cap.flags & V4L2_FLAG_PREVIEW && !h->ov_error)
ret |= CAN_OVERLAY;
if ((h->cap.flags & V4L2_FLAG_STREAMING) ||
(h->cap.flags & V4L2_FLAG_READ))
ret |= CAN_CAPTURE;
if (h->cap.flags & V4L2_FLAG_TUNER)
ret |= CAN_TUNE;
return ret;
}
static struct ng_attribute* v4l2_attrs(void *handle)
{
struct v4l2_handle *h = handle;
return h->attr;
}
/* ---------------------------------------------------------------------- */
static unsigned long
v4l2_getfreq(void *handle)
{
struct v4l2_handle *h = handle;
unsigned long freq;
xioctl(h->fd, VIDIOC_G_FREQ, &freq, 0);
return freq;
}
static void
v4l2_setfreq(void *handle, unsigned long freq)
{
struct v4l2_handle *h = handle;
if (ng_debug)
fprintf(stderr,"v4l2: freq: %.3f\n",(float)freq/16);
xioctl(h->fd, VIDIOC_S_FREQ, &freq, 0);
}
static int
v4l2_tuned(void *handle)
{
struct v4l2_handle *h = handle;
struct v4l2_tuner tuner;
usleep(10000);
if (-1 == xioctl(h->fd,VIDIOC_G_TUNER,&tuner,0))
return 0;
return tuner.signal ? 1 : 0;
}
/* ---------------------------------------------------------------------- */
/* overlay */
static int
v4l2_setupfb(void *handle, struct ng_video_fmt *fmt, void *base)
{
struct v4l2_handle *h = handle;
if (-1 == xioctl(h->fd, VIDIOC_G_FBUF, &h->ov_fb, 0))
return -1;
if (1 /* ng_debug */)
print_fbinfo(&h->ov_fb);
/* double-check settings */
if (NULL != base && h->ov_fb.base[0] != base) {
fprintf(stderr,"v4l2: WARNING: framebuffer base address mismatch\n");
fprintf(stderr,"v4l2: me=%p v4l=%p\n",base,h->ov_fb.base);
h->ov_error = 1;
return -1;
}
if (h->ov_fb.fmt.width != fmt->width ||
h->ov_fb.fmt.height != fmt->height) {
fprintf(stderr,"v4l2: WARNING: framebuffer size mismatch\n");
fprintf(stderr,"v4l2: me=%dx%d v4l=%dx%d\n",
fmt->width,fmt->height,h->ov_fb.fmt.width,h->ov_fb.fmt.height);
h->ov_error = 1;
return -1;
}
if ((h->ov_fb.fmt.flags & V4L2_FMT_FLAG_BYTESPERLINE) &&
fmt->bytesperline > 0 &&
fmt->bytesperline != h->ov_fb.fmt.bytesperline) {
fprintf(stderr,"v4l2: WARNING: framebuffer bpl mismatch\n");
fprintf(stderr,"v4l2: me=%d v4l=%d\n",
fmt->bytesperline,h->ov_fb.fmt.bytesperline);
h->ov_error = 1;
return -1;
}
#if 0
if (h->ov_fb.fmt.pixelformat != xawtv_pixelformat[fmt->fmtid]) {
fprintf(stderr,"v4l2: WARNING: framebuffer format mismatch\n");
fprintf(stderr,"v4l2: me=%c%c%c%c [%s] v4l=%c%c%c%c\n",
xawtv_pixelformat[fmt->fmtid] & 0xff,
(xawtv_pixelformat[fmt->fmtid] >> 8) & 0xff,
(xawtv_pixelformat[fmt->fmtid] >> 16) & 0xff,
(xawtv_pixelformat[fmt->fmtid] >> 24) & 0xff,
ng_vfmt_to_desc[fmt->fmtid],
h->ov_fb.fmt.pixelformat & 0xff,
(h->ov_fb.fmt.pixelformat >> 8) & 0xff,
(h->ov_fb.fmt.pixelformat >> 16) & 0xff,
(h->ov_fb.fmt.pixelformat >> 24) & 0xff);
h->ov_error = 1;
return -1;
}
#endif
return 0;
}
static int
v4l2_overlay(void *handle, struct ng_video_fmt *fmt, int x, int y,
struct OVERLAY_CLIP *oc, int count, int aspect)
{
struct v4l2_handle *h = handle;
int rc,i;
if (h->ov_error)
return -1;
if (NULL == fmt) {
if (ng_debug)
fprintf(stderr,"v4l2: overlay off\n");
if (h->ov_enabled) {
h->ov_enabled = 0;
h->ov_on = 0;
xioctl(h->fd, VIDIOC_PREVIEW, &h->ov_on, 0);
}
return 0;
}
if (ng_debug)
fprintf(stderr,"v4l2: overlay win=%dx%d+%d+%d, %d clips\n",
fmt->width,fmt->height,x,y,count);
h->ov_win.x = x;
h->ov_win.y = y;
h->ov_win.width = fmt->width;
h->ov_win.height = fmt->height;
/* check against max. size */
ioctl(h->fd,VIDIOC_QUERYCAP,&h->cap);
if (h->ov_win.width > h->cap.maxwidth) {
h->ov_win.width = h->cap.maxwidth;
h->ov_win.x += (fmt->width - h->ov_win.width)/2;
}
if (h->ov_win.height > h->cap.maxheight) {
h->ov_win.height = h->cap.maxheight;
h->ov_win.y += (fmt->height - h->ov_win.height)/2;
}
if (aspect)
ng_ratio_fixup(&h->ov_win.width,&h->ov_win.height,
&h->ov_win.x,&h->ov_win.y);
/* fixups */
ng_check_clipping(h->ov_win.width, h->ov_win.height,
x - h->ov_win.x, y - h->ov_win.y,
oc, &count);
if (h->ov_fb.capability & V4L2_FBUF_CAP_CLIPPING) {
h->ov_win.clips = h->ov_clips;
h->ov_win.clipcount = count;
for (i = 0; i < count; i++) {
h->ov_clips[i].next = (i+1 == count) ? NULL : &h->ov_clips[i+1];
h->ov_clips[i].x = oc[i].x1;
h->ov_clips[i].y = oc[i].y1;
h->ov_clips[i].width = oc[i].x2-oc[i].x1;
h->ov_clips[i].height = oc[i].y2-oc[i].y1;
}
}
#if 0
if (h->ov_fb.flags & V4L2_FBUF_FLAG_CHROMAKEY) {
h->ov_win.chromakey = 0; /* FIXME */
}
#endif
rc = xioctl(h->fd, VIDIOC_S_WIN, &h->ov_win, 0);
h->ov_enabled = (0 == rc) ? 1 : 0;
h->ov_on = (0 == rc) ? 1 : 0;
xioctl(h->fd, VIDIOC_PREVIEW, &h->ov_on, 0);
return 0;
}
/* ---------------------------------------------------------------------- */
/* capture helpers */
static int
v4l2_queue_buffer(struct v4l2_handle *h)
{
int frame = h->queue % h->reqbufs.count;
int rc;
if (0 != h->buf_me[frame].refcount) {
if (0 != h->queue - h->waiton)
return -1;
fprintf(stderr,"v4l2: waiting for a free buffer\n");
ng_waiton_video_buf(h->buf_me+frame);
}
rc = xioctl(h->fd,VIDIOC_QBUF,&h->buf_v4l2[frame], 0);
if (0 == rc)
h->queue++;
return rc;
}
static void
v4l2_queue_all(struct v4l2_handle *h)
{
for (;;) {
if (h->queue - h->waiton >= h->reqbufs.count)
return;
if (0 != v4l2_queue_buffer(h))
return;
}
}
static int
v4l2_waiton(struct v4l2_handle *h)
{
struct v4l2_buffer buf;
struct timeval tv;
fd_set rdset;
/* wait for the next frame */
again:
tv.tv_sec = 5;
tv.tv_usec = 0;
FD_ZERO(&rdset);
FD_SET(h->fd, &rdset);
switch (select(h->fd + 1, &rdset, NULL, NULL, &tv)) {
case -1:
if (EINTR == errno)
goto again;
perror("v4l2: select");
return -1;
case 0:
fprintf(stderr,"v4l2: oops: select timeout\n");
return -1;
}
/* get it */
memset(&buf,0,sizeof(buf));
buf.type = V4L2_BUF_TYPE_CAPTURE;
if (-1 == xioctl(h->fd,VIDIOC_DQBUF,&buf, 0))
return -1;
h->waiton++;
h->buf_v4l2[buf.index] = buf;
return buf.index;
}
static int
v4l2_start_streaming(struct v4l2_handle *h, int buffers)
{
int disable_overlay = 0;
int i;
/* setup buffers */
h->reqbufs.count = buffers;
h->reqbufs.type = V4L2_BUF_TYPE_CAPTURE;
if (-1 == xioctl(h->fd, VIDIOC_REQBUFS, &h->reqbufs, 0))
return -1;
for (i = 0; i < h->reqbufs.count; i++) {
h->buf_v4l2[i].index = i;
h->buf_v4l2[i].type = V4L2_BUF_TYPE_CAPTURE;
if (-1 == ioctl(h->fd, VIDIOC_QUERYBUF, &h->buf_v4l2[i]))
return -1;
h->buf_me[i].fmt = h->fmt_me;
h->buf_me[i].size = h->buf_me[i].fmt.bytesperline *
h->buf_me[i].fmt.height;
h->buf_me[i].data = mmap(NULL, h->buf_v4l2[i].length,
PROT_READ | PROT_WRITE, MAP_SHARED,
h->fd, h->buf_v4l2[i].offset);
if ((void*)-1 == h->buf_me[i].data) {
perror("mmap");
return -1;
}
if (ng_debug)
print_bufinfo(&h->buf_v4l2[i]);
}
/* queue up all buffers */
v4l2_queue_all(h);
try_again:
/* turn off preview (if needed) */
if (disable_overlay) {
h->ov_on = 0;
xioctl(h->fd, VIDIOC_PREVIEW, &h->ov_on, 0);
if (ng_debug)
fprintf(stderr,"v4l2: overlay off (start_streaming)\n");
}
/* start capture */
if (-1 == xioctl(h->fd,VIDIOC_STREAMON,&h->fmt_v4l2.type,
h->ov_on ? EBUSY : 0)) {
if (h->ov_on && errno == EBUSY) {
disable_overlay = 1;
goto try_again;
}
return -1;
}
return 0;
}
static void
v4l2_stop_streaming(struct v4l2_handle *h)
{
int i;
/* stop capture */
if (-1 == ioctl(h->fd,VIDIOC_STREAMOFF,&h->fmt_v4l2.type))
perror("ioctl VIDIOC_STREAMOFF");
/* free buffers */
for (i = 0; i < h->reqbufs.count; i++) {
if (0 != h->buf_me[i].refcount)
ng_waiton_video_buf(&h->buf_me[i]);
if (-1 == munmap(h->buf_me[i].data,h->buf_me[i].size))
perror("munmap");
}
h->queue = 0;
h->waiton = 0;
/* turn on preview (if needed) */
if (h->ov_on != h->ov_enabled) {
h->ov_on = h->ov_enabled;
xioctl(h->fd, VIDIOC_PREVIEW, &h->ov_on, 0);
if (ng_debug)
fprintf(stderr,"v4l2: overlay on (stop_streaming)\n");
}
}
/* ---------------------------------------------------------------------- */
/* capture interface */
/* set capture parameters */
static int
v4l2_setformat(void *handle, struct ng_video_fmt *fmt)
{
struct v4l2_handle *h = handle;
h->fmt_v4l2.type = V4L2_BUF_TYPE_CAPTURE;
h->fmt_v4l2.fmt.pix.pixelformat = xawtv_pixelformat[fmt->fmtid];
h->fmt_v4l2.fmt.pix.flags = V4L2_FMT_FLAG_INTERLACED;
h->fmt_v4l2.fmt.pix.depth = ng_vfmt_to_depth[fmt->fmtid];
h->fmt_v4l2.fmt.pix.width = fmt->width;
h->fmt_v4l2.fmt.pix.height = fmt->height;
h->fmt_v4l2.fmt.pix.bytesperline = fmt->bytesperline;
if (-1 == xioctl(h->fd, VIDIOC_S_FMT, &h->fmt_v4l2, EINVAL))
return -1;
if (h->fmt_v4l2.fmt.pix.pixelformat != xawtv_pixelformat[fmt->fmtid])
return -1;
fmt->width = h->fmt_v4l2.fmt.pix.width;
fmt->height = h->fmt_v4l2.fmt.pix.height;
fmt->bytesperline = h->fmt_v4l2.fmt.pix.bytesperline;
if (0 == fmt->bytesperline)
fmt->bytesperline = fmt->width * ng_vfmt_to_depth[fmt->fmtid] / 8;
h->fmt_me = *fmt;
if (ng_debug)
fprintf(stderr,"v4l2: new capture params (%dx%d, %c%c%c%c, %d byte)\n",
fmt->width,fmt->height,
h->fmt_v4l2.fmt.pix.pixelformat & 0xff,
(h->fmt_v4l2.fmt.pix.pixelformat >> 8) & 0xff,
(h->fmt_v4l2.fmt.pix.pixelformat >> 16) & 0xff,
(h->fmt_v4l2.fmt.pix.pixelformat >> 24) & 0xff,
h->fmt_v4l2.fmt.pix.sizeimage);
return 0;
}
/* start/stop video */
static int
v4l2_startvideo(void *handle, int fps, unsigned int buffers)
{
struct v4l2_handle *h = handle;
if (0 != h->fps)
fprintf(stderr,"v4l2_startvideo: oops: fps!=0\n");
h->fps = fps;
h->first = 1;
h->start = 0;
if (h->cap.flags & V4L2_FLAG_STREAMING)
return v4l2_start_streaming(h,buffers);
return 0;
}
static void
v4l2_stopvideo(void *handle)
{
struct v4l2_handle *h = handle;
if (0 == h->fps)
fprintf(stderr,"v4l2_stopvideo: oops: fps==0\n");
h->fps = 0;
if (h->cap.flags & V4L2_FLAG_STREAMING)
v4l2_stop_streaming(h);
}
/* read images */
static struct ng_video_buf*
v4l2_nextframe(void *handle)
{
struct v4l2_handle *h = handle;
struct ng_video_buf *buf = NULL;
int rc,size,frame = 0;
if (h->cap.flags & V4L2_FLAG_STREAMING) {
v4l2_queue_all(h);
frame = v4l2_waiton(h);
if (-1 == frame)
return NULL;
h->buf_me[frame].refcount++;
buf = &h->buf_me[frame];
memset(&buf->info,0,sizeof(buf->info));
buf->info.ts = h->buf_v4l2[frame].timestamp;
} else {
size = h->fmt_me.bytesperline * h->fmt_me.height;
buf = ng_malloc_video_buf(&h->fmt_me,size);
rc = read(h->fd,buf->data,size);
if (rc != size) {
if (-1 == rc) {
perror("v4l2: read");
} else {
fprintf(stderr, "v4l2: read: rc=%d/size=%d\n",rc,size);
}
ng_release_video_buf(buf);
return NULL;
}
memset(&buf->info,0,sizeof(buf->info));
buf->info.ts = ng_get_timestamp();
}
if (h->first) {
h->first = 0;
h->start = buf->info.ts;
if (ng_debug)
fprintf(stderr,"v4l2: start ts=%lld\n",h->start);
}
buf->info.ts -= h->start;
return buf;
}
static struct ng_video_buf*
v4l2_getimage(void *handle)
{
struct v4l2_handle *h = handle;
struct ng_video_buf *buf;
int size,frame,rc;
size = h->fmt_me.bytesperline * h->fmt_me.height;
buf = ng_malloc_video_buf(&h->fmt_me,size);
if (h->cap.flags & V4L2_FLAG_READ) {
rc = read(h->fd,buf->data,size);
if (rc != size) {
if (-1 == rc) {
perror("v4l2: read");
} else {
fprintf(stderr, "v4l2: read: rc=%d/size=%d\n",rc,size);
}
ng_release_video_buf(buf);
return NULL;
}
} else {
if (-1 == v4l2_start_streaming(h,1)) {
v4l2_stop_streaming(h);
return NULL;
}
frame = v4l2_waiton(h);
if (-1 == frame) {
v4l2_stop_streaming(h);
return NULL;
}
memcpy(buf->data,h->buf_me[0].data,size);
v4l2_stop_streaming(h);
}
return buf;
}
/* ---------------------------------------------------------------------- */
extern void ng_plugin_init(void);
void ng_plugin_init(void)
{
ng_vid_driver_register(NG_PLUGIN_MAGIC,__FILE__,&v4l2_driver);
}
amsn-0.98.9/utils/linux/capture/libng/plugins/Makefile 0000644 0001750 0001750 00000000034 10246003435 022541 0 ustar billiob billiob default:
cd ../..; $(MAKE)
amsn-0.98.9/utils/linux/capture/libng/plugins/sn9c10x.c 0000644 0001750 0001750 00000022756 10574640152 022500 0 ustar billiob billiob /*
* SN9C10x formats
* (C) 2007 Gabriel Gambetta
*
* A libng plugin for the SN9C102 driver formats.
*
*
*
* BA81 decoding taken from :
*
* Sonix SN9C101 based webcam basic I/F routines
* Copyright (C) 2004 Takafumi Mizuno
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*
*
* S910 decoding taken from sn-webcam (http://sn-webcam.sourceforge.net)
*
*/
#define NG_PRIVATE
#include "config.h"
#include
#include
#include
#include
#include
#include
#include "grab-ng.h"
/* ======================================================================== */
/* BA81 decoder */
/* ======================================================================== */
static void* bayer_init (struct ng_video_fmt* out, void* priv)
{
return 0;
}
static void bayer_decompress (void* handle, struct ng_video_buf* out, struct ng_video_buf* in)
{
long int i;
unsigned char* rawpt;
unsigned char* scanpt;
long int size;
int WIDTH, HEIGHT;
WIDTH = in->fmt.width;
HEIGHT = in->fmt.height;
rawpt = in->data;
scanpt = out->data;
size = WIDTH * HEIGHT;
for (i = 0; i < size; i++)
{
if ((i / WIDTH) % 2 == 0)
{
if ((i % 2) == 0)
{
/* B */
if ((i > WIDTH) && ((i % WIDTH) > 0))
{
*scanpt++ = (*(rawpt - WIDTH - 1) + *(rawpt - WIDTH + 1) + *(rawpt + WIDTH - 1) + *(rawpt + WIDTH + 1)) / 4; /* R */
*scanpt++ = (*(rawpt - 1) + *(rawpt + 1) + *(rawpt + WIDTH) + *(rawpt - WIDTH)) / 4; /* G */
*scanpt++ = *rawpt; /* B */
}
else
{
/* first line or left column */
*scanpt++ = *(rawpt + WIDTH + 1); /* R */
*scanpt++ = (*(rawpt + 1) + *(rawpt + WIDTH)) / 2; /* G */
*scanpt++ = *rawpt; /* B */
}
}
else
{
/* (B)G */
if ((i > WIDTH) && ((i % WIDTH) < (WIDTH - 1)))
{
*scanpt++ = (*(rawpt + WIDTH) + *(rawpt - WIDTH)) / 2; /* R */
*scanpt++ = *rawpt; /* G */
*scanpt++ = (*(rawpt - 1) + *(rawpt + 1)) / 2; /* B */
}
else
{
/* first line or right column */
*scanpt++ = *(rawpt + WIDTH); /* R */
*scanpt++ = *rawpt; /* G */
*scanpt++ = *(rawpt - 1); /* B */
}
}
}
else
{
if ((i % 2) == 0)
{
/* G(R) */
if ((i < (WIDTH * (HEIGHT - 1))) && ((i % WIDTH) > 0))
{
*scanpt++ = (*(rawpt - 1) + *(rawpt + 1)) / 2; /* R */
*scanpt++ = *rawpt; /* G */
*scanpt++ = (*(rawpt + WIDTH) + *(rawpt - WIDTH)) / 2; /* B */
}
else
{
/* bottom line or left column */
*scanpt++ = *(rawpt + 1); /* R */
*scanpt++ = *rawpt; /* G */
*scanpt++ = *(rawpt - WIDTH); /* B */
}
}
else
{
/* R */
if (i < (WIDTH * (HEIGHT - 1)) && ((i % WIDTH) < (WIDTH - 1)))
{
*scanpt++ = *rawpt; /* R */
*scanpt++ = (*(rawpt - 1) + *(rawpt + 1) + *(rawpt - WIDTH) + *(rawpt + WIDTH)) / 4; /* G */
*scanpt++ = (*(rawpt - WIDTH - 1) + *(rawpt - WIDTH + 1) + *(rawpt + WIDTH - 1) + *(rawpt + WIDTH + 1)) / 4; /* B */
}
else
{
/* bottom line or right column */
*scanpt++ = *rawpt; /* R */
*scanpt++ = (*(rawpt - 1) + *(rawpt - WIDTH)) / 2; /* G */
*scanpt++ = *(rawpt - WIDTH - 1); /* B */
}
}
}
rawpt++;
}
}
static void bayer_cleanup (void* handle)
{
}
/* ======================================================================== */
/* SN10 decoder */
/* ======================================================================== */
#define CLAMP(x) ((x)<0?0:((x)>255)?255:(x))
typedef struct
{
int is_abs;
int len;
int val;
int unk;
} code_table_t;
/* local storage */
static code_table_t table[256];
static int init_done = 0;
/* global variable */
int sonix_unknown = 0;
/*
sonix_decompress_init
=====================
pre-calculates a locally stored table for efficient huffman-decoding.
Each entry at index x in the table represents the codeword
present at the MSB of byte x.
*/
static void sonix_decompress_init (void)
{
int i;
int is_abs, val, len, unk;
for (i = 0; i < 256; i++)
{
is_abs = 0;
val = 0;
len = 0;
unk = 0;
if ((i & 0x80) == 0)
{
/* code 0 */
val = 0;
len = 1;
}
else if ((i & 0xE0) == 0x80)
{
/* code 100 */
val = +4;
len = 3;
}
else if ((i & 0xE0) == 0xA0)
{
/* code 101 */
val = -4;
len = 3;
}
else if ((i & 0xF0) == 0xD0)
{
/* code 1101 */
val = +11;
len = 4;
}
else if ((i & 0xF0) == 0xF0)
{
/* code 1111 */
val = -11;
len = 4;
}
else if ((i & 0xF8) == 0xC8)
{
/* code 11001 */
val = +20;
len = 5;
}
else if ((i & 0xFC) == 0xC0)
{
/* code 110000 */
val = -20;
len = 6;
}
else if ((i & 0xFC) == 0xC4)
{
/* code 110001xx: unknown */
val = 0;
len = 8;
unk = 1;
}
else if ((i & 0xF0) == 0xE0)
{
/* code 1110xxxx */
is_abs = 1;
val = (i & 0x0F) << 4;
len = 8;
}
table[i].is_abs = is_abs;
table[i].val = val;
table[i].len = len;
table[i].unk = unk;
}
sonix_unknown = 0;
init_done = 1;
}
struct S910Context
{
unsigned char* sTempBuffer;
void* pBayerContext;
};
static void* s910_init (struct ng_video_fmt* out, void* priv)
{
struct S910Context* pContext;
if (!init_done)
sonix_decompress_init();
pContext = (struct S910Context*)malloc(sizeof(struct S910Context));
pContext->sTempBuffer = (unsigned char*)malloc(3*out->width*out->height);
pContext->pBayerContext = bayer_init(out, priv);
return pContext;
}
static void s910_decompress (void* handle, struct ng_video_buf* out, struct ng_video_buf* in)
{
int row, col;
int val;
int bitpos;
unsigned char code;
unsigned char* addr;
int width;
int height;
unsigned char* inp;
unsigned char* outp;
unsigned char* inp_save;
struct S910Context* pContext;
if (!init_done)
return;
pContext = (struct S910Context*)handle;
width = out->fmt.width;
height = out->fmt.height;
inp = in->data;
outp = pContext->sTempBuffer;
inp_save = in->data;
bitpos = 0;
for (row = 0; row < height; row++)
{
col = 0;
/* first two pixels in first two rows are stored as raw 8-bit */
if (row < 2)
{
addr = inp + (bitpos >> 3);
code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)));
bitpos += 8;
*outp++ = code;
addr = inp + (bitpos >> 3);
code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)));
bitpos += 8;
*outp++ = code;
col += 2;
}
while (col < width)
{
/* get bitcode from bitstream */
addr = inp + (bitpos >> 3);
code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)));
/* update bit position */
bitpos += table[code].len;
/* update code statistics */
sonix_unknown += table[code].unk;
/* calculate pixel value */
val = table[code].val;
if (!table[code].is_abs)
{
/* value is relative to top and left pixel */
if (col < 2)
{
/* left column: relative to top pixel */
val += outp[-2 * width];
}
else if (row < 2)
{
/* top row: relative to left pixel */
val += outp[-2];
}
else
{
/* main area: average of left pixel and top pixel */
val += (outp[-2] + outp[-2 * width]) / 2;
}
}
/* store pixel */
*outp++ = CLAMP(val);
col++;
}
}
in->data = pContext->sTempBuffer;
bayer_decompress(NULL, out, in);
in->data = inp_save;
}
static void s910_cleanup (void* handle)
{
struct S910Context* pContext;
pContext = (struct S910Context*)handle;
bayer_cleanup(pContext->pBayerContext);
free(pContext->sTempBuffer);
free(pContext);
}
/* ======================================================================== */
/* Init stuff */
/* ======================================================================== */
static struct ng_video_conv conv_list[] =
{
{
.init = s910_init,
.p.frame = s910_decompress,
.p.fini = s910_cleanup,
.p.mode = NG_MODE_TRIVIAL,
.fmtid_in = VIDEO_S910,
.fmtid_out = VIDEO_RGB24,
},
{
.init = bayer_init,
.p.frame = bayer_decompress,
.p.fini = bayer_cleanup,
.p.mode = NG_MODE_TRIVIAL,
.fmtid_in = VIDEO_BAYER,
.fmtid_out = VIDEO_RGB24,
},
};
static const int nconv = sizeof(conv_list)/sizeof(struct ng_video_conv);
/* ------------------------------------------------------------------- */
static void __init ng_plugin_init(void)
{
ng_conv_register(NG_PLUGIN_MAGIC, __FILE__, conv_list, nconv);
}
amsn-0.98.9/utils/linux/capture/libng/plugins/conv-mjpeg.c 0000644 0001750 0001750 00000051536 10545303304 023327 0 ustar billiob billiob #include "config.h"
#include
#include
#include
#include
#include
#include
#include "grab-ng.h"
/* ---------------------------------------------------------------------- */
struct mjpeg_compress {
struct jpeg_destination_mgr mjpg_dest; /* must be first */
struct jpeg_compress_struct mjpg_cinfo;
struct jpeg_error_mgr mjpg_jerr;
struct ng_video_fmt fmt;
JOCTET *mjpg_buffer;
size_t mjpg_bufsize;
size_t mjpg_bufused;
int mjpg_tables;
/* yuv */
unsigned char **mjpg_ptrs[3];
};
struct mjpeg_decompress {
struct jpeg_source_mgr mjpg_src; /* must be first */
struct jpeg_decompress_struct mjpg_cinfo;
struct jpeg_error_mgr mjpg_jerr;
struct ng_video_fmt fmt;
struct ng_video_buf *buf;
/* yuv */
unsigned char **mjpg_ptrs[3];
};
struct mjpeg_yuv_priv {
int luma_h;
int luma_v;
};
static void
swap_rgb24(char *mem, int n)
{
char c;
char *p = mem;
int i = n;
while (--i) {
c = p[0]; p[0] = p[2]; p[2] = c;
p += 3;
}
}
/* ---------------------------------------------------------------------- */
/* I/O manager */
static void mjpg_dest_init(struct jpeg_compress_struct *cinfo)
{
struct mjpeg_compress *h = (struct mjpeg_compress*)cinfo->dest;
cinfo->dest->next_output_byte = h->mjpg_buffer;
cinfo->dest->free_in_buffer = h->mjpg_bufsize;
}
static boolean mjpg_dest_flush(struct jpeg_compress_struct *cinfo)
{
fprintf(stderr,"mjpg: panic: output buffer too small\n");
exit(1);
}
static void mjpg_dest_term(struct jpeg_compress_struct *cinfo)
{
struct mjpeg_compress *h = (struct mjpeg_compress*)cinfo->dest;
h->mjpg_bufused = h->mjpg_bufsize - cinfo->dest->free_in_buffer;
}
static void mjpg_src_init(struct jpeg_decompress_struct *cinfo)
{
struct mjpeg_decompress *h = (struct mjpeg_decompress*)cinfo->src;
cinfo->src->next_input_byte = h->buf->data;
cinfo->src->bytes_in_buffer = h->buf->size;
}
static int mjpg_src_fill(struct jpeg_decompress_struct *cinfo)
{
fprintf(stderr,"mjpg: panic: no more input data\n");
exit(1);
}
static void mjpg_src_skip(struct jpeg_decompress_struct *cinfo,
long num_bytes)
{
cinfo->src->next_input_byte += num_bytes;
}
static void mjpg_src_term(struct jpeg_decompress_struct *cinfo)
{
/* nothing */
}
/* ---------------------------------------------------------------------- */
/* compress */
static struct mjpeg_compress*
mjpg_init(struct ng_video_fmt *fmt)
{
struct mjpeg_compress *h;
h = malloc(sizeof(*h));
if (NULL == h)
return NULL;
memset(h,0,sizeof(*h));
h->mjpg_cinfo.err = jpeg_std_error(&h->mjpg_jerr);
jpeg_create_compress(&h->mjpg_cinfo);
h->mjpg_dest.init_destination = mjpg_dest_init;
h->mjpg_dest.empty_output_buffer = mjpg_dest_flush;
h->mjpg_dest.term_destination = mjpg_dest_term;
h->mjpg_cinfo.dest = &h->mjpg_dest;
h->fmt = *fmt;
h->mjpg_tables = TRUE;
h->mjpg_cinfo.image_width = fmt->width;
h->mjpg_cinfo.image_height = fmt->height;
h->mjpg_cinfo.image_width &= ~(2*DCTSIZE-1);
h->mjpg_cinfo.image_height &= ~(2*DCTSIZE-1);
return h;
}
static void
mjpg_cleanup(void *handle)
{
struct mjpeg_compress *h = handle;
int i;
if (ng_debug > 1)
fprintf(stderr,"mjpg_cleanup\n");
jpeg_destroy_compress(&h->mjpg_cinfo);
for (i = 0; i < 3; i++)
if (NULL != h->mjpg_ptrs[i])
free(h->mjpg_ptrs[i]);
free(h);
}
/* ---------------------------------------------------------------------- */
static void*
mjpg_rgb_init(struct ng_video_fmt *out, void *priv)
{
struct mjpeg_compress *h;
if (ng_debug > 1)
fprintf(stderr,"mjpg_rgb_init\n");
h = mjpg_init(out);
if (NULL == h)
return NULL;
h->mjpg_cinfo.input_components = 3;
h->mjpg_cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&h->mjpg_cinfo);
h->mjpg_cinfo.dct_method = JDCT_FASTEST;
jpeg_set_quality(&h->mjpg_cinfo, ng_jpeg_quality, TRUE);
jpeg_suppress_tables(&h->mjpg_cinfo, TRUE);
return h;
}
static void
mjpg_rgb_compress(void *handle, struct ng_video_buf *out,
struct ng_video_buf *in)
{
struct mjpeg_compress *h = handle;
unsigned char *line;
unsigned int i;
if (ng_debug > 1)
fprintf(stderr,"mjpg_rgb_compress\n");
h->mjpg_buffer = out->data;
h->mjpg_bufsize = out->size;
jpeg_start_compress(&h->mjpg_cinfo, h->mjpg_tables);
for (i = 0, line = in->data; i < h->mjpg_cinfo.image_height;
i++, line += 3*h->mjpg_cinfo.image_width)
jpeg_write_scanlines(&h->mjpg_cinfo, &line, 1);
jpeg_finish_compress(&h->mjpg_cinfo);
out->size = h->mjpg_bufused;
}
static void
mjpg_bgr_compress(void *handle, struct ng_video_buf *out,
struct ng_video_buf *in)
{
swap_rgb24(in->data,in->fmt.width*in->fmt.height); /* FIXME */
return mjpg_rgb_compress(handle,out,in);
}
/* ---------------------------------------------------------------------- */
static void*
mjpg_yuv_init(struct ng_video_fmt *out, void *priv)
{
struct mjpeg_compress *h;
struct mjpeg_yuv_priv *c = priv;
if (ng_debug > 1)
fprintf(stderr,"mjpg_yuv_init\n");
h = mjpg_init(out);
if (NULL == h)
return NULL;
h->mjpg_cinfo.input_components = 3;
h->mjpg_cinfo.in_color_space = JCS_YCbCr;
jpeg_set_defaults(&h->mjpg_cinfo);
h->mjpg_cinfo.dct_method = JDCT_FASTEST;
jpeg_set_quality(&h->mjpg_cinfo, ng_jpeg_quality, TRUE);
h->mjpg_cinfo.raw_data_in = TRUE;
jpeg_set_colorspace(&h->mjpg_cinfo,JCS_YCbCr);
h->mjpg_ptrs[0] = malloc(h->fmt.height*sizeof(char*));
h->mjpg_ptrs[1] = malloc(h->fmt.height*sizeof(char*));
h->mjpg_ptrs[2] = malloc(h->fmt.height*sizeof(char*));
h->mjpg_cinfo.comp_info[0].h_samp_factor = c->luma_h;
h->mjpg_cinfo.comp_info[0].v_samp_factor = c->luma_v;
h->mjpg_cinfo.comp_info[1].h_samp_factor = 1;
h->mjpg_cinfo.comp_info[1].v_samp_factor = 1;
h->mjpg_cinfo.comp_info[2].h_samp_factor = 1;
h->mjpg_cinfo.comp_info[2].v_samp_factor = 1;
jpeg_suppress_tables(&h->mjpg_cinfo, TRUE);
return h;
}
static void
mjpg_420_compress(struct mjpeg_compress *h)
{
unsigned char **mjpg_run[3];
unsigned int y;
mjpg_run[0] = h->mjpg_ptrs[0];
mjpg_run[1] = h->mjpg_ptrs[1];
mjpg_run[2] = h->mjpg_ptrs[2];
jpeg_start_compress(&h->mjpg_cinfo, h->mjpg_tables);
for (y = 0; y < h->mjpg_cinfo.image_height; y += 2*DCTSIZE) {
jpeg_write_raw_data(&h->mjpg_cinfo, mjpg_run,2*DCTSIZE);
mjpg_run[0] += 2*DCTSIZE;
mjpg_run[1] += DCTSIZE;
mjpg_run[2] += DCTSIZE;
}
jpeg_finish_compress(&h->mjpg_cinfo);
}
static void
mjpg_422_compress(struct mjpeg_compress *h)
{
unsigned char **mjpg_run[3];
unsigned int y;
mjpg_run[0] = h->mjpg_ptrs[0];
mjpg_run[1] = h->mjpg_ptrs[1];
mjpg_run[2] = h->mjpg_ptrs[2];
h->mjpg_cinfo.write_JFIF_header = FALSE;
jpeg_start_compress(&h->mjpg_cinfo, h->mjpg_tables);
jpeg_write_marker(&h->mjpg_cinfo, JPEG_APP0, "AVI1\0\0\0\0", 8);
for (y = 0; y < h->mjpg_cinfo.image_height; y += DCTSIZE) {
jpeg_write_raw_data(&h->mjpg_cinfo, mjpg_run, DCTSIZE);
mjpg_run[0] += DCTSIZE;
mjpg_run[1] += DCTSIZE;
mjpg_run[2] += DCTSIZE;
}
jpeg_finish_compress(&h->mjpg_cinfo);
}
/* ---------------------------------------------------------------------- */
static void
mjpg_422_420_compress(void *handle, struct ng_video_buf *out,
struct ng_video_buf *in)
{
struct mjpeg_compress *h = handle;
unsigned char *line;
unsigned int i;
if (ng_debug > 1)
fprintf(stderr,"mjpg_422_420_compress\n");
h->mjpg_buffer = out->data;
h->mjpg_bufsize = out->size;
line = in->data;
for (i = 0; i < h->mjpg_cinfo.image_height; i++, line += in->fmt.width)
h->mjpg_ptrs[0][i] = line;
line = in->data + in->fmt.width*in->fmt.height;
for (i = 0; i < h->mjpg_cinfo.image_height; i+=2, line += in->fmt.width)
h->mjpg_ptrs[1][i/2] = line;
line = in->data + in->fmt.width*in->fmt.height*3/2;
for (i = 0; i < h->mjpg_cinfo.image_height; i+=2, line += in->fmt.width)
h->mjpg_ptrs[2][i/2] = line;
mjpg_420_compress(h);
out->size = h->mjpg_bufused;
}
static void
mjpg_420_420_compress(void *handle, struct ng_video_buf *out,
struct ng_video_buf *in)
{
struct mjpeg_compress *h = handle;
unsigned char *line;
unsigned int i;
if (ng_debug > 1)
fprintf(stderr,"mjpg_420_420_compress\n");
h->mjpg_buffer = out->data;
h->mjpg_bufsize = out->size;
line = in->data;
for (i = 0; i < h->mjpg_cinfo.image_height; i++, line += in->fmt.width)
h->mjpg_ptrs[0][i] = line;
line = in->data + in->fmt.width*in->fmt.height;
for (i = 0; i < h->mjpg_cinfo.image_height; i+=2, line += in->fmt.width/2)
h->mjpg_ptrs[1][i/2] = line;
line = in->data + in->fmt.width*in->fmt.height*5/4;
for (i = 0; i < h->mjpg_cinfo.image_height; i+=2, line += in->fmt.width/2)
h->mjpg_ptrs[2][i/2] = line;
mjpg_420_compress(h);
out->size = h->mjpg_bufused;
}
/* ---------------------------------------------------------------------- */
static void
mjpg_422_422_compress(void *handle, struct ng_video_buf *out,
struct ng_video_buf *in)
{
struct mjpeg_compress *h = handle;
unsigned char *line;
unsigned int i;
if (ng_debug > 1)
fprintf(stderr,"mjpg_422_422_compress\n");
h->mjpg_buffer = out->data;
h->mjpg_bufsize = out->size;
line = in->data;
for (i = 0; i < h->mjpg_cinfo.image_height; i++, line += in->fmt.width)
h->mjpg_ptrs[0][i] = line;
line = in->data + in->fmt.width*in->fmt.height;
for (i = 0; i < h->mjpg_cinfo.image_height; i++, line += in->fmt.width/2)
h->mjpg_ptrs[1][i] = line;
line = in->data + in->fmt.width*in->fmt.height*3/2;
for (i = 0; i < h->mjpg_cinfo.image_height; i++, line += in->fmt.width/2)
h->mjpg_ptrs[2][i] = line;
mjpg_422_compress(h);
out->size = h->mjpg_bufused;
}
/* ---------------------------------------------------------------------- */
/* decompress */
static void*
mjpg_de_init(struct ng_video_fmt *fmt, void *priv)
{
struct mjpeg_decompress *h;
h = malloc(sizeof(*h));
if (NULL == h)
return NULL;
memset(h,0,sizeof(*h));
h->fmt = *fmt;
h->mjpg_cinfo.err = jpeg_std_error(&h->mjpg_jerr);
jpeg_create_decompress(&h->mjpg_cinfo);
jpeg_load_dht((j_common_ptr)&h->mjpg_cinfo,
h->mjpg_cinfo.ac_huff_tbl_ptrs,
h->mjpg_cinfo.dc_huff_tbl_ptrs);
h->mjpg_src.init_source = mjpg_src_init;
h->mjpg_src.fill_input_buffer = mjpg_src_fill;
h->mjpg_src.skip_input_data = mjpg_src_skip;
h->mjpg_src.resync_to_restart = jpeg_resync_to_restart;
h->mjpg_src.term_source = mjpg_src_term;
h->mjpg_cinfo.src = &h->mjpg_src;
switch (h->fmt.fmtid) {
case VIDEO_YUV420P:
h->mjpg_ptrs[0] = malloc(h->fmt.height*sizeof(char*));
h->mjpg_ptrs[1] = malloc(h->fmt.height*sizeof(char*));
h->mjpg_ptrs[2] = malloc(h->fmt.height*sizeof(char*));
break;
}
return h;
}
static void
mjpg_rgb_decompress(void *handle, struct ng_video_buf *out,
struct ng_video_buf *in)
{
struct mjpeg_decompress *h = handle;
unsigned char *line;
unsigned int i;
if (ng_debug > 1)
fprintf(stderr,"mjpg_rgb_decompress\n");
h->buf = in;
jpeg_read_header(&h->mjpg_cinfo,1);
h->mjpg_cinfo.out_color_space = JCS_RGB;
jpeg_start_decompress(&h->mjpg_cinfo);
for (i = 0, line = out->data; i < out->fmt.height;
i++, line += out->fmt.bytesperline) {
jpeg_read_scanlines(&h->mjpg_cinfo, &line, 1);
}
jpeg_finish_decompress(&h->mjpg_cinfo);
}
static void
mjpg_yuv420_decompress(void *handle, struct ng_video_buf *out,
struct ng_video_buf *in)
{
struct mjpeg_decompress *h = handle;
unsigned char **mjpg_run[3];
unsigned char *line;
unsigned int i,y;
if (ng_debug > 1)
fprintf(stderr,"mjpg_yuv_decompress\n");
h->buf = in;
jpeg_read_header(&h->mjpg_cinfo,1);
h->mjpg_cinfo.raw_data_out = 1;
if (ng_debug > 1)
fprintf(stderr,"yuv: %dx%d - %d %d / %d %d / %d %d\n",
h->mjpg_cinfo.image_width,
h->mjpg_cinfo.image_height,
h->mjpg_cinfo.comp_info[0].h_samp_factor,
h->mjpg_cinfo.comp_info[0].v_samp_factor,
h->mjpg_cinfo.comp_info[1].h_samp_factor,
h->mjpg_cinfo.comp_info[1].v_samp_factor,
h->mjpg_cinfo.comp_info[2].h_samp_factor,
h->mjpg_cinfo.comp_info[2].v_samp_factor);
jpeg_start_decompress(&h->mjpg_cinfo);
mjpg_run[0] = h->mjpg_ptrs[0];
mjpg_run[1] = h->mjpg_ptrs[1];
mjpg_run[2] = h->mjpg_ptrs[2];
line = out->data;
for (i = 0; i < h->mjpg_cinfo.image_height; i++, line += out->fmt.width)
h->mjpg_ptrs[0][i] = line;
if (2 == h->mjpg_cinfo.comp_info[0].v_samp_factor) {
/* file has 420 -- all fine */
line = out->data + out->fmt.width*out->fmt.height;
for (i = 0; i < out->fmt.height; i+=2, line += out->fmt.width/2)
h->mjpg_ptrs[1][i/2] = line;
line = out->data + out->fmt.width*out->fmt.height*5/4;
for (i = 0; i < out->fmt.height; i+=2, line += out->fmt.width/2)
h->mjpg_ptrs[2][i/2] = line;
for (y = 0; y < out->fmt.height; y += 2*DCTSIZE) {
jpeg_read_raw_data(&h->mjpg_cinfo, mjpg_run,2*DCTSIZE);
mjpg_run[0] += 2*DCTSIZE;
mjpg_run[1] += DCTSIZE;
mjpg_run[2] += DCTSIZE;
}
} else {
/* file has 422 -- drop lines */
line = out->data + out->fmt.width*out->fmt.height;
for (i = 0; i < out->fmt.height; i+=2, line += out->fmt.width/2) {
h->mjpg_ptrs[1][i+0] = line;
h->mjpg_ptrs[1][i+1] = line;
}
line = out->data + out->fmt.width*out->fmt.height*5/4;
for (i = 0; i < out->fmt.height; i+=2, line += out->fmt.width/2) {
h->mjpg_ptrs[2][i+0] = line;
h->mjpg_ptrs[2][i+1] = line;
}
for (y = 0; y < h->mjpg_cinfo.image_height; y += DCTSIZE) {
jpeg_read_raw_data(&h->mjpg_cinfo, mjpg_run,DCTSIZE);
mjpg_run[0] += DCTSIZE;
mjpg_run[1] += DCTSIZE;
mjpg_run[2] += DCTSIZE;
}
}
jpeg_finish_decompress(&h->mjpg_cinfo);
}
static void
mjpg_de_cleanup(void *handle)
{
struct mjpeg_decompress *h = handle;
if (ng_debug > 1)
fprintf(stderr,"mjpg_de_cleanup\n");
jpeg_destroy_decompress(&h->mjpg_cinfo);
if (h->mjpg_ptrs[0])
free(h->mjpg_ptrs[0]);
if (h->mjpg_ptrs[1])
free(h->mjpg_ptrs[1]);
if (h->mjpg_ptrs[2])
free(h->mjpg_ptrs[2]);
free(h);
}
/* ---------------------------------------------------------------------- */
/* static data + register */
static struct mjpeg_yuv_priv priv_420 = {
luma_h: 2,
luma_v: 2,
};
static struct mjpeg_yuv_priv priv_422 = {
luma_h: 2,
luma_v: 1,
};
static struct ng_video_conv mjpg_list[] = {
{
/* --- compress --- */
.init= mjpg_yuv_init,
.p.frame= mjpg_420_420_compress,
.p.fini= mjpg_cleanup,
.p.mode= NG_MODE_TRIVIAL,
.fmtid_in= VIDEO_YUV420P,
.fmtid_out= VIDEO_JPEG,
.priv= &priv_420,
},{
.init= mjpg_yuv_init,
.p.frame= mjpg_422_420_compress,
.p.fini= mjpg_cleanup,
.p.mode= NG_MODE_TRIVIAL,
.fmtid_in= VIDEO_YUV422P,
.fmtid_out= VIDEO_JPEG,
.priv= &priv_420,
},{
.init= mjpg_rgb_init,
.p.frame= mjpg_rgb_compress,
.p.fini= mjpg_cleanup,
.p.mode= NG_MODE_TRIVIAL,
.fmtid_in= VIDEO_RGB24,
.fmtid_out= VIDEO_JPEG,
},{
.init= mjpg_rgb_init,
.p.frame= mjpg_bgr_compress,
.p.fini= mjpg_cleanup,
.p.mode= NG_MODE_TRIVIAL,
.fmtid_in= VIDEO_BGR24,
.fmtid_out= VIDEO_JPEG,
},{
.init= mjpg_yuv_init,
.p.frame= mjpg_422_422_compress,
.p.fini= mjpg_cleanup,
.p.mode= NG_MODE_TRIVIAL,
.fmtid_in= VIDEO_YUV422P,
.fmtid_out= VIDEO_MJPEG,
.priv= &priv_422,
},{
/* --- uncompress --- */
.init= mjpg_de_init,
.p.frame= mjpg_rgb_decompress,
.p.fini= mjpg_de_cleanup,
.p.mode= NG_MODE_TRIVIAL,
.fmtid_in= VIDEO_MJPEG,
.fmtid_out= VIDEO_RGB24,
},{
.init= mjpg_de_init,
.p.frame= mjpg_rgb_decompress,
.p.fini= mjpg_de_cleanup,
.p.mode= NG_MODE_TRIVIAL,
.fmtid_in= VIDEO_JPEG,
.fmtid_out= VIDEO_RGB24,
},{
.init= mjpg_de_init,
.p.frame= mjpg_yuv420_decompress,
.p.fini= mjpg_de_cleanup,
.p.mode= NG_MODE_TRIVIAL,
.fmtid_in= VIDEO_MJPEG,
.fmtid_out= VIDEO_YUV420P,
},{
.init= mjpg_de_init,
.p.frame= mjpg_yuv420_decompress,
.p.fini= mjpg_de_cleanup,
.p.mode= NG_MODE_TRIVIAL,
.fmtid_in= VIDEO_JPEG,
.fmtid_out= VIDEO_YUV420P,
}
};
static const int nconv = sizeof(mjpg_list)/sizeof(struct ng_video_conv);
//extern void ng_plugin_init(void);
static void __init ng_plugin_init(void)
{
ng_conv_register(NG_PLUGIN_MAGIC,__FILE__,mjpg_list,nconv);
}
// Here are huffmann tables
/* JPEG DHT Segment for YCrCb omitted from MJPG data */
static unsigned char
jpeg_odml_dht[0x1a4] = {
0xff, 0xc4, 0x01, 0xa2,
0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,
0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
0xf9, 0xfa,
0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77,
0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
0xf9, 0xfa
};
/* Parse the DHT table */
int jpeg_load_dht (j_common_ptr info, JHUFF_TBL* ac_tables[], JHUFF_TBL* dc_tables[])
{
unsigned int length = (jpeg_odml_dht[2] << 8) + jpeg_odml_dht[3] - 2;
unsigned int pos = 4;
unsigned int count, i;
int index;
JHUFF_TBL **hufftbl;
unsigned char bits[17];
unsigned char huffval[256];
while (length > 16) {
bits[0] = 0;
index = jpeg_odml_dht[pos++];
count = 0;
for (i = 1; i <= 16; ++i) {
bits[i] = jpeg_odml_dht[pos++];
count += bits[i];
}
length -= 17;
if (count > 256 || count > length)
return -1;
for (i = 0; i < count; ++i)
huffval[i] = jpeg_odml_dht[pos++];
length -= count;
if (index & 0x10) {
index -= 0x10;
hufftbl = &ac_tables[index];
} else
hufftbl = &dc_tables[index];
if (index < 0 || index >= NUM_HUFF_TBLS)
return -1;
if (*hufftbl == NULL)
*hufftbl = jpeg_alloc_huff_table (info);
if (*hufftbl == NULL)
return -1;
memcpy((*hufftbl)->bits, bits, sizeof (*hufftbl)->bits);
memcpy((*hufftbl)->huffval, huffval, sizeof (*hufftbl)->huffval);
}
if (length != 0)
return -1;
return 0;
}
amsn-0.98.9/utils/linux/capture/libng/plugins/drv0-bsd.c 0000644 0001750 0001750 00000055310 10246003435 022675 0 ustar billiob billiob /*
* interface to the bsd bktr driver
*
* (c) 2000-04 Gerd Knorr
*
*/
#include "config.h"
#include
#include
#include
#include
#include