951 lines
59 KiB
HTML
951 lines
59 KiB
HTML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||
<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Be Newsletters - Volume 2: 1997</title><link rel="stylesheet" href="be_newsletter.css" type="text/css" media="all" /><link rel="shortcut icon" type="image/vnd.microsoft.icon" href="./images/favicon.ico" /><!--[if IE]>
|
||
<link rel="stylesheet" type="text/css" href="be_newsletter_ie.css" />
|
||
<![endif]--><meta name="generator" content="DocBook XSL Stylesheets V1.73.2" /><link rel="start" href="index.html" title="Be Newsletters" /><link rel="up" href="volume2.html" title="Volume 2: 1997" /><link rel="prev" href="Issue2-46.html" title="Issue 2-46, November 19, 1997" /><link rel="next" href="Issue2-48.html" title="Issue 2-48, December 3, 1997" /></head><body><div id="header"><div id="headerT"><div id="headerTL"><a accesskey="p" href="Issue2-46.html" title="Issue 2-46, November 19, 1997"><img src="./images/navigation/prev.png" alt="Prev" /></a> <a accesskey="u" href="volume2.html" title="Volume 2: 1997"><img src="./images/navigation/up.png" alt="Up" /></a> <a accesskey="n" href="Issue2-48.html" title="Issue 2-48, December 3, 1997"><img src="./images/navigation/next.png" alt="Next" /></a></div><div id="headerTR"><div id="navigpeople"><a href="http://www.haiku-os.org"><img src="./images/People_24.png" alt="haiku-os.org" title="Visit The Haiku Website" /></a></div><div class="navighome" title="Home"><a accesskey="h" href="index.html"><img src="./images/navigation/home.png" alt="Home" /></a></div><div class="navigboxed" id="naviglang" title="English">en</div></div><div id="headerTC">Be Newsletters - Volume 2: 1997</div></div><div id="headerB">Prev: <a href="Issue2-46.html">Issue 2-46, November 19, 1997</a> Up: <a href="volume2.html">Volume 2: 1997</a> Next: <a href="Issue2-48.html">Issue 2-48, December 3, 1997</a></div><hr /></div><div class="article"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h2 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="Issue2-47"></a>Issue 2-47, November 26, 1997</h2></div></div></div><div class="sect1"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h2 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="Engineering2-47"></a>Be Engineering Insights: Buried Treasures...</h2></div><div xmlns:d="http://docbook.org/ns/docbook"><span xmlns="http://www.w3.org/1999/xhtml" class="author">By <span class="firstname">Dominic</span> <span class="surname">Giampaolo</span></span></div></div></div><p>
|
||
In a system like the BeOS, much effort goes into documenting the
|
||
specifics of programming the BeOS and not as much is spent documenting
|
||
more common parts of the libraries, such as the C library.
|
||
</p><p>
|
||
This makes sense, since there are numerous books on the C library and
|
||
POSIX that cover it in adequate detail. Unfortunately, when some of us
|
||
incorrigible C weenies add functions or extensions to the C library it
|
||
means that they tend not to get documented.
|
||
</p><p>
|
||
Thus, it pays to peruse the header files found in:
|
||
</p><p>
|
||
<code class="filename">/boot/develop/headers/posix/</code>
|
||
</p><p>
|
||
If you poke around in this directory, one "interesting" header you'll
|
||
find is <code class="filename">parsedate.h</code>.
|
||
This is the header file for the <code class="function">parsedate()</code> function
|
||
that I added to the BeOS C library (which is part of
|
||
<code class="filename">libroot.so</code>). The
|
||
<code class="function">parsedate()</code> routine is a sophisticated date parsing function that knows
|
||
how to convert from a human-readable string into a standard <span class="type">time_t</span>
|
||
variable (i.e., the number of seconds since January 1, 1970). It even
|
||
knows about time zones.
|
||
</p><p>
|
||
The <code class="function">parsedate()</code> routine is pretty nifty, because it understands common
|
||
time formats like "Mon, June 10th, 1993 10:00:03 am GMT". In fact,
|
||
<code class="function">parsedate()</code> understands virtually every imaginable verbose time format.
|
||
This includes all the typical formats that you'd see in an e-mail message
|
||
or Usenet news posting, or that other programs would print using <code class="function">ctime()</code>
|
||
or <code class="function">strftime()</code>. The initial list of date formats supported by <code class="function">parsedate()</code>
|
||
was generated by culling the Date: line from around 80,000 news postings,
|
||
so it's reliably comprehensive.
|
||
</p><p>
|
||
Having a routine that can parse such strings and return a canonical
|
||
integer time is very useful if you ever have to parse an e-mail header or
|
||
input a date that was output from another program. One drawback to using
|
||
time formats such as these is that their rigidity makes them difficult
|
||
for users to type. This becomes an issue if you need users to input a
|
||
date as part of your program and you want to use <code class="function">parsedate()</code>.
|
||
</p><p>
|
||
To remedy the problem of inflexible time formats, <code class="function">parsedate()</code> also
|
||
understands many natural date and time specifications. The
|
||
<code class="filename">parsedate.h</code>
|
||
file alludes to this, but doesn't really go into detail about what these
|
||
formats are. The parsedate function accepts the following "natural" time
|
||
formats (square brackets indicate an optional item):
|
||
</p><pre class="screen">
|
||
yesterday
|
||
today
|
||
tomorrow
|
||
[last | next] dayname (monday, tuesday, etc;
|
||
e.g., last monday)
|
||
[last | next] hour
|
||
[last | next] week
|
||
[last | next] month
|
||
[last | next] year
|
||
number minute (e.g. 15 min, -30 minutes)
|
||
number hour (e.g. 4 hours, -1 hour)
|
||
number day (e.g. 5 days, -3 days)
|
||
number month (e.g. 1 month, -2 months)
|
||
number year (e.g. 2 years, -3 years)
|
||
</pre><p>
|
||
Some slightly less casual but still fairly loose formats also work:
|
||
</p><pre class="screen">
|
||
11/10/97 3pm
|
||
Dec 25th 5:00pm
|
||
Friday July 9th
|
||
10am Sunday
|
||
</pre><p>
|
||
Because <code class="function">parsedate()</code> understands these types of formats, you can use it in
|
||
a variety of situations. It's easy to imagine a reminder/calendar program
|
||
that, as an option, lets users just type a day (i.e., remind me next
|
||
Thursday of ...). It's also possible to imagine a mail filter which would
|
||
scan message text for date strings and build a calendar automatically
|
||
(strings like "this Friday" are easily detectable).
|
||
</p><p>
|
||
<code class="function">parsedate()</code> is also helpful in the BeOS Find panel. For example, if you
|
||
need to find everything created in the last two days, you can do a find
|
||
by last modification time and simply enter the string "-2 days". Other
|
||
common finds might be everything modified since "yesterday" or "last
|
||
week".
|
||
</p><p>
|
||
Another aspect of <code class="function">parsedate()</code> is that when there's a choice of how to
|
||
interpret a date, it assumes you want a date after the current time. For
|
||
example, if today is Wednesday and you give a time of "monday",
|
||
<code class="function">parsedate()</code> interprets that to mean next Monday. If that's not what you
|
||
want, you may have to be more explicit or use a relative time format like
|
||
"-2 days".
|
||
</p><p>
|
||
We'll add support for other "casual" date formats as we come across them
|
||
(I've added about 10 more since I started writing this article). If you
|
||
have suggestions for other common formats, send them to us and we'll see
|
||
about adding them to the list (barring ambiguity problems).
|
||
</p><p>
|
||
To wrap things up, here is simple demonstration program that shows you
|
||
how to use <code class="function">parsedate()</code> and lets you play with inputs to it.
|
||
</p><pre class="programlisting cpp">
|
||
<span class="comment">/*
|
||
This is a simple program to demonstrate using parsedate()
|
||
on the BeOS.
|
||
dbg@be.com
|
||
*/</span>
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <time.h>
|
||
#include <parsedate.h>
|
||
|
||
<span class="type">int</span>
|
||
<code class="function">main</code>(<span class="type">int</span> <code class="parameter">argc</code>, <span class="type">char **</span><code class="parameter">argv</code>)
|
||
{
|
||
<span class="type">char</span> <code class="varname">str</code>[256];
|
||
<span class="type">time_t</span> <code class="varname">remind_time</code>;
|
||
<span class="type">struct tm *</span><code class="varname">tm</code>;
|
||
|
||
<code class="function">printf</code>("\nI am Chronos, the keeper of time.\n");
|
||
<code class="function">printf</code>("I am feared by ctime() implementors everywhere.\n");
|
||
<code class="function">printf</code>("Enter a time and I will parse it!\n\n");
|
||
|
||
while (<code class="function">fgets</code>(<code class="varname">str</code>, <code class="function">sizeof</code>(<code class="varname">str</code>), <code class="varname">stdin</code>) != <code class="constant">NULL</code>) {
|
||
if (<code class="varname">str</code>[0] == '\n')
|
||
continue;
|
||
if (<code class="function">strcmp</code>(<code class="varname">str</code>, "quit\n") == 0 ||
|
||
<code class="function">strcmp</code>(<code class="varname">str</code>, "exit\n") == 0)
|
||
break;
|
||
|
||
<span class="comment">/*
|
||
woo-hoo! here it is...dun dun da nah...
|
||
the call to parsedate()!
|
||
|
||
pretty complex eh? The -1 argument means to parse
|
||
relative to now.
|
||
*/</span>
|
||
|
||
<code class="varname">remind_time</code> = <code class="function">parsedate</code>(<code class="varname">str</code>, -1);
|
||
|
||
if (<code class="varname">remind_time</code> == ~0) {
|
||
<code class="function">fprintf</code>(<code class="varname">stderr</code>,
|
||
"\nHmmm:\n %sis not recognized.\n", str);
|
||
<code class="function">fprintf</code>(<code class="varname">stderr</code>,
|
||
"You should tell my trusty assistant dbg@be.com\n\n");
|
||
continue;
|
||
}
|
||
|
||
<code class="function">printf</code>("\nThe canonical form for the time you entered was:\n");
|
||
|
||
<span class="comment">/*
|
||
convert to a struct tm which has all the time fields
|
||
broken out
|
||
*/</span>
|
||
|
||
<code class="varname">tm</code> = <code class="function">localtime</code>(&<code class="varname">remind_time</code>);
|
||
|
||
<code class="function">printf</code>(" Year: %d Month: %d Day: %d Hour: %.2d:%.2d\n",
|
||
<code class="varname">tm</code>-><code class="varname">tm_year</code>, <code class="varname">tm</code>-><code class="varname">tm_mon</code>+1, <code class="varname">tm</code>-><code class="varname">tm_mday</code>, <code class="varname">tm</code>-><code class="varname">tm_hour</code>,
|
||
<code class="varname">tm</code>-><code class="varname">tm_min</code>);
|
||
|
||
<span class="comment">/*
|
||
also print the result of ctime()
|
||
*/</span>
|
||
|
||
<code class="function">printf</code>(" %s\n", <code class="function">ctime</code>(&<code class="varname">remind_time</code>));
|
||
}
|
||
}
|
||
</pre><p>
|
||
Have fun and maybe next time we'll poke around in that mysterious looking
|
||
header file called <code class="filename">malloc_internal.h</code>...
|
||
</p></div><hr class="pagebreak" /><div class="sect1"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h2 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="Engineering2-47-2"></a>A Remembrance of Things Past: Writing Mass Storage Device Drivers</h2></div><div xmlns:d="http://docbook.org/ns/docbook"><span xmlns="http://www.w3.org/1999/xhtml" class="author">By <span class="firstname">Dmitriy</span> <span class="surname">Budko</span></span></div></div></div><p>
|
||
When was the last time you used a RAM drive? Do you still remember what a
|
||
RAM drive is?
|
||
</p><p>
|
||
On my first PC (an AT 286, 12 MHz, 2 MB RAM) a RAM disk was the only
|
||
workable way to use more than 1 MB of memory while running under MS-DOS.
|
||
Unlike creaky MS-DOS, a current OS like the BeOS usually uses free memory
|
||
in the file system cache; in general, caching algorithms provide much
|
||
better performance than a simple RAM disk. Recently though, I was
|
||
overcome by inexplicable nostalgia for the good old days and I decided to
|
||
write a driver for that "disk" of yesteryear.
|
||
</p><p>
|
||
So if you have memory to burn, you may want to try using some of your
|
||
surplus as a RAM "disk." If nothing else you'll find out that a RAM disk
|
||
driver is an excellent example of using a device driver not only as a
|
||
hardware interface but also to emulate it! And if you develop a file
|
||
system driver, a big RAM disk can speed up the testing.
|
||
</p><p>
|
||
I assume that you know the basics of BeOS device drivers, so I'll focus
|
||
on features specific to mass storage devices (floppy drive, IDE disk,
|
||
IEEE 1394 [FireWire] disk) and on some tricks related to the volatile
|
||
nature of RAM.
|
||
</p><p>
|
||
The driver has to support all standard entry points. In addition it has
|
||
to handle some mass storage device I/O control codes.
|
||
</p><p>
|
||
I tried to make the driver as simple as possible, so it supports only one
|
||
RAM disk. Its dynamic configuration is almost nonexistent, and its
|
||
emulation of the hard drive seek process is very primitive. This
|
||
simplification let me forget about synchronization problems.
|
||
</p><p>
|
||
Here's the driver source code. You can find the original source,
|
||
unaltered for or by e-mail transmission, at:
|
||
</p><p>
|
||
ftp://ftp.be.com/pub/samples/preview/drivers/ramdrive.zip
|
||
</p><pre class="programlisting c">
|
||
<span class="comment">/****************** cut here ******************************/</span>
|
||
|
||
#include <OS.h>
|
||
#include <Drivers.h>
|
||
#include <KernelExport.h>
|
||
#include <stdlib.h>
|
||
|
||
<span class="type">status_t</span> <code class="function">vd_open</code>(<span class="type">const char *</span><code class="parameter">name</code>, <span class="type">uint32</span> <code class="parameter">flags</code>,
|
||
<span class="type">void **</span><code class="parameter">cookie</code>);
|
||
<span class="type">status_t</span> <code class="function">vd_free</code> (<span class="type">void *</span><code class="parameter">cookie</code>);
|
||
<span class="type">status_t</span> <code class="function">vd_close</code>(<span class="type">void *</span><code class="parameter">cookie</code>);
|
||
<span class="type">status_t</span> <code class="function">vd_control</code>(<span class="type">void *</span><code class="parameter">cookie</code>, <span class="type">uint32</span> <code class="parameter">msg</code>, <span class="type">void *</span><code class="parameter">buf</code>,
|
||
<span class="type">size_t</span> <code class="parameter">size</code>);
|
||
<span class="type">status_t</span> <code class="function">vd_read</code>(<span class="type">void *</span><code class="parameter">cookie</code>, <span class="type">off_t</span> <code class="parameter">pos</code>, <span class="type">void *</span><code class="parameter">buf</code>,
|
||
<span class="type">size_t *</span><code class="parameter">count</code>);
|
||
<span class="type">status_t</span> <code class="function">vd_write</code>(<span class="type">void *</span><code class="parameter">cookie</code>, <span class="type">off_t</span> <code class="parameter">pos</code>, <span class="type">constvoid *</span><code class="parameter">buf</code>,
|
||
<span class="type">size_t *</span><code class="parameter">count</code>);
|
||
|
||
static <span class="type">void</span> <code class="function">format_ram_drive</code>(<span class="type">void*</span> <code class="parameter">buf</code>);
|
||
static <span class="type">uchar*</span> <code class="function">create_ram_drive_area</code>(<span class="type">size_t</span> <code class="parameter">drive_size</code>);
|
||
static <span class="type">status_t</span> <code class="function">delete_ram_drive_area</code>(<span class="type">void</span>);
|
||
static <span class="type">void</span> <code class="function">emulate_seek</code>(<span class="type">off_t</span> <code class="parameter">pos</code>);
|
||
|
||
#define <code class="constant">RAM_DRIVE_RELEASE_MEMORY</code> (<code class="constant">B_DEVICE_OP_CODES_END</code>+1)
|
||
#define <code class="constant">RAM_DRIVE_EMULATE_SEEK</code> (<code class="constant">B_DEVICE_OP_CODES_END</code>+2)
|
||
|
||
#define <code class="constant">RAM_DRIVE_SIZE</code> (8*1024*1024)
|
||
#define <code class="constant">RAM_BLOCK_SIZE</code> 512
|
||
#define <code class="constant">MAX_SEEK_TIME</code> 1000.0 <span class="comment">/* microseconds */</span>
|
||
#define <code class="constant">PREFETCH_BUFFER_SIZE</code> (32*1024)
|
||
|
||
static <span class="type">const char*</span> const
|
||
<code class="varname">ram_drive_area_name</code> = "RAM drive area";
|
||
<span class="type">uchar</span> <code class="varname">icon_disk</code>[<code class="constant">B_LARGE_ICON</code> * <code class="constant">B_LARGE_ICON</code>];
|
||
<span class="type">uchar</span> <code class="varname">icon_disk_mini</code>[<code class="constant">B_MINI_ICON</code> * <code class="constant">B_MINI_ICON</code>];
|
||
<span class="type">int</span> <code class="varname">emulate_seek_flag</code> = <code class="constant">FALSE</code>;
|
||
<span class="type">uchar *</span> <code class="varname">ram</code> = <code class="constant">NULL</code>;
|
||
|
||
static <span class="type">const char *</span><code class="varname">vd_name</code>[] = {
|
||
"disk/virtual/ram_drive",
|
||
NULL
|
||
};
|
||
|
||
<span class="type">device_hooks</span> <code class="varname">vd_devices</code> = {
|
||
vd_open,
|
||
vd_close,
|
||
vd_free,
|
||
vd_control,
|
||
vd_read,
|
||
vd_write
|
||
};
|
||
|
||
<span class="type">status_t</span>
|
||
<code class="function">init_driver</code>(<span class="type">void</span>)
|
||
{
|
||
<code class="function">dprintf</code>("vd driver: %s %s, init_driver()\n",
|
||
__DATE__, __TIME__);
|
||
<code class="varname">ram</code> = <code class="function">create_ram_drive_area</code>(<code class="constant">RAM_DRIVE_SIZE</code>);
|
||
if(<code class="varname">ram</code> == <code class="constant">NULL</code>)
|
||
return <code class="constant">B_ERROR</code>;
|
||
return <code class="constant">B_NO_ERROR</code>;
|
||
}
|
||
|
||
<span class="type">void</span>
|
||
<code class="function">uninit_driver</code>(<span class="type">void</span>)
|
||
{
|
||
<code class="function">dprintf</code>("vd driver: uninit_driver()\n");
|
||
}
|
||
|
||
<span class="type">const char**</span>
|
||
<code class="function">publish_devices</code>()
|
||
{
|
||
<code class="function">dprintf</code>("vd driver: publish_devices()\n");
|
||
return <code class="varname">vd_name</code>;
|
||
}
|
||
|
||
<span class="type">device_hooks*</span>
|
||
<code class="function">find_device</code>(<span class="type">const char*</span> <code class="parameter">name</code>)
|
||
{
|
||
<code class="function">dprintf</code>("vd driver: find_device()\n");
|
||
return &<code class="varname">vd_devices</code>;
|
||
}
|
||
|
||
<span class="type">status_t</span>
|
||
<code class="function">vd_open</code>(<span class="type">const char *</span><code class="parameter">dname</code>, <span class="type">uint32</span> <code class="parameter">flags</code>, <span class="type">void **</span><code class="parameter">cookie</code>)
|
||
{
|
||
<code class="function">dprintf</code>("vd driver: open(%s)\n", <code class="parameter">dname</code>);
|
||
return <code class="constant">B_NO_ERROR</code>;
|
||
}
|
||
|
||
<span class="type">status_t</span>
|
||
<code class="function">vd_free</code>(<span class="type">void *</span><code class="parameter">cookie</code>)
|
||
{
|
||
<code class="function">dprintf</code>("vd driver: free()\n");
|
||
return <code class="constant">B_NO_ERROR</code>;
|
||
}
|
||
|
||
<span class="type">status_t</span>
|
||
<code class="function">vd_close</code>(<span class="type">void *</span><code class="parameter">cookie</code>)
|
||
{
|
||
<code class="function">dprintf</code>("vd driver: close()\n");
|
||
return <code class="constant">B_NO_ERROR</code>;
|
||
}
|
||
|
||
<span class="type">status_t</span>
|
||
<code class="function">vd_read</code>(<span class="type">void *</span><code class="parameter">cookie</code>, <span class="type">off_t</span> <code class="parameter">pos</code>, <span class="type">void *</span><code class="parameter">buf</code>, <span class="type">size_t *</span><code class="parameter">count</code>)
|
||
{
|
||
<span class="type">size_t</span> <code class="varname">len</code>;
|
||
<span class="type">status_t</span> <code class="varname">ret</code> = <code class="constant">B_NO_ERROR</code>;
|
||
|
||
if(<code class="parameter">pos</code> >= <code class="constant">RAM_DRIVE_SIZE</code>)
|
||
{
|
||
<code class="varname">len</code> = 0;
|
||
}
|
||
else
|
||
{
|
||
<code class="varname">len</code> = (<code class="parameter">pos</code> + (*<code class="parameter">count</code>) > <code class="constant">RAM_DRIVE_SIZE</code>) ?
|
||
(<code class="constant">RAM_DRIVE_SIZE</code> - <code class="parameter">pos</code>) : (*<code class="parameter">count</code>);
|
||
<code class="function">emulate_seek</code>(<code class="parameter">pos</code>);
|
||
<code class="function">memcpy</code>(<code class="parameter">buf</code>, <code class="varname">ram</code>+<code class="parameter">pos</code>, <code class="varname">len</code>);
|
||
}
|
||
*<code class="parameter">count</code> = <code class="varname">len</code>;
|
||
return <code class="varname">ret</code>;
|
||
}
|
||
|
||
<span class="type">status_t</span>
|
||
<code class="function">vd_write</code>(<span class="type">void *</span><code class="parameter">cookie</code>, <span class="type">off_t</span> <code class="parameter">pos</code>, <span class="type">constvoid *</span><code class="parameter">buf</code>,
|
||
<span class="type">size_t *</span><code class="parameter">count</code>)
|
||
{
|
||
<span class="type">size_t</span> <code class="varname">len</code>;
|
||
<span class="type">status_t</span> <code class="varname">ret</code> = <code class="constant">B_NO_ERROR</code>;
|
||
|
||
if(<code class="parameter">pos</code> >= <code class="constant">RAM_DRIVE_SIZE</code>)
|
||
{
|
||
<code class="varname">len</code> = 0;
|
||
}
|
||
else
|
||
{
|
||
<code class="varname">len</code> = (<code class="parameter">pos</code> + (*<code class="parameter">count</code>) > <code class="constant">RAM_DRIVE_SIZE</code>) ?
|
||
(<code class="constant">RAM_DRIVE_SIZE</code> - <code class="parameter">pos</code>) : (*<code class="parameter">count</code>);
|
||
<code class="function">emulate_seek</code>(<code class="parameter">pos</code>);
|
||
<code class="function">memcpy</code>(<code class="varname">ram</code>+<code class="parameter">pos</code>, <code class="parameter">buf</code>, <code class="varname">len</code>);
|
||
}
|
||
*<code class="parameter">count</code> = <code class="varname">len</code>;
|
||
return <code class="varname">ret</code>;
|
||
}
|
||
|
||
<span class="type">status_t</span>
|
||
<code class="function">vd_control</code>(<span class="type">void *</span><code class="parameter">cookie</code>, <span class="type">uint32</span> <code class="parameter">ioctl</code>, <span class="type">void *</span><code class="parameter">arg1</code>,
|
||
<span class="type">size_t</span> <code class="parameter">len</code>)
|
||
{
|
||
<span class="type">device_geometry *</span><code class="varname">dinfo</code>;
|
||
|
||
dprintf("vd driver: control(%d)\n", <code class="parameter">ioctl</code>);
|
||
switch (<code class="parameter">ioctl</code>)
|
||
{
|
||
|
||
<span class="comment">/* generic mass storage device IO control codes */</span>
|
||
|
||
case <code class="constant">B_GET_GEOMETRY</code>:
|
||
<code class="varname">dinfo</code> = (<span class="type">device_geometry *</span>) <code class="parameter">arg1</code>;
|
||
|
||
<code class="varname">dinfo</code>-><code class="varname">sectors_per_track</code> =
|
||
<code class="constant">RAM_DRIVE_SIZE</code>/<code class="constant">RAM_BLOCK_SIZE</code>;
|
||
<code class="varname">dinfo</code>-><code class="varname">cylinder_count</code> = 1;
|
||
<code class="varname">dinfo</code>-><code class="varname">head_count</code> = 1;
|
||
|
||
<code class="varname">dinfo</code>-><code class="varname">bytes_per_sector</code> = <code class="constant">RAM_BLOCK_SIZE</code>;
|
||
<code class="varname">dinfo</code>-><code class="varname">removable</code> = <code class="constant">FALSE</code> ;
|
||
<code class="varname">dinfo</code>-><code class="varname">read_only</code> = <code class="constant">FALSE</code>;
|
||
<code class="varname">dinfo</code>-><code class="varname">device_type</code> = <code class="constant">B_DISK</code>;
|
||
<code class="varname">dinfo</code>-><code class="varname">write_once</code> = <code class="constant">FALSE</code>;
|
||
|
||
return <code class="constant">B_NO_ERROR</code>;
|
||
|
||
case <code class="constant">B_FORMAT_DEVICE</code>:
|
||
<code class="function">format_ram_drive</code>(<code class="varname">ram</code>);
|
||
return <code class="constant">B_NO_ERROR</code>;
|
||
|
||
case <code class="constant">B_GET_DEVICE_SIZE</code>:
|
||
*(<span class="type">size_t*</span>)<code class="parameter">arg1</code> = <code class="constant">RAM_DRIVE_SIZE</code>;
|
||
return <code class="constant">B_NO_ERROR</code>;
|
||
|
||
case <code class="constant">B_GET_ICON</code>:
|
||
switch (((<span class="type">device_icon *</span>)<code class="parameter">arg1</code>)-><code class="varname">icon_size</code>)
|
||
{
|
||
case <code class="constant">B_LARGE_ICON</code>:
|
||
<code class="function">memcpy</code>(((<span class="type">device_icon *</span>)<code class="parameter">arg1</code>)-><code class="varname">icon_data</code>, <code class="varname">icon_disk</code>,
|
||
<code class="constant">B_LARGE_ICON</code> * <code class="constant">B_LARGE_ICON</code>);
|
||
break;
|
||
|
||
case <code class="constant">B_MINI_ICON</code>:
|
||
<code class="function">memcpy</code>(((<span class="type">device_icon *</span>)<code class="parameter">arg1</code>)-><code class="varname">icon_data</code>,
|
||
<code class="varname">icon_disk_mini</code>, <code class="constant">B_MINI_ICON</code> * <code class="constant">B_MINI_ICON</code>);
|
||
break;
|
||
|
||
default:
|
||
return <code class="constant">B_BAD_TYPE</code>;
|
||
}
|
||
return <code class="constant">B_NO_ERROR</code>;
|
||
|
||
<span class="comment">/* device specific IO control codes */</span>
|
||
|
||
case <code class="constant">RAM_DRIVE_RELEASE_MEMORY</code>:
|
||
return <code class="function">delete_ram_drive_area</code>();
|
||
|
||
case <code class="constant">RAM_DRIVE_EMULATE_SEEK</code>:
|
||
<code class="varname">emulate_seek_flag</code> = *(<span class="type">int*</span>)<code class="parameter">arg1</code>;
|
||
return <code class="constant">B_NO_ERROR</code>;
|
||
|
||
default:
|
||
return <code class="constant">B_ERROR</code>;
|
||
}
|
||
}
|
||
|
||
static <span class="type">void</span> <code class="function">format_ram_drive</code>(<span class="type">void*</span> <code class="parameter">buf</code>)
|
||
{
|
||
static <span class="type">const char</span> <code class="varname">format_str</code>[16] = "RAM drive ";
|
||
<span class="type">uchar*</span> <code class="varname">ptr</code> = (<span class="type">uchar*</span>)<code class="parameter">buf</code>;
|
||
<span class="type">off_t</span> <code class="varname">i</code>;
|
||
|
||
<code class="function">dprintf</code>("vd driver: format_ram_drive(%08x)\n", <code class="parameter">buf</code>);
|
||
for(<code class="varname">i</code>=0; <code class="varname">i</code><<code class="constant">RAM_DRIVE_SIZE</code>/16; <code class="varname">i</code>++)
|
||
{
|
||
<code class="function">memcpy</code>(<code class="varname">ptr</code>, <code class="varname">format_str</code>, 16);
|
||
<code class="varname">ptr</code> += 16;
|
||
}
|
||
|
||
}
|
||
|
||
static <span class="type">uchar*</span>
|
||
<code class="function">create_ram_drive_area</code>(<span class="type">size_t</span> <code class="parameter">drive_size</code>)
|
||
{
|
||
<span class="type">void*</span> <code class="varname">addr</code>;
|
||
<span class="type">area_id</span> <code class="varname">area</code> = find_area(<code class="varname">ram_drive_area_name</code>);
|
||
|
||
if(<code class="varname">area</code> == <code class="constant">B_NAME_NOT_FOUND</code>)
|
||
{
|
||
<code class="varname">area</code> = <code class="function">create_area</code>(<code class="varname">ram_drive_area_name</code>,
|
||
&<code class="varname">addr</code>,
|
||
<code class="constant">B_ANY_KERNEL_ADDRESS</code>,<span class="comment">/*kernel team will own this area*/</span>
|
||
<code class="parameter">drive_size</code>,
|
||
<code class="constant">B_LAZY_LOCK</code>,
|
||
<code class="constant">B_READ_AREA</code> | <code class="constant">B_WRITE_AREA</code>);
|
||
|
||
if((<code class="varname">area</code>==<code class="constant">B_ERROR</code>) ||
|
||
(<code class="varname">area</code>==<code class="constant">B_NO_MEMORY</code>) ||
|
||
(<code class="varname">area</code>==<code class="constant">B_BAD_VALUE</code>))
|
||
<code class="varname">addr</code> = <code class="constant">NULL</code>;
|
||
}
|
||
else
|
||
{
|
||
<span class="type">area_info</span> <code class="varname">info</code>;
|
||
|
||
<code class="function">get_area_info</code>(<code class="varname">area</code>, &<code class="varname">info</code>);
|
||
<code class="varname">addr</code> = <code class="varname">info</code>.<code class="varname">address</code>;
|
||
}
|
||
return (<span class="type">uchar*</span>)<code class="varname">addr</code>;
|
||
}
|
||
|
||
static <span class="type">status_t</span>
|
||
<code class="function">delete_ram_drive_area</code>(<span class="type">void</span>)
|
||
{
|
||
<span class="type">area_id</span> <code class="varname">area</code> = <code class="function">find_area</code>(<code class="varname">ram_drive_area_name</code>);
|
||
|
||
if(<code class="varname">area</code> == <code class="constant">B_NAME_NOT_FOUND</code>)
|
||
return <code class="constant">B_ERROR</code>;
|
||
else
|
||
return <code class="function">delete_area</code>(<code class="varname">area</code>);
|
||
}
|
||
|
||
static <span class="type">void</span>
|
||
<code class="function">emulate_seek</code>(<span class="type">off_t</span> <code class="parameter">pos</code>)
|
||
{
|
||
static <span class="type">off_t</span> <code class="varname">old_pos</code> = 0;
|
||
|
||
if(!<code class="varname">emulate_seek_flag</code>)
|
||
return;
|
||
|
||
if(abs(<code class="parameter">pos</code>-<code class="varname">old_pos</code>)><code class="constant">PREFETCH_BUFFER_SIZE</code>)
|
||
{
|
||
<code class="varname">old_pos</code> = <code class="parameter">pos</code>;
|
||
<code class="function">snooze</code>((<span class="type">int</span>)(<code class="function">rand()</code>* <code class="constant">MAX_SEEK_TIME</code>)/<code class="constant">RAND_MAX</code>);
|
||
}
|
||
}
|
||
|
||
<span class="comment">/****************** cut here ******************************/</span>
|
||
</pre><p>
|
||
What happens is that <code class="function">init_driver()</code> creates the kernel memory area that's
|
||
used to store the data. The driver can't use
|
||
<code class="function">malloc()</code>/<code class="function">free()</code> because when
|
||
the driver is unloaded the memory (and all data) is lost. It's actually
|
||
present somewhere, but there's no easy way to find it when the driver is
|
||
loaded again.
|
||
</p><p>
|
||
So <code class="function">init_driver()</code> calls <code class="function">create_ram_drive_area()</code>, which tries to find the
|
||
previously created memory area with the name "RAM drive area." If the
|
||
search is unsuccessful the driver is loaded the first time. In that case
|
||
<code class="function">create_ram_drive_area()</code> creates the memory area. It uses a currently
|
||
undocumented flag, <code class="constant">B_ANY_KERNEL_ADDRESS</code>. This flag gives ownership of
|
||
this memory area to the kernel, so the area will not be deleted when the
|
||
application that opened the driver quits.
|
||
</p><p>
|
||
It also uses the <code class="constant">B_LAZY_LOCK</code> flag so the driver doesn't consume RAM until
|
||
the first time you use it. I could have used <code class="constant">B_FULL_LOCK</code> and put the
|
||
memory allocation in <code class="function">vd_open()</code>, but being lazy I didn't want to provide a
|
||
critical section synchronization for it.
|
||
</p><p>
|
||
<code class="function">vd_open()</code> can be called a few times simultaneously;
|
||
<code class="function">init_driver()</code> cannot.
|
||
<code class="function">publish_devices()</code> creates the device file in
|
||
<code class="filename">/dev/disk/virtual/ram_drive</code>.
|
||
The <code class="filename">/virtual/ram_drive</code> part of the name is arbitrary, but
|
||
<code class="filename">/dev/disk</code>
|
||
is mandatory if you want to use a standard disk setup program—like
|
||
<span class="application">DriveSetup</span>—to configure the RAM disk.
|
||
</p><p>
|
||
<code class="function">vd_open()</code>, <code class="function">vd_free()</code>, and
|
||
<code class="function">vd_close()</code> do nothing and return success.
|
||
</p><p>
|
||
<code class="function">vd_read()</code> and <code class="function">vd_write()</code> check
|
||
to see if the caller tries to read/write
|
||
over the end of the disk. They adjust the requested length accordingly,
|
||
then simply copy the data from/to the requested offset in the RAM area
|
||
to/from the caller's buffer.
|
||
</p><p>
|
||
If <code class="varname">emulate_seek_flag</code> is set the driver calls
|
||
<code class="function">emulate_seek()</code>.
|
||
<code class="function">emulate_seek()</code> is a crude imitation of real hard drive mechanics and
|
||
caching. The current implementation is not in a critical section so it is
|
||
capable of multiple concurrent seeks. It would be great to have a real
|
||
drive with an infinite number of head arms! Readers are welcome to create
|
||
a more realistic model.
|
||
</p><p>
|
||
Still, with this function implemented, the RAM drive is better suited for
|
||
testing a file system driver. It can block the caller's thread as a driver
|
||
for a real drive would do.
|
||
</p><p>
|
||
<code class="function">vd_control()</code> handles four generic I/O control codes for a mass storage
|
||
device: <code class="constant">B_GET_GEOMETRY</code>, <code class="constant">B_FORMAT_DEVICE</code>,
|
||
<code class="constant">B_GET_DEVICE_SIZE</code>, <code class="constant">B_GET_ICON</code>.
|
||
The first three are mandatory; the last one is optional.
|
||
</p><p>
|
||
This driver has zero-initialized arrays for large and small icons. The
|
||
real driver should provide more pleasing icons than black rectangles.
|
||
</p><p>
|
||
<code class="constant">RAM_DRIVE_RELEASE_MEMORY</code> deletes the allocated memory area and thus
|
||
destroys all information on the RAM drive. <code class="constant">RAM_DRIVE_EMULATE_SEEK</code> sets or
|
||
clears the <code class="varname">emulate_seek_flag</code>. A control panel application for the RAM
|
||
drive could send such commands.
|
||
</p><p>
|
||
Now here's how to build and install the driver:
|
||
</p><div class="orderedlist"><ol><li><p>
|
||
Instruct the linker to produce an add-on image.
|
||
</p></li><li><p>
|
||
Disable linking to the default shared system libraries.
|
||
</p></li><li><p>
|
||
Export the driver's entry points—for example, by exporting
|
||
everything.
|
||
</p></li><li><p>
|
||
Place a copy of the appropriate kernel file (<code class="filename">kernel_joe</code>,
|
||
<code class="filename">kernel_mac</code>, or <code class="filename">kernel_intel</code>) in your project directory. Link against
|
||
this file.
|
||
</p></li><li><p>
|
||
Copy the compiled driver in the
|
||
<code class="filename">/boot/home/config/add-ons/kernel/drivers</code> directory.
|
||
</p></li><li><p>
|
||
Use your favorite disk format program or BeOS
|
||
preferences/DriveSetup to partition and/or install BFS on the
|
||
<code class="filename">/dev/disk/virtual/ram_drive</code> device.
|
||
</p></li></ol></div><p>
|
||
That's it. You're all set!
|
||
</p><p>
|
||
I hope that this simple device driver may help get somebody started in
|
||
BeOS driver development. If any seasoned device drivers out there have
|
||
feature requests or comments (why does Be have such-and-such stupid
|
||
restriction or does not have such-and-such device driver API ...), let me
|
||
know and I'll try to implement them. The Intel port in particular may
|
||
require same changes: @#$% ISA 16 MB limit on DMA, PCI interrupt sharing,
|
||
ISA PnP, etc.
|
||
</p><p>
|
||
Speak now and you can make your life running the BeOS on Intel that much
|
||
easier!
|
||
</p></div><hr class="pagebreak" /><div class="sect1"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h2 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="DevWorkshop2-47"></a>Developers' Workshop: BYOB!</h2></div><div xmlns:d="http://docbook.org/ns/docbook"><span xmlns="http://www.w3.org/1999/xhtml" class="author">By <span class="firstname">Doug</span> <span class="surname">Wright</span></span></div></div></div><p>
|
||
"Developers' Workshop" is a new weekly feature that provides answers to
|
||
our developers' questions. Each week, a Be technical support or
|
||
documentation professional will choose a question (or two) sent in by an
|
||
actual developer and provide an answer.
|
||
</p><p>
|
||
We've created a new section on our website. Please send us your
|
||
Newsletter topic suggestions by visiting the website at:
|
||
http://www.be.com/developers/suggestion_box.html.
|
||
</p><p>
|
||
Hello Be people. As the newest Developer Technical Support Engineer, I
|
||
have spoken with some of you recently regarding specific problems but
|
||
this is my first taste of the Be Newsletter audience. Playing live shows
|
||
in a band once or twice a month has tamed my wild urge to run and hide in
|
||
front of a crowd, but writing an article that persists over time
|
||
definitely feels different then being live on stage.
|
||
</p><p>
|
||
So with a little nervousness, I present you with my first (not last!) bit
|
||
of Be insight, in two parts. The subjects were inspired by many things
|
||
but the titles were inspired by my favorite thing—BYOB!
|
||
</p><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id605525"></a>Part I: Bring Your Own Bugs!</h3></div></div></div><p>
|
||
Melissa has graciously given me the task of evaluating bugs submitted by
|
||
developers. In attempting to climb this ant hill I have found that some
|
||
people are natural bug writers and others, well, are more like Hostess
|
||
Twinkies. To help out all those American snack cakes out there, I will
|
||
offer a few guidelines to writing a good bug (and the only *good* bugs
|
||
are the ones you can hunt down and kill!).
|
||
</p><p>
|
||
Step 1: A reproducible case is needed. If you can't reproduce it, neither
|
||
can we.
|
||
</p><p>
|
||
Step 2: Document each step necessary to reproduce the bug. For example:
|
||
</p><div class="orderedlist"><ol><li><p>
|
||
Open a Terminal
|
||
</p></li><li><p>
|
||
Type twinky -old
|
||
</p></li><li><p>
|
||
Open a Tracker window
|
||
</p></li><li><p>
|
||
Create a folder called Hostess
|
||
</p></li><li><p>
|
||
Right click the folder
|
||
</p></li><li><p>
|
||
Crash!
|
||
</p></li></ol></div><p>
|
||
Step 3: Document your machine configuration. Include all the hardware AND
|
||
software your are running. For example, a developer recently forgot to
|
||
mention that <code class="code">MALLOC_DEBUG</code> was turned on.
|
||
</p><p>
|
||
Step 4: If the app that crashes is yours, include the code. Don't worry,
|
||
that little window on the bug report form scrolls for a long time! Just
|
||
paste it right in there.
|
||
</p><p>
|
||
Now I know you're thinking "Hey, I've got 50 source files, they won't all
|
||
fit." You need to find the piece of code that is causing the crash and
|
||
put it in a little test app.
|
||
</p><p>
|
||
HelloWorld is great for this. It has an app and a window and a view. Most
|
||
bugs don't need more than that to cause trouble. HINT: This can also help
|
||
you find bugs in your own code!
|
||
</p><p>
|
||
If the only way to cause the crash is to include your entire source, then
|
||
zip it up and send it in to devservices@be.com with a reference to the
|
||
bug number that you get when you submit the description using the web
|
||
form.
|
||
</p><p>
|
||
Step 5: The last part of Step 4 is really Step 5. Write down your bug
|
||
number so that you can contact us about it in the future.
|
||
</p><p>
|
||
If you skip any one of these steps, your bug will more than likely get
|
||
classified as "Unreproducible." This is bad for you and for Be, because
|
||
your bug will still be running around in the next release causing you and
|
||
everyone else problems! If you have any trouble with the bug reporting
|
||
process or you feel that we've made a grave error and classified your bug
|
||
as a feature, please don't hesitate to fill out a Developer tech Support
|
||
form in the Registered Developer Area and we will look into your problem.
|
||
</p></div><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id605634"></a>Part II: Build Your Own Buttons!</h3></div></div></div><p>
|
||
Are you building that killer tractor app, and you want the interface to
|
||
be oh-so-cool? It's not going to knock their socks of with a bunch of
|
||
plain-jane buttons. You need to customize! So I've prepared some sample
|
||
code to get you started making your very own buttons. Find the complete
|
||
archive on the Be website at:
|
||
</p><p>
|
||
ftp://ftp.be.com/pub/samples/preview/intro/ButtonWorld.zip
|
||
</p><p>
|
||
The <code class="classname">BPictureButton</code> class is a button that
|
||
takes two <code class="classname">BPicture</code>s as
|
||
arguments. You can build these pictures out of <code class="classname">BBitmap</code>s, a combination of
|
||
<code class="classname">BBitmap</code>s and <code class="classname">BButton</code>s
|
||
(for that grey look) or any other drawing routine.
|
||
The two pictures each represent one of two states, on and off.
|
||
</p><p>
|
||
I started by scanning a familiar form. I used Photoshop on the Mac ;-( to
|
||
save my scanned image in raw format. You need to remember the dimensions
|
||
of the image and the bit depth. The width needs to be a multiple of four
|
||
in order to use the command line tool craw to convert them into code. My
|
||
images were 48 x 48 so I just typed "$craw 48 48 myrawimage" in a
|
||
terminal.
|
||
</p><p>
|
||
(For more information on how to use craw check out...
|
||
</p><p>
|
||
<a class="xref" href="Issue1-15.html#Engineering1-15" title="Be Engineering Insights: craw, shex, and script: Excuse Me?">Be Engineering Insights: craw, shex, and script: Excuse Me?</a>
|
||
</p><p>
|
||
This is an oldie but a goodie! William Adams also addressed creating
|
||
custom graphics from images in a <a class="xref" href="Issue2-23.html#News2-23" title="News From The Front">News From The Front</a> article...
|
||
</p><p>
|
||
Some of the samples he referred to have been moved, including mkimghdr,
|
||
which is now at...
|
||
</p><p>
|
||
ftp://ftp.be.com/pub/samples/preview/interface_kit/mkimghdr.tgz.)
|
||
</p><p>
|
||
Craw generates an unsigned char array. blue4x4 and blue4x4on are the
|
||
names of my two arrays. Now I'm ready to fill some bitmaps and create a
|
||
button...
|
||
</p><pre class="programlisting cpp">
|
||
<span class="comment">/* NOTE: This is all happening during the construction of a
|
||
Window inheriting from a BWindow. */</span>
|
||
|
||
<code class="classname">BRect</code> <code class="varname">rect</code>;
|
||
<code class="varname">rect</code>.<code class="methodname">Set</code>(0,0,47,47);
|
||
|
||
<span class="comment">//bitmaps for the pictures</span>
|
||
|
||
<code class="classname">BBitmap</code> <code class="varname">onBitmap</code>(<code class="varname">rect</code>, <code class="constant">B_COLOR_8_BIT</code> );
|
||
<code class="classname">BBitmap</code> <code class="varname">offBitmap</code>(<code class="varname">rect</code>, <code class="constant">B_COLOR_8_BIT</code> );
|
||
|
||
<span class="comment">//fill bitmap</span>
|
||
|
||
<code class="varname">onBitmap</code>.<code class="methodname">SetBits</code>(<code class="varname">blue4x4on</code>, 18432, 0, <code class="constant">B_COLOR_8_BIT</code>);
|
||
<code class="varname">offBitmap</code>.<code class="methodname">SetBits</code>(<code class="varname">blue4x4</code>, 18432, 0, <code class="constant">B_COLOR_8_BIT</code>);
|
||
|
||
<span class="comment">/* Next, I create two BPictures and draw my bitmaps
|
||
in them. */</span>
|
||
|
||
<span class="comment">//tempview for creating the picture</span>
|
||
|
||
<span class="type"><code class="classname">BView</code> *</span><code class="varname">tempView</code> =
|
||
new <code class="classname">BView</code>(<code class="varname">rect</code>, "temp", <code class="constant">B_FOLLOW_NONE</code>, <code class="constant">B_WILL_DRAW</code>);
|
||
<code class="methodname">AddChild</code>(<code class="varname">tempView</code>);
|
||
|
||
<span class="comment">//create on picture</span>
|
||
|
||
<span class="type"><code class="classname">BPicture</code> *</span><code class="varname">on</code>;
|
||
<code class="varname">tempView</code>-><code class="methodname">BeginPicture</code>(new <code class="classname">BPicture</code>);
|
||
<code class="varname">tempView</code>-><code class="methodname">DrawBitmap</code>(&<code class="varname">onBitmap</code>);
|
||
<code class="varname">on</code> = <code class="varname">tempView</code>-><code class="methodname">EndPicture</code>();
|
||
|
||
<span class="comment">//create off picture</span>
|
||
|
||
<span class="type"><code class="classname">BPicture</code> *</span><code class="varname">off</code>;
|
||
<code class="varname">tempView</code>-><code class="methodname">BeginPicture</code>(new <code class="classname">BPicture</code>);
|
||
<code class="varname">tempView</code>-><code class="methodname">DrawBitmap</code>(&<code class="varname">offBitmap</code>);
|
||
<code class="varname">off</code> = <code class="varname">tempView</code>-><code class="methodname">EndPicture</code>();
|
||
|
||
<span class="comment">//get rid of tempview</span>
|
||
|
||
<code class="methodname">RemoveChild</code>(<code class="varname">tempView</code>);
|
||
delete <code class="varname">tempView</code>;
|
||
|
||
<span class="comment">/* Finally I create my BPicture button and the other things
|
||
that it needs including the message that will be sent to
|
||
its target. */</span>
|
||
|
||
<span class="comment">//create a message for the button</span>
|
||
|
||
<span class="type"><code class="classname">BMessage</code> *</span><code class="varname">pictmsg</code> = new <code class="classname">BMessage</code>(<code class="constant">BUTTON_MSG</code>);
|
||
<code class="varname">pictmsg</code>-><code class="methodname">AddString</code>("text", "Picture Button");
|
||
|
||
<span class="comment">//create a picture button using the two pictures</span>
|
||
|
||
<code class="varname">rect</code>.<code class="methodname">Set</code>( 120, 45, 167, 92 );
|
||
<span class="type"><code class="classname">BPictureButton</code>*</span> <code class="varname">pictureButton</code> =
|
||
new <code class="classname">BPictureButton</code>(<code class="varname">rect</code>, "picture", <code class="varname">off</code>, <code class="varname">on</code>, <code class="varname">pictmsg</code>,
|
||
<code class="constant">B_TWO_STATE_BUTTON</code>);
|
||
|
||
<span class="comment">/* The last argument for the BPictureButton is a flag for
|
||
the mode. B_TWO_STATE_BUTTON behaves like a toggle
|
||
switch. Turn it on with one click. Turn it off with
|
||
another. A B_ONE_STATE_BUTTON is only on while you hold
|
||
the mouse down. */</span>
|
||
|
||
<span class="comment">/* Once you have created your button you can add it as a
|
||
child to the window. The buttonView is a BTextView to
|
||
which we will send our message. */</span>
|
||
|
||
<span class="comment">// add view and button to window</span>
|
||
|
||
<code class="methodname">AddChild</code>(<code class="varname">buttonView</code>);
|
||
<code class="methodname">AddChild</code>(<code class="varname">pictureButton</code>);
|
||
|
||
<span class="comment">/* Finally in order to direct the message your button sends
|
||
you need to assign it a target. */</span>
|
||
|
||
<span class="comment">// make the view the target of the buttons</span>
|
||
|
||
<code class="varname">pictureButton</code>-><code class="methodname">SetTarget</code>(<code class="varname">buttonView</code>);
|
||
</pre><p>
|
||
Now when you click on the button, a message is sent to the <code class="varname">buttonView</code>
|
||
which displays the string contained by the message. To see how the
|
||
<code class="classname">BStringView</code> handles the message, please check out the complete sample.
|
||
Have fun and remember, we're happy to have you BYOB at Be! If you need
|
||
more information, don't hesitate to ask!
|
||
</p></div></div><hr class="pagebreak" /><div class="sect1"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h2 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="Gassee2-47"></a>A Nice Comdex</h2></div><div xmlns:d="http://docbook.org/ns/docbook"><span xmlns="http://www.w3.org/1999/xhtml" class="author">By <span class="firstname">Jean-Louis</span> <span class="surname">Gassée</span></span></div></div></div><p>
|
||
It is fashionable to complain about Comdex, from the bad food, the taxi
|
||
lines, expensive hotel rooms, sore feet at the end of the day and silly
|
||
carnival acts in the booths of companies who should know better. Perhaps,
|
||
but I still like Comdex, and I liked this one even better, for two
|
||
reasons.
|
||
</p><p>
|
||
The first is Umax. Our partner graciously hosted us on their booth in the
|
||
main hall, providing us with the opportunity to show both the PowerPC and
|
||
the Intel versions of the BeOS as befits their own business addressing
|
||
both standards.
|
||
</p><p>
|
||
As expected we got both good reactions and blank stares, when not eyes
|
||
rolling. Some visitors knew us, or had heard about us and were happy to
|
||
get a progress report. Others had no idea we existed and a few questioned
|
||
our sanity. When we got the opportunity, we disposed easily of the mental
|
||
health question by pointing out the difference between OS/2 trying to
|
||
dislodge Windows and the BeOS happily coexisting with the general-purpose
|
||
OS.
|
||
</p><p>
|
||
This experience is a useful reminder of what awaits us in the Intel-based
|
||
market. It's not just larger than the PowerPC market, it's much different
|
||
and our reputation, the exposure we enjoy in the PowerPC segment, aren't
|
||
worth much in the new space. The newer Intel version performed well
|
||
during the week, much better than we had anticipated and, towards the
|
||
end, we sneaked in a "just baked" port on an Intel-powered laptop.
|
||
</p><p>
|
||
The second reason to like Comdex this year is the abundance of technology
|
||
coming out of gestation, ready to become a real product at Fry's some
|
||
time in the next twelve months. Flat panels were big, literally and in
|
||
their ubiquity. A forty-six-inch panel is still horribly expensive, but
|
||
the smaller models are soon to grace the desktops of Corporate America.
|
||
</p><p>
|
||
Closer to our business, video cameras, ever higher-speed graphic cards,
|
||
still cameras, IEEE 1394 connections, high-bandwidth disk adapters...all
|
||
sing the song of better, faster, more affordable digital media.
|
||
</p><p>
|
||
This year we didn't hear the old saw: "The industry is becoming
|
||
commoditized, boring, less innovative." Confusing, a little disorganized
|
||
perhaps, but we like that, there is little room for a start-up such as
|
||
ours in a perfectly stable and organized world.
|
||
</p><p>
|
||
As for the expensive rooms and the bad food, a minivan gets you a little
|
||
out of the way, the hotel prices plummet and you even find restaurants
|
||
without slot machines.
|
||
</p></div><hr class="pagebreak" /><div class="sect1"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h2 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="BeDevTalk2-47"></a>BeDevTalk Summary</h2></div></div></div><p>
|
||
BeDevTalk is an unmonitored discussion group in which technical
|
||
information is shared by Be developers and interested parties. In this
|
||
column, we summarize some of the active threads, listed by their subject
|
||
lines as they appear, verbatim, in the mail.
|
||
</p><p>
|
||
To subscribe to BeDevTalk, visit the mailing list page on our web site:
|
||
http://www.be.com/aboutbe/mailinglists.html.
|
||
</p><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id606282"></a>NEW</h3></div></div></div><div class="sect3"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h4 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id606288"></a>Subject: Help with error...</h4></div></div></div><p>
|
||
We've all seen it...the "Data > 32K" compiler error message. What does
|
||
it mean? It means you've asked for too much local data. The 32k limit
|
||
is enforced by the compiler in order to be ANSI compliant, but beyond
|
||
that, is biting off huge chunks of local data bad programming? Earl
|
||
Malmrose saw some advantages in the practice:
|
||
</p><p>
|
||
“<span class="quote">Being local, you have automatic garbage collection of a sort - [the
|
||
data] will never be leaked. You also have to write less code.</span>”
|
||
</p><p>
|
||
Jon Watte listed some reasons behind the limitation, among which:
|
||
</p><p>
|
||
“<span class="quote">In a multi-threaded environment, each thread has to be given its own
|
||
stack...there is a very real trade-off between how many threads you can
|
||
create, and how much stack space they get.</span>”
|
||
</p><p>
|
||
Nonetheless, there were objections to the "bad programming practice"
|
||
characterization. It was contended that the negative citations were
|
||
architecture specific (hardware or software)—that there were no
|
||
intrinsic reasons why huge local data is bad. Then Osma Ahvenlampi
|
||
added this:
|
||
</p><p>
|
||
“<span class="quote">In addition to the problems pointed out by others, note that it
|
||
[relying on the stack for memory allocation] will not give you any kind
|
||
of error recovery. What happens when there isn't enough memory to give
|
||
you that big a stack frame? Crash, most likely.</span>”
|
||
</p></div><div class="sect3"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h4 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id606350"></a>Subject: Digital Signatures on the BeOS</h4></div></div></div><p>
|
||
Can a PGP-style signature be stored as an attribute of a file? (Sure.)
|
||
But would the attribute itself affect the signature for the file? (Not
|
||
if you didn't want it to—attributes can be selectively ignored.)
|
||
</p><p>
|
||
Expanding the equation, what if you wanted to verify attributes as well
|
||
as data? Peter Folk suggested a 3-tier scheme:
|
||
</p><ul class="itemizedlist"><li><p>
|
||
PGP__SIG is a signature for the main data stream.
|
||
</p></li><li><p>
|
||
PGP_<attributename>_SIG is a signature for whichever attributes
|
||
you care to sign (excluding PGP__SIG).
|
||
</p></li><li><p>
|
||
PGPSIG_SIG is a signature of all the PGP_*_SIG attributes.
|
||
</p></li></ul><p>
|
||
This may be overkill, suggests Jon Watte:
|
||
</p><p>
|
||
“<span class="quote">Having one signature for each attribute is rather wasteful... Instead,
|
||
you can sign the data with one signature, and the union of all
|
||
non-changing [attributes] with another; that should be enough even for
|
||
the most paranoid among us.</span>”
|
||
</p><p>
|
||
Speaking of paranoia, the thread veered into a discussion of reliable
|
||
key retrieval and verification. Anthony Towns provided a tidy wish list
|
||
that summarized the elements of the problem (paraphrased here):
|
||
</p><ul class="itemizedlist"><li><p>
|
||
Some way of storing public keys. This would naturally expand to
|
||
include encryption as well as verification keys...
|
||
</p></li><li><p>
|
||
Some way of easily requesting keys. This is strongly related to
|
||
the public key database: first you check it, then you check a public
|
||
key server somewhere.
|
||
</p></li><li><p>
|
||
Library support for verifying signatures.
|
||
</p></li><li><p>
|
||
Convenient methods for signing files (including support for
|
||
various signature algorithms).
|
||
</p></li><li><p>
|
||
An integrated encryption API.
|
||
</p></li></ul><p>
|
||
But should Be be in the encryption business? Some folks think not.
|
||
</p><p>
|
||
Also, it was contended that the entire signature-in-an-attribute
|
||
approach is flawed: Attributes can get lost in an ftp transfer (for
|
||
example). Important signature information should be encoded in the data
|
||
portion of a file.
|
||
</p></div><div class="sect3"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h4 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id606461"></a>Subject: BRect confusion</h4></div></div></div><p>
|
||
Should the <code class="methodname">Width()</code> of a <code class="classname">BRect</code>
|
||
return the "virtual" width of the
|
||
rectangle, or the number of pixels the stroked and filled rect touches?
|
||
The function returns the former, a practice that many developers are
|
||
confused by; when you ask for the width of a rectangle, you should get
|
||
a count of the number of (horizontal) pixels it encloses. But, goes the
|
||
counter-argument, such a measurement would need to consider the pen
|
||
size, so the status quo is proper. If you want the pixel-touched
|
||
measure, you have to add the pen size to the rectangle width.
|
||
</p><p>
|
||
Eric Berdahl contends that the width+pen_size business is a product of
|
||
Be's "center pen" approach. He would like to see Be adopt a more
|
||
flexible pen model (i.e. "inset" and "outset" pens).
|
||
</p></div><div class="sect3"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h4 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id606486"></a>Subject: Be supporting developers</h4></div></div></div><p>
|
||
Devtalkers take a step back (or across, or something) and discuss Be's
|
||
marketing approach, its seemingly unshakable association with Apple,
|
||
whether a brainwash-the-CS- department approach can work, the role of
|
||
free and eminently portable software in an OS company's success, and
|
||
other non-technical matters that all broached the question: How shall
|
||
Be thrive? Lots of opinions, or, at least, a lot of attitudes.
|
||
</p><p>
|
||
Side-stepping back into the tech stream, another question was raised:
|
||
What's a Be app? Does a port count, or is there some other defining
|
||
element. Some proposed litmus strips:
|
||
</p><ul class="itemizedlist"><li><p>
|
||
<code class="classname">BWindow</code>. If you don't have a <code class="classname">BWindow</code>, you're not a Be app.
|
||
</p></li><li><p>
|
||
<code class="classname">BMessage</code>s. Non-UI apps (servers) can still qualify if they
|
||
respond to <code class="classname">BMessage</code>s.
|
||
</p></li></ul></div></div></div></div><div id="footer"><hr /><div id="footerT">Prev: <a href="Issue2-46.html">Issue 2-46, November 19, 1997</a> Up: <a href="volume2.html">Volume 2: 1997</a> Next: <a href="Issue2-48.html">Issue 2-48, December 3, 1997</a> </div><div id="footerB"><div id="footerBL"><a href="Issue2-46.html" title="Issue 2-46, November 19, 1997"><img src="./images/navigation/prev.png" alt="Prev" /></a> <a href="volume2.html" title="Volume 2: 1997"><img src="./images/navigation/up.png" alt="Up" /></a> <a href="Issue2-48.html" title="Issue 2-48, December 3, 1997"><img src="./images/navigation/next.png" alt="Next" /></a></div><div id="footerBR"><div><a href="http://www.haiku-os.org"><img src="./images/People_24.png" alt="haiku-os.org" title="Visit The Haiku Website" /></a></div><div class="navighome" title="Home"><a accesskey="h" href="index.html"><img src="./images/navigation/home.png" alt="Home" /></a></div></div><div id="footerBC"><a href="http://www.access-company.com/home.html" title="ACCESS Co."><img alt="Access Company" src="./images/access_logo.png" /></a></div></div></div><div id="licenseFooter"><div id="licenseFooterBL"><a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/3.0/" title="Creative Commons License"><img alt="Creative Commons License" style="border-width:0" src="https://licensebuttons.net/l/by-nc-nd/3.0/88x31.png" /></a></div><div id="licenseFooterBR"><a href="./LegalNotice.html">Legal Notice</a></div><div id="licenseFooterBC"><span id="licenseText">This work is licensed under a
|
||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/3.0/">Creative
|
||
Commons Attribution-Non commercial-No Derivative Works 3.0 License</a>.</span></div></div></body></html>
|