xref: /openbsd/gnu/usr.bin/cvs/doc/cvsclient.info-3 (revision 7b36286a)
1This is cvsclient.info, produced by makeinfo version 4.0 from
2cvsclient.texi.
3
4INFO-DIR-SECTION Programming
5START-INFO-DIR-ENTRY
6* cvsclient: (cvsclient).      The CVS client/server protocol.
7END-INFO-DIR-ENTRY
8
9
10File: cvsclient.info,  Node: Responses,  Next: Text tags,  Prev: Response pathnames,  Up: Protocol
11
12Responses
13=========
14
15   Here are the responses:
16
17`Valid-requests REQUEST-LIST \n'
18     Indicate what requests the server will accept.  REQUEST-LIST is a
19     space separated list of tokens.  If the server supports sending
20     patches, it will include `update-patches' in this list.  The
21     `update-patches' request does not actually do anything.
22
23`Checked-in PATHNAME \n'
24     Additional data: New Entries line, \n.  This means a file PATHNAME
25     has been successfully operated on (checked in, added, etc.).  name
26     in the Entries line is the same as the last component of PATHNAME.
27
28`New-entry PATHNAME \n'
29     Additional data: New Entries line, \n.  Like `Checked-in', but the
30     file is not up to date.
31
32`Updated PATHNAME \n'
33     Additional data: New Entries line, \n, mode, \n, file
34     transmission.  A new copy of the file is enclosed.  This is used
35     for a new revision of an existing file, or for a new file, or for
36     any other case in which the local (client-side) copy of the file
37     needs to be updated, and after being updated it will be up to
38     date.  If any directory in pathname does not exist, create it.
39     This response is not used if `Created' and `Update-existing' are
40     supported.
41
42`Created PATHNAME \n'
43     This is just like `Updated' and takes the same additional data, but
44     is used only if no `Entry', `Modified', or `Unchanged' request has
45     been sent for the file in question.  The distinction between
46     `Created' and `Update-existing' is so that the client can give an
47     error message in several cases: (1) there is a file in the working
48     directory, but not one for which `Entry', `Modified', or
49     `Unchanged' was sent (for example, a file which was ignored, or a
50     file for which `Questionable' was sent), (2) there is a file in
51     the working directory whose name differs from the one mentioned in
52     `Created' in ways that the client is unable to use to distinguish
53     files.  For example, the client is case-insensitive and the names
54     differ only in case.
55
56`Update-existing PATHNAME \n'
57     This is just like `Updated' and takes the same additional data, but
58     is used only if a `Entry', `Modified', or `Unchanged' request has
59     been sent for the file in question.
60
61     This response, or `Merged', indicates that the server has
62     determined that it is OK to overwrite the previous contents of the
63     file specified by PATHNAME.  Provided that the client has correctly
64     sent `Modified' or `Is-modified' requests for a modified file, and
65     the file was not modified while CVS was running, the server can
66     ensure that a user's modifications are not lost.
67
68`Merged PATHNAME \n'
69     This is just like `Updated' and takes the same additional data,
70     with the one difference that after the new copy of the file is
71     enclosed, it will still not be up to date.  Used for the results
72     of a merge, with or without conflicts.
73
74     It is useful to preserve an copy of what the file looked like
75     before the merge.  This is basically handled by the server; before
76     sending `Merged' it will send a `Copy-file' response.  For
77     example, if the file is `aa' and it derives from revision 1.3, the
78     `Copy-file' response will tell the client to copy `aa' to
79     `.#aa.1.3'.  It is up to the client to decide how long to keep this
80     file around; traditionally clients have left it around forever,
81     thus letting the user clean it up as desired.  But another answer,
82     such as until the next commit, might be preferable.
83
84`Rcs-diff PATHNAME \n'
85     This is just like `Updated' and takes the same additional data,
86     with the one difference that instead of sending a new copy of the
87     file, the server sends an RCS change text.  This change text is
88     produced by `diff -n' (the GNU diff `-a' option may also be used).
89     The client must apply this change text to the existing file.
90     This will only be used when the client has an exact copy of an
91     earlier revision of a file.  This response is only used if the
92     `update' command is given the `-u' argument.
93
94`Patched PATHNAME \n'
95     This is just like `Rcs-diff' and takes the same additional data,
96     except that it sends a standard patch rather than an RCS change
97     text.  The patch is produced by `diff -c' for CVS 1.6 and later
98     (see POSIX.2 for a description of this format), or `diff -u' for
99     previous versions of CVS; clients are encouraged to accept either
100     format.  Like `Rcs-diff', this response is only used if the
101     `update' command is given the `-u' argument.
102
103     The `Patched' response is deprecated in favor of the `Rcs-diff'
104     response.  However, older clients (CVS 1.9 and earlier) only
105     support `Patched'.
106
107`Mode MODE \n'
108     This MODE applies to the next file mentioned in `Checked-in'.
109     `Mode' is a file update modifying response as described in *Note
110     Response intro::.
111
112`Mod-time TIME \n'
113     Set the modification time of the next file sent to TIME.
114     `Mod-time' is a file update modifying response as described in
115     *Note Response intro::.  The TIME is in the format specified by
116     RFC822 as modified by RFC1123.  The server may specify any
117     timezone it chooses; clients will want to convert that to their
118     own timezone as appropriate.  An example of this format is:
119
120          26 May 1997 13:01:40 -0400
121
122     There is no requirement that the client and server clocks be
123     synchronized.  The server just sends its recommendation for a
124     timestamp (based on its own clock, presumably), and the client
125     should just believe it (this means that the time might be in the
126     future, for example).
127
128     If the server does not send `Mod-time' for a given file, the client
129     should pick a modification time in the usual way (usually, just
130     let the operating system set the modification time to the time
131     that the CVS command is running).
132
133`Checksum CHECKSUM\n'
134     The CHECKSUM applies to the next file sent (that is, `Checksum' is
135     a file update modifying response as described in *Note Response
136     intro::).  In the case of `Patched', the checksum applies to the
137     file after being patched, not to the patch itself.  The client
138     should compute the checksum itself, after receiving the file or
139     patch, and signal an error if the checksums do not match.  The
140     checksum is the 128 bit MD5 checksum represented as 32 hex digits
141     (MD5 is described in RFC1321).  This response is optional, and is
142     only used if the client supports it (as judged by the
143     `Valid-responses' request).
144
145`Copy-file PATHNAME \n'
146     Additional data: NEWNAME \n.  Copy file PATHNAME to NEWNAME in the
147     same directory where it already is.  This does not affect
148     `CVS/Entries'.
149
150     This can optionally be implemented as a rename instead of a copy.
151     The only use for it which currently has been identified is prior
152     to a `Merged' response as described under `Merged'.  Clients can
153     probably assume that is how it is being used, if they want to worry
154     about things like how long to keep the NEWNAME file around.
155
156`Removed PATHNAME \n'
157     The file has been removed from the repository (this is the case
158     where cvs prints `file foobar.c is no longer pertinent').
159
160`Remove-entry PATHNAME \n'
161     The file needs its entry removed from `CVS/Entries', but the file
162     itself is already gone (this happens in response to a `ci' request
163     which involves committing the removal of a file).
164
165`Set-static-directory PATHNAME \n'
166     This instructs the client to set the `Entries.Static' flag, which
167     it should then send back to the server in a `Static-directory'
168     request whenever the directory is operated on.  PATHNAME ends in a
169     slash; its purpose is to specify a directory, not a file within a
170     directory.
171
172`Clear-static-directory PATHNAME \n'
173     Like `Set-static-directory', but clear, not set, the flag.
174
175`Set-sticky PATHNAME \n'
176     Additional data: TAGSPEC \n.  Tell the client to set a sticky tag
177     or date, which should be supplied with the `Sticky' request for
178     future operations.  PATHNAME ends in a slash; its purpose is to
179     specify a directory, not a file within a directory.  The client
180     should store TAGSPEC and pass it back to the server as-is, to
181     allow for future expansion.  The first character of TAGSPEC is `T'
182     for a tag, `D' for a date, or something else for future expansion.
183     The remainder of TAGSPEC contains the actual tag or date.
184
185`Clear-sticky PATHNAME \n'
186     Clear any sticky tag or date set by `Set-sticky'.
187
188`Template PATHNAME \n'
189     Additional data: file transmission (note: compressed file
190     transmissions are not supported).  PATHNAME ends in a slash; its
191     purpose is to specify a directory, not a file within a directory.
192     Tell the client to store the file transmission as the template log
193     message, and then use that template in the future when prompting
194     the user for a log message.
195
196`Set-checkin-prog DIR \n'
197     Additional data: PROG \n.  Tell the client to set a checkin
198     program, which should be supplied with the `Checkin-prog' request
199     for future operations.
200
201`Set-update-prog DIR \n'
202     Additional data: PROG \n.  Tell the client to set an update
203     program, which should be supplied with the `Update-prog' request
204     for future operations.
205
206`Notified PATHNAME \n'
207     Indicate to the client that the notification for PATHNAME has been
208     done.  There should be one such response for every `Notify'
209     request; if there are several `Notify' requests for a single file,
210     the requests should be processed in order; the first `Notified'
211     response pertains to the first `Notify' request, etc.
212
213`Module-expansion PATHNAME \n'
214     Return a file or directory which is included in a particular
215     module.  PATHNAME is relative to cvsroot, unlike most pathnames in
216     responses.  PATHNAME should be used to look and see whether some
217     or all of the module exists on the client side; it is not
218     necessarily suitable for passing as an argument to a `co' request
219     (for example, if the modules file contains the `-d' option, it
220     will be the directory specified with `-d', not the name of the
221     module).
222
223`Wrapper-rcsOption PATTERN -k 'OPTION' \n'
224     Transmit to the client a filename pattern which implies a certain
225     keyword expansion mode.  The PATTERN is a wildcard pattern (for
226     example, `*.exe'.  The OPTION is `b' for binary, and so on.  Note
227     that although the syntax happens to resemble the syntax in certain
228     CVS configuration files, it is more constrained; there must be
229     exactly one space between PATTERN and `-k' and exactly one space
230     between `-k' and `'', and no string is permitted in place of `-k'
231     (extensions should be done with new responses, not by extending
232     this one, for graceful handling of `Valid-responses').
233
234`M TEXT \n'
235     A one-line message for the user.  Note that the format of TEXT is
236     not designed for machine parsing.  Although sometimes scripts and
237     clients will have little choice, the exact text which is output is
238     subject to vary at the discretion of the server and the example
239     output given in this document is just that, example output.
240     Servers are encouraged to use the `MT' response, and future
241     versions of this document will hopefully standardize more of the
242     `MT' tags; see *Note Text tags::.
243
244`Mbinary \n'
245     Additional data: file transmission (note: compressed file
246     transmissions are not supported).  This is like `M', except the
247     contents of the file transmission are binary and should be copied
248     to standard output without translation to local text file
249     conventions.  To transmit a text file to standard output, servers
250     should use a series of `M' requests.
251
252`E TEXT \n'
253     Same as `M' but send to stderr not stdout.
254
255`F \n'
256     Flush stderr.  That is, make it possible for the user to see what
257     has been written to stderr (it is up to the implementation to
258     decide exactly how far it should go to ensure this).
259
260`MT TAGNAME DATA \n'
261     This response provides for tagged text.  It is similar to
262     SGML/HTML/XML in that the data is structured and a naive
263     application can also make some sense of it without understanding
264     the structure.  The syntax is not SGML-like, however, in order to
265     fit into the CVS protocol better and (more importantly) to make it
266     easier to parse, especially in a language like perl or awk.
267
268     The TAGNAME can have several forms.  If it starts with `a' to `z'
269     or `A' to `Z', then it represents tagged text.  If the
270     implementation recognizes TAGNAME, then it may interpret DATA in
271     some particular fashion.  If the implementation does not recognize
272     TAGNAME, then it should simply treat DATA as text to be sent to
273     the user (similar to an `M' response).  There are two tags which
274     are general purpose.  The `text' tag is similar to an unrecognized
275     tag in that it provides text which will ordinarily be sent to the
276     user.  The `newline' tag is used without DATA and indicates that a
277     newline will ordinarily be sent to the user (there is no provision
278     for embedding newlines in the DATA of other tagged text responses).
279
280     If TAGNAME starts with `+' it indicates a start tag and if it
281     starts with `-' it indicates an end tag.  The remainder of TAGNAME
282     should be the same for matching start and end tags, and tags
283     should be nested (for example one could have tags in the following
284     order `+bold' `+italic' `text' `-italic' `-bold' but not `+bold'
285     `+italic' `text' `-bold' `-italic').  A particular start and end
286     tag may be documented to constrain the tagged text responses which
287     are valid between them.
288
289     Note that if DATA is present there will always be exactly one
290     space between TAGNAME and DATA; if there is more than one space,
291     then the spaces beyond the first are part of DATA.
292
293     Here is an example of some tagged text responses.  Note that there
294     is a trailing space after `Checking in' and `initial revision:'
295     and there are two trailing spaces after `<--'.  Such trailing
296     spaces are, of course, part of DATA.
297
298          MT +checking-in
299          MT text Checking in
300          MT fname gz.tst
301          MT text ;
302          MT newline
303          MT rcsfile /home/kingdon/zwork/cvsroot/foo/gz.tst,v
304          MT text   <--
305          MT fname gz.tst
306          MT newline
307          MT text initial revision:
308          MT init-rev 1.1
309          MT newline
310          MT text done
311          MT newline
312          MT -checking-in
313
314     If the client does not support the `MT' response, the same
315     responses might be sent as:
316
317          M Checking in gz.tst;
318          M /home/kingdon/zwork/cvsroot/foo/gz.tst,v  <--  gz.tst
319          M initial revision: 1.1
320          M done
321
322     For a list of specific tags, see *Note Text tags::.
323
324`error ERRNO-CODE ` ' TEXT \n'
325     The command completed with an error.  ERRNO-CODE is a symbolic
326     error code (e.g. `ENOENT'); if the server doesn't support this
327     feature, or if it's not appropriate for this particular message,
328     it just omits the errno-code (in that case there are two spaces
329     after `error').  Text is an error message such as that provided by
330     strerror(), or any other message the server wants to use.  The
331     TEXT is like the `M' response, in the sense that it is not
332     particularly intended to be machine-parsed; servers may wish to
333     print an error message with `MT' responses, and then issue a
334     `error' response without TEXT (although it should be noted that
335     `MT' currently has no way of flagging the output as intended for
336     standard error, the way that the `E' response does).
337
338`ok \n'
339     The command completed successfully.
340
341
342File: cvsclient.info,  Node: Text tags,  Next: Example,  Prev: Responses,  Up: Protocol
343
344Tags for the MT tagged text response
345====================================
346
347   The `MT' response, as described in *Note Responses::, offers a way
348for the server to send tagged text to the client.  This section
349describes specific tags.  The intention is to update this section as
350servers add new tags.
351
352   In the following descriptions, `text' and `newline' tags are
353omitted.  Such tags contain information which is intended for users (or
354to be discarded), and are subject to change at the whim of the server.
355To avoid being vulnerable to such whim, clients should look for the tags
356listed here, not `text', `newline', or other tags.
357
358   The following tag means to indicate to the user that a file has been
359updated.  It is more or less redundant with the `Created' and
360`Update-existing' responses, but we don't try to specify here whether
361it occurs in exactly the same circumstances as `Created' and
362`Update-existing'.  The NAME is the pathname of the file being updated
363relative to the directory in which the command is occurring (that is,
364the last `Directory' request which is sent before the command).
365
366     MT +updated
367     MT fname NAME
368     MT -updated
369
370   The `importmergecmd' tag is used when doing an import which has
371conflicts.  The client can use it to report how to merge in the newly
372imported changes.  The COUNT is the number of conflicts.  The newly
373imported changes can be merged by running the following command:
374     cvs checkout -j TAG1 -j TAG2 REPOSITORY
375
376     MT +importmergecmd
377     MT conflicts COUNT
378     MT mergetag1 TAG1
379     MT mergetag2 TAG2
380     MT repository REPOSITORY
381     MT -importmergecmd
382
383
384File: cvsclient.info,  Node: Example,  Next: Requirements,  Prev: Text tags,  Up: Protocol
385
386Example
387=======
388
389   Here is an example; lines are prefixed by `C: ' to indicate the
390client sends them or `S: ' to indicate the server sends them.
391
392   The client starts by connecting, sending the root, and completing the
393protocol negotiation.  In actual practice the lists of valid responses
394and requests would be longer.
395
396     C: Root /u/cvsroot
397     C: Valid-responses ok error Checked-in M E
398     C: valid-requests
399     S: Valid-requests Root Directory Entry Modified Argument Argumentx ci co
400     S: ok
401     C: UseUnchanged
402
403   The client wants to check out the `supermunger' module into a fresh
404working directory.  Therefore it first expands the `supermunger'
405module; this step would be omitted if the client was operating on a
406directory rather than a module.
407
408     C: Argument supermunger
409     C: Directory .
410     C: /u/cvsroot
411     C: expand-modules
412
413   The server replies that the `supermunger' module expands to the
414directory `supermunger' (the simplest case):
415
416     S: Module-expansion supermunger
417     S: ok
418
419   The client then proceeds to check out the directory.  The fact that
420it sends only a single `Directory' request which specifies `.' for the
421working directory means that there is not already a `supermunger'
422directory on the client.
423
424     C: Argument -N
425     C: Argument supermunger
426     C: Directory .
427     C: /u/cvsroot
428     C: co
429
430   The server replies with the requested files.  In this example, there
431is only one file, `mungeall.c'.  The `Clear-sticky' and
432`Clear-static-directory' requests are sent by the current
433implementation but they have no effect because the default is for those
434settings to be clear when a directory is newly created.
435
436     S: Clear-sticky supermunger/
437     S: /u/cvsroot/supermunger/
438     S: Clear-static-directory supermunger/
439     S: /u/cvsroot/supermunger/
440     S: E cvs server: Updating supermunger
441     S: M U supermunger/mungeall.c
442     S: Created supermunger/
443     S: /u/cvsroot/supermunger/mungeall.c
444     S: /mungeall.c/1.1///
445     S: u=rw,g=r,o=r
446     S: 26
447     S: int mein () { abort (); }
448     S: ok
449
450   The current client implementation would break the connection here
451and make a new connection for the next command.  However, the protocol
452allows it to keep the connection open and continue, which is what we
453show here.
454
455   After the user modifies the file and instructs the client to check it
456back in.  The client sends arguments to specify the log message and file
457to check in:
458
459     C: Argument -m
460     C: Argument Well, you see, it took me hours and hours to find
461     C: Argumentx this typo and I searched and searched and eventually
462     C: Argumentx had to ask John for help.
463     C: Argument mungeall.c
464
465   It also sends information about the contents of the working
466directory, including the new contents of the modified file.  Note that
467the user has changed into the `supermunger' directory before executing
468this command; the top level directory is a user-visible concept because
469the server should print filenames in `M' and `E' responses relative to
470that directory.
471
472     C: Directory .
473     C: /u/cvsroot/supermunger
474     C: Entry /mungeall.c/1.1///
475     C: Modified mungeall.c
476     C: u=rw,g=r,o=r
477     C: 26
478     C: int main () { abort (); }
479
480   And finally, the client issues the checkin command (which makes use
481of the data just sent):
482
483     C: ci
484
485   And the server tells the client that the checkin succeeded:
486
487     S: M Checking in mungeall.c;
488     S: E /u/cvsroot/supermunger/mungeall.c,v  <--  mungeall.c
489     S: E new revision: 1.2; previous revision: 1.1
490     S: E done
491     S: Mode u=rw,g=r,o=r
492     S: Checked-in ./
493     S: /u/cvsroot/supermunger/mungeall.c
494     S: /mungeall.c/1.2///
495     S: ok
496
497
498File: cvsclient.info,  Node: Requirements,  Next: Obsolete,  Prev: Example,  Up: Protocol
499
500Required versus optional parts of the protocol
501==============================================
502
503   The following are part of every known implementation of the CVS
504protocol (except obsolete, pre-1.5, versions of CVS) and it is
505considered reasonable behavior to completely fail to work if you are
506connected with an implementation which attempts to not support them.
507Requests: `Root', `Valid-responses', `valid-requests', `Directory',
508`Entry', `Modified', `Unchanged', `Argument', `Argumentx', `ci', `co',
509`update'.  Responses: `ok', `error', `Valid-requests', `Checked-in',
510`Updated', `Merged', `Removed', `M', `E'.
511
512   A server need not implement `Repository', but in order to
513interoperate with CVS 1.5 through 1.9 it must claim to implement it (in
514`Valid-requests').  The client will not actually send the request.
515
516
517File: cvsclient.info,  Node: Obsolete,  Prev: Requirements,  Up: Protocol
518
519Obsolete protocol elements
520==========================
521
522   This section briefly describes protocol elements which are obsolete.
523There is no attempt to document them in full detail.
524
525   There was a `Repository' request which was like `Directory' except
526it only provided REPOSITORY, and the local directory was assumed to be
527similarly named.
528
529   If the `UseUnchanged' request was not sent, there was a `Lost'
530request which was sent to indicate that a file did not exist in the
531working directory, and the meaning of sending `Entries' without `Lost'
532or `Modified' was different.  All current clients (CVS 1.5 and later)
533will send `UseUnchanged' if it is supported.
534
535
536File: cvsclient.info,  Node: Protocol Notes,  Prev: Protocol,  Up: Top
537
538Notes on the Protocol
539*********************
540
541   A number of enhancements are possible.  Also see the file TODO in
542the CVS source distribution, which has further ideas concerning various
543aspects of CVS, some of which impact the protocol.  Similarly, the
544`http://www.cvshome.org' site, in particular the `Development' pages.
545
546   * The `Modified' request could be speeded up by sending diffs rather
547     than entire files.  The client would need some way to keep the
548     version of the file which was originally checked out; probably
549     requiring the use of "cvs edit" in this case is the most sensible
550     course (the "cvs edit" could be handled by a package like VC for
551     emacs).  This would also allow local operation of `cvs diff'
552     without arguments.
553
554   * The fact that `pserver' requires an extra network turnaround in
555     order to perform authentication would be nice to avoid.  This
556     relates to the issue of reporting errors; probably the clean
557     solution is to defer the error until the client has issued a
558     request which expects a response.  To some extent this might
559     relate to the next item (in terms of how easy it is to skip a
560     whole bunch of requests until we get to one that expects a
561     response).  I know that the kerberos code doesn't wait in this
562     fashion, but that probably can cause network deadlocks and perhaps
563     future problems running over a transport which is more transaction
564     oriented than TCP.  On the other hand I'm not sure it is wise to
565     make the client conduct a lengthy upload only to find there is an
566     authentication failure.
567
568   * The protocol uses an extra network turnaround for protocol
569     negotiation (`valid-requests').  It might be nice to avoid this by
570     having the client be able to send requests and tell the server to
571     ignore them if they are unrecognized (different requests could
572     produce a fatal error if unrecognized).  To do this there should
573     be a standard syntax for requests.  For example, perhaps all
574     future requests should be a single line, with mechanisms analogous
575     to `Argumentx', or several requests working together, to provide
576     greater amounts of information.  Or there might be a standard
577     mechanism for counted data (analogous to that used by `Modified')
578     or continuation lines (like a generalized `Argumentx').  It would
579     be useful to compare what HTTP is planning in this area; last I
580     looked they were contemplating something called Protocol Extension
581     Protocol but I haven't looked at the relevant IETF documents in
582     any detail.  Obviously, we want something as simple as possible
583     (but no simpler).
584
585   * The scrambling algorithm in the CVS client and server actually
586     support more characters than those documented in *Note Password
587     scrambling::.  Someday we are going to either have to document
588     them all (but this is not as easy as it may look, see below), or
589     (gradually and with adequate process) phase out the support for
590     other characters in the CVS implementation.  This business of
591     having the feature partly undocumented isn't a desirable state
592     long-term.
593
594     The problem with documenting other characters is that unless we
595     know what character set is in use, there is no way to make a
596     password portable from one system to another.  For example, a with
597     a circle on top might have different encodings in different
598     character sets.
599
600     It _almost_ works to say that the client picks an arbitrary,
601     unknown character set (indeed, having the CVS client know what
602     character set the user has in mind is a hard problem otherwise),
603     and scrambles according to a certain octet<->octet mapping.  There
604     are two problems with this.  One is that the protocol has no way
605     to transmit character 10 decimal (linefeed), and the current
606     server and clients have no way to handle 0 decimal (NUL).  This
607     may cause problems with certain multibyte character sets, in which
608     octets 10 and 0 will appear in the middle of other characters.
609     The other problem, which is more minor and possibly not worth
610     worrying about, is that someone can type a password on one system
611     and then go to another system which uses a different encoding for
612     the same characters, and have their password not work.
613
614     The restriction to the ISO646 invariant subset is the best
615     approach for strings which are not particularly significant to
616     users.  Passwords are visible enough that this is somewhat
617     doubtful as applied here.  ISO646 does, however, have the virtue
618     (!?) of offending everyone.  It is easy to say "But the $ is right
619     on people's keyboards!  Surely we can't forbid that".  From a
620     human factors point of view, that makes quite a bit of sense.  The
621     contrary argument, of course, is that a with a circle on top, or
622     some of the characters poorly handled by Unicode, are on
623     _someone_'s keyboard.
624
625
626
627