wily-0.13.42/000075502366570000012000000000001041526270100125025ustar00ozstaff00004330000002wily-0.13.42/Doc/000075502366570000012000000000001033320152300132015ustar00ozstaff00004330000002wily-0.13.42/Doc/LSM000064402366570000012000000021661033320152300135640ustar00ozstaff00004330000002Begin3 Title: Wily - a simple, powerful, mouse-based text environment Version: 0.13.23 [November 1996] Entered-date: November 1996 Description: Interact in a general way with text on the screen using a mouse. Instead of menus or control keys, clicking on text with the middle mouse button executes it, clicking on text with the right mouse button "goes to" a file, directory, string or regular expression. Wily was written by programmers for programmers: there are very few rules and almost no exceptions. The learning curve is steep but short, and very few people have used wily for a few hours and gone back to another editor. Wily is an emulation for Unix and X of Acme which only works in the Plan 9 environment. Acme was inspired chiefly by Oberon. Keywords: text-editor window-manager integrated-development-environment Author: gary@cs.su.oz.au Maintained-by: gary@cs.su.oz.au Primary-site: ftp.cs.su.oz.au /gary/wily/ 312k wily.tgz Alternate-site: ftp.northsea.com /pub/plan9_unix/wily/ Original-site: Platform: UNIX Copying-policy: Artistic End wily-0.13.42/Doc/old/000075502366570000012000000000001033320152300137575ustar00ozstaff00004330000002wily-0.13.42/Doc/old/tile.html000064402366570000012000001155031033320152300156070ustar00ozstaff00004330000002 tile.nw

A New Window Management Scheme for Wily

Goals

  1. Generalization of code for both column and row management.
  2. Help take care of some stuff-locating code (such as finding the stuff under a mouse click).
  3. Adding and immediately deleting a window should not change the placement of the remaining windows.

Data Structures

Tiles

Central to the new window management system is the tile. The tile contains the minimum amount of information necessary to rearrange the elements of <data structures>= (U->) [D->] typedef struct Tile Tile; struct Tile { <tile elements> };

  1. The starting and ending location of the tile in screen coordinates (this could be either the x or y coordinate). The terms "min" and "max" are used for consistency with the definition of Rectangle.
    <tile elements>= (<-U) [D->]
    int min, max;
    

  2. The minimum size of the tile. As a special case, non-positive tiles sizes are permitted for hidden tiles (this is explained in detail elsewhere).
    <tile elements>+= (<-U) [<-D->]
    int base;
    

  3. The size increment of the tile. This is the amount by which the tile must grow. For example, text windows need to grow by the height of the font they display.
    <tile elements>+= (<-U) [<-D->]
    int step;
    

  4. A pointer to the enclosing tile list.
    <tile elements>+= (<-U) [<-D]
    TileList* list;
    

Instead of putting a pointer to a tile in all the windows and columns, we simply insist that the first element in a window or column is a tile structure. This way, (struct tile *) windowptr makes sense.

Tile Lists

Tiles are strewn out in lists. Instead of using linked lists, I have chosen to use arrays, but that is just an implementation detail. TileLists need a rectangle to determine where its tiles go.
<data structures>+= (U->) [<-D]
struct TileList {
        <tile list elements>
};

The tile list consists of

  1. A tile structures (since tile lists are themselves tiles). Note that self is not used in anywhere in the tile code, as the the tile list may be a member of a super-tile-list running the other way.
    <tile list elements>= (<-U) [D->]
    Tile self;
    

  2. The array of tiles it contains.
    <tile list elements>+= (<-U) [<-D->]
    Tile **tiles;
    

  3. The range to which the tile list elements are limited.
    <tile list elements>+= (<-U) [<-D->]
    int min, max;
    

  4. The number of tiles currently in the array, and the maximum size of the tile array.
    <tile list elements>+= (<-U) [<-D->]
    ushort count, maxtiles;
    

  5. hidden is used to determine how many tiles are hidden "to the left of" the tiles actually displayed (as a result of a B3, for instance).
    <tile list elements>+= (<-U) [<-D]
    ushort hidden;
    

    };

    <typedefs>= (U->)
    typedef struct TileList TileList;
    

    Operations

    There really are only a few operations that involve tiles.
    1. Adding a tile to a tile list (e.g., as a result of a New), either arbitrarily or near a desired location.
    2. Removing a tile from its tile list (e.g., as a result of a Del).
    3. Moving a tile within a tile list. This might look better than simply deleting and adding it, especially if the tile is not really moving (i.e., it is just growing or shrinking).
    4. Making a tile big enough to be visible (necessary to make sure that new output is visible, for instance).
    5. Locating a tile in a tile list given a location (to figure out where typing should go).
    6. Growing a tile "some" (for B1 clicks), "lots" (for B2 clicks), or "way lots" (for B3 clicks).
    7. Resizing. This should only occur as a result of wily's X window being resized.
    The only policy that tiles and tile collections are responsible for is how to handle B1, B2, and B3 clicks, and what to do when a window is deleted. The operator to add a tile will take hints as to where to place a tile (with respect to a location).

    Growing a Tile

    Growing a tile proceeds in two simple steps: Make the tile the desired size, and then push everything else out of the way. With a B3, it would also be desirable to mark everything else as hidden instead of adjusting the windows unnecessarily).

    Since the tile growth is rather blind at times, tile_list_reshaped is called without a specific "untouchable" tile, thereby fixing a prior bug.

    <public tile functions>= (U->) [D->]
    void
    tile_grow(Tile *tile, Growth grow) {
            TileList *list = tile->list;
            <tile_grow locals>
    
            <tile consistency checks>
    
            switch (grow) {
            case Gsome:
                    <grow tile a little>
                    break;
            case Gmost:
                    <grow tile lots>
                    break;
            case Gall:
                    <grow tile way lots>
                    break;
            default:
                    assert(grow != grow);
            }
            tile_list_reshaped(list, 0);
    }
    
    <public function declarations>= (U->) [D->]
    void tile_grow(Tile *, Growth);
    

    This is probably too small, especially when a column is being grown, but it will work for now. Also, it does not check boundary conditions.

    <grow tile a little>= (<-U)
    tile->min -= tile->step;
    tile->max += tile->step;
    

    The B2 implementation of this code relies slightly on the way tile_list_reshaped is currently implemented, as it relies on it not to hide any windows until it has tried shrinking them all. Since this is good user interface policy anyhow, this assumption presents little problem.

    <grow tile lots>= (<-U)
    space = list->min;
    for (i = list->hidden; i < list->count; i++) {
            if (list->tiles[i] == tile) {
                    tile->min = space;
                    space = 0;
                    continue;
            }
            space += list->tiles[i]->base;
    }
    tile->max = list->max - space;
    
    <tile_grow locals>= (<-U)
    int i, space;
    

    To grow a tile way lots, the remaining tiles are added to the "hidden" list. For the moment, the tiles are added in order by simply swapping the selected tile to the end of the array, but heuristics should be added so that the "least hidden" tile is the one the user is most likely to want to see next.

    A little trickery here -- the code only counts up to count - 1. This is because the tile being expanded way lots gets swapped to the end position in the array during the loop. If the tile being expanded is already at the end, then there is no problem. Of course, if the caller called with an array where tile was not in list, then there is a problem.

    <grow tile way lots>= (<-U)
    for (i = list->hidden; i < list->count - 1; i++) {
            if (list->tiles[i] == tile) {
                    list->tiles[i] = list->tiles[list->count - 1];
                    list->tiles[list->count - 1] = tile;
                    continue;
            }
            list->tiles[i]->min = list->tiles[i]->max;
    }
    list->hidden = list->count - 1;
    tile->min = list->min;
    tile->max = list->max;
    

    Locating a Tile

    This funtion simply relies on index_for_place to find the right tile and then looks the tile up in the array.
    <public tile functions>+= (U->) [<-D->]
    Tile *
    point2tile(TileList *list, int spot) {
            int i = index_for_place(list, spot);
    
            check_list_consistency(list);
    
            return (i >= 0) ? list->tiles[i] : 0;
    }
    
    <public function declarations>+= (U->) [<-D->]
    Tile *point2tile(TileList *, int);
    

    Making a Tile Visible

    As a gross heuristic, the tile size is set to base+3step. If there is not enough room for that, make the tile simply take the whole list over. Of course, if the tile is already showing, there is no reason to expand it.
    <public tile functions>+= (U->) [<-D->]
    void
    tile_show(Tile *tile) {
            TileList *list;
    
            <tile consistency checks>
            list = tile->list;
            check_list_consistency(list);
    
            if (TILESIZE(tile) == 0) {
                    <expose the hidden tile tile>
            }
            if (TILESIZE(tile) >= tile->base + tile->step)
                    return;
            tile->max = tile->min + tile->base + 3 * tile->step;
            if (tile->max > list->max) {
                    tile->max = list->max;
                    tile->min = tile->max - (tile->base + 3 * tile->step);
                    if (tile->min < list->min)
                            tile->min = list->min;
            }
            tile_list_reshaped(list, tile);
    }
    
    <public function declarations>+= (U->) [<-D->]
    void tile_show(Tile *);
    

    Hidden tiles present a small problem -- they first must be "unhidden" so they can be displayed. For lack of a better place to put it,, the tile is added at the end of the tile list. +Errors windows probably belong at the bottom anyhow.

    <expose the hidden tile tile>= (<-U)
    int i;
    
    for (i = 0; i < list->count && tile != list->tiles[i]; i++)
            ;
    while (++i < list->count)
            list->tiles[i-1] = list->tiles[i];
    list->tiles[i] = tile;
    list->hidden--;
    

    Moving a Tile Within a Tile List

    Just add and delete it for now.
    <public tile functions>+= (U->) [<-D->]
    void
    tile_move(Tile *tile) {
            tile_del(tile);
            tile_add(tile->list, tile);
    }
    
    <public function declarations>+= (U->) [<-D->]
    void tile_move(Tile *);
    

    Adding a Tile to a Tile List

    This function uses the minimum coordinate of the new tile to determine where it should go. What if the caller doesn't care? If the caller does not know how large it wants the tile, it should specify a tile with a size of 0.
    <public tile functions>+= (U->) [<-D->]
    void
    tile_add(TileList *list, Tile *tile) {
            <local variables for adding a tile>
    
            <tile consistency checks>
            check_list_consistency(list);
    
            <make sure tile shape is reasonable>
            <determine where to place the new tile in the list>
            <add the tile to the list>
            tile->list = list;
            tile_list_reshaped(list, tile);
    }
    
    <public function declarations>+= (U->) [<-D->]
    void tile_add(TileList *, Tile *);
    

    The tile location must be constrained to its collection. If the tile is so deformed after this reshaping that its size exceeds the bounds of its container, it is simply shrunk to zero size.

    <make sure tile shape is reasonable>= (<-U)
    assert(tile->min < tile->max);
    if (tile->min < list->min) {
            tile->max += list->min - tile->min;
            tile->min = list->min;
    }
    if (tile->max > list->max) {
            tile->max = list->max;
    }
    if (tile->max - tile->min < tile->base)
            tile->min = tile->max = 0;
    

    To determine where the tile should go in the list, we perform a binary search on the tiles in the tile list to find the tile containing tile->min. This will be useful enough to warrant a separate function. The program must then determine whether the new tile will go before or after the tile it is being placed on. The tile is placed so that the tile it is supplanting is moved as little as possible.

    <determine where to place the new tile in the list>= (<-U)
    if (list->count == list->hidden) {
            i = list->hidden;
            tile->min = list->min;
            tile->max = list->max;
    } else {
            i = index_for_place(list, tile->min);
            if ((<distance to move current tile up>) < 
                            (<distance to move current tile down>)) {
                    i++;
            }
    }
    
    <local variables for adding a tile>= (<-U) [D->]
    ushort i;
    

    Moving a tile up means just moving it by the distance from its bottom to the desired top of the new window. Figuring out how far a tile down would move down is more complicated, but essentially works out to the distance from the top of the displaced tile to the bottom of the new tile.

    <distance to move current tile up>= (<-U)
    list->tiles[i]->max - tile->min
    
    <distance to move current tile down>= (<-U)
    tile->max - list->tiles[i]->min
    

    Once we know where in the array the tile goes, the other tiles need to be shuffled out of the way.

    <add the tile to the list>= (<-U)
    <make sure tile list has room for one more>
    for (j = ++list->count; j > i; j--)
            list->tiles[j] = list->tiles[j-1];
    list->tiles[i] = tile;
    
    <local variables for adding a tile>+= (<-U) [<-D]
    ushort j;
    

    Removing a Tile from a List

    This is pretty dull, actually -- the remaining elements of the tile list are shuffled down in the array, and then the tiles are resized to fit the new tile list.

    One bug found: I was passing tile into tile_list_reshaped, of all the silly things.

    <public tile functions>+= (U->) [<-D->]
    void
    tile_del(Tile *tile) {
            TileList *list = tile->list;
            int i;
    
            for (i = 0; i < list->count; i++) {
                    if (list->tiles[i] == tile) {
                            while (++i < list->count) {
                                    list->tiles[i-1] = list->tiles[i];
                            }
                            list->count--;
                            tile_list_reshaped(list, 0);
                            return;
                    }
            }
            assert(0);
    }
    
    <public function declarations>+= (U->) [<-D->]
    void tile_del(Tile *);
    

    Adjusting tile sizes

    When there is not enough room for the collection's tiles as they stand, this function is called to fix the tiles. The tile argument is used to indicate the tile that should not be adjusted. Specifying a tile of zero prevents any tile from being treated as special.

    Adjusting the tiles, then, is split into two phases -- adjusting the tiles above tile, and adjusting those below it. tileidx is used in the next chunk of code. It is initially set to a location not in the tile list.

    <public tile functions>+= (U->) [<-D->]
    void
    tile_list_reshaped(TileList *list, Tile *tile) {
            int i;
            int tileidx = -1;
            <tile_list_reshaped locals>
    
            if (!tile)
                    adjust_sizes_in_range(list, list->hidden, list->count,
                                    list->max - list->min);
            else {
                    <tile consistency checks>
    
                    for (i = 0; list->tiles[i] != tile; i++) {
                            assert(i < list->count);
                    }
                    tileidx = i;
                    adjust_sizes_in_range(list, list->hidden, i, tile->min - list->min);
                    adjust_sizes_in_range(list, i + 1, list->count, list->max - tile->max);
            }
            <repair tile locations>
            check_list_consistency(list);
    }
    
    <public function declarations>+= (U->) [<-D->]
    void tile_list_reshaped(TileList *, Tile *);
    

    Once the tiles all fit, their locations must be updated (adjust_sizes_in_range does not do this). This is merely a matter of sticking the tiles end-to-end.

    <repair tile locations>= (<-U)
    for (prevmax = list->min, i = list->hidden; i < list->count; i++) {
            if (i != tileidx) {
                    list->tiles[i]->max -= list->tiles[i]->min - prevmax;
                    list->tiles[i]->min = prevmax;
            }
            prevmax = list->tiles[i]->max;
    }
    
    <tile_list_reshaped locals>= (<-U)
    int prevmax;
    

    The tiles in a particular range are adjusted through a simple series of steps. Note that this only adjusts the sizes of the tiles -- it does not adjust the tiles' locations.

    Bugs found:

    1. The expansion code was seriously broken. Rethinking it in terms of computing an amount to shrink the tile dramatically simplified and improved the code.
    2. The expansion code did not work when there were no tiles to adjust. Optimizing out an empty range is probably worthwhile anyhow.
    <static tile functions>= (U->) [D->]
    static void
    adjust_sizes_in_range(TileList *list, int start, int max, int available) {
            <local variables for tile adjustment>
    
            if (start == max)
                    return;
    
            <determine amount of space needed>
            if (0 && needed < 0) {
                    <expand tiles to fill slack>
                    return;
            }
            <shrink tiles until space available>
    }
    

    Determining the space required is easy -- determine the difference between the heights of the tiles and the collection they appear in.

    <determine amount of space needed>= (<-U)
    needed = -available;
    for (i = start; i < max; i++)
            needed += TILESIZE(list->tiles[i]);
    
    <local variables for tile adjustment>= (<-U)
    int i;
    int needed;
    

    At this point, tiles are shrunk in a fairly arbitrary manner. The tile at the top gets shrunk first, and on down until the necessary space has been acquired. Tiles should be removed from view completely if adequate space is not available.

    A small ugly here -- there may be a gap right before the "fixed" tile.

    <shrink tiles until space available>= (<-U)
    for (i = start; needed && i < max; i++) {
            int base = list->tiles[i]->base;
            int step = list->tiles[i]->step;
            int shrink = TILESIZE(list->tiles[i]) - base;
    
            shrink = ((shrink - base) / step) * step + base;
            if (shrink > needed)
                    shrink = needed;
            needed -= shrink;
            list->tiles[i]->max -= shrink;
    }
    

    For the moment, expanding to fill a gap is handled is a relatively arbitrary manner -- the last tile is grown to fill the gap. What about any fuzz?

    <expand tiles to fill slack>= (<-U)
    list->tiles[max-1]->max -= needed;
    

    Useful Macros

    Accessing Tile Elements

    Abstracting access via tile structures can very much simplify the code. The first one returns the tile representing the column in the global column list. The second one returns the column in which a window resides. It is not actually defined as a macro in order to improve type checking.
    <public function declarations>+= (U->) [<-D->]
    #define COLTILE(t)      (&(t)->tiles.self)
    static Col *WINCOL(Win *w) {return (Col *) w->tile.list;}
    

    Iteration

    There is no reason that every file dealing with tile lists need care about the internals of the list. This also substantially helps if the algorithm needs to be rearranged.
    <public function declarations>+= (U->) [<-D->]
    #define FOR_ALL_TILES(t, l)\
    { int __fral;\
            for (__fral = 0; __fral < (l)->count && (t = (l)->tiles[__fral]); __fral++)
    #define FOR_ALL_SHOWING_TILES(t, l)\
    { int __fral;\
            for (__fral = (l)->hidden; __fral < (l)->count && (t = (l)->tiles[__fral]); __fral++)
    #define END_ALL }
    

    Computing a Tile's Height

    This is a trivial computation, but occurs frequently enough to warrant its own macro.
    <public function declarations>+= (U->) [<-D->]
    #define TILESIZE(tile)  ((tile)->max - (tile)->min)
    

    Internal Functions

    TileList Management

    For the moment, the only code we have to worry about is the stuff that makes sure adding a tile goes cleanly. The array in the tile list grows exponentially. It never shrinks, as it should never get very large anyhow.
    <make sure tile list has room for one more>= (<-U)
    if (list->count == list->maxtiles) {
            list->maxtiles *= 2;
            list->tiles = realloc(list->tiles, list->maxtiles * sizeof(list->tiles[0]));
    }
    

    Finding a Tile

    Finding a tile given a location is useful on at least a couple of occassions. This function returns the index of the tile in the supplied list, or -1 if no such tile exists. This is a little extra-clever because we can search through the tiles binarily instead of just slogging through them linearly. We see that this terminates because, on every iteration, either start is increased by at least 1 or end is decreased by at least one (because of C's rounding, start + (end - start / 2 is always less than start + (end - start)).
    <static tile functions>+= (U->) [<-D]
    static int
    index_for_place(TileList *list, int spot) {
            int start = list->hidden;
            int end = list->count;
            int mid;
            Tile *tile;
    
            while (start < end) {
                    mid  = start + (end - start) / 2;
                    tile = list->tiles[mid];
                    if (spot < tile->min)
                            end = mid;
                    else if (spot > tile->max)
                            start = mid + 1;
                    else
                            return mid;
            }
            return -1;
    }
    

    Assertions

    There will be some useful assertions to make at various points in the code. Some are catastrophic, others are merely aeshetic problems.
    <public tile functions>+= (U->) [<-D]
    void
    check_tile_consistency(Tile *tile) {
            <tile consistency checks>
    }
    
    void
    check_list_consistency(TileList *list) {
            int i;
            Tile *t;
    
            <tile list consistency checks>
            FOR_ALL_TILES(t, list) {
                    check_tile_consistency(t);
            } END_ALL;
    }
    
    <public function declarations>+= (U->) [<-D]
    void check_list_consistency(TileList *);
    

    Catastrophic problems include:

    1. The tile list is null.
      <tile list consistency checks>= (<-U) [D->]
      assert(list);
      

    2. There are more tiles than there is space for them.
      <tile list consistency checks>+= (<-U) [<-D->]
      assert(list->count <= list->maxtiles);
      

    3. There are hidden tiles but no visible tiles.
      <tile list consistency checks>+= (<-U) [<-D->]
      assert(list->count == 0 || list->count > list->hidden);
      

    4. The first or last element of the tile list is off-screen.
      <tile list consistency checks>+= (<-U) [<-D->]
      assert(list->count == 0 || list->tiles[list->hidden]->min >= list->min);
      assert(list->count == 0 || list->tiles[list->count - 1]->max <= list->max);
      

    5. The max edge of one tile is not equal to the min edge of the following tile.
      <tile list consistency checks>+= (<-U) [<-D]
      for (i = list->hidden + 1; i < list->count; i++)
              assert(list->tiles[i-1]->max == list->tiles[i]->min);
      

    6. The tile's tag is not at tile.r.min.
    7. The tile's tag is wider than the tile.
    8. The information in struct tile is not consistent with the information in the enclosing structure.
    9. The tile has negative height.
      <tile consistency checks>= (<-U <-U <-U <-U <-U)
      assert(tile->min <= tile->max);
      

    The code is ugly if:
    1. The right side of the rightmost column should be equal to screen.r.max.y.
    2. The bottom of the bottommost window is further than font->height above screen.r.max.x.
    3. The tile's tag is narrower than the tile.

    Slamming It All Together

    Not much cleverness here....
    <tiletypedef.h>=
    <typedefs>
    
    <tiletype.h>=
    <data structures>
    
    <tileproto.h>=
    <public function declarations>
    
    <tile.c>=
    #include "wily.h"
    
    <static tile functions>
    <public tile functions>
    

    on every iteration, either start is increased by at least 1 or end is decreased by at least one (because of C's rounding, start + (end - start / 2 iswily-0.13.42/Doc/old/pythonpaper.html000064402366570000012000000514601033320152300172240ustar00ozstaff00004330000002 Wily + Python > Emacs + Lisp?

    DRAFT ONLY

    This is a draft of a document which will be submitted to the 4th International Python Conference to be held at June 4-6, 1996 at the Lawrence Livermore labs in California.

    This document describes aspects of Wily which are not yet released for beta testing.

    Wily + Python > Emacs + Lisp?

    Gary Capell <gary@cs.su.oz.au>
    Basser Department of Computer Science,
    University of Sydney, 2006
    Australia
    Wily is an editing environment which can be extended with Python programs. Instead of using an embedded Python interpreter, Wily talks a simple message protocol, and a module lets Python speak the same protocol. This approach is general (one can use any language) and clean (the editor is responsible for only a small set of functions). The message interface promotes a clear separation of functions, with the Wily editing environment providing a standard way of interacting with client programs. The main disadvantage may be that the looser binding between programming language and editor is less efficient, but this is not expected to be a significant problem.

    The editor itself is simple, clean, and efficient, with a few features which combine consistently. It abandons backwards compatibility with the virtual terminals of yesteryear, to take full advantage of a bitmapped terminal and three button mouse.

    Table of Contents

    This documet describes:

    An appendix defines the Python interface in more detail.

    Overview of Wily

    This is necessarily very brief, and Wily and Acme are very different from what most people are used to. Please read Rob Pike's paper for a better and more complete description of the interface.

    Wily's main attractions are that it is very simple (the User Manual describing the whole user interface is about seven pages), very quick to use, and integrates well with other Unix tools.

    History

    Wily emulates in the Unix and X Windows environment the Acme editor from Plan 9. Acme couldn't easily be ported to Unix because it is written in Alef (a concurrent programming language not widely available) and uses non-portable features of Plan 9 . Also, a port of Acme would not be freely distributable.

    The name ``Wily'' derives from Wile E. Coyote, an avid consumer of Acme products.

    Modern Aesthetics

    Wily windows, Unicode text propotionally spaced

    The screen is divided into columns, which are divided into windows. A window may represent a file, a directory, or the output from some program. The screen, columns and windows each have a narrow horizontal ``tag'' at the top, which contains some useful text, and for windows contains the name of the window and a "file is modified" indicator.

    Text is displayed in a propotionally spaced font by default. There is a built in function to toggle with a monospace font, but there are very few occasions when this is necessary or desirable. In most cases limiting a text editor to monospace fonts is blindly following the hardware limitations of the 1960s.

    Text is read and written as UTF8-encoded Unicode, providing some support for editing multi-lingual and scientific text, but remaining backwardly compatible with plain 7-bit ASCII text.

    Everything is text

    All actions in Wily are through creating and interacting with text on the screen, using the three-button mouse and the keyboard. B1 (mouse button one) selects text, B2 executes text and B3 attempts to ``goto'' the text.

    When executing text, there are some built in operations, such as ``Quit'', or ``Del'' which are executed by Wily itself. Otherwise, the command is executed in a subprocess, with output redirected to a window within Wily and input from /dev/null. It is also possible to use the current selection (currently selected text) as input for and/or output of some child program. For example |fmt formats the current selection, >spell checks its spelling and <date replaces it with the current time.

    The goto operation used with B3 is polymorphic in that it recognises three different patterns:

    name
    If name is a file or directory, open it, otherwise search for the literal name
    :address
    Search for address in the current window. The address may be a line number, a character number, a regular expression, or two of these, separated by a comma.
    file:address
    Open file and search in it for address

    Wily's power derives in part from its general treatment of text. Whether text is found in a file, or directory listing, created by Wily, output by some other program, or typed by the user, it can all be treated the same way. A simple text file may be used as a menu of commands or a simple form of hypertext. Previously typed commands or ``usage'' messages can be edited and executed. There is no need for dialogs, menus, modes, buttons or accelerator keys, just operations on text on the screen.

    No wasted user actions

    Wily minimizes the number of unnecessary mouse or keyboard actions the user must make. For instance, placing newly created windows is done without needing the user's help, although the user can easily rearrange things if Wily's heuristics aren't acceptable. Wily also makes cutting, pasting, executing and searching for text so easy to do with the mouse that there is no need to retype text already on the screen.

    Cutting and pasting text is made particularly convenient using combinations of mouse buttons. To cut text, select it with B1, and while still holding B1, also click B2: this is a B1-B2 chord. To paste text use a B1-B3 chord. This style is unusual, but once it becomes familiar other methods of cutting and pasting seem unbearably slow. Another chord (B2-B1) is used to execute some text with an argument.

    To avoid having to position the mouse accurately, a mouse selection of zero length (i.e. a mouse click) is expanded in a ``reasonable'' manner. Clicking with B2 in a word expands to that word, which is then executed. Clicking with B3 in an address (e.g. foo.c:45) expands to that address. Double-clicking with B1 just inside paired braces, brackets or quotes selects the region thus delimited.

    Wily's general approach to text as commands and addresses is compounded because these basic functions can be accessed so conveniently. Most operations can be achieved with a single mouse click or mouse combination.

    Synergy

    The consistent and general use of text for input and output in Wily makes the combination of its features more than the sum of its parts.

    Stepping through an example session might best illustrate this:

    Susan has fetched the file frob.tar.Z. She clicks with B1 in the file name, and with B2 in the word untarz. The utility untarz uncompresses and untars the file, verbosely printing file names as it goes. She clicks with B3 on one of the file names, INSTALL, which opens the file. The INSTALL file suggests that she run configure then make. She clicks B2 in each of these words to run the suggested programs, but there's a problem. The make fails when gcc quits with the error message
    keyboard.c:4: strings.h: No such file or directory.
    She clicks with B3 in the first part of the error message, which opens the file and selects the line. On Susan's system there is a string.h but no strings.h. She removes the last s with a B1-B2 chord. When she modifies the file, Wily sets the ``file modified'' indicator, and adds the word ``Save'' to the tag for this window. Susan clicks B2 on the word Save to write the file, clicks B2 on make again, and she's done.

    This whole process uses about ten mouse clicks and no typing.

    Connecting Programs to Wily

    Wily waits for a program to connect to it using a socket, and then sends and receives messages. The messages can be RPC requests and replies, or ``event'' messages generated by Wily when certain actions happen in windows which a remote program has asked to monitor.

    The interface is deliberately at a rather high level. The intent is that Wily will take care of of the details of interaction, with other programs providing the semantics of executing a command, opening a window or searching for an address. This promotes a consistent set of tools and an efficient division of labour, but necessarily at the loss of some generality.

    The requests allow the remote program to

    • list the windows currently open
    • create a new window with a given name, which may or may not correspond to an existing file or directory
    • ask to be sent some subset of the events which happen in a particular window
    • change the name of a window
    • read the text from some part of a window
    • modify the text in a window
    • act as if some string were selected with B2 or B3 in a window (useful for searching for text, or accessing built in functions)

    A program may ask to be notified when events happen in a particular window. These events are generated when:

    • text is selected with B2 or B3 (i.e. the user is trying to execute or ``goto'' some text)
    • text has been modified
    • the window is destroyed

    When a program is being sent B2 or B3 events, Wily doesn't act on them, merely sends them on. The program may opt to ``send back'' some events which Wily will then act on. Events which modify text, on the other hand, are always handled by Wily, which then may inform the remote program what has happened. In other words, the remote program cannot stop the user modifying any piece of text, although it can repair the text later if it wishes.

    The Python interface

    Wilymodule.c

    This is a very simple interface between Python and the Wily message protocol. It establishes a connection, provides remote procedure calls and queues events until they are requested.

    A Connection is initialized with no arguments, and represents the connection to Wily. All the other functions are methods of a connection object.

    The Connection has methods to return a list of windows representing all the windows currently open in Wily, to create a new window, and to return the next event from Wily. Windows are represented as integers, which correspond to window identifiers with Wily, and events are represented as tuples.

    The Connection has a number of methods which provide operations on Wily windows. These operations allow a program, once it has an identifier for a window, to change its event mask, its name or its ``tools'' (useful text in the window's tag), read or modify some of its text, or simulate a B2 or B3 action.

    Wilywin.py

    This is a small Python module which provides a friendlier interface to Wily's functionality.

    Example Program Fragment

    # Create a window called "hello",and fill it with 
    # the text "Hello, world"
    
    import wily
    con = wily.Connection()
    win = con.win("hello")
    con.replace(win, 0,0, "Hello, world\n")
    

    Sample Tools

    These are small tools written as proof of concept, to test and refine the message interface, and as templates for other applications.

    News reader

    This uses Python classes for threading, talking NNTP and reading and writing .newsrc files, and Wily for displaying newsgroups and articles. The program acts on B3 actions on article numbers, and B2 actions on some special function names (e.g. Catch-up, Follow-up) which it also places in the correct tags.

    Session save and restore

    There are two programs to save and restore the ``state'' of an editing session. The ``save'' program determines from Wily what windows are open, what the current selection is for each, and the full text of windows which don't represent a file or directory. The ``restore'' program connects to Wily and uses the saved information to create and massage windows to hopefully return the session to the original state.

    Terminal

    There are some useful programs which require the traditional ``prompt and read a line of input'' interface. Examples include gdb, /bin/sh or /bin/mail. To use these programs, but from within the Wily editing environment, a simple terminal program was written, in C. It is called win.

    Win provides standard input and output for its client program, and creates and monitors a Wily window, maintaining an input point. When win sees a carriage return entered after the input point, it sends the text between the input point and the carriage return to the client program. Output coming back from the client program is inserted just before the input point.

    Win does not attempt to provide a pseudo tty or work with any programs which attempt to use curses-style screen addressing. However, it works fine for programs such as those mentioned above, and was written with only 230 lines of commented C.

    Alternative approaches

    Wily's approach to extending the editor is to communicate with other processes using a socket or pipe. Here we examine some alternative strategies, and why Wily doesn't use them.

    Build an interpreter into the editor

    This is by far the most common design for an extensible editor.

    There are a few advantages to this approach. Letting the extension language share the address space of the editor is more efficient than using IPC. The language can also be tailored to provide a close match to the editing requirements.

    There are two reasons why this approach was rejected for Wily. The first reason is that it restricts users to a single language, and it often means designing a new (possibly half-baked) language. The second reason is that embedding a language interpreter in the editing environment seemed an unnecessary step towards monolithism and code bloat.

    For comparison, below are the sizes of three stripped, dynamically linked executables on the author's sun4d Solaris system:
    167264 wily
    234272 vi
    1873336 xemacs

    Link code dynamically

    Another approach is to dynamically link extension code with the editor. This is more general and more efficient than the built in interpreter design. CodeWright® from Premia uses this approach in the Microsoft Windows environment.

    One problem with this approach is that dynamic linking is not standard on all UNIXes. Another is that one errant code fragment dynamically linked in might damage the integrity of the editor. The result might be lost data, or even worse, data quietly modified in some subtle manner.

    When this approach becomes ubiquitously available and more secure, it will be re-examined.

    ILU or CORBA

    It would seem that ILU and CORBA both provide a ready-made solution to turn an editor into a distributed object server. However, both seemed too heavy-weight for this simple task.

    Further Work

    There is a strong belief amongst Wily's users and developers that ``creeping featurism'' is evil. Most of the ongoing work will be towards refining existing features, and improving the clarity and correctness of the code. Retaining the ``look and feel'' of Acme is also an important consideration.

    There is still room for innovation, though. The message interface is still very young, and may change with the demands of application writers. The author hopes that the Python community will be able to make good use of an editor programmable in Python. Although there is no need for cursor keys to navigate around Wily, they may be added later, although they are a low priority.

    Networking and security

    Currently programs connect to Wily by writing to a UNIX named pipe. Wily's security relies on this pipe being writable only by its owner. This means Wily can't accept connections directly from remote machines, which would be desirable for some applications. A design which avoids this limitation securely and efficiently has not been decided upon.

    Obtaining Wily

    Wily is freely available.

    The prime source for information about Wily is the WWW page at http://www.cs.su.oz.au/~gary/wily/ The wily distribution contains wilymodule.c, and can be obtained at ftp://ftp.cs.su.oz.au/gary/wily.tgz

    Acknowledgements

    The early design and source of Wily owe a lot to Bill Trost. Wily and this paper have also been improved by patches, suggestions and bug reports from Assar, Davor Cubranic, Kyle Dean, Stephen Gallimore, Mark H. Wilkinson, Bjorn Helgaas, Steve Kilbane, Beirne Konarski, Bob Krzaczek, Alberto Nava, Arnold Robbins, Rich Salz, Scott Schwartz, Chris Siebenmann, and Richard Wolff.

    Wily builds on the Sam distribution by Rob Pike and Howard Trickey, and originally used libtext by James Farrow. James Farrow also makes available a set of Unicode fonts for X at ftp.cs.su.oz.au/matty/unicode/


    Appendix: The Python/Wily Module

    con = wily.Con()

    Connection

    Connection objects have no attributes and suport the following methods:

    list()
    Returns a list of names and Win objects representing the windows currently open.
    win(name)
    Return a new window called name
    event()
    Return the next Event. Note that this method will block until an event is available.
    eventwouldblock()
    Indicates whether calling Connection.event() would block.
    returnevent(event)
    Send event back to Wily, probably because we have no use for it.

    The following methods of a connection object act on a window.

    attach(id,mask)
    Request events for this window.
    detach(id)
    Cancel request for events for this window.
    setname(id,string)
    Set the name of this window.
    settools(id,string)
    Set the toolbar for this window.
    read(id,from,to)
    Read some range from this window, returns a UTF8 string.
    replace(id,from,to, string)
    Replace some range of window with some other text.
    run(id, command)
    Makes wily act as if command had been selected with B2 in this window. This can be used to access Wily's built in functions. For example, to delete w, call con.run(w_id, "Del")
    goto(id,address)
    Makes wily act as if address had been selected with B3 in this window. Returns a tuple identifying the window and position which are the result of the search.

    Events

    Events are returned as tuples. Every event has at least two elements, which are a window identifer, and an event type identifier (which is one of wily.GOTO, wily.EXEC, wily.REPLACE or wily.DEL). All of these event types except DEL also have a from, to and string attribute. e always handled by Wily, which then may inform the remote program what has happened. In other words, the remote program cannot stop the user modifying any piece of text, although it can repair the twily-0.13.42/Doc/old/auug.tex000064402366570000012000000303201033320152300154400ustar00ozstaff00004330000002\documentclass[twocolumn]{article} \usepackage{times,a4wide,epsfig} \title{The Wily User Interface (Acme for Unix)} \author{Gary Capell\\ Basser Department of Computer Science,\\ University of Sydney, 2006\\ Australia\\ gary@cs.su.oz.au} %\keywords{text editor, window manager, user interface} \begin{document} \maketitle \begin{abstract} The Wile E. Interface (wily) provides much of the feel of Acme [Pike95] in the Unix/X environment. This paper gives a brief overview of wily's interface, explains the implementation, and includes a brief note on window management. \end{abstract} \section{History} Wily is a reimplementation of Acme \cite{acme} for the Unix/X environment. Acme itself was heavily inspired by the Oberon \cite{oberon} user interface. A port was not possible because the Acme implentation relies on Alef \cite{alef}(a concurrent programming language not widely available) and non-portable features of Plan 9 \cite{9BLabs}. The name "wily" derives from Wile E. Coyote, an avid user of Acme products. \section{The Interface} This is a sketch of the interface, for details refer to \cite{acme} or \cite{wilyu}. \subsection{Why Wily?} Wily attempts to take maximum advantage of a bitmapped display and three-button mouse, and to require a minimum of effort from its users to achieve common tasks. Common editing operations that with other editors require incantations of control keys or selecting from lists of menu items can be done with with very little effort using the mouse. There have been no user studies, but subjectively, wily seems to substantially streamline the editing and debugging process. The interface integrates some of the functions of editor, window manager, file browser and shell, as well as providing an interface for external programs such as mail and news readers and debuggers. The interface is not obvious or familiar, but is composed of a few principles consistently applied, and does not take long to learn. Once learnt, the interface is sufficiently addictive that the author re-implemented Acme to work under Unix, rather than coping with other editors. \subsection{Appearance} \begin{figure} \epsfig{file=pane2.ps,width=8cm} \caption{Wily windows}{} \end{figure} Wily appears as one or more vertical columns, divided into windows of scrolling text. Each column or window is headed by a thin horizontal tag which includes the name of the file or directory the window represents, some commands, and a marker indicating if the file contains changes not yet written to disk. The text in a window may represent a directory, a file, an interface to some external program such as a news reader, or the output from some command. \subsection{Mouse Actions} \emph{Any} text on the screen can be selected by dragging with a mouse button. The actions of the different buttons are: \begin{description} \item[Button 1] highlights the text for later actions \item[Button 2] executes the text as a command, e.g. selecting the word 'make' will run the make command as if it were typed to the shell. There is a small set of built-in functions that are searched for first. \item[Button 3] attempts to \emph{open} the selected text. What this means depends on the text selected. If the text is the name of a file or a search pattern for a part of some file, the file is opened if necessary, and the pattern is searched for. Otherwise, the text is treated as a string to be searched for in the current window. \end{description} Panes and columns can be moved and reshaped by clicking or dragging in the \emph{buttons} to the left of their tags. There are no menus, and five special keys (page up, page down, kill word, kill line, select recently typed text). All functions are accessed through mouse actions on text. \subsection{Context} Commands and file names are interpreted with respect to the directory of the window in which they originate, so for example selecting \texttt{foo.h} with button 3 in file \texttt{/src/wily/bar.c} will open the file \texttt{/src/wily/foo.h}. Similarly selecting \texttt{make} in the tag of \texttt{/src/wily/bar.c} will run \texttt{make} in \texttt{/src/wily/}, with any output sent to a window labelled \texttt{/src/wily/+Errors} (which will be created if necessary). \subsection{Short Cuts} Double-clicking with button 1 selects either a word, a line or a piece of text delimited by parentheses, quotes or brackets. If buttons 2 or 3 make a selection of zero length (i.e. a click) the selection is expanded to a whole word or a file name with optional address (respectively). Mouse \emph{chords} are used for cutting and pasting. To move some text from one place to another, it first is selected by dragging with button 1. While holding button 1 down, if button 2 is pressed, the text is \emph{cut}. The text can later be pasted into place by holding button 1 and then clicking button 3. This action is easier done than said, and is much quicker than searching for a menu entry. A mouse chord is also used as a short-hand for the idiom of executing a command with some argument. While clicking with button 2 in the command, if button 1 is then pressed, the text most recently selected with button 1 is given as an argument to the command. For example, one could click with button 1 in a program variable, chord buttons 2 and 1 on the name of a script to grep through source files, and get a list of all occurrences of that variable. Clicking with button 3 on any of the occurrences on that list will open the relevant file at the correct line. The mouse cursor is often warped to where the program predicts the next action is likely to take place. For example, after opening a file at a particular address, the cursor is warped to that position of that file. The escape key selects any text typed since the last cursor movement, making it easier to select with the mouse. \subsection{Miscellanea} Wily by default displays text proportionally spaced, which is much more pleasant to read than constant width text. A builtin function lets the font be switched temporarily to constant width when necessary. Wily provides a full Undo/Redo history for each window. Newly created windows are placed by the program, not the user. While it is possible for the user to reposition or resize the window after it is created, window-positioning heuristics generally make such positioning unnecessary. \subsection{A Short Example} Gary has been using wily to develop a program called wily. He clicks button 2 in the word \texttt{make} which he's left in the tag of the window for his source directory. A new window pops up labelled \texttt{/src/wily/+Errors}, containing amongst other things the line \texttt{builtins.c:78: parse error before `)'}. He clicks button 3 anywhere in \texttt{builtins.c:78:}. A new window labelled \texttt{/src/wily/builtins.c} appears, with line 78 highlighted, and the cursor warps to this line. Gary sees that the last \texttt{)} on that line is unnecessary. He selects it with button 1, and while holding button 1 down, clicks button 2 to cut out the offending parenthesis. The button of the window changes, to indicate that the window represents a file which is "dirty". Gary clicks button 2 in the word "Put" in the window's tag, to write the file to disk. He selects \texttt{make} in the tag of the window of the directory, and the cycle begins again. This whole interaction required six mouse clicks and much less time than the time to read about it. \section{The Implementation} Wily is a single-threaded event-driven server process. The events it waits for are keyboard and mouse actions, and output arriving on pipes shared with child processes. Text display is handled by text widgets. \subsection{Child Processes} To execute a command that isn't built in, the wily server forks a child, modifies the child's execution environment, and the child \texttt{exec}s the required command. The current directory is set to that which the command was invoked from. The child's file descriptors are set so that \texttt{stdin} is redirected from \texttt{/dev/null}, \texttt{stdout} and \texttt{stderr} are redirected to a file descriptor the server listens to for output, and file descriptor 3 is a socket open to pass messages between the server and child. The child also inherits some environment variables which are helpful for writing scripts: \texttt{WILYLABEL} is the context the command was invoked from, and \texttt{WILYARGLABEL} is the context of the argument to the command, if any. The parent adds the file descriptors passed to the child to a list of file descriptors that it monitors for output, and remembers which directory that stream is associated with, so that output will appear in an appropriate window. More sophisticated client processes can communicate with the server through a message protocol. The message protocol is still being designed, but basically when the user interacts with a wily window, wily sends messages to the client program to let it know what the user has done. For example a news reading client might display an overview of a news group, and wait for a message from wily to indicate that the user has clicked with button 3 to indicate that they want to "open" a particular news item. Wrappers for the shell and Python\cite{python} have been written to make writing programs using wily as their interface even easier. For example, here is a simple mail interface written in \texttt{rc}: \begin{verbatim} #!/bin/rc id= `{wnew} # create a new window wcmd $id Label $home/Mail/inbox wcmd $id Tag inc scan rmm repl wout $id scan # display scan's output \end{verbatim} On the author's system, Wily's binary (not including X shared libraries) is one-fourteenth the size of Xemacs'. The source code for wily (not including libtext, libframe, libXg) takes 3045 lines (measured by \texttt{wc -l *.[ch]}). \section{Window Management} One of the reasons wily was written was to experiment with alternatives for window management. Acme's tiling windows are occasionally quite annoying. An earlier implementation of wily used one window (and one process) per pane, which communicated using two X cut buffers and named pipes. Window management was then passed on to the X window manager. This had the benefits of providing overlapping windows, multiple work spaces (using the virtual root window), and the option of iconifying windows. Unfortunately, this arrangement turned out to be much more annoying than the tiling window management of Acme, when used with the large numbers of windows that come into play when, for example, developing software using wily. Sadder but wiser, a tiling window manager was added to wily. \section{Strengths, Weaknesses and Further Work} The things the author misses most when using another editor are: mouse chording for cut and paste (alternatives seem very awkward), opening a file to a particular line with a single mouse click, and editing in a proportional font. Some of wily's strengths may also be seen as weaknesses: heavy exploitation of bitmapped terminal and three button mouse mean wily is unusable on glass and paper ttys. The terse mouse command language is opaque and even intimidating for new users. Occasionally it seems that arrow keys would be helpful. Wily doesn't yet provide all the features of Acme. Notably missing are sophisticated window arrangement and regular expression searching. These features are towards the top of the wily To Do list, along with minimizing portability problems, simplifying the code, and firming up the messaging interface. Built-in functions may soon be provided to allow selected text to be piped through, to be replaced by the output of, or to be used as the input for some executed command. The display of text may also be experimented with. One possibility is to provide an \emph{outline} mode where subtrees of a hierarchy may be hidden. \section{Availability} Wily is available for anonymous FTP from \texttt{ftp.cs.su.oz.au} in directory \texttt{gary/wily}. The author welcomes comments, suggestions and fixes to portability problems. \section{Acknowledgements} Many suggestions on wily and this paper, and much of the code were received from Bill Trost \texttt{trost@cloud.rain.com}. Libraries used include libXg and libframe, part of the Sam distribution by Rob Pike and Howard Trickey, and libtext by James Farrow. \bibliography{wily} \bibliographystyle{plain} \end{document} wily-0.13.42/Doc/old/python.sgml000064402366570000012000000074221033320152300161710ustar00ozstaff00004330000002

    Wily/Python Interface <author> <htmlurl url="http://www.cs.su.oz.au/~gary/" name="Gary Capell"> <date>v0.11.0 April 1996 <abstract> This document describes the Python interface to <htmlurl url="http://www.cs.su.oz.au/~gary/wily/" name="Wily">, which is implemented in <tt/wilymodule.c/. It defines three classes: <tt/Connection/, <tt/Win/ and <tt/Event/. A <tt/Connection/ is initialized with no arguments, and represents the connection to Wily. A <tt/Win/ object is created by the <tt/Connection/, and is usually initialized with the name for a new window. The <tt/Connection/ has methods to return a list of windows representing all the windows currently open at Wily, to create a new window, and to return the next <tt/Event/ from Wily. A <tt/Win/ has methods to change its event mask, name or ``tools'' (useful text in the window's tag), read or modify some of its text, or simulate a B2 or B3. <tt/Event/ objects have attributes to identify the window to which they refer, the event type, and other optional attributes depending on the event type. B2 and B3 events include the text selected, and where it was located in the text. Text modifying events indicate where the change took place, and what new text was added. See also the <htmlurl url="msg.html" name="Wily Messaging Interface"> for C programs, the <htmlurl url="user.html" name="Wily User's Guide"> and <htmlurl url="pythonpaper.ps" name="Wily+Python>Emacs+Lisp"> This document is also available in <htmlurl url="python.ps" name="Postscript">. </abstract> <toc> <sect>Connection<P> <sect1>Creating<P> <verb> import wily con = wily.connection() </verb> <sect1>Attributes None <sect1>Methods<P> <descrip> <tag/win(name)/ Returns a new window, with the given <tt/name/ <tag/list()/ Returns a list of <tt/win/s representing the windows currently open in wily. <tag/event()/ Returns the next Event. Note that this function will block until it receives an event. <tag/event_wouldblock()/ Indicates whether <tt/event()/ would block. </descrip> <sect>win<P> <sect1>Creating<P> <tt/win/ objects are returned by <tt/connection.win(name)/ or as part of <tt/connection.list()/ <sect1>Attributes<P> <descrip> <tag/id/ window id <tag/name/ name <tag/dot/ a (from,to) tuple representing the currently selected portion of the window. </descrip> <sect1>Methods<P> <descrip> <tag/attach()/ Request events for this window. <tag/detach()/ Cancel request for events for this window. <tag/setname(s)/ Set the name of this window. <tag/settools(s)/ Set the toolbar for this window. <tag/read((from,to))/ Read some range from this window. <P>Called with a tuple representing the range to read, returns a UTF string. <tag/replace((from,to),s)/ Replace some range of window with some other text. <P>Called with a tuple representing the range to replace, and a string to replace it with. Insertion and deletion are special cases of <tt/replace/, with null range or replacement string respectively. <tag/run(s)/ Execute some text in this window. Makes wily act as if <tt/s/ had been selected with button 2 in this window. This can be used to access Wily's built-in functions. For example, to delete <tt/w/, call <tt/w.run("Del")/ <tag/goto(s)/ "Goto" some text in this window. Makes wily act as if <tt/s/ had been selected with button 3 in this window. This can be used to open a new window, or search for some regular expression. Returns a <tt/win/ if the Goto resulted in a successful search in this window. </descrip> <sect>Event <sect1>Attributes <P><descrip> <tag/id/ of the window the event occurred in <tag/t/ Message type: one of <tt/wily.GOTO/, <tt/wily.EXEC/ or <tt/wily.REPLACE/. <tag/r/ (from,to) tuple <tag/s/ string </descrip> <sect1>Methods <P><descrip> <tag/returnevent/ Send this event back to Wily to interpret </descrip> </article> of <tt/win/s representing the windows currently open in wily. <tag/event()/ Returns the next Event. Note that this function will block until it receives an event. <tag/event_wouldblock()/ Indicates whether <tt/event()/ would block. </deswily-0.13.42/Doc/old/wily.bib�����������������������������������������������������������������������0000644�0236657�0000012�00000013264�10333201523�0015427�0����������������������������������������������������������������������������������������������������ustar�00oz������������������������������staff���������������������������0000433�0000002������������������������������������������������������������������������������������������������������������������������������������������������������������������������@INPROCEEDINGS{hello, author = "Rob Pike and Ken Thompson", title = "{Hello World}", editor = "", booktitle = "Proc. of the Winter 1993 USENIX Conf." , number = "", series = "", pages = "43-50", month = "", year = 1993, address = "San Diego", organization = "", publisher = "", note = "", } @INPROCEEDINGS{8.5, author = "Rob Pike", title = "{8$1/2$, the Plan 9 Window System}", editor = "", booktitle = "Summer 1991 USENIX" , number = "", series = "", pages = "257-265 ", month = "June", year = 1991, address = "Nashville", organization = "", publisher = "", note = "", } @INPROCEEDINGS{9BLabs, author = "Rob Pike and Dave Presotto and Ken Thompson and Howard Trickey", title = "{Plan 9 from Bell Labs}", editor = "", booktitle = "Summer 1990 UKUUG Conference" , number = "", series = "", pages = "1-9", month = "July", year = 1990, address = "London", organization = "", publisher = "", note = "", } @INPROCEEDINGS{9Dsys, author = "Dave Presotto and Rob Pike and Ken Thompson and Howard Trickey", title = "{Plan 9, A Distributed System}", editor = "", booktitle = "Spring 1991 EurOpen Conference" , number = 17, series = "", pages = "43-50", month = "May", year = 1991, address = "Troms", organization = "", publisher = "", note = "", } @INPROCEEDINGS{9Mstream, author = "Dave Presotto", title = "{Multiprocessor Streams for Plan 9}", editor = "", booktitle = "Summer 1990 UKUUG Conference", number = "", series = "", pages = "11-19", month = "July", year = 1990, address = "London", organization = "", publisher = "", note = "", } @INPROCEEDINGS{9Sleep, author = "Dave Presotto and Rob Pike and Ken Thompson and Gerard Holzmann", title = "{Process Sleep and Wakeup on a Shared-Memory Multiprocessor}", editor = "", booktitle = "Spring 1991 EurOpen Conference" , number = "", series = "", pages = "161-166", month = "May", year = 1991, address = "Troms", organization = "", publisher = "", note = "", } @INPROCEEDINGS{9net, author = "Dave Presotto and Phil Winterbottom", title = "{The Organization of Networks in Plan 9}", editor = "", booktitle = "USENIX Winter '93" , number = "", series = "", pages = "271-287", month = "", year = 1993, address = "San Diego, CA", organization = "", publisher = "", note = "", } @INPROCEEDINGS{acid, author = "Phil Winterbottom", title = "{ACID: A Debugger Built From A Language}", editor = "", booktitle = "USENIX " , number = "", series = "", pages = "", month = "January ", year = 1994, address = "San Francisco, California", organization = "", publisher = "", note = "", } @INPROCEEDINGS{alef, author = "Phil Winterbottom: ", title = "{Alef language Reference Manual}", editor = "", booktitle = "Plan 9 Programmer's Manual, Volume Two, 2nd Ed." , number = "", series = "", pages = "", month = "", year = 1995, address = "", organization = "AT \& T Bell Labs", publisher = "Harcourt Brace and Company", note = "", } @INPROCEEDINGS{acme, author = "Rob Pike ", title = "{Acme: A User Interface for Programmers (\texttt{http://plan9.att.com/plan9/doc/acme.html}}", editor = "", booktitle = "USENIX" , number = "", series = "", pages = "", month = "January", year = 1994, address = "San Franciso, California", organization = "", publisher = "", note = "", } @INPROCEEDINGS{help, author = "Rob Pike ", title = "{A minimalist Global User Interface}", editor = "", booktitle = "Graphics Interface '92" , number = "", series = "", pages = "282-293", month = "January", year = 1992, address = "Vancouver", organization = "", publisher = "", note = "", } @Article{oberon, author = "N. Wirth and J. Gutknecht", title = "{The Oberon System}", editor = "", journal = "Software - Practice and Experience" , number = "9", volume="19", pages = "857-894", month = "Sep", year = 1989, address = "", organization = "", publisher = "", note = "", } @INPROCEEDINGS{rc, author = "Tom Duff", title = "{Rc - A Shell for Plan 9 and UNIX Systems}", editor = "", booktitle = "Summer 1990 UKUUG Conference", number = "", series = "", pages = "21-33", month = "July", year = 1990, address = "London ", organization = "", publisher = "", note = "", } @Article{worm, author = "Sean Quinlan", title = "{A Cached WORM File System}", OPTcrossref = "", OPTkey = "", journal = "Software-Practice and Experience", year = "1991", volume = "21", number = "12", pages = "1289-1299", month = "December", OPTnote = "", OPTannote = "" } @Misc{wilyu, author = "Gary Capell", title = "{Wily User Manual}", OPTcrossref = "", OPTkey = "", journal = "", year = "1995", volume = "", number = "", pages = "", month = "", OPTnote = "", OPTannote = "" } @TechReport{python, author = "Guido van Rossum", title = "{Python Tutorial}", institution = "CWI", year = "1995", number = "CS-R9526", address = "", } @TechReport{ilu, author = "Xerox Corporation", title = "{ILU homepage \texttt{ftp://ftp.parc.xerox.com/pub/ilu/ilu.html}}", institution = "Xerox", year = "1996", number = "", address = "", } @TechReport{corba, author = "Object Management Group", title = "{What is CORBA? \texttt{http://ruby.omg.org/corba.html}}", institution = "OMG", year = "1996", number = "", address = "", } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������wily-0.13.42/Doc/old/wily.1�������������������������������������������������������������������������0000644�0236657�0000012�00000030566�10333201523�0015037�0����������������������������������������������������������������������������������������������������ustar�00oz������������������������������staff���������������������������0000433�0000002������������������������������������������������������������������������������������������������������������������������������������������������������������������������.TH WILY 1 .SH NAME wily, win, awd \- interactive text windows .SH SYNOPSIS .B wily [ .B -f .I varfont ] [ .B -F .I fixfont ] [ .B -c .I ncol ] .LP .B win [ .I command ] .LP .B awd [ .I label ] .SH DESCRIPTION .I Wily manages windows of text that may be edited interactively or by external programs. The interactive interface uses a different interface. .PP Any named .I files are read into .I wily windows before .I wily accepts input. Plain files display as text; directories display as columnated lists of the names of their components, as in .B "ls -p directory|mc except that the names of subdirectories have a slash appended. .PP The .B -f .RB ( -F ) option sets the default variable-pitch (fixed-pitch) font; the default is .B /lib/font/bit/lucidasans/euro.8.font .RB ( \&.../lucm/unicode.9.font ). Tab intervals are set to the width of 4(8) numeral zeros in the variable-pitch font. .PP .SS Windows .I Wily windows are in two parts: a short .I tag above a multi-line .IR body . The body typically contains an image of a file, as in .IR sam (1), or the output of a program, as in an .IR 8½ (1) window. The tag contains a number of blank-separated words, followed by a vertical bar character, followed by anything. The first word is the name of the window, typically the name of the associated file or directory, and the other words are commands available in that window. Any text may be added after the bar; examples are strings to search for or commands to execute in that window. .PP If a window holds a directory, the name (first word of the tag) will end with a slash. .SS Scrolling Each window has a scroll bar to the left of the body. The scroll bar behaves much as in .IR sam (1) or .IR 8½ (1) except that scrolling occurs when the button is pressed, rather than released, and continues as long as the mouse button is held down in the scroll bar. For example, to scroll slowly through a file, hold button 3 down near the top of the scroll bar. Moving the mouse down the scroll bar speeds up the rate of scrolling. .SS Layout .I Wily windows are arranged in columns. By default, it creates two columns when starting; this can be overridden with the .B -c option. Placement is automatic but may be adjusted using the .I layout box in the upper left corner of each window and column. Pressing and holding any mouse button in the box drags the associated window or column. For windows, just clicking in the layout box grows the window in place: button 1 grows it a little, button 2 grows it as much as it can, still leaving all other tags in that column visible, and button 3 takes over the column completely, temporarily hiding other windows in the column. (They will return .I en masse if any of them needs attention.) The layout box in a window is normally white; when it is black in the center, it records that the file is `dirty': .I Wily believes it is modified from its original contents. .PP Tags exist at the top of each column and across the whole display. .I Wily pre-loads them with useful commands. Also, the tag across the top maintains a list of executing long-running commands. .SS Typing The behavior of typed text is similar to that in .IR 8½ (1) except that the characters are delivered to the tag or body under the mouse; there is no `click to type'. The usual backspacing conventions apply. As in .IR sam (1) but not .IR 8½ , the ESC key selects the text typed since the last mouse action, a feature particularly useful when executing commands. A side effect is that typing ESC with text already selected is identical to a .B Cut command .RI ( q.v. ). .PP All text, including the names of windows, may be edited uniformly. .SS "Directory context Each window's tag names a directory: explicitly if the window holds a directory; implicitly if it holds a regular file (e.g. the directory .B /adm if the window holds .BR /adm/users ). This directory provides a .I context for interpreting file names in that window. For example, the string .B users in a window labeled .B /adm/ or .B /adm/keys will be interpreted as the file name .BR /adm/users . The directory is defined purely textually, so it can be a non-existent directory or a real directory associated with a non-existent file (e.g. .BR /adm/not-a-file ). File names beginning with a slash are assumed to be absolute file names. .SS Errors Windows whose names begin with .B - or .B + conventionally hold diagnostics and other data not directly associated with files. A window labeled .B +Errors receives all diagnostics produced by .I wily itself. Diagnostics from commands run by .I wily appear in a window named .IB directory /+Errors where .I directory is identified by the context of the command. These error windows are created when needed. .SS "Mouse button 1 Mouse button 1 selects text just as in .IR sam (1) or .IR 8½ (1) , including the usual double-clicking conventions. .SS "Mouse button 2 By an action similar to selecting text with button 1, button 2 indicates text to execute as a command. If the indicated text has multiple white-space-separated words, the first is the command name and the second and subsequent are its arguments. If button 2 is `clicked'\(emindicates a null string\(em\c .I wily .I expands the indicated text to find a command to run: if the click is within button-1-selected text, .I wily takes that selection as the command; otherwise it takes the largest string of valid file name characters containing the click. Valid file name characters are alphanumerics and .B _ .B . .B - .B + .BR / . This behavior is similar to double-clicking with button 1 but, because a null command is meaningless, only a single click is required. .PP Some commands, all by convention starting with a capital letter, are .I built-ins that are executed directly by .IR wily : .TP .B Cut Delete most recently selected text and place in snarf buffer. .TP .B Del Delete window. If window is dirty, saves a backup of the file. .TP .B Delcol Delete column and all its windows, after checking that windows are not dirty. .TP .B Quit Exit .I wily after checking that windows are not dirty. .TP .B Font With no arguments, change the font of the associated window or column from fixed-spaced to proportional-spaced or .I vice versa\f1. Given a font name argument, change the font of the window to the named font. Other existing windows are unaffected. .TP .B Get Load file into window, replacing previous contents (after checking for dirtiness as in .BR Del ). With no argument, use the existing file name of the window. Given an argument, use that file but do not change the window's file name. .TP .B Kill Send a .B kill note to .IR wily -initiated commands named as arguments. .TP .B Look Search in body for occurrence of literal text indicated by the argument or, if none is given, by the selected text in the body. .TP .B New Make new window. With arguments, load the named files into windows. .TP .B Newcol Make new column. .TP .B Paste Replace most recently selected text with contents of snarf buffer. .TP .B Put Write window to the named file. With no argument, write to the file named in the tag of the window. .TP .B Putall Write all dirty windows whose names indicate existing regular files. .TP .B Redo Complement of .BR Undo . .TP .B Send Append selected text or snarf buffer to end of body; used mainly with .IR win . .TP .B Snarf Place selected text in snarf buffer. .TP .B Sort Arrange the windows in the column from top to bottom in lexicographical order based on their names. .TP .B Split Create a copy of the window containing most recently selected text. .TP .B Undo Undo last textual change or set of changes. .PP A common place to store text for commands is in the tag; in fact .I wily maintains a set of commands appropriate to the state of the window to the left of the bar in the tag. .PP If the text indicated with button 2 is not a recognized built-in, it is executed as a shell command. For example, indicating .B date with button 2 runs .IR date (1). The standard and error outputs of commands are sent to the error window associated with the directory from which the command was run, which will be created if necessary. For example, in a window .B /adm/users executing .B pwd will produce the output .B /adm in a (possibly newly-created) window labeled .BR /adm/+Errors ; in a window containing .B /sys/src/cmd/sam/sam.c executing .B make will run .IR make (1) in .BR /sys/src/cmd/sam , producing output in a window labeled .BR /sys/src/cmd/sam/+Errors . .SS "Mouse button 3 Pointing at text with button 3 instructs .I wily to locate or acquire the file, string, etc. described by the indicated text and its context. This description follows the actions taken when button 3 is released after sweeping out some text. In the description, .I text refers to the text of the original sweep or, if it was null, the result of applying similar expansion rules that apply to button 2 actions. .PP If the text names an existing window, .I wily moves the mouse cursor to the selected text in the body of that window. If the text names an existing file with no associated window, .I wily loads the file into a new window and moves the mouse there. .PP If the text begins with a colon, it is taken to be an address, in the style of .IR sam (1), within the body of the window containing the text. The address is evaluated, the resulting text highlighted, and the mouse moved to it. Thus, in .IR wily , one must type .B :/regexp or .B :127 not just .B /regexp or .BR 127 . (There is an easier way to locate literal text; see below.) .PP If the text is a file name followed by a colon and an address, .I wily loads the file and evaluates the address. For example, clicking button 3 anywhere in the text .B file.c:27 will open .BR file.c , select line 27, and put the mouse at the beginning of the line. The rules about Error files, directories, and so on all combine to make this an efficient way to investigate errors from compilers, etc. .PP If the text is not an address or file, it is taken to be literal text, which is then searched for in the body of the window in which button 3 was clicked. If a match is found, it is selected and the mouse is moved there. Thus, to search for occurrences of a word in a file, just click button 3 on the word. Because of the rule of using the selection as the button 3 action, subsequent clicks will find subsequent occurrences without moving the mouse. .PP In all these actions, the mouse motion is not done if the text is a null string within a non-null selected string in the tag, so that (for example) complex regular expressions may be selected and applied repeatedly to the body by just clicking button 3 over them. .SS "Chords of mouse buttons Several operations are bound to multiple-button actions. After selecting text, with button 1 still down, pressing button 2 executes .B Cut and button 3 executes .BR Paste . After clicking one button, the other undoes the first; thus (while holding down button 1) 2 followed by 3 is a .B Snarf that leaves the file undirtied; 3 followed by 2 is a no-op. These actions also apply to text selected by double-clicking because the double-click expansion is made when the second click starts, not when it ends. .PP Commands may be given extra arguments by a mouse chord with buttons 2 and 1. While holding down button 2 on text to be executed as a command, clicking button 1 appends the text last pointed to by button 1 as a distinct final argument. For example, to search for literal .B text one may execute .B Look text with button 2 or instead point at .B text with button 1 in any window, release button 1, then execute .BR Look , clicking button 1 while 2 is held down. .PP When an external command (e.g. .IR echo (1)) is executed this way, the extra argument is passed as expected and an environment variable .B $wilyaddr is created that holds, in the form interpreted by button 3, the fully-qualified address of the extra argument. .SS "Support programs .I Win creates a new .I wily window and runs a .I command (default .BR $SHELL ) in it, turning the window into something analogous to an .IR 8½ (1) window. Executing text in a .I win window with button 2 is similar to using .BR Send . .PP .I Awd loads the tag line of its window with the directory in which it's running, suffixed .BI - label (default .BR rc ); it is intended to be executed by a .B cd function for use in .I win windows. An example definition is .EX fn cd { builtin cd $1 && awd $sysname } .EE .SH FILES .TF $home/.wilybak .TP .B $home/.wilybak default directory for backup files. .SH SEE ALSO .IR wily (4) .br Rob Pike, .I Acme: A User Interface for Programmers. .SH BUGS ayout box grows the window in place: button 1 grows it a little, button 2 grows it as much as it can, still leaving all other tags in thatwily-0.13.42/Doc/old/user.sgml����������������������������������������������������������������������0000644�0236657�0000012�00000043052�10333201523�0015625�0����������������������������������������������������������������������������������������������������ustar�00oz������������������������������staff���������������������������0000433�0000002������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!doctype linuxdoc system> <article> <title>Wily User Manual <author><htmlurl url="http://www.cs.su.oz.au/~gary/" name="Gary Capell"> <date>v0.12.7 June 1996 <abstract> Use the <em/left/ mouse button to <em/select/ text, use the <em/middle/ mouse button to <em/execute/ text, and use the <em/right/ mouse button to <em/goto/ text. Use a left/middle mouse button combination to <em/cut/ text, use a left/right mouse button combination to <em/paste/ text, and use a middle/left mouse button combination to <em/execute/ text with an <em/argument/. The <em/resize box/ indicates if a file is dirty, and can be clicked or dragged with various mouse buttons to resize and reposition windows. <htmlurl url="user.ps" name="A Postscript version of this file is available"> </abstract> <toc> <sect>Invocation, Environment variables <P><tt/wily [-d] [-v] [-f font] [-F fixedfont] [-t tabsize][file name...]/ <descrip> <tag/-d/ Enable debugging output <tag/-v/ Print version number and exit <tag/-f font/ (or X resource <tt/p9font/) set the default proportional font. <tag/-F font/ (or X resource <tt/p9fixed/) set the monospace font. <tag/-t tabsize/ set the maximum width of tabs (as multiple of the width of the character '0') for the proportional font. Defaults to 4. <tag/-T tabsize/ set the maximum width of tabs (as multiple of the width of the character '0') for the monospace font. Defaults to 8. <tag/file name.../ Start wily with the named files and directories open. </descrip> <sect1>Environment variables<P> <descrip> <tag/SHELL/ External commands are sent to the shell for evaluation. <tag/HISTORY/ If set, commands are written to this file before execution. <tag/WILYBAK/ Wily uses <tt/$WILYBAK/ or <tt>$HOME/.wilybak</tt> as the directory for backups. <tag/WILYFIFO, DISPLAY, TMPDIR/ Wily communicates with some other programs using a fifo at a well-known location. <P>The name of the fifo will be <tt/$WILYFIFO/ if this variable is set, otherwise it will be <tt>/tmp/wilyUSER$DISPLAY</tt>, where USER is calculated from the password file. If <tt/$TMPDIR/ is defined, it is used instead of <tt>/tmp</tt>. <P>Wily also sets <tt/$WILYFIFO/ so any children it creates will know how to talk to it. </descrip> <sect>Appearance<P> foo <sect1>Scrollbars and scrolling<P> Scrollbars are proportional, i.e. the size and position of the scrollbar's "thumb" indicates the size and position of the visible portion of the text. Each of the three mouse buttons does something different when clicked in the scrollbar. The <em/right/ mouse button moves the text next to the mouse pointer <em/up/ to the top of the window. The <em/left/ mouse button moves the text at the top of the window <em/down/ so it is next to the pointer. Both of these rules have the effect that clicking near the top of the scrollbar causes small movements, and clicking near the bottom causes large movements. The <em/middle/ button moves the visible part of the text to a point in the text proportional to how far down the scrollbar the pointer is. That is, clicking at the bottom of the scrollbar with button 2 jumps to the end of the text, clicking at the top of the scrollbar with button 2 jumps to the beginning of the text. All of these movements repeat if the mouse button is held down in the scroll bar. The <em/PageUp/ and <em/PageDown/ keys scroll up or down by about half a page. The <em/Home/ and <em/End/ keys scroll to the top or bottom of the file. <sect1>Context<P> All text in wily has a <em/context/, which is just the name of a directory associated with that text. For text in a window, the context is the name of the window, up to and including the last <TT>/</TT>. So if three windows have the names <TT>/usr/gary/+Errors</TT>, <TT>/usr/gary/guide</TT> and <TT>/usr/gary/</TT>, they will all have the same context: <TT>/usr/gary/</TT>. Note that the context need not be a directory which actually exists. For column tags and the top-level tag, the context is the name of the directory where wily was started. When text is <EM/executed/, wily uses the context of the text as the directory in which to run the program. Output from the command will appear in the window <tt>{context}/+Errors</tt>. When trying to <em/Goto/ some text, the text will be interpreted relative to its context. For example, the text <tt>foo.c:14</tt> in a window with context <tt>/usr/gary/src/fish/</tt> will be interpreted to mean the address <tt>/usr/gary/src/fish/foo.c:14</tt> <sect>Mouse actions<P> <sect1>Double-click<P> Double-clicking with the left mouse button can select a word, a line, or the text delimited by quotation marks, braces, brackets or parentheses. <sect1>Selection expansion<P> A null selection (single click) with the middle or right mouse button will be expanded to some of the surrounding text. A click inside an existing selection will be expanded to that selection. This means you can select (with the left button) some complicated command once, and click the middle button inside this selection many times to execute the command repeatedly. This rule is also helpful when searching through multiple occurrences of a piece of text, as clicking with the right button in the most recently found instance searches for the next instance. A click that is not inside an existing selection will be expanded depending on which mouse button was used. Clicks with the middle button are expanded to select commands, i.e. strings of alphanumeric characters, |, > or <. Clicks with the right button are expanded to select addresses, i.e. strings of alphanumeric characters, :, ",". <sect1>Combinations of Mouse Buttons (mouse chords)<P> Pressing more than one mouse button at a time is called a mouse chord, and can be used for some special short cuts. <sect1>Cut,Paste mouse chords<P> To cut some text into the clipboard, select the text with the left button, and <em>while holding it down</em>, click the middle button. The selected text will be cut from the window and copied to the clipboard. Similarly, select some text with the left mouse button, and while holding it down also click the right button, and the selected text will be replaced by the contents of the clipboard. The clipboard will be unaltered. Note that so long as you hold the left button down, you can alternately cut and paste the selected text by pressing the middle and right buttons. A cut immediately followed by a paste in this way leaves the file unmodified. <sect1>Execute with argument<P> A command can be called with an argument using another mouse chord. Sweep the command with the middle button, and while holding it down, click the left button. The command is invoked with the text most recently selected with the left button as argument. For example, one might select <tt>main.c</tt> with the left button, then chord the middle and left buttons on the word <tt>wc</tt> to run <tt>wc main.c</tt>. When an argument is selected in this manner, the context of the argument becomes the context of the command. One idiom is to select some text in one window, and <tt>Look</tt> for it in another window using this chord. <sect>Execute<P> If text is selected with the middle mouse button, it is executed. If you press the middle button in some text, then decide you <em/don't/ want to execute it, press the right mouse button to abort. If the text is the name of one of the builtin functions, that function will be executed. If the text begins with |, > or <, the most recent selection will be piped through the command, piped to the command, or replaced by the output of the command, respectively. The command is executed by <tt>$SHELL -c command [argument]</tt>. If <tt>$SHELL</tt> is not defined, <tt>/bin/sh</tt> is used. Standard output from the command will appear in a window in wily. Standard input for the command will be from <tt>/dev/null</tt>. The main wily tag indicates which programs are currently running. Wily tends to be more useful if <TT>.</TT> is in <tt>$PATH</tt> <sect1>Builtin Functions<P> These commands are looked for first. Some of them operate differently if called with an argument (using the Middle/Left mouse chord). <descrip> <tag>Put,Get,Putall</tag> Put and Get write the window to disk, or fetch from disk, respectively. If called with an argument, they will use the argument this as the filename, instead of the name of the window. Putall writes all dirty files to disk. <tag>New, Del</tag> Create a new window, or delete a window, respectively. If New is called with an argument, it will use the argument as the name of a file to create. <tag>Look</tag> Searches in the window containing Look for literal text: either the argument, if it is given one, or the current selection in the window containing Look <tag>Undo, Redo</tag> Undo or redo an action. With an argument, undo(redo) until the window reflects the state of the file on disk. <tag>Newcol, Delcol</tag> Create or delete a column <tag>Cut, Paste, Snarf</tag> Cut the currently selected text to the X selection buffer, replace the currently selected text with the X selection buffer, or copy the currently selected text to the X selection buffer, respectively. The <em/currently selected text/ is defined as the selection in the most recently selected window. This should be indicated by that window having a slightly thicker border. <tag>Quit</tag> Exit wily. Any dirty files will be backed up. <tag>Kill</tag> Kill some process which was started from wily. Kill must be given as an argument the name of the process to kill. The topmost tag always contains the list of long-running programs started from within wily. To kill one of these, click in the name of the process in the tag, then do a middle/left mouse chord in 'Kill'. <tag>Font</tag> Toggle between fixed and proportional fonts. Depending on where Font is clicked, changes the font for a window, a column, or for all the windows on the screen. <tag>Dotfiles</tag> Toggles whether or not dot files are displayed in directories. Directories will not be re-read automatically, though. <tag>Anchor</tag> Puts an address in the tag of the most recently selected window. The address is from the current position to '.'. This can be used to select large chunks of text. Click at the beginning position, execute Anchor, click at the end position, then click with the right mouse button in the address in the tag. The anchor may also be used as a bookmark. <tag>Split</tag> Split the most recently selected window into two. Editing actions in one window will be visible in the other. </descrip> <sect>Goto Text<P> Wily will attempt to <em/goto/ text selected with the right mouse button. What this means depends on the text selected. <P>The <em/goto/ operation used with B3 is polymorphic in that it recognises three different patterns: <DESCRIP> <tag/name/ If <TT/name/ is a file or directory, open it, otherwise search for the literal <TT/name/ <tag/:address/ Search for <TT/address/ in the current window, where the form of an address is defined below. <tag/file:address/ Open <TT/file/ and search in it for <TT/address/ </DESCRIP> <sect1>Addresses<P> Wily uses the address and regular expression code from <htmlurl url="http://plan9.bell-labs.com/plan9/doc/sam.html" name="Sam">. Please refer to the <htmlurl url="http://plan9.bell-labs.com/magic/man2html/1/sam" name="Sam manual"> for a better explanation. The following description was cut and pasted from the <htmlurl url="http://plan9.bell-labs.com/magic/man2html/1/sam" name="Sam manual"> <sect2>Simple Addresses<P> <descrip > <tag/#n/ The empty string after character n; #0 is the beginning of the file. <tag/n/ Line n; 0 is the beginning of the file. <tag>/regexp/ ?regexp? </tag> The substring that matches the regular expression, found by looking toward the end (/) or beginning (?) of the file, and if necessary continuing the search from the other end to the starting point of the search. The matched substring may straddle the starting point. When entering a pattern containing a literal question mark for a backward search, the question mark should be specified as a member of a class. <tag/$/ The null string at the end of the file. <tag/./ Dot. The current selection in a window. </descrip> <sect2>Compound Addresses<P> In the following, a1 and a2 are addresses. <descrip > <tag/ a1+a2 / The address a2 evaluated starting at the end of a1. <tag/a1-a2 / The address a2 evaluated looking in the reverse direction starting at the beginning of a1. <tag/a1,a2/ The substring from the beginning of a1 to the end of a2. If a1 is missing, 0 is substituted. If a2 is missing, $ is substituted. <tag/a1;a2 / Like a1,a2 but with a2 evaluated at the end of, and dot set to, a1. </descrip> The operators + and - are high precedence, while , and ; are low precedence. In both + and - forms, if a2 is a line or character address with a missing number, the number defaults to 1. If a1 is missing, . is substituted. If both a1 and a2 are present and distinguishable, + may be elided. a2 may be a regular expression; if it is delimited by ?'s, the effect of the + or - is reversed. It is an error for a compound address to represent a malformed substring. Some useful idioms: a1+- %(a1-+) selects the line containing the end (beginning) of a1. 0/regexp/ locates the first match of the expression in the file. (The form 0;// sets dot unnecessarily.) ./regexp/// finds the second following occurrence of the expression, and .,/regexp/ extends dot. <sect1>Cursor Warping<P> After a successful search, the text that was found is highlighted, and the cursor is warped there, so that to search for the next instance of the search text, no cursor movement is required, it is only necessary to click the rightmost mouse button again. Window re-arranging operations warp the cursor to the resize box of the window that moved, so the move can be easily refined. <sect>Miscellaneous<P> <sect1>Window Reshaping<P> Wily windows are placed automatically using heuristics. Hopefully most of the time the window will be placed somewhere useful. However, windows and columns can be moved and reshaped. The resize box (the little box on the far left of the tag) of a pane or a column may be manipulated to move or reshape a window. Dragging the resize box (with any mouse button) moves the column or window to the desired location. Clicking in a pane's button with different mouse buttons has these different effects: <descrip > <tag/Left button/ the window grows a bit, first taking up any blank space in the column <tag/Middle button/ Every window except the desired one is shrunk so that only their tags are visible, leaving more space for the desired window. <tag/Right button/ The window expands to take up the whole column, obscuring all the other windows in that column. Clicking with any mouse button in the window's resize box will undo this effect. </descrip> <sect1>Back-up files<P> Whenever a window is to be deleted which represents a file and which contains text which hasn't been written to disk, a backup is made. This is an experimental alternative to the familiar (and often-annoying) "are you <em/sure/ you want to close this window?" dialog. A warning message is printed when this happens, alerting the user, and allowing her to easily recover the modified file, or compare the old and new files. This seems not only quicker but safer than forcing a dialog, as occasionally the user might give the wrong answer to a dialog, whereas with this system a backup is always there. Backup files are kept in directory <tt>$WILYBAK</tt> if it exists, or <tt>$HOME/.wilybak</tt>. In this directory the file <tt>TOC</tt> is a table of contents showing what real file each backup file maps to. <sect1>Remote Control<P> A programming interface is provided to wily, for writing more complex programs such as mailers, news readers, terminals, code browsers, etc. See the <htmlurl url="msg.html" name="Wily Message Interface guide"> for more details. <sect1>Fonts<P> (Taken from font(4)) External fonts are described by a plain text file that can be read using <em/rdfontfile/. The format of the file is a header followed by any number of subfont range specifications. The header contains two numbers: the height and the ascent. The height is the inter-line spacing and the ascent is the distance from the top of the line to the baseline. These numbers are chosen to display consistently all the subfonts of the font. A subfont range specification contains two numbers and a font name. The numbers are the inclusive range of characters covered by the subfont, and name specifies the name of an X font suitable for <em/getsubfont/. The minimum number of a covered range is mapped to the first defined character of the corresponding subfont. Each field must be followed by some white space. Each numeric field may be C-format decimal, octal, or hexadecimal. Here is the start of the font file the author uses for a monospace font: <tscreen><verb> 17 14 0x0000 0x00FF lucm.latin1.9 0x0100 0x017E lucm.latineur.9 0x0180 0x01F0 matty.latinext.9 0x0250 0x02E9 lucm.ipa.9 0x0300 0x0308 matty.gendiacritics.9 0x0370 0x0372 matty.greekpunc.9 0x0386 0x03F5 lucm.greek.9 0x0400 0x0475 misc.cyrillic.9 </verb></tscreen> <sect1>Entering non-ASCII characters<P> Refer to the Plan 9 <htmlurl url="http://plan9.bell-labs.com/magic/man2html/6/keyboard" name="keyboard(6)"> manual page, which is <em/mostly/ how it works in wily. </article> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������wily-0.13.42/Doc/old/msg.sgml�����������������������������������������������������������������������0000644�0236657�0000012�00000025065�10333201523�0015441�0����������������������������������������������������������������������������������������������������ustar�00oz������������������������������staff���������������������������0000433�0000002������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!doctype linuxdoc system> <article> <title>Wily Messaging Interface <author><htmlurl url="http://www.cs.su.oz.au/~gary/" name="Gary Capell"> <date>v0.11.0 April 1996 <abstract> This document explains <htmlurl url="http://www.cs.su.oz.au/~gary/wily/msg.h" name="msg.h"> There are five sections. The first two describe the Msg struct and the list of message types, with a brief explanation of each. The last three detail functions to establish a connection to wily; to pack and unpack messages for sending to the network; and to access a "cooked" RPC-style interface. A <htmlurl url="msg.ps" name="Postscript version"> is available. </abstract> <toc> <sect>The Msg Struct<P> This is the "in-memory" representation of the messages which flow between Wily and remote programs. The representation of messages as they flow across the network is deliberately hidden. <tscreen><verb> struct Msg { Mtype t; Id m; /* message */ Id w; /* window */ Range r; uchar flag; char *s; }; </verb></tscreen> <P><tt/s/ is a null-terminated UTF string, and must be a complete UTF sequence. <P><tt/t/ identifies the type of the message. The possible values of <tt/t/ are enumerated in the next section. <P><tt/m/ identifies the message within a sequence of messages. <P><tt/w/ identifies a particular window. <P><tt/r/ specifies a contiguous set of runes within a window. The range <tt/r.p0, r.p1/ means all the characters with offset not less than <tt/r.p0/, and strictly less than <tt/r.p1/ <P><tt/flag/ is used to modify the meaning of some types of message, and can be used to hold a true/false value, or a bit mask. <P>The client sends request messages to Wily. For every request message, Wily sends back either a reply message (if the request was fulfilled successfully) or an error message. In either case, the message sent in response will have the same message id (<tt/m.m/) as the request message. Each reply message has a <tt/Mtype/ value one greater than the corresponding request message. <P>Wily may also send event messages to the client, if the client has asked for them. <sect>The Mtype enum <P>For each of the message types defined, there is a brief description, and an indication of which fields of the <tt/Msg/ struct are significant for this type of message. <P>The names of request messages start with <tt/WM/, those of response messages with <tt/WR/, and those of events with <tt/WE/ <sect1>Requests/Responses <P><descrip> <tag/WRerror(s)/ Message type returned by wily if there's an error in decoding or fulfilling some request. <tt/s/ contains an error message. <tag/WMlist/ Asks wily to send a list of windows currently displayed. <tag/WRlist(s)/ <tt/s/ contains a list of lines terminated by newlines. Each line contains a name and an id (as a textual number) separated by whitespace. <tag/WMnew(s,flag), WRnew(w)/ Asks wily to create a window with a given label (which may be an existing file). The new window will be treated as a normal file, with backups kept for it, If and only if <tt/flag/ is set. <P><tt/w/ is set to the id of the newly created window. <tag/WMattach(w,flag), WRattach/ Set the event mask for <tt/w/ to <tt/flag/. Used to start or stop the flow of events for a particular window. See the <em/Events/ section for details on what values the <tt/mask/ can have. <tag/WMsetname(w,s), WRsetname/ Change <tt/w/'s name to <tt/s/. <tag/WMsettools(w,s), WRsettools/ Change the tools for this window. Tools are simply words appearing in the tag of a window, after the window name and before the 'pipe' symbol. They are (will be) automatically maintained, i.e. they will be replaced if accidentally deleted. <tag/WMread(w,r),WRread(s)/ Read the text from <tt/w/ in range <tt/r/. <P><tt/s/ is the requested text, as a UTF string. <tag/WMreplace(w,r,s), WRreplace/ Replace the text from <tt/w/ in range <tt/r/ with UTF string <tt/s/ <tag/WMexec(w,s),WRexec/ Act as if <tt/s/ had been clicked with B2 in <tt/w/. Note that this can be used to access Wily's built in functions. <tag/WMgoto(w,r,flag,s), WRgoto(w,r)/ Act as if <tt/s/ had been clicked with b3 in <tt/w/ at <tt/r/, possibly opening a file or directory, or searching for some combination of line address, character address or regular expression. If and only if <tt/flag/ is set do we select the range found, and set "dot". In either case, we return the window and text range to which we would have jumped. <P>This request will return an error if it tries to search for something which isn't there. <P>The response message contains the window and range we went to. <tag/WMfencepost/ Not used for any message. Receiving a message with Mtype greater than <tt/WMfencepost/ indicates some horrible error. </descrip> <sect1>Events <P>These are the messages sent by Wily to clients who request to be notified of events in a particular window using <tt/WMattach/ <P>The event types are used to form a mask to be given as a parameter to the <tt/WMattach/ request. For example, to request only exec and goto events, set <tt>m.f = WEexec|WEgoto</tt> before sending message <tt/m/ <descrip> <tag/WEexec(w,s)/ <tt/s/ was selected with B2 somewhere in <tt/w/ <tag/WEgoto(w,r,s)/ <tt/s/ was selected with B3 at <tt/r/ in <tt/w/ <tag/WEdestroy(w)/ <tt/w/ has been destroyed. <tag/WEreplace(w,r,s)/ The text at <tt/r/ in <tt/w/ was replaced by <tt/s/ Note that insertion. and deletion are simply special cases of replacement . <tag/WEfencepost/ Never actually used. Any message with <tt/Mtype/ greater than <tt/WEfencepost/ is a request or response. Any message with <tt/Mtype/ less than <tt/WEfencepost/ is an event. </descrip> <P>If a client is sent an event which it doesn't want to use, it can send the event back to wily. Wily will act on the event, but not send a confirmation back to the client. <sect>Establishing a Connection <P>Simply call <tt/client_connect()/, which returns a file descriptor open for reading and writing to Wily, or a negative number if there's been some error. <P>Wily and client programs both use the environment variable <tt/$WILYFIFO/ to establish communications, and Wily sets this variable for any children it creates. <sect>Packing and Unpacking Messages<P> <descrip> <tag/int msg_size (Msg *m);/ Returns the size of buffer that will be needed to "flatten" <tt/m/ <tag/void msg_flatten (Msg*m, char*buf);/ "Flatten" <tt/m/ into <tt/buf/, which must have enough storage space allocated. <tag/ulong msg_bufsize (char*buf);/ Returns the total size of the flattened message starting at <tt/buf/. Assumes that at least <tt/HSIZE/ bytes are stored in <tt/buf/. <P>A useful macro is <verb> #define FULLMSG(ptr,n) ( (n) >= HSIZE && (n) >= msg_bufsize(ptr) ) </verb> <tag/int msg_init (Msg*m, char*buf);/ The reverse of <tt/msg_flatten/. Fills in the fields of 'm' using the flat representation starting at <tt/buf/ <tt/Msg_init/ assumes that <tt/buf/ holds the complete message. <tt/m->s/ will point to an area within <tt/buf/, but <tt/buf/ itself is not modified. <tag/void msg_print (Msg *m);/ Print a human-readable form of <tt/m/ to <tt/stderr/ </descrip> <sect>RPC-style interface <P>These functions aren't necessary to interact with Wily. However, they are convenient, and provide some type-checking to help make sure you send the right messages. <sect1>Opening, Closing and Checking the RPC interface <P><descrip> <tag>Handle* rpc_init (int fd);</tag> Create a new RPC handle to use file descriptor <tt/fd/, which was probably returned from <tt/client_connect/ <tag>Bool rpc_isconnected(Handle*h);</tag> Indicate whether or not <tt/h/ is still connected. <P>If the RPC library starts receiving gibberish messages, it will cut the connection, and will return a "not connected" error message for every request. <tag>void rpc_free(Handle*h);</tag> Release any resources used by <tt/h/, and free <tt/h/ itself. </descrip> <sect1>Requests <P>If there's any sort of failure, all of these functions return a pointer to an error message, which is stored in a static buffer and only guaranteed to remain valid until the next <tt/rpc_*/ function is called. After a failure, it's possible that the connection to wily has been lost. This should be checked using <tt/rpc_isconnected/ <P>If successful, these functions return NULL. <descrip> <tag>char* rpc_list (Handle*h, char **bufptr);</tag> If successful, allocates a string, stores the window list in the string, and stores a pointer to the string in <tt/bufptr/. Don't forget to <tt/free(*bufptr)/ when you're finished. <tag>char* rpc_new (Handle*h, char *s, Id*id);</tag> Create window with name <tt/s/, setting <tt/id/ if successful. <tag>char* rpc_attach (Handle*h, Id w, ushort mask);</tag> Request events associated with <tt/w/ and matching event <tt/mask/. This will fail if <tt/w/ doesn't exist, or is already sending its events somewhere else. <tag>char* rpc_detach (Handle*h, Id w);</tag> Cancel request for events associated with <tt/w/ <tag>char* rpc_setname (Handle*h, Id w, char *s);</tag> Set the name of <tt/w/ to <tt/s/ <tag>char* rpc_settools (Handle*h, Id w, char *);</tag> Set the tools section of <tt/w/ to <tt/s/ <tag>char* rpc_read (Handle*h, Id w, Range r, char*buf);</tag> Read range <tt/r/ from <tt/w/ into <tt/buf/, which must have enough space (<tt/UTFmax * RLEN(r)/). Fails if <tt/r/ is not contained in window <tt/w/ <tag>char* rpc_replace (Handle*h, Id w, Range r, char*s);</tag> Replace range <tt/r/ in <tt/w/ with UTF string <tt/s/ <tag>char* rpc_exec (Handle*h, Id w , char *s);</tag> Cause Wily to act as though <tt/s/ were selected in <tt/w/ with button 2. <tag>char* rpc_goto (Handle*h, Id *w , Range *r, char*s, Bool setdot);</tag> Make Wily act as though <tt/s/ were selected in <tt/w/ with button 3. <P>Sets <tt/*w/ and <tt/*r/ with the window and range found by the search operation. Actually jumps to and selects some text if and only if <tt/setdot/ is true. This request will return an error if it tries to search for something which isn't there. </descrip> <sect1>Events<P> <descrip> <tag>int rpc_event (Handle*h, Msg *m);</tag> Block until an event is received by <tt/h/ and fill in <tt/m/. Returns 0 for success, -1 for failure. After a successful call to <tt/rpc_event/, <tt/m->s/ will need to be freed. <tag>char *rpc_bounce(Handle *h, Msg *m)</tag> Returns <tt/m/, which must be an event filled in by <tt/rpc_event/, back to wily, and frees <tt/m->s/. Useful for events which we receive but we'd rather wily took the default action on. <tag>Bool rpc_wouldblock(Handle*h);</tag> Returns <tt/true/ if <tt/rpc_event/ would block. Only useful if your program is reading from other input sources as well. (e.g. see <tt/win.c/) </descrip> </article> equence. <P><tt/t/ identifies the type of the message. The possible values of <tt/t/ are enumerated in the next section. <P><tt/m/ identifies the message within a sequence of messages. <P><tt/w/ identifies a particular window. <P><tt/r/ specifies a contiguous set of runes within a window. The range <tt/r.p0, r.p1/ means all the characters with offset not less than <tt/r.p0/, and strictly less than <tt/r.p1/ <P><tt/flag/ is used to modify the meaning ofwily-0.13.42/Doc/old/wily.html����������������������������������������������������������������������0000644�0236657�0000012�00000046445�10333201523�0015646�0����������������������������������������������������������������������������������������������������ustar�00oz������������������������������staff���������������������������0000433�0000002������������������������������������������������������������������������������������������������������������������������������������������������������������������������<HTML><HEAD> <TITLE>Wily

    Wily

    Silly Cartoon
    Gary Capell

    This document


    Appearance, Unicode - Mouse Actions - Example - Extensions - Implementation - Availability - History -

    Other documents

    Note for Sydney-ites

    I'd be keen to demonstrate/explain Wily for interested folks in Sydney

    Abstract:

    Wily is an emulation for the Unix/X environment of Acme [Pike95] from Plan 9. It combines most of the features of text editor, window manager, file manager and general user interface. It exploits a three-button mouse and bitmapped display to provide a smooth, simple and powerful environment for interacting with text of all kinds.

    Wily differs from most other editors in a number of areas. Nearly all operations are through mouse actions on text on the screen: there are no menus, few "key bindings" and no "function keys". Text is usually displayed in a proportionally-spaced font, and is interpreted as UTF8-encoded Unicode. Mouse "chords" (combinations of mouse buttons) are used extensively. Wily's core functionality is almost totally unconfigurable. However, it is quite simple to extend Wily using other programs, written in any language, both for simple text-manipulation tasks, and to use Wily as a front-end for other programs such as mail or news readers, or terminals.

    It is possible (and intended) to "live" in wily as with other, more complicated editors.

    The learning curve is steep, but short. Once learnt, the interface is sufficiently addictive that the author re-implemented Acme to work under Unix, rather than coping with other editors. Wily and Acme have a small but growing number of addicts.

    Appearance

    Wily appears as one or more vertical columns, divided into windows of scrolling text. Each column or window is headed by a thin horizontal tag. The leftmost text of the tag is the name of the file or directory the window represents. Other text in the tag are some words useful as commands.

    The small square-ish box to the left of the tag is called the resize box. If the resize box is filled, this indicates that the text in the associated window has been modified since it was last read from or written to disk.

    The text in the body of the window may represent a directory, a file, the interface to some program like a news reader, or the output from some program like make.

    Proportionally spaced, Unicode text

    Text is displayed in a propotionally spaced font by default. There is a built in function to toggle with a monospace font (seen in the bottom-left window in the example pictured), but there are very few occasions when this is necessary or desirable. In most cases limiting a text editor to monospace fonts is blindly following the hardware limitations of the 1960s.

    Text is read and written as UTF8-encoded Unicode, providing some support for editing multi-lingual and scientific text, but remaining backwardly compatible with plain 7-bit ASCII text. See 9term for an example of another program with Unicode support, with some screen shots.

    Basic Mouse Actions

    Any text on the screen can be selected by dragging with a mouse button. Briefly, the left, middle and right mouse buttons are used to select, execute or goto text. In more detail:
    Left button
    highlights the text for later actions
    Middle button
    executes the text as a command, e.g. selecting the word 'make' will run the make command as if it were typed to the shell. There is a small set of built-in functions (e.g. Undo, Redo, ) that are searched for first. Wily arranges for text representing these functions to be on the screen when and where appropriate, although they can always be typed anywhere anytime. Output from programs is captured and displayed in windows in Wily.
    Right button
    attempts to goto the selected text. What this means depends on the text selected, but may involve opening a file or directory, or searching for a line number, regular expression or literal text.

    Wily tries to parse the selected text as filename:address, where address may be a line number or /regexp.

    Either or both of the filename and the :address may be recognized.

    If Wily cannot recognise any of these forms, it searches for the next occurrence of the selected text in the current window.

    Panes and columns can be moved and reshaped by clicking or dragging in the resize box to the left of their tags.

    There are no menus, and few special keys (page up, page down, arrow keys, Home, End, kill word, kill line, select recently typed text). All functions are accessed through mouse actions on text.

    A short example

    Sally has been using wily to develop a program called wily.
    • She clicks the middle mouse button in the word make somewhere in the tag of the window for her source directory, /src/wily/. Clicking the middle mouse button in some text tells wily to execute that text. In this case wily runs make in another process. The output and errors from this process will appear in a window labelled /src/wily/+Errors. (The window will be created if necessary). Unfortunately there is an error: the output includes the line builtins.c:78: parse error before `)'.
    • She clicks the right mouse button anywhere in the text builtins.c:78:. Clicking in some text with the rightmost mouse button tells wily to goto that text. A new window labelled /src/wily/builtins.c is created if necessary, with line 78 centred and highlighted, and the cursor warps to this line. Sally sees that the last ) on that line is unnecessary.
    • She selects it with the left mouse button, and while holding this button down, also clicks the middle mouse button to cut out the offending parenthesis. Cutting and pasting text in wily can be done with combinations of mouse keys. This is very quick and easy. The resize box of the window is filled in, to indicate that the file has been modified.
    • She clicks the middle mouse button in the word "Put" in the window's tag. Wily recognizes this as the name of the builtin function to write the file to disk, and does so. The resize box is cleared, to indicate that the file is "clean".
    • She clicks the middle mouse button in the word make, and the cycle begins again.

    This whole interaction requires six mouse clicks and much less time than the time to read about it.

    Combinations of mouse buttons

    The system does some things so that the user doesn't need to place the mouse accurately. Double-clicking with the left mouse button selects a word, a line or a piece of text delimited by quotes, braces or brackets. With the middle or right button, a click inside a selection will be expanded to that selection, or a click inside a word that can be recognised as a command or address will be expanded to that word.

    Simultaneous combinations of mouse buttons (Mouse chords) are used for cutting and pasting. To move some text from one place to another, it first is selected by dragging with the left mouse button. While holding this button down, if the middle button is also pressed, the text is cut. The text can later be pasted into place by holding the left button and then clicking the right button. This action is easier done than said, and is much quicker than searching for a menu entry.

    A mouse chord is also used as a short-hand for the idiom of executing a command with some argument. While clicking with the middle button in the command, if the leftbutton is then pressed, the most recently selected text is given as an argument to the command. For example, one could point to a program variable, click the middle and left buttons on the name of some simple program, and get a list showing all the places that variable occurs. Clicking with the right button on any of the occurrences on that list will open the relevant file at the correct line.

    The mouse cursor is often warped to where the program predicts the next action is likely to take place. For example, after opening a file at a particular address, the cursor is warped to that position of that file.

    The escape key selects any text typed since the last cursor movement, making it easier to select with the mouse.

    Undo/Redo

    Wily provides a full Undo/Redo history for each window.

    Window Positioning

    Newly created windows are placed by the program, not the user. While it is possible for the user to reposition or resize the window after it is created, window-positioning heuristics generally make such positioning unnecessary.

    Extensions

    Wily has no extension language, but is easy to connect to other UNIX programs.

    Program output is useful

    The output (both stdout and stderr) of any commands run from wily will appear in a wily window, where it may be useful. For example, the author uses the shell functions sg and def. sg (short for source grep) is defined as fn sg {agrep -w -n $* *.[ch]}, def as fn def {grep -n '^'^$1 *.c /dev/null}. To find the definition of some C function, the author clicks with the left button in the name of the function, and does a middle-left button combination on the word def. The output from def will appear in a wily window, and be something like /usr/gary/src/dir/file.c:243 function(int arg, char* otherarg). Clicking here with the right mouse button will then open the file if necessary, and move to and highlight the correct line. The function sg operates similarly, listing all occurrences of some identifier. Note that it would be simple to modify these functions to operate with other languages (HTML, Java, ...) and that they could be written in any language the user chooses.

    Filter programs

    Commands beginning with |, > or < operate on the most recent selection. They either pipe it through a command, send it to a command, or replace it with the output of a command. For example, to reformat a paragraph, select it (using the left button), then click anywhere in the text |fmt. fmt will be executed, with its input taken from the current selection, and its output replacing the current selection.

    Programs may also be used to filter text in wily windows. If a command starts with the pipe symbol |, it uses the most recently selected wily text as input and output. Indenting, formatting, html tagging can all be done using standard Unix tools, or tools written by the user in any language. Simply select some text, and click with the middle mouse button in |cmd. For example, here is the author's file lib/html/guide:

    |title |h1 |h2 |h3 |h4
    |italic |emph |strong |bold |code |href prog.html |name remote
    |fmt >spell |blanks2P
    

    Wily as a front-end

    Longer-running processes may instead open a socket to wily, which can be used to send requests or receive events. One example of this is the program win, which provides a simple terminal within Wily. (For details refer to [Cap95a])

    Python and Perl bindings for this message interface are available.

    Mail and news readers or code browsers should be fairly simple to write using Wily as their front end. All of these programs would operate in a familiar fashion (left mouse button selects, middle button executes, right button does a "goto").

    No confirmations

    When you close a file that wily knows contains changes, it doesn't bother you with a confirmation dialog, but does a backup of the file and prints a warning message in case you've made a mistake. This is quicker in the common case that you do want to discard the changes, is simple to recover from if you have made a mistake, and eliminates the mistake of confirming a deletion that shouldn't have been confirmed.

    The Implementation

    Wily is a single-threaded event-driven server process. The events it waits for are keyboard and mouse actions, and output arriving on sockets shared with child processes. Text display is handled by text widgets.

    Child Processes

    To execute a command that isn't built in, the wily server forks a child, which modifies its execution environment, and execs the required command.

    The child sets its current directory to the directory the command was invoked from. The child's file descriptors are set so that stdin is redirected from /dev/null, and stdout and stderr are redirected to a file descriptor the server listens to for output.

    The parent adds the file descriptors passed to the child to a list of file descriptors that it monitors for output, and remembers which directory that stream is associated with, so that output will appear in an appropriate window.

    More sophisticated client processes can open a socket to wily and send (and receive messages). The idea here is that wily provides the "look and feel" of the user interface, with various client programs providing different data (mail, news, debugger...),

    Code bloat (not!)

    Wily's source code (excluding some libraries from Bell Labs) takes 7600 lines of code, or 3100 counting only lines with semicolons. The binary (ELF 32-bit MSB executable SPARC Version 1, dynamically linked, stripped) is 150k (c.f. 234k for vi, 2044k for xemacs). Wily typically takes less memory to run than Xterm.

    Strengths, Weaknesses and Further Work

    The things the author misses most when using another editor are: mouse chording for cut and paste (alternatives seem very awkward), opening a file to a particular line with a single mouse click, and editing in a proportional font.

    Some of wily's strengths may also be seen as weaknesses: heavy exploitation of bitmapped terminal and three button mouse mean wily is unusable on glass and paper teletypes. The terse mouse command language is opaque and even intimidating for new users.

    The author is very interested in cooperating with any HCI researchers interested in comparing the usability and/or ease of learning of this editor with more traditional ones, or in comparing mouse-based and keyboard-based editors.

    Wily is not as robust or efficient as the author would like.

    Availability

    Wily source code and documentation (263k) and some binaries are available via FTP from sites in Australia, Israel, the UK and the US.

    The author welcomes comments and suggestions.

    There is a mailing list for discussion about wily and announcements of new releases. Mail wilyfans-request@jli.com to subscribe. The list is archived.

    Wily runs on BSDi, AIX, OSF, HP-UX, IRIX, Linux, Solaris, SunOS4, (these are the OSs the author knows of to date). With any luck, gunzip, tar, configure, make install should get you going.

    History

    Wily is a reimplementation of Acme [Pike95] for the Unix/X environment. Acme itself was heavily inspired by the Oberon [Wirt89] user interface. A port was not possible because the Acme implementation relies on Alef [Win95](a concurrent programming language not widely available) and non-portable features of Plan 9 [Pike95a].

    The name "wily" derives from Wile E. Coyote, an avid user of Acme products.

    Acknowledgements

    Many suggestions on wily and this paper, and much of the code were received from Bill Trost <trost@cloud.rain.com>. Libraries used include libXg and libframe, part of the Sam distribution by Rob Pike and Howard Trickey, and libtext by James Farrow.

    This is an incomplete, alphabetical list of other people who have made significant contributions to wily: Assar, Davor Cubranic, Kyle Dean, Stephen Gallimore, Mark H. Wilkinson, Bjorn Helgaas, Steve Kilbane, Beirne Konarski, Bob Krzaczek, Alberto Nava, Arnold Robbins, Rich Salz, Scott Schwartz, Chris Siebenmann, and Richard Wolff.

    References

    [Cap95]
    Gary Capell: Wily User's Guide
    http://www.cs.su.oz.au/~gary/wily/user.html
    [Cap95a]
    Gary Capell: Wily Programmer's Guide
    http://www.cs.su.oz.au/~gary/wily/msg.html
    [Pike95]
    Rob Pike: Acme: A User Interface for Programmers,
    Plan 9 Programmer's Manual, Volume Two, 2nd Ed.
    http://plan9.bell-labs.com/plan9/doc/acme.html
    [Pike95a]
    Rob Pike et al.: Plan 9 from Bell Labs,
    Plan 9 Programmer's Manual, Volume Two, 2nd Ed.
    http://plan9.bell-labs.com/plan9/doc/9.html
    [Win95]
    Phil Winterbottom: Alef language Reference Manual,
    Plan 9 Programmer's Manual, Volume Two, 2nd Ed.
    http://plan9.bell-labs.com/plan9/doc/ref.html
    [vanRo95]
    Guido van Rossum: Python Tutorial,
    CWI Technical Report CS-R9526,
    1995
    http://www.python.org/
    [Wirt89]
    N. Wirth and J. Gutknecht: The Oberon System,
    Software - Practice and Experience,
    Sep. 1989, Vol 19 #9, pp 857-894
    place. For example, after opening a file at a particular address, the cursor is warped to that position of that file.

    The escape key selects any text typed since the last cursor movement, making it easier to selectwily-0.13.42/Doc/sam/000075502366570000012000000000001033320152300137615ustar00ozstaff00004330000002wily-0.13.42/Doc/sam/bitblt.3000064402366570000012000000156071033320152300153360ustar00ozstaff00004330000002.de F .B .if !"\\$1"" \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 .. .de L .B .if !"\\$1"" \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 .. .de FR .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de LR .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de CW .ft B .. .\" This is gross but it avoids relying on internal implementation details .\" of the -man macros. .de TF .IP "" \w'\fB\\$1\ \ \fP'u .PD0 .. .de EX .CW .nf .. .de EE .fi .. .\" delete above this point if your system has F, L, FR, LR, CW and TF macros .TH BITBLT 3G .SH NAME bitblt, bitbltclip, copymasked, clipline, point, segment, polysegment, arc, circle, disc, ellipse, texture, border, string, strsize, strwidth, Fcode \- graphics functions .SH SYNOPSIS .nf .B #include .B #include .PP .ta \w'\fLPoint 'u .B void bitblt(Bitmap *db, Point dp, Bitmap *sb, .B Rectangle sr, Fcode f) .PP .B int bitbltclip(void *) .PP .B void copymasked(Bitmap *db, Point dp, Bitmap *sb, Bitmap *mb, Rectangle sr) .PP .B int clipline(Rectangle r, Point *p0, Point *p1); .PP .B void point(Bitmap *b, Point p, int v, Fcode f); .PP .B void segment(Bitmap *b, Point p, Point q, int v, Fcode f) .PP .B void polysegment(Bitmap *b, int n, Point *pp, int v, Fcode f) .PP .B void circle(Bitmap *b, Point p, int r, int v, Fcode f); .PP .B void arc(Bitmap *b, Point p0, Point p1, Point p2, int v, Fcode f); .PP .B void disc(Bitmap *b, Point p, int r, int v, Fcode f); .PP .B void ellipse(Bitmap *b, Point p, int a, int b, int v, Fcode f); .PP .B void texture(Bitmap *b, Rectangle r, Bitmap *t, Fcode f) .PP .B void border(Bitmap *b, Rectangle r, int w, Fcode f) .PP .B Point string(Bitmap *b, Point p, Font *ft, char *s, Fcode f) .PP .B Point strsize(Font *ft, char *s) .PP .B long strwidth(Font *ft, char *s) .PP .ft L .ta 8n +\w'xxxxxxxxxx'u +\w'xxxxxxxxxx'u +\w'xxxxxxxxxx'u +\w'xxxxxxxxxx'u enum Fcode { Zero, DnorS, DandnotS, notS, notDandS, notD, DxorS, DnandS, DandS, DxnorS, D, DornotS, S, notDorS, DorS, F } Fcode; .ft P .fi .SH DESCRIPTION .I Bitblt (bit-block transfer) takes bits from rectangle .I sr in the .I source Bitmap, .IR sb, and overlays them on a congruent rectangle with the .B min corner at point .B dp in the .I destination bitmap, .IR db . The .I f parameter says how to compute each destination pixel as a function of the source and destination pixels. The first sixteen codes in .B Fcode give all possible boolean operations on the source, .B S and destination .BR D . The code values have been arranged so that they may be expressed as boolean operations on the values .B S and .BR D. So, for example, .B D|S computes the result as the logical .I or of the destination pixel's old value and the overlaying source pixel's value. If pixels are more than one bit deep, the operations are bitwise. The .B Zero and .B F codes result in new pixel values that are all zeros or all ones, respectively. .PP If the source and destination bitmaps have different depths, the source rectangle is first converted to have the same depth as the destination, as follows: conversion to a smaller number of bits per pixel is accomplished by taking the desired number of high order bits; conversion to a larger number of bits per pixel is accomplished by putting the small value into the high order bits, and replicating it as many times as necessary to fill the lower order bits. .PP .I Copymasked copies rectangle .I sr in the source bitmap .I sb to the congruent rectangle with the .B min corner at point .B dp in the destination bitmap .IR db , masked by bitmap .I mb . This means that .I mb is overlayed on the destination rectangle, and only pixels corresponding to 1 bits in the mask are changed. .I Mb must be a 1-bit-deep bitmap with origin (0,0) and congruent to .IR sr . Bitmaps .I sb and .I db must have the same depth. .PP All of the drawing graphics functions clip the rectangle against the source and destination bitmaps, so that only pixels within the destination bitmap are changed, and none are changed that would have come from areas outside the source bitmap. .I Bitbltclip takes a pointer to the first argument of a .I bitblt argument list, and modifies .I dp and .I sr so that no more clipping is needed. .PP .I Point changes the value of the destination point .I p in bitmap .I b according to function code .IR f . The source is a pixel with value .IR v . It is useful to use .B "~0" when the maximum pixel value is desired for the source. .PP .IR Segment , .IR circle , .IR disc , and .I ellipse all draw in bitmap .I b with function code .I f and a source pixel with value .IR v . .I Arc draws a circular arc centered on .IR p0 , traveling clockwise from .I p1 to .I p2 or a point on the circle near .IR p2 . .I Segment draws a line segment in bitmap .I b from point .I p to .IR q . The segment is half-open: .I p is the first point of the segment and .I q is the first point beyond the segment, so adjacent segments sharing endpoints abut. .PP .I Polysegment draws the .IR n \-1 segments joining the .I n points in the array pointed to by .I pp. .I Clipline clips the line segment from .RI * p0 to .RI * p1 .RI ( p0 is closed, .I p1 is open) to rectangle .IR r , adjusting .I p0 and .I p1 so that the segment is within the rectangle and .RI * p1 is closed. It returns 0 if none of the segment is in the rectangle, 1 otherwise. .PP .I Circle draws a circle with radius .I r and center at point .IR p . .I Disc is the same except that it fills the circle. .I Ellipse draws an ellipse with horizontal semi-axis .I a and vertical semi-axis .IR b. .PP .I Border draws, with function .I f in bitmap .IR b , the rectangular outline with lines of width .IR w , fitting just inside rectangle .IR r . .PP .I Texture draws, with function .I f in bitmap .IR b , a texture using the bitmap specified by .IR t . The texture bitmap is aligned on .IR b 's coordinate system so that (0,0) in both coordinate systems coincide, and then .I t is replicated to form a tiling of .IR b . The tiling is clipped to rectangle .I r in .IR b , and then transferred to .I b using the specified function. .PP .I String draws the text characters given by the null-terminated (UTF encoded) string .I s into bitmap .IR b , using font .IR ft. The upper left corner of the first character (i.e., a point that is .IB ft ->ascent above the baseline) is placed at point .IR p , and subsequent characters are placed on the same baseline, displaced to the right by the previous character's .BR width . The individual characters are .IR bitblt 'ed into the destination, using drawing function .IR f . .I String returns the point in the destination bitmap after the final character of .I s (or where the final character would be drawn, assuming no clipping; the returned value might be outside the destination bitmap). .PP The bounding box for text to be drawn with .I string in font .I ft can be found with .IR strsize ; it returns the .B max point of the bounding box, assuming a .B min point of (0,0). .I Strwidth returns the .IR x -component of the .B max point. .SH SEE ALSO .IR graphics (3), .IT utf (4). wily-0.13.42/Doc/sam/bitmap.6000064402366570000012000000052271033320152300153320ustar00ozstaff00004330000002.de F .B .if !"\\$1"" \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 .. .de L .B .if !"\\$1"" \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 .. .de FR .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de LR .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de CW .ft B .. .\" This is gross but it avoids relying on internal implementation details .\" of the -man macros. .de TF .IP "" \w'\fB\\$1\ \ \fP'u .PD0 .. .de EX .CW .nf .. .de EE .fi .. .\" delete above this point if your system has F, L, FR, LR, CW and TF macros .TH BITMAP 6 .SH NAME bitmap \- external format for bitmaps .SH SYNOPSIS .B #include .B #include .SH DESCRIPTION Bitmaps are described in .IR graphics (3). Fonts and bitmaps are stored in external files in machine-independent formats. .PP Bitmap files are read and written using .I rdbitmapfile and .I wrbitmapfile (see .IR balloc (3)). A bitmap file starts with 5 decimal strings: .BR ldepth , .BR r.min.x , .BR r.min.y , .BR r.max.x , and .BR r.max.y . Each number is right-justified and blank padded in 11 characters, followed by a blank. The rest of the file contains the .BR r.max.y \- r.min.y rows of bitmap data. A .I row consists of the byte containing pixel .B r.min.x and all the bytes up to and including the byte containing pixel .B r.max.x\fR\(mi1. A pixel with x-coordinate = .I x in a bitmap with .B ldepth = .I l will appear as .if t \fIw\fP = 2\u\s8\fIl\fP\s10\d .if n w = 2^l contiguous bits in a byte, with the pixel's high order bit starting at the byte's bit number .if t \fIw\fP\(mu((\fIx\fP mod 8)/\fIw\fP), .if n w*(x mod 8/w), where bits within a byte are numbered 0 to 7 from the high order to the low order bit. If .I w is greater than 8, it is a multiple of 8, so pixel values take up an integral number of bytes. Rows contain integral number of bytes, so there may be some unused pixels at either end of a row. .PP The .I rdbitmap and .I wrbitmap functions described in .IR balloc (3) also deal with rows in this format, stored in user memory. .PP Some small images, in particular 48\(mu48 face files and 16\(mu16 cursors, are stored textually, suitable for inclusion in C source. Each line of text represents one scan line as a comma-separated sequence of hexadecimal bytes, shorts, or words in C format. For cursors, each line defines a pair of bytes. (It takes two images to define a cursor; each must be stored separately.) Face files of one bit per pixel are stored as a sequence of shorts, those of larger pixel sizes as a sequence of longs. Software that reads these files must deduce the image size from the input; there is no header. These formats reflect history rather than design. .SH "SEE ALSO" .IR graphics (3), .IR bitblt (3), .IR balloc (3), .IR font (6) wily-0.13.42/Doc/sam/add.3000064402366570000012000000072561033320152300146070ustar00ozstaff00004330000002.de F .B .if !"\\$1"" \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 .. .de L .B .if !"\\$1"" \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 .. .de FR .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de LR .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de CW .ft B .. .\" This is gross but it avoids relying on internal implementation details .\" of the -man macros. .de TF .IP "" \w'\fB\\$1\ \ \fP'u .PD0 .. .de EX .CW .nf .. .de EE .fi .. .\" delete above this point if your system has F, L, FR, LR, CW and TF macros .TH ADD 3G .SH NAME add, sub, mul, divpt, raddp, rsubp, rmul, rdiv, rshift, inset, rcanon, eqpt, eqrect, ptinrect, rectinrect, rectXrect, rectclip, Dx, Dy, Pt, Rect, Rpt \- arithmetic on points and rectangles .SH SYNOPSIS .nf .B #include .B #include .PP .B .ta 12n +12n +12n +12n +12n Point add(Point p, Point q) .PP .B Point sub(Point p, Point q) .PP .B Point mul(Point p, int a) .PP .B Point divpt(Point p, int a) .PP .B Rectangle raddp(Rectangle r, Point p) .PP .B Rectangle rsubp(Rectangle r, Point p) .PP .B Rectangle rmul(Rectangle r, int a) .PP .B Rectangle rdiv(Rectangle r, int a) .PP .B Rectangle rshift(Rectangle r, int a) .PP .B Rectangle inset(Rectangle r, int n) .PP .B Rectangle rcanon(Rectangle r) .PP .B int eqpt(Point p, Point q) .PP .B int eqrect(Rectangle r, Rectangle s) .PP .B int ptinrect(Point p, Rectangle r) .PP .B int rectinrect(Rectangle r, Rectangle s) .PP .B int rectXrect(Rectangle r, Rectangle s) .PP .B int rectclip(Rectangle *rp, Rectangle b) .PP .B int Dx(Rectangle r); .PP .B int Dy(Rectangle r); .PP .B Point Pt(int x, int y) .PP .B Rectangle Rect(int x0, int y0, int x1, int y1) .PP .B Rectangle Rpt(Point p, Point q) .fi .SH DESCRIPTION The functions .IR Pt , .I Rect and .I Rpt construct geometrical data types from their components. These are implemented as functions. (Under Plan 9 these are implemented as macros.) .PP .I Add returns the Point sum of its arguments: .BI Pt( p .x+ q .x, .IB p .y+ q .y). .I Sub returns the Point difference of its arguments: .BI Pt( p .x- q .x, .IB p .y- q .y). .I Mul returns the Point .BI Pt( p .x* a , .IB p .y* a ). .I Divpt returns the Point .BI Pt( p .x/ a , .IB p .y/ a ). .PP .I Raddp returns the Rectangle .BI Rect(add( r .min, .IB p ), .BI add( r .max, .IB p ))\fR; .I rsubp returns the Rectangle .BI Rpt(sub( r .min, .IB p ), .BI sub( r .max, .IB p ))\fR. .I Rmul returns the Rectangle .BI Rpt(mul( r .min, a ), .BI mul( r .max, a ))\fR; .I Rdiv returns the Rectangle .BI Rpt(div( r .min, a ), .BI div( r .max, a ))\fR. .PP .I Rshift returns the rectangle .I r with all coordinates either left-shifted or right-shifted by .IR a , depending on whether .I a is positive or negative, respectively. .PP .I Inset returns the Rectangle .BI Rect( r .min.x+ n , .IB r .min.y+ n , .IB r .max.x- n , .IB r .max.y- n ) . .PP .I Rcanon returns a rectangle with the same extent as .IR r , canonicalized so that .B min.x .if t \(<= .if n <= .BR max.x , and .B min.y .if t \(<= .if n <= .BR max.y . .PP .I Eqpt compares its argument Points and returns 0 if unequal, 1 if equal. .I Eqrect does the same for its argument Rectangles. .PP .I Ptinrect returns 1 if .I p is a point within .IR r , and 0 otherwise. .PP .I Rectinrect returns 1 if all the pixels in .I r are also in .IR s , and 0 otherwise. .PP .I RectXrect returns 1 if .I r and .I s share any point, and 0 otherwise. .PP .I Rectclip clips in place the Rectangle pointed to by .I rp so that it is completely contained within .IR b . The return value is 1 if any part of .RI * rp is within .IR b . Otherwise, the return value is 0 and .RI * rp is unchanged. .PP The functions .I Dx and .I Dy give the width (delta x) and height (delta y) of a Rectangle. They are implemented as macros. .SH SEE ALSO .IR graphics (3). wily-0.13.42/Doc/sam/sam.1000064402366570000012000000473021033320152300146310ustar00ozstaff00004330000002.de F .B .if !"\\$1"" \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 .. .de L .B .if !"\\$1"" \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 .. .de FR .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de LR .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de CW .ft B .. .\" This is gross but it avoids relying on internal implementation details .\" of the -man macros. .de TF .br .IP "" \w'\fB\\$1\ \ \fP'u .PD0 .. .de EX .CW .nf .. .de EE .fi .. .\" delete above this point if your system has F, L, FR, LR, CW and TF macros .ds a \fR*\ \fP .TH SAM 1 .CT 1 editor .SH NAME sam \- screen editor with structural regular expressions .SH SYNOPSIS .B sam [ .I option .\|.\|. ] [ .I files ] .PP .B sam .B \-r .I machine .PP .B sam.save .PP .B B [ .BI \-nnnn ] .I file .\|.\|. .SH DESCRIPTION .I Sam is a multi-file editor. It modifies a local copy of an external file. The copy is here called a .IR file . The files are listed in a menu available through mouse button 3 or the .B n command. Each file has an associated name, usually the name of the external file from which it was read, and a `modified' bit that indicates whether the editor's file agrees with the external file. The external file is not read into the editor's file until it first becomes the current file\(emthat to which editing commands apply\(emwhereupon its menu entry is printed. The options are .TF "\-r machine " .TP .B \-d Do not download the terminal part of .I sam. Editing will be done with the command language only, as in .IR ed (1). .TP .BI \-r " machine Run the host part remotely on the specified machine, the terminal part locally. .TP .BI \-s " file Start the host part from the indicated file on the remote host. Only meaningful with the .BI \-r option. .TP .BI \-t " path Start the terminal part from the indicated file. Useful for debugging. .PP The standard X11 .BI \-geom toolkit option can be used to select the desired window geometry. .SS Regular expressions Regular expressions are as in .IR regexp (6) with the addition of .BR \en to represent newlines. A regular expression may never contain a literal newline character. The elements of regular expressions are: .TF "[^abc] " .TP .B . Match any character except newline. .TP .B \en Match newline. .TP .B \ex For any character except .B n match the character (here .BR x ). .TP .B [abc] Match any character in the square brackets. .B \en may be mentioned. .TP .B [^abc] Match any character not in the square brackets, but never a newline. Both these forms accept a range of .SM ASCII characters indicated by a dash, as in .BR a\-z . .TP .B ^ Match the null string immediately after a newline. .TP .B $ Match the null string immediately before a newline. .PP Any other character except newline matches itself. .PP In the following, .I r1 and .I r2 are regular expressions. .TF "r1|r2 " .TP .BI ( r1 ) Match what .I r1 matches. .TP .IB r1 | r2 Match what .I r1 or what .IR r2 matches. .TP .IB r1 * Match zero or more adjacent matches of .IR r1 . .TP .IB r1 + Match one or more adjacent matches of .IR r1 . .TP .IB r1 ? Match zero or one matches of .IR r1 . .PP The operators .BR * , .B + and .B ? are highest precedence, then catenation, then .B | is lowest. The empty regular expression stands for the last complete expression encountered. A regular expression in .I sam matches the longest leftmost substring formally matched by the expression. Searching in the reverse direction is equivalent to searching backwards with the catenation operations reversed in the expression. .SS Addresses An address identifies a substring in a file. In the following, `character .IR n ' means the null string after the \%\fIn\fP-th character in the file, with 1 the first character in the file. `Line .IR n ' means the .IR n -th match, starting at the beginning of the file, of the regular expression .LR .*\en? . (The peculiar properties of a last line without a newline are temporarily undefined.) All files always have a current substring, called dot, that is the default address. .SS Simple Addresses .TF ?regexp? .TP .BI # n The empty string after character .IR n ; .B #0 is the beginning of the file. .TP .I n Line .IR n . .TP .BI / regexp / .PD0 .TP .BI ? regexp ? The substring that matches the regular expression, found by looking toward the end .RB ( / ) or beginning .RB ( ? ) of the file, and if necessary continuing the search from the other end to the starting point of the search. The matched substring may straddle the starting point. When entering a pattern containing a literal question mark for a backward search, the question mark should be specified as a member of a class. .PD .TP .B 0 The string before the first full line. This is not necessarily the null string; see .B + and .B \- below. .TP .B $ The null string at the end of the file. .TP .B . Dot. .TP .B \&' The mark in the file (see the .B k command below). .TP \f(CW"\f2regexp\f(CW"\f1\f1 Preceding a simple address (default .BR . ), refers to the address evaluated in the unique file whose menu line matches the regular expression. .SS Compound Addresses In the following, .I a1 and .I a2 are addresses. .TF "a1+a2 " .TP .IB a1 + a2 The address .I a2 evaluated starting at the end of .IR a1 . .TP .IB a1 \- a2 The address .I a2 evaluated looking in the reverse direction starting at the beginning of .IR a1 . .TP .IB a1 ,\^ a2 The substring from the beginning of .I a1 to the end of .IR a2 . If .I a1 is missing, .B 0 is substituted. If .I a2 is missing, .B $ is substituted. .TP .IB a1 ;\^ a2 Like .IB a1 ,\^ a2, but with .I a2 evaluated at the end of, and dot set to, .IR a1 . .PP The operators .B + and .B \- are high precedence, while .B , and .B ; are low precedence. .PP In both .B + and .B \- forms, if .I a2 is a line or character address with a missing number, the number defaults to 1. If .I a1 is missing, .L . is substituted. If both .I a1 and .I a2 are present and distinguishable, .B + may be elided. .I a2 may be a regular expression; if it is delimited by .LR ? 's, the effect of the .B + or .B \- is reversed. .PP It is an error for a compound address to represent a malformed substring. Some useful idioms: .IB a1 +\^\- .RI ( a1 \&\f5\-\^+\fP ) selects the line containing the end (beginning) of a1. .BI 0/ regexp / locates the first match of the expression in the file. (The form .B 0;\^// sets dot unnecessarily.) .BI .\^/ regexp /// finds the second following occurrence of the expression, and .BI .\^,\^/ regexp / extends dot. .SS Commands In the following, text demarcated by slashes represents text delimited by any printable .SM ASCII character except alphanumerics. Any number of trailing delimiters may be elided, with multiple elisions then representing null strings, but the first delimiter must always be present. In any delimited text, newline may not appear literally; .B \en may be typed for newline; and .B \e\^/ quotes the delimiter, here .LR / . Backslash is otherwise interpreted literally, except in .B s commands. .PP Most commands may be prefixed by an address to indicate their range of operation. Those that may not are marked with a .L * below. If a command takes an address and none is supplied, dot is used. The sole exception is the .B w command, which defaults to .BR 0\^,\^$ . In the description, `range' is used to represent whatever address is supplied. Many commands set the value of dot as a side effect. If so, it is always set to the `result' of the change: the empty string for a deletion, the new text for an insertion, etc. (but see the .B s and .B e commands). .br .ne 1.2i .SS Text commands .PD0 .TP .BI a/ text / .TP or .TP .B a .TP .I lines of text .TP .B . Insert the text into the file after the range. Set dot. .TP .B c\fP .br .ns .TP .B i\fP Same as .BR a , but .B c replaces the text, while .B i inserts .I before the range. .TP .B d Delete the text in the range. Set dot. .TP .BI s/ regexp / text / Substitute .I text for the first match to the regular expression in the range. Set dot to the modified range. In .I text the character .B & stands for the string that matched the expression. Backslash behaves as usual unless followed by a digit: .BI \e \^d stands for the string that matched the subexpression begun by the .IR d -th left parenthesis. If .I s is followed immediately by a number .IR n , as in .BR s2/x/y/ , the .IR n -th match in the range is substituted. If the command is followed by a .BR g , as in .BR s/x/y/g , all matches in the range are substituted. .TP .BI m " a1 .br .ns .TP .BI t " a1 Move the range to after .I a1 .RB ( m ), or copy it .RB ( t ). Set dot. .SS Display commands .TP .B p Print the text in the range. Set dot. .TP .B = Print the line address and character address of the range. .TP .B =# Print just the character address of the range. .SS File commands .TP .BI \*ab " file-list Set the current file to the first file named in the list that .I sam also has in its menu. The list may be expressed .BI < "shell command" in which case the file names are taken as words (in the shell sense) generated by the shell command. .TP .BI \*aB " file-list Same as .BR b , except that file names not in the menu are entered there, and all file names in the list are examined. .TP .B \*an Print a menu of files. The format is: .RS .TF "XorXblankXX" .TP .BR ' " or blank" indicating the file is modified or clean, .TP .BR \- " or \&" + indicating the file is unread or has been read (in the terminal, .B * means more than one window is open), .TP .BR . " or blank indicating the current file, .TP a blank, .TP and the file name. .RE .TP 0 .BI \*aD " file-list Delete the named files from the menu. If no files are named, the current file is deleted. It is an error to .B D a modified file, but a subsequent .B D will delete such a file. .SS I/O Commands .TP .BI \*ae " filename Replace the file by the contents of the named external file. Set dot to the beginning of the file. .TP .BI r " filename Replace the text in the range by the contents of the named external file. Set dot. .TP .BI w " filename Write the range (default .BR 0\^,\^$ ) to the named external file. .TP .BI \*af " filename Set the file name and print the resulting menu entry. .PP If the file name is absent from any of these, the current file name is used. .B e always sets the file name, .B r and .B w do so if the file has no name. .TP .BI < " shell-command Replace the range by the standard output of the shell command. .TP .BI > " shell-command Sends the range to the standard input of the shell command. .TP .BI | " shell-command Send the range to the standard input, and replace it by the standard output, of the shell command. .TP .BI \*a! " shell-command Run the shell command. .TP .BI \*acd " directory Change working directory. If no directory is specified, .B $HOME is used. .PP In any of .BR < , .BR > , .B | or .BR ! , if the .I shell command is omitted the last .I shell command (of any type) is substituted. If .I sam is downloaded, .B ! sets standard input to .FR /dev/null , and otherwise unassigned output .RB ( stdout for .B ! and .BR > , .B stderr for all) is placed in .F $HOME/sam.err and the first few lines are printed. .SS Loops and Conditionals .TP .BI x/ regexp / " command For each match of the regular expression in the range, run the command with dot set to the match. Set dot to the last match. If the regular expression and its slashes are omitted, .L /.*\en/ is assumed. Null string matches potentially occur before every character of the range and at the end of the range. .TP .BI y/ regexp / " command Like .B x, but run the command for each substring that lies before, between, or after the matches that would be generated by .BR x . There is no default behavior. Null substrings potentially occur before every character in the range. .TP .BI \*aX/ regexp / " command For each file whose menu entry matches the regular expression, make that the current file and run the command. If the expression is omitted, the command is run in every file. .TP .BI \*aY/ regexp / " command Same as .BR X , but for files that do not match the regular expression, and the expression is required. .TP .BI g/ regexp / " command .br .ns .TP .BI v/ regexp / " command If the range contains .RB ( g ) or does not contain .RB ( v ) a match for the expression, set dot to the range and run the command. .PP These may be nested arbitrarily deeply, but only one instance of either .B X or .B Y may appear in a \%single command. An empty command in an .B x or .B y defaults to .BR p ; an empty command in .B X or .B Y defaults to .BR f . .B g and .B v do not have defaults. .SS Miscellany .TP .B k Set the current file's mark to the range. Does not set dot. .TP .B \*aq Quit. It is an error to quit with modified files, but a second .B q will succeed. .TP .BI \*au " n Undo the last .I n (default 1) top-level commands that changed the contents or name of the current file, and any other file whose most recent change was simultaneous with the current file's change. Successive .BR u 's move further back in time. The only commands for which u is ineffective are .BR cd , .BR u , .BR q , .B w and .BR D . .TP (empty) If the range is explicit, set dot to the range. If .I sam is downloaded, the resulting dot is selected on the screen; otherwise it is printed. If no address is specified (the command is a newline) dot is extended in either direction to line boundaries and printed. If dot is thereby unchanged, it is set to .B .+1 and printed. .PD .SS Grouping and multiple changes Commands may be grouped by enclosing them in braces .BR {} . Commands within the braces must appear on separate lines (no backslashes are required between commands). Semantically, an opening brace is like a command: it takes an (optional) address and sets dot for each sub-command. Commands within the braces are executed sequentially, but changes made by one command are not visible to other commands (see the next paragraph). Braces may be nested arbitrarily. .PP When a command makes a number of changes to a file, as in .BR x/re/c/text/ , the addresses of all changes to the file are computed in the original file. If the changes are in sequence, they are applied to the file. Successive insertions at the same address are catenated into a single insertion composed of the several insertions in the order applied. .SS The terminal What follows refers to behavior of .I sam when downloaded, that is, when operating as a display editor on a bitmap display. This is the default behavior; invoking .I sam with the .B \-d (no download) option provides access to the command language only. .PP Each file may have zero or more windows open. Each window is equivalent and is updated simultaneously with changes in other windows on the same file. Each window has an independent value of dot, indicated by a highlighted substring on the display. Dot may be in a region not within the window. There is usually a `current window', marked with a dark border, to which typed text and editing commands apply. The escape key (ESC) selects (sets dot to) text typed since the last mouse button hit. .PP The button 3 menu controls window operations. The top of the menu provides the following operators, each of which uses one or more cursors to prompt for selection of a window or sweeping of a rectangle. .TF "reshape " .TP .B new Create a new, empty file: Depress button 3 where one corner of the new rectangle should appear (box cursor), and move the mouse while holding down button 3 to the diagonally opposite corner. `Sweeping' a null rectangle gets a large window, disjoint from the command window or the whole sam window, depending on where the null rectangle is. .TP .B xerox Create a copy of an existing window. After selecting the window to copy with button 1, sweep out the window for the copy. .TP .B reshape Change the size and location of a window. First click button 3 in the window to be changed (gunsight cursor). Then sweep out a window as for the .B new menu selection. .TP .B close Delete the window. In the last window of a file, .B close is equivalent to a .B D for the file. .TP .B write Equivalent to a .B w for the file. .PD .PP Below these operators is a list of available files, starting with .BR ~~sam~~ , the command window. Selecting a file from the list makes the most recently used window on that file current, unless it is already current, in which case selections cycle through the open windows. If no windows are open on the file, the user is prompted to open one. Files other than .B ~~sam~~ are marked with one of the characters .B \-\^+* according as zero, one, or more windows are open on the file. A further mark .L . appears on the file in the current window and a single quote, .BR ' , on a file modified since last write. .PP The command window, created automatically when .B sam starts, is an ordinary window except that text typed to it is interpreted as commands for the editor rather than passive text, and text printed by editor commands appears in it. There is an `output point' that separates commands being typed from previous output. Commands typed in the command window apply to the current open file\(emthe file in the most recently current window. .SS Manipulating text Typed characters replace the current selection (dot) in the current window. Backspace deletes the previous character. Escape selects (sets dot to) everything typed since the last mouse hit. .PP Button 1 changes selection. Pointing to a non-current window with button 1 makes it current; within the current window, button 1 selects text, thus setting dot. Double-clicking selects text to the boundaries of words, lines, quoted strings or bracketed strings, depending on the text at the click. .PP Button 2 provides a menu of editing commands: .TF "/regexp" .TP .B cut Delete dot and save the deleted text in the snarf buffer. .TP .B paste Replace the text in dot by the contents of the snarf buffer. .TP .B snarf Save the text in dot in the snarf buffer. .TP .B look Search forward for the next occurrence of the literal text in dot. If dot is the null string, the text in the snarf buffer is used. The snarf buffer is unaffected. .TP .B Exchange the snarf buffer with the current selection in another X11 window. The exchange of a large amount of selected text is truncated to the size of Sam's internal snarf buffer (currently 4K) without warning. .TP .BI / regexp Search forward for the next match of the last regular expression typed in a command. (Not in command window.) .TP .B send Send the text in dot, or the snarf buffer if dot is the null string, as if it were typed to the command window. Saves the sent text in the snarf buffer. (Command window only.) .PD .SS X11 resources Various attributes of .I sam can be set by giving values to X11 resources for the class .B Sam. There are various ways to do this; one is to have a file called .B Sam in your home directory, with entries in it like: .PP .CW .nf Sam*width: 500 Sam*height: 600 Sam*font: fixed Sam*scrollForwardR: true .fi .PP In addition to the usual X11 toolkit resources, the .B scrollForwardR resource says where the right button (button 3) scrolls forward or backward in the file. .SS Abnormal termination If .I sam terminates other than by a .B q command (by hangup, deleting its window, etc.), modified files are saved in an executable file, .FR $HOME/sam.save . This program, when executed, asks whether to write each file back to a external file. The answer .L y causes writing; anything else skips the file. If a machine crash prevents the creation of a .F sam.save file, all changes are lost. If an editing session is difficult to replicate, you should write your changed files often. .PP .I B is a shell-level command that causes an instance of .I sam running on the same terminal to load the named .I files. The option allows a line number to be specified for the initial position to display in the last named file. .SH FILES .F $HOME/sam.save .br .F $HOME/sam.err .br .B /samsave the program called to unpack .BR $home/sam.save . .SH SEE ALSO .IR ed (1), .IR regexp (6) .SH BUGS .PP When a sam window is resized, the command window may have the wrong size. by the contents of the named external file. Set dot. .TP .BI w " filename Write the range (default .BR 0\^,\^$ ) to the named external file. .TP .BI \*af " filename Set the file name and print the resulting menu entry. .PP If the file name is absent from any of these, the current file name is used. .B e always sets twily-0.13.42/Doc/sam/utf.4000064402366570000012000000052431033320152300146500ustar00ozstaff00004330000002.de F .B .if !"\\$1"" \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 .. .de L .B .if !"\\$1"" \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 .. .de FR .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de LR .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de CW .ft B .. .\" This is gross but it avoids relying on internal implementation details .\" of the -man macros. .de TF .IP "" \w'\fB\\$1\ \ \fP'u .PD0 .. .de EX .CW .nf .. .de EE .fi .. .\" delete above this point if your system has F, L, FR, LR, CW and TF macros .TH UTF 4 .SH NAME UTF, Unicode, ASCII, rune \- character set and format .SH DESCRIPTION The Plan 9 character set and representation are based on Unicode and on a proposed X-Open multibyte .SM FSS-UCS-TF (File System Safe Universal Character Set Transformation Format) encoding. Unicode represents its characters in 16 bits; .SM FSS-UCS-TF, or just .SM UTF, represent such values in an 8-bit byte stream. .PP In Plan 9, a .I rune is a 16-bit quantity representing a Unicode character. Internally, programs may store characters as runes. However, any external manifestation of textual information, in files or at the interface between programs, uses a machine-independent, byte-stream encoding called .SM UTF. .PP .SM UTF is designed so the 7-bit .SM ASCII set (values hexadecimal 00 to 7F), appear only as themselves in the encoding. Runes with values above 7F appear as sequences of two or more bytes with values only from 80 to FF. .PP The .SM UTF encoding of Unicode is backward compatible with .SM ASCII\c : programs presented only with .SM ASCII work on Plan 9 even if not written to deal with .SM UTF, as do programs that deal with uninterpreted byte streams. However, programs that perform semantic processing on .SM ASCII graphic characters must convert from .SM UTF to runes in order to work properly with non-\c .SM ASCII input. See .IR rune (2). .PP Letting numbers be binary, a rune x is converted to a multibyte .SM UTF sequence as follows: .PP 01. x in [00000000.0bbbbbbb] \(-> 0bbbbbbb .br 10. x in [00000bbb.bbbbbbbb] \(-> 110bbbbb, 10bbbbbb .br 11. x in [bbbbbbbb.bbbbbbbb] \(-> 1110bbbb, 10bbbbbb, 10bbbbbb .br .PP Conversion 01 provides a one-byte sequence that spans the .SM ASCII character set in a compatible way. Conversions 10 and 11 represent higher-valued characters as sequences of two or three bytes with the high bit set. Plan 9 does not support the 4, 5, and 6 byte sequences proposed by X-Open. When there are multiple ways to encode a value, for example rune 0, the shortest encoding is used. .PP In the inverse mapping, any sequence except those described above is incorrect and is converted to rune 0080. .SH "SEE ALSO" .IR ascii (1), .IR rune (3), .IR keyboard (4), .IR "The Unicode Standard" . alled .SM UTF. .PP .SM UTF is designed so the 7-bit .SM ASCII set (values hexadecimal 00 to 7F), appear only as themselves in the encoding. Runes with values above 7F appear as sequences of two or more bytes with values only from 80 to FF. .PP The .SM UTF encoding of Unicode is backward compatible with .SM ASCII\c : programs presented only with .Swily-0.13.42/Doc/sam/README000064402366570000012000000361021033320152300146430ustar00ozstaff00004330000002 * The authors of this software are Rob Pike and Howard Trickey. * Copyright (c) 1992 by AT&T. * Permission to use, copy, modify, and distribute this software for any * purpose without fee is hereby granted, provided that this entire notice * is included in all copies of any software which is or includes a copy * or modification of this software and in all copies of the supporting * documentation for such software. * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. This is an X11 version of Rob Pike's editor, sam. Documentation describing its use and construction are provided in subdirectory doc. The file doc/sam.1 contains the manual page; doc/sam.tut.ms is a tutorial that can be formatted with troff -ms. It substitutes Bold and Italics for the fonts named CW and CS; if your system has these fonts, remove the CW and CS macros at the beginning of the file. The files doc/sam.ps and doc/se.ps are postscript versions of published papers describing sam and structural regular expressions. These papers reflect sam's capabilities at the time of publication several years ago; while the general description remains accurate, some functions may have changed or been removed. Other files in the doc directory contain manual pages for the library packages used by sam. Sam is composed of two programs: sam itself, which does the command processing and file manipulation; and samterm, which controls the display and interacts with the user. You can run sam on one machine and samterm on another connected via remote execution. This version of sam is based on the Plan 9 implementation. Its design and expression reflect the functionality of the Plan 9 environment; most notably, characters are represented internally by 16-bit values called Runes. Header files include/u.h and include/libc.h and source files libframe/misc.c, libXg/rune.c, sam/unix.c and samterm/unix.c contain code that insinuates sam into the Unix world. Two other files, sam/plan9.c and samterm/plan9.c, contain Plan 9-specific code; they are not used in the Unix version of sam and are provided as examples of the Plan 9 interface. Sam requires an ANSI/POSIX-compatible C compiler and libraries. We have found that some commercial compilers which claim to meet this standard are deficient. For our sanity, we only port sam to the standard; it is up to you to modify it for non-standard aspects of your local environment. Hints for some non-standard systems are provided at the end of this file. The handling of varargs is the source of many porting problems. We advise you to inspect the functions dprint and fprint in the files sam/unix.c and libframe/misc.c to ensure the accuracy of the implementation. We also encourage you to look at function newtmp() in sam/unix.c which creates a sam temporary file. We prefer to use the tempnam() function; it allows us to select the directory where the temp file is placed, a useful optimization for systems with small local disks. However, tempnam() is not a POSIX function, so you may have to use tmpfile() or a similar function to create the temporary file. The typedefs for uchar, ushort, and ulong defined in include/u.h, may conflict with exisiting definitions in include file on some systems. If this occurs, remove the offending definitions from include/u.h. The distribution consists of six directories: sam - The source for sam. It loads against libXg to pick up some utility routines. samterm - The source for samterm. It loads against libframe, libXg, and your local X11 libraries. libframe - The source for the frame library. This library is used by samterm so it must be made first. libXg - The source code of the graphics library and some general utility modules. Header file u.h provides much of the interface between sam and the local environment. It is included in every source file. Sam's graphics operations are implemented by Plan 9 libg functions. This library emulates those functions using X11 operations. You might find libXg to be independently useful to tame the horrors of X11 programming. You can put it anywhere; the samterm makefiles assume it is in ../libXg. libXg must be made first. include - header files. doc - The documentation for sam and the libraries. Each source directory contains makefiles for several typical architectures. The master makefile in the top directory builds the subdirectories in proper order. Most customization effort is confined to configuring the makefiles. You can usually minimize your work by copying the makefile for your architecture to Makefile and then editing a couple of lines. For example, to install sam on a Sun, go to each source subdirectory, copy Make.sun to Makefile, and customize each Makefile. Most of the time only the makefiles need configuration. Occasionally, it may be necessary to twiddle some of the macros and pre-processor magic in include/u.h or include/libc.h. In unusual cases, you may have to massage system-dependent code in files libXg/misc.c, sam/unix.c, or samterm/unix.c. Of course, systems with non-standard compilers or libraries may require minor modifications to any or all of the source files. Variables in each makefile define most configuration-dependent parameters; each is explained by a comment in the makefile. The RSAMNAME variable in sam/Makefile contains the name of the sam executable; this is only used when executing sam remotely. If sam is stored in the same path on every machine in your network or you use symbolic links to make it look like it is, this variable should specify the full path name of the executable. If sam resides in various directories on different machines, you've got a problem. The best strategy is to simply set the name of the file containing sam (usually, "sam") without a path component and rely on the users to set the directory in their PATH on the remote system. Unfortunately, this fails when the Berkeley rsh is used as the remote execution agent because it neglects to evaluate the user's profile in some situations. If a sam session terminates abnormally, sam creates a shell script named sam.save in the user's home directory. When this file is executed, it asks the user about each file and restores those selected. The files are restored with the names as they were known to sam; usually you will want to move sam.save to the last directory you had changed to in sam and restore the files from that point. The restoration script relies on a second script provided in sam/samsave. The SAMSAVEDIR variable in the sam Makefile contains the name of a directory to hold this script. The SAMSAVE variable contains the shell command to unpack each file; the command works with both the Bourne shell or Tom Duff's 'rc'. After configuring the makefiles, change to the top-level directory and type "make". Typing "make install" installs sam, samterm and samsave in their permanent homes. During testing, the path of samterm may be specified using the -t command line option to sam. Similarly, the path of sam itself may be specified using the -s command line option; this is handy for testing the remote execution feature. You may want to install Sam.ad as "Sam" in the system application defaults library (which will have some name like /usr/lib/X11/app-defaults) or your own home directory, if you don't have permission to write in app-defaults. Sam.ad can be edited to give default values for things like the starting height and width, the font, and the foreground and background colors. Currently, only the -geom X11 parameter can be specified on the command line. New X11 parameters can be easily added by including the first character of the parameter in the switch statement in main() in file sam/sam.c. Valid parameter strings are passed to samterm and then directly to X11 for interpretation. The scripts 'B.sh' and and 'B.rc' for the Bourne Shell and 'rc', respectively, send a 'B' command to a runninng instance of sam and optionally position the file to a selected line. The scripts are located in the sam subdirectory; install one or both in the appropriate directory depending on the conventions of your site. There is no installation target for them in the makefiles. These commands require a POSIX-compliant named pipe facility; if your system lacks this capability, replace the code in exstart() in samterm/unix.c with a 'return' statement and throw away B.sh and B.rc. We have successfully made this distribution for IRIX 4.0.1, SunOs 4.1.1 and Mips 4.5.2 at our site. Additionally, Rich Salz, Dan McDonald, Alain Kagi and Ed Kubaitis have contributed prototype makefiles for other architectures. We are unable to test and verify them but they provide a good starting point for customizing a makefile. The original protocol between sam and samterm assumed that memory addresses and longs were 32 bits. Dave Hanson removed this dependency from the protocol allowing sam to run on 64-bit processors. However, other dependencies on structure alignment remain. If you are installing sam on a processor with 64-bit addresses, please read the comment immediately preceding the declaration of the Block data structure in file sam/sam.h (at approximately line 85), and fiddle with the declaration appropriately. Rob Pike designed and implemented the original Unix version of sam and the current version ported from Plan 9. Howard Trickey provided the X version of the graphics library, libXg. Matty Farrow and his colleagues at the University of Sydney extended libXg to support Runes. Boyd Roberts supplied the external command interface and the shell scripts for the 'B' command. Doug Gwyn contributed many useful ideas to the X implementation of sam. James Clark provided the simulations of the V10 Unix Man macros at the beginning of each manual page. Matty Farrow of the University of Sydney has implemented 9term, an X11 version of a Plan 9 window. It is available via anonymous FTP from ftp.cs.su.oz.au in directory /matty/unicode. Chris Siebenmann of the University of Toronto runs the sam-fans mailing list, a source of tips, bug patches, controversy and gossip among sam users. Send your e-mail address to sam-fans-request@hawkwind.utcs.toronto.edu to enroll in the list. Andrew Hume has written tcs, a Unix utility which converts input text in one user-specified character set to output text in another user-specified character set. It is useful for converting text represented in a variety of standard character set encodings to UTF, the standard character set accepted by sam. The tcs source package is available via ftp in file dist/tcs.shar.Z on research.att.com. In general, we are uninterested in adding further capabilities to sam; we provide the source to allow you to customize it if you wish to "improve" it. Please send bug fixes and comments to: Bob Flandrena, bobf@research.att.com ----------------------------------------------------------------------------------- Following are modifications necessary to paper over compiler or library deficiencies to complying with the ANSI/POSIX standard. Please inform us of any other changes. ----------------------------------------------------------------------------------- SUNOS Release 4.1.1 The implementation of realloc does not conform to ANSI semantics. Sam assumes realloc(0, n); is equivalent to malloc(n). Replace each occurrence of p = realloc(p, n); with: p = ((p == 0) ? malloc(n) : realloc(p, n)); or something equivalent. Several files that include the X11 Intrinsics header file must have the variable SYSV defined before the inclusion. The shell script sun.ed attempts to automatically apply these patches when run from the top directory. Older versions of gcc lack the '-fno-builtin'. If this describes your site, remove the flag from the CFLAGS variable in Make.sun. Because the standard Sun compiler is not Ansi-compatible, frantic Sun users have been forced to cobble together their own compiling environment. Unfortunately, the resulting system configurations have little in common and it is virtually impossible to provide a universal build procedure. We suggest the use of gcc; other than that, Sun users are, as always, in the dark and on their own. ----------------------------------------------------------------------------------- MIPS OS Release 4.5.2 (and DEC ULTRIX Version 4.2A) There are two major deficiencies with the Mips implementation: the use of the old System V implementation of varargs and a compiler bug that botches the parsing of certain typedeffed parameters in function prototypes. The following changes are required: In sam/unix.c, replace function dprint with the following code: void dprint(char *fmt, int va_alist) va_dcl { va_list args; char buf[BLOCKSIZE]; va_start(args); vsprintf(buf, fmt, args); termwrite(buf); va_end(args); } In libframe/misc.c, replace function fprint with the following code: void fprint(int fd, char *fmt, int va_alist) va_dcl { va_list args; char buf[2048]; /* pick reasonable blocksize */ va_start(args); vsprintf(buf, fmt, args); write(fd, buf, strlen(buf)); va_end(args); } In samterm/flayer.h, replace the declaration of the member named textfn (near line 20) in structure Flayer, currently declared as: Rune *(*textfn)(Flayer*, long, ulong*); with Rune *(*textfn)(Flayer*, long, unsigned long*); In sam/parse.h, replace the declaration of the member named fn (near line 46) in structure cmdtab, currently declared as: int (*fn)(File*, Cmd*); /* function to call with parse tree */ with int (*fn)(File*, struct Cmd*); /* function to call with parse tree */ In sam/sam.h, replace the declaration of function dprint (near line 245) with: void dprint(); In include/libc.h, replace the declaration of function fprint (near line 53) with: void fprint(); Near line 71 of samterm/samterm.h, change the declaration of function gettext from: Rune *gettext(Flayer*, long, ulong*); to Rune *gettext(Flayer*, long, unsigned long*); The shell script mips.ed attempts to automatically apply these patches when run from the top directory. ----------------------------------------------------------------------------------- Convex ConvexOS 9.1 In libXg/latin1.c, the Convex compiler requires room for a NULL at the end of the 2-byte character field in struct latin. This can be fixed by changing the dimension of the character array named 'c' near line 6 to 3 from 2. This bug appears to be fixed in the compiler for Release 10.1. ----------------------------------------------------------------------------------- Sequent PTX V2.0.3 The calls to _exits() in sam/io.c near lines 184 and 205 clash with the prototype for a system function of the same name. Replace the statements _exits("damn"); with _exits('d'); ----------------------------------------------------------------------------------- IBM AIX V3.2.3 AIX xlc V1.2.1 generates bad code in the second call to border() in samterm/flayer.c:flborder() causing a core dump. Fix is to upgrade to later version of xlc (V1.2.1.4). Or, compile samterm/flayer.c (at least) with '-O'. d using the -t command line option to sam. Similarly, the path of sam itself may be specified using the -s command line option; this is handy for testing the remote execution feature. You may want to install Sam.ad as "Sam" in the system application defaults library (which will have some name like /usr/lib/X11/app-defaults) or your own home directory, if you don't have permission to write in app-defaults. Sam.ad can be edited to give defauwily-0.13.42/Doc/sam/rgbpix.3000064402366570000012000000050411033320152300153400ustar00ozstaff00004330000002.de F .B .if !"\\$1"" \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 .. .de L .B .if !"\\$1"" \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 .. .de FR .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de LR .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de CW .ft B .. .\" This is gross but it avoids relying on internal implementation details .\" of the -man macros. .de TF .IP "" \w'\fB\\$1\ \ \fP'u .PD0 .. .de EX .CW .nf .. .de EE .fi .. .\" delete above this point if your system has F, L, FR, LR, CW and TF macros .TH RGBPIX 3G .SH NAME RGB, rgbpix, rdcolmap, wrcolmap .SH SYNOPSIS .nf .PP .B #include .B #include .PP .ta \w'\fLunsigned long 'u .B unsigned long rgbpix(Bitmap *b, RGB rgb) .PP .B void rdcolmap(Bitmap *b, RGB *map) .PP .B void wrcolmap(Bitmap *b, RGB *map) .fi .SH DESCRIPTION Colors are described by the red, green, and blue light intensities, in an .B RGB datum: .IP .EX .ta 6n typedef struct RGB { unsigned long red; unsigned long green; unsigned long blue; } RGB; .EE .PP Zero intensity means there is no component of the given color; hence, black is represented by zero in all three positions and white has the maximum unsigned long value in all three positions. .PP Some of the graphics functions, such as .I point (see .IR bitblt (3)), take a .I pixel value argument, which is a single unsigned long. For a given bitmap, .I rgbpix returns the pixel value with a color closest to the color represented by the .I rgb argument. .PP There is a .I colormap associated with each Bitmap. A colormap is an array of .BR RGB s, of length .if t 2\u\s82\u\s6\fIldepth\fP\d\d\s10, .if n 2^(2^\fIldepth\fP), giving the colors for pixels 0, 1, 2, etc. .PP .I Rdcolormap reads the colormap for the given bitmap into the provided .IR map , which must have enough space to hold it. .I Wrcolormap associates the given colormap with the given bitmap, if possible. (The hardware might not allow this.) .SH CAVEAT The X implementation of libg uses whatever colourmap is the default when it starts up. A call to .I rgbpix will result in a call to .I XAllocColor and the allocation of a new colour in the application's colourmap if there is room. If no new colours can be allocated .I rgbpix will return the closest pixel value approximating the requested colour. If an application calls .I wrcolmap the default colourmap is replaced with the new colourmap and from then on .I rgbpix will deal with the new colourmap. .SH BUGS These functions only work for the screen bitmap. This interface will have to be refined for screens with ldepth > 3. .SH "SEE ALSO" .IR graphics (3), .IR bitblt (3) ap .SH SYNOPSIS .nf .PP .B #include .B #include .PP .ta \w'\fLunsigned long 'u .B unsigned long rgbpix(Bitmap *b, RGB rgb) .PP .B void rdcolmap(Bitmap *b, RGB *map) .PP .B void wrcolmap(Bitmap *b, RGB *map) .fi .SH DESCRIPTION Colors are described by the red, green, and blue light intensities, in an .B RGB datum: .IP .EX .ta 6n typedef struct RGB { unsigned long red; unsigned long green; unsigned long blue; } RGB; .EE .PP Zero intensity means there is nowily-0.13.42/Doc/sam/cachechars.3000064402366570000012000000131141033320152300161310ustar00ozstaff00004330000002.de F .B .if !"\\$1"" \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 .. .de L .B .if !"\\$1"" \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 .. .de FR .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de LR .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de CW .ft B .. .\" This is gross but it avoids relying on internal implementation details .\" of the -man macros. .de TF .IP "" \w'\fB\\$1\ \ \fP'u .PD0 .. .de EX .CW .nf .. .de EE .fi .. .\" delete above this point if your system has F, L, FR, LR, CW and TF macros .TH CACHECHARS 3G .SH NAME cachechars, Subfont, Cachesubf, Fontchar, Font \- font utilities .SH SYNOPSIS .nf .B #include .B #include .PP .ta \w'\fLCacheinfo 'u .PP .B int cachechars(Font *f, char **s, XChar2b *c, int n, int *widp, ushort *fp) .fi .SH DESCRIPTION A .I Font may contain too many characters to hold in memory simultaneously. The graphics library and X server cooperate to solve this problem by maintaining a cache of recently used character images. The details of this cooperation need not be known by most programs: .I xtbinit and its associated .I *p9font X resource, .I rdfontfile, .I charwidth, .I string, and .I ffree are sufficient for most purposes. The routines described below are used internally by the graphics library to maintain the font cache. .PP A .B Subfont may be considered to be a set of images for a contiguous range of characters, stored as a single bitmap with the characters placed side-by-side on a common baseline. It is described by the following data structures. .IP .EX .ta 6n +\w'Fontchar 'u +\w'bottom; 'u typedef struct Fontchar { ushort cwidth; /* width of glyph */ uchar top; /* first non-zero scan-line */ uchar bottom; /* last non-zero scan-line */ char left; /* offset of baseline */ uchar width; /* advance to next char's origin */ } Fontchar; typedef struct Subfont { short minrow; /* first character row in font (for X subfonts) */ short mincol; /* first character col in font (for X subfonts) */ short minchar; /* first char code in font (for X subfonts) */ short maxchar; /* last char code in font (for X subfonts) */ short width; /* number of chars in row (for X subfonts) */ short n; /* number of chars in subfont */ unsigned char height; /* height of bitmap */ char ascent; /* top of bitmap to baseline */ Fontchar *info; /* n+1 character descriptors */ int id; /* of font */ } Subfont; .EE .PP The actual bitmap for each character is stored on the server but the metrics associated with character .I c are cached locally in .B subfont->info[\fIc\fP]\fR. When a character is displayed at .B Point .B p in a bitmap, the character rectangle is placed at .BI (p.x+ i ->left, .B p.y) and the next character of the string is displayed at .BI (p.x+ i ->width+( i +1)->left, .BR p.y) . The baseline of the characters is .L ascent rows down from the top of the subfont bitmap. Each .B Fontchar has two widths associated with it: .I width is the width of the rectangular bitmap to contain the character; .I cwidth is the true width of the character, that is, the number of pixels between the leftmost and rightmost pixels of the character glyph. .PP A .B Font consists of an overall height and ascent and a collection of subfonts together with the ranges of runes (see .IR utf (4)) they represent. Fonts are described by the following structures. .IP .EX .ta 6n +\w'Cachesubf 'u +\w'height; 'u typedef struct Cachesubf { Rune min; /* rune value of 0th char in subfont */ Rune max; /* rune value+1 of last char in subfont */ char *name; Subfont *f; /* attached subfont */ } Cachefont; typedef struct Font { char *name; uchar height; /* max height of bitmap, interline spacing */ char ascent; /* top of bitmap to baseline */ char width; /* widest so far; used in caching only */ char ldepth; /* of images */ short id; /* of font */ short nsubf; /* number of subfonts */ Cachesubf *subf; /* as read from file */ } Font; .EE .PP The .LR height , .LR ascent , and .L ldepth fields of Font are described in .IR graphics (3). .L Subf contains .L nsubf pointers to .BR Cachesubfs . A .B Cachesubf connects runes .L min through .LR max , inclusive, to the subfont .LR name ; it corresponds to a line of the file describing the font. .PP The image for rune .I r is found in position \fIr\fR\(mi\fLmin\fR\(pl\fLminchar\fR of the subfont. .PP For each font, the library, with support from the graphics server, maintains a list of subfonts. The .L width of a font is the maximum of the horizontal extents of the characters in the cache. [ .L width is unused in the X implementation of libg.] .I String draws a string by calling .I cachechars and emitting a sequence of X font indices to draw. .I Cachechars calculates the subfont/index pairs for the characters pointed to by .IR *s . It calls .I getsubfont to fetch subfonts which are not yet in the subfont list of .IR f . .I Cachechars translates the character string into a set of subfont/index pairs. It loads the character indices into the array .IR c , up to a maximum of .I n indices or the length of the string. It also loads the corresponding element of .I fp with the subfont index for each character. .I Cachechars returns in .I c the number of subfont indices emitted, updates .I *s to point to the next character to be processed, and sets .I *widp to the total width of the characters processed. .I Cachechars may return before the end of the string if it cannot proceed. It can return zero if it is unable to make progress because a character code does not covered by any subfont range. .SH SEE ALSO .IR graphics (3), .IR balloc (3), .IR bitblt (3), .IR font (4). .SH DIAGNOSTICS All of the functions use the graphics error function (see .IR graphics (3)). wily-0.13.42/Doc/sam/boilerplate000064402366570000012000000013101033320152300162010ustar00ozstaff00004330000002 /* * The authors of this software are Rob Pike and Howard Trickey. * Copyright (c) 1992 by AT&T. * Permission to use, copy, modify, and distribute this software for any * purpose without fee is hereby granted, provided that this entire notice * is included in all copies of any software which is or includes a copy * or modification of this software and in all copies of the supporting * documentation for such software. * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. */ wily-0.13.42/Doc/sam/Sam.ad000064402366570000012000000001501033320152300150030ustar00ozstaff00004330000002*width: 500 *height: 600 *font: fixed *scrollForwardR: true *saveUnder: true *backingStore: WhenMapped wily-0.13.42/Doc/sam/event.3000064402366570000012000000133601033320152300151710ustar00ozstaff00004330000002.de F .B .if !"\\$1"" \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 .. .de L .B .if !"\\$1"" \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 .. .de FR .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de LR .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de CW .ft B .. .\" This is gross but it avoids relying on internal implementation details .\" of the -man macros. .de TF .IP "" \w'\fB\\$1\ \ \fP'u .PD0 .. .de EX .CW .nf .. .de EE .fi .. .\" delete above this point if your system has F, L, FR, LR, CW and TF macros .TH EVENT 3G .SH NAME event, einit, estart, etimer, eread, emouse, ekbd, ecanread, ecanmouse, ecankbd, ereshaped, getrect, menuhit, Event, Mouse, Menu \- graphics events .SH SYNOPSIS .nf .B #include .B #include .PP .ta \w'\fLunsigned long 'u .PP .B void einit(ulong keys) .PP .B unsigned long event(Event *e) .PP .B Mouse emouse(void) .PP .B int ekbd(void) .PP .B int ecanmouse(void) .PP .B int ecankbd(void) .PP .B unsigned long estart(ulong key, int fd, int n) .PP .B unsigned long etimer(ulong key, int n) .PP .B unsigned long eread(ulong keys, Event *e) .PP .B int ecanread(ulong keys) .PP .B void ereshaped(Rectangle r) .PP .B Rectangle getrect(int but, Mouse *m) .PP .B int menuhit(int but, Mouse *m, Menu *menu) .PP .ft L enum{ Emouse = 1, Ekeyboard = 2, } .ft P .fi .SH DESCRIPTION These routines provide an interface to multiple sources of input. To use them, .I einit must be called. If the argument to .I enit has the .B Emouse and .B Ekeyboard bits set, the mouse and keyboard events will be enabled; in this case, .IR xtbinit (see .IR graphics (3)) must have already been called. The user must provide a function called .IR ereshaped , which will be called whenever the window in which the process is running has been reshaped; the argument will be the Rectangle for the new window shape, including the border. .PP As characters are typed on the keyboard, they are read by the event mechanism and put in a queue. .I Ekbd returns the next character from the queue, blocking until the queue is non-empty. The characters are read by the event mechanism from the keyboard so they are available as soon as they are typed. .PP When the mouse moves or a mouse button is depressed or released, a new mouse event is queued by the event mechanism. .I Emouse returns the next mouse event from the queue, blocking until the queue is non-empty. .I Emouse returns a .B Mouse structure: .IP .EX .ta 6n +\w'unsigned long 'u struct Mouse { int buttons; Point xy; unsigned long msec; }; .EE .PP .B Buttons is a bit field; .B buttons&1 is set when the left mouse button is depressed, .B buttons&2 when the middle button is depressed, and .B buttons&4 when the right button is depressed. The current mouse position is always returned in .BR xy . .BR Msec is the time stamp of the mouse event in units of milliseconds. .PP .I Ecankbd and .I ecanmouse return non-zero when there are keyboard or mouse events to available to be read. .PP .I Estart can be used to register additional file descriptors. It takes as arguments the file descriptor to register, the maximum length of an event message on that descriptor, and a key to be used in accessing the event. The key must be a power of 2 and must not confilict with any previous keys. If a zero key is given, one which is not used will be chosen and returned. .B Ekeyboard and .B Emouse are the mouse and keyboard event keys. .PP .I Etimer starts a repeating timer with a period of n milliseconds (default 1 second). Only one timer can be started. Extra timer events are not queued and the timer channel has no associated data. .PP .I Eread waits for the next event specified by the mask .B keys of event keys submitted to estart. It fills in the appropriate field of the argument .B Event structure, which looks like: .IP .EX struct Event { int kbdc; Mouse mouse; int n; uchar data[EMAXMSG]; } .EE .PP .B Data is an array which is large enough to hold a plan 9 protocol message. .I Eread returns the key for the event which was chosen. For example, if a mouse event was read, .I Emouse will be returned. .PP .I Event waits for the next event of any kind. The return is the same as for .IR eread . .PP As described in .IR graphics (3), the graphics functions are buffered. .IR Event , .IR eread , .IR emouse , and .I ekbd all cause a buffer flush unless there is an event of the appropriate type ready to return. .PP .I Getrect is used to prompt the user to sweep a rectangle. It should be called with .I m holding the mouse event that triggered the .I getrect (or, if none, a .B Mouse with .B buttons set to 7). It changes to the sweep cursor, waits for the buttons to all go up, and then waits for button number .I but to be depressed, marking the initial corner. If another button is depressed instead, .I getrect returns a rectangle with zero for both x-coordinates, after waiting for all the buttons to be released. Otherwise, .I getrect continually draws the swept rectangle until the button is released again, and returns the swept rectangle. The mouse structure pointed to by .I m will contain the final mouse event. .PP .I Menuhit displays a menu and returns a seleced menu item number. It should be called with .I m holding the mouse event that triggered the .I menuhit . A .B Menu is a structure: .IP .EX struct Menu { char **item; char *(*gen)(int); int lasthit; } .EE .PP If .B item is nonzero, it should be a null-terminated array of the character strings to be displayed as menu items. Otherwise, .B gen should be a function that, given an item number, returns the character string for that item, or zero if the number is past the end of the list. Items are numbered starting at zero. .I Menuhit waits until .I but is released, and then returns the number of the selection, or \(mi1 for no selection. The .I m argument is filled in with the final mouse event. .SH "SEE ALSO" .IR graphics (3). wily-0.13.42/Doc/sam/font.4000064402366570000012000000036301033320152300150160ustar00ozstaff00004330000002.de F .B .if !"\\$1"" \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 .. .de L .B .if !"\\$1"" \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 .. .de FR .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de LR .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de CW .ft B .. .\" This is gross but it avoids relying on internal implementation details .\" of the -man macros. .de TF .IP "" \w'\fB\\$1\ \ \fP'u .PD0 .. .de EX .CW .nf .. .de EE .fi .. .\" delete above this point if your system has F, L, FR, LR, CW and TF macros .TH FONT 4 .SH NAME font, subfont \- external format for fonts and subfonts .SH SYNOPSIS .nf .B #include .B #include .fi .SH DESCRIPTION Fonts and subfonts are described in .IR cachechars (3). .PP External fonts are described by a plain text file that can be read using .I rdfontfile. The format of the file is a header followed by any number of subfont range specifications. The header contains two numbers: the height and the ascent. The height is the inter-line spacing and the ascent is the distance from the top of the line to the baseline. These numbers are chosen to display consistently all the subfonts of the font. A subfont range specification contains two numbers and a font name. The numbers are the inclusive range of characters covered by the subfont, and name specifies the name of an X font suitable for .IR getsubfont . The minimum number of a covered range is mapped to the first defined character of the corresponding subfont. Each field must be followed by some white space. Each numeric field may be C-format decimal, octal, or hexadecimal. .PP Subfonts may be loaded using .IR getsubfont , see .IR graphics (3). .SH BUGS Some X font names contain spaces which will terminate the field. For some fonts this can be worked around by replacing the spaces with .L `*' characters in an attempt to fool the X font name pattern matching mechanism. .SH "SEE ALSO" .IR graphics (3), .IR bitblt (3), .IR cachechars (3). wily-0.13.42/Doc/sam/frame.3000064402366570000012000000143001033320152300151350ustar00ozstaff00004330000002.de F .B .if !"\\$1"" \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 .. .de L .B .if !"\\$1"" \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 .. .de FR .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de LR .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de CW .ft B .. .\" This is gross but it avoids relying on internal implementation details .\" of the -man macros. .de TF .IP "" \w'\fB\\$1\ \ \fP'u .PD0 .. .de EX .CW .nf .. .de EE .fi .. .\" delete above this point if your system has F, L, FR, LR, CW and TF macros .TH FRINIT 3G .SH NAME frinit, frsetrects, frclear, frcharofpt, frptofchar, frinsert, frdelete, frselect, frselectp, frselectf, frgetmouse \- frames of text .SH SYNOPSIS .nf .B #include .B #include .B #include .B #include .PP .B void frinit(Frame *f, Rectangle r, Font *ft, Bitmap *b); .PP .B void frsetrects(Frame *f, Rectangle r, Bitmap *b); .PP .B void frclear(Frame *f); .PP .B ulong frcharofpt(Frame *f, Point pt); .PP .B Point frptofchar(Frame *f, ulong p); .PP .B void frinsert(Frame *f, Rune *r0, Rune *r1, ulong p); .PP .B int frdelete(Frame *f, ulong p0, ulong p1); .PP .B void frselect(Frame *f, Mouse *m); .PP .B void frselectp(Frame *f, Fcode fc); .PP .B void frselectf(Frame *f, Point p0, Point p1, Fcode c); .PP .B extern void frgetmouse(void); .fi .SH DESCRIPTION This library supports .I frames of editable text in a single font on bitmap displays, such as in .IR sam (1), .IR 8\(12 (1), and .IR 9term (1). Frames may hold any character except NUL. Long lines are folded and tabs are at fixed intervals. .PP The user-visible data structure, a .BR Frame , is defined in .BR : .IP .EX .ta 6n +\w'Rectangle 'u +\w'lastlinefull; 'u typedef struct Frame Frame; struct Frame { Font *font; /* of chars in the frame */ Bitmap *b; /* on which frame appears */ Rectangle r; /* in which text appears */ Rectangle entire; /* of full frame */ Frbox *box; ulong p0, p1; /* selection */ short left; /* left edge of text */ ushort nbox, nalloc; ushort maxtab; /* max size of tab, in pixels */ ushort nchars; /* # runes in frame */ ushort nlines; /* # lines with text */ ushort maxlines; /* total # lines in frame */ ushort lastlinefull; /* last line fills frame */ ushort modified; /* changed since frselect() */ }; .EE .PP .B Frbox is an internal type and is not used by the interface. .B P0 and .B p1 may be changed by the application provided the selection routines are called afterwards to maintain a consistent display. .I Maxtab determines the size of tab stops. .I Frinit sets it to 8 times the width of a .B 1 character in the font; it may be changed before any text is added to the frame. The other elements of the structure are maintained by the library and should not be modified directly. .PP There are no routines in the library to allocate .BR Frames ; instead the interface assumes that .B Frames will be components of larger structures. .I Frinit prepares the .B Frame .I f so characters drawn in it will appear in the single .B Font .I ft. It then calls .B frsetrects to initialize the geometry for the .B Frame. The .B Bitmap .I b is where the .B Frame is to be drawn; .B Rectangle .I r defines the limit of the portion of the .B Bitmap the text will occupy. The .B Bitmap pointer may be null, allowing the other routines to be called to maintain the associated data structure in, for example, an obscured window. .PP .I Frclear frees the internal structures associated with .I f, permitting another .I frinit or .I frsetrects on the .BR Frame . If .I f is to be deallocated, the associated .B Font and .B Bitmap must be freed separately. .PP To reshape a .B Frame, use .I frclear and .I frinit and then .I frinsert (q.v.) to recreate the display. If a .B Frame is being moved but not reshaped, that is, if the shape of its containing rectangle is unchanged, it is sufficient to .IR bitblt (3) the containing rectangle from the old to the new location and then call .I frsetrects to establish the new geometry. No redrawing is necessary. .PP .B Frames hold text as runes, not as bytes. .I Frptofchar returns the location of the upper left corner of the .I p'th rune in the .B Frame .I f. If .I f holds fewer than .I p runes, .I frptofchar returns the location of the upper right corner of the last character in .I f. .I Frcharofpt is the inverse: it returns the index of the closest rune whose image's upper left corner is up and to the left of .I pt. .PP .I Frinsert inserts into .B Frame .I f starting at rune index .I p the runes between .I r0 and .I r1. .PP .I Frdelete deletes from the .B Frame the text between .I p0 and .I p1. .PP .I Frselect tracks the mouse to select a contiguous string of text in the .BR Frame . When called, mouse button 1 should be depressed. It will return when the button is released and will set .IB f ->p0 and .IB f ->p1 to the selected range of text. .I Frselectf and .I Frselectp modify the display of the selected text. .I Frselectf highlights the text between .I p0 and .I p1 (which must have been returned by .IR frptofochar ) using .B bitblt in mode .I c. .I Frselectp is similar but highlights the text from .IB f ->p0 to .IB f ->p1 . Neither .I frselectf nor .I frselectp modifies .IB f ->p0 or .IB f ->p1 . .PP Upon return from .I frinsert or .I frdelete, the display will be consistent but .IB f ->p0 and .IB f ->p1 may not point to the desired selection. It may be necessary to adjust the selection and use .I frselectf or .I frselectp to fix the display. .PP .I Frgetmouse must be provided by the application; .I frselect calls it to get mouse updates. Each call to .I frgetmouse should update the .B Mouse structure pointed to by .I frselect's argument .I m. .I Frgetmouse should block until the mouse status has changed. .PP The text within frames is not directly addressable; instead frames are designed to work alongside another structure that holds the text. The typical application is to display a section of a longer document such as a text file or terminal session. Only the text that is visible is held by the .BR Frame ; the application must check .BR maxlines , .BR nlines , and .B lastlinefull to determine, for example, whether new text needs to be appended at the end of the .B Frame after calling .BR frdelete . .SH SEE ALSO .IR graphics (3), .IR bitblt (3), .IR event (3), .IR cachechar (3). wily-0.13.42/Doc/sam/rune.3000064402366570000012000000051051033320152300150170ustar00ozstaff00004330000002.de F .B .if !"\\$1"" \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 .. .de L .B .if !"\\$1"" \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 .. .de FR .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de LR .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de CW .ft B .. .\" This is gross but it avoids relying on internal implementation details .\" of the -man macros. .de TF .IP "" \w'\fB\\$1\ \ \fP'u .PD0 .. .de EX .CW .nf .. .de EE .fi .. .\" delete above this point if your system has F, L, FR, LR, CW and TF macros .TH RUNE 3 .SH NAME runetochar, chartorune, runelen, fullrune, utflen, utfrune, utfrrune, utfutf \- rune/UTF conversion .SH SYNOPSIS .nf .B #include .B int runetochar(char *s, Rune *r) .PP .B int chartorune(Rune *r, char *s) .PP .B int runelen(long r) .PP .B int fullrune(char *s, int n) .PP .B int utflen(char *s) .PP .B char* utfrune(char *s, long c) .PP .B char* utfrrune(char *s, long c) .PP .B char* utfutf(char *s1, char *s2) .fi .SH DESCRIPTION These routines convert to and from a .SM UTF byte stream and runes. .PP .I Runetochar copies one rune at .I r to at most .B UTFmax characters starting at .I s and returns the number of characters copied. .BR UTFmax , defined as .B 3 in .BR , is the maximum number of bytes required to represent a rune. .PP .I Chartorune copies at most .B UTFmax characters starting at .I s to one rune at .I r and returns the number of characters copied. If the characters are not exactly in .SM UTF format, .I chartorune will convert to 0x80 and return 1. .PP .I Runelen returns the number of characters required to convert .I r into .SM UTF. .PP .I Fullrune returns 1 if the string .I s of length .I n is long enough to be decoded by .I chartorune and 0 otherwise. This does not guarantee that the string contains a legal .SM UTF encoding. This routine is used by programs that obtain input a character at a time and need to know when a full rune has arrived. .PP The following routines are analogous to the corresponding string routines with .B utf substituted for .B str and .B rune substituted for .BR chr . .PP .I Utflen returns the number of runes that are represented by the .SM UTF string .IR s . .PP .I Utfrune .RI ( utfrrune ) returns a pointer to the first (last) occurrence of rune .I c in the .SM UTF string .IR s , or 0 if .I c does not occur in the string. The NUL character terminating a string is considered to be part of the string .IR s . .PP .I Utfutf returns a pointer to the first occurrence of the .SM UTF string .I s2 as a .SM UTF substring of .IR s1 , or 0 if there is none. If .I s2 is the null string, .I utfutf returns .IR s1 . .SH SEE ALSO .IR utf (4) wily-0.13.42/Doc/sam/version000064402366570000012000000000571033320152300153730ustar00ozstaff00004330000002Version 4.3 built Mon Mar 27 16:31:38 EST 1995 wily-0.13.42/Doc/sam/balloc.3000064402366570000012000000067751033320152300153200ustar00ozstaff00004330000002.de F .B .if !"\\$1"" \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 .. .de L .B .if !"\\$1"" \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 .. .de FR .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de LR .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de CW .ft B .. .\" This is gross but it avoids relying on internal implementation details .\" of the -man macros. .de TF .IP "" \w'\fB\\$1\ \ \fP'u .PD0 .. .de EX .CW .nf .. .de EE .fi .. .\" delete above this point if your system has F, L, FR, LR, CW and TF macros .TH BALLOC 3G .SH NAME balloc, bfree, rdbitmap, wrbitmap, rdbitmapfile, wrbitmapfile \- allocating, freeing, reading, writing bitmaps .SH SYNOPSIS .nf .PP .B #include .B #include .PP .ta \w'\fLBitmap 'u .B Bitmap *balloc(Rectangle r, int ldepth) .PP .B void bfree(Bitmap *b) .PP .B void rdbitmap(Bitmap *b, int miny, int maxy, uchar *data) .PP .B void wrbitmap(Bitmap *b, int miny, int maxy, uchar *data) .PP .B Bitmap *rdbitmapfile(int fd) .PP .B void wrbitmapfile(int fd, Bitmap *b) .SH DESCRIPTION A new bitmap is allocated with .BR balloc ; it will have the extent and depth given by its arguments, and will be filled with zeros. The .I id field contains the handle of the X .B Pixmap associated with the bitmap and the .I cache field is zero. .I Balloc returns 0 if the server has run out of bitmap resources. .B Bfree frees the resources used by its argument bitmap. .PP The remaining functions deal with moving groups of pixel values between bitmaps and user space or external files. There is a fixed format for the bitmap data in user space or on external files. A pixel with x-coordinate = .I x in a bitmap with .B ldepth = .I l will appear as .if t \fIw\fP = 2\u\s8\fIl\fP\s10\d .if n w = 2^l contiguous bits in a byte, with the pixel's high order bit starting at the byte's bit number .if t \fIw\fP\(mu(\fIx\fP mod 8/\fIw\fP), .if n w*(x mod 8/w), where bits within a byte are numbered 0 to 7 from the high order to the low order bit. If .I w is greater than 8, it is a multiple of 8, so pixel values take up an integral number of bytes. A .I row of bitmap .I b consists of the byte containing pixel .IB b .r.min.x and all the bytes up to and including the byte containing pixel .IB b .r.max.x\fR\(mi1. .PP .I Rdbitmap reads rows of pixels from bitmap .I b into .IR data . The rows read have .IR y = ymin , ymin "+1, ... " .IR ymax \(mi1. Those rows must be within the range allowed by .IB b .r. .PP .B Wrbitmap replaces the specified rows of pixels in bitmap .I b with .IR data . .PP .I Rdbitmapfile creates a bitmap from data contained an external file; .I fd should be a file descriptor obtained by opening such a file for reading. The external file should start with 5 ASCII integers: .BR ldepth , .BR r.min.x , .BR r.min.y , .BR r.max.x , and .BR r.max.y . Each number is right-justified in 11 characters, followed by a blank. The rows of bitmap data, formatted as described above, follow the header. The returned bitmap is allocated using .I balloc . .I Rdbitmapfile returns 0 if the server has run out of bitmap resources. .PP .I Wrbitmapfile writes bitmap .I b onto file descriptor .IR fd , which should be open for writing. The format is as just described for .IR rdbitmapfile . .PP .I Rdbitmapfile and .I wrbitmapfile don't close .IR fd . .PP .SH DIAGNOSTICS Some errors can occur when accessing the internal bitmaps, when trying to malloc, or when trying to read or write the argument file descriptors; the graphics error function (see .IR graphics (3)) is called when this happens. .SH "SEE ALSO" .IR bitmap (6), .IR graphics (3), .IR bitblt (3). wily-0.13.42/Doc/sam/keyboard.4000064402366570000012000000077421033320152300156600ustar00ozstaff00004330000002.de F .B .if !"\\$1"" \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 .. .de L .B .if !"\\$1"" \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 .. .de FR .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de LR .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de CW .ft B .. .\" This is gross but it avoids relying on internal implementation details .\" of the -man macros. .de TF .IP "" \w'\fB\\$1\ \ \fP'u .PD0 .. .de EX .CW .nf .. .de EE .fi .. .\" delete above this point if your system has F, L, FR, LR, CW and TF macros .TH KEYBOARD 4 .SH NAME keyboard \- how to type characters .SH DESCRIPTION Keyboards are idiosyncratic. It should be obvious how to type ordinary .SM ASCII characters, backspace, tab, escape, and newline. In general, the key labeled .B Return or .B Enter generates a newline .RB ( 0x0A ); if there is a key labeled .B Line .BR Feed , it generates a carriage return .RB ( 0x0D ); CRLFs are not used. All control characters are typed in the usual way; in particular, control-J is a line feed and control-M a carriage return. .PP The delete character .RB ( 0x7F ) is usually generated by a key labeled .BI Del , .BI Delete , or .BI Int . .PP The view character .RB ( 0x80 ), .IR sam (1), and .IR 9term (1), causes windows to scroll forward; the back-view character .RB ( 0x81 ), causes windows to scroll backward. The view character is generated by the \(<- and \(da keys; the back-view character is generated by the \(-> and \(ua keys. .PP Internally, characters are represented as runes (see .IR utf (4)). Any 16-bit rune can be typed as a multi-character sequence. The compose key must be pressed while the first character of the sequence is typed; on most terminals, the compose key is labeled .BI Alt . While pressing the compose key, type a capital .L X and exactly four hexadecimal characters (digits and .L a to .LR f ) to enter the rune with the value represented by the typed number. There are two-character shorthands for some characters. The compose key must be pressed while typing the first character of the pair. The following sequences generate the desired rune: .IP .EX .ta 10n +12n +10n +12n +10n +12n +10n +12n +10n \(I! !! \(ct c$ \(po l$ \(gc g$ \($J y$ \(| || \(sc SS \(.. "" \(co cO \(Fo sa \(d< << \(no no [0xad] -- \(rg rO \(ma __ \(de de \(+- +- \(s2 s2 \(s3 s3 \(aa '' [0xb5] mi \(pp pg \(cp .. \(cd ,, \(s1 s1 \(Mo s0 \(d> >> \(14 14 \(12 12 \(34 34 \(I? ?? \(`A `A \('A 'A \(^A ^A \(~A ~A \("A "A \(oA oA \(AE AE \(,C ,C \(`E `E \('E 'E \(^E ^E \("E "E \(`I `I \('I 'I \(^I ^I \("I "I \(D- D- \(~N ~N \(`O `O \('O 'O \(^O ^O \(~O ~O \("O "O \(mu mu \(O/ /O \(`U `U \('U 'U \(^U ^U \("U "U \('Y 'Y \(|P |P \(ss ss \(`a `a \('a 'a \(^a ^a \(~a ~a \("a "a \(oa oa \(ae ae \(,c ,c \(`e `e \('e 'e \(^e ^e \("e "e \('i `i \('i 'i \(^i ^i \("i "i \(d- d- \(~n ~n \(`o `o \('o 'o \(^o ^o \(~o ~o \("o "o \(di -: \(o/ /o \(`u `u \('u 'u \(^u ^u \("u "u \('y 'y \(|p |p \("y "y \(*a *a \(*b *b \(*g *g \(*d *d \(*e *e \(*z *z \(*y *y \(*h *h \(*i *i \(*k *k \(*l *l \(*m *m \(*n *n \(*c *c \(*o *o \(*p *p \(*r *r \(ts ts \(*s *s \(*t *t \(*u *u \(*f *f \(*x *x \(*q *q \(*w *w \(*A *A \(*B *B \(*G *G \(*D *D \(*E *E \(*Z *Z \(*Y *Y \(*H *H \(*I *I \(*K *K \(*L *L \(*M *M \(*N *N \(*C *C \(*O *O \(*P *P \(*R *R \(*S *S \(*T *T \(*U *U \(*F *F \(*X *X \(*Q *Q \(*W *W \(<- <- \(ua ua \(-> -> \(da da \(<> ab \(fa fa \(te te \(pd pd \(es es [0x2206] De \(gr gr \(!m !m [0x220d] st \(** ** \(bu bu \(sr sr \(pt pt \(if if \(ag an \(an l& \(lo l| \(ca ca \(cu cu \(is is \(tf tf [0x2243] ~= \(~= cg [0x2248] ~~ \(!= != \(== == \(<= <= \(>= >= \(sb sb \(sp sp \(!s !b \(ib ib \(ip ip \(a+ O+ [0x2296] O- \(ax Ox [0x22a2] tu [0x22a8] Tu [0x22c4] lz \(el el .EE .PP Note the difference between \(ss (ss) and [0xb5] (micron) and the Greek \(*b and \(*m. As well, white and black chess pieces may be escaped using the sequence color .RB ( w or .BR b ) followed by piece .RB ( k for king, .B q for queen, .B r for rook, .B n for knight, .B b for bishop, or .B p for pawn). .SH "SEE ALSO" .IR ascii (5), .IR sam (1), .IR 9term (1), .IR graphics (3), .IR utf (4) wily-0.13.42/Doc/sam/graphics.3000064402366570000012000000246241033320152300156550ustar00ozstaff00004330000002.de F .B .if !"\\$1"" \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 .. .de L .B .if !"\\$1"" \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 .. .de FR .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de LR .BR "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" .. .de CW .ft B .. .\" This is gross but it avoids relying on internal implementation details .\" of the -man macros. .de TF .IP "" \w'\fB\\$1\ \ \fP'u .PD0 .. .de EX .CW .nf .. .de EE .fi .. .\" delete above this point if your system has F, L, FR, LR, CW and TF macros .TH GRAPHICS 3G .SH NAME Point, Rectangle, Bitmap, Cursor, xtbinit, bclose, berror, bscreenrect, bflush, clipr, cursorswitch, cursorset, rdfontfile, ffree, charwidth, getsubfont, mkfont, scrollfwdbut \- graphics .SH SYNOPSIS .nf .PP .B #include .B #include .PP .ta \w'\fLRectangle 'u .B void xtbinit(void (*errfun)(char *), char *class, int *pargc, .B char **argv, char **fallbacks) .PP .B void bclose(void) .PP .B void berror(char *msg) .PP .B Rectangle bscreenrect(Rectangle *clipr) .PP .B void bflush(void) .PP .B int clipr(Bitmap *b, Rectangle cr) .PP .B void cursorswitch(Cursor *curs) .PP .B void cursorset(Point p) .PP .B Font* rdfontfile(char *name, int ldepth) .PP .B void ffree(Font *f) .PP .B int charwidth(Font *f, Rune r) .PP .B Subfont *getsubfont(char *name) .PP .B Font *mkfont(Subfont *subfont); .PP .B int scrollfwdbut(void); .PP .B extern Bitmap screen .PP .B extern Font *font .fi .SH DESCRIPTION A .B Point is a location in a bitmap (see below), such as the screen, and is defined as: .IP .EX .ta 6n typedef struct Point { int x; int y; } Point; .EE .PP The coordinate system has .I x increasing to the right and .I y increasing down. .PP A .B Rectangle is a rectangular area in a bitmap. .IP .EX .ta 6n typedef struct Rectangle { Point min; /* upper left */ Point max; /* lower right */ } Rectangle; .EE .PP By definition, .B min.x <= max.x and .BR "min.y <= max.y" . By convention, the right (maximum .IR x ) and bottom (maximum .IR y ) edges are excluded from the represented rectangle, so abutting rectangles have no points in common. Thus, .B max contains the coordinates of the first point beyond the rectangle. .PP A .B Bitmap holds a rectangular image. .IP .EX .ta 6n +\w'Rectangle 'u +\w'ldepth; 'u typedef struct Bitmap { Rectangle r; /* rectangle in data area, local coords */ Rectangle clipr; /* clipping region */ int ldepth; /* log base 2 of number of bits per pixel */ int id; /* id as known in the X server */ Bitmap* cache; /* zero; distinguishes bitmap from layer */ int flag; /* flag used by X implementation of libg */ } Bitmap; .EE .PP .B R.min is the location in the bitmap of the upper-leftmost point in the image. There are .if t .I 2\u\s8ldepth\s10\d .if n 2^ldepth contiguous bits for each pixel of the image; the bits form a binary number giving the pixel value. .L Clipr is the clipping rectangle; typically it is the same as .B r except in a window, where it is inset by the width of the border. Graphical operations on the .B Bitmap will be confined to the clipping rectangle. The subroutine .I Clipr sets the clipping rectangle of .B b to the intersection of .B cr and .BR b->r . If .I cr does not intersect .BR b->r it does nothing. .I Clipr returns 1 if the clipping region was set, 0 if it was not. .PP A .B Font is a set of character images, indexed by runes (see .IR utf (4)). The images are organized into .BR Subfont s, each containing the images for a small, contiguous set of runes. .B Font and .B Subfont structures contain two related fields: .LR ascent , the distance from the top of the highest character (actually the top of the bitmap holding all the characters) to the baseline, and .LR height , the distance from the top of the highest character to the bottom of the lowest character (and hence, the interline spacing). The width of any particular character .L r in a font is returned by .IR charwidth. The width is defined as the amount to add to the horizontal position after drawing the character. .I Charwidth calls the graphics error function if .B r is zero (NUL) because .B string (see .IR bitblt (3)) cannot draw a NUL. The other fields are used internally by the text-drawing functions. See .IR cachechars (3) for a detailed description. .PP .I Rdfontfile reads the font description in file .I name and returns a pointer that can by used by .I string (see .IR bitblt (3)) to draw characters from the font. The .I ldepth argument specifies how characters will be cached; it should usually be the ldepth of the bitmap that will most often be the target of .IR string . [ .I ldepth is unused in the X implementation of libg.] .I Ffree frees a font. The convention for naming font files is: .IP .B \fIfontdir\fP/\fIname\fP.\fIrange\fP.\fIsize\fP.font .PD .PP where .I size is approximately the height in pixels of the lower case letters (without ascenders or descenders). .I Range gives some indication of which characters will be available: for example .BR ascii , .BR latin1 , .BR euro , or .BR unicode . .B Euro includes most European languages, punctuation marks, the International Phonetic Alphabet, etc., but no Oriental languages. .B Unicode includes every character for which images exist on the system. .PP A font is selected by notifying the X server of the location of the subfonts and then specifying the desired font file. The directory containing the subfonts must be added to the server's font search path using the .B xset command. For example, .PP .EX xset +fp /usr/local/p9snf .EE .PP adds the directory .B /usr/local/p9snf to the font search path. The .B p9font resource contains the full path name of the desired font file; it is usually specified in the .B .Xdefaults or .B .xrdb startup file. For example, the entry: .PP .EX *p9font: /n/pyxis/usr/local/p9fonts/pelm.unicode.9.font .EE .PP selects the 9-point Pellucida Modern unicode font. .PP A .I Cursor is defined: .IP .EX .ta 6n +\w'Point 'u typedef struct Cursor { Point offset; uchar clr[2*16]; uchar set[2*16]; } Cursor; .EE .PP The arrays are arranged in rows, two bytes per row, left to right in big-endian order to give 16 rows of 16 bits each. A cursor is displayed on the screen by adding .B offset to the current mouse position, using .B clr as a mask to zero the pixels where .B clr is 1, and then setting pixels to ones where .B set is one. .PP The function .I xtbinit should be called before using any graphics operations. The .I errfun argument is a function that will be called with an error message argument when the graphics functions detect an error; such an error function should not return. A zero for the .I errfun argument means use .IR berror , which prints the message and exits. The .I class argument is the name of the class of X application, or zero to use the capitalized version of the program name. The .I pargc and .I argv arguments should be a pointer to the main program's .I argc and .IR argv ; any standard toolkit options in the argument list will be used to initialize the window's options, and after .I xtbinit returns, those options will have been removed from the argument list. The .I fallbacks argument, when non-null, specifies a list of fallback resources for the application. .B Xtbinit sets up the global .I screen to be a bitmap describing the area of the screen that the program can use. .I Xtbinit also initializes the global default .IR font . By default, .I xtbinit does not install the standard Plan 9 colourmap, see .IR rgbpix (3). .PP .I Bclose releases the resources allocated by .I xtbinit and the other graphics functions. It usually isn't necessary, since the resources will be released on program exit. [ .I Bclose is currently unimplemented.] .PP The .IB screen .r field is not guaranteed to be always accurate; the .I bscreenrect function returns the current size (see .IR event (3) to see how to get reshape notification). .PP The mouse cursor is always displayed. The initial cursor is an arrow. .I Cursorswitch causes the argument cursor to be displayed instead. A zero argument causes a switch back to the arrow cursor. .I Cursorset moves the mouse cursor to position .I p, provided (if in a window) that the requesting program is executing in the current window and the mouse is within the window boundaries; otherwise .I cursorset is a no-op. .PP The graphics functions described in .IR bitblt (3) and .IR balloc (3) are implemented by writing commands to the X server; the writes are buffered, so the functions may not take effect immediately. .I Bflush flushes the buffer, doing all pending graphics operations. .I Xtbinit arranges that .I bflush will be called on exit, and the following graphics functions all cause a flush: .IR balloc , .IR bfree , .IR bscreenrect , .IR cursorset , .IR cursorswitch , .IR ecankbd , .IR ecanmouse , .IR ekbd , .IR emouse , .IR event , .IR rdbitmap , and .IR wrbitmap . .PP .I Getsubfont attempts to load the font given by .IR name ; it returns a pointer to a .B Subfont struct if it succeeds, zero otherwise, see .IR font (4). The subfont returned by .I getsubfont may be passed to .I mkfont to generate a .B Font suitable for use in .IR string . .PP .I Scrollfwdbut returns 3 or 1 depending on which buttons is to be used as the forward scrolling button on the mouse. The default is to return 3. .SH "X DEFAULTS" LibXg understands all of the core X Toolkit resource names and classes as well as: .TP 8 .B "p9font (\fPclass\fB P9font)" Specifies the path name of a font file. If the file does not exist or is not a properly formatted font file, the default X11 font directory is searched for an X11 font of the same name. .TP 8 .B "composeMod (\fPclass\fB ComposeMod)" Specifies the modifier key to be used in composing characters. The integers 1 to 5 correspond to using modifier keys 1 to 5. When this resource is non-zero it is only necessary to press the compose modifier once before beginning a compose sequence, i.e., it need not be held down for any of the characters in the sequence. A zero for .B composeMod means use modifier key 1 and this key must be held down in conjuction with the first key of the sequence. .TP 8 .B "scrollForwardR (\fPclass\fB ScrollForwardR)" The value .I true for this resource reverses the value returned by .IR scrollfwdbut , i.e., it returns 3 instead of 1. This reverses the scroll direction selected by clicks of the left or right mouse buttons in the scrollbar. .SH "SEE ALSO" .IR add (3), .IR balloc (3), .IR cachechars (3), .IR bitblt (3), .IR event (3), .IR frame (3), .IR rgbpix (3), .IR bitmap (4), .IR font (4). .SH DIAGNOSTICS An error function may call .IR errstr (2) for further diagnostics. wily-0.13.42/Doc/sam/sam.tut.ms000064402366570000012000001164721033320152300157300ustar00ozstaff00004330000002.de P1 .KS .DS .ft CW .ta 5n 10n 15n 20n 25n 30n 35n 40n 45n 50n 55n 60n 65n 70n 75n 80n .. .de P2 .ft 1 .DE .KE .. .de CW .lg 0 \%\&\\$3\fB\\$1\fP\&\\$2 .lg .. .de WC .lg 0 \%\&\\$3\fI\\$1\fP\&\\$2 .lg .. .TL A tutorial for the .CW sam .B command language .AU Rob Pike .AI .MH .AB .CW sam is an interactive text editor with a command language that makes heavy use of regular expressions. Although the language is syntactically similar to .CW ed (1), the details are interestingly different. This tutorial introduces the command language, but does not discuss the screen and mouse interface. With apologies to those unfamiliar with the Ninth Edition Blit software, it is assumed that the similarity of .CW sam to .CW mux (9) at this level makes .CW sam 's mouse language easy to learn. .PP The .CW sam command language applies identically to two environments: when running .CW sam on an ordinary terminal (\f2via\f1\f1 .CW sam\ -d ), and in the command window of a .I downloaded .CW sam , that is, one using the bitmap display and mouse. .AE .SH Introduction .PP This tutorial describes the command language of .CW sam , an interactive text editor that runs on Blits and some computers with bitmap displays. For most editing tasks, the mouse-based editing features are sufficient, and they are easy to use and to learn. .PP The command language is often useful, however, particularly when making global changes. Unlike the commands in .CW ed , which are necessary to make changes, .CW sam commands tend to be used only for complicated or repetitive editing tasks. It is in these more involved uses that the differences between .CW sam and other text editors are most evident. .PP .CW sam 's language makes it easy to do some things that other editors, including programs like .CW sed and .CW awk , do not handle gracefully, so this tutorial serves partly as a lesson in .CW sam 's manner of manipulating text. The examples below therefore concentrate entirely on the language, assuming that facility with the use of the mouse in .CW sam is at worst easy to pick up. In fact, .CW sam can be run without the mouse at all (not .I downloaded ), by specifying the .CW -d flag, and it is this domain that the tutorial occupies; the command language in these modes are identical. .PP A word to the Unix adept: although .CW sam is syntactically very similar to .CW ed , it is fundamentally and deliberately different in design and detailed semantics. You might use knowledge of .CW ed to predict how the substitute command works, but you'd only be right if you had used some understanding of .CW sam 's workings to influence your prediction. Be particularly careful about idioms. Idioms form in curious nooks of languages and depend on undependable peculiarities. .CW ed idioms simply don't work in .CW sam : .CW 1,$s/a/b/ makes one substitution in the whole file, not one per line. .CW sam has its own idioms. Much of the purpose of this tutorial is to publish them and make fluency in .CW sam a matter of learning, not cunning. .PP The tutorial depends on familiarity with regular expressions, although some experience with a more traditional Unix editor may be helpful. To aid readers familiar with .CW ed , I have pointed out in square brackets [] some of the relevant differences between .CW ed and .CW sam . Read these comments only if you wish to understand the differences; the lesson is about .CW sam , not .CW sam .I vs. .CW ed . Another typographic convention is that output appears in .CW "this font, while typed input appears as .WC "slanty text. .PP Nomenclature: .CW sam keeps a copy of the text it is editing. This copy is called a .I file . To avoid confusion, I have called the permanent storage on disc a .I Unix file. .R .SH Text .PP To get started, we need some text to play with. Any text will do; try something from James Gosling's Emacs manual: .P1 $ \fIsam -d a This manual is organized in a rather haphazard manner. The first several sections were written hastily in an attempt to provide a general introduction to the commands in Emacs and to try to show the method in the madness that is the Emacs command structure. \&. .ft .P2 .WC "sam -d starts .CW sam running. The .CW a command adds text until a line containing just a period, and sets the .I current text .R (also called .I dot ) to what was typed \(em everything between the .CW a and the period. .CW ed "" [ would leave dot set to only the last line.] The .CW p command prints the current text: .P1 .WC p This manual is organized in a rather haphazard manner. The first several sections were written hastily in an attempt to provide a general introduction to the commands in Emacs and to try to show the method in the madness that is the Emacs command structure. .P2 [Again, .CW ed would print only the last line.] The .CW a command adds its text .I after dot; the .CW i command is like .CW a, but adds the text .I before dot. .P1 .ft I i Introduction \&. p .ft Introduction .P2 There is also a .CW c command that changes (replaces) the current text, and .CW d that deletes it; these are illustrated below. .PP To see all the text, we can specify what text to print; for the moment, suffice it to say that .WC 0,$ specifies the entire file. .CW ed "" [ users would probably type .WC 1,$ , which in practice is the same thing, but see below.] .P1 .WC 0,$p Introduction This manual is organized in a rather haphazard manner. The first several sections were written hastily in an attempt to provide a general introduction to the commands in Emacs and to try to show the method in the madness that is the Emacs command structure. .P2 Except for the .CW w command described below, .I all commands, including .CW p , set dot to the text they touch. Thus, .CW a and .CW i set dot to the new text, .CW p to the text printed, and so on. Similarly, all commands (except .CW w ) by default operate on the current text [unlike .CW ed , for which some commands (such as .CW g ) default to the entire file]. .PP Things are not going to get very interesting until we can set dot arbitrarily. This is done by .I addresses , which specify a piece of the file. The address .CW 1 , for example, sets dot to the first line of the file. .P1 .WC 1p Introduction .WC c .WC Preamble .WC . .P2 The .CW c command didn't need to specify dot; the .CW p left it on line one. It's therefore easy to delete the first line utterly; the last command left dot set to line one: .P1 .WC d .WC 1p This manual is organized in a rather haphazard manner. The first .P2 (Line numbers change to reflect changes to the file.) .PP The address \f(CW/\f2text\f(CW/\f1 sets dot to the first appearance of .I text , after dot. .CW ed "" [ matches the first line containing .I text .] If .I text is not found, the search restarts at the beginning of the file and continues until dot. .P1 .WC /Emacs/p Emacs .P2 It's difficult to indicate typographically, but in this example no newline appears after .CW Emacs : the text to be printed is the string .CW Emacs ', ` exactly. (The final .CW p may be left off \(em it is the default command. When downloaded, however, the default is instead to select the text, to highlight it, and to make it visible by moving the window on the file if necessary. Thus, .CW /Emacs/ indicates on the display the next occurrence of the text.) .PP Imagine we wanted to change the word .CW haphazard to .CW thoughtless . Obviously, what's needed is another .CW c command, but the method used so far to insert text includes a newline. The syntax for including text without newlines is to surround the text with slashes (which is the same as the syntax for text searches, but what is going on should be clear from context). The text must appear immediately after the .CW c (or .CW a or .CW i ). Given this, it is easy to make the required change: .P1 .WC /haphazard/c/thoughtless/ 1p This manual is organized in a rather thoughtless manner. The first .P2 [Changes can always be done with a .CW c command, even if the text is smaller than a line]. You'll find that this way of providing text to commands is much more common than is the multiple-lines syntax. If you want to include a slash .CW / in the text, just precede it with a backslash .CW \e , and use a backslash to protect a backslash itself. .P1 .WC /Emacs/c/Emacs\e\e360/ .WC 4p general introduction to the commands in Emacs\e360 and to try to show .P2 We could also make this particular change by .P1 .WC /Emacs/a/\e\e360/ .P2 .PP This is as good a place as any to introduce the .CW u command, which undoes the last command. A second .CW u will undo the penultimate command, and so on. .P1 .WC u .WC 4p general introduction to the commands in Emacs and to try to show .WC u .WC 3p This manual is organized in a rather haphazard manner. The first .P2 Undoing can only back up; there is no way to undo a previous .CW u . .SH Addresses .PP We've seen the simplest forms of addresses, but there is more to learn before we can get too much further. An address selects a region in the file \(em a substring \(em and therefore must define the beginning and the end of a region. Thus, the address .CW 13 selects from the beginning of line thirteen to the end of line thirteen, and .CW /Emacs/ selects from the beginning of the word .CW Emacs ' ` to the end. .PP Addresses may be combined with a comma: .P1 13,15 .P2 selects lines thirteen through fifteen. The definition of the comma operator is to select from the beginning of the left hand address (the beginning of line 13) to the end of the right hand address (the end of line 15). .PP A few special simple addresses come in handy: .CW . (a period) represents dot, the current text, .CW 0 (line zero) selects the null string at the beginning of the file, and .CW $ selects the null string at the end of the file [not the last line of the file]. Therefore, .P1 0,13 .P2 selects from the beginning of the file to the end of line thirteen, .P1 \&.,$ .P2 selects from the beginning of the current text to the end of the file, and .P1 0,$ .P2 selects the whole file [that is, a single string containing the whole file, not a list of all the lines in the file]. .PP These are all .I absolute addresses: they refer to specific places in the file. .CW sam also has relative addresses, which depend on the value of dot, and in fact we have already seen one form: .CW /Emacs/ finds the first occurrence of .CW Emacs searching forwards from dot. Which occurrence of .CW Emacs it finds depends on the value of dot. What if you wanted the first occurrence .CW before dot? Just precede the pattern with a minus sign, which reverses the direction of the search: .P1 -/Emacs/ .P2 In fact, the complete syntax for forward searching is .P1 +/Emacs/ .P2 but the plus sign is the default, and in practice is rarely used. Here is an example that includes it for clarity: .P1 0+/Emacs/ .P2 selects the first occurrence of .CW Emacs in the file; read it as ``go to line 0, then search forwards for .CW Emacs .'' Since the .CW + is optional, this can be written .CW 0/Emacs/ . Similarly, .P1 $-/Emacs/ .P2 finds the last occurrence in the file, so .P1 0/Emacs/,$-/Emacs/ .P2 selects the text from the first to last .CW Emacs , inclusive. Slightly more interesting: .P1 /Emacs/+/Emacs/ .P2 (there is an implicit .CW .+ at the beginning) selects the second .CW Emacs following dot. .PP Line numbers may also be relative. .P1 -2 .P2 selects the second previous line, and .P1 +5 .P2 selects the fifth following line (here the plus sign is obligatory). .PP Since addresses may select (and dot may be) more than one line, we need a definition of `previous' and `following:' `previous' means .I before the beginning .R of dot, and `following' means .I after the end .R of dot. For example, if the file contains \fBA\fIAA\fBA\f1, with dot set to the middle two .CW A 's (the slanting characters), .CW -/A/ sets dot to the first .CW A , and .CW +/A/ sets dot to the last .CW A . Except under odd circumstances (such as when the only occurrence of the text in the file is already the current text), the text selected by a search will be disjoint from dot. .PP To select the .CW "troff -ms paragraph containing dot, however long it is, use .P1 -/.PP/,/.PP/-1 .P2 which will include the .CW .PP that begins the paragraph, and exclude the one that ends it. .PP When typing relative line number addresses, the default number is .CW 1 , so the above could be written slightly more simply: .P1 -/.PP/,/.PP/- .P2 .PP What does the address .CW +1-1 or the equivalent .CW +- mean? It looks like it does nothing, but recall that dot need not be a complete line of text. .CW +1 selects the line after the end of the current text, and .CW -1 selects the line before the beginning. Therefore .CW +1-1 selects the line before the line after the end of dot, that is, the complete line containing the end of dot. We can use this construction to expand a selection to include a complete line, say the first line in the file containing .CW Emacs : .P1 .WC 0/Emacs/+-p general introduction to the commands in Emacs and to try to show .P2 The address .CW +- is an idiom. .SH Loops .PP Above, we changed one occurrence of .CW Emacs to .CW Emacs\e360 , but if the name of the editor is really changing, it would be useful to change .I all instances of the name in a single command. .CW sam provides a command, .CW x (extract), for just that job. The syntax is \f(CWx/\f2pattern\f(CW/\f2command\f1. For each occurrence of the pattern in the selected text, .CW x sets dot to the occurrence and runs command. For example, to change .CW Emacs to .CW vi, .P1 .WC 0,$x/Emacs/c/vi/ .WC 0,$p This manual is organized in a rather haphazard manner. The first several sections were written hastily in an attempt to provide a general introduction to the commands in vi and to try to show the method in the madness that is the vi command structure. .P2 This works by subdividing the current text .CW 0,$ "" ( \(em the whole file) into appearances of its textual argument .CW Emacs ), ( and then running the command that follows .CW c/vi/ ) ( with dot set to the text. We can read this example as, ``find all occurrences of .CW Emacs in the file, and for each one, set the current text to the occurrence and run the command .CW c/vi/ , which will replace the current text by .CW vi. '' [This command is somewhat similar to .CW ed 's .CW g command. The differences will develop below, but note that the default address, as always, is dot rather than the whole file.] .PP A single .CW u command is sufficient to undo an .CW x command, regardless of how many individual changes the .CW x makes. .P1 .WC u .WC 0,$p This manual is organized in a rather haphazard manner. The first several sections were written hastily in an attempt to provide a general introduction to the commands in Emacs and to try to show the method in the madness that is the Emacs command structure. .P2 .PP Of course, .CW c is not the only command .CW x can run. An .CW a command can be used to put proprietary markings on .CW Emacs : .P1 .WC 0,$x/Emacs/a/{TM}/ .WC /Emacs/+-p general introduction to the commands in Emacs{TM} and to try to show .P2 [There is no way to see the changes as they happen, as in .CW ed 's .CW g/Emacs/s//&{TM}/p ; see the section on Multiple Changes, below.] .PP The .CW p command is also useful when driven by an .CW x , but be careful that you say what you mean; .P1 .WC 0,$x/Emacs/p EmacsEmacs .P2 since .CW x sets dot to the text in the slashes, printing only that text is not going to be very informative. But the command that .CW x runs can contain addresses. For example, if we want to print all lines containing .CW Emacs , just use .CW +- : .P1 .WC 0,$x/Emacs/+-p general introduction to the commands in Emacs{TM} and to try to show the method in the madness that is the Emacs{TM} command structure. .P2 Finally, let's restore the state of the file with another .CW x command, and make use of a handy shorthand: a comma in an address has its left side default to .CW 0 , and its right side default to .CW $ , so the easy-to-type address .CW , refers to the whole file: .P1 .WC ",x/Emacs/ /{TM}/d .WC ,p This manual is organized in a rather haphazard manner. The first several sections were written hastily in an attempt to provide a general introduction to the commands in Emacs and to try to show the method in the madness that is the Emacs command structure. .P2 Notice what this .CW x does: for each occurrence of Emacs, find the .CW {TM} that follows, and delete it. .PP The `text' .CW sam accepts for searches in addresses and in .CW x commands is not simple text, but rather .I regular\ expressions. Unix has several distinct interpretations of regular expressions. The form used by .CW sam is that of .CW regexp (6), including parentheses .CW () for grouping and an `or' operator .CW | for matching strings in parallel. .CW sam also matches the character sequence .CW \en with a newline character. Replacement text, such as used in the .CW a and .CW c commands, is still plain text, but the sequence .CW \en represents newline in that context, too. .PP Here is an example. Say we wanted to double space the document, that is, turn every newline into two newlines. The following all do the job: .P1 .WC ",x/\en/ a/\en/ .WC ",x/\en/ c/\en\en/ .WC ",x/$/ a/\en/ .WC ",x/^/ i/\en/ .P2 The last example is slightly different, because it puts a newline .I before each line; the other examples place it after. The first two examples manipulate newlines directly [something outside .CW ed 's ken]; the last two use regular expressions: .CW $ is the empty string at the end of a line, while .CW ^ is the empty string at the beginning. .PP These solutions all have a possible drawback: if there is already a blank line (that is, two consecutive newlines), they make it much larger (four consecutive newlines). A better method is to extend every group of newlines by one: .P1 .WC ",x/\en+/ a/\en/ .P2 The regular expression operator .CW + means `one or more;' .CW \en+ is identical to .CW \en\en* . Thus, this example takes every sequence of newlines and adds another to the end. .PP A more common example is indenting a block of text by a tab stop. The following all work, although the first is arguably the cleanest (the blank text in slashes is a tab): .P1 .WC ",x/^/a/ / .WC ",x/^/c/ / .WC ",x/.*\en/i/ / .P2 The last example uses the pattern (idiom, really) .CW .*\en to match lines: .CW .* matches the longest possible string of non-newline characters. Taking initial tabs away is just as easy: .P1 .WC ",x/^ /d .P2 In these examples I have specified an address (the whole file), but in practice commands like these are more likely to be run without an address, using the value of dot set by selecting text with the mouse. .SH Conditionals .PP The .CW x command is a looping construct: for each match of a regular expression, it extracts (sets dot to) the match and runs a command. .CW sam also has a conditional, .CW g : \f(CWg/\f2pattern\f(CW/\f2command\f1 runs the command if dot contains a match of the pattern .I without changing the value of dot. .R The inverse, .CW v , runs the command if dot does .I not contain a match of the pattern. (The letters .CW g and .CW v are historical and have no mnemonic significance. You might think of .CW g as `guard.') .CW ed "" [ users should read the above definitions very carefully; the .CW g command in .CW sam is fundamentally different from that in .CW ed .] Here is an example of the difference between .CW x and .CW g: .P1 ,x/Emacs/c/vi/ .P2 changes each occurrence of the word .CW Emacs in the file to the word .CW vi , but .P1 ,g/Emacs/c/vi/ .P2 changes the .I "whole file to .CW vi if there is the word .CW Emacs anywhere in the file. .PP Neither of these commands is particularly interesting in isolation, but they are valuable when combined with .CW x and with themselves. .SH Composition .PP One way to think about the .CW x command is that, given a selection (a value of dot) it iterates through interesting subselections (values of dot within). In other words, it takes a piece of text and cuts it into smaller pieces. But the text that it cuts up may already be a piece cut by a previous .CW x command or selected by a .CW g . .CW sam 's most interesting property is the ability to define a sequence of commands to perform a particular task.\(dg .FS \(dg The obvious analogy with shell pipelines is only partially valid, because the individual .CW sam commands are all working on the same text; it is only how the text is sliced up that is changing. .FE A simple example is to change all occurrences of .CW Emacs to .CW emacs ; certainly the command .P1 .WC ",x/Emacs/ c/emacs/ .P2 will work, but we can use an .CW x command to save retyping most of the word .CW Emacs : .P1 .WC ",x/Emacs/ x/E/ c/e/ .P2 (Blanks can be used to separate commands on a line to make them easier to read.) What this command does is find all occurrences of .CW Emacs .CW ,x/Emacs/ ), ( and then .I with dot set to that text, .R find all occurrences of the letter .CW E .CW x/E/ ), ( and then .I with dot set to that text, .R run the command .CW c/e/ to change the character to lower case. Note that the address for the command \(em the whole file, specified by a comma \(em is only given to the leftmost piece of the command; the rest of the pieces have dot set for them by the execution of the pieces to their left. .PP As another simple example, consider a problem solved above: printing all lines in the file containing the word .CW Emacs: .P1 .WC ",x/.*\en/ g/Emacs/p general introduction to the commands in Emacs and to try to show the method in the madness that is the Emacs command structure. .P2 This command says to break the file into lines .CW ,x/.*\en/ ), ( and for each line that contains the string .CW Emacs .CW g/Emacs/ ), ( run the command .CW p with dot set to the line (not the match of .CW Emacs ), which prints the line. To save typing, because .CW .*\en is a common pattern in .CW x commands, if the .CW x is followed immediately by a space, the pattern .CW .*\en is assumed. Therefore, the above could be written more succinctly: .P1 .WC ",x g/Emacs/p .P2 The solution we used before was .P1 .WC ,x/Emacs/+-p .P2 which runs the command .CW +-p with dot set to each match of .CW Emacs in the file (recall that the idiom .CW +-p prints the line containing the end of dot). .PP The two commands usually produce the same result (the .CW +-p form will print a line twice if it contains .CW Emacs twice). Which is better? .CW ,x/Emacs/+-p is easier to type and will be much faster if the file is large and there are few occurrences of the string, but it is really an odd special case. .CW ",x/.*\en/ g/Emacs/p is slower \(em it breaks each line out separately, then examines it for a match \(em but is conceptually cleaner, and generalizes more easily. For example, consider the following piece of the Emacs manual: .P1 command name="append-to-file", key="[unbound]" Takes the contents of the current buffer and appends it to the named file. If the file doesn't exist, it will be created. command name="apropos", key="ESC-?" Prompts for a keyword and then prints a list of those commands whose short description contains that keyword. For example, if you forget which commands deal with windows, just type "@b[ESC-?]@t[window]@b[ESC]". \&\f2and so on\f(CW .P2 This text consists of groups of non-empty lines, with a simple format for the text within each group. Imagine that we wanted to find the description of the `apropos' command. The problem is to break the file into individual descriptions, and then to find the description of `apropos' and to print it. The solution is straightforward: .P1 .WC ,x/(.+\en)+/\ g/command\ name="apropos"/p command name="apropos", key="ESC-?" Prompts for a keyword and then prints a list of those commands whose short description contains that keyword. For example, if you forget which commands deal with windows, just type "@b[ESC-?]@t[window]@b[ESC]". .P2 The regular expression .CW (.+\en)+ matches one or more lines with one or more characters each, that is, the text between blank lines, so .CW ,x/(.+\en)+/ extracts each description; then .CW g/command\ name="apropos"/ selects the description for `apropos' and .CW p prints it. .PP Imagine that we had a C program containing the variable .CW n , but we wanted to change it to .CW num . This command is a first cut: .P1 .WC ",x/n/ c/num/ .P2 but is obviously flawed: it will change all .CW n 's in the file, not just the .I identifier .CW n . A better solution is to use an .CW x command to extract the identifiers, and then use .CW g to find the .CW n 's: .P1 .WC ",x/[a-zA-Z_][a-zA-Z_0-9]*/ g/n/ v/../ c/num/ .P2 It looks awful, but it's fairly easy to understand when read left to right. A C identifier is an alphabetic or underscore followed by zero or more alphanumerics or underscores, that is, matches of the regular expression .CW [a-zA-Z_][a-zA-Z_0-9]* . The .CW g command selects those identifiers containing .CW n , and the .CW v is a trick: it rejects those identifiers containing more than one character. Hence the .CW c/num/ applies only to free-standing .CW n 's. .PP There is still a problem here: we don't want to change .CW n 's that are part of the character constant .CW \en . There is a command .CW y , complementary to .CW x , that is just what we need: \f(CWy/\f2pattern\f(CW/\f2command\f1 runs the command on the pieces of text .I between matches of the pattern; if .CW x selects, .CW y rejects. Here is the final command: .P1 .WC ",y/\e\en/ x/[a-zA-Z_][a-zA-Z_0-9]*/ g/n/ v/../ c/num/ .P2 The .CW y/\e\en/ (with backslash doubled to make it a literal character) removes the two-character sequence .CW \en from consideration, so the rest of the command will not touch it. There is more we could do here; for example, another .CW y could be prefixed to protect comments in the code. I won't elaborate the example any further, but you should have an idea of the way in which the looping and conditional commands in .CW sam may be composed to do interesting things. .SH Grouping .PP There is another way to arrange commands. By enclosing them in brace brackets .CW {} , commands may be applied in parallel. This example uses the .CW = command, which reports the line and character numbers of dot, together with .CW p , to report on appearances of .CW Emacs in our original file: .P1 .WC ,p This manual is organized in a rather haphazard manner. The first several sections were written hastily in an attempt to provide a general introduction to the commands in Emacs and to try to show the method in the madness that is the Emacs command structure. .ft I ,x/Emacs/{ = +-p } .ft 3; #171,#176 general introduction to the commands in Emacs and to try to show 4; #234,#239 the method in the madness that is the Emacs command structure. .P2 (The number before the semicolon is the line number; the numbers beginning with .CW # are character numbers.) As a more interesting example, consider changing all occurrences of .CW Emacs to .CW vi and vice versa. We can type .P1 .ft I ,x/Emacs|vi/{ g/Emacs/ c/vi/ g/vi/ c/Emacs/ } .ft .P2 or even .P1 .ft I ,x/[a-zA-Z]+/{ g/Emacs/ v/....../ c/vi/ g/vi/ v/.../ c/Emacs/ } .ft .P2 to make sure we don't change strings embedded in words. .SH Multiple Changes .PP You might wonder why, once .CW Emacs has been changed to .CW vi in the above example, the second command in the braces doesn't put it back again. The reason is that the commands are run in parallel: within any top-level .CW sam command, all changes to the file refer to the state of the file before any of the changes in that command are made. After all the changes have been determined, they are all applied simultaneously. .PP This means, as mentioned, that commands within a compound command see the state of the file before any of the changes apply. This method of evaluation makes some things easier (such as the exchange of .CW Emacs and .CW vi ), and some things harder. For instance, it is impossible to use a .CW p command to print the changes as they happen, because they haven't happened when the .CW p is executed. An indirect ramification is that changes must occur in forward order through the file, and must not overlap. .SH Unix .PP .CW sam has a few commands to connect to Unix processes. The simplest is .CW ! , which runs the command with input and output connected to the terminal. .P1 .WC !date Wed May 28 23:25:21 EDT 1986 ! .P2 (When downloaded, the input is connected to .CW /dev/null and only the first few lines of output are printed; any overflow is stored in .CW $HOME/sam.err .) The final .CW ! is a prompt to indicate when the command completes. .PP Slightly more interesting is .CW > , which provides the current text as standard input to the Unix command: .P1 .WC "1,2 >wc 2 22 131 ! .P2 The complement of .CW > is, naturally, .CW < : it replaces the current text with the standard output of the Unix command: .P1 .WC "1 : the current text is provided as standard input to the Unix command, and the Unix command's standard output is collected and used to replace the original text. For example, .P1 .WC ",| sort .P2 runs .CW sort (1) on the file, sorting the lines of the text lexicographically. Note that .CW < , .CW > and .CW | are .CW sam commands, not Unix shell operators. .PP The next example converts all appearances of .CW Emacs to upper case using .CW tr (1): .P1 .WC ",x/Emacs/ | tr a-z A-Z .P2 .CW tr is run once for each occurrence of .CW Emacs . Of course, you could do this example more efficiently with a simple .CW c command, but here's a trickier one: given a Unix mail box as input, convert all the .CW Subject headers to distinct fortunes: .P1 .WC ",x/^Subject:.*\en/ x/[^:]*\en/ < /usr/games/fortune .P2 (The regular expression .CW [^:] refers to any character .I except .CW : and newline; the negation operator .CW ^ excludes newline from the list of characters.) Again, .CW /usr/games/fortune is run once for each .CW Subject line, so each .CW Subject line is changed to a different fortune. .SH A few other text commands .PP For completeness, I should mention three other commands that manipulate text. The .CW m command moves the current text to after the text specified by the (obligatory) address after the command. Thus .P1 .WC "/Emacs/+- m 0 .P2 moves the next line containing .CW Emacs to the beginning of the file. Similarly, .CW t (another historic character) copies the text: .P1 .WC "/Emacs/+- t 0 .P2 would make, at the beginning of the file, a copy of the next line containing .CW Emacs . .PP The third command is more interesting: it makes substitutions. Its syntax is \f(CWs/\f2pattern\f(CW/\f2replacement\f(CW/\f1. Within the current text, it finds the first occurrence of the pattern and replaces it by the replacement text, leaving dot set to the entire address of the substitution. .P1 .WC 1p This manual is organized in a rather haphazard manner. The first .WC s/haphazard/thoughtless/ .WC p This manual is organized in a rather thoughtless manner. The first .P2 Occurrences of the character .CW & in the replacement text stand for the text matching the pattern. .P1 .WC s/T/"&&&&"/ .WC p "TTTT"his manual is organized in a rather thoughtless manner. The first .P2 There are two variants. The first is that a number may be specified after the .CW s , to indicate which occurrence of the pattern to substitute; the default is the first. .P1 .WC s2/is/was/ .WC p "TTTT"his manual was organized in a rather thoughtless manner. The first .P2 The second is that suffixing a .CW g (global) causes replacement of all occurrences, not just the first. .P1 .WC s/[a-zA-Z]/x/g .WC p "xxxx"xxx xxxxxx xxx xxxxxxxxx xx x xxxxxx xxxxxxxxxxx xxxxxxx xxx xxxxx .P2 Notice that in all these examples dot is left set to the entire line. .PP [The substitute command is vital to .CW ed, because it is the only way to make changes within a line. It is less valuable in .CW sam , in which the concept of a line is much less important. For example, many .CW ed substitution idioms are handled well by .CW sam 's basic commands. Consider the commands .P1 s/good/bad/ s/good// s/good/& bye/ .P2 which are equivalent in .CW sam to .P1 /good/c/bad/ /good/d /good/a/ bye/ .P2 and for which the context search is likely unnecessary because the desired text is already dot. Also, beware this .CW ed idiom: .P1 1,$s/good/bad/ .P2 which changes the first .CW good on each line; the same command in .CW sam will only change the first one in the whole file. The correct .CW sam version is .P1 ,x s/good/bad/ .P2 but what is more likely meant is .P1 ,x/good/ c/bad/ .P2 .CW sam operates under different rules.] .SH Files .PP So far, we have only been working with a single file, but .CW sam is a multi-file editor. Only one file may be edited at a time, but it is easy to change which file is the `current' file for editing. To see how to do this, we need a .CW sam with a few files; the easiest way to do this is to start it with a list of Unix file names to edit. .P1 $ \fIecho *.ms\f(CW conquest.ms death.ms emacs.ms famine.ms slaughter.ms $ \fIsam -d *.ms\f(CW -. conquest.ms .P2 (I'm sorry the Horsemen don't appear in liturgical order.) The line printed by .CW sam is an indication that the Unix file .CW conquest.ms has been read, and is now the current file. .CW sam does not read the Unix file until the associated .CW sam file becomes current. .PP The .CW n command prints the names of all the files: .P1 .WC n -. conquest.ms - death.ms - emacs.ms - famine.ms - slaughter.ms .P2 This list is also available in the menu on mouse button 3. The command .CW f tells the name of just the current file: .P1 .WC f -. conquest.ms .P2 The characters to the left of the file name encode helpful information about the file. The minus sign becomes a plus sign if the file has a window open, and an asterisk if more than one is open. The period (another meaning of dot) identifies the current file. The leading blank changes to an apostrophe if the file is different from the contents of the associated Unix file, as far as .CW sam knows. This becomes evident if we make a change. .P1 .WC 1d .WC f \&'-. conquest.ms .P2 If the file is restored by an undo command, the apostrophe disappears. .P1 .WC u .WC f -. conquest.ms .P2 The file name may be changed by providing a new name with the .CW f command: .P1 .CW "f pestilence.ms \&'-. pestilence.ms .P2 .WC f prints the new status of the file, that is, it changes the name if one is provided, and prints the name regardless. A file name change may also be undone. .P1 .WC u .WC f -. conquest.ms .P2 .PP When .CW sam is downloaded, the current file may be changed simply by selecting the desired file from the menu (selecting the same file subsequently cycles through the windows opened on the file). Otherwise, the .CW b command can be used to choose the desired file:\(dg .FS \(dg A bug prevents the .CW b command from working when downloaded. Because the menu is more convenient anyway, and because the method of choosing files from the command language is slated to change, the bug hasn't been fixed. .FE .P1 .WC "b emacs.ms -. emacs.ms .P2 Again, .CW sam prints the name (actually, executes an implicit .CW f command) because the Unix file .CW emacs.ms is being read for the first time. It is an error to ask for a file .CW sam doesn't know about, but the .CW B command will prime .CW sam 's menu with a new file, and make it current. .P1 .WC "b flood.pic ?no such file `flood.pic' .WC "B flood.pic -. flood.pic .WC n - conquest.ms - death.ms - emacs.ms - famine.ms -. flood.pic - slaughter.ms .P2 Both .CW b and .CW B will accept a list of file names. .CW b simply takes the first file in the list, but .CW B loads them all. The list may be typed on one line \(em .P1 .WC "B devil.tex satan.tex 666.tex emacs.tex .P2 \(em or generated by a Unix command \(em .P1 .WC "B core dump ************ DOCO *************** list of pointers to unicode software make it easy to install/use fonts add "what about a win 3.1/95/NT port" FAQ entry ************ PORTABILITY BUGS *************** ************ IMPORTANT FEATURES *************** Use empty space when placing new windows (bill) tab argument use -tab instead of -a ************ FEATURES *************** persistence (Load/Store) Check file mod. time, stop you from overwriting changed file full Sam regexps full Sam commands argument to Font wilyproxy empty columns should still have a vertical line tag should indicate if it isn't displaying everything give tags different background colour international characters entry use X11R6 "input extensions"? (schwartz) extra process monitors (and modifies) inputted text (Steve_Kilbane) newline in tag on _directory_ could mean 'open that directory' scrolling tag -- always show RIGHTmost stuff experiment with DontList _regexp_ to restrict directory listings dir.c:#1227 (Elliott Hughes) -title option check out joe: claims: Joe uses the Boyer-Moore algorithm adapted for segmented blocks. This more than overcomes the simplicity you would get by having only a single gap. ************ EXPERIMENT *************** running autosave? "Get" builtin, like Look but for addresses, perhaps called ':' wily-0.13.42/Doc/tute/000075502366570000012000000000001033320152300141625ustar00ozstaff00004330000002wily-0.13.42/Doc/tute/start000064402366570000012000000225451033320152300152520ustar00ozstaff00004330000002 START HERE Hello, welcome to wily. Once you've finished this tutorial you will know nearly all of wily's features, and hopefully be addicted. Wily is quite different from any editor you're already familiar with, but it isn't difficult to learn the wily way. TERMINOLOGY B1, B2, B3 mean left, middle and right mouse buttons. Each window is divided into a _tag_ (the single line of text which has the filename in it and is at the top of the window) and a _body_ (the big area below the tag where all the "meat" of the file is). SCROLLING UP AND DOWN The Scroll-bar The scrollbar is the vertical bar to the left. Clicking in it with different mouse buttons scrolls the text window. Move the cursor into the scrollbar next to this line, and click B3. The line should have moved to the top of the window. Don't move the cursor, and click with B1. The line should move back down so its next to the cursor again. You can see that B1 and B3 in the scrollbar are good for _relative_ movement. How far the text "jumps" depends on how far down the scrollbar you click. Use B2 in the scroll bar for _absolute_ positioning. For example, to get to the top of this file, click with B2 in the scroll bar, at the very top of the scroll bar. Try jumping quickly to the top and bottom of the file using B2. The "thumb" on the scrollbar (the bit which isn't "greyed out") indicates where our visible region is in relation to the whole file, and how big our visible region is in relation to the whole file. If you hold a mouse button down in the scroll bar, the window will keep scrolling. Movement keys The PageUp and PageDown keys move the text window up or down by 1/2 a window. The Home and End keys move the window to the top or bottom of the document. The arrow keys move the "selection" by one character or line. Try these out now. B3 MEANS "GOTO" B3 (the rightmost mouse button) is also known as the "goto" button. Selecting some text (or clicking in some text) with the rightmost button makes wily "goto" that text. What this means depends on what the text is. Before you start: clicking with B3 will create some new windows. When you want to get rid of a window, look for the word "Del" somewhere in that window, and click on that word with B2. We'll learn later why this works. Try clicking with the rightmost mouse button in some of these examples: (NB wily will warp the cursor to the place you "goto"--nine times out of ten this is what you want) hello.c hello.c:3 hello.c:/^main hello.c:/p.*f FNORD Gnu FNORD $HOME As you can see, you can "goto" a file, a directory, a specific line of a file, a regular expression within a file, an environment variable that represents any of these, or the next occurrence of a piece of text. You can use the "goto" mouse button on _any_ piece of text _anywhere_ in wily. B2 MEANS "exec" This is also known as the "exec" button. Selecting some text (or clicking in some text) with the middle mouse button makes wily _execute_ that text. If the command which is executed produces any output, it will be sent to another wily window (which will be created if necessary). Try clicking with the middle mouse button in some of these examples: who pwd id date ./script Builtin Functions Wily provides some builtin functions which it searches for first when asked to "exec" some text. By convention, these all start with capital letters. You will see most of them on the screen right now. For example, to exit wily, (don't do this now!), you would click with the "exec" (middle) mouse button somewhere in the word "Quit". To delete a window, click with the "exec" (middle) mouse button (but not right now) on the word "Del" somewhere in that window. B1 MEANS "select" This is also known as the "select" button. This button is used to select text, to be acted on later. Selected text is highlighted (in reverse video). Text typed with the keyboard replaces the current selection. Double-clicking with the left mouse button selects a word, a line, or the text delimited by quote marks, braces or brackets, depending on where the double-click occurs. The "exec" (middle) and "goto" (right) mouse buttons will use an existing selection if they are clicked inside it. Try this now: double-click just inside the quotation marks in the paragraph below to _select_ the complex command, then click with the "exec" (middle) mouse button in the selection (reversed text) to execute the command. Here is the command: "grep -n main *" Now modify the command above by double-clicking on "main" to select it, typing "select", double-clicking just inside the quote marks to select the whole command again, then clicking inside the selection with the "exec" (middle) button. BUILTIN FUNCTIONS These are pieces of text that wily recognises and treats specially. By convention, they all start with capital letters. When you deleted windows before by B2ing (clicking with B2) the word "Del", you were executing that builtin function. They are often placed somewhere on the screen by Wily, but their positions aren't magical: you could B2 the word 'Quit' _anywhere_ on the screen, to quit wily. The builtin functions are: Undo and Redo Wily keeps an infinite undo history. Make a lot of changes to this file (type stuff and delete stuff), and then B2 on Undo repeatedly until the black square disappears from the little box in the top left of this window. The black square indicates that what you see on the screen is _not_ the same as what is on disk. Put and Get Use these to write a file to disk, or fetch the old version from disk, respectively. If the file cannot be written, a diagnostic message will tell you about it. Putall writes all dirty files to disk. Newcol and Delcol Used to create and delete columns. Cut Paste Snarf All of these act on the most recent selection. Del Delete a window. If the window represents a file with some changes that haven't been written to disk, a backup copy will be made, and a diagnostic message printed. Quit Exits wily. Also backs up any modified files before quitting. New Create a new file. Kill Kill a process which was started by wily. Must be called with the name of the process (as seen at the top left of the wily tag) as an argument. USING UNIX TOOLS As well as treating builtin functions specially, the "exec" mouse button also treats specially text which starts with any of the symbols | < or > If the command you select with B2 starts with one of these, the command is run using the most recent selection as its input or output or both. For example, select the entire list below with the left button: banana apple pear carrot then click with the middle (exec) button in the command below: |sort You can use Undo to undo the change and do it again if you like. Similarly, select the paragraph below: 'Twas brillig and the slithy toves did gyre and gimble in the wabe. All mimsy were the borogroves and "exec" this command: >spell Finally, select (with B1) _and_ exec (with B2) this text: ./send_to_gary [ I finished the wily tutorial. I thought it was too fast/too slow/just right. I will definitely/maybe/never use wily again. I think the interface is interesting/horrid/cool. And furthermore ...] For more information, B2 the line below: netscape http://www.cs.su.oz.au/~gary/wily To finish up, click in the word Quit with B2. wily-0.13.42/Doc/tute/findword000064402366570000012000000001471033320152300157230ustar00ozstaff00004330000002#!/bin/sh # list all places that $1 appears in all the files in the # current directory. grep -nw $1 * wily-0.13.42/Doc/tute/hello.c000064402366570000012000000000611033320152300154260ustar00ozstaff00004330000002void main(void) { printf("hello, world\n"); } } wily-0.13.42/Doc/tute/script000064402366570000012000000007151033320152300154140ustar00ozstaff00004330000002#!/bin/sh echo Here is some output produced by a shell script called "script" echo echo 'Click with the "goto" (rightmost) mouse button' echo on the word script to have a look at the program echo echo It uses grep to find all the places the word "mouse" appears in the echo file "start". echo Click with the "goto" button in any of the bits of text like echo start:42 to go to one of the lines where the word "mouse" is used. echo grep -n mouse start /dev/null wily-0.13.42/Doc/tute/send_to_gary000064402366570000012000000001131033320152300165550ustar00ozstaff00004330000002#!/bin/sh cat | mail gary@cs.su.oz.au echo message has been mailed to gary wily-0.13.42/Doc/tute/typescript000064402366570000012000000001241033320152300163100ustar00ozstaff00004330000002Script started on Wed Apr 10 17:46:05 1996 script done on Wed Apr 10 17:46:05 1996 wily-0.13.42/Doc/hack.html000064402366570000012000000035201033320152300147750ustar00ozstaff00004330000002Hacking Wily

    note

    This document is pretty scrappy, and will likely remain so for some time. You're best bet is to use the documentation in the source files themselves.

    Hacking Wily

    Main data structures

    Text

    The text buffer data structure. All file and text manipulation happens through a text buffer. Every text buffer has a pointer to a list of Views which look after the screen. Texts belonging to a window have a pointer to the corresponding Data, with t->isbody indicating whether the text is for the tag or body.

    The text also maintains a small cache used in searching through the buffer.

    Files which #include "text.h":

    text.c
    This (discounting text.h) is the only file that knows how a text buffer is organised in memory (a simple buffer gap, but keep that to yourself :-). It contains the basic routines to read and write a text buffer to/from memory or a file.
    undo.c
    Responsible for maintaining the undo log.
    sam.h, sambuf.c
    Wrappers to make a Text behave like a Sam file, so we can use the Sam regexp code. They provide a small buffer and some macros for quickly traversing the Runes of the buffer.
    click.c
    Code to expand double-clicks etc. Uses the interface provided by sambuf.c
    search.c
    Various routines to search through a Text
    text2.c
    Mostly convenience wrappers around the functionality of text.c, plus routines for formatting directories.

    Data

    View

    Tile

    Main needs

    Flicker-free scrolling, Tile heuristics, Sam commands
    gary@cs.su.oz.au wily-0.13.42/Doc/00README000064402366570000012000000002051033320152300142160ustar00ozstaff00004330000002index.html Start page for HTML documentation tute/start Start page for "online tutorial" (Just open this file with Wily and read) wily-0.13.42/Doc/fonts000064402366570000012000000025411033320152300142570ustar00ozstaff00004330000002To read/write unicode text, you need three things: your application defaults set correctly, a font file, and appropriate X fonts installed. 1. application defaults (either with xrdb or $XAPPLRESDIR/Wily) Your application defaults should point to a font file, or you can start up wily with wily -p9font fontfile *p9font: /usr/pgrad/gary/lib/font/prop.9.font *p9fixed: /usr/pgrad/gary/lib/font/fixed.9.font 2. Font file (e.g. ~gary/lib/font/prop.9.font) The first line of this gives the line height and ascent, the lines afterwards are unicode ranges and X font names. e.g. 18 13 0x0000 0x0019 lucm.latin1.9 0x0000 0x007F -bigelow*-lucida-medium-r-*-*-16-*-*-*-p-*-*-* 0x0000 0x00ff lucm.latin1.9 0x0100 0x017E lucm.latineur.9 0x0180 0x01F0 matty.latinext.9 0x0250 0x02E9 lucm.ipa.9 0x0300 0x0308 matty.gendiacritics.9 0x0370 0x0372 matty.greekpunc.9 .... 0x9800 0x99ff jis.jis9800.16 0x9a00 0x9bff jis.jis9a00.16 0x9c00 0x9dff jis.jis9c00.16 0x9e00 0x9fff jis.jis9e00.16 0xe000 0xe05f matty.tengwar.9 0xfee0 0xff5e lucm.latin1.9 0xfffd 0xfffd pelm.fffd.9 3. X fonts The only source I'm aware of (please tell me if you know different) for suitable X fonts is ftp://ftp.cs.su.oz.au/matty/unicode/libXg.utf.fonts.tar.gz which contains most of the maths and sci. symbols, and a lot of CJK glyphs. Adding these fonts to your font path is a bit system specific, good luck :-) wily-0.13.42/Doc/mouse000064402366570000012000000043071033320152300142600ustar00ozstaff00004330000002[Bruce Tognazzini, "Tog on Interface", Addison-Wesley pp 26-27] We've done a cool $50 million of R&D on the Apple Human Interface. We discovered, among other things, two pertinent facts: * Test subjects consistently report that keyboarding is faster than mousing. * The stopwatch consistently proves mousing is faster than keyboarding. This contradiction between user-experience and reality apparently forms the basis for many user/developers' belief that the keyboard is faster. People new to the mouse find the process of reaching for it every time they want to do anything other than type to be incredibly time-wasting. And therein lies the very advantage of the mouse: It is boring to find it because the two-second search does not require high-level cognitive engagement. It takes two seconds to decide upon which special-function key to press. Deciding among abstract symbols is a high-level cognitive function. Not only is this decision not boring, the user actually experiences amnesia! _Real_ amnesia! The time-slice spent making the decision simply ceases to exist. While the keyboard users in this case feel as though they have gained two seconds over the mouse users, the oppositie is really the case. Because while the keyboard users have been engaged in a process so fascinating that they have experienced amnesia, the mouse users have been so disengaged that they have been able to continue thinking about the task they are trying to accomplish. They have not had to set their task aside to think about or remember abstract symbols. Hence, users achieve a singifcant productivity increase with the mouse in spite of their subjective experience. Not that any of the above True Facts will stop the religious wars. And, in fact, I find myself on the opposite side in at least one instance, namely editing. By using Command-X, -C and -V, the user can select with one hand and act with the other. Two-handed input. Two-handed input results in solid productivity gains (Buxton, 1986) [Buxton, William (1986). "There's More to Interaction than Meets the Eye: Some Issues in Manual Input," in D. Norman and F.W. Draper (Eds.), New Perspectives on Human-Computer Interaction, Lawrene Erlbaum Associates, Hillsdale, N.J.] wily-0.13.42/Doc/announce/000075502366570000012000000000001033320152300150075ustar00ozstaff00004330000002wily-0.13.42/Doc/announce/1995.8000064402366570000012000000016311033320152300155100ustar00ozstaff00004330000002What is Wily? Wily's basic functions are to edit and search for text and to run commands. It requires UNIX, X and a three-button mouse. It is intended to eventually be an integrated working environment for all tasks involving text. It uses the mouse heavily. It emphasises speed for experienced users, but is probably simple to learn as it has very few concepts. What state is it in? Not finished yet, but probably ready for most people to use. A few people here (Basser) are using it pretty heavily already, but there's still quite a lot of work remaining. Grab it if you want to have a look/play, but expect (and please mail me) bugs. Please mail me portability fixes (but not problems). It's being jointly written on a Solaris and a FreeBSD machine. Documentation? Check out http://www.cs.su.oz.au/~gary/hobby/wily/auug.html Where do you get it? ftp://www.cs.su.oz.au/gary/wily.tgz (tar'ed, gzip'ed file) wily-0.13.42/Doc/announce/1995.11000064402366570000012000000043171033320152300155660ustar00ozstaff00004330000002Announcing the first beta release of Wily. What is Wily? Wily's basic functions are to edit and search for text and to run commands. It requires UNIX, X and a three-button mouse. It is intended to eventually be an integrated working environment for all tasks involving text. It uses the mouse heavily. It emphasises speed for experienced users, but is probably simple to learn as it has very few concepts. What's different about it? Wily is quite different from most other editors in a number of areas. Nearly all operations are through mouse actions on text on the screen: there are no menus, and almost no "key bindings" or "function keys". Full support for Unicode and proportionally-spaced text is provided. A bitmapped terminal and three-button mouse are assumed, and "chords" (combinations of mouse buttons) are used extensively. Minimising the number of keystrokes and mouse actions needed while working with wily was a design aim. Wily itself is almost totally UNconfigurable, but it is quite simple to connect wily to other programs, written in _any_ language, both for simple text-manipulation tasks, and to use wily as a front-end for other programs such as mail or news readers, or terminals. It is possible (and intended) to "live" in wily as with other, more complicated editors. Wily itself is pretty simple, and small (148k for the stripped dynamically linked binary on the author's machine, c.f. 236k for vi, 2044k for xemacs). What state is it in? Development continues, but it is probably ready for most people to use. About fifty people have been using it continuously for the last few months. More information? Can be found at http://www.cs.usyd.edu.au/~gary/wily/ http://plan9.att.com/plan9/doc/acme.html describes the Plan 9 program that wily was modelled after. Where do you get it? http://www.cs.usyd.edu.au/~gary/wily/wily.tgz or ftp://ftp.cs.usyd.edu.au/gary/wily.tgz (tar'ed, gzip'ed file) Will it work on my system? I hope so. There's a 'configure' script which should work. It has worked on SunOS, Solaris, Linux, AIX, HPUX, OSF, Ultrix, BSDI, Irix. What conditions/license? See the README, but basically do whatever you like so long as you don't make money out of it and you leave my name around. wily-0.13.42/Doc/announce/1996.11000064402366570000012000000047301033320152300155660ustar00ozstaff00004330000002Announcing the second beta release of Wily. (0.13.23) What is Wily? Wily edits and displays text and directories, and runs commands. It requires UNIX, X and a three-button mouse. It is intended to eventually be an integrated working environment for all tasks involving text. It uses the mouse heavily. It emphasises speed for experienced users, but is probably simple to learn as it has very few concepts. There are simple mouse-based editors for beginners, and fast, powerful keyboard-based editors for experts. Wily is a simple, fast, powerful mouse-based editor for experts. ;-) It is based heavily on the Acme environment from Plan 9, which in turn was strongly influenced by the Oberon environment. What's different about it? Wily is quite different from most other editors in a number of areas. Nearly all operations are through mouse actions on text on the screen: there are no menus, and almost no "key bindings" or "function keys". Full support for Unicode and proportionally-spaced text is provided. A bitmapped terminal and three-button mouse are assumed, and "chords" (combinations of mouse buttons) are used extensively. Minimising the number of keystrokes and mouse actions needed while working with wily was a design aim. Wily itself is almost totally UNconfigurable, but it is quite simple to connect wily to other programs, written in _any_ language, both for simple text-manipulation tasks, and to use wily as a front-end for other programs such as mail or news readers, or terminals. It is possible (and intended) to "live" in wily as with other, more complicated editors. Wily itself is pretty simple, and small (148k for the stripped dynamically linked binary on the author's machine, c.f. 236k for vi, 2044k for xemacs). What state is it in? Development continues, but it is probably ready for most people to use. About fifty people have been using it continuously for more than a year. More information? Can be found at http://www.cs.usyd.edu.au/~gary/wily/ http://plan9.att.com/plan9/doc/acme.html describes the Plan 9 program that wily was modelled after. Where do you get it? ftp://ftp.cs.su.oz.au/gary/wily/ ftp://ftp.math.tau.ac.il/pub/laden/wily ftp://ftp.cs.york.ac.uk:/pub/mhw/wily/ ftp://ftp.northsea.com:/pub/plan9_unix/wily/ Will it work on my system? I hope so. There's a 'configure' script which should work. It has worked on SunOS, Solaris, Linux, AIX, HPUX, OSF, Ultrix, BSDI, Irix. What conditions/license? The Artistic License, similar to that of Perl. wily-0.13.42/Doc/FAQ.txt000064402366570000012000000054151033320152300143560ustar00ozstaff00004330000002What is wily? See the introduction. What does "wilydiag: File exists: can't open fifo" mean? Wily opens and listens on a fifo in /tmpin case some program tries to communicate with it. If you're not doing anything tricky like that, it won't get used at all. Ordinarily wily cleans the fifo up when it exits, but if something dire happens Wily may not get a chance to clean up. The fifo will be named $WILYFIFO if that is defined, otherwise /tmp/wilyUSER$DISPLAY, where USER is your login name. Just remove it and restart wily to be able to use wily messages. Why does my compiler/editor/whatever complain about illegal characters? The line looks fine to me." Chances are that you've managed to enter a control character accidentally, and the font you're using doesn't display control characters. The easiest way to check is to select the line (or other text) that's causing the complaint, and click on "|cat -v" (or some other program that can display control characters, such as vis or od). I find ^A the most common offender. Why does Wily have to do its own window management? See a long explanation Funky B3 expansion allows some letters, not others? To quote rob (it was originally rob's comment, wasn't it?): "Hard to get absolutely right." The problem is that you can have pretty much everything in a filename apart from \0, but usually you want it to pick sensible strings. It's not just filenames, after all, but also identifiers in programs. After all, Acme is primarily a programmer's tool, because there aren't any other kinds of Plan 9 user. :-) Plus, most of them are shell metacharacters (in rc). The set you want to match varies from instance to instance, so it's pretty much an arbitrary choice. Sometimes you lose. Some justification would be good for the docs, though. Anyone know why "*" is considered a valid character? Hmmm. Ones not in the above list are "#$^*_-:~,./". Of these, "~./" are parts of common filenames (~steve/x.c), "#$-:,." are part of the syntax for expressing an Acme address, and "_" is a common identifier character. That just leaves "^*". I suspect these are allowed because they're commonly used as part of a regexp search. Steve Kilbane Why does it take so long to load my [mumble]-meg file? Blame steve. What about a Win 3.1/95/NT port? Gary's not likely to do it because he doesn't have a development environment for Win (or know much about the Win environment (or want to)) It may not be as useful under windows as under Unix because you won't have the same command-line toolbox (sed, grep, glimpse, ...) There's a Win version of sam, which presumably means there's a Win version of libg (libg.dll?). Starting from that would probably make the port much easier. he font you're using doesn't display control characters. The easiest way to check is to select the line (or other text) that's causing the complaint, and click on "|cat -v" (or some other program that can display control characters, such aswily-0.13.42/Doc/README000064402366570000012000000002051033320152300140560ustar00ozstaff00004330000002index.html Start page for HTML documentation tute/start Start page for "online tutorial" (Just open this file with Wily and read) wily-0.13.42/Doc/pythonpaper.html000064402366570000012000000514601033320152300164460ustar00ozstaff00004330000002 Wily + Python > Emacs + Lisp?

    DRAFT ONLY

    This is a draft of a document which will be submitted to the 4th International Python Conference to be held at June 4-6, 1996 at the Lawrence Livermore labs in California.

    This document describes aspects of Wily which are not yet released for beta testing.

    Wily + Python > Emacs + Lisp?

    Gary Capell <gary@cs.su.oz.au>
    Basser Department of Computer Science,
    University of Sydney, 2006
    Australia
    Wily is an editing environment which can be extended with Python programs. Instead of using an embedded Python interpreter, Wily talks a simple message protocol, and a module lets Python speak the same protocol. This approach is general (one can use any language) and clean (the editor is responsible for only a small set of functions). The message interface promotes a clear separation of functions, with the Wily editing environment providing a standard way of interacting with client programs. The main disadvantage may be that the looser binding between programming language and editor is less efficient, but this is not expected to be a significant problem.

    The editor itself is simple, clean, and efficient, with a few features which combine consistently. It abandons backwards compatibility with the virtual terminals of yesteryear, to take full advantage of a bitmapped terminal and three button mouse.

    Table of Contents

    This documet describes:

    An appendix defines the Python interface in more detail.

    Overview of Wily

    This is necessarily very brief, and Wily and Acme are very different from what most people are used to. Please read Rob Pike's paper for a better and more complete description of the interface.

    Wily's main attractions are that it is very simple (the User Manual describing the whole user interface is about seven pages), very quick to use, and integrates well with other Unix tools.

    History

    Wily emulates in the Unix and X Windows environment the Acme editor from Plan 9. Acme couldn't easily be ported to Unix because it is written in Alef (a concurrent programming language not widely available) and uses non-portable features of Plan 9 . Also, a port of Acme would not be freely distributable.

    The name ``Wily'' derives from Wile E. Coyote, an avid consumer of Acme products.

    Modern Aesthetics

    Wily windows, Unicode text propotionally spaced

    The screen is divided into columns, which are divided into windows. A window may represent a file, a directory, or the output from some program. The screen, columns and windows each have a narrow horizontal ``tag'' at the top, which contains some useful text, and for windows contains the name of the window and a "file is modified" indicator.

    Text is displayed in a propotionally spaced font by default. There is a built in function to toggle with a monospace font, but there are very few occasions when this is necessary or desirable. In most cases limiting a text editor to monospace fonts is blindly following the hardware limitations of the 1960s.

    Text is read and written as UTF8-encoded Unicode, providing some support for editing multi-lingual and scientific text, but remaining backwardly compatible with plain 7-bit ASCII text.

    Everything is text

    All actions in Wily are through creating and interacting with text on the screen, using the three-button mouse and the keyboard. B1 (mouse button one) selects text, B2 executes text and B3 attempts to ``goto'' the text.

    When executing text, there are some built in operations, such as ``Quit'', or ``Del'' which are executed by Wily itself. Otherwise, the command is executed in a subprocess, with output redirected to a window within Wily and input from /dev/null. It is also possible to use the current selection (currently selected text) as input for and/or output of some child program. For example |fmt formats the current selection, >spell checks its spelling and <date replaces it with the current time.

    The goto operation used with B3 is polymorphic in that it recognises three different patterns:

    name
    If name is a file or directory, open it, otherwise search for the literal name
    :address
    Search for address in the current window. The address may be a line number, a character number, a regular expression, or two of these, separated by a comma.
    file:address
    Open file and search in it for address

    Wily's power derives in part from its general treatment of text. Whether text is found in a file, or directory listing, created by Wily, output by some other program, or typed by the user, it can all be treated the same way. A simple text file may be used as a menu of commands or a simple form of hypertext. Previously typed commands or ``usage'' messages can be edited and executed. There is no need for dialogs, menus, modes, buttons or accelerator keys, just operations on text on the screen.

    No wasted user actions

    Wily minimizes the number of unnecessary mouse or keyboard actions the user must make. For instance, placing newly created windows is done without needing the user's help, although the user can easily rearrange things if Wily's heuristics aren't acceptable. Wily also makes cutting, pasting, executing and searching for text so easy to do with the mouse that there is no need to retype text already on the screen.

    Cutting and pasting text is made particularly convenient using combinations of mouse buttons. To cut text, select it with B1, and while still holding B1, also click B2: this is a B1-B2 chord. To paste text use a B1-B3 chord. This style is unusual, but once it becomes familiar other methods of cutting and pasting seem unbearably slow. Another chord (B2-B1) is used to execute some text with an argument.

    To avoid having to position the mouse accurately, a mouse selection of zero length (i.e. a mouse click) is expanded in a ``reasonable'' manner. Clicking with B2 in a word expands to that word, which is then executed. Clicking with B3 in an address (e.g. foo.c:45) expands to that address. Double-clicking with B1 just inside paired braces, brackets or quotes selects the region thus delimited.

    Wily's general approach to text as commands and addresses is compounded because these basic functions can be accessed so conveniently. Most operations can be achieved with a single mouse click or mouse combination.

    Synergy

    The consistent and general use of text for input and output in Wily makes the combination of its features more than the sum of its parts.

    Stepping through an example session might best illustrate this:

    Susan has fetched the file frob.tar.Z. She clicks with B1 in the file name, and with B2 in the word untarz. The utility untarz uncompresses and untars the file, verbosely printing file names as it goes. She clicks with B3 on one of the file names, INSTALL, which opens the file. The INSTALL file suggests that she run configure then make. She clicks B2 in each of these words to run the suggested programs, but there's a problem. The make fails when gcc quits with the error message
    keyboard.c:4: strings.h: No such file or directory.
    She clicks with B3 in the first part of the error message, which opens the file and selects the line. On Susan's system there is a string.h but no strings.h. She removes the last s with a B1-B2 chord. When she modifies the file, Wily sets the ``file modified'' indicator, and adds the word ``Save'' to the tag for this window. Susan clicks B2 on the word Save to write the file, clicks B2 on make again, and she's done.

    This whole process uses about ten mouse clicks and no typing.

    Connecting Programs to Wily

    Wily waits for a program to connect to it using a socket, and then sends and receives messages. The messages can be RPC requests and replies, or ``event'' messages generated by Wily when certain actions happen in windows which a remote program has asked to monitor.

    The interface is deliberately at a rather high level. The intent is that Wily will take care of of the details of interaction, with other programs providing the semantics of executing a command, opening a window or searching for an address. This promotes a consistent set of tools and an efficient division of labour, but necessarily at the loss of some generality.

    The requests allow the remote program to

    • list the windows currently open
    • create a new window with a given name, which may or may not correspond to an existing file or directory
    • ask to be sent some subset of the events which happen in a particular window
    • change the name of a window
    • read the text from some part of a window
    • modify the text in a window
    • act as if some string were selected with B2 or B3 in a window (useful for searching for text, or accessing built in functions)

    A program may ask to be notified when events happen in a particular window. These events are generated when:

    • text is selected with B2 or B3 (i.e. the user is trying to execute or ``goto'' some text)
    • text has been modified
    • the window is destroyed

    When a program is being sent B2 or B3 events, Wily doesn't act on them, merely sends them on. The program may opt to ``send back'' some events which Wily will then act on. Events which modify text, on the other hand, are always handled by Wily, which then may inform the remote program what has happened. In other words, the remote program cannot stop the user modifying any piece of text, although it can repair the text later if it wishes.

    The Python interface

    Wilymodule.c

    This is a very simple interface between Python and the Wily message protocol. It establishes a connection, provides remote procedure calls and queues events until they are requested.

    A Connection is initialized with no arguments, and represents the connection to Wily. All the other functions are methods of a connection object.

    The Connection has methods to return a list of windows representing all the windows currently open in Wily, to create a new window, and to return the next event from Wily. Windows are represented as integers, which correspond to window identifiers with Wily, and events are represented as tuples.

    The Connection has a number of methods which provide operations on Wily windows. These operations allow a program, once it has an identifier for a window, to change its event mask, its name or its ``tools'' (useful text in the window's tag), read or modify some of its text, or simulate a B2 or B3 action.

    Wilywin.py

    This is a small Python module which provides a friendlier interface to Wily's functionality.

    Example Program Fragment

    # Create a window called "hello",and fill it with 
    # the text "Hello, world"
    
    import wily
    con = wily.Connection()
    win = con.win("hello")
    con.replace(win, 0,0, "Hello, world\n")
    

    Sample Tools

    These are small tools written as proof of concept, to test and refine the message interface, and as templates for other applications.

    News reader

    This uses Python classes for threading, talking NNTP and reading and writing .newsrc files, and Wily for displaying newsgroups and articles. The program acts on B3 actions on article numbers, and B2 actions on some special function names (e.g. Catch-up, Follow-up) which it also places in the correct tags.

    Session save and restore

    There are two programs to save and restore the ``state'' of an editing session. The ``save'' program determines from Wily what windows are open, what the current selection is for each, and the full text of windows which don't represent a file or directory. The ``restore'' program connects to Wily and uses the saved information to create and massage windows to hopefully return the session to the original state.

    Terminal

    There are some useful programs which require the traditional ``prompt and read a line of input'' interface. Examples include gdb, /bin/sh or /bin/mail. To use these programs, but from within the Wily editing environment, a simple terminal program was written, in C. It is called win.

    Win provides standard input and output for its client program, and creates and monitors a Wily window, maintaining an input point. When win sees a carriage return entered after the input point, it sends the text between the input point and the carriage return to the client program. Output coming back from the client program is inserted just before the input point.

    Win does not attempt to provide a pseudo tty or work with any programs which attempt to use curses-style screen addressing. However, it works fine for programs such as those mentioned above, and was written with only 230 lines of commented C.

    Alternative approaches

    Wily's approach to extending the editor is to communicate with other processes using a socket or pipe. Here we examine some alternative strategies, and why Wily doesn't use them.

    Build an interpreter into the editor

    This is by far the most common design for an extensible editor.

    There are a few advantages to this approach. Letting the extension language share the address space of the editor is more efficient than using IPC. The language can also be tailored to provide a close match to the editing requirements.

    There are two reasons why this approach was rejected for Wily. The first reason is that it restricts users to a single language, and it often means designing a new (possibly half-baked) language. The second reason is that embedding a language interpreter in the editing environment seemed an unnecessary step towards monolithism and code bloat.

    For comparison, below are the sizes of three stripped, dynamically linked executables on the author's sun4d Solaris system:
    167264 wily
    234272 vi
    1873336 xemacs

    Link code dynamically

    Another approach is to dynamically link extension code with the editor. This is more general and more efficient than the built in interpreter design. CodeWright® from Premia uses this approach in the Microsoft Windows environment.

    One problem with this approach is that dynamic linking is not standard on all UNIXes. Another is that one errant code fragment dynamically linked in might damage the integrity of the editor. The result might be lost data, or even worse, data quietly modified in some subtle manner.

    When this approach becomes ubiquitously available and more secure, it will be re-examined.

    ILU or CORBA

    It would seem that ILU and CORBA both provide a ready-made solution to turn an editor into a distributed object server. However, both seemed too heavy-weight for this simple task.

    Further Work

    There is a strong belief amongst Wily's users and developers that ``creeping featurism'' is evil. Most of the ongoing work will be towards refining existing features, and improving the clarity and correctness of the code. Retaining the ``look and feel'' of Acme is also an important consideration.

    There is still room for innovation, though. The message interface is still very young, and may change with the demands of application writers. The author hopes that the Python community will be able to make good use of an editor programmable in Python. Although there is no need for cursor keys to navigate around Wily, they may be added later, although they are a low priority.

    Networking and security

    Currently programs connect to Wily by writing to a UNIX named pipe. Wily's security relies on this pipe being writable only by its owner. This means Wily can't accept connections directly from remote machines, which would be desirable for some applications. A design which avoids this limitation securely and efficiently has not been decided upon.

    Obtaining Wily

    Wily is freely available.

    The prime source for information about Wily is the WWW page at http://www.cs.su.oz.au/~gary/wily/ The wily distribution contains wilymodule.c, and can be obtained at ftp://ftp.cs.su.oz.au/gary/wily.tgz

    Acknowledgements

    The early design and source of Wily owe a lot to Bill Trost. Wily and this paper have also been improved by patches, suggestions and bug reports from Assar, Davor Cubranic, Kyle Dean, Stephen Gallimore, Mark H. Wilkinson, Bjorn Helgaas, Steve Kilbane, Beirne Konarski, Bob Krzaczek, Alberto Nava, Arnold Robbins, Rich Salz, Scott Schwartz, Chris Siebenmann, and Richard Wolff.

    Wily builds on the Sam distribution by Rob Pike and Howard Trickey, and originally used libtext by James Farrow. James Farrow also makes available a set of Unicode fonts for X at ftp.cs.su.oz.au/matty/unicode/


    Appendix: The Python/Wily Module

    con = wily.Con()

    Connection

    Connection objects have no attributes and suport the following methods:

    list()
    Returns a list of names and Win objects representing the windows currently open.
    win(name)
    Return a new window called name
    event()
    Return the next Event. Note that this method will block until an event is available.
    eventwouldblock()
    Indicates whether calling Connection.event() would block.
    returnevent(event)
    Send event back to Wily, probably because we have no use for it.

    The following methods of a connection object act on a window.

    attach(id,mask)
    Request events for this window.
    detach(id)
    Cancel request for events for this window.
    setname(id,string)
    Set the name of this window.
    settools(id,string)
    Set the toolbar for this window.
    read(id,from,to)
    Read some range from this window, returns a UTF8 string.
    replace(id,from,to, string)
    Replace some range of window with some other text.
    run(id, command)
    Makes wily act as if command had been selected with B2 in this window. This can be used to access Wily's built in functions. For example, to delete w, call con.run(w_id, "Del")
    goto(id,address)
    Makes wily act as if address had been selected with B3 in this window. Returns a tuple identifying the window and position which are the result of the search.

    Events

    Events are returned as tuples. Every event has at least two elements, which are a window identifer, and an event type identifier (which is one of wily.GOTO, wily.EXEC, wily.REPLACE or wily.DEL). All of these event types except DEL also have a from, to and string attribute. e always handled by Wily, which then may inform the remote program what has happened. In other words, the remote program cannot stop the user modifying any piece of text, although it can repair the twily-0.13.42/Doc/python.html000064402366570000012000000064161033320152300154170ustar00ozstaff00004330000002Wily Python Programmers Manual

    Wily Python Programmers Manual

    Summary

    Create a Connection, use it to create and manipulate Wily windows.

    See pythonpaper.html for a discussion of the design. (Unfortunately out of date).

    Creating a Connection

    import wily
    con = wily.Connection()
    

    methods of a Connection object

    list()
    Returns the names and IDs of all open windows. The values are returned in one big string, with names and IDs separated by a tab, and each (name,id) pair on its own line.
    listing = con.list()
    lines = string.split(listing, '\n')
    winid = {}
    for line in lines[:-1]:
    	[name,id] = string.split(line, '\t')
    	winid[name] = string.atoi(id)
    
    ... will give you a dictionary mapping names to numeric ids.
    win(name:string, isBackedUp:integer)
    Returns an integer window identifier, to be used for later operations on the window
    event()
    returns an event tuple (w, t, r0, r1, s), whose fields are:
    w
    window identifier
    t
    event type
    r0, r1
    affected range
    s
    string
    The meaning (if any) of the values of r0, r1 and s depend on the event type 't'
    eventwouldblock()
    If eventwouldblock() returns true, calling event() might have to wait. If eventwouldblock() returns false, calling event() would return immediately because an event is already queued up and waiting.
    bounce(tuple)
    Called with an event tuple as returned by event(). Returns None. Used for returning an event we want Wily to handle instead of us.
    attach(w:integer, mask:integer)
    'w' is a window identifier as obtained by new() or list(). 'mask' is a bitmask of event types. Sets the mask of events to be sent to us.
    setname(w:integer, s:string)
    Set w's name to 's'
    settools(w:integer, s:string)
    Set w's tools to 's'
    read(w:integer, from:integer, to:integer)
    returns a (UTF) string
    replace(w:integer, from:integer, to:integer, s:string)
    replace the text in 'w' from 'from' to 'to' with 's'
    run(w:integer, s:string)
    has the same effect as sweeping 's' with B2 in window 'w'
    goto(w:integer, from:long, to:long, s:string, flag:integer)
    has the same effect as sweeping 's' with B3 in window 'w', and starting any search at range(from,to), except that we only warp and select text if 'flag' is set.
    Returns a tuple (w:integer, from:long, to:long), which represents the window and selection that was opened.

    Constants

    GOTO, EXEC, DESTROY and REPLACE are event bitmask values, useful for comparing to the event type returned by event(), and for setting the bitmask in attach().
    gary@cs.su.oz.au wily-0.13.42/Doc/mailout000064402366570000012000000010551033320152300145770ustar00ozstaff00004330000002~/.wilydirhide, .wilytools > If wily checked to see if it needed to reload this file before generating a > listing (a simple stat(2) -- a feature .wilytools needs as well), it would > substitute for Dotfiles quite nicely. That's a whole lot of stat-ing going on. Every time a window opens for .wilytools, and every time a directory opens for .wilydirhide. A cheesy hack would be to look at those files when we open or write them from inside wily, i.e. check the label of the file we write/open to see if it is magic. strcmp should be cheaper than stat wily-0.13.42/Doc/one.html000064402366570000012000000071151033320152300146540ustar00ozstaff00004330000002Concise Wily User Manual
    Notation
    B1, B2 & B3 are left, middle, right mouse buttons, respectively. "B1B2" means to select some text with B1 held down, then click and release on B2 while still holding B1 down. This is the B1B2 chord. There are others. "Sweep with B1" means to hold down B1, drag it across some text to select it, and then release B1.
    Screen layout/control.
    The screen is divided into columns, each of which is divided into windows. Each window has a scrollbar and a one-line "tag" containing a file/directory name and some commands. There is also a tag at the top of each column, and at the top of the whole screen. A "layout box" is at the left of each tag: dragging this box with B1 moves the window around the screen; windows re-layout automatically when you drag and release windows with this box. Clicking on the with B1 "grows" the window slightly; B2 makes it grow until all other windows in the column only show their tags. B3 makes the window tag up the whole column, hiding other windows completely.
    Selecting and editing text
    Type normally anywhere on the screen to enter text; move the pointer into the tag/window you want to type into. Position the cursor within text either with cursor keys, or clicking once with B1. Sweeping text and then typing Cuts the selected text, and replaces it with the typed text. Cut and Paste are chords B1B2 and B1B3: sweep text with B1, and complete the B1B2 chord to delete. B1B3 Pastes text over the selected text. Double-clicking with B1 selects text quickly, picking a word, a line, or text delimited by quotes, brackets, braces, or parentheses, depending on where you double-clicked. Undo and Redo give edit history. Layout box is filled in when text is modified but not saved.
    Executing commands
    Sweep text (anywhere!) with B2 to execute it as a command. A single B2 click automatically selects a sensible "word" as the command. Commands can be built-in (Capital first letters, by convention) or passed to the shell for invocation. To invoke commands with arguments, sweep the argument with B1, then click on the command with B2B1. If a B2 command begins with |, > or < characters, the B1-selected text is piped through, fed into or replaced by the results of the command, respectively. Any output generated by commands appears in a window named dir/+Errors, where dir is the directory the command was invoked in.
    File/directory management
    Windows show file or directory contents. The full path of the file/directory is given in the tag. Selecting a filename with B3 (sweep or single-click) will attempt to open that name relative to the pathname in the window's tag. The new file/directory appears in a new window. If the file can't be found, the B3'd text is searched for in the current window instead. If the B3'd text is of the form ":n", it is a line number to go to. ":/pattern" is a regular expression pattern to search for.
    Builtin commands
    Anchor prints current selection address in tag. Clear clears window. Cut cuts selected text to buffer. Del deletes window. Delcol deletes column and windows. Dotfiles toggles display of dot files in directory windows. Font toggles fixed/proportional fonts. Get reloads window. Indent toggles autoindent. Kill halts named B2'd program. Look searches for text. New creates new window. Newcol creates new column. Paste pastes buffer. Put writes file to disk. Putall writes all files. Quit exits Wily. Redo undoes last Undo. Snarf copies text to buffer. Split opens up another window on the same file. Undo undoes last edit. wily-0.13.42/Doc/example.gif000064402366570000012000000254031033320152300153270ustar00ozstaff00004330000002GIF87a,ڋ޼H扦j L ĢL*̦ J?jܮW| UFJn\xGGXhxH3888gc))Iɇ9h:ę*:䉳zǚx ek:;+ܘLXH-46[n~ ^=| >z _N:\>Y/ٽX!>%a|"6ۧ0ȑ$ѭ[=>)R1K,9 f3Uz iM࿜[ #΀VV2֭YNJHUʰEe."*SؖmjhMMk6Rn;7-[N8b^+K1 ם붲4oyZzwmნS g\!۾׶>G /.D5gMQ_iO:aAavp4˛?[,V~t-CO]Hf\NޱvS~CwS#oA zNHnuWly_jf_<}z=f8vWV cAơAaK NTj0vsQ^LShm@Dm=f9?g1ǑrD _m d\Bu)'`9&z`oėffեui>rꨊj QꫲΊފkz l1 l&a.l> mNKm^mn[, ~ nKn枋nn oKoދo"p pp(̰4lmgTD,JHHxq&"јhƄ˅39+n2|nϟFɄn E4QΊ&qE B/TUEX#[Mr]JGPrEQEMҞb{e "ݜN-tE.M3&> Ғ_n#܈K*ؐ鐼FhIy-~h4?gLz/:nJnk5e6~L|օ JPxCf<,a﹂­%|琾v'}-Uy|MU%KZEhc`}?-@ C%Gl17(ɀ|% II V ]Ϸ-Cc5!́!{ݓKP 5D. Ax !2mMzCVɇcSbgO FrNIsgxvMŭ:%9sGAEL7ŠΆ\343!5dV ԑiGI]BYHZ S9<*񓸳2Ϝ&:3:zd ՜{ے܇oT*ŪԜj\TE) bšDKKX`1K,kcձecKYcE eekfY14 -:MjVSL[i4mvBz .p*wms Jwԭujڼ y{VXob&[m7J!V+~W]fg_v~_F +*6Fhn^ 6)eN{} [1ۇ9wþuY;t&!S:{ {7ҿH(# m*TSeLv0-l9d"bTǜc'79y+M)64;;]5մ s"G)Tiň')HHط2zH7.$TpҷЛP2Ƕ68On"n$5g"MXW9Y4g!Ie؞n^\i^3 숣iZ'kw'Or՜d+Ne_ ޳1Vf),CEx-lJN,苴GvO!-UOva_yPj6KX 3|T$YϬ9oo&7 :H[uuQrT߽6A4qO]M{_o5^eo:oh.}YF9|Thury򩲶zN{B=hvA(EJ4qDneܦTh٠{+|gd4}tAAd_NT/vq} 5Iz=Nsehfl0w-$5cދ-߭v&=R4ܤ~mm8xgv~qz27]G~*WqOrBk4UvWkF-Ewt'hKVGE~W'cUQCE,T z4!wu/ׂqMgGUy $=(im9SJ7c:g#sOT(AFrGvx:~,TW.8Hvs0:>HK7Y7\F1vnEMGsfwncVZ4 e"hy ]7>W}*5+BdLV-'8_$xA38؊~ȋ^ hchh1Ȍ1(ܲ]׈٨ȍ(H.\ψȎE&(^8F!{1Nd&15x7/u8.eQ;]Vl&:7E2834W!Q7[R)b7#uW\@&e搘2(#^Yaqܣe=wR|ea"vqԓh`u6MSgg6puSVfWohxL0=tS5C)gX?Yx cn{Q}rQgXt9whkxDXGml&ʆ~дvy{O(ym(LJ3vi@I n9v|q"H{yrRޑ>eWkp);% SzjJF*ZBɈ]{1iO e˘h2gKl{:6Pi=BȴGȝ 2 .ڴN 9eW6G9J_G\9RJ [L#pF6:B|ؑ]*pr7ۊ[wES=3xgVɻG(|`jsˣjg7lXvaYކ?;UIUdq >Qhz#j%7g,4hC6D&u(!l4Ŝxۗ"EۇVp& ?!xV% *ꟕh(4 JP ů(<N>ڨ[$9>YƧ+g|t)XF WCD fYŗÀR֋y.|K1/:dHj 7,V[; &9~Gyvf, DLZw?=gx],ڀ*Ɲ;W}%93ƪ')~jykL'۹x>ɑh QK:}Ž*%hjڢ)\\|\w$̺_sRxwx8J:+Tn6,ȶwin |ÜЛyl!5"ЩòlMKaש܋CZ̦97벉 ){2{[n[ . lf$} 1]+-؏:ӄз@,6MJ=ԱҍڒU-黶X}1Pղ"Ԭx?[۸K֤˪#XYG-Yk(=}F`LEc3kzc-ثb3-מxzZpX+zp+6לMmviis* ƓW Mg[*(ZȾmt&8 ;!أY?keft&;_.ؒ׹yYhI9 *Ƭ$'̪6 .;LSk4K)92<Zf#lgf?HE^xXWEY}kG]#ibK?GRݧaeݺUvMQ%T3&THŢh K@lF|7 S&$nV0O|%exb%#2raQGti?˽V&BJ0THβA+[(ukαJr#VCo_%1X/` +dT4aNs]eWɎ1g<˛ksѠ l4 PO={hjiEun o껈+NDž3ws:zuga/戧ɱa={A? ~}փ+] b|wO>Kn@ >T+?PB 0Pÿsm +h Dى(OlB uO S0 RHVsmTl8DH|-Iw .",2=t=9"jͦR5TCgqT.$+<;:S+-h2mlϦ̼P w$oI)K1TM9OA UQI-RT%.Y +{T)/XeIȘ;P(\TemgVi5C2QZRIJrkYUϬJoR:c_-6_1]HS(^ʝq4% &hy(XZU%Tu|.I.9t\D&NYXE atk-3^px,rdӎ6Y+Rf?έӍj1pJC/=G}deO\5^}9(DN&8ٟ1F;Rx_T+ZP]U,:"mEsNW5"oK5OBDTqe c?ôr|kERTPˌ7zJ ةaqhz}%=#+@E6fљwau`Wo[{^2=}πL +E@E(x\CҌ'(dOe ObX&&HIMHP% V% ^ΈnK0:bjM\%WZOjiJAHDv?JSr$sh^U"OITZ3s)əS+EyShuj9ԔuukYVچ#Y xU _u;U*Tp[=^I;N}SX)&lW:+H/Jwڄvrm(_+Zwe8iJfϙGb]lEc>2n p*<%jv!>:,yԏ{a3ne:*nRSB/l9V2!B׶BE}y܌뀃l,ǓZ4f'}k܄ROeMoZWWs@, -bdMcoekaNT`߼8D{CW`ĺ9bIm ^Y]EN.1J\2$nc2 o1(Vo^_yV2@2HQe{]LVQD^َԻWr.k3zgSe0cSP$̍vF?GbV1A*' PQ˥>Kܒrz~]Xp^a:PLj ;jsfaŜbnֲ1_;0#EC$-[kj>ZL qOxſ=ԦYf@_Vm\gm[[Z m~ }gT/s=2o8Бn7%]1Dzљu-]Ugԭu~Q]]ϐ7uFO:+>vw]eOi:kep"ݭM- ##s!+USnGIMXčn%G{HO4&/:mA96^y<9N0eL[9ϵ*YwLgb6\̠~lz}3~,c UBW&gO _gVQshw#(goJϲGrVn)fI'fȻ . "P,K>+;Zo&^uJ d,sU"-؇y,zŬ.lUT6oJgĉˤVN)Ljtt͜JH҆Ft:fIOX$/N 4l_z")pЁ~ Po`M, Ph·fOrϯLp*jp< 3z"pઇ+(qg  j.1iKr-\O-ƫ \q"P,XlxQ9+ْ1 KĭnIkQ{+/~RQm0(y._hRG1,(^ƞk9#2 nRr;0D l=e'%RO%j#j#|"p̈f,$y~P%Ck&v d*D 1$!*(͒R<.Qj" ?|-bFFBpUR q]MmɴFA rP'+Hsjv.)R3Q؊I&3iƱ.=)OoE3Y9q%[d*lo!)8 =и ʳz}5Yw)=ѓ?0sK21).gv3梒ΠQR TMpL49e@,d8cG<"߶<0V5qsMT2HABUsC#5':np4EN,yGHTXHC4IAo-@7Žų#JtLFqFotdĔLElIJ#/qM0M41NZ1::M">APzD?`=˳rQ!mƴ:) ;u6J-tPPT-&OTg|Us]3'xR$J4#.4#0JVAm,> 1 5XL]O]1Xy^AZTV%2 /yhUr[u] rIwG"qV_[4-{R<]iK'ͦ|tUeKT-u+]<Y 'bI=OU na,uZŦ1S5ioVXi# } bgY5vhAh!,mI NdMNѦ8Qʒ[ԫԵ6'V` TqlE̶@rpb6nqWQInAWQ^G`_;Nk@ӵ\4qmS65pT.0TIWNnH% TewDSgo,\J5Gx/5yp @jGufqLOO=吏ܾw_4}{]6Uٷmv~Ke~}:>7JBDKԀw b5u˯ayܷ7 ytWUNAd5F΄NV 5.MCix3S"awof?׏OSoWic9ؘ^5T Տ,lj9V'[rl+iԔO9!K?wy\ R*l/r1%_AX6-0M Ky89o` 9˖'+ |ϗ'xPő# fmdQQD)W3MFyXr#ק|v g]/VuSX͡Vb#֜*SE@-ZNً;S[RÖx;q_ywAl|7LuRiT1x,mc1yN:Z{5[u~vkFٺIliHCWu3W {b~ZOev0[u[9밓A;3YY㴟7XGQD#mPU/eq ;:oOx]lxTM=CzHȋKuxKWNt k)&u_x۳}P]ZI}ݝ=ޥ4]}}߅n==߽^ڡ=^ %^ k89(;}{?41'N)؋g9<U-hL۸9~©ɻ ̝zHlœ~SDb-j_¬lOs.osĔTI|ci=᢭\gl} K[̮ZJWp 87 -H`X{9a l.~mftKTo/hWqCuGخLwily-0.13.42/Doc/index.html000064402366570000012000000024611033320152300152010ustar00ozstaff00004330000002Wily Homepage The primary location for these documents is http://www.cs.su.oz.au/~gary/wily/

    Wily Homepage

    Silly Cartoon
    Please send comments or queries to gary@cs.su.oz.au wily-0.13.42/Doc/Credits000064402366570000012000000027221033320152300145240ustar00ozstaff00004330000002N. Wirth, J. Gutknecht Oberon Rob Pike Acme Gary Capell Wily first draft, current maintainer Bill Trost too many patches, bugfixes, ideas to list fixed listen() race condition stripnulls bug expanded address stuff better env.c reduce excessive redraws fix for next_width bug much of the messaging design "undo" bugfix Dot builtin tag_findtool Steve Kilbane integrated sam's regexp Richard Wolff sunos4 patches, msg.c bugfix use salloc, srealloc in sam regexp stuff Arnold Robbins cleanup wilyfifo ignore SIGPIPE Assar autoconfig stuff Scott Schwartz prevent $TMPDIR replacing /tmp in tag fix to wily/sam.c:/^error_c path.c - nextstr pathfind searchincludedirs Mark H. Wilkinson fix ESC bug use $WILYBAK as the backup directory bug in delpane snarf/paste use X clipboard memory overrun in libmsg/util.c:/^stripnulls pstrapp Bjorn Helgaas fix bug when scrolling one-line window bug in event.c Font builtin better scrolling Local builtin nicer scroll_init FILENAME_MAX -> MAXPATHLEN in libmsg/connect.c Kyle wily.xpm bug: in win.c Davor Cubranic bugs: New window has no cursor, Look in empty window dumps core Rich Salz, Beirne Konarski, Scott Schwartz Daniel Neri "Split" bug-report Stephen Gallimore pathfind patch wily-0.13.42/Doc/onepage.html000064402366570000012000000073601033320152300155130ustar00ozstaff00004330000002Concise Wily User Manual Wily

    Notation

    B1, B2 & B3 are left, middle, right mouse buttons, respectively. "B1B2" means to select some text with B1 held down, then click and release on B2 while still holding B1 down. This is the B1B2 chord. There are others. "Sweep with B1" means to hold down B1, drag it across some text to select it, and then release B1.

    Screen layout/control.

    The screen is divided into columns, each of which is divided into windows. Each window has a scrollbar and a one-line "tag" containing a file/directory name and some commands. There is also a tag at the top of each column, and at the top of the whole screen. A "layout box" is at the left of each tag: dragging this box with B1 moves the window around the screen; windows re-layout automatically when you drag and release windows with this box. Clicking on the with B1 "grows" the window slightly; B2 makes it grow until all other windows in the column only show their tags. B3 makes the window tag up the whole column, hiding other windows completely.

    Selecting and editing text

    Type normally anywhere on the screen to enter text; move the pointer into the tag/window you want to type into. Position the cursor within text either with cursor keys, or clicking once with B1. Sweeping text and then typing Cuts the selected text, and replaces it with the typed text. Cut and Paste are chords B1B2 and B1B3: sweep text with B1, and complete the B1B2 chord to delete. B1B3 Pastes text over the selected text. Double-clicking with B1 selects text quickly, picking a word, a line, or text delimited by quotes, brackets, braces, or parentheses, depending on where you double-clicked. Undo and Redo give edit history. Layout box is filled in when text is modified but not saved.

    Executing commands

    Sweep text (anywhere!) with B2 to execute it as a command. A single B2 click automatically selects a sensible "word" as the command. Commands can be built-in (Capital first letters, by convention) or passed to the shell for invocation. To invoke commands with arguments, sweep the argument with B1, then click on the command with B2B1. If a B2 command begins with |, > or < characters, the B1-selected text is piped through, fed into or replaced by the results of the command, respectively. Any output generated by commands appears in a window named dir/+Errors, where dir is the directory the command was invoked in.

    File/directory management

    Windows show file or directory contents. The full path of the file/directory is given in the tag. Selecting a filename with B3 (sweep or single-click) will attempt to open that name relative to the pathname in the window's tag. The new file/directory appears in a new window. If the file can't be found, the B3'd text is searched for in the current window instead. If the B3'd text is of the form ":n", it is a line number to go to. ":/pattern" is a regular expression pattern to search for.

    Builtin commands

    Anchor prints current selection address in tag. Clear clears window. Cut cuts selected text to buffer. Del deletes window. Delcol deletes column and windows. Dotfiles toggles display of dot files in directory windows. Font toggles fixed/proportional fonts. Get reloads window. Indent toggles autoindent. Kill halts named B2'd program. Look searches for text. New creates new window. Newcol creates new column. Paste pastes buffer. Put writes file to disk. Putall writes all files. Quit exits Wily. Redo undoes last Undo. Snarf copies text to buffer. Split opens up another window on the same file. Undo undoes last edit.
    Steve_Kilbane@cegelecproj.co.uk wily-0.13.42/Doc/winmanager.html000064402366570000012000000027001033320152300162160ustar00ozstaff00004330000002

    The Wily Window Manager?

    Window management is probably the biggest open problem with Wily, probably because there's no real solution, only heuristics.

    The first iteration of Wily creatied a bunch of separate X windows and let the window manager handle arranging them. This seems a more modular, tool-based approach. However, bitter experience showed that most existing window managers just don't cut it when you're quickly creating and deleting lots of windows. Acme's window management,was much better.

    The logical solution then would be to write an X window manager that works like the window management in Acme. However:

    • Writing a window manager requires knowing a _lot_ more about X than I ever want to know
    • Either the wily windows would need to be separate processes, communicating probably via some sort of X IPC (more arcane X'ery), or libXg would need to be modified to allow multiple windows (O who will save me from this plague of X?)
    • This sort of window manager would probably _not_ be appropriate for managing the other windows normally on the desktop.

    So Wily is designed to be run in one big window, and it does its own window management within that. It's a bit of a hack, but probably the best solution for the moment.

    Still, I hope it shouldn't be too hard to remove the "Wily is managing all the windows" assumption from the code if some brave soul solves the problems mentioned above. wily-0.13.42/Doc/download.html000064402366570000012000000013041033320152300156740ustar00ozstaff00004330000002Fetching Wily Wily


    Fetching Wily

    Wily source code and documentation and some binaries are available via FTP from sites in

    The Australian site is the primary, the others are mirrors.

    If anyone else sets up a mirror for this stuff, please tell me?


    gary@cs.su.oz.au wily-0.13.42/Doc/idioms.html000064402366570000012000000125141033320152300153560ustar00ozstaff00004330000002Wily Idioms Wily

    Wily Idioms

    This is a collection of useful scripts, guide files and ways of working with Wily.

    Guide files

    Collect useful script names, file names, regular expressions into a simple text file, which can act as a tool box/menu. e.g. my $h/lib/html/guide
    	|title |h1 |h2 |h3
    	|href http://
    	|mailto gary@cs.su.oz.au
    	|i |b |tt
    	|tag blockquote
    	|indent
    	
    and my $h/guide
    	remote rm guide |par |indent |undent :., :, W sam sg wdef  9term
    	Mace/in src/jcrab
    	news; overp comp.risks
    	$wilysrc $wilybin
    	
    I edit my $h/guide to have the names of files and directories I'm frequently working with.

    Start-up Script

    Start Wily from a shell script which sets up the environment, and initial files
    	#!/plan9/bin/rc
    	EDITOR=W	# makes wily the editor for mail, etc.
    	path=(. $path)	# add '.' to the path
    	exec wily  $h/guide	# use an initial 'guide file'
    	

    Short-cut Environment Variables

    Set environment variables to make window labels shorter and easier to type, e.g.
    	h = $HOME
    	wilysrc = $h/src/wily/wily
    	wilybin = $h/obj/$cputype/wily/wily
    	

    "buttons"

    These are commands designed to operate on the window in which they are clicked.
    1. Write a script which operates on $WILYLABEL, e.g. createreplymessage $WILYLABEL
    2. Add a .wilytools entry so the name of the script appears automatically in the tags of appropriate windows, e.g.
      	Mace.*\$		subject
      	Mace	reply
      	
      would ensure that all the subdirectories of Mace have a "subject" button, and all the normal files in the Mace file tree have a "reply" button.

    wily tag

    Use the wily tag (the tag above the columns) to store very frequently used commands and addresses. This is particularly useful because the wily tag is never obscured.

    I normally copy the top line of my $h/guide file to the wilytag as soon as I start Wily.

    B3 to change "last selection"

    B3 in the label of a window to make its body the last selection without having to sweep the selection out again.

    Plan to double-click

    Put quotes or brackets around long commands you might want to re-select later. It's just a bit easier than sweeping the command out again.

    double-click to check syntax

    Double-click just inside a bracket or brace to find where the other half of the matching pair is, e.g. to check if you've got enough closing brackets.

    double-click to select SGML elements

    Double-clicking will select between >< pairs, so given this text: "<H1>the heading</H1>", double-clicking just before "the" will select "the heading".

    address expressions in the wily tag

    B3-ing in a tag with no body (i.e. the wily tag or a column tag) searches for the address in the last selected window. This lets you put common address searches (e.g. :, (select the whole window)) in the wily tag and apply them to a window by selecting the window, then B3-ing in the address.

    use history file(s)

    Set $history and use it as a memory for obscure commands you perform infrequently, and as a short-cut for for commands you've performed recently.

    I set $history based on the date. This gives me one file with recent commands, and a directory full of files with older commands. I use two history-printing commands, one called 'h' which searches through the current history file, the other called 'hg' searches through all my history files, using glimpse.

    h

    	#!/plan9/bin/rc
    	if ( % $#* 0 ) {
    		tail $history
    	} else {
    		agrep $1 $history | tail
    	}
    	

    hg

    	#!/plan9/bin/rc
    	glimpse -H $h/lib/history -h -y -L 15 $*
    	

    remote interface to netscape

    I call this script 'remote'
    #!/plan9/bin/rc
    for(i) {
    	netscape -noraise -remote 'openURL('^$i^',new-window)'
    }
    

    To use it, select one or more URLs, and B2B1 on 'remote'. Netscape will then open a window on each of the URLs.

    Look

    • Use B2B1 on "Look" to search in one window for a symbol you have selected in a different window
    • Use "Look" to search for a symbol you can't search for with B3 because its also the name of a file in "this" directory or the include path.

    Backups

    Edit and execute the "backup warning" messages.

    A typical one might be

    backup 48 /n/staff/u13/pgrad/gary/guide
    

    Replace the word backup with 'diff' and execute the line to find out what changes were discarded. Replace the word 'backup' with 'cp' to easily recover the modified version of the file.

    Poor man's hypertext

    You can put the name of a related file in a comment, to let you more easily jump between files. E.g. I have the documentation for msg.h in C.html, so each file has a comment referring to the other, e.g. in msg.h,
    /* see ../Doc/C.html for more extensive documentation */
    and in C.html
    <!-- documentation for msg.h -->

    This makes it more likely that when I change one file I'll just B3 in the name of the related file to jump to it.


    gary@cs.su.oz.au wily-0.13.42/Doc/Tcl.html000064402366570000012000000043441033320152300146160ustar00ozstaff00004330000002Tcl Programmers Manual

    Wily Tcl Programmers Manual

    this is a package of tools for communicating with wily using the Tcl library. the file wily.c defines a thin veneer round wily's libmsg.

    this compiles with wily-0.13.1[89] with tclversion 7.4.

    the files wtcl.c and wtk.c compile against wily.c to give a tclsh alike with wily support called wtcl, and a wish alike with wily support called wtk.

    the only addition to standard tcl/tk is the ``wily'' command. this has several subcommands

    wily init
    connects to wily. should be called before any other wily command
    wily isconnected
    checks that we can still talk to wily. returns boolean.
    wily list
    returns a list of window ids (integers).
    wily name <id>
    returns the name of the window with given id.
    wily new <filename>
    opens a new window with given filename.
    wily attach <id>
    offer to collect events for window with given id. we collect _all_ events.
    wily setname <id> <name>
    set the name of window with given id to the given new name.
    wily settools <id> <tools>
    appends the given tools to the tools for window with given id.
    wily read <id> <begin> <end>
    returns the text between points <begin> and <end> in window <id>.
    wily replace <id> <begin> <end> <text>
    replaces the text between points <begin> and <end> in window id with .
    wily exec <id> <command>
    just as if <command> had been b2'd in window <id>.
    wily goto <id> <string> <bool>
    as if string had been b3'd in windows <id>. if <bool> is true then we jump to and select the result.
    wily length <id>
    the length of the text in window <id>
    wily wouldblock
    return boolean. true if there is no event in queue. false if there is.
    wily event
    returns a string describing the event.
    wily bounce
    return the last event received back to wily.

    "stephen" sp106@york.ac.ukwily-0.13.42/Doc/demo.utf000064402366570000012000000005151033320152300146460ustar00ozstaff00004330000002∙ Why use :-) when you can use ☺? ∙ Gøëring, Garçon ∙ Γαρη Ξαπελλ ∙ ∀x ∃y : ½y ≧ x² ∙ ♘♙♚♜♝♞♟♠♡♢♣♤♥♦♧♩♪♭♮♯ ∙ ЙКЛ МОП РСУФХЦЧШЩЪЫЬЭЯабвг ∙ ひびぴふぶぷへべ ぺみむめもゃやゅゆょよるゎゐァイキ ∙ ∴ Use Wily wily-0.13.42/Doc/Tcl.txt000064402366570000012000000033301033320152300144630ustar00ozstaff00004330000002this is a package of tools for communicating with wily using the Tcl library. the file wily.c defines a thin veneer round wily's libmsg. this compiles with wily-0.13.1[89] with tclversion 7.4. the files wtcl.c and wtk.c compile against wily.c to give a tclsh alike with wily support called wtcl, and a wish alike with wily support called wtk. the only addition to standard tcl/tk is the ``wily'' command. this has several subcommands wily init connects to wily. should be called before any other wily command wily isconnected checks that we can still talk to wily. returns boolean. wily list returns a list of window ids (integers). wily name returns the name of the window with given id. wily new opens a new window with given filename. wily attach offer to collect events for window with given id. we collect _all_ events. wily setname set the name of window with given id to the given new name. wily settools appends the given tools to the tools for window with given id. wily read returns the text between points and in window . wily replace replaces the text between points and in window id with . wily exec just as if had been b2'd in window . wily goto as if string had been b3'd in windows . if is true then we jump to and select the result. wily length the length of the text in window wily wouldblock return boolean. true if there is no event in queue. false if there is. wily event returns a string describing the event. wily bounce return the last event received back to wily. wily-0.13.42/Doc/auug.html000064402366570000012000000024611033320152300150330ustar00ozstaff00004330000002Wily Homepage The primary location for these documents is http://www.cs.su.oz.au/~gary/wily/

    Wily Homepage

    Silly Cartoon
    Please send comments or queries to gary@cs.su.oz.au wily-0.13.42/Doc/AcmeVsWily.html000064402366570000012000000054651033320152300161240ustar00ozstaff00004330000002Acme Vs. Wily

    Acme Vs. Wily

    The following is a side-by-side comparison of Acme under Plan 9 vs. Wily under Unix. See http://www.cs.su.oz.au/~gary/wily/ for more docs.

    Wily extensions and differences include:

    • sam-like command redirections: <, >, | - operate on the current selection
    • you can export rc functions and variables to wily
    • no confirmations - automatic backup of dirty files
    • no warnings when using New to create a new file
    • black (dirty) resize box is more visible in wily
    • long-running processes can open a socket to wily
    • HISTORY mechanism
    • Indent, Dotfiles, Clear and Anchor builtins
    • Exit in acme is called Quit in wily
    • Zerox in acme is called Split in wily
    • acme executes a B2B1 command in the context of the command whereas wily does it in the context of the argument
    • acme selects B2 output
    • window tags scroll horizontally
    • contracting labels using environment variables. For example, if a window represents /u13/pgrad/gary/src/, on the screen it will show up as $h/src/ if you set h=/usr/pgrad/gary
    • if you hit Return immediately after selecting some tag text with the Escape key, it acts as if you'd clicked it with button 2, so typing 'echo fish', Escape, Return executes that command.
    • each line in $WILYTOOLS or $HOME/.wilytools can contain either a comment (starts with whitespace or '#') or a regexp, then a tab, then some tools (i.e. some text) which will be appended into the tag of any window whose label matches the regexp. The first regexp match wins.
    • editing the label of a window does "the right thing" if you then B2 on Get
    • you can set the wily file, directory, column and main tags, via $WFILETAG, $WDIRTAG, $WCOLTAG and $WMAINTAG
    Wily does not have the following Acme capabilities:
    • the Font builtin should be able to take an argument - this can be fixed
    • Dump/Load not implemented yet (could be done by an external program)
    • acme makes the right column skinnier - good for guide files
    • there is no equivalent to /mnt/acme
    • ID, Incl, Local, Send, Sort not implemented
    A striking similarity :-)
    • the View will scroll (with lots of ugly flicker) while selecting, to allow you to select an area larger than the View.

    Thanks to <Gerry.Tomlinson@newcastle.ac.uk> and <gary@cs.su.oz.au> for their comments.
    Steve Kotsopoulos <steve@border.com> - Nov 11, 1996 wily-0.13.42/Doc/intro.html000064402366570000012000000100041033320152300152150ustar00ozstaff00004330000002Introduction to Wily

    Introduction to Wily

    What is it?

    Wily is a mouse-oriented, text-based working environment for programmers. It lets you interact with your files, directories and other programs through mouse and keyboard operations on plain text.

    ./configure; make should compile the program with no problems on most Unixes with X Windows.

    What does it look like?

    screen shot Wily divides the screen into columns, and the columns into windows. Each window has a one-line tag which holds the name of the window, and some useful bits of text. Text can be displayed in either proportional or fixed-width fonts. Unicode fonts are supported. Text is read and written in UTF8 format, which is backwards compatible with 7-bit ASCII. The screen shot demonstrates some of these features. Directories are tabulated.

    What's good about it?

    Wily's most attractive qualities are simplicity, power and speed.

    Simplicity

    The interface is simple to learn. A one page user manual gives a reasonably complete description of how to use Wily.

    The implementation is also reasonably simple: wc -l *.[ch] gives a total of 8832 lines.

    Power

    Wily's simplicity derives from having few features. However, these features are quite general, have few complicating exceptions and combine well together. Every piece of text on screen can be interacted with in exactly the same way. Part of Wily's power emerges from being able to combine a few simple primitives in arbitrary combinations (like chess or go).

    Wily also encourages the use of other tools from the Unix toolchest. It is easy to build a set of (for example) HTML processing tools that work well with Wily.

    Speed

    With some practice, a decent mouse and mousepad, a Wily user can be very quick. The author is moved almost to tears of frustration using many other editors. You need never retype anything while using Wily.

    Interesting Features

    Backups

    Whenever a window containing changes not refleted on disk is deleted, Wily first makes a backup of the file, instead of initiating an "are you sure?" dialog. This seems not only quicker but safer than forcing a dialog, as occasionally the user might give the wrong answer to a dialog, whereas with this system a backup is always there.

    Proportional text by default

    This is much easier to read. On the rare occasions you need to drop back to monospace, it can be done with a mouse-click.

    Mouse "chords"

    i.e. using a combination of mouse buttons for Cut and Paste. This is way cool.

    Unicode text

    This is becoming more expected than unusual.

    Drawbacks and problems

    Wily is certainly not for everyone.

    The main complaints against Wily, with some responses, follow:

    You have to use the mouse too much
    The mouse is currently the best way to quickly select an arbitrary piece of text on screen. Mostly you're either using the mouse exclusively or the keyboard exclusively. It is quite rare to "thrash" between the two.
    There aren't enough control keys/function keys
    go away
    There's no syntax highlighting
    Wily is for editing plain text
    I have to use an external program to do global replace?
    1. this is pretty simple and reasonably efficient
    2. Wily may someday include this functionality
    A builtin extension language would be more efficient than using external programs
    Probably. The current system is much simpler and is efficient enough so far.
    It doesn't seem very intuitive
    In other words, it doesn't seem very familiar, at first. Of course. This is a necessary price of being very different. On the other hand, Wily is so simple it takes very little time to become familiar with it.

    gary@cs.su.oz.au wily-0.13.42/Doc/credits.html000064402366570000012000000052031033320152300155240ustar00ozstaff00004330000002People and history behind Wily

    People and history behind Wily

    Wilyfans

    Mail wilyfans@jli.com with comments and queries about Wily. The wilyfans list is the place for discussing and announcing changes to Wily.

    Mail wilyfans-request@jli.com to (un)subscribe.

    The list is archived at http://wwwtios.cs.utwente.nl/archive/wilyfans/threads.html

    People

    Regrettably, this list is very incomplete and out-of-date.

    N. Wirth, J. Gutknecht
    Oberon
    Rob Pike <rob@plan9.bell-labs.com>
    Acme
    Gary Capell <gary@cs.su.oz.au>
    Wily first draft, current maintainer
    Bill Trost <trost@cloud.rain.com>
    too many patches, bugfixes, ideas to list
    fixed listen() race condition
    stripnulls bug
    expanded address stuff
    better env.c
    reduce excessive redraws
    fix for next_width bug
    much of the messaging design
    "undo" bugfix
    Dot builtin
    tag_findtool
    Steve Kilbane
    integrated sam's regexp
    Richard Wolff
    sunos4 patches,
    msg.c bugfix
    use salloc, srealloc in sam regexp stuff
    Arnold Robbins
    cleanup wilyfifo
    ignore SIGPIPE
    Assar <assar@pdc.kth.se>
    autoconfig stuff
    Scott Schwartz
    prevent $TMPDIR replacing /tmp in tag
    fix to wily/sam.c:/^error_c
    path.c - nextstr pathfind searchincludedirs
    Mark H. Wilkinson <mhw@minster.york.ac.uk>
    fix ESC bug
    use $WILYBAK as the backup directory
    bug in delpane
    snarf/paste use X clipboard
    memory overrun in libmsg/util.c:/^stripnulls
    pstrapp
    Bjorn Helgaas <helgaas@convex.hp.com>
    fix bug when scrolling one-line window
    bug in event.c
    Font builtin
    better scrolling
    Local builtin
    nicer scroll_init
    FILENAME_MAX -> MAXPATHLEN in libmsg/connect.c
    Kyle <kaschei@staff.cs.su.oz.au>
    wily.xpm
    bug: in win.c
    Davor Cubranic <cubranic@hermes.si>
    bugs: New window has no cursor, Look in empty window dumps core
    Rich Salz,
    Beirne Konarski,
    Scott Schwartz
    Daniel Neri <d92-dne@nada.kth.se>
    "Split" bug-report
    Stephen Gallimore <stephen@psyc.leeds.ac.uk>
    pathfind patch

    History

    Oberon

    Help

    Acme

    Wily

    Differences between Wily and Acme

    Are detailed in another file wily-0.13.42/Doc/FAQ.html000064402366570000012000000074271033320152300145100ustar00ozstaff00004330000002Wily FAQ

    Wily FAQ

    What is wily?
    See the introduction.
    What does "wilydiag: File exists: can't open fifo" mean?
    Wily opens and listens on a fifo in /tmpin case some program tries to communicate with it. If you're not doing anything tricky like that, it won't get used at all. Ordinarily wily cleans the fifo up when it exits, but if something dire happens Wily may not get a chance to clean up. The fifo will be named $WILYFIFO if that is defined, otherwise /tmp/wilyUSER$DISPLAY, where USER is your login name. Just remove it and restart wily to be able to use wily messages.
    "Why does my compiler/editor/whatever complain about illegal characters? The line looks fine to me."
    Chances are that you've managed to enter a control character accidentally, and the font you're using doesn't display control characters. The easiest way to check is to select the line (or other text) that's causing the complaint, and click on "|cat -v" (or some other program that can display control characters, such as vis or od). I find ^A the most common offender.

    The Wily Window Manager?

    Window management is probably the biggest open problem with Wily, probably because there's no real solution, only heuristics.

    The first iteration of Wily creatied a bunch of separate X windows and let the window manager handle arranging them. This seems a more modular, tool-based approach. However, bitter experience showed that most existing window managers just don't cut it when you're quickly creating and deleting lots of windows. Acme's window management,was much better.

    The logical solution then would be to write an X window manager that works like the window management in Acme. However:

    • Writing a window manager requires knowing a _lot_ more about X than I ever want to know
    • Either the wily windows would need to be separate processes, communicating probably via some sort of X IPC (more arcane X'ery), or libXg would need to be modified to allow multiple windows (O who will save me from this plague of X?)
    • This sort of window manager would probably _not_ be appropriate for managing the other windows normally on the desktop.

    So Wily is designed to be run in one big window, and it does its own window management within that. It's a bit of a hack, but probably the best solution for the moment.

    Still, I hope it shouldn't be too hard to remove the "Wily is managing all the windows" assumption from the code if some brave soul solves the problems mentioned above.

    Funky B3 expansion allows some letters, not others?

    To quote rob (it was originally rob's comment, wasn't it?): "Hard to get absolutely right." The problem is that you can have pretty much everything in a filename apart from \0, but usually you want it to pick sensible strings. It's not just filenames, after all, but also identifiers in programs. After all, Acme is primarily a programmer's tool, because there aren't any other kinds of Plan 9 user. :-) Plus, most of them are shell metacharacters (in rc).

    The set you want to match varies from instance to instance, so it's pretty much an arbitrary choice. Sometimes you lose. Some justification would be good for the docs, though. Anyone know why "*" is considered a valid character? Hmmm. Ones not in the above list are "#$^*_-:~,./". Of these, "~./" are parts of common filenames (~steve/x.c), "#$-:,." are part of the syntax for expressing an Acme address, and "_" is a common identifier character. That just leaves "^*". I suspect these are allowed because they're commonly used as part of a regexp search.

    Steve Kilbane

    Why does it take so long to load my [mumble]-meg file?

    Blame steve. wily-0.13.42/Doc/user.html000064402366570000012000000575601033320152300150620ustar00ozstaff00004330000002Wily User Manual

    Wily User Manual

    Command-line Arguments

    wily [-p9fn font] [-fn font] [-p9fixed fixedfont] [-a tabsize] [-c columns] [file name...]

    -p9fn font
    (or X resource p9font) set the default proportional font. This must be the name of a Plan 9 font file.
    -fn font
    (or X resource font) set the default proportional font. This must be the name of a X font. The default is "variable"
    -p9fixed fixedfont
    (or X resource p9fixed) set the monospace font. This must be the name of a Plan 9 font file. The default monospace font is "fixed"
    -a tabsize
    set the maximum width of tabs (as multiple of the width of the character '0') for the proportional font. Defaults to 4.
    -c columns
    set the initial number of columns. Defaults to 2.
    -e command
    Run 'command' on startup.
    file name...
    Start wily with the named files and directories open.

    Environment variables

    SHELL
    External commands are sent to the shell for evaluation. Defaults to /bin/sh
    HISTORY
    If $HISTORY or $history are set, commands are written to this file before execution.
    WILYBAK
    Wily uses $WILYBAK or $HOME/.wilybak as the directory for backups.
    WMAINTAG, WCOLTAG, WFILETAG, WDIRTAG
    If any of these are set, their value is appended to the default text to be added to the tag of the main window, a column, a file window or a directory window, respectively.
    WILYTOOLS
    If $WILYTOOLS or $HOME/.wilytools exist, they are read and used as a tools patterns file. (See later section).
    INCLUDES
    If set, this is used as a search path for include files.
    WILYLABEL, w
    For external processes, Wily sets $WILYLABEL and $w to the label of the window in whose context a command is executing.
    PATH
    Wily itself ignores $PATH, but when it calls the shell to run external programs the value of $PATH is important.
    WILYFIFO, DISPLAY, TMPDIR
    Wily communicates with some other programs using a fifo at a well-known location.

    The name of the fifo will be $WILYFIFO if this variable is set, otherwise it will be /tmp/wilyUSER$DISPLAY, where USER is calculated from the password file. If $TMPDIR is defined, it is used instead of /tmp.

    Wily also sets $WILYFIFO so any children it creates will know how to talk to it.

    Appearance

    Column, window, tag, body, resize box

    screen shot Wily appears as one or more vertical columns, divided into windows of scrolling text. Each column or window is headed by a one-line tag. The leftmost text of the tag (up until the first whitespace) is the name of the window. Usually this is the name of some file or directory. Wily also places other bits of text in the tag, which might be useful later as commands. There is a one-line tag above all the columns, which is called the wily tag.

    The text in the body of the window may represent a directory, a file, the interface to some program like a news reader, or the output from a program.

    The small square-ish box to the left of the tag is called the resize box. The resize box is used for moving and reshaping windows and columns.

    If the resize box is filled in, this indicates that the window is dirty. A dirty window contains text which has been modified since it was last read from or written to disk.

    Proportionally spaced, Unicode text

    Text is displayed in a propotionally spaced font by default. There is a built in function to toggle with a monospace font when required.

    Text is read and written as UTF8-encoded Unicode, providing some support for editing multi-lingual and scientific text, but remaining backwardly compatible with plain 7-bit ASCII text. See 9term for an example of another program with Unicode support, with some screen shots.

    Notation

    B1, B2 & B3 are left, middle, right mouse buttons, respectively. Used as a verb, they mean "click with that button". E.g. "B2 in the command word" means "click with the middle mouse button in the command word".

    B1B2 means to select some text with B1 held down, then click and release on B2 while still holding B1 down.

    Sweep with B1 means to hold down B1, drag it across some text to select it, and then release B1.

    The last selected text is the text which was most recently selected, usually by being swept with B1.

    The last selected window is the window containing the last selected text. This is indicated by that window having a slightly thicker border. If the last selected text was in a column tag or the wily tag, there is no last selected window.

    Context

    All text in wily has a context. The context is the name of a directory associated with that text. This context is used when executing commands and opening files.

    If the text is in a window, its context is the name of that window, up to and including the last /. So if three windows have the names /usr/gary/+Errors, /usr/gary/guide and /usr/gary/, the context for all the text in all of these windows is the same: /usr/gary/. Note that the context need not be a directory which actually exists.

    If the text is in a tag which isn't part of a window (i.e. a column tag or the wily tag), the context is the name of the directory where wily was started.

    Scrollbars and scrolling

    Scrollbars are proportional, i.e. the size and position of the scrollbar's thumb indicates the size and position of the visible portion of the text.

    Each of the three mouse buttons does something different when clicked in the scrollbar.

    B1 and B3 are used for relative movements. B3 moves the text next to the mouse pointer up to the top of the window. B1 moves the text at the top of the window down so it is next to the pointer. Both of these rules have the effect that clicking near the top of the scrollbar causes small movements, (either up or down) and clicking near the bottom causes large movements.

    B2 is used for absolute positioning. B2 moves the visible part of the text to a point in the text proportional to how far down the scrollbar the pointer is. That is, clicking at the bottom of the scrollbar with B2 jumps to the end of the text, clicking at the top of the scrollbar with B2 jumps to the beginning of the text.

    All of these movements repeat if the mouse button is held down in the scroll bar.

    The PageUp and PageDown keys scroll up or down by about half a page. The Home and End keys scroll to the top or bottom of the file.

    Selecting and editing text (B1)

    Type normally anywhere on the screen to enter text. The keyboard focus follows the pointer in a "point to type" fashion. That is, the characters you type will appear in the tag or body which currently contains the pointer. Position the cursor within text either with cursor keys, or clicking once with B1. Select text by sweeping it with B1. Sweeping text and then typing replaces the selected text with the typed text.

    Control Keys

    ctrl-u
    delete line
    ctrl-w
    delete word
    Escape
    if the selection is null, select all the most recently typed text, otherwise delete the selection

    Double-click

    Double-clicking with B1 can select a word, a line, or the text delimited by quotation marks, braces, brackets or parentheses, depending on where you double-click.

    Executing commands (B2)

    Selecting the command

    Sweep text with B2 to execute it as a command.

    If you start sweeping some text with B2, then decide you don't want to execute it, click B3 before you release B2 (i.e. a B3B2 chord) to abort.

    The command window is the window containing the text which was swept with B2. The context of the command is the context of the text swept with B2.

    If the text starts with the name of one of the builtin commands, that builtin is executed.

    Otherwise, the command is executed by forking a subprocess, establishing an environment and execing $SHELL -c command.

    Environment for external commands

    • The current directory is set to the context of the command.
    • $WILYLABEL and $w are set to the name of the command window and added to the environment.
    • Standard input is set to /dev/null
    • Standard output and standard error are set such that output to them ends up being sent to a window in Wily called context/+Errors
    • The first word of the command will be added to the wily tag to indicate which programs are currently running.
    • $WILYFIFO will be set to the name of the fifo this instance of Wily is listening to for messages. See the main wily page for programmers manuals on how to use this messaging interface.

    One exception is that if the name of the command starts with "|", "<" or ">", standard input and output of the command are set up such that the last selection is piped through the command, fed into the command or replaced by the output of the command, respectively.

    For example if a paragraph is currently the last selection, executing "|fmt" will format the paragraph, executing ">lp" will print it, and executing "<cat file" will replace it with "file"

    Builtin Functions

    By convention all of the builtin functions start with a capital letter. Some of them operate differently if called with an argument.
    Put, Get, Putall
    Put and Get write the window to disk, or fetch from disk, respectively. If called with an argument, they will use the argument as the filename, instead of the name of the window.

    Putall writes all dirty files to disk.

    New, Del
    Create a new window, or delete a window, respectively. If New is called with an argument, it will use the argument as the name of a file to create, otherwise the new window is called context/New, where the context is taken from the last selection.
    Look
    Searches in the command window for literal text. The text it searches for is either the argument to Look, or the current selection in the body of the command window.
    Undo, Redo
    Move backward or forwards through the (infinite) Undo log. If called with an argument, these commands repeat until they reach an end of the log, or the text is in the same state as it was the last time the file was read from or written to disk.
    Newcol, Delcol
    Create or delete a column
    Cut, Paste, Snarf
    Cut the currently selected text to the X selection buffer, replace the currently selected text with the X selection buffer, or copy the currently selected text to the X selection buffer, respectively.
    Quit
    Exit wily.
    Kill
    Kill some process which was started from wily. If called with an argument, Kill that process. Without an argument, Kill writes a list of possible Kill commands to window $wilydir/+Errors
    Font
    Toggle between fixed and proportional fonts. Depending on where Font is clicked, changes the font for a window, a column, or for all the windows on the screen.
    Dotfiles
    Toggles whether or not dot files are displayed in directories. Directories will not be re-read automatically, though.
    Anchor
    Adds an address to the tag of the last selected window. If called with an argument, the address is a line address, otherwise the address is a character address. The address is of the form ":currentaddress,."

    To select large chunks of text, B1 click at the beginning position, execute Anchor, B1 click at the end position, then click with B3 in the address in the tag. The anchor may also be used as a bookmark, or just to find the character or line position in a window.

    Split
    Split the most recently selected window into two. Editing actions in one window will be visible in the other.
    Indent
    Toggles autoindent for a window or all windows, depending on the command window.
    Clear
    Deletes all the text in the command window.

    The system tries to ensure that the names of some builtin commands are added to or removed from window tags as appropriate. For instance, when a window becomes "dirty", the word "Put" is added to its tag, and removed again when the file becomes clean. Similarly, the words "Undo" and "Redo" should appear in the tag of a window when and only when they can be executed.

    Open/Search (B3)

    Sweep text with B3 to make Wily try to goto (open or search for) the swept text.

    The text may be interpreted as:

    filename:address
    Open filename and search in it for address
    :address
    Search for address in the window containing the swept text, or in the last selected window, if the swept text was not in a window.
    filename
    Open file or directory filename if it exists.
    includefilename
    Open includefilename if it can be "massaged" (see below) into the name of an include file (e.g. stdio.h)
    literal
    If the swept text is contained in a window, do a literal search in the body of the window for literal.

    When trying to open a file or directory, the swept file name will be interpreted relative to its context. For example, the text foo.c:14 in a window with context /usr/gary/src/ will be interpreted to mean the address /usr/gary/src/foo.c:14

    Addresses

    Wily uses the address and regular expression code from Sam. Please refer to the Sam manual for a better explanation.
    #n
    The empty string after character n; #0 is the beginning of the file.
    n
    Line n; 1 is the beginning of the file.
    /regexp/ ?regexp?
    The substring that matches the regular expression, found by looking toward the end (/) or beginning (?) of the file, and if necessary continuing the search from the other end to the starting point of the search. The matched substring may straddle the starting point. When entering a pattern containing a literal question mark for a backward search, the question mark should be specified as a member of a class.

    Regexps are as defined in regexp(6) in the Plan 9 manual.

    $
    The null string at the end of the file.
    .
    Dot. The current selection in a window.
    address1,address2
    The range from the start of address1 (defaulting to the start of the file) to the end of address2 (defaulting to the end of the file). E.g. :., selects from the current selection to the end of file.

    Include Files

    When searching for a filename, if the filename doesn't exist in the context of the search text, Wily also tries to expand the file name using a few simple heuristics.

    If we are searching for name and name appears between double-quotes or angle brackets, Wily also searches for name in the directories in the search path $INCLUDES (or /usr/include, if $INCLUDES isn't set).

    For example, sweeping stdio.h between angle brackets will open /usr/include/stdio.h on the author's system.

    Mouse short cuts

    Cut (B1B2), Paste (B1B3)

    To cut some text into the clipboard, select the text with B1, and while holding it down, click B2. The selected text will be cut from the window and copied to the clipboard.

    Similarly, select some text with B1, and while holding it down also click B2, and the selected text will be replaced by the contents of the clipboard. The clipboard will be unaltered.

    Note that so long as you hold down B1, you can alternately Cut and Paste the selected text with B2 and B3. A Cut immediately followed by a Paste in this way leaves the file unmodified, and has the effect of copying the current selection to the clipboard.

    Execute with argument (B2B1)

    A command can be called with an argument using another mouse chord. Sweep the command with B2, and while holding it down, click B1. The last selection will be appended to the command. The context of the command and the command window will be set to the context of the last selection (unless the command is a builtin).

    For example, say I have a script called "sg" (short for source grep) that greps through all the source files in the current directory for a symbol given as an argument. I can then sweep with B1 to select "printf" in a source file, then B2B1 on the word sg (anywhere). The command "sg printf" will then run in the same directory as the source file.

    Selection expansion

    A null selection (single click) with B2 or B3 will be expanded to some of the surrounding text.

    A click inside an existing selection will be expanded to that selection.

    This means you can select (with B1) some complicated command once, and B2 inside this selection many times to execute the command repeatedly.

    This rule is also helpful when searching through multiple occurrences of a piece of text, as clicking with B3 in the most recently found instance searches for the next instance.

    A click that is not inside an existing selection will be expanded depending on which mouse button was used.

    A single B2 click automatically selects a sensible "word" as the command. Commands can be built-in (Capital first letters, by convention) or passed to the shell for invocation.

    Clicks with B2 are expanded to select commands, i.e. strings of alphanumeric characters, |, > or <. Clicks with B3 are expanded to select addresses, i.e. strings of alphanumeric characters, :, ",".

    Miscellaneous

    Window management

    Wily windows are placed automatically using heuristics. Hopefully most of the time the window will be placed somewhere useful. However, windows and columns can be moved and reshaped. The resize box (the little box on the far left of the tag) of a pane or a column may be manipulated to move or reshape a window.

    Dragging the resize box (with any mouse button) moves the column or window to the desired location.

    Clicking in a pane's button with different mouse buttons has these different effects:

    B1
    the window grows a bit, first taking up any blank space in the column
    B2
    Every window except the desired one is shrunk so that only their tags are visible, leaving more space for the desired window.
    B3
    The window expands to take up the whole column, obscuring all the other windows in that column. Clicking with any mouse button in the window's resize box will undo this effect.

    Cursor Warping

    After a successful search, the text that was found is highlighted, and the cursor is warped there, so that to search for the next instance of the search text, no cursor movement is required, it is only necessary to click the rightmost mouse button again. Window re-arranging operations warp the cursor to the resize box of the window that moved, so the move can be easily refined.

    Back-up files

    Whenever a dirty window is to be deleted, a backup is made. This is an alternative to the familiar (and often-annoying) "are you sure you want to close this window?" dialog. A warning message is printed when this happens.

    Backup files are kept in directory $WILYBAK if it exists, or $HOME/.wilybak. In this directory the file TOC is a table of contents showing what real file each backup file maps to.

    .wilytools

    Wily attempts to read either $WILYTOOLS or $HOME/.wilytools. Each line in this file should be either empty, a comment (starts with '#') or a pattern, a tab, and some arbitrary text. The pattern is a regular expression. Every time Wily creates a new window, if the window's name matches one of the patterns, the text after the tab on that line will be appended to the tag for that window. Wily stops searching after the first match.

    Below is the author's .wilytools :

    Mace.*Errors$	Clear mace subject 
    Errors$		Clear
    Mace/in/$	mace subject
    Mace/in		reply wrm wmov
    Mace.*/$	subject 
    Mace/out	deliver 
    Mace		reply	wrm 
    /src/.*/$	def sg 
    News		followup 
    Makefile	make 
    print/$		gv bpr 
    \.py$		ptest
    bin/rc/		775
    
    The mace, reply, deliver and subject scripts and Mace directory are to do with reading mail. def and sg are useful scripts for searching through source files, so they are added to the tag of any directory with src in its pathname. make is a logical command to execute when viewing a Makefile.

    Fonts

    Wily uses two fonts: a variable-width default font, and an alternative fixed-width font. These may be set with command-line arguments or X resources.

    Wily first tries to open a Plan 9 font file, given as either a -p9fn command-line option or *p9font X resource. Failing that, it uses the -fn command-line option or *font X resource. Failing that, it uses the font "variable".

    Plan 9 font files are useful for supporting the full Unicode range without requiring massive fonts. The font file sets up a font by joining together different subfonts. See the 9term page for information about obtaining Unicode fonts and utilities to convert other character sets to Unicode.

    The format of of a font file is described below: (Taken from font(4) from the Plan 9 Manual)

    External fonts are described by a plain text file that can be read using rdfontfile. The format of the file is a header followed by any number of subfont range specifications. The header contains two numbers: the height and the ascent. The height is the inter-line spacing and the ascent is the distance from the top of the line to the baseline. These numbers are chosen to display consistently all the subfonts of the font. A subfont range specification contains two numbers and a font name. The numbers are the inclusive range of characters covered by the subfont, and name specifies the name of an X font suitable for getsubfont. The minimum number of a covered range is mapped to the first defined character of the corresponding subfont. Each field must be followed by some white space. Each numeric field may be C-format decimal, octal, or hexadecimal.

    Here is the start of the font file the author uses for a monospace font:

    17	14
    0x0000	0x00FF	lucm.latin1.9
    0x0100	0x017E	lucm.latineur.9
    0x0180	0x01F0	matty.latinext.9
    0x0250	0x02E9	lucm.ipa.9
    0x0300	0x0308	matty.gendiacritics.9
    0x0370	0x0372	matty.greekpunc.9
    0x0386	0x03F5	lucm.greek.9
    0x0400	0x0475	misc.cyrillic.9
    

    Entering non-ASCII characters

    Refer to the Plan 9 keyboard(6) manual page, which is mostly how it works in wily.

    References

    UTF8-encoded Unicode,
    gary@cs.su.oz.au the text foo.c:14 in a window with context /usr/gary/src/ will be interpreted to mean the address /usr/gary/src/foo.c:14;[ThztSiY :dED#F}Φw[/2hlul&3jPH飉fƥ)!cvk$n\XmScreate('/win/name'); %wins = $wily->list(); $id = $win->id(); if ($win->isattached()) { ... } $win->setname('/mumble'); $win->settools('foo bar baz'); $win->attach($mask); $win = $wily->open($name, $id); $text = $win->read($p0, $p1); $win->replace($p0, $p1, $newtext); $win->exec($cmd); $win->goto($q0, $q1, $addr, $setdot); $length = $win->length(); if ($win->wouldblock()) { ... } $msg = $wily->event(); $msg = $win->event(); $win->bounce($msg); $wily->bounce($msg); ($type, $msgid, $winid, $p0, $p1, $flag, $string) = unwrapmsg($msg); $msg = wrapmsg($type, $msgid, $winid, $p0, $p1, $flag, $string); $fd = $wily->fileno(); $errmsg = $wily->errstr(); DESCRIPTION CONNECTING TO WILY $wily = new Wily; This connects to Wily. It doesn't do anything else, so you're not going to receive any events, or see any new windows appear. $wily is an object that you can use to communicate with wily, however. There is no disconnect operation: this happens automatically when the Perl process dies. CREATING NEW WINDOWS $win = $wily->create($winname); This returns a new object that you can use for performing operations on the window. The window should appear on Wily's screen immediately. You can use $win for sending messages to Wily immediately - see below. Right now, you can't specify whether the window refers to a real or virtual file. This method used to be called newwin(), but was renamed to open() as of 0.03. newwin() will still work, but you'll get a non-suppressable warning. LISTING EXISTING WINDOWS %list = $wily->list(); or %list = $win->list(); The returned hash is the paths of each window currently open in Wily, indexed by their window ids. Note that it doesn't matter whether you use the connection object or a window object to get the list. OPENING EXITING WINDOWS $win = $wily->open($name); $win = $wily->open($id); $win = $wily->open($name, $id); This method returns a window object that is connected to the named window, but not attached to it; you won't receive any events from it yet. You can use the window's name, id or both to specify the window to be opened. This method was briefly called oldwin(), which was pretty daft. It's also the reason why newwin() was renamed to create(). WINDOW IDENTIFIERS $id = $win->id(); This just returns the id of the current window. You only really need this for finding out the window's pathname, with the list() method above. Window objects will return their identifiers, but the connection object will return a fake ID (because it's not really a window). This ID has the value $MainCon, which you can reference if you include it in the "use" statement, or if you explicitly give the package name: $Wily::MainCon. CHANGING TAG LINES $win->setname($newname); $win->settools($newtools); These methods allow you to change the pathname or tool list for a window. They return true if successful. Note that the tool listing is a single string. It should probably be a list, but it isn't, at the moment. READING WINDOW TEXT $text = $win->read($p0, $p1); This method returns a single UTF string, containing the text between character offsets $p0 and $p1 ($p1 is the offset of the first character AFTER the returned range). If the read fails - such as because the range is invalid - the method returns undef. WRITING WINDOW TEXT $win->replace($p0, $p1, $newtext); This method is used for updating window contents. The text specified by the range $p0-$p1 is removed, and $newtext is inserted in its place. If $p0==$p1, this is just a simple insertion. If $newtext is the empty string, then this is just a deletion. Returns false if it fails. SEARCHING AND ADDRESSES $win->goto($q0, $q1, $addr, $setdot); A slightly more complex method, this. It's used for two things: resolving a textual address into a character offset range, and for setting dot. $q0 and $q1 specify the starting range for the search. $addr is the text to search for. It can be any Wily address: If Wily manages to find what you're searching for, it sets the values of $q0 and $q1 to its address. If $setdot is also true, it also moves the window's current selection to be where the matched text is. Returns true if the pattern is found, and false otherwise. There are a couple of bugs in this method. The first is that you should be able to specify that dot will be used, and that $q0 and $q1 are ignored. The second is that if the address happens to reference a different window, it should return the window id of the new window. WINDOW CONTENTS LENGTH $len = $win->length(); This method is just a wrapper around goto(), but it seems to be quite handy. SENDING COMMANDS TO WILY $win->exec($cmd); Runs $cmd in the context of the window. $cmd can be a shell command, or it can be a Wily builtin. Returns false if something doesn't work. HANDLING EVENTS Attaching Initially, window objects aren't attached to the window they're associated with. This means that Wily handles all events itself. To start receiving events for a window you've created, use: $win->attach($mask); Mask specifies which events you're interested in. The events are: Just add the events that you're interested in together, as in: $win->attach($WEexec + $WEgoto); Again, name the events in the "use" statement, or use $Wily::WEexec, etc. Attach returns true for success, and false for failure. To attach to an existing window, use: $win = $wily->open($id); $win->attach($mask); where $id is the ID (or the name) of the window you want to attach to. The resulting object is an attached window object (or undef, if something goes wrong). Version 0.02 used a method called attachid(), which turned out to just a fairly limited improvement over version 0.01 - you could attach to windows just created with newwin(), but not to existing windows. attachid() has been replaced by a combination of open() and attach(); attachid() will still work, but you'll get a non-suppressable warning message. Wily will send goto and exec events directly to your client, without any processing. In contrast, replace events will already have been processed when you receive them; Wily is merely informing you of their occurrence. I'm not sure when wily sends destroy events; so far, I've never seen one. :-) Wily patch The wily.patch file contains a patch to ../wily/external.c - it fixes two problems. The first is that Wily 0.12.11 didn't expect any clients to bounce WEreplace events (after all, Wily's already processed them), so it didn't check for them. The result was that it reports them as unknown events. This patch just makes Wily ignore them. The other problem is that Wily echoes WEreplace events back to the client that sent them in the first place, if that client is attached to the window. This is a little silly, and means that clients have to be extremely careful about event handling. This patch stops Wily doing this, so you know that if you *cause* the event, you're not going to be notified about it too. Detaching $status = $win->isattached(); This method is to determine whether you're attached to the window. The Wily.pm module is supposed to notice the destroy events coming in from Wily, and mark the window object as detached, but since Wily doesn't seem to send these events, this doesn't work at the moment. As for explicitly detaching, there ISN'T a method for doing that. Nor, apparently, can you change the set of events you want to receive. Accepting events You receive events with: $msg = $win->event(); The returned value is an anonymous hash containing the components of the message. The keys are: 't' - the message type. =item 'm' - message ID. =item 'w' - window ID. =item 'p0' and 'p1' - the range. =item 'f' - the flag. =item 's' - the string. so you can do: if ($msg->{'t'} == $WEexec && $msg->{'s'} eq 'Del') { ... } The event() method blocks until it receives an event, so you can use: $win->wouldblock() which returns true if event() would block. For both event() and wouldblock(), if you call them from a window object, they'll only consider events for that window. If you call them from the connection object, they'll return events for any windows. WARNING: This is untested functionality - I *think* it'll queue events for other windows properly, but I haven't had a chance to check it yet. Also, bear in mind that if you have several windows accepting events, you should make sure that you read events for other windows eventually, to drain the queues. In the returned hash, 't' is a numeric value, equal to one of the four event types given previously. 'm' is the identifier of the message. I don't think it's actually useful, but Wily might pay attention to it in bounces - I'm not sure. 'w' is the window identifier of the window this event occurred in. This is necessary if you've got more than one window attached at once, and you're reading with the connection object, instead of the window object. 'p0' and 'p1' are range involved: In both exec and goto events, the range will have been expanded by Wily to something sensible, if it was a single-click event. Offhand, I can't remember what 'f', the flag signifies, in events. 's' is the inserted text, for replace events, the command to be executed in exec events, or the pattern to be searched for, in goto events. If you don't like using the returned hash, you can break it up into a list, using the function "unwrapmsg": ($type, $msgid, $winid, $p0, $p1, $flag, $string) = unwrapmsg($msg); Note that this isn't a method, which means that you have to name it in the "use" statement, or precede it with "Wily::". Bouncing events It's quite common that you're only interested in specific instances of a kind of event. For example, with exec events, you probably only care about the commands your client supports. The bounce() method allows you to send an event back to wily, if you're not interesting in handling it: $win->bounce($msg); $wily->bounce($msg); It doesn't matter whether you use the connection object or a window object - the information needed is all in the message anyway. If you to construct the message yourself, you can use the function "wrapmsg": $msg = wrapmsg($type, $msgid, $winid, $p0, $p1, $flag, $string); Again, this is a function, not a method, so you'll have to import it. WAITING ON MULTIPLE INPUT SOURCES If you need to select() on Wily's connection, because you've got other input sources to worry about, then you can use: $fd = $wily->fileno(); This will return a file descriptor that you can use with vec() and select() in the normal Perl way. Note that this relies on a small modification to libmsg/rpc.c, so you have to apply the patch in the file msg/rpc.patch before it'll work (or, in fact, compile). ERROR MESSAGES The errstr() method is supposed to return any error messages generated by libmsg, but it doesn't appear to be too reliable. Is that ironic, or what? print "Everything's broken: " $wily->errstr(), "\n"; DEBUGGING If you set $Wily::Debugging = 1, then you'll get buckets of diagnostics from the Perl module. If you define -DWILYPERLDEBUG in the Makefile.PLs, and rebuild *everything*, you'll get a little more from the underlying C code, but nothing startling. TESTING The test script, test.pl, attempts to exercise some of the module's functionality in a controlled way. It doesn't try out everything, because I can't think of a way of testing some of the methods where I can confirm their results reliably. You should have an instance of Wily running when you do "make test", and the Wily version must be the same as the one you originally linked the Wily module with, otherwise they probably won't talk to each other. Also check at the beginning of the script, for where it sets the value of $WILYFIFO: # $ Steve_Kilbane@cegelecproj.co.uk rch. $addr is the text to search for. It can be any Wily address: If Wily manages to find what you're searching for, it sets the values of $q0 and $q1 to its address. If $setdot is also true, it also moves the window's current selection to be where the matched text is. Returns true if the pattern is found, and false otherwise. There are a couple of bugs in this method. The first is that you should be able to specwily-0.13.42/Doc/C.html000064402366570000012000000272651033320152300142650ustar00ozstaff00004330000002Wily C Programmers Manual

    Wily C Programmers Manual

    Introduction

    Although a lot can be done with simple scripts and Wily, some applications will need finer control. Wily can act as a "user interface server". Clients can create and manipulate windows, and/or monitor events which happen in windows, by sending and receiving messages.

    There are two "levels" to the interface: an "RPC" level, where the library looks after low-level details of queueing, packing and unpacking messages, and a lower-level interface dealing more directly with message packets.

    Warning this API hasn't been used very much. There could well be bugs lurking in unused sections of code, and the API could well change.

    Establishing a Connection

    Call client_connect(), which returns a file descriptor open for reading and writing to Wily, or a negative number if there's been some error. client_connect() uses $WILYFIFO if it is set.

    RPC-style Interface

    Opening, Closing and Checking the RPC interface

    Handle* rpc_init (int fd);

    Create a new RPC handle to use file descriptor fd, which was probably returned from client_connect

    rpc_init cannot fail.

    Bool rpc_isconnected(Handle*h);

    Return whether or not h is still connected. If the RPC library starts receiving gibberish messages, it will cut the connection.

    void rpc_freehandle(Handle*h);

    Release any resources used by h, and free h itself.

    Requests

    If there's any sort of failure, all of these functions return a pointer to an error message, which is stored in a static buffer and only guaranteed to remain valid until the next rpc_* function is called. After a failure, it's possible that the connection to wily has been lost. This should be checked using rpc_isconnected

    If successful, these functions return (char*)0.

    List existing windows
    char* rpc_list (Handle*, char **bufptr);

    If successful, allocates a string, and stores a pointer to it in bufptr. It is the programmer's responsibility to free(*bufptr). The string contains one line for each window currently open in Wily. Each line contains the name of the window, some whitespace, and a unique number which identifies the window. The window identifiers are not reused within an invocation of Wily.

    Below is some example output from rpc_list:

    /n/staff/u13/pgrad/gary/src/wily/Doc/C.html	45
    /n/staff/u13/pgrad/gary/src/wily/Doc/index.html	41
    /n/staff/u13/pgrad/gary/src/wily/Doc/	40
    /n/staff/u13/pgrad/gary/guide	0
    

    Open or create a window
    char* rpc_new (Handle*, char *s, Id*id, ushort backup);

    Create or open window with name s. If Wily already has a window named 's', it uses that window, otherwise it creates a new window.

    The identifier for the opened/created window will be stored in id.

    If this request creates (not just opens) the window, Wily will make sure backups are kept for the window (and indicate when the window is dirty) if and only if backup is set.

    Request events from a window
    char* rpc_attach (Handle*, Id w, ushort mask);

    Asks Wily to send us events which happen in window w and match event bitmask mask.

    Each window can be sending events to at most one remote process. The window sends only events which match its event bitmask. An event bitmask is formed by ORing some combination of (WEexec, WEgoto, WEdestroy, WEreplace) (explained further below).

    rpc_attach will fail if w doesn't exist, or is already sending its events somewhere else.

    To stop receiving events from a window, use an rpc_attach with a mask of 0.

    Change a window's name
    char* rpc_setname (Handle*, Id w, char *s);

    Set the name of window w to s.

    Change a window's "tools"
    char* rpc_settools (Handle*, Id w, char *s);

    Set the tools section of w to s

    Read data from a window
    char* rpc_read (Handle*, Id w, Range r, char*buf);

    Read range r from w into buf, which must have enough space (UTFmax * RLEN(r)).

    The range r means the Rune offsets in w >= r.p0 and < r.p1. Don't forget that each Rune will be potentially encoded in UTFmax bytes.

    rpc_read fails if r is not fully contained in window w. rpc_goto may be useful to obtain legal ranges.

    Insert, delete or replace text
    char* rpc_replace (Handle*, Id w, Range r, char*s);

    Replace range r in w with UTF string s

    Note that insertion and deletion are special cases of replacement.

    Ask Wily to execute a command
    char* rpc_exec (Handle*, Id w , char *s);

    Cause Wily to act as though s were selected in w with button 2.

    Note that builtin functions (e.g. Del) can also be executed with rpc_exec.

    Ask Wily to "goto" a file or location
    char* rpc_goto (Handle*, Id *w , Range* r, char*s, ushort flag);

    Cause Wily to act as though s were selected in w with button 3.

    If this makes Wily do a search within '*w', the start position for the search is usually taken from '*r'. The search can instead start from the current selection of the file if r->p0 > r->p1. If there are multiple views of the same file, one is chosen arbitrarily.

    If the search is successful, '*w' and '*r' are set to the window and range found by the search. The range found will be selected and highlighted if and only if 'flag' is set.

    Hint: rpc_goto can be used to find useful ranges for rpc_read and rpc_replace. Don't forget that the search string can be any address that Wily understands, e.g. :4 or :, or :.,

    Events

    int rpc_event (Handle*h, Msg *m);

    Block until an event is received by h and fill in m. Returns 0 for success, -1 for failure. After a successful call to rpc_event, you will need to free(m->s).

    char *rpc_bounce(Handle *h, Msg *m)

    Returns m to Wily. Useful for events which we receive but we'd rather Wily took the default action on.

    Bool rpc_event_iswaiting(Handle*h);

    Returns true if rpc_event could be called without needing to block. Only useful if your program is reading from other input sources as well. (e.g. see win.c)

    Message-Passing Interface

    struct Msg {
            Mtype   t;	/* message type */
            Id      m;      /* message */
            Id      w;      /* window */    
            Range   r;
            uchar   flag;
            char    *s;
    };
    

    All the fields except the message type are optional. The string s is always null-terminated, is in UTF format, must be a complete UTF sequence, and is of zero length if not being used.

    These are the message types declared in msg.h, with brief descriptions, and important parameters:

    Request/Reply/Error

    WRerror(s)

    Message type returned by wily if there's an error with some request. s contains an error message. On the other hand, if the request completes successfully wily returns a message with message type one greater than the message type of the request.

    WMlist

    Asks wily to send a list of windows currently displayed.

    WRlist(s)

    Wily's reply to WMlist. Includes a string containing one line per active window. Each line contains a name and an id (as a textual number) separated by whitespace.

    WMnew(s,flag)

    Asks wily to create a window with a given label (which may be an existing file). If and only if flag is set, backups will be kept for the new window.

    WRnew(w)

    The id of the newly created window.

    WMattach(w,flag)

    Asks wily to send to the client events associated with this window, and matching the event mask set in flag

    WRattach()

    WMdetach(w)

    Asks wily to stop sending to the client events associated with this window.

    WRdetach()

    WMsetname(w,s)

    Change the name of this window.

    WRsetname()

    WMsettools(w,s)

    Change the tools for this window. Tools are simply words appearing in the tag of a window, after the window name and before the 'pipe' symbol. They are (will be) automatically maintained, i.e. they will be replaced if accidentally deleted.

    WRsettools()

    WMread(w,r)

    Read the text from w in range r.

    WRread(s)

    The requested text, as a UTF string.

    WMreplace(w,r,s)

    Replace the text from w in range r with UTF string s

    WRreplace()

    WMexec(w,s)

    Act as if s had been clicked with b2 in w

    WRexec()

    WMgoto(w,r,flag,s)

    Act as if s had been clicked with B3 in w at r. If flag is set then "dot" is set by wily, otherwise we return the window and range that would have been jumped to, but don't actually change "dot".

    WRgoto(w,r)

    The window and range we went to.

    WMfencepost()

    Not used for any message. Messages with Mtype less than WMfencepost are to do with our requests. Messages with Mtype greater than WMfencepost are events.

    Events

    These are the messages sent by Wily to clients who request to be notified of events in a particular window using WMattach

    The event types are used to form a mask to be given as a parameter to the WMattach request. For example, to request only exec and goto events, set m.f = WEexec|WEgoto before sending message m

    WEexec(w,s)

    s was selected with the middle (execute) button somewhere in w

    WEgoto(w,r,s)

    s was selected with the right (goto) button at r in w

    WEdestroy(w)

    w has been destroyed.

    WEreplace(w,r,s)

    The text at r in w was replaced by s.

    Packing and Unpacking Messages

    int msg_size (Msg *m);

    Returns the size of buffer that will be needed to "flatten" m

    void msg_flatten (Msg*m, char*buf);

    "Flatten" m into buf, which must have enough storage space allocated.

    ulong msg_bufsize (char*buf);

    Returns the total size of the flattened message starting at buf. Assumes that at least HSIZE bytes are stored in buf. A useful macro is #define FULLMSG(ptr,n) ( (n) >= HSIZE && (n) >= msg_bufsize(ptr) )

    int msg_init (Msg*m, char*buf);

    The reverse of msg_flatten. Fills in the fields of 'm' using the flat representation starting at buf Msg_init assumes that buf holds the complete message. m->s will point to an area within buf, but buf itself is not modified.

    void msg_print (Msg *m);

    Print a human-readable form of m to stderr Egoto, WEdestroy, WEreplace
    ) (explained further below).

    rpc_attach will fail if w doesn't exist, or is already sending its events somewhere else.

    To stop receiving events from a window, use an rpc_attach with a mask of 0.

    Change a window's name
    char* rpc_setname wily-0.13.42/Doc/cartoon.gif000064402366570000012000000501471033320152300153440ustar00ozstaff00004330000002GIF87a`AAApppVVV,`@H*\ȰÇHb X, #'pɊ( r 2I#Gv4͎3l@@J c qe1G0UVAe{bb*JyPV 0hWJVQ*cRj%'DMh{ Wd1YV/YœMWj|UURԠxl":rĔ^A@jɆibxjy(ӬQkJI+]6PSrldUTSU ,X_[Wn+phJ'EڤcMdncke e6gS^u]f3_}s]OѴZnVLuO=ZU:O')j:en]~^netdޔmURe`I7 eMڀ:1 m:T %Ti@a[ij{ZT[?7{6)Q_ԺM``7߼Wu:zM4-9Oa}Iz^3n(,%OMvhM<%KRc%`^<ЂV+,nySW+:j>&rQA6e;"5@/Iӭt[х4H3`Ȣ200{Xn2#]G<"T2(!#IE=V v~v(̦L/sA5H %54JQZ%tq=ׂRFOdD&LVF/Q v ٲJ..~Pغd1MT&Q"&>R09/p]2G')M~KF5nj,6IyjKŢ値D6Ͼt*z*RL38$u8HbdF da0H^68 C2;{-Y u:*K.4ǹ^]P78YXQ5NiZMJ.2(tLʢ,$0jMY3Y. MAbmCGWX}`{Ts , 6Lrd5=rB1#1iN -w:k;r6܉b\5q"&(,.jkM'6Z]\f~Dg69R^ܔ I%jqO.Qv⨪f-?ls探83w1);xrqK 4 o E]a&g0p|Sjf8SrY}l4%XnĜdT $iqe0:Ԍ\xMХMB m$sj 1Y9ֆޗ$[OY{%_"TfAN$,}s+.o3-ៗ?&AcQӚ-#7D<~KO#7v~~-K1'Q$r#/>6!A=BCXC\=G5sh`6'x1HOE5d8cVsI 4G}*ZGyGS@B( $,1e>q;uRG3p4(^1u`P!%5EB,"<0#0&WE)I-D.(xCSs0X҃rCgw46f.q^ -AX̑t%ESXRb2Q8Ƹ$lI:i5ô}0Uad_=6&>gTjE9RLl5BTZeL!g+1EF!fѤw L'1y)#S(TڨUc"0ϨK%F@As@#3`8$^mazUF 2M3TmsGD5zcP^;T~Z4'#+6t{Aj#S~`l9ì~WH):YTbP9HYsjs`"ʲ7pPkAY=b$JbJ5$@ٵ 1TpsDCÑw)]ex[yp<4•WC d61T /·1;E$E(5r=mzT@[݉792(h5UvnŊ6yU*Qts2i\ɇ)dINY7L΢=!gc(݇?;M)dq;*[w-uNdenqq))!p6L3fѣⴇa+q MaJ|)JL781dV]w<.ù[UhƽVA7(EH8rտ4 2\Nh$.Ŭufd-LRj,N "s)dP` Z<BAvWj_rfGls,H6}k+.@3f#"q++'g%@] "4pm>9]W=Ќ1C%"iv `^u#U<:N:ңX^SK[~wKU>I,Ęl(:)WULYRq NmysG,&!B;X7 +noɾrxשSY;*[;GCRv R;go;YXh$ռRgξ*OO 2w83)\byR~.;>\my"ɐ%~F9+j uTrxt#~DXBۂ19Zwc[E`Uu"/<+?/wП{h ۫$ۏIR :/Oj? lui)3 mθ!@ 0 DxD !Tx1#D„"f$iRɈ*%J%ɔ#[,@0 Ti;e>5I`耣  @V KmW/Efl*@Vb53[6yѮGgVYˍlar\O\ꀁB `ZuG =;0Rr-*UI´;g>DXe…tnޞjeej|-S!K:.YAuAn_†Z7<ƻ|-3G2 `ۨr=d̤ Ϸ{,v2 )Z[*{n1C [**8=۫ 2#J(> Rҭ"L %.zP컫&)b|*!n<-(h+ԎpL41JL|N[ACGٰ3?>ϵҫ11Cȡq.`$3&Փ;BѥT]ʨ**4+C(OK1<رzkȧ#(mkթ*ӮWH_ lO(W.M܌%^.Huɨ^E(x=4R1t<5H)4+X;x,v7IsR,7+@==5jfIbE̋1S6Jo-1R9 )J t9("JMK-4Ǘ9&)'a='(5(z sbJ|7"Lo#OCs(M!Di{Ry,`SJamc6>h6,In$-)PWow窧8l:$v]G9:&(aD9hn?%,m'Xvy!($?qd!V4+i,Ccu*ႄe+;gU:uP6苣5Bh4a~RAPRFhH5t/^?1pJ8Cp^f&h֜I2Ͻ.FudQR;zjA͎ۨ١ޔ[pYٜZⰭ3?fR+֐p&$XJS|0O ͩO@Ҙi#\i`:F%z#Φc 4k2W hI!s.ˮ$hUCG:QW??0ҜoiP*X:@1:l}39oʲpZ *!$*<@I+C A*b2~q)ϋ=Y:?x[B@r7m"0'E @})䍪yШ3!{ `xG[R)oZs=E<p1YWY͹ ? {%r"ye<E;0|OA ?9NA ؜<ۢW{9Gt l11!TzK9Q"}P Ҧy+T+c63)ojI|;#* ؒrNˆE S )!E!yK¬n+ & %.Shw\hwۉH!@K#a3 LCl* ȎsY8TKr!4(Z/TCA`$/\ B,,sRzGyhL=;z0Ȫ3(9I S( .Fi(?Aswk4 %`#RکG:PPz DzK)0@+HM D:9s3˝hO\Ы7KCPHE338xØ2 LSyP3:y8У@{)&v,6!BY$◼ A`rP2yЊ yqMڢ@;߻*,$x5.^;פ8G bܳAq%;Zi0=98C,7?̢GYTŕ+ڕaTOzl &+hBx}tr f9H;s tz!ಒ@( YJ9K@.h"d+ ]K`Oӵa#|E(9,<("S d}9Eɉ2uIE} Q VQPCr2*茤6R [AI -Y #+ )(4QҽY JR"uJҵ[&R)o9r ElZ\D{3T^AJD)< etױeV! +et#=Ԭ Ŏ P [1؂ f Myٺ’ 8Y (So5J + ?PJYCK!DXڽ\̬ yZqҠк?R]L I=th!+9uA_TsrRIYa=DR6yk݁L?\,>.)) 0/'h`+ܧ-I|nDL#a:fY^Ԓ'B"-D|&Q"ǩ ڱf#F,KM,=;iin)S"2e`/;]-y6 ʍ8}5% 3P<"]SdK@dNK/ ɛ 4Da<,18R/n 1;yQW dƕ]4Cbt,j891RE_۟&2yyS 1Ս a,#!hi48-]E=1|;{[!]j(":E TNC'"*a9xCa=QeG ,A o5ݰCcՉ,RB*Ik^G IE7Q 9uB&,!hPZ#2VbwĎ{\f?+@叒 1#٨R)Ʈ iIր5a™U, XKA(>ۓӣ&γ ZbvHx^Y&V/whFMfccd?:4K |fʞ=n/ZN'9IP6ݾh@#Fn&QRUX+P gm'Y`Zi)Y' S9!o N"( =J69jh!oП"eKLՋ M%̖q$ p%ig8%0/ ,L'l)0,9Mr&m\h(7hNK=~[39 ۵YJJN;18~PX-&" 8H2?ֹko5N*:90;#iaPi\&k¢JYcqKs`f[&fs iȦDd} ܦ1$gwD&19ZK+I#꼓a'~['59 _twvTոxl\/gNҽ.Q]mM Ip&\`}saZ*UÒc):z Pg Z1\T y/q^R8LIe) X% 9n^/X'IX_߈7Gh[EgTj%M3svn'~APd?^,$N"ܑ߫KAЈh 5۷We9/Ϯ\5"N?ͱѭWX&#z(h Gb aﮈ>%`dh 3]yR]w̺b):!!fR1~`ĜcSpvV)ߑua$!噊eUfUjx"cCC3i`Xk]yN~FWMiI]HS%pWQy]&p&sE|qNeE7b^5)-Dpi"VݤqGdƽGb(T[)K}im $EB6GI0 gfZի!g͚qY4؜FU2;0~Vm') +" -\ble<4Ѫez(QtqFDFơUYccb 3Bl@)W_FXǦZ|ѓ]9&ׁWؙ%5>fb16̉Yo;zJpZϕ|Ps|HdDtˑ'5 qė^\uRzDbv+Jl;~dgMZ ^e-p݂Dx^5888N]oy ՈsZ1EiW9&% 0: 872aib9@G+CF#ͤ(Q)({@FC1kTHgRk*yD"^$F(ᑫ7cR L(-נl6?@L$c 88\b>q1haϬ5*8ԵJ`(*/d0[DyRD~rL*rTg!$u- ) &+v0EKגWR{93j7WW^)hӹI~/fD/z5![2#P!4ŕ*@{6=fo W~b5@o6Sljɉ(m V^V7iE뭅I/b-n"fj5 42bfl-pNb֥rQEUc$32 VO#c#;93r/S:;f' xqb0[f\̩.ܶZx ڧqJq=; vO2bC35SZ(9Sw.OhOQPZ.7&UV(}WpkxI'm_EpT6*~dfbJ狮AaW#So={)l k"Rlz)Nٵ_jՁ=U㵕ćPOԎZ-PF0mD5QN|ag`OUdG PrQTL]Tɰj`ғCm)Ynp@P̔ا%PdD}шmɰ}TGv@N0Y&MF"ZTcfT$W,1 . \VUR4b#.}uLRM&|43޼__(QRȎiALbޢ!9[0 d RgV! %ciZ:# E鄄_q΄\^%ʮEV"K\y(h'8ȁL#dRWBu栾]V%LƧ1c@^LJl&G<<ǃ Ԁ bgpV5*c+S~eD&Ol0HXh XȉKUJlT\HDh]+$o KO V ^yt ˞N۩Ƙq伴fTq۔^ҭ ,bRm:QT.6Jv\ G]Pܪe6h|]I;]."ǜ&K @Ȟ%rN ⥯;mz$FC͚׾ [!)JĮY'Ž2. _^r٨ ii u4ԜO\Y8]ƓGgWҊoh lR޾ ~M8r ШOkxp鿼Km֦u|f8RmDZ~xM=Oź@ vpz/ԏ}ՌH@ K(|jCBO, JUapECҸPK`naZ@  @C8q"C84P@G 4P`$I a#QK A H,@ (EG&UiSO>-ǚ Du 0p@!40@`١fLf 0nJ? Drkav]TyĜJ {q0GVȂ(9fhQ`/eZ.wo߿63$օ.nl؝WܺSNCc u~MI{V 1/*3] r UƆj0c-^ jCh MB"i0 N 9P)Z+z > 5b"jn8:!>*:+Aj "6)FDjͶ*6r0$ c,(lͧ r1XdlcKGhΣ#RQ:RoPn; 58T%&nMNغ >$S6b0UW7 qЮPҪ&d HI5FuB?lRzͤRlnWBb5/Ih$UOb6dbb|fݏ-+wׁ 13s̱ zo-]I 8PB#E#Y,:*M+GB"v}VI2c%AU0q ni"빎r2oPdҫEB+9H+1<*,e(cQҝΏԩ<ˢ$ Ig҄& @}3K/ +PLN,K1?*dt굆X²( =)k(0`!^::B4';*D%|H_r1^*FU LS\|̣Nn$`i,3W>`Ӕ$u$4'ՓQw!n ^iҠ$/Cq<4(2V)H MaYƗ¦u*Ix3/($1OlhL(!?ݱX^-P%C\ ;$lSI 6SKEDp⒟OPƼ`8KPsfy%2vT-dC% u9Fs 3㓙}:/AAĖ0K]JЎӖX9ab@옉hip$4'1N%'NAND=(1/K[6?(i&hCL'A9}42Uц!¥+2YXNACDnz-S|5-Yuuw/f`.pHi[4$PuXpNŽ4\Q6Q[#EPܝں&x6/('#pf5#, [jTk >4v^k|F Qfsj@ZFHka.6"QiRل.#WǢIt1CV0I/~K|lq^4),iIMa{%jhD]r0<W;(Ri"4FE՝xf_-]g_GLCG#'':.tMX*(_ZZIT礔l;W+M]ms4* LvSnhP;_Źtڦ4+eᥲbZ涠F,7onYnWaׯuEdcr/^k(,TlbsoR"FSi`~SM=7;iX#XfUAq"G%PC;~oi{ i[gJ0;i~c6Vc+UZGx pl,'tx"j(%FdD"w**gQ6kQpNhdҦ0X]AZKK/o> `˜'f$5(b"8#&\< H`:dcN!&c F cЮ/p e0)#Dt0;jroFF/ %2h-^`HPcx.("l< i  i0o0k?# &R|c.(dRznX' #Fmh(cc nyQ#c:gfcІvcPPh MŚg0֩gzd$ &vQQ6D"fxs'N:)Ip-d1[s40QJI]zD 8;1G? ?LX=9gP';:Ƌ&7j]4⠦D$ILZ2Jax䣚J'()2f%׭_b^#8:>3ѝB> -MeR s@Bz$&5#HD*/ʲ۰F(rI&$Oq"RƎ)-Dl H&!dTc/ i"<1Цo&?~$!,(&'zhppc psZ(ҤV-RG+ mccB7$!9Q%JR̆JN0snvDS3O:<#+=yJôO6K'7R"VF0(ѧ46+5,q%^z#S: FBX@Y扚4l"V;"F4c2Vh,og45yc,bޓF"}0Dwqj+/FEPXd"^;034gRۨDfT+gGv-H64H 80)Dg0.ižj(DG,,胎720Q~L(N,}xKh¤jS͢g<ǓBj'I[RGD#lBc8di+2vAeXP.Ψ3ۦ5S.Ls)b=9,Ce<-y&'Įi"LL̄"F2=fu qf/ۓӣ&γ Zbwily-0.13.42/Doc/changes.txt000064402366570000012000000067211033320152300153600ustar00ozstaff000043300000020.13.12 started this file * Each line in $WILYTOOLS or $HOME/.wilytools can contain either a comment (starts with whitespace or '#') or a regexp, then a tab, then some tools (i.e. some text) which will be put into the tag of any window whose label matches the regexp. The _first_ regexp match wins. 0.13.14 * Scrolling forward works better * plugged some memory leaks 0.13.15 fixed silly bug in text_read: Axel Belinfant patch from Steve Kotsopoulos - $WMAINTAG and $WCOLTAG removed last_escape_select newline only special in tag now h version Version builtin removed no longer warps cursor when expanding tile after typing in it utfwrite handles short writes -- Bill Trost wilytools have newline stripped, b2b1 on Anchor selects line changed mouse_expand: clicking _near_ a selection hits the selection use view_cut a lot removed some functions in keyboard.c use view->autoindent to decide to autoindent a view Indent builtin option -a to set tabsize 0.13.16 bugfix with B2B1 removed Version from default wilytools word-delete seems saner to me B3 checks for local files before include files 0.13.17 splitting data.c up tidied a few functions in data.c cloned windows share the same tag, modifying label works better tag modification seems to be working 0.13.18 ctrlu patch -- Bill removed some dead code from mouse.c renamed globals.h global.h updated MANIFEST moved columnate to from dir.c to util.c moved more out of dir.c removed a few syntax errors broken view.c into different files renamed view_left view_hscroll moved most of selection_fd to text_fd more from view.c to util.c removed selection_fd altogether Kill patch from Steve_Kilbane replaced view_isvisible with ISVISIBLE compiles with view.c all split up renamed the view-related files renamed the view-related files 0.13.19 scrollbugfix from Steve_Kilbane removed text.h from view.c tinkering with vgeom moved stuff from vsearch to text2 moved b3 from mouse.c to vsearch.c view_goto simplified lotsa internal changes rename data_labelmodified to data_setlabel rename data_backall to data_backupall broke search.c into click.c and sambuf.c removed text_clear removed text_delete split and tidied text2.c uses sam regexp 0.13.20 remove garyfind hack bugfix undo.c (was causing core dumps) msg_new now matches doco 0.13.21 exec dies if cannot chdir tile patch from Bill Trost 0.13.22 utfwrite handles write returning _all_ the resize boxes of a window are updated when the window is written right undo stuff happens for directory read misc. patches from Bill Trost realpath uses cached value of cwd tag_init no longer uses fgets 0.13.23 selected window display patch -- Bill Trost directory speedup patch -- Bill Trost aesthetic improvements patch -- awatson@NMSU.Edu made Alan's and Bill's aesthetics patches cooperate a bit noutput bugfix -- Bill Trost, Alan Watson 0.13.24 make sure anchor is at end of tag for new windows organising builtins bugfix: scrollbar geometry a bit wierd separated out all operations on lines into line.c scrolling backwards through a file now much faster text_linenumber simplified tute/start updated a bit 0.13.25 stop complaining if cannot open .wilytools -- awatson@NMSU.Edu prettier scrolling, wily -e -- awatson@NMSU.Edu text_replace in tag doesn't get forwarded fix the problems with switching between Fonts -- Bill Trost append WMAINTAG, rather than replace it -- Steve Kotsopoulos undo patch --Bill fixes to above -- Gary getname, gettools -- gary 0.13.26 wily-0.13.42/misc/000075502366570000012000000000001033320152300134275ustar00ozstaff00004330000002wily-0.13.42/misc/fixed.9.font000064402366570000012000000036211033320152300155670ustar00ozstaff0000433000000217 14 0x0000 0x00FF lucm.latin1.9 0x0100 0x017E lucm.latineur.9 0x0180 0x01F0 matty.latinext.9 0x0250 0x02E9 lucm.ipa.9 0x0300 0x0308 matty.gendiacritics.9 0x0370 0x0372 matty.greekpunc.9 0x0386 0x03F5 lucm.greek.9 0x0400 0x0475 misc.cyrillic.9 0x2000 0x2044 lucm.genpunc.9 0x2070 0x208E lucm.supsub.9 0x20A0 0x20AA lucm.currency.9 0x2100 0x2138 matty.letterlike.9 0x2190 0x21EA misc.arrows 0x2200 0x227F matty.math1 0x2280 0x22F1 matty.math2 0x2300 0x232C matty.tech 0x2500 0x257F matty.chart 0x2580 0x2595 matty.blocks 0x25a0 0x25ee matty.geometric 0x2600 0x266F misc.ding 0x3000 0x303f jis.jis3000.16 0x3041 0x309e jis.hiragana.16 0x30a1 0x30fe jis.katakana.16 0x4e00 0x4fff jis.jis4e00.16 0x5000 0x51ff jis.jis5000.16 0x5200 0x53ff jis.jis5200.16 0x5400 0x55ff jis.jis5400.16 0x5600 0x57ff jis.jis5600.16 0x5800 0x59ff jis.jis5800.16 0x5a00 0x5bff jis.jis5a00.16 0x5c00 0x5dff jis.jis5c00.16 0x5e00 0x5fff jis.jis5e00.16 0x6000 0x61ff jis.jis6000.16 0x6200 0x63ff jis.jis6200.16 0x6400 0x65ff jis.jis6400.16 0x6600 0x67ff jis.jis6600.16 0x6800 0x69ff jis.jis6800.16 0x6a00 0x6bff jis.jis6a00.16 0x6c00 0x6dff jis.jis6c00.16 0x6e00 0x6fff jis.jis6e00.16 0x7000 0x71ff jis.jis7000.16 0x7200 0x73ff jis.jis7200.16 0x7400 0x75ff jis.jis7400.16 0x7600 0x77ff jis.jis7600.16 0x7800 0x79ff jis.jis7800.16 0x7a00 0x7bff jis.jis7a00.16 0x7c00 0x7dff jis.jis7c00.16 0x7e00 0x7fff jis.jis7e00.16 0x8000 0x81ff jis.jis8000.16 0x8200 0x83ff jis.jis8200.16 0x8400 0x85ff jis.jis8400.16 0x8600 0x87ff jis.jis8600.16 0x8800 0x89ff jis.jis8800.16 0x8a00 0x8bff jis.jis8a00.16 0x8c00 0x8dff jis.jis8c00.16 0x8e00 0x8fff jis.jis8e00.16 0x9000 0x91ff jis.jis9000.16 0x9200 0x93ff jis.jis9200.16 0x9400 0x95ff jis.jis9400.16 0x9600 0x97ff jis.jis9600.16 0x9800 0x99ff jis.jis9800.16 0x9a00 0x9bff jis.jis9a00.16 0x9c00 0x9dff jis.jis9c00.16 0x9e00 0x9fff jis.jis9e00.16 0xe000 0xe05f matty.tengwar.9 0xfee0 0xff5e lucm.latin1.9 0xfffd 0xfffd pelm.fffd.9 wily-0.13.42/misc/README000064402366570000012000000004131033320152300143050ustar00ozstaff00004330000002Wily.ad Sample X Application Defaults file. Needs to be edited. fixed.9.font My fixed-width font file (at one stage) prop.9.font My proportional font file (at one stage) wily.xpm An xpm suitable for a desktop icon wily2.xpm Another xpm suitable for a desktop icon wily-0.13.42/misc/Wily.ad000064402366570000012000000003411033320152300146570ustar00ozstaff00004330000002*geometry: 1200x1000 *p9font: /usr/pgrad/gary/lib/prop.9.font *p9fixed: /usr/pgrad/gary/lib/fixed.9.font #*font: -*-lucida-bold-r-*-*-16-*-*-*-*-*-*-* #*font: -*-new century schoolbook-medium-r-normal-*-14-*-*-*-p-*-*-* wily-0.13.42/misc/prop.9.font000064402366570000012000000037211033320152300154510ustar00ozstaff0000433000000216 13 0x0000 0x0019 lucm.latin1.9 0x0000 0x00FF -*-lucida-bold-r-normal-sans-14-140-75-75-p-*-*-* 0x0100 0x017E lucm.latineur.9 0x0180 0x01F0 matty.latinext.9 0x0250 0x02E9 lucm.ipa.9 0x0300 0x0308 matty.gendiacritics.9 0x0370 0x0372 matty.greekpunc.9 0x0386 0x03F5 lucm.greek.9 0x0400 0x0475 misc.cyrillic.9 0x2000 0x2044 lucm.genpunc.9 0x2070 0x208E lucm.supsub.9 0x20A0 0x20AA lucm.currency.9 0x2100 0x2138 matty.letterlike.9 0x2190 0x21EA misc.arrows 0x2200 0x227F matty.math1 0x2280 0x22F1 matty.math2 0x2300 0x232C matty.tech 0x2500 0x257F matty.chart 0x2580 0x2595 matty.blocks 0x25a0 0x25ee matty.geometric 0x2600 0x266F misc.ding 0x3000 0x303f jis.jis3000.16 0x3041 0x309e jis.hiragana.16 0x30a1 0x30fe jis.katakana.16 0x4e00 0x4fff jis.jis4e00.16 0x5000 0x51ff jis.jis5000.16 0x5200 0x53ff jis.jis5200.16 0x5400 0x55ff jis.jis5400.16 0x5600 0x57ff jis.jis5600.16 0x5800 0x59ff jis.jis5800.16 0x5a00 0x5bff jis.jis5a00.16 0x5c00 0x5dff jis.jis5c00.16 0x5e00 0x5fff jis.jis5e00.16 0x6000 0x61ff jis.jis6000.16 0x6200 0x63ff jis.jis6200.16 0x6400 0x65ff jis.jis6400.16 0x6600 0x67ff jis.jis6600.16 0x6800 0x69ff jis.jis6800.16 0x6a00 0x6bff jis.jis6a00.16 0x6c00 0x6dff jis.jis6c00.16 0x6e00 0x6fff jis.jis6e00.16 0x7000 0x71ff jis.jis7000.16 0x7200 0x73ff jis.jis7200.16 0x7400 0x75ff jis.jis7400.16 0x7600 0x77ff jis.jis7600.16 0x7800 0x79ff jis.jis7800.16 0x7a00 0x7bff jis.jis7a00.16 0x7c00 0x7dff jis.jis7c00.16 0x7e00 0x7fff jis.jis7e00.16 0x8000 0x81ff jis.jis8000.16 0x8200 0x83ff jis.jis8200.16 0x8400 0x85ff jis.jis8400.16 0x8600 0x87ff jis.jis8600.16 0x8800 0x89ff jis.jis8800.16 0x8a00 0x8bff jis.jis8a00.16 0x8c00 0x8dff jis.jis8c00.16 0x8e00 0x8fff jis.jis8e00.16 0x9000 0x91ff jis.jis9000.16 0x9200 0x93ff jis.jis9200.16 0x9400 0x95ff jis.jis9400.16 0x9600 0x97ff jis.jis9600.16 0x9800 0x99ff jis.jis9800.16 0x9a00 0x9bff jis.jis9a00.16 0x9c00 0x9dff jis.jis9c00.16 0x9e00 0x9fff jis.jis9e00.16 0xe000 0xe05f matty.tengwar.9 0xfee0 0xff5e lucm.latin1.9 0xfffd 0xfffd pelm.fffd.9 wily-0.13.42/misc/wily.xpm000064402366570000012000000052021033320152300151400ustar00ozstaff00004330000002/* XPM */ static char *wily[] = { /* width height num_colors chars_per_pixel */ " 48 48 3 1", /* colors */ " s mask c none" ". c #ffffff", "# c #000000", /* pixels */ " # " " ## " " #.# " " #.## " " #.## " " #.##### " " # #.##.##.### " " ## #..####..## " " #.## #...#.##.## " " #.### #....##.#.# " " #.#.# ##...###.#.# " " #..#.# #.....###### " " #..#..## ##....##.## " " #...##.## #....##.## " " #...##.# #....##.# " " #...##.# ###..#.# " " #.....### #####.## " " #.......## #.###.# " " #......### #####.# " " #......### ###.# " " #.....### #.### " " ###...#.# ##.#### " " ###..## #.###..## " " ##### ###.#.#..# " " #.#.#.#.#.#.# " " ###.##.##.#.# #### " " ####.#.#...#.## ###....# " " #.####..#..#..# ##.....## " " #.#.#.......#.##........# " " ###.###....###......#....# " " ####..#.##.##..#........#....# " " #.......#.####.........##....# " " #.....#.##.###.....###.......# " " #...##..............#.........# " " ##...#......#.....#.........# " " #.##..#......................# " " ###.##.......###.........# " " #####.........##......######## " " #######.......##......### " " ##.####.......#......## " " #.#######...#.......# " " ###### ###...#....# " " ### #................###### " " ###...........###....#### " " ####.....#..#########.#..### " " ##.......########.###.#..## " " #######.....#....#..#.####.#..#..# " " #..#..##....##.....#.####.######..# " }; wily-0.13.42/misc/wily2.xpm000064402366570000012000000042001033320152300152170ustar00ozstaff00004330000002/* XPM */ static char * image_name[] = { "42 39 16 1", " c None", ". c #000000000000", "X c #71C6555528A2", "o c #79E7555530C2", "O c #EFBEF7DEFFFF", "+ c #F7DEFBEE38E3", "@ c #D75CAEBA71C6", "# c #104004100000", "$ c #208104100000", "% c #D75CB2CA69A6", "& c #CF3CAEBA79E7", "* c #D75CAEBA8E38", "= c #104010402081", "- c #000000000820", "; c #28A20C300820", ": c #71C64D3430C2", " .X. .XXXXX. ", " .XX... .XXXXX. ", " .XXXXX.. .XXXXXX. ", " .XXXXXXX....XXXXXX. ", " ..XXXXXXXX..XXXXXX. ", " ...XXXXXXX.XXXXXX. ", " ..XXXXX..XXXXXX. ", " .XXXXX..XXXXX. ", " ..XXXX.XXXXX. ", " .XXX..XXoX. ", " .XXXX.XXXX. ", " .XXXX.XXX. ", " .XXXX.XXX. ", " .XXXXXXXX. ", " .XXXXXXXXX. ", " .XXXXXXXXX. ", " .XXXXXXXXXX. ", " ++XXXXXXXXXX. ", " +++XXXXXXXXXXX. ", " .. ..++XXXXXXXXXXX.. ", " .... ..++XXXX@@@@@@@@@. ", " ....... +++XXX@@@@@@@@@@@. ", " ...#@@..... ++@@@@@@@@@@@@@@@@. ", " ..$@@@@@@@.........@@@@@@@@%@@@@@@@@@. ", " .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@. ", " .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@. ", " ..@@@@@@@@@@@@@@@@..@@@@@@@@@@@@@@. ", " ......@@@@......@@@@@@@@@@@@@&@@. ", " ......@@@@@@@@@@@@@@@@@@@@. ", " .@@@@@@@@@@@@@@@@@@@.. ", " .*@@@@@@@@@@@@@@... ", " .#@@@@@@@@@@@... ", " =@@@@@@#... ", " -@@@@@. ", " -@@@XX ", " .@@@X. ", " .@@XX. ", " .@@XXXX.. ", " ;@@@:XXXXX. "} wily-0.13.42/wily/000075502366570000012000000000001041526267400134775ustar00ozstaff00004330000002wily-0.13.42/wily/const.h000064402366570000012000000017711033320152300147650ustar00ozstaff00004330000002/******************************************* * Constant declarations *******************************************/ #include /* for MAXPATHLEN */ #ifndef DEFAULTSHELL #define DEFAULTSHELL "/bin/sh" #endif #ifndef FOPEN_MAX #define FOPEN_MAX NOFILE #endif #ifndef MAXPATH #define MAXPATH MAXPATHLEN #endif enum { /* memory */ GAPSIZE = 512, /* buffer gap */ BUFFERSIZE = 10240, /* when copying a whole file */ FILLCHUNK = 512, /* when filling a View */ /* geometry */ SCROLLWIDTH = 13, MINWIDTH = 50, /* ... of a window or column */ SELECTEDBORDER = 3, SMALLDISTANCE = 5*5, /* 5 pixels squared */ INSET = 4, /* mouse buttons */ LEFT =1, MIDDLE=2, RIGHT=4, /* keys */ Backspace = 0x7f, PageDown = 0x80, PageUp = 0x81, LeftArrow = 0x82, RightArrow = 0x83, DownArrow = 0x84, UpArrow = 0x85, Home = 0x86 , End = 0x87, NEWLINE = '\n', Ctrlh = 010, Ctrlu = 025, Ctrlw = 027, Esc = 27, /* time delays (ms) */ DOUBLECLICK = 500, SCROLLTIME = 100 }; wily-0.13.42/wily/NOTES000064402366570000012000000030211033320152300142670ustar00ozstaff00004330000002Coding conventions Everything before the first blank line in each file is a comment about that whole file. Functions manipulating a Fish structure are called fish_functionName() TEXT.C buffer gap implementation: The buffer is represented as a contiguous array of Runes, with a "gap". To insert or delete text, we move the gap to the required position, then add text into the gap or expand the gap. Anywhere else which needs to access the buffer has to get to it through text_copy or text_replace. SEARCH.C handles literal search, double-click and other expansion, line counting, ... For efficiency, grabs text from the buffer into a buffer and works from the buffer. SAM.C wrapper to support regexp.c from the program sam. Uses the buffering code in search.c. The buffering is optimised to go in one direction or the other, and regexp.c uses the internal structure of that buffer :-( VIEW.C Glue to connect frames, which actually display stuff, and text buffers. Must cope with the fact that sometimes views have zero height (if they're squeezed out by the other views), and sometimes views change size (by adding text to a tag). If a view has been squeezed, then it has zero height, its frame has been frclear'ed, and you should not attempt to update the frame. NAMES A file name may be: 1. a short file name, for typing or for window labels 2. a unique identifier for a file 3. a name which the file system understands We should distinguish between these usages and meanings. A file name is possibly not the best thing for 2. wily-0.13.42/wily/col.c000064402366570000012000000016571033320152300144120ustar00ozstaff00004330000002/******************************************* * Functions on columns *******************************************/ #include "tile.h" extern char* columntools; /* Return the column enclosing 'tile', or 0 */ Tile* tile_col(Tile*tile){ if(tile && tile->ori != H) tile = tile->up; return tile; } /* Create and display a new column. */ void col_new(View*v, char *arg) { int min, max; Tile *col; Text *tagt; findplace(wily, &min, &max); tagt = text_alloc(0, false); text_replaceutf(tagt, nr, columntools); col = tile_new(H, min, max, MINWIDTH, wily, tagt, 0); list_add(wily, col); } /* Delete as many of the windows of 'tile' as possible. Return 0 * if we got them all. */ static int col_delwins(Tile*tile) { Tile *t, *next; int problem = 0; for(t = tile->down; t; t= next) { next = t->right; if (win_del(t)) problem = 1; } return problem; } void col_del(Tile*t) { if(t && !col_delwins(t)) { tile_del(t); } } wily-0.13.42/wily/dir.c000064402366570000012000000037231033320152300144070ustar00ozstaff00004330000002/******************************************* * Read and format directories *******************************************/ #include "wily.h" #include "data.h" enum { MAXNAMES = 10240 /* initial number of names in a directory */ }; static int mycmp (const void *a, const void *d) { return strcmp(*(char**)a, *(char**)d); } /* A few OS's have file systems that know which files in a directory are dirs. */ #ifdef DT_DIR #define CHECKDIR(dp) ((dp)->d_type == DT_DIR) #else #define CHECKDIR(dp) (0) #endif /* * Read 'dirp', return null-terminated array of strings representing the * files in the directory. Both the strings and the array need to be * freed later (use dirnames_free()). * * Returns 0 on error. */ char ** dirnames (DIR *dirp, char *path) { struct stat statbuf; struct dirent *direntp; char *name; char **list; int nfiles; int maxnames = MAXNAMES; /* Read the directory into a big buffer */ rewinddir(dirp); /* Workaround for FreeBSD. */ list = (char**) salloc(maxnames * sizeof(char*)); /* temporarily chdir so we can stat */ if(chdir(path)) { diag(path, "couldn't chdir"); return 0; } nfiles = 0; while ((direntp = readdir(dirp))) { name = direntp->d_name; if( name[0] == '.' && (!show_dot_files || name[1]=='\0')) { continue; } if (!(nfiles+2 < maxnames) ) { maxnames *= 2; list = (char**) srealloc(list, maxnames * sizeof(char*)); } if (CHECKDIR(direntp) || (stat(name, &statbuf) >= 0 && S_ISDIR(statbuf.st_mode))) { Path buf; sprintf(buf, "%s/", name); list[nfiles++] = strdup(buf); } else { list[nfiles++] = strdup(name); } } /* return to wilydir */ if(chdir(wilydir)) { diag(wilydir, "couldn't chdir back to wilydir [%s]", wilydir); } closedir(dirp); qsort(list, nfiles, sizeof(char*), mycmp); list[nfiles] = 0; return list; } /* Keep consistent with dirnames() */ void dirnames_free(char**names) { char **s; if(!names) return; for(s=names; *s; s++) free(*s); free(names); } wily-0.13.42/wily/env.c000064402366570000012000000043501033320152300144160ustar00ozstaff00004330000002/******************************************* * ~ and $ expand and contract *******************************************/ #include "wily.h" #include #include #include typedef struct Abbrev Abbrev; struct Abbrev { Path env; Stat buf; }; static struct Abbrev *abbrev = 0; static int nabbrev = 0, maxabbrev = 0; static Bool foundmatch (char*dest, char*orig); static Bool contract (char*dest, char*orig); static void newenv (char *env, Stat*buf); static Abbrev* findstat (Stat*buf); void env_init(char **envp) { char *env, *ptr; Stat buf; /* Add environment variables */ while ( (env = *envp++)) { if (! (ptr = strchr(env, '=')) ) continue; *ptr ++ = 0; if (strlen(ptr)&& !stat(ptr, &buf)) newenv(env, &buf); *--ptr = '='; } } /* Copy shorter version of 'orig' into 'dest' */ void pathcontract(char*dest, char *orig) { if(orig[0]=='/' && contract(dest, orig)) { ; /* we're done */ } else { strcpy(dest,orig); } } /****************************************************** static functions ******************************************************/ static Bool foundmatch(char*dest, char*orig){ Stat buf; Abbrev *ab; if(!stat(orig,&buf) && (ab = findstat(&buf))){ sprintf(dest, "$%s", ab->env); return true; } else { return false; } } static Bool contract(char*dest, char*orig) { char*lastslash; Bool retval; if(foundmatch(dest, orig)) { return true; } else { lastslash = strrchr(orig,'/'); if(lastslash) { *lastslash = '\0'; retval = contract(dest,orig); *lastslash = '/'; if(retval) { strcat(dest, lastslash); } return retval; } else { return false; } } } static void newenv(char *env, Stat*buf) { Abbrev*new; Abbrev*old; /* "I told him we've already got one" Holy Grail */ if((old = findstat(buf))){ if(strlen(env)env)) strcpy(old->env, env); return; } if (nabbrev == maxabbrev) { maxabbrev = maxabbrev? maxabbrev*2 : maxabbrev + 2; abbrev = srealloc(abbrev, maxabbrev * sizeof(*abbrev)); } new = &abbrev[nabbrev++]; strcpy(new->env, env); new->buf = *buf; } static Abbrev* findstat(Stat*buf){ Abbrev*ab; for(ab = abbrev; ab < abbrev + nabbrev; ab++) if( !statcmp( buf, &ab->buf)) return ab; return 0; } wily-0.13.42/wily/msg.c000064402366570000012000000165401033320152300144200ustar00ozstaff00004330000002/******************************************* * Handle messages from remote processes *******************************************/ #include "wily.h" #include "data.h" static char* badrange ="bad range"; static char* unknown ="unknown message type"; static char* data_attach(Data*d, int fd, ushort emask); static void data_changelabel(Data *d,char*label); static char* data_getname(Data*d); static char * data_list(void); static int msg_send(Msg*m, int fd); static void msg_new(Msg*m); static void msg_fillfd(Msg*m, int fd); static Bool msg_form_and_send(Mtype, Id, Id, Range, ushort, char *, int); static void msg_process(Msg*m, int fd); static void msg_error(Msg*m, char*s); /**************************************************************** Unpack and handle incoming messages ****************************************************************/ void mbuf_init(Mbuf*m){ m->buf = 0; m->alloced = 0; m->n = 0; } void mbuf_clear(Mbuf*m){ m->n = 0; } /* * Handle the message contained in 'buf' (which might have * part of an old message) and 's', which contains 'n' new bytes. * Send any replies back along 'fd'. * * Return 0 unless we get a badly formatted message. */ int partialmsg(Mbuf *m, int fd, int n, char*s){ char *ptr; int left; /* copy to m->buf */ SETSIZE(m->buf, m->alloced, m->n + n); memcpy(m->buf + m->n, s, n); m->n += n; /* process any whole messages */ ptr = m->buf; left = m->n; while (FULLMSG(ptr,left)) { Msg msg; int eaten = msg_bufsize(ptr); if(msg_init(&msg, ptr)){ return -1; } ptr += eaten; left -= eaten; msg_process(&msg, fd); } /* move any incomplete messages to front of buf->buf */ if (left && left != m->n) memmove(m->buf, ptr, left); m->n = left; return 0; } /* * Stop any data from sending events to 'fd', * which is probably closed. */ void data_fdstop(int fd) { Data *d; for (d=dataroot; d; d = d->next) { if(d->fd == fd){ d->fd = 0; d->emask = 0; } } } /**************************************************************** Send out messages in response to user events ****************************************************************/ /* * If someone's monitoring this window for 'replace' events, * send them one. If we fail to send the message, or don't need * to send the message, return false. */ Bool data_sendreplace(Data *d,Range r, Rstring s) { char *buf; Bool retval; if(! ( d && d->emask & WEreplace) ) return false; buf = salloc(RSLEN(s) * UTFmax); buf[texttoutf(buf, s.r0, s.r1)] = '\0'; retval = msg_form_and_send(WEreplace, 0, d->id, r, 0, buf, d->fd); free(buf); return retval; } /* see data_sendreplace */ Bool data_senddestroy(Data *d) { if(! ( d && d->emask & WEdestroy) ) return false; return msg_form_and_send(WEdestroy, 0, d->id, nr, 0, 0, d->fd); } /* see data_sendreplace */ Bool data_sendgoto(Data *d,Range r, char *s) { if(! ( d && d->emask & WEgoto) ) return false; return msg_form_and_send(WEgoto, 0, d->id, r, 0, s, d->fd); } /* see data_sendreplace */ Bool data_sendexec(Data *d,char*cmd, char *arg) { Bool retval; char *s; if(! ( d && d->emask & WEexec) ) return false; if(arg) { s = salloc( strlen(cmd) + strlen(arg) + 2); sprintf(s, "%s %s", cmd, arg); } else { s = cmd; } retval = msg_form_and_send(WEexec, 0, d->id, nr, 0, s, d->fd); if(arg) free(s); return retval; } /********************************************** Static functions **********************************************/ static char* data_attach(Data*d, int fd, ushort emask) { if(d->fd) return "This window already attached"; else { d->fd = fd; d->emask = emask; return 0; } } /* Change the d->label to 'label', update d->path. * Only called in response to a remote message. */ static void data_changelabel(Data *d,char*label) { strcpy(d->label, label); tag_setlabel(d->tag, d->label); } static char* data_getname(Data*d){ static Path buf; label2path(buf, d->label); return buf; } /* Return newline-separated list of tab-separated (winname,id) tuples */ static char * data_list(void) { static char *buf=0; static int alloced=0; int size = 0; Data *d; char *ptr; Path path; /* calculate the size of buffer required */ size =0; for(d=dataroot; d; d=d->next) { label2path(path, d->label); size += strlen(path) + 15; } if(size > alloced) { alloced = size; buf = srealloc(buf, alloced); } ptr = buf; for(d=dataroot; d; d=d->next) { label2path(path, d->label); sprintf(ptr, "%s\t%d\n", path, d->id); ptr += strlen(ptr); } return buf; } /* Return 0 for success */ static int msg_send(Msg*m, int fd) { static uchar*buf=0; static int alloced=0; ulong size = msg_size(m); SETSIZE(buf, alloced, size); msg_flatten(m, buf); return write(fd,buf,size)!=size; /* todo - handle partial writes? */ } static void msg_new(Msg*m) { View *v; Data *d; if(!(v = data_find(m->s))) v = data_open(m->s, true); d = view_data(v); if(!m->flag) data_setbackup(d,0); m->w = d->id; } static void handleattach(Msg*m, Data*d, int fd){ m->s = data_attach(d, fd, m->flag); if(m->s) m->t = WRerror; } static void handleread(Msg*m, Text *t ) { if (text_badrange(t,m->r)) { msg_error(m, badrange); } else { m->s = text_duputf(t, m->r); } } static void handlereplace(Msg*m, Text *t ) { if (text_badrange(t,m->r)) { msg_error(m, badrange); } else { text_replaceutf(t, m->r, m->s); } } static void handlegoto(Msg*m, View*v) { Bool show; Range r; show = (m->t == WEgoto) || m->flag; /* We get the search start position * either from 'm' or 'dot' in the view. */ r = m->r; if(r.p0>r.p1) r = view_getsel(v); if(view_goto(&v, &r, m->s)){ if (show) { view_show(v, r); view_select(v, r); view_warp(v, r); } m->r = r; m->w = text_data(view_text(v))->id; } else { /* indicate search failure */ m->r.p0 = -1; m->r.p1 = 0; } } static void msg_error(Msg*m, char*s){ m->s = s; m->t = WRerror; } /* Process a message which arrived on 'fd'. Modifies 'm'. */ static void msg_fillfd(Msg*m, int fd) { Data *d=0; View *v; /* WMlist or WMnew don't need to be associated with a valid window. */ switch(m->t) { case WMlist: m->s = data_list(); return; case WMnew: msg_new(m); return; default: break; } if(!(d=data_findid(m->w))) { msg_error(m, "No window with this id"); return; } v = text_view(d->t); switch(m->t) { case WMattach: handleattach(m,d,fd); break; case WMsetname: data_changelabel(d, m->s); break; case WMgetname: m->s = data_getname(d); break; case WMsettools: tag_settools(d->tag, m->s); break; case WMgettools: m->s=tag_gettools(d->tag); break; case WMread: handleread(m, d->t); break; case WEreplace: break; case WMreplace: handlereplace(m,d->t); break; case WMexec: /* fall through */ case WEexec: run(v, m->s, 0); break; case WMgoto: /* fall through */ case WEgoto: handlegoto(m,v); break; default: msg_error(m, unknown); break; } } static Bool msg_form_and_send(Mtype t, Id m, Id w, Range r, ushort flag, char *s, int fd) { Msg msg; msg.t = t; msg.m = m; msg.w = w; msg.r = r; msg.flag = flag; msg.s = s; return ! msg_send(&msg, fd); } /* Process a message which arrived on 'fd' */ static void msg_process(Msg*m, int fd) { Bool isbounce; isbounce = m->t < WEfencepost; msg_fillfd(m, fd); if(!isbounce){ if(m->t != WRerror) m->t ++; (void)msg_send(m,fd); } else if (m->t == WRerror) { diag(0, "error from bounced event %s", m->s); msg_print(m); } } d && d->emask & WEreplace) ) return false; buf = salloc(RSLEN(s) * UTFmax); buf[texttoutf(buf, s.r0, s.r1)] = '\0'; retval = msg_form_and_send(WEreplace,wily-0.13.42/wily/sam.c000064402366570000012000000067141033320152300144140ustar00ozstaff00004330000002/* sam.c - some stubs and interface code to tie sam's regexp.c * to the rest of wily. * S. Kilbane, 13/9/95. */ #include #define SAM_CODE #include "sam.h" static jmp_buf regexp_state; static char *errs[] = { "Etoolong", "Eleftpar", "Erightpar", "Emissop", "Ebadregexp", "Ebadclass", "Eoverflow" }; /* * Initialise a File to the Text given. */ void Finit(File *f, Text*t, Range *r) { f->t = t; f->nrunes = t->length; f->dot.r.p1 = r->p0; f->dot.r.w2 = r->p1; f->dot.f = f; return; } /* * stub routines */ static int do_compile(String *s) { compile(s); return (startinst == 0); } void panic(char *str) { (void)fprintf(stderr,"panic:%s\n",str); exit(1); } void samerror(Err e) { fprintf(stderr, "regexp error: %s\n",errs[e]); longjmp(regexp_state, 1); } void Strduplstr(String *s0, String *s1) { ulong n; n = s1->n; if (s0->n < s1->n) s0->s = srealloc(s0->s, n*RUNESIZE); s0->n = s1->n; memcpy(s0->s, s1->s, n); } int Strcmp(String *s0, String *s1) { Rune *i, *j; if (!s0->s || !s1->s) return 1; for (i = s0->s, j = s1->s; *i && (*i == *j); i++, j++) ; return *i != *j; } void error_c(Err e, int c) { fprintf(stderr, "regexp: %s, %c\n", errs[e], c); longjmp(regexp_state, 1); } void Strzero(String *s) { memset(s->s, 0, s->n*RUNESIZE); } /* * Seems to work, so now I need to sort out the handling of * ranges. I think it should search from the current p1, * wrap around, and continue to before p0. Should probably * play with ACME a bit, and see how that goes... */ /* * text_regexp(t,re,r,fwd) - the interface between wily and sam. * compile the regexp, and do a search from the current point. * If we find a match, set r, and return true. Otherwise, * return false. */ static Bool text_strregexp(Text *t, String str, Range *r, Bool fwd) { File f; Bool found; ulong q0, q1; /* We run into all sorts of setjmp/longjmp madness * if text_strregexp somehow calls itself. * Let's make sure that doesn't happen. * For this same reason, can't use diag anywhere * in sam.c or regexp.c, fprintf(stderr,...) instead. */ static Bool active = false; assert(!active); active = true; if (setjmp(regexp_state)) { found = false; goto out; } found =false; if (do_compile(&str)) { fprintf(stderr, "regexp: compilation failed\n"); goto out; } q0 = r->p0; q1 = r->p1; Finit(&f, t, r); /* first, try after current posn to end of file. */ found = fwd? execute(&f, q1, t->length) : bexecute(&f,q0); if (found) { r->p0 = sel.w[0].p1; r->p1 = sel.w[0].w2; goto out; } /* No good. wrap, and try from start of file. */ found = fwd? execute(&f,0,t->length) : bexecute(&f,t->length); if (found) { r->p0 = sel.w[0].p1; r->p1 = sel.w[0].w2; } out: active = false; return found; } Bool text_utfregexp(Text *t, char *re, Range *r, Bool fwd) { static String str; int l = (1+strlen(re))*sizeof(Rune); if (str.n <= l) { str.n = l; str.s = srealloc(str.s, str.n); } str.s[utftotext(str.s, re, re+strlen(re))] = 0; return text_strregexp(t, str, r, fwd); } Bool text_regexp(Text *t, Rstring re, Range *r, Bool fwd) { static String str; int l = (1+RSLEN(re))*sizeof(Rune); if (str.n <= l) { str.n = l; str.s = srealloc(str.s, str.n); } memcpy(str.s, re.r0, RSLEN(re)*sizeof(Rune)); str.s[RSLEN(re)] = 0; return text_strregexp(t, str, r, fwd); } long Tchars(Text *t, Rune *buf, ulong p0, ulong p1) { Range r; assert(p0 <= p1); r = range( p0, MIN(p1, t->length)); text_copy(t, r, buf); return RLEN(r); } wily-0.13.42/wily/sam.h000064402366570000012000000046311033320152300144150ustar00ozstaff00004330000002/******************************************* * Utility declarations for regexp.c *******************************************/ /* This source file is derived from the sam.h file in the sam distribution, which is: */ /* Copyright (c) 1992 AT&T - All rights reserved. */ /* * sam and wily both define an error() function. To avoid changing * anything in regexp.c, we use a macro to rename it. This relies * on other wily functions including wily.h before sam.h. */ #ifndef WILY_H #define error(X) samerror(X) #define SAM_CODE #endif #define emalloc salloc #define erealloc srealloc #include #include #include #include "wily.h" #include "text.h" #define NSUBEXP 10 /* number of () matches in a regexp */ typedef long Posn; /* file position or address */ typedef struct Address Address; typedef struct File File; typedef struct samRange samRange; typedef struct samRangeset samRangeset; typedef struct String String; typedef struct Inst Inst; typedef enum { Etoolong, Eleftpar, Erightpar, Emissop, Ebadregexp, Ebadclass, Eoverflow } Err; struct String { int n; Rune *s; }; struct samRange { Posn p1, w2; }; struct samRangeset { samRange w[NSUBEXP]; }; struct Address { samRange r; File *f; }; #ifdef TRUE #undef TRUE #endif #ifdef FALSE #undef FALSE #endif enum { FALSE=0, TRUE = 1, RUNESIZE = (sizeof(Rune)), INFINITY = 0x7FFFFFFFL }; /* * In the original sam.h, the File structure is that which manages * all the caches and buffers of the file being edited. We're not * concerned with any of that - we just want to make the contents * of a View look like a File to sam. */ struct File { Text *t; /* the Text that we'll search */ Posn nrunes; /* total length of file */ Address dot; /* current position */ }; #define Fgetc(f) (Tgetc(f->t)) #define Fbgetc(f) (Tbgetc(f->t)) #define Fgetcload(f,p) Tgetcload((f)->t, (p)) #define Fbgetcload(f,p) Tbgetcload((f)->t, (p)) #define Fgetcset(f,p) Tgetcset((f)->t, (p)) #define Fbgetcset(f,p) Tbgetcset((f)->t, (p)) #define Fchars(f,r,p0,p1) Tchars((f)->t, (r),(p0),(p1)) int bexecute(File*, Posn); void compile(String*); int execute(File*, Posn, Posn); void nextmatch(File*, String*, Posn, int); void error_c(Err, int); void panic(char*); void Strduplstr(String *, String *); int Strcmp(String *, String *); void Strzero(String *); void error(Err); /* really samerror() */ extern samRangeset sel; extern Inst *startinst; wily-0.13.42/wily/label.c000064402366570000012000000032611033320152300147050ustar00ozstaff00004330000002/************************************************************* Various routines to do with a Data's label and/or path *************************************************************/ #include "wily.h" #include "data.h" static void data_restat(Data*d); #define DATALABEL(d) ((d)?(d)->label:wilydir) void data_addcontext(Data*d, char*dest, char*orig) { addcontext(dest, DATALABEL(d), orig); labelclean(dest); } /* Copy d's label (or wilydir) to 'dest' */ void data_getlabel(Data*d, char*dest){ strcpy(dest, DATALABEL(d)); } /* D's label has been changed to 's', * update our internal structures. */ void data_setlabel(Data*d, char *s) { assert(d); /* Just record the new label, only update * other stuff on demand. */ strcpy(d->label, s); if(STRSAME(d->label, d->cachedlabel)) { if(!data_isdirty(d)) { tag_rmtool(d->tag, "Put"); } } else { tag_addtool(d->tag, "Get"); tag_addtool(d->tag, "Put"); } } /* Return pointer to View with same 'label', or null. */ View * data_find(char*label) { Data *d; Stat buf; Path path; /* Search for data with same label */ for(d=dataroot; d; d=d->next) { if (STRSAME(d->label, label)) return text_view(d->t); } /* Search for data with same stat buffer */ label2path(path,label); if(stat(path,&buf)) return 0; for(d=dataroot; d; d=d->next) { data_restat(d); if (d->has_stat && !statcmp(&buf, &d->stat)) return text_view(d->t); } return 0; } /* If 'label' has changed under us, update * some other information. */ static void data_restat(Data*d) { if(strcmp(d->label, d->cachedlabel)) { Path path; strcpy(d->cachedlabel, d->label); label2path(path, d->label); d->has_stat = !stat(path, &d->stat); } } wily-0.13.42/wily/tag.c000064402366570000012000000074051033320152300144050ustar00ozstaff00004330000002/******************************************* * Maintain and monitor tags *******************************************/ #include "wily.h" #include "view.h" #include "text.h" #include #include /* The tag for a window contains: a label then whitespace, then some * system-maintained tools, then a pipe symbol, then user stuff. */ static char * whitespace_regexp = "[ \t\n]+"; static Range tag_findtool(Text *, char*); static Bool wily_modifying_tag = false; /************************************************ Gettools and Settools only used by the messaging interface. It's still up in the air what exactly they should do. TODO - ensure space before/after "|" separator. ************************************************/ char* tag_gettools(Text*t){ Range r; r = nr; if(text_utfregexp(t, "\\|.*", &r, true)) { r.p0++; return text_duputf(t, r); } else { return ""; } } void tag_settools(Text*t, char*s) { Range r = nr; ulong len; if(text_utfregexp(t, "\\|.*", &r, true)) { r.p0++; } else { len = text_length(t); r = range(len,len); } text_replaceutf(t,r,s); } void tag_set(Text*t, char*s) { View *v; assert(TEXT_ISTAG(t)); wily_modifying_tag = true; text_replaceutf(t, text_all(t), s); if ((v = text_view(t))) v->anchor = text_length(t); wily_modifying_tag = false; } void tag_setlabel(Text *t, char *s) { Range r; Path buf; ulong l; wily_modifying_tag = true; /* find first whitespace_regexp */ r = range(0,0); if(! text_utfregexp(t, whitespace_regexp, &r, true)) { l = text_length(t); r = range(l,l); } r.p0 = 0; sprintf(buf, "%s ", s); text_replaceutf(t, r, buf); wily_modifying_tag = false; } /* Remove 's' from the tool section of tag 't', if it exists there. */ void tag_rmtool(Text *t, char *s) { Range r; wily_modifying_tag = true; r = tag_findtool(t, s); if(RLEN(r)) text_replace(t, r, rstring(0,0)); if(STRSAME(s,"Put")) text_fillbutton(t, Zero); wily_modifying_tag = false; } /* Replace 'r' in 't' with 's' and a trailing space */ static void place_tool(Text*t, Range r, char*s) { Path tmp; sprintf(tmp, "%s ", s); text_replaceutf(t,r,tmp); } /* * Add a string to represent a running command to 't'. * * Almost the same as tag_addtool, the difference being * that tag_addrunning will create duplicates, e.g. the * tag could read "xterm xterm " */ void tag_addrunning(Text *t, char *cmd) { Range r; r = tag_findtool(t,cmd); r.p0 = r.p1; /* don't replace */ place_tool(t,r,cmd); } /* Add 's' to the tool section of tag 't', unless it's there already. */ void tag_addtool(Text *t, char *s) { Range r; wily_modifying_tag = true; r = tag_findtool(t,s); if(!RLEN(r)) place_tool(t,r,s); if(STRSAME(s,"Put")) text_fillbutton(t, F); wily_modifying_tag = false; } /* If 's' is in the system tools section of t, return the range * containing 's' and all the immediately following whitespace. * Otherwise return a 0-length range where the next tool * should be inserted. */ static Range tag_findtool(Text*t, char*s) { Range pos, endpos; ulong l; endpos = pos = nr; if(text_findliteralutf(t, &endpos, "|")) { endpos.p1 = endpos.p0; } else { l = text_length(t); endpos = range(l,l); } if(text_findwordutf(t, &pos, s) && pos.p0 < endpos.p0) return pos; return endpos; } /* * 't' has been modified in some fashion. 'p' is the index of the * most recently modified character. */ void tag_modified(Text*t, ulong p) { Range r; Path buf; int n; assert(t->data && TEXT_ISTAG(t)); if( wily_modifying_tag) return; /* find first whitespace_regexp */ r = nr; if(text_utfregexp(t, whitespace_regexp, &r, true)) { if(p>r.p0) return; r.p1 = r.p0; r.p0 = 0; } else { r = text_all(t); } n = text_copyutf(t, r, buf); buf[n] = 0; data_setlabel(text_data(t), buf); } wily-0.13.42/wily/win.c000064402366570000012000000027301033320152300144230ustar00ozstaff00004330000002/******************************************* * add and delete windows *******************************************/ #include "tile.h" static void win_place(Tile *col, Text *tag, Text *body); /* Free the resources tied up by 'win'. Return 0 for success. */ int win_del(Tile *w) { if(!w) return 0; assert(ISWIN(w)); /* make sure we can delete the body */ if(view_delete(w->body)){ return -1; } /* delete the tag, and the tile */ view_delete(w->tag); tile_del(w); return 0; } /* Return the window associated with 'tile', or 0. */ Tile* tile_win(Tile*tile) { return (tile && tile->body) ? tile : 0; } /* clone 'win' */ void win_clone(Tile *win) { Text *tag, *body; assert(ISWIN(win)); tag = view_text(win->tag); body = view_text(win->body); win_place(win->up, tag, body); } /* Create a window to represent 'path' */ void win_new(char*path, Text*tag, Text*body) { Tile * col; col = findcol(path); win_place(col, tag, body); } /* Add some text to w's tag representing the current selection */ void win_anchor(Tile*w, char *arg) { char buf[80]; assert(ISWIN(w)); view_getdot(w->body, buf, arg!=0); tag_addtool(view_text(w->tag), buf); } /** Create and place a new window with the given 'tag' and 'body' * text, in the given 'col'umn **/ static void win_place(Tile *col, Text *tag, Text *body) { Tile *win; int max, min; findplace(col, &min, &max); win = tile_new(V, min, max, tagheight, col, tag, body); list_add(col, win); assert(ISWIN(win)); } wily-0.13.42/wily/vsearch.c000064402366570000012000000110151033320152300152550ustar00ozstaff00004330000002/******************************************* * b3-type stuff in a view *******************************************/ #include "wily.h" #include "view.h" #include static Bool view_literal(View**vp, Range*r, char*s); static Bool view_gotofile(View**vp, Range *r, char *s); /* If 'label' is the label of some existing file, return View for it. */ View* openlabel(char*label, Bool create) { View*v; Path contracted; pathcontract(contracted,label); if ( (v=data_find(contracted)) ) { tile_show(v->tile); return v; } else if ( (v=data_open(contracted,create)) ) return v; else return 0; } /* Look (builtin) for 'arg' in the context of 'v' */ void view_look (View *v, char *arg) { Bool found = false; ulong p; Range r; assert(ISBODY(v)); if( ! text_length(v->t)) return ; p = (v->sel.p0 + 1) % text_length(v->t); r = range(p, p); if(arg) { found = text_findliteralutf(v->t, &r, arg); } else if (RLEN(v->sel) ){ found = text_look(v->t, &r, v->sel); } else { found = false; } if(found){ view_show(v,r); view_select(v, r); view_setlastselection(v); } } /* * Search for address 's'. Use *vp for context, *r as the starting point * for searches. May create a new window, but doesn't otherwise affect * the screen. If it finds something, return true, and fill in *vp and * and *r with the location of where we found something. * * 's' may be of the form path:addr, :addr, path or a literal, searched * for in that order. * * NB modifies 's' */ Bool view_goto(View**vp, Range *r, char *s) { return view_gotofile(vp,r,s) || view_literal(vp, r,s); } /* We've clicked the 'goto' button, selecting 'r' in 'v' * If this window is under external control, just send the event, * otherwise expand the selection, and 'goto' it, in the context of 'v'. */ void b3(View *v, Range r) { char *s; View *oldv; Range expanded; Data *d; View*found; /* Try to send simply expanded version to remote process */ expanded = view_expand(v, r, notaddress); if (!RLEN(expanded)) return; /* empty click nowhere -- ignore */ s = text_duputf(v->t, expanded); d = view_data(v); oldv = v; /* Send to remote process? */ if(data_sendgoto(d,expanded, s)) goto cleanup; if (view_gotofile(&v, &expanded, s)) { /* Simple file? */ r = expanded; } else if ( (found = openinclude(v,r)) ) { v = found; r = found->sel; } else if (view_literal(&v, &expanded, s)) { /* Literal? */ r = expanded; } else { /* found nothing */ goto cleanup; } view_show(v,r); view_select(v,r); view_setlastselection(v); /* warp unless b3 in the tag jumps to the body. */ if (oldv != tile_tag(view_win(v))) view_warp(v,r); cleanup: free(s); } /* Search for literal 's' in '*vp' starting at '*r'. * If we find a match, update 'vp' and 'r' and return true, * otherwise, return false. */ static Bool view_literal(View**vp, Range*r, char*s) { View*v; Text *t; Range tmp; v = *vp; tmp = *r; /* Only makes sense if 'v' is a body or we can find a useful body */ if(!ISBODY(v)){ if ((v = view_body(v)) || (v = view_body(last_selection))) { tmp = v->sel; } else { return false; } } assert(ISBODY(v)); t = v->t; if(text_findliteralutf(t, &tmp, s)) { *vp = v; *r = tmp; return true; } return false; } /* * Search for address 'a'. Use *vp for context, *r as the starting point * for searches. May create a new window, but doesn't otherwise affect * the screen. If it finds something, update *vp and *r and return * true, otherwise return false and leave vp and r alone. * * 's' may be of the form path:addr, or path, or :addr. */ static Bool view_gotofile(View**vp, Range *r, char *a) { Path s; View *v = *vp; View *v2; char *colon; /* preserve the colon */ Path label; if (strlen(a) > sizeof(Path)-1) { errno=0; diag(0, "couldn't goto \"%s\": path too long", a); return false; } strcpy(s,a); colon = strchr(s, ':'); if (colon) { *colon=0; } /* look for 's' as a file or directory */ if(strlen(s)) { /* 'path' or 'path:addr' */ data_addcontext(view_data(v), label, s); if( (v2=openlabel(label, false))){ if(colon) { Range oldr = v2->sel; if(!text_search(v2->t, r, colon+1, v2->sel)) { *r = oldr; } } else { *r = v2->sel; } *vp = v2; return true; } else return false; /* bad path */ } assert(!strlen(s)); /* :addr by itself then */ if(!ISBODY(v)){ if( ! ((v = view_body(v)) || (v = view_body(last_selection))) ) return false; } *r = v->sel; if (text_search(v->t, r, colon+1, v->sel)) { *vp = v; return true; } return false; } wily-0.13.42/wily/textpage.c000064402366570000012000000072361033320152300154550ustar00ozstaff00004330000002enum { PAGESIZE = BUFSIZE; } struct TextPage { TextPage *next, *prev; Rune *buf; /* Points to PAGESIZE bytes */ Range gap; int nrunes; /* active bytes in this page */ ulong base; Bool isLineCountValid; int LineCount; } /* Read the contents of 't' from 'fd', which should have 'len' bytes. * Return 0 for success, -1 for failure */ int text_read(Text *t, int fd, int len) { int desired, nread; char buf[RUNES_PER_PAGE]; extern int utftotext_unconverted; int offset; TextPage *page; text_clear(t); while(len > 0) { desired = MIN(len, sizeof(buf) - leftover); nread = read(fd, buf + leftover, desired); if(nread<=0) return -1; len -= nread; total = leftover + nread; page = text_appendPage(t, buf, total, &leftover); if (leftover ) { memcpy(buf, buf + nconverted, leftover); } } if (leftover) { warn("incomplete runes"); } } text_appendPage(Text*t, char*buf, int total, int*leftover) { Page* p = newPage(); /* Make sure we can fit all these bytes on one page */ assert(total <= RUNES_PER_PAGE); p->nrunes = utftotext(p->buf, buf, total); *leftover = utftotext_unconverted; p->gap.p0 = p->nrunes; p->gap.p1 = RUNES_PER_PAGE; if(t->tail) { t->tail->next = p; p->prev = t->tail; } else { t->tail = t->head = p; } } Page* newPage() { Page*p = oalloc(sizeof(Page)); p->buf = pagealloc(); p->gap = Range( return p; } int text_write_range(Text*t, Range r, int fd) { Page *p; for (p = firstInRange(t,r); p && page_contains(p,r); p= p->next) page_writeRange(p,r,fd); } } void text_copy(Text*t, Range r, Rune*buf) { Page *p; for (p = firstInRange(t,r); p && page_contains(p,r); p= p->next) buf = page_copy(p, r, buf); } /* Replace data in range 'r' of 't' with 's'. Update displays. * Return the range of the inserted text. */ Range text_replace(Text *t, Range r, Rstring s){ Page*p; for(p = t->head; p; p = p->next) if (p->base + p->len > r.p0) break; if(!p) { } if(p->len + RSLEN(s) - RLEN(r) <= RUNES_PER_PAGE) { } if(RLEN(r)) text_delete(t,r); text_updatePages(t); if(RSLEN(s)) text_insert(t, r.p0, s); text_updatePages(t); } void text_updatePages(Text*t) { Page*p; ulong base = 0; for(p = t->head; p; p=p->next){ p->base = base; base += p->nrunes; } } void text_delete(Text*t, Range r) { Page *p, *next; p = firstInRange(t,r); while(p && page_contains(p,r)){ if (page_containedIn(p,r)) { next = p->next; text_rmpage(t,p); p = next; } else { page_delete(p,r); p = p->next; } } } void text_insert(Text*t, ulong p, Rstring s){ } /** Is 'p' contained completely in 'r'? **/ Bool page_containedIn(Page*p, Range r) { } /** Completely remove 'p' from 't' **/ void text_rmpage(Text*t, Page *p) { } /** Delete 'r' from 'p' **/ void page_delete(Page*p, Range r) { /* move and extend p's gap */ } /** Returns first Page in 't' which contains 'r', (or returns 0) **/ Page* firstInRange(Text*t, Range r){ Page *p; for(p = t->head; p ; p = p->next) if (page_contains(p,r)) break; return p; } Boolean page_contains(Page*p, Range r) { ulong start,end; start = p->base; end = p->base + nrunes; /* contains r.p0 or contains r.p1 */ return !(r.p0>=end || r.p1 /**************************************************** Random garbage ****************************************************/ void text_allread (Text*t) { undo_reset(t); undo_start(t); viewlist_refresh(t->v); } /**************************************************** Simple data access ****************************************************/ Data* text_data(Text*t) { return t? t->data:0; } View* text_view(Text*t) { return t->v; } ulong text_length(Text*t) { return t->length; } Bool text_needsbackup(Text*t) { return t->needsbackup; } /**************************************************** Cooked data access ****************************************************/ /* Return body view associated with 't'. */ View* text_body(Text*t) { if(t->data) { if (TEXT_ISTAG(t)) { t = data_body(t->data); return t->v; } else { return t->v; } } else { return 0; } } /**************************************************** Simple data manipulations ****************************************************/ void text_setneedsbackup(Text*t, Bool b) { t->needsbackup = b; } Bool text_badrange(Text *t, Range r) { return r.p1 > t->length || r.p0 > r.p1; } void text_addview(Text*t, View*v) { v->next = t->v; t->v = v; } /* * Remove 'v' from list of views displaying 't'. If 'v' was the last * one, remove 't'. If 't' represents some Data, make sure we've backed * it up if necessary. Return 0 for success. */ int text_rmview(Text*t, View *v) { View**ptr; if (t->v ==v && v->next == 0) { /* this is the last view */ if (t->isbody && data_del(t->data)) return -1; } /* update the list of views of the same body */ for (ptr = &(t->v); *ptr != v; ptr = &( (*ptr)->next)) ; *ptr = v->next; if(!t->v) { /* we've deleted the last view */ text_free(t); free(t); } return 0; } /**************************************************** Write to file ****************************************************/ /* Write the contents of 't' to 'fname'. Return 0 for success. */ int text_write(Text *t, char *fname) { int fd; int retval; /* open 0666 and rely on the umask */ if((fd = open(fname,O_RDWR|O_CREAT|O_TRUNC, 0666))<0){ diag(fname, "couldn't open %s for write",fname); return 1; } retval = text_write_range(t, range(0, t->length), fd); if(retval) diag(fname, "couldn't write %s",fname); close(fd); return retval; } /*Return a file descriptor open for reading from a temporary * file which has a copy of the current selection. * * The input for the child comes from the current selection. * Put the selection into a text file and attach that text * file to the command's fdin. */ int text_fd(Text *t, Range sel) { char *file = tmpnam(0); int fd = -1; int input = -1; if ((fd = open(file, O_WRONLY|O_CREAT, 0600)) < 0) { perror("open temp file"); goto fail; } /* Now for the child's end. Do it quick so we can unlink. */ if ((input = open(file, O_RDONLY)) < 0) { perror("open temp file"); goto fail; } if (unlink(file) < 0) perror("unlink temp file"); /* no need to *do* anything about it */ /* Our buffer is the most recent selection, or if the * most recent selection is in a tag, the selection in the body * of that win. */ if (text_write_range(t, sel, fd)) { perror("write temp file"); goto fail; } if (close(fd) < 0) perror("close temp file"); return input; fail: if (input >= 0) (void) close(input); if (fd >= 0) { (void) close(fd); (void) unlink(file); } return(-1); } /**************************************************** Auto indent ****************************************************/ enum {MAXAI=128}; /* * Return an Rstring to be inserted after position 'p', * given that autoindent is on. * The Rstring is to a *static* Rune buffer. */ /** NB *not* reentrant */ Rstring text_autoindent(Text *t, ulong p) { static Rune buf[MAXAI]; Rstring s; Range r; int i; buf[0] = '\n'; s.r0 = buf; r = range(text_startOfLine(t, p), p); if (RLEN(r) > MAXAI) r.p1 = r.p0 + MAXAI; text_copy(t, r, buf +1); i = 1; while (i <= RLEN(r) && (buf[i] < 128) && isspace(buf[i])) /* FIXME unicode isspace() */ i++; s.r1 = buf + i; return s; } /**************************************************** Convenience functions ****************************************************/ /* * Return the character to start displaying from, * such that the character at 'p' will be offset by * 'height', when displayed * in a window of width 'w', with Font 'f' */ int back_height(Text *t, ulong p, Font *f, int width, int height) { int c, hpos; if (p > 0) --p; for( hpos = 0; p>0 && height>0; p--) { Tgetcset(t,p); c = Tgetc(t); switch(c) { case '\t': hpos += tabsize; break; case '\n': hpos = 0; height -= f->height; break; default: hpos += charwidth(f,c); break; } if (hpos >= width) { hpos =0; height -= f->height; } } return p? p+2 : p; } Range text_all(Text*t){ Range r; r.p0 = 0; r.p1 = t->length; return r; } void text_fillbutton(Text*t, Fcode f) { View*v; for(v = t->v; v; v= v->next) view_fillbutton(v,f); } /* Try to copy 'n' Runes at 'p' from 't' into 'buf'. * Return the number of runes copied. */ ulong text_ncopy(Text *t, Rune*buf, ulong p, ulong n) { Range r; if (p >= t->length) return 0; r = range(p, MIN(p+n, t->length)); text_copy(t, r, buf); return RLEN(r); } /* Replace 'r' in 't' with 'utf', return the range of newly placed runes */ Range text_replaceutf(Text*t, Range r, char*utf) { Rstring s; s = utf2rstring(utf); r = text_replace(t, r, s); if(s.r0) free(s.r0); return r; } /* Return a newly allocated string containing the utf * representation of the given range inside 't' */ char * text_duputf(Text *t, Range r) { ulong len = RLEN(r); ulong n; char *buf; if(!len) return strdup(""); assert(len > 0); buf = salloc(len * UTFmax); n = text_copyutf(t, r, buf); buf[n] = '\0'; return buf; } /* Copy Range 'r' from 't', convert it to utf, store it * in 'buf', (which must have enough space allocated). * Returns the number of utf characters copied. */ int text_copyutf(Text*t, Range r, char *buf) { Rune *rbuf; int rlen; int n; rlen = RLEN(r); assert(rlen >= 0); if (rlen == 0) return 0; rbuf = salloc( rlen * sizeof(Rune)); text_copy(t, r, rbuf); n = texttoutf(buf, rbuf, rbuf + rlen); free(rbuf); return n; } /**************************************************** Formatting text representing a directory ****************************************************/ static void text_getdir(Text *t, char**names) { Frame *f; char *s; f = &t->v->f; s = columnate(Dx(f->r), f->maxtab, f->font, names); undo_reset(t); text_replaceutf(t, range(0, t->length), s); undo_start(t); free(s); } /* * If 't' represents a directory, and doesn't have any modified text, * reformat the directory and return true. Otherwise return false. */ Bool text_refreshdir(Text*t) { char**names; if ( t->isbody && (names = data_names(t->data)) && undo_atmark(t) && t->v) { text_getdir(t, names); return true; } else { return false; } } /* Reformat 'd' (which must hold a directory) to fit nicely * in the smallest view displaying it. */ void text_formatdir(Text *t, char**names) { if(!(t->v && names)) return; text_getdir(t,names); viewlist_refresh(t->v); } wily-0.13.42/wily/event.c000064402366570000012000000161721033320152300147540ustar00ozstaff00004330000002/********************************************************* Set up and handle interactions with all the libXg events that aren't mouse,timer or keyboard. *********************************************************/ #include "wily.h" #include #include typedef struct Key Key; /* Different uses for a libXg event key */ typedef enum Keytype { Kfree, /* not in use */ Klisten, /* connection requests */ Kout, /* output to stderr or a window */ Kmsg /* from external connections */ } Keytype; /* Info about a libXg event key */ struct Key { Keytype t; int fd; /* file descriptor*/ ulong key; /* libXg event key */ /* * Buffer for incomplete messages. * Only in use if k->t == Kmsg. */ Mbuf buf; /* * Info about the program sending us output. * Only valid if k->t == Kout. */ int pid; Path cmd; /* shortened name of executing command */ Path olabel; /* where output should go */ /* If output should replace some View's selection ( |, > ). * Note that when we use |cmd or >cmd, we'll get TWO * event Keys, one for stderr (with k->v == 0), and * one for stdout, (with k->v set). */ View *v; Bool first; /* ** Runes with multibyte UTF codes must not be split across ** block boundaries. Strip them off and join them in this buffer. */ char obuf[UTFmax+1]; int nobuf; }; /* * Because libXg can only keep track of a small number of * event keys, so do we. We keep the Keys in a static array. * The Key at position 'n' in keytab has libXg event key 2^n. * * This is a bit wasteful, and a bit inefficient. Some event keys * will never be used here. Too bad. */ enum { MAXKEYS =FOPEN_MAX }; static Key keytab[MAXKEYS]; static Key* key_find(ulong key); static void outmsg(Key*k, int n, char*s); static void key_del(Key *k); static Key* key_new(ulong key, int fd, Keytype t); static Key* key_findcmd(char*cmd); static void oneword(char*s, char*l, int s_length); static void output_fullutfs(Key*k, int n, char*s); static void output(Key*k, int n, char*s); static void ex_accept(int n, char*s); /* Initialise keytab */ void keytab_init(void) { Key *k; ulong key = 1; for(k = keytab; k < keytab + MAXKEYS; k++) { k->t = Kfree; k->key = key; key *= 2; mbuf_init(&k->buf); } } /* * Start listening for output on 'fd'. * The output is from the (long) command 'cmd', process 'pid'. * The context is associated with 'label'. * If 'v' is set, we are piping the output to this View. */ int event_outputstart(int fd, int pid, char*cmd, char*label, View *v){ ulong key; Key *k; if (!(key = estart(0, fd, 0))) { diag(0, "estart"); return -1; } k = key_new(key, fd, Kout); k->pid = pid; k->v = v; /* Every 'pipe' key has another 'stderr' key, we only * display the 'cmd' associated with the 'stderr' key. */ if(k->v) { k->first = true; } else { oneword(k->cmd, cmd, sizeof(k->cmd)); olabel(k->olabel, label); addrunning(k->cmd); } k->nobuf = 0; return 0; } /* Start listening for connection attempts on 'fd' */ void event_wellknown(int fd){ ulong key; if(!(key = estart(0, fd, 0))) error("estart"); key_new(key,fd, Klisten); } /* * Handle 'n' bytes of data in 's' which arrived from * libXg event key 'key'. */ void dofd(ulong key, int n, char*s) { Key *k = key_find(key); if(!n) { key_del(k); return; } switch(k->t){ case Klisten: ex_accept(n,s); break; case Kout: output_fullutfs(k, n, s); break; case Kmsg: outmsg(k, n, s); break; default: error("bad key type %d", k->t); break; } } /* * Kill all the external processes matching * the arguments. */ void kill_all(char*s) { Key *k = 0; const char *sep = " \t\n"; for (s = strtok(s, sep); s; s = strtok(NULL, sep)) { if ((k = key_findcmd(s))) { /* only output keys have a prog attached */ assert(k->t == Kout); if(kill(- k->pid, SIGKILL)) diag(0, "kill %s", s); } } } /* Output a list of possible 'Kill' commands. */ void kill_list(void){ Key *k; errno = 0; for(k = keytab; k < keytab + MAXKEYS; k++) if(k->t == Kout && !k->v) diag(0, "Kill %s", k->cmd); } /****************************************************** static functions ******************************************************/ static void outmsg(Key*k, int n, char*s) { if(partialmsg(&k->buf, k->fd, n, s)){ diag(0, "Received bad message, closing connection"); key_del(k); } } /* Free any resources that 'k' was tying up. */ static void key_del(Key *k) { close(k->fd); estop(k->key); switch(k->t) { case Kout: if (k->nobuf > 0) output(k, k->nobuf, k->obuf); if (!k->v) rmrunning(k->cmd); break; case Kmsg: data_fdstop(k->fd); break; case Klisten: error("Klisten closed"); default: error("bad key type %d", k->t); } k->t = Kfree; } /* Allocate and return a new Key with the given key, fd and type */ static Key* key_new(ulong key, int fd, Keytype t) { Key *k; k = key_find(key); assert(k->t == Kfree); k->fd = fd; k->t = t; return k; } /* Find the output Key with the given 'cmd' */ static Key* key_findcmd(char*cmd) { Key *k; for(k = keytab; k < keytab + MAXKEYS; k++) if (k->t == Kout && STRSAME(cmd, k->cmd)) return k; return 0; } /* Put a one-word version of long command 'l' into 's' */ static void oneword(char*s, char*l, int s_length){ char *blank = strpbrk(l, whitespace); if ((blank) && (blank - l < s_length)) s_length = blank - l + 1; strncpy(s, l, s_length); s[s_length-1] = '\0'; /* some strncpy() don't do this */ } /* ** Key has a buffer where we concatenate runes that get split between two ** (or more -- very small?) blocks. This is accomplished in four steps: ** 1) If we have an uncomplete rune from last call, try to complete it. ** 2) If output isn't exhausted and we have something from last call, ** output it -- it's either a full rune or bad utf. ** 3) Put away any unfull rune at the and of the output. ** 4) Output any remaining output, which is now only full utfs. */ static void output_fullutfs(Key *k, int n, char *s) { if (k->nobuf > 0) { int m = fillutfchar(k->obuf, k->nobuf, s, n); k->nobuf+=m, s+=m, n-=m; } if ((n > 0) && (k->nobuf > 0)) { output(k, k->nobuf, k->obuf); k->nobuf = 0; } if (n > 0) { int m = unfullutfbytes(s, n); if (m > 0) { memcpy(k->obuf, s+n-m, m); k->obuf[m] = '\0'; n -= m; } k->nobuf=m; } if (n > 0) { output(k, n, s); } } /* Copy the 'n' bytes of data in 's' to the window or output directory * corresponding to 'k' */ static void output(Key*k, int n, char*s) { if(k->v) view_pipe(k->v, &k->first, s, n); else noutput(k->olabel, s, n); } /* Accept the connection we're told about with 's' and 'n' */ static void ex_accept(int n, char*s) { int fd; ulong key; Key *k; if((fd =wily_connect(s,n))<0) { diag(0, "failed connection attempt"); return; } if (!(key= estart(0,fd,0))){ diag(0, "couldn't estart to accept connection"); close(fd); return; } k = key_new(key, fd, Kmsg); mbuf_clear(&k->buf); } /* * Find the Key info given the libXg event key. * * ASSUMPTION: integers at least 32 bit. */ static Key* key_find(ulong key) { Key *k; for(k = keytab; k < keytab + MAXKEYS; k++) if(k->key == key) return k; /* We assume key_find will always work */ assert(false); return 0; } wily-0.13.42/wily/cursor.c000064402366570000012000000022241033320152300151410ustar00ozstaff00004330000002/******************************************* * Cursor bitmaps *******************************************/ /* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include Cursor boxcursor = { {-7, -7}, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x00, 0x00} }; Cursor fatarrow = { { -1, -1 }, { 0xff, 0xff, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0c, 0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04, 0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8c, 0x04, 0x92, 0x08, 0x91, 0x10, 0xa0, 0xa0, 0xc0, 0x40, }, { 0x00, 0x00, 0x7f, 0xfe, 0x7f, 0xfc, 0x7f, 0xf0, 0x7f, 0xe0, 0x7f, 0xe0, 0x7f, 0xf0, 0x7f, 0xf8, 0x7f, 0xfc, 0x7f, 0xfe, 0x7f, 0xfc, 0x73, 0xf8, 0x61, 0xf0, 0x60, 0xe0, 0x40, 0x40, 0x00, 0x00, }, }; Cursor *cursor=&fatarrow; /* Cursor *cursor=0; thin cursor */ wily-0.13.42/wily/global.c000064402366570000012000000013621033320152300150660ustar00ozstaff00004330000002#include "wily.h" Bool show_dot_files = false; Bool autoindent_enabled = true; /* cwd for wily process */ Path wilydir; /* widget with most recent b1 click */ View * last_selection; /* 'last_focus' is a cache of the view we are pointing at, * (we use point to type). We update this only when we start * typing after moving the pointer, or if the view is deleted. */ View *last_focus; /* "stop" characters for various text expansions. * heuristic guesses only. */ char *notfilename = "!\"#%&'()*;<=>?@`[\\]^{|}"; char *notinclude = "!#%&'()*;=?@`[\\]^{|}"; char *notdoubleclick= "!\"#$%&'()*+,-./:;<=>?@`[\\]^{|}~"; char *notcommand= "!\"#%&'()*;:=?@`[\\]^{}"; char *notaddress= "!\"%&'()+;<=>?@`[]{|}"; char *whitespace = " \t\v\n"; wily-0.13.42/wily/global.h000064402366570000012000000010201033320152300150620ustar00ozstaff00004330000002/* wily.c */ extern char*filetools; extern char*dirtools; /* global.c */ extern Bool show_dot_files; extern Bool autoindent_enabled; extern View *last_selection; extern View *last_focus; extern char * notfilename, *notdoubleclick , *notcommand, *notaddress, *notinclude; extern char* whitespace; extern Path wilydir; /* icons.c */ extern Cursor boxcursor; extern Cursor fatarrow; extern Cursor *cursor; /* tile.c */ extern Tile *wily; /* wily.c */ extern int tagheight; extern int tabsize; /* ../sam/libframe/frinit.c */ wily-0.13.42/wily/tile2.c000064402366570000012000000243001033320152300146420ustar00ozstaff00004330000002/******************************************* * Tiling window manager *******************************************/ #include "tile.h" /* Is the tile hidden? */ Bool tile_hidden(Tile *t) { /* We are hidden, or one of our ancestors is hidden */ return HIDDEN(t) || (t->up && HIDDEN(t->up)); } /** 't' contains p. * Return the lowest-level subtile which * still contains 'p' **/ View* tile_containingView(Tile *t, Point p) { /* 't' contains 'p' */ assert(t && ptinrect(p, t->r)); if(ptinrect(t->tagr, p)) return t->tag; if (t->type == TILE_WIN) return t->c.body; return tileSet_containingView(&t->c.children, p); } View* tileSet_containingView(TileSet *ts, Point p) { int j; Tile *t; assert(t && ptinrect(p, ts->r)); /* todo(optimize): we could save some comparisons * by making use of the fact that the tiles are in order and * abut one another */ for(j=0; jntiles; j++){ Tile *t = ts->tile[j]; if(ptinrect(p, t->r)) return tile_containingView(t,p); } } /* 't's shape has changed. Redisplay it, and any of its children */ void tile_reshaped(Tile *t, Rectangle r) { t->tagr = t->contentsr = r; t->tagr.maxy = t->contentsr.miny = t->tagr.miny + tag_height(t->tag); tag_reshaped(t->tag, t->tagr); if(t->type == TILE_WINDOW) { view_reshaped(t->c.body, t->contentsr); } else { tileSet_reshaped(&t->c.children, t->contentsr); } assert(tile_invariant(t)); } static void tileSet_reshaped(TileSet *ts, Rectangle r) { ts->r = r; /* set sizes */ tileSet_setsizes(ts,r); /* reshape children */ for(int j=0; jntiles; j++) { t = ts->tile[j]; if(ts->isHorizontal) { r.max.x = r.min.x + t->size; } else { r.max.y = r.min.y + t->size; } if(t->size) { tile_reshaped(t,r); } if(ts->isHorizontal) { r.min.x = r.max.x; } else { r.min.y = r.max.y; } } } /* * Adjust the sizes of the children, redisplay them if necessary. * We can assume that all of the * tiles have the right approximate size, but that's it. */ static void tileSet_setsizes(TileSet *ts, Rectangle r) { available = ts->isHorizontal? Dx(r) : Dy(r); /* todo: spread available size amongst children tiles. * We might currently have some tiles which are hidden, * and we might end up having to hide some tiles. */ Tile *t; int cmin, cmax; Tile *slop; int diff; assert(list_oksizes(l)); if (tile) { crop(tile,l); adjust_position(tile); adjust_sizes_in_range(l->down, tile, tile->min - l->cmin); adjust_sizes_in_range(tile->right, 0, l->cmax - tile->max); } else adjust_sizes_in_range(l->down, 0, LISTSIZE(l)); assert(list_oksizes(l)); assert(list_size(l->down, 0) <= LISTSIZE(l)); FOR_EACH_VISIBLE(l->down,0) { quantize(t); } diff = LISTSIZE(l) - list_size(l->down, 0); assert(diff>=0); /* Even things up a little bit */ if ((slop = last_visible_body(l->down,0)) || (slop = last_visible(l->down, 0)) ) { slop->max += diff; } list_slide(l); setcminmax(l, &cmin, &cmax); FOR_EACH_TILE(l->down,0) { t->cmin = cmin; t->cmax = cmax; if(!t->ishidden) tile_reshaped(t); } assert(list_invariant(l)); } /* Add 't' to 'ts' and redisplay the modified 'list' * Try to maintain 't's size and position, but also try to avoid hiding * other tiles. Make sure that 'tile' ends up with a reasonable amount * of space. */ void list_add(TileSet *ts, Tile *t) { Tile *left; Tile *next; int max; assert(!list->ishidden); assert(!tile->ishidden); assert(list_invariant(list)); if(tile->body) { Path buf; Data *d; d = view_data(tile->body); data_getlabel(d, buf); placedcol( buf, list); } tile->up = list; crop(tile, list); if( (left = list_find(list, tile->min)) ) { /* Add 'tile' just to the right of 'left' */ left->max = tile->min; if(TILESIZE(left) < tile->base) left->ishidden = true; else quantize(left); tile->left = left; tile->right = left->right; left->right = tile; if (tile->right) tile->right->left = tile; } else { assert(!list->down); /* ...or we would have found a tile */ tile->right = tile->left = 0; list->down = tile; tile->min = list->cmin; tile->max = list->cmax; } /* Maybe expand tile->max */ next = next_visible(tile); max = next? next->min : list->cmax; tile->max = MAX(tile->max, max); tile->min = MIN(tile->max - tile->base, tile->min); list_reshaped(list, tile); } /* * Unlink 'tile' from its parent/child/siblings. */ void tile_unlink(Tile*tile){ /* Unlink tile */ if(tile->right) tile->right->left = tile->left; if(tile->left) { tile->left->right = tile->right; /* Give the preceding window all the space. */ tile->left->max = tile->max; } else { tile->up->down = tile->right; } list_unhide(tile->up); cls(rectangle(tile)); list_reshaped(tile->up, 0); } /* * Free up all the resources used by 'tile' */ void tile_free(Tile*tile){ /* Free tile's resources */ free(tile->body); free(tile->tag); free(tile); } /* * Unlink 'tile' from its parent/child/siblings. * Free up all the resources used by 'tile' */ void tile_del(Tile *tile) { tile_unlink(tile); tile_free(tile); } /* Find a new parent for 'tile' somewhere at point 'p' */ Tile* newparent(Tile*tile, Point p){ Tile *t = point2tile(wily, p); assert(t); while((t->ori == tile->ori) || t->body) t = t->up; return t; } void tile_move(Tile *tile, Point p){ Tile *parent; int dest; /* Make sure we'll have someplace worth moving to */ parent = point2tile(wily,p); if (parent == 0 || parent == wily) return; tile_unlink(tile); dest = (tile->ori == H) ? p.x : p.y; if (tile->min < dest && dest < tile->max) tile->min = dest; else moveto(tile, dest); parent = newparent(tile, p); list_add(parent, tile); cursorset(buttonpos(tile)); } void tile_show(Tile *tile) { if(tile->up) tile_show(tile->up); if (tile->ishidden || (TILESIZE(tile) < tile_minsize(tile))) tile_grow(tile, 1); } View* tile_body(Tile*t) { return t? t->body: 0; } View* tile_tag(Tile*t) { return t? t->tag: 0; } /* Fill in 'min' and 'max' with a subregion within 'tile' for creating a new tile */ static void tile_split(Tile *tile, int *min, int *max){ int lastline, average; *max = tile->max; average = (tile->max + tile->min)/ 2; if(tile->body) { lastline = view_lastlinepos(tile->body); assert(lastline <= tile->max); *min = MIN(average, lastline); } else { *min = average; } } /* Fill 'min' and 'max' with a good place to add a tile within 'list' */ void findplace(Tile*list, int *min, int *max){ /* Split the largest visible tile, or use all the available space. */ Tile*biggest; if ( (biggest=biggest_visible(list->down, 0)) ) { tile_split(biggest, min, max); } else { *max = list->cmax; *min = list->cmin; } } /* Change t's position, keeping its size. */ void moveto(Tile*t, int pos) { int size = TILESIZE(t); t->min = pos; t->max = t->min + size; } /* Create (but don't display) a new tile */ Tile* tile_new(Ori ori, int min, int max, int base, Tile*parent, Text *tagt, Text*bodyt){ Tile*tile = NEW(Tile); int minsize; tile->ishidden = false; tile->ori = ori; tile->min = min; tile->max = max; tile->base = base; tile->up = parent; setcminmax(parent, &tile->cmin, &tile->cmax); tile->down = tile->left = tile->right = 0; tile->tag = view_new(font, true, tagt, tile); tile->body = bodyt ? view_new(font, false, bodyt, tile): 0; minsize = tile_minsize(tile); if(TILESIZE(tile) < minsize) tile->max = tile->min + minsize; return tile; } /* The minimum comfortable viewing size for 't' */ int tile_minsize(Tile*t){ return 3 * t->base; } static Bool tile_invariant(Tile *t) { int size ,body,tag, diff; Tile *last; /* not null pointer */ assert(t); switch(t->type){ case TILE_WIN: /* win checks */ break; case TILE_PARENT: /* TileSet checks */ break; default: /* illegal t->type */ assert(false); } } static Bool tileSet_invariant(TileSet *t) { /* * The size of the tile == the sum of the sizes of its body and * tag, except if we're the "bottom" tile, in which case the * size of the tile might be a _little_ bit bigger than that * sum. */ body = view_height(tile->body); tag = view_height(tile->tag); last = last_visible_body(tile, 0); if (tile != last) { assert(size == body + tag); } else { /* bottom tile might have a little 'slop' */ diff = size - (body + tag); assert(diff >= 0); assert (diff <= tag); } return true; } /* Ensure 't' wil fit inside 'list'. */ static void crop(Tile*t, Tile *list) { int size = TILESIZE(t); int listsize = LISTSIZE(list); assert(t->up == list); assert (size >= 0); if(size > listsize) { t->max = t->min + listsize; size = listsize; } if (t->min < list->cmin) moveto(t, list->cmin); if (t->max > list->cmax) t->max = list->cmax; assert (t->max >= t->min); assert (t->max <= list->cmax); assert (t->min >= list->cmin); } /* "Snap" the size of 't' to some "neat" value, * without increasing 't's size. */ static void quantize(Tile*t) { int tag, body,size; if (!t->body) return; /* only really makes sense for windows */ size = TILESIZE(t); tag = snapheight(t->tag, size); assert(size >= tag); /* or we should have been hidden */ body = snapheight( t->body, size -tag); t->max = t->min + tag + body; } /* Adjust the position of 't', to try to make sure we don't * have to hide all of t's siblings. On the other hand, don't * move 't' _too_ much. */ static void adjust_position(Tile *t) { Tile *l = t->up; int size, available, before, after, minsize, diff, move; before = list_basesize(l->down, t); after = list_basesize(t->right, 0); size = TILESIZE(t); /* We're prepared to shrink to half our asked-for size, * or the minimum size for a tile of our type, whichever * is bigger. */ minsize = MAX(size/2, tile_minsize(t)); available = size - minsize; /* move t->min down a bit? */ diff = l->cmin + before - t->min; if (diff>0) { move= MIN(available, diff); if(move > 0) { t->min += move; available -= move; } } /* move t->min up a bit? */ diff = t->max - (l->cmax - after); if (diff>0) { move= MIN(available, diff); if(move > 0) { t->max -= move; } } } /* Change the font of 't' and t's children */ void tile_setfont(Tile *t,char* arg) { if(t->body) { view_setfont( t->body, arg); } else { FOR_EACH_TILE(t->down, 0) { tile_setfont(t, arg); } } } * We are hidden, or one of our ancestors is hidden */ return HIDDEN(t) || (t->up && HIDDEN(t->up)); } /** 't' contains p. * Return the lowest-level subtile which * still contains 'p' **/ View* tile_containingView(Tile *t, Point p) { /* 't' contains 'p' */ assert(t && ptinrect(p, t->r)); if(ptinrect(t->tagr, wily-0.13.42/wily/tile2.h000064402366570000012000000026741033320152300146610ustar00ozstaff00004330000002/******************************************* * tile data structure *******************************************/ #include "wily.h" typedef enum TileType { TILE_WIN, TILE_PARENT } TileType; typedef struct TileSet TileSet; struct Tile { Rectangle r, tagr, contentsr; View *tag; /* every tile has a tag */ int pos; /* position of this tile within a set */ int size; /* current actual size (maybe zero) */ int desiredSize; /* remember a good size if we're minimized */ int minSize; /* minimum usable size */ /* Depending on 'type', we might contain a 'body', or * a set of children */ TileType type; union { View* body; TileSet children; } c; /* contents -- my Kingdom for anonymous unions*/ Tile *parent; /* null for main window */ }; #define HIDDEN(t) ((t)->size==0) tile_paint(Tile*t, Rect r) { view_paint(tag, r); if (t->type == TILE_WIN) { view_paint(t->contents.body, r2); } else { tileSetPaint(t->contents.children, r2); } } /** TileSet contains a list of tiles, which might be arranged * horizontally (e.g. columns within main wily win) * or vertically (e.g. windows within a column). **/ struct TileSet { Tile **tile; int ntiles, maxtiles; int totalSize; Rectangle r; Bool isHorizontal; } #define TILESIZE(tile) ((tile)->max - (tile)->min) #define LISTSIZE(list) ((list)->cmax - (list)->cmin) #define ISWIN(tile) ( (tile)->type== TILE_WIN ) extern int tagheight; /* height of a tag */ extern Tile *wily; wily-0.13.42/wily/scroll.c000064402366570000012000000052741033320152300151320ustar00ozstaff00004330000002/******************************************* * Display scroll_bars *******************************************/ #include "wily.h" static Bitmap *dkgrey_o, *dkgrey_e; struct Scroll { Rectangle r; Bitmap *b; ulong thumb, extent, max; }; static Rectangle getthumb(Scroll *, ulong , ulong , ulong ); /* Initialize bitmaps for scrollbars. Called once, on system entry. */ void scroll_init(void) { int x, y; int dx = 4, dy = 2; dkgrey_o = balloc(Rect(0, 0, dx, dy), 0); bitblt(dkgrey_o, dkgrey_o->r.min, dkgrey_o, dkgrey_o->r, F); for (x = 0; x < dx; x += 2) for (y = (x % 4) / 2; y < dy; y += 2) point(dkgrey_o, Pt(x, y), 0, Zero); dkgrey_e = balloc(Rect(0, 0, dx, dy), 0); bitblt(dkgrey_e, dkgrey_e->r.min, dkgrey_e, dkgrey_e->r, F); for (x = 1; x < dx; x += 2) for (y = (x % 4) / 2; y < dy; y += 2) point(dkgrey_e, Pt(x, y), 0, Zero); } void scroll_setrects(Scroll*s, Bitmap *b, Rectangle r) { if(!s) return; s->r = r; s->b = b; s->thumb = s->extent = s->max = 0; if(b) { bitblt(b, r.min, b, r, Zero); border(b, r, 1, F); } assert(Dx(s->r)<=SCROLLWIDTH); } Scroll * scroll_alloc(Bitmap *b, Rectangle r) { Scroll *s; s = NEW(Scroll); scroll_setrects(s,b,r); return s; } void scroll_set(Scroll *s, ulong thumb, ulong extent, ulong max) { Rectangle q, oldr, newr, above, below; oldr = getthumb(s, s->extent, s->max, s->thumb); above = below = s->r; above.max.y = oldr.min.y; below.min.y = oldr.max.y; newr = getthumb(s, extent, max, thumb); /* Sections that before were NOT in the thumb, but now are */ q = newr; if (rectclip(&q, above)) bitblt(s->b, q.min, s->b, q, Zero); q = newr; if (rectclip(&q, below)) bitblt(s->b, q.min, s->b, q, Zero); above = below = s->r; above.max.y = newr.min.y; below.min.y = newr.max.y; /* Sections that before WERE in the thumb, but now are NOT */ q = oldr; if (rectclip(&q, above)) { if (s->r.min.x % 2 == 0) texture(s->b, q, dkgrey_e, S); else texture(s->b, q, dkgrey_o, S); } q = oldr; if (rectclip(&q, below)) { if (s->r.min.x % 2 == 0) texture(s->b, q, dkgrey_e, S); else texture(s->b, q, dkgrey_o, S); } s->thumb = thumb; s->extent = extent; s->max = max; } static ulong div_down(unsigned long long p, unsigned long long q) { return p / q; } static ulong div_up(ulong p, ulong q) { return (p + q - 1) / q; } static Rectangle getthumb(Scroll *s, ulong extent, ulong max, ulong thumb) { Rectangle r; unsigned long long length; r = inset(s->r, 1); assert (Dx(s->r)<= SCROLLWIDTH); length = Dy(r); if (extent < max) { r.min.y = r.min.y + div_down(length * thumb, max); if (thumb < max) { r.max.y = r.min.y + div_up(length * extent, max); } else r.min.y = r.max.y; } return r; } wily-0.13.42/wily/data.c000064402366570000012000000056421033320152300145440ustar00ozstaff00004330000002/******************************************* * Data methods *******************************************/ #include "wily.h" #include "data.h" #include Data *dataroot; Text* data_body(Data*d) { return d->t; } Text* data_tag(Data*d){ return d->tag; } /* Return the names in directory 'd', or 0 */ char** data_names(Data*d){ return d ? d->names : 0; } /* Return true if 'd' should have its resize box filled in */ Bool data_isdirty(Data *d) { return d && NEEDSBACKUP(d); } /* Write all dirty windows. Return 0 for success. */ int data_putall(void) { Data *d; int retval = 0; for(d=dataroot; d; d=d->next) if(NEEDSBACKUP(d)) if (data_put(d,0)) retval = -1; return retval; } /* Backup all dirty files. Return 0 unless we failed to backup something. */ int data_backupall(void) { Data *d; int retval= 0; for(d = dataroot; d; d = d->next) { if (data_backup(d)) { retval = 1; } } return retval; } /* * Write the contents of 'd' to 'path'. * Return 0 if we've successfully written 'd' to its label. */ int data_put(Data *d, char *label) { int fd; Stat buf; Path path; Bool statfailed, writefailed; if(!label) label = d->label; label2path(path, label); statfailed = stat(path, &buf); if((fd = open(path,O_RDWR|O_CREAT|O_TRUNC, 0666))<0){ diag(path, "couldn't open \"%s\" for write", path); return -1; } writefailed = text_write_range(d->t, text_all(d->t), fd); close(fd); if(writefailed) { diag(path, "write failed: \"%s\"", path); return -1; } if (!strcmp(d->label,label) || !statcmp(&buf, &d->stat)) { if(!d->names) { tag_rmtool(d->tag, "Put"); undo_mark(d->t); if (d->backupto && strcmp(d->backupto, path)) data_setbackup(d, path); } return 0; } return -1; } void data_listremove(Data *d) { Data **ptr; for(ptr = &dataroot; *ptr != d; ptr = &((*ptr)->next)) ; *ptr = d->next; } /* Delete 'd' if we can do so without permanently losing * data, and return 0. If there's a problem, return 1. */ int data_del(Data*d) { if(data_backup(d)) return 1; data_senddestroy(d); data_listremove(d); dirnames_free(d->names); if(d->backupto) free(d->backupto); free(d); return 0; } /* Backup 'd' if necessary. Return 0 for success. */ int data_backup(Data *d) { Path fname; if (!NEEDSBACKUP(d)) return 0; if( (backup_name(d->backupto, fname)) ) return -1; if(text_write(d->t, fname)) return -1; errno = 0; diag(fname, "backup %s %s", mybasename(fname), d->backupto); return 0; } /* Record that in emergencies, 'd' should be saved, noting * that it is a copy of 'bfile' */ void data_setbackup(Data *d, char*bfile) { if(d->backupto) free(d->backupto); if(bfile && !strstr(bfile, "+Errors")) { d->backupto = strdup(bfile); text_setneedsbackup(d->t, true); } else { d->backupto = 0; text_setneedsbackup(d->t, false); }; } Data * data_findid(Id id) { Data *d; for(d=dataroot; d; d=d->next) if(d->id==id) break; return d; } wily-0.13.42/wily/data.h000064402366570000012000000037731033320152300145540ustar00ozstaff00004330000002/******************************************* * the stuff a window represents (file, directory, type-script...) *******************************************/ #include /* The 'Data' struct The 'label' is the name of the window, as it appears in the window. The label can start with: / meaning an absolute path name, e.g. /bin $ meaning an environment variable, e.g. $HOME ~ meaning a home-dir, e.g. ~/, ~i/ anything else is interpreted relative to the directory wily started in. If the window is a directory, the label should end with a / If we represent some file which should be backed up, 'backupto' is set to the name of the file to back up. For data objects monitored by some external process we track the file descriptor to that process, and an event mask telling us what events that process is interested in. For directories, we cache a null-terminated list of strings representing the files in the directory. This is so when the window is reshaped we can reformat the list without having to reread the directory. If this Data object doesn't represent a directory, 'names' ==0 'label' is what currently appears in the tag. 'cachedlabel' is the value of 'label' at the last successful stat/open/... We only update 'has_stat' and 'stat' when necessary. */ struct Data { Text *t; Text *tag; Data *next; Path label, cachedlabel; /* Path path; */ Bool has_stat; Stat stat; char *backupto; /* for object connected to some external process */ int fd; ushort emask; Id id; /* Unique identifier */ char **names; /* cache of names of files in this directory, or 0 */ }; /* A data object needs to be backed up if there is some backup file associated * with it, and it's Text isn't clean */ #define NEEDSBACKUP(d) (d->backupto && !undo_atmark(d->t)) void data_setbackup(Data *, char*); Data * data_findid(Id ); extern Data *dataroot; Bool data_senddestroy(Data *d); void data_listremove(Data *d); /* dir.c */ void dirnames_free(char**names); char** dirnames (DIR *dirp, char *path); wily-0.13.42/wily/file.c000064402366570000012000000113211033320152300145410ustar00ozstaff00004330000002/******************************************* * Data read/write files, directories *******************************************/ #include "wily.h" #include "data.h" #include static int data_getstat (Data*, char*, char*, Stat*); static void data_opennew (Data*, char*, char*path); static int data_getdir (Data*, char*, char*, Stat*); static int data_getfile (Data*, char*, char*, Stat*); static void data_settag (Data*, char*); static Data * data_alloc (void); /* * Open a new 'data' to represent 'label'. Either read 'label', or if * it doesn't exist and 'create' is set, return an empty window to * represent where we _will_ write it. * * Return (View*)0 if 'label' exists but we can't read it, or it doesn't * exist and we don't want to create it. */ View* data_open(char*label, Bool create) { Data *d; Stat buf; Path path; Bool failure; label2path(path, label); d = data_alloc(); failure = false; if(stat(path,&buf)) { /* doesn't exist -- yet */ if(create) data_opennew(d, label, path); else failure = true; } else { failure = data_getstat(d, label, path,&buf); } if(failure){ data_listremove(d); free(d); return 0; } else { if(d->names) add_slash(path); data_settag(d, path); win_new(path, d->tag, d->t); return text_view(d->t); } } /* * Read file or directory 'label' into 'd'. * Return 0 for success. */ int data_get(Data *d, char *label) { Stat buf; Path path; if(data_backup(d)) return -1; /* If we did this, we'd lose data */ if(!label) label = d->label; /* is strcpy(a,a) bad? */ label2path(path,label); if(stat(path,&buf)){ diag(0, "Couldn't stat [%s (%s)]", path, label); return -1; } else { return data_getstat(d, label, path, &buf); } } /* Load 'd' with 'path', which has stat buffer 'buf'. * Returns 0 if we loaded succesfully. */ static int data_getstat(Data*d, char* label, char*path, Stat*buf) { int failed; cursorswitch(&boxcursor); bflush(); undo_reset(d->t); failed = S_ISDIR(buf->st_mode) ? data_getdir(d, label, path, buf) : data_getfile(d, label, path, buf); undo_start(d->t); if(!failed) undo_mark(d->t); cursorswitch(cursor); return failed; } /* Load 'd' with new file 'path'. */ static void data_opennew(Data*d, char*label, char*path) { /* d */ pathcontract(d->label, label); strcpy(d->cachedlabel, d->label); d->has_stat = false; data_setbackup(d, path); dirnames_free(d->names); d->names = 0; /* d->t */ text_replace(d->t, text_all(d->t), rstring(0,0)); undo_start(d->t); undo_mark(d->t); /* d->tag */ tag_setlabel(d->tag, d->label); tag_rmtool(d->tag, "Put"); } /* Load 'd' with directory 'path', which has stat buffer 'buf'. * Returns 0 if we loaded succesfully. */ static int data_getdir(Data*d, char*label, char*path, Stat*buf) { DIR* dirp; if((dirp = opendir(path)) == NULL) { diag(0, "opendir [%s]", path); return -1; /* failure - modify nothing */ } /* d */ pathcontract(d->label,label); add_slash(d->label); strcpy(d->cachedlabel, d->label); d->has_stat = true; d->stat = *buf; data_setbackup(d,0); dirnames_free(d->names); d->names = dirnames(dirp, path); /* d->t */ text_formatdir(d->t, d->names); /* d->tag */ tag_rmtool(d->tag, "Put"); tag_addtool(d->tag, "Get"); tag_setlabel(d->tag, d->label); return 0; } /* Load 'd' with file 'path', which has stat buffer 'buf'. * Returns 0 if we loaded succesfully. */ static int data_getfile(Data*d, char*label, char*path, Stat*buf) { int fd; extern Bool utfHadNulls; if((fd = open(path, O_RDONLY)) == -1) { diag(path, "open [%s]", path); return -1; /* failure - modify nothing */ } /* d */ pathcontract(d->label, label); strcpy(d->cachedlabel, d->label); d->has_stat = true; d->stat = *buf; data_setbackup(d,path); dirnames_free(d->names); d->names = 0; /* d->t */ utfHadNulls = false; text_read(d->t, fd, buf->st_size); close(fd); if (utfHadNulls) { errno=0, diag(path, "nulls or illegal utf in [%s]", path); data_setbackup(d,0); } /* d->tag */ tag_rmtool(d->tag, "Put"); tag_rmtool(d->tag, "Get"); tag_setlabel(d->tag, d->label); return 0; } /* Fill 'buf' with appropriate stuff for d's tag */ static void data_settag(Data*d, char *path) { Path buf; char*common; char*specific; common = d->names? dirtools : filetools; specific = tag_match(path); sprintf (buf, "%s %s | %s %s ", d->label, d->names? "Get":"", common, specific); tag_set(d->tag, buf); } static Data * data_alloc(void) { Data *d; static Id id; d = NEW(Data); d->id = id++; d->next = dataroot; dataroot = d; d->t = text_alloc(d, true); d->tag = text_alloc(d, false); d->names = 0; d->backupto = 0; d->fd = 0; d->emask = 0; d->has_stat = false; strcpy(d->label, ""); strcpy(d->cachedlabel, ""); return d; } wily-0.13.42/wily/exec.c000064402366570000012000000176411033320152300145610ustar00ozstaff00004330000002/******************************************* * fork, setup environment, exec children *******************************************/ #include "wily.h" #include #include #include static char * historyfile; static char * shell; static int ex_run (View*, char *); static int pipe_views (char**cmd, View**vout, View**vin); static int openpipes (int*out, int *err, Bool ); static int ex_parent (int , int , char*, char*, View *, int ); static void ex_child (int , int , char *, char *, View *); static void history (char *cmd); static void childenv (char *,char*); static void childfds (int fderr, int fdout, View *vin); static void reap (void); static void signal_init (void) ; static void well_known_init(void) ; /* * Initialize whatever we need * for dealing with external processes */ void ex_init(void) { keytab_init(); well_known_init(); signal_init(); historyfile = getenv("HISTORY"); if(!historyfile) historyfile = getenv("history"); shell = getenv("SHELL"); if(!shell) shell=DEFAULTSHELL; } /* * Run 'cmd' with arg 'arg' in View 'v'. * * 'arg' may be null, 'cmd' must be nonnull. */ void run(View *v, char *cmd, char *arg) { char *buf, *buf2; char *a2; cmd += strspn(cmd, whitespace); if(!*cmd) return; /* * For builtins, we want to separate cmd and arg, * and if we're passed a pointer to 'arg', we must pass * one on to builtin, even if the arg is just whitespace. */ if(arg) { buf = salloc( strlen(cmd) + strlen(arg) + 2); sprintf(buf, "%s %s", cmd, arg); } else { buf = strdup(cmd); } buf2 = strdup(buf); /* before we scribble over buf */ cmd = strtok(buf, whitespace); assert(*cmd && !isspace(*cmd)); a2 = strtok(0, ""); if(!a2) a2 = arg; if(!builtin(v, cmd, a2)) ex_run(v, buf2); free (buf); free (buf2); } /********************************************************************* Static Functions *********************************************************************/ /* Execute 'cmd', which was selected in 'v'. * PRE: the first character of cmd is not 0 or whitespace. * Return 0 for success. */ static int ex_run(View*v, char *cmd) { View *vout, *vin; /* Views for output/input */ int pout[2]; /* pipe for stdout */ int perr[2]; /* pipe for stderr */ Path label; int pid; if(pipe_views(&cmd, &vout, &vin)) return -1; if(openpipes(pout, perr, vout!=0)) return -1; data_getlabel(view_data(v), label); switch(pid=fork()) { case -1: /* fork failed */ close(perr[0]); close(perr[1]); close(pout[0]); close(pout[1]); return -1; default: /* parent */ close(perr[1]); close(pout[1]); return ex_parent(perr[0], pout[0], label, cmd, vout, pid); case 0: /* child */ close(perr[0]); close(pout[0]); ex_child(perr[1], pout[1], label, cmd, vin); /* ex_child doesn't return */ assert(false); exit(1); return -1; } } /* * Update 'cmd', 'vout' and 'vin' * appropriately depending on whether 'cmd' is a piping command, * i.e. starts with | < or >. * Return 0 for success. */ static int pipe_views(char**cmd, View**vout, View**vin) { char op; View*vpipe; op = **cmd; *vout = 0; *vin = 0; if(!( op == '|' || op == '<' || op == '>')){ return 0; } /* Pipe operations are on the body of the last selection */ if(!(vpipe = view_body(last_selection))) return -1; /* Make 'cmd' now point to the command, after '|' and * optional whitespace. */ *cmd += 1 + strspn((*cmd)+1, whitespace); /* don't execute an empty command */ if (!strlen(*cmd)) return -1; if (op == '|' || op == '<') *vout = vpipe; if (op == '|' || op == '>') *vin= vpipe; return 0; } /* Open pipes for stdout and stderr. * If and only if this is a '|' or '>' operation, stdout * will be distinct from stderr. * * Return 0 for success. * * If we don't succeed, make sure * we don't leave any open file descriptors. */ static int openpipes(int*out, int *err, Bool is_pipe_operation){ if (pipe(err) < 0) { diag(0, "pipe"); return -1; } if (is_pipe_operation) { if (pipe(out) < 0) { diag(0, "pipe"); close(err[0]); close(err[1]); return -1; } } else { out[0] = err[0]; out[1] = err[1]; } return 0; } /* * Parent-side accounting for a recently started external process. * * 'fderr', 'fdout' are file descriptors for stdout and stderr * 'label' is the label of the window we started in. * 'cmd' is the command being executed * 'vout', if non-null, is the View to send stdout to. * 'pid' is the process id of the child process. * * Return 0 for success. */ static int ex_parent(int fderr, int fdout, char*label, char*cmd, View *vout, int pid) { /* fderr == fdout if and only if vout == 0 */ assert( (vout==0) == (fderr == fdout)); reap(); event_outputstart(fderr, pid, cmd, label,0); if(vout) event_outputstart(fdout, pid, cmd, label, vout); return 0; } /* * Child-side accounting for a recently started external process. * * 'fderr', 'fdout' are file descriptors for stdout and stderr * 'label' is the label of the window we started in. * 'cmd' is the command being executed * 'vin', if non-null, is the View to get stdin from. * * Does not return. * Don't use normal diag stuff -- we're a separate process. * After we've set up stderr, just fprintf(stderr,...) */ static void ex_child(int fderr, int fdout, char *label, char *cmd, View *vin) { Path dir; Path path; childfds(fderr, fdout, vin); /* become process group leader */ if(setsid()<0) perror("setsid"); label2path(path, label); strcpy(dir,path); dirnametrunc(dir); /* Executing the command without being in the right directory * would be _bad_. */ if(chdir(dir)){ Path buf; sprintf(buf, "chdir(%s)", dir); perror(buf); exit(1); } childenv(label, path); history(cmd); execl(shell, shell, "-c", cmd, 0); perror(shell); exit(1); } /* Record 'cmd' in the history file */ static void history(char *cmd) { FILE *fp; if(!historyfile) return; fp = fopen(historyfile, "a"); fprintf(fp,"%s\n", cmd); fclose(fp); } /* Add some stuff to the environment of our child */ static void childenv(char *label,char*path) { Path buf; sprintf(buf, "WILYLABEL=%s", label); (void)putenv(strdup(buf)); sprintf(buf, "WILYPATH=%s", path); (void)putenv(strdup(buf)); sprintf(buf, "w=%s", path); (void)putenv(strdup(buf)); } /* * Set up default file descriptors for a child process. * * Replace 'stderr' and 'stdout' with 'fderr' and 'fdout'. * * If 'vin' is not null, replace 'stdin' with a file descriptor * that will give the contents of the selection in 'vin', * otherwise, 'stdin' is set to '/dev/null'. */ static void childfds(int fderr, int fdout, View *vin) { int j; int fdin; /* redirect fdout and fderr */ if (dup2(fderr, 2) < 0 || dup2(fdout, 1) < 0) { perror("dup2"); exit(1); } if (vin) { /* fd open to read current selection */ fdin = text_fd(view_text(vin), view_getsel(vin)); if(fdin<0) exit(1); } else if ((fdin = open("/dev/null", O_RDONLY, 0)) < 0) { perror("open /dev/null"); fdin = 0; } if (fdin) { if (dup2(fdin, 0) < 0) { perror("input dup2"); fdin = 0; } } if (!fdin) { /* no need to panic... */ if (close(0) < 0) { /* OK, panic. */ perror("close fdin"); exit(1); } } /* Don't inherit any other open fds */ for(j=3; j 0 ) ; } /* Prepare to catch some signals */ static void signal_init(void) { /* in case external process exits */ signal(SIGPIPE, SIG_IGN); signal(SIGHUP, cleanup_and_die); signal(SIGINT, cleanup_and_die); signal(SIGTERM, cleanup_and_die); signal(SIGSEGV, cleanup_and_abort); /* signal(SIGSYS, cleanup_and_abort); */ signal(SIGILL, cleanup_and_abort); } /* Start listening to fifo in well-known location */ static void well_known_init(void) { int fd; if((fd = wilyfifolisten())<0) { diag(0, "couldn't open fifo"); } else { event_wellknown(fd); } } wily-0.13.42/wily/mouse.c000064402366570000012000000106351033320152300147610ustar00ozstaff00004330000002/******************************************* * Handle mouse actions *******************************************/ #include "wily.h" #include "view.h" #include static void b2 (View *, Range, Bool); static void dobutton (View *, Mouse *); static void doscroll (View *, Mouse *); static void action (View *, Mouse *, Range, ulong); /* PRE: a mouse button is down * POST: no mouse buttons down, we've probably done something. */ void domouse(View *v, Mouse *m) { assert(m->buttons); if ( POINTINSCROLL(m->xy, v) ) { if(v->scroll) doscroll(v,m); else dobutton(v, m); } else { ulong oldbuttons = m->buttons; Range r = vselect(v, m); action(v, m, r, oldbuttons); } } /****************************************************** static functions ******************************************************/ static void dobutton(View *v, Mouse *orig) { Mouse m; Tile *tile = view_tile(v); assert(ISTAG(v)); assert(orig->buttons); if(tile == wily) /* can't move the main window this way */ return; /* swap cursor, follow mouse until button state changes */ cursorswitch(&boxcursor); do { m = emouse(); } while(m.buttons == orig->buttons); cursorswitch(cursor); /* aborted by pressing a different button? */ if(m.buttons) return; if (distance(m.xy, orig->xy) < SMALLDISTANCE) { tile_grow(tile, orig->buttons); cursorset(buttonpos(tile)); } else tile_move(tile, m.xy); } /* * Some builtins should always be applied to the window where * you clicked button 2. * * BUG: Doesn't check for leading whitespace which *is* removed in run(). */ static char *locals[] = {"Look", "Put", "Get", "Undo", "Redo", 0}; static Bool islocal(char *s) { char **ptr; for (ptr =locals; *ptr; ptr++) if (!strncmp(s, *ptr, strlen(*ptr))) return true; return false; } /* clicked button 2 in 'v' selecting 'r'. 'ischord' is true * if we also clicked button 1. */ static void b2(View *v, Range r, Bool ischord) { char *cmd,*arg; View *ls = last_selection; r = view_expand(v, r, notcommand); if(!RLEN(r)) return; cmd = text_duputf(v->t, r); if(ischord && ls && RLEN(ls->sel) < 200) { Range rarg; rarg = view_expand(ls, ls->sel, notfilename); arg = text_duputf(ls->t, rarg); /* use arg for context-- with some exceptions */ if(!islocal(cmd)) v = ls; } else arg = 0; if (!data_sendexec(view_data(v),cmd, arg)) run(v, cmd, arg); free(cmd); if(arg) free(arg); } /* * Currently mouse is like 'm', originally we had 'oldbuttons'. When * we're finished, v's display should be correct, and no mouse buttons * should be down. */ static void action(View *v, Mouse *m, Range r, ulong oldbuttons) { /* mouse button state has changed, possibly do something */ assert(m->buttons != oldbuttons); if (oldbuttons&LEFT) { enum {Cancut = 1, Canpaste = 2} state = Cancut | Canpaste; while(m->buttons) { if(m->buttons&MIDDLE) { if (state&Cancut) { view_cut(v, v->sel); state = Canpaste; } } else if ( m->buttons&RIGHT) { if (state&Canpaste) { view_paste(v); state = Cancut; } } *m = emouse(); } } else if (oldbuttons & MIDDLE) { if(m->buttons) { if(m->buttons&LEFT) /* chord */ b2(v,r,true); while (m->buttons) /* wait for button up */ *m = emouse(); } else { b2(v,r,false); } } else { assert((oldbuttons&RIGHT)); if(m->buttons) /* cancelled a b3 */ while (m->buttons) *m = emouse(); else b3(v, r); } } /* PRE: 'e' a mouse event in 'v', but not in v's frame, so probably in * the scrollbar. 'v' is a body frame. * POST: we've tracked the mouse until all the buttons are down, * and have scrolled if we should have. */ static void doscroll(View *v, Mouse *m ) { ulong buttons; ulong timer; ulong type; int delay = DOUBLECLICK / SCROLLTIME; Bool firstmouse; Event e; assert(ptinrect(m->xy, v->r)); assert(v->scroll); buttons = m->buttons; assert(buttons); type = Emouse; firstmouse = true; e.mouse = *m; m = &e.mouse; /* start waiting for timer events */ timer = etimer(0, SCROLLTIME); do { assert(type== timer || type == Emouse); if(type==Emouse) { if (firstmouse) { firstmouse = false; view_scroll(v, m); } } else { if(delay) delay--; else view_scroll(v, m); } type = eread(Emouse|timer,&e); } while (!(type ==Emouse && m->buttons != buttons)); estoptimer(timer); /* stop the timer */ /* wait for buttons up */ while (m->buttons) eread(Emouse, &e); } ssert(ISTAG(v)); assert(orig->buttons); if(tile == wily) /* can't move the main window this waywily-0.13.42/wily/Makefile.in000064402366570000012000000030761033320152300155330ustar00ozstaff00004330000002SHELL=/bin/sh srcdir=@srcdir@ VPATH=@srcdir@ prefix = @prefix@ LIBS=@LIBS@ exec_prefix = @exec_prefix@ # Directory in which to install scripts. bindir = $(exec_prefix)/bin CC=@CC@ RANLIB=@RANLIB@ INCLUDES= -I.. -I$(srcdir)/../include @X_CFLAGS@ OPTS=-DNDEBUG CFLAGS= @CFLAGS@ $(OPTS) $(INCLUDES) TARGET=wily OBJECTS= env.o include.o label.o file.o msg.o data.o line.o\ vgeom.o vsearch.o vshow.o \ tagmatch.o place.o event.o exec.o dir.o \ point.o global.o cursor.o scroll.o path.o keyboard.o \ wily.o tag.o view.o grow.o adjust.o win.o list.o col.o\ undo.o builtins.o util.o select.o\ mouse.o regexp.o text2.o \ sam.o text.o click.o tile.o search.o MYLIBS=../libmsg/libmsg.a ../libframe/libframe.a ../libXg/libXg.a XLIBS=$(LIBS) @X_LIBS@ -lXt @X_PRE_LIBS@ -lX11 @X_EXTRA_LIBS@ all: $(TARGET) $(TARGET): $(OBJECTS) $(MYLIBS) $(CC) $(LDFLAGS) -o $(TARGET) $(OBJECTS) $(MYLIBS) $(XLIBS) pure: $(OBJECTS) $(MYLIBS) purify $(CC) $(LDFLAGS) -o $(TARGET) $(OBJECTS) $(MYLIBS) $(XLIBS) $(OBJECTS): wily.h const.h proto.h ../include/msg.h builtins.o keyboard.o mouse.o tag.o text.o text2.o tile.o view.o: view.h keyboard.o search.o tag.o text.o text2.o undo.o view.o line.o click.o : text.h tile.o grow.o adjust.o win.o col.o list.o: tile.h point.o: tile.h view.h sam.o regexp.o: sam.h file.o msg.o data.o label.o : data.h adjust.o builtins.o keyboard.o mouse.o point.o select.o tag.o text2.o tile.o vgeom.o view.o vsearch.o vshow.o : view.h clean: rm -f *.o core *pure* nuke: clean rm -f $(TARGET) dist: nuke cp -r `ls |grep -v RCS` ../dist/wily install: $(TARGET) cp $(TARGET) $(bindir) wily-0.13.42/wily/grow.c000064402366570000012000000037031033320152300146050ustar00ozstaff00004330000002/******************************************* * grow tiles by different amounts *******************************************/ #include "tile.h" /************************************************************ Tile growth functions: Modify tile->min, tile->max, possibly min and max for tile's siblings. After these functions, every visible tile will have the _size_ which we want, but the tiles may not abutt, and may not fit into tile->up. We rely on list_reshaped to tidy these things up. ************************************************************/ /* grow tile a little */ static void gsome(Tile*tile) { tile->min -= tile->base*2; tile->max += tile->base*2; } /* grow tile lots */ static void gmost(Tile*tile) { Tile *t, *up = tile->up; int space = 0; /* space either above or below 'tile' */ for (t = up->down; t; t=t->right) { if (t != tile) { space += t->base; t->max = t->min + t->base; } else { t->min = space + up->cmin; space = 0; /* start counting space _above_ tile */ } } tile->max = up->cmax - space; } /* grow tile way lots */ static void gall(Tile *tile) { Tile *t, *up = tile->up; for (t = up->down; t; t=t->right) { if (t != tile) t->ishidden = true; } tile->min = up->cmin; tile->max = up->cmax; } /************************************************************ End of Tile growth functions: ************************************************************/ /* Grow 'tile' by some amount */ void tile_grow(Tile *tile, int buttons) { assert(list_invariant(tile->up)); list_unhide(tile->up); /* Adjust the placement of tile, and possibly tile's siblings. Don't worry too much about placing them. Relies on list_reshaped to do the placement and redisplay. */ switch (buttons) { case 1: gsome(tile); break; case 2: gmost(tile); break; case 4: gall(tile); break; default: gsome(tile); break; } list_reshaped(tile->up, tile); assert(list_invariant(tile->up)); } wily-0.13.42/wily/search.c000064402366570000012000000110741033320152300150740ustar00ozstaff00004330000002/******************************************* * Search in text *******************************************/ #include "wily.h" #include "text.h" static char *endword = "[^a-zA-Z0-9][^a-zA-Z0-9:.$|]*"; static char *startword = "[^a-zA-Z0-9]"; static char *special = ".*+?(|)\\[]^$"; static Bool findend(Text *t, Range *r, char *addr, Range dot); static Rstring word(Rstring s); static Rstring literal(Rstring s); static void strip_re_slash(char *re); /* Look for the text in 'dot'. * If found, set '*r' and return true, * otherwise return false. */ Bool text_look(Text*t, Range *r, Range dot) { RPath buf; ulong len; assert(!text_badrange(t,dot)); len = RLEN(dot); /* don't try to search for HUGE dot */ if( len > MAXPATH) return false; text_copy(t, dot, buf); return text_findliteral(t, r, rstring(buf, buf + len)); } Bool text_findliteralutf(Text*t, Range *r, char*lit) { Rstring s; Bool found; s = utf2rstring(lit); /* r->p0 = r->p1; */ found = text_findliteral(t, r, s); free(s.r0); return found; } Bool text_findwordutf(Text*t, Range *r, char*lit) { Rstring s; Bool found; s = utf2rstring(lit); found = text_findword(t, r, s); free(s.r0); return found; } /* * If we can find 's' in 't' (start looking at 'r'), return true and * set 'r' to the location of the start of the string. Otherwise, * return false. */ Bool text_findliteral(Text *t, Range *r, Rstring s) { Rstring s2; Bool found; s2 = literal(s); found = text_regexp(t, s2, r, 1); RSFREE(s2); return found; } Bool text_findword(Text *t, Range *r, Rstring s) { Rstring s2; Bool found; s2 = word(s); found = text_regexp(t, s2, r, 1); RSFREE(s2); r->p0++; return found; } /* If we can find 'addr', preferably someplace just after 'r', * set 'r' to the range we found, and return true, otherwise return false. * 'addr' may be any Sam-style address. */ Bool text_search(Text *t, Range *r, char *addr, Range dot) { char *addr2; assert(addr); /* * Find the second addr in the pair. Some complexity here: * (1) If the first addr is a regexp, must first find its end -- but watch * out for escaped "/"'s. * (2) Otherwise, just find the first comma. */ if (*(addr2=addr) == '-') addr2++; if (*addr2++ == '/') { /* find an unescaped "/" */ while ((addr2 = strchr(addr2, '/')) && addr2[-1] == '\\') addr2++; /* check to see that it's followed by a comma */ if (addr2 && *++addr2 != ',') addr2 = 0; } else addr2 = strchr(addr, ','); if (addr2) *addr2++ = '\0'; if (*addr == '\0') { r->p0 = 0; } else if (!findend(t, r, addr, dot)) { return false; } if (addr2) { Range range2 = *r; if (*addr2 == '\0') r->p1 = t->length; else if (!findend(t, &range2, addr2, dot)) return false; else if ( range2.p1 < r->p0) return false; else r->p1 = range2.p1; } return true; } /* * Used to find one "end" of an addr (which might be the whole addr, but * never mind). The address passed in here is not expected to contain * commas. */ static Bool findend(Text *t, Range *r, char *addr, Range dot) { if(!strchr("/-#$.0123456789", *addr)) return false; switch(*addr){ case '/': strip_re_slash(addr); return text_utfregexp(t, addr+1, r, true); case '-': if(addr[1] != '/') return false; strip_re_slash(addr); return text_utfregexp(t, addr+2, r, 0); case '#': r->p0 = r->p1 = atol(addr + 1); return r->p0 <= t->length; case '$': if(addr[1] != '\0') return false; *r = text_lastline(t); return true; case '.': if(addr[1] != '\0') return false; *r = dot; return true; default: return text_findline(t, r, atol(addr)); } } /* * Strip trailing slash from a regexp, if present and not escaped. * WARNING: This code can reference the character * immediately preceding its argument, so use with care. */ static void strip_re_slash(char *re) { if ((re = strrchr(re, '/')) && re[1] == '\0' && re[-1] != '\\') re[0] = '\0'; } static Rstring literal(Rstring s) { Rstring s2; Rune *r; /* quote any special characters in 's' */ s2.r0 = s2.r1 = (Rune*)salloc(RSLEN(s)*2*sizeof(Rune)); for (r = s.r0; r < s.r1; r++){ if(utfrune(special, *r)) *s2.r1++ = '\\'; *s2.r1++ = *r; } return s2; } static Rstring word(Rstring s) { Rstring s2; Rune *r; int nrunes; nrunes = RSLEN(s)*2 +strlen(startword) + strlen(endword); s2.r0 = s2.r1 = (Rune*)salloc(nrunes*sizeof(Rune)); s2.r1 += utftotext(s2.r1, startword, startword + strlen(startword)); for (r = s.r0; r < s.r1; r++){ if(utfrune(special, *r)) *s2.r1++ = '\\'; *s2.r1++ = *r; } s2.r1 += utftotext(s2.r1, endword, endword + strlen(endword)); return s2; } ) { Rstring s; Bool found; s = utf2rstring(lit); found = text_findword(t, r, s); free(s.r0); return found; } /* * If we can find 's' in 't' (start looking at 'r'), return true and * set 'r' to the location of the start of the string. Otherwise, * return false. */ Bool text_findliteral(Text *t, Range *r, Rstring s) { Rstring s2; Bool found; s2 = literal(s); found = text_regexp(t, s2, r, 1); RSFREE(s2); return found; } Bool twily-0.13.42/wily/tagmatch.c000064402366570000012000000050071033320152300154160ustar00ozstaff00004330000002/******************************************* * Maintain and query (regexp, tag tools) pairs *******************************************/ #include "wily.h" #include #include #include #include #include #include typedef struct Pair Pair; struct Pair { char* regex; char* tools; }; static Pair* pair; static int npairs = 0; static int maxpairs = 0; static Bool match(char *regex, char *s) { /* Make a dummy text file, search in that */ static Text *t=0; Range r; Bool retval; if(!t) t = text_alloc(0, false); r = nr; text_replaceutf(t, text_all(t), s); text_replaceutf(t, range(text_length(t),text_length(t)), "\n"); retval = text_utfregexp(t, regex, &r, true); return retval; } static void addpair(char *regex, char* tools) { Pair p; char *nl; p.regex = regex; p.tools = tools; if ((nl = strchr(p.tools, '\n'))) { *nl = 0; } if(npairs == maxpairs) { maxpairs = maxpairs? maxpairs*2 : maxpairs + 10; pair = (Pair*) srealloc(pair, maxpairs * sizeof(Pair)); } pair[npairs++] = p; } char* tag_match(char*label) { int j; static Bool inprogress; if(inprogress) { j= npairs; } else { inprogress = true; for(j=0; j0) { nread = read(fd, buf, size); if(nread <= 0) { perror(filename); free(buf); return 0; } size -= nread; } close(fd); return buf; } /* * Read 'filename', initialize 'pair' and 'npairs'. * 'filename' is made up of lines, each of which may * be blank, a comment (starts with '#'), or a pattern * toolset pair (separated by tabs) */ void tag_init(char *filename) { char *buf, *ptr, *tab; if(!(buf=readfile(filename))) return; for(ptr = strtok(buf, "\n"); ptr; ptr = strtok(0, "\n")) { /* comment or blank line */ if (ptr[0] == '#' || isspace(ptr[0])) continue; if((tab = strchr(ptr, '\t'))) { *tab++ = 0; /* strip leading whitespace */ tab += strspn(tab, whitespace); addpair(ptr, tab); } else { addpair(ptr, ""); } } /* don't free(buf) - keep the memory in the array of strings */ } wily-0.13.42/wily/include.c000064402366570000012000000036101033320152300152470ustar00ozstaff00004330000002/******************************************* * Expand b3-clicks to "include" files, e.g. *******************************************/ #include "wily.h" static char * pathfind (const char *paths, const char *file); static Bool is_includebrackets(char left, char right); /* * The user has selected 'r' in 'v'. * If possible, open an appropriate include file, return a View * representing its body. * * If no include file is appropriate, return 0. */ View* openinclude(View *v, Range r) { Range expanded; Path buf, pbuf; int len; Text *t; char *s; t = view_text(v); expanded = text_expand(t, r, notinclude); len = RLEN(expanded); if( len > (MAXPATH*UTFmax) || len < 2) return false; len = text_copyutf(t, expanded, buf); if (!is_includebrackets(buf[0], buf[len-1])) return false; buf[len-1] = 0; s = pathfind(getenv("INCLUDES"), buf+1); if(!s) { sprintf(pbuf, "/usr/include/%s", buf+1); s = pbuf; } return openlabel(s, false); } /********************************************************** static functions **********************************************************/ static Bool is_includebrackets(char left, char right) { return (left == '"' && right == '"') || (left == '<' && right == '>'); } static const char * nextstr (const char *p, const char *c, int *n){ int i; if (!p || !*p) return 0; *n = i = strcspn (p, c); /* XXX - utf */ if (p[i]) i += 1; /* strspn (p+i, c); ? */ return p+i; } static char * pathfind (const char *paths, const char *file) { const char *p,*ptmp; int flen; int plen; if (!paths || !file) return 0; flen = strlen(file); p = paths; while((ptmp = nextstr(p, ":", &plen))!= 0) { int fd; char *tmp = malloc(plen+1+flen+1); if (tmp) { sprintf(tmp, "%.*s/%s", plen, p, file); if ((fd = open(tmp, 0)) < 0) { free(tmp); } else { close(fd); return tmp; } } p = ptmp; } return 0; } wily-0.13.42/wily/line.c000064402366570000012000000044171033320152300145610ustar00ozstaff00004330000002/*********************************************************** * Functions to do with finding/counting lines. * * Currently Wily doesn't keep track of line boundaries, * and searches for them when it needs to. These functions * are all in the one file in case we ever decide to cache any * of this information. ***********************************************************/ #include "wily.h" #include "text.h" /* What line number is at Rune position p? */ int text_linenumber(Text *t, ulong p) { int c; int newlines=1; Tbgetcset(t, p); while ( (c=Tbgetc(t)) != -1) if( c == NEWLINE) newlines++; return newlines; } /* * If 't' has at least 'n' lines, fills 'r' with the range for line 'n', * and returns true. Otherwise, fills 'r' with gibberish and returns * false. */ Bool text_findline(Text *t, Range *r, ulong n) { Bool foundstart = false; int c; if (n==0) return false; else if (n==1) { foundstart = true; r->p0 = 0; } n--; Tgetcset(t,0); for( ; (c=Tgetc(t)) != -1; ) { if( c == NEWLINE ) { if (foundstart) break; else if (!--n) { r->p0 = t->pos; foundstart = true; } } } r->p1 = t->pos; return foundstart; } /* Return the range for the last line of 't' */ Range text_lastline(Text *t) { int c; Tbgetcset(t, t->length); while ( (c=Tbgetc(t)) != -1 && c != NEWLINE) ; return range(t->pos+1, t->length); } /* * Find the offset of the first character of the line 'delta' away from 'pos'. *'delta' may be positive or negative. * * text_nl(t, pos, 0): start of current line * text_nl(t, pos, -1): start of line above * text_nl(t, pos, 1): start of line below */ ulong text_nl(Text *t, ulong pos, int delta) { int c; ulong retval; assert(pos <= t->length); if(delta > 0) { Tgetcset(t, pos); while ( (c=Tgetc(t)) != -1 ) if(c==NEWLINE) if(!--delta) break; retval = (c != -1) ? t->pos : t->length; } else { Tbgetcset(t,pos); while ( (c=Tbgetc(t)) != -1 ) if(c==NEWLINE) if(!delta++) break; retval = (c != -1) ? t->pos+1 : 0; } return retval; } /* Return the position of the first character of the line containing 'p' */ ulong text_startOfLine(Text *t, ulong p) { int c; Tbgetcset(t,p); do { c=Tbgetc(t); } while ( c != -1 && c != NEWLINE); return (c != -1) ? t->pos+1 : t->pos; } r decide to cache any * of this information. ***********************************************************/ #include "wily.h" #include "text.h" /* What line number is at Rune position p? */ int text_linenumber(Text *t, ulong p) { int c; wily-0.13.42/wily/list.c000064402366570000012000000045771033320152300146140ustar00ozstaff00004330000002/******************************************* * Simple operations to apply to every visible tile in a list. *******************************************/ #include "tile.h" /******************************************************** Simple operations to apply to every visible tile in a list. ********************************************************/ Bool list_oksizes(Tile*list) { Tile*t; FOR_EACH_VISIBLE(list->down,0){ assert(TILESIZE(t) >= t->base); } return true; } void list_unhide(Tile*list) { Tile*t; FOR_EACH_TILE(list->down,0) { t->ishidden = false; if ( TILESIZE(t) < t->base) t->max = t->min + t->base; } } /* Slide the visible children of 't' along so that they abut one another */ void list_slide(Tile *t) { int prev = t->cmin; FOR_EACH_VISIBLE(t->down, 0) { moveto(t, prev); prev = t->max; } } /* Return the biggest visible child in the (half-open) range */ Tile* biggest_visible(Tile*start, Tile*end) { Tile *t, *big = 0; FOR_EACH_VISIBLE(start, end) { if (!big || TILESIZE(t) > TILESIZE(big)) big =t; } return big; } /* Return the last child with a visible body in the (half-open) range */ Tile* last_visible_body(Tile*start, Tile*end) { Tile *t, *last=0; FOR_EACH_VISIBLE(start, end) { if(TILESIZE(t) > t->base) last =t; } return last; } /* Return the last visible child in the (half-open) range */ Tile* last_visible(Tile*start, Tile*end) { Tile *t, *last=0; FOR_EACH_VISIBLE(start, end) { last = t; } return last; } /* The total size of the visible tiles in the (half-open) range. */ int list_size(Tile *start, Tile *end) { int size=0; Tile *t; FOR_EACH_VISIBLE(start, end) { size += TILESIZE(t); } return size; } /* Sum the base sizes of the tiles in the (half-open) range. */ int list_basesize(Tile*start, Tile*end) { int size=0; Tile *t; FOR_EACH_VISIBLE(start, end) { size += t->base; } return size; } /* Find the child of 'parent' which contains position 'n' */ Tile* list_find(Tile*parent, int n) { Tile *t; FOR_EACH_VISIBLE(parent->down, 0) { if (n < t->max && n >= t->min) break; } return t; } /* Return the next visible tile after 't' */ Tile* next_visible(Tile*t) { FOR_EACH_VISIBLE(t->right, 0) { break; } return t; } /* Return the next visible tile after 't' */ Bool list_contains(Tile*start, Tile*end, Tile *want) { Tile*t; FOR_EACH_VISIBLE(start,end) { if(t==want) return true; } return false; } wily-0.13.42/wily/path.c000064402366570000012000000042451033320152300145650ustar00ozstaff00004330000002/******************************************* * Expand abbreviations for pathnames *******************************************/ #include "wily.h" #include static char* gettilde(const char*s); /* * Expand 'orig' into 'dest', using 'expansion'. * Expansion must take a char*, and return a static char*, * i.e. one we don't have to free (and can't keep). */ static void expand(char*dest, char*orig, char*(*expansion)(const char*)){ Path key; char *val; char *slash; assert(orig[0]=='$' || orig[0]=='~'); strcpy(key,orig+1); if( (slash=strchr(key,'/')) ) { *slash = 0; } val = (*expansion)(key); if(slash) *slash = '/'; if(val){ sprintf(dest, "%s%s", val, slash? slash: ""); } else { strcpy(dest, orig); } } /* Convert a 'label' to a 'path'. Paths are always absolute. */ void label2path(char*path, char*label) { if(!label){ strcpy(path,wilydir); return; } switch(label[0]) { case '$': expand(path, label, getenv); break; case '~': expand(path, label, gettilde); break; case '/': strcpy(path, label); break; default: sprintf(path, "%s%s", wilydir, label); break; } labelclean(path); } /********************************************************* static functions *********************************************************/ /* Clean up 'label' by removing components with '.' or '..' */ void labelclean(char*label) { char *slash, *from, *to, c; char *back; slash = strchr(label,'/'); if(slash) { from = to = slash+1; } else { return; } while (from[0] != '\0') { assert(to[-1] == '/'); switch(from[0]){ case '/': /* ignore "//" */ from++; continue; case '.': switch(from[1]){ case '\0': case '/': /* Ignore "./" */ from++; continue; case '.': if (from[2] == '\0' || from[2] == '/') { from += 2; to[-1] = '\0'; back = strrchr(label, '/'); if(back){ to = back+1; } else { to[-1] ='/'; } continue; } } default: do { c = (*to++ = *from++); } while (c != '\0' && c != '/'); from--; } } *to='\0'; } static char* gettilde(const char*s) { struct passwd *pw; pw = strlen(s) ? getpwnam(s) : getpwuid(getuid()); return pw ? pw->pw_dir : 0; } wily-0.13.42/wily/select.c000064402366570000012000000143031033320152300151040ustar00ozstaff00004330000002/******************************************* * drag out a selection, scrolling as you go *******************************************/ #include "wily.h" #include "view.h" #include "text.h" static void frselectf2(Frame *f, Point p0, Point p1, Fcode c); static void dclick(View *, ulong, ulong *, ulong *); typedef void (*SelFn)(Frame*, Point, Point, Fcode); #define BASE(v) ((v)->visible.p0) /* Return a-b, or 0 */ static ulong usub (ulong a, ulong b) { return a>b? a-b : 0; } /* PRE: 'v' shows the region [p0,p1] selected with 'fn' * POST: 'v' shows the region [p0, q] selected with 'fn' */ static void update(View *v, SelFn fn, ulong p0, ulong p1, ulong q) { Frame *f = &v->f; Point pt0, pt1, qt; pt0 = frptofchar(f, usub(p0, BASE(v))); pt1 = frptofchar(f, usub(p1, BASE(v))); qt = frptofchar(f, usub(q, BASE(v))); if(p0 == p1) (*fn)(f, pt0, pt1, F&~D); if(p1 < q) (*fn)(f, pt1, qt, F&~D); else (*fn)(f, qt, pt1, F&~D); if(p0 == q) (*fn)(f, pt0, qt, F&~D); } /* Toggle the region p0,p1 in 'v' with 'fn' */ static void toggle(View *v, SelFn fn, ulong p0, ulong p1) { Frame *f = &v->f; Point pt0,pt1; pt0 = frptofchar(f, usub(MIN(p0,p1), BASE(v))); pt1 = frptofchar(f, usub(MAX(p0,p1), BASE(v))); (*fn)(f, pt0, pt1, F&~D); } /* PRE: The region [p0,p1] in 'v' is indicated with 'fn' * POST: We've scrolled towards 'pt', but the region is still indicated. */ static void move(View *v, SelFn fn, Point pt, ulong p0, ulong p1) { Rectangle r = v->f.r; assert(!ptinrect(pt, r)); /* If we moved off the left or right edge of a view with a * scrollbar, or if we're trying to scroll past the top or bottom * of the text, don't do anything. This avoids a flicker. It also * avoids scrolling down when the bottom of the text is already * visible. * * The "right" way to fix the flickering * may be to fix the selection so we don't * have to turn it off, then back on. This would avoid a * flicker while scrolling as well. I'm not entirely sure * why we need toggle(). * * If the flickering is fixed, we will still need to check that * we aren't scrolling down unnecessarily when the bottom of * the text is visible. That check can appear in a more * appropriate context, however. */ if (v->scroll && ((pt.y >= r.min.y && pt.y <= r.max.y) || (pt.y < r.min.y && v->visible.p0 == 0) || (pt.y > r.max.y && v->visible.p1 == view_text(v)->length))) return; toggle(v,fn,p0,p1); v->f.p0 = v->f.p1 = 0; if (v->scroll) { if (pt.y < r.min.y) view_linesdown(v, 2, false); else if (pt.y > r.max.y) view_linesdown(v, 2, true); } else { if (pt.x < r.min.x) view_hscroll(v, true); else if (pt.x > r.max.x) view_hscroll(v, false); } toggle(v,fn,p0,p1); } /* PRE: nothing is selected in 'v', our initial desired selection is [p0,p1] * POST: 'v' indicates a selection (using Selfn 'fn'), we return the selected * range. */ static Range follow(View *v, ulong oldq, ulong p0, ulong p1, Bool selecting, Mouse *m) { ulong buttons = m->buttons; Frame *f = &v->f; ulong q; Event e; ulong type, timer=0; SelFn fn; fn = selecting? frselectf : frselectf2; toggle(v, fn, p0, p1); v->selecting = true; *m= emouse(); type = 0; while(m->buttons == buttons){ q = frcharofpt(f, m->xy) +v->visible.p0; /* We only autoscroll while affecting the selection, not for b2 or b3 */ if (selecting) { /* We want the timer going iff we're outside the rectangle */ if (ptinrect(m->xy, f->r)) { if (timer){ estoptimer(timer); timer=0; } } else { /* We do a move on timer events, or the first mouse event */ if(timer == type || timer == 0) move(v, fn, m->xy, p0, p1); if (timer==0) timer = etimer(0, SCROLLTIME); } } if(q != oldq && p1 != q){ update(v, fn, p0, p1, q); oldq = p1 = q; } if((type = eread(Emouse|timer,&e))==Emouse) *m= e.mouse; } v->selecting = false; if(timer) estoptimer(timer); return maybereverserange(p0,p1); } /* Drag out a selection, starting with 'm' (mouse down), * until the mouse buttons change. Return the selected range. */ Range vselect(View *v, Mouse *m) { Frame *f = &v->f; Bool selecting; /* affects selection */ ulong orig, p0, p1; Range sel; orig = p0 = p1 = frcharofpt(f, m->xy) + BASE(v); selecting = m->buttons&LEFT; if (selecting) { frselectp(f, F&~D); /*remove old highlighted bit */ view_setlastselection(v); dclick(v, m->msec, &p0, &p1); } sel = follow(v, orig, p0, p1, selecting, m); if(selecting) { v->sel = sel; v->anchor = sel.p1; f->p0 = pclipr(sel.p0, v->visible) - BASE(v); f->p1 = pclipr(sel.p1, v->visible) - BASE(v); } else { frselectf2(f, frptofchar(f, sel.p0 -BASE(v) ), frptofchar(f, sel.p1 -BASE(v)), F&~D); } assert(view_invariants(v)); return sel; } /* it is assumed p0<=p1 and both were generated by frptofchar() */ static void frselectf2(Frame *f, Point p0, Point p1, Fcode c) { int n; int ht; if(p0.x == f->left) p0.x = f->r.min.x; if(p1.x == f->left) p1.x = f->r.min.x; ht = f->font->height; n = (p1.y-p0.y)/ht; /* p0.y += ht - 1; p1.y = p0.y + 1; */ p1.y = p0.y + ht; /* p0.y = (p0.y + p1.y) >> 1; */ p0.y = p1.y - 2; if(f->b == 0) berror("frselect2 b==0"); if(p0.y == f->r.max.y) return; if(n == 0){ if(p0.x == p1.x) if(p0.x == f->r.min.x) p1.x++; else p0.x--; bitblt(f->b, p0, f->b, Rpt(p0, p1), c); /* bitblt(f->b, p0, f->d, Rpt(p0, p1), c); */ }else{ if(p0.x >= f->r.max.x) p0.x = f->r.max.x-1; bitblt(f->b, p0, f->b, Rect(p0.x, p0.y, f->r.max.x, p1.y), c); while (--n > 0) { p0.y += ht; p1.y += ht; bitblt(f->b, Pt(f->r.min.x, p0.y), f->b, Rect(f->r.min.x, p0.y, f->r.max.x, p1.y), c); } p0.y += ht; p1.y += ht; bitblt(f->b, Pt(f->r.min.x, p0.y), f->b, Rect(f->r.min.x, p0.y, p1.x, p1.y), c); } } /* Check for double-click. If 'click' happened not long after 'lastclick', * set '*p0' and '*p1' appropriately. Update 'lastclick'. */ static void dclick(View *v, ulong click, ulong *p0, ulong *p1) { Range sel; static ulong lastclick; /* check for double click */ if( (v->sel.p0 == *p0 ) && (click < lastclick + DOUBLECLICK )) { sel = text_doubleclick(v->t, *p0); *p0 = sel.p0; *p1 = sel.p1; lastclick = 0; } else { lastclick = click; } } wily-0.13.42/wily/adjust.c000064402366570000012000000057011033320152300151210ustar00ozstaff00004330000002/***************************************************************** Collection of functions to reduce the size of a tile. Each reduces the tile's size, and return the amount of savings. They appear in order of severity. *****************************************************************/ #include "tile.h" /* If t's body contains any blank lines, get rid of them */ static int stripwhitespace(Tile *t, int excess) { int saving,size; if (!t->body ) return 0; size = TILESIZE(t); /* Possibly we've already mangled this tile, so it can no longer * properly contain its body and tag */ if(size < view_height(t->body) + view_height(t->tag)) return 0; if((saving = view_stripwhitespace(t->body))) { assert(saving < size); saving = MIN(saving, excess); t->max -= saving; assert(TILESIZE(t) >= t->base); } return saving; } /* Halve the amount by which t's size exceeds t->base */ static int halve(Tile*t, int excess) { int saving,size = TILESIZE(t); int extra = size - t->base; if(extra > 0) { saving = MIN(extra/2, excess); t->max -= saving; return size - TILESIZE(t); } return 0; } /* Shrink 't' down to t->base */ static int shrink(Tile *t, int excess) { int saving = MIN(TILESIZE(t) - t->base, excess); t->max -= saving; return saving; } /* Hide 't': => size = 0 */ static int hide(Tile *t, int excess) { assert(TILESIZE(t) == t->base); /* we've already done 'shrink' */ t->ishidden = true; return t->base; } typedef int (*SizeAdjust)(Tile*, int); SizeAdjust method [] = { stripwhitespace, halve, shrink, hide, 0 }; /***************************************************************** End of Collection of functions to reduce the size of a tile. *****************************************************************/ /* * Adjust the sizes of the tiles in [start,end) so that they add to * <= 'available'. * Return the total size. */ int adjust_sizes_in_range(Tile*start, Tile*end, int available) { Tile *t; int size,saving,excess; int now; int j; SizeAdjust m; /* method to adjust the size of a tile */ assert(available >= 0); size = list_size(start,end); for(j=0; (m=method[j]); j++) { FOR_EACH_VISIBLE(start,end){ assert(size == (now = list_size(start, end))); excess = MAX(size - available, 0); saving = (*m)(t, excess); assert(t->ishidden || (TILESIZE(t) >= t->base)); size -= saving; /* check our math */ assert(size == (now = list_size(start, end))); if (size <= available) { /* C doesn't have labelled break. So sue me. */ goto out; } } } out: /* check our math */ assert(size == (now = list_size(start, end))); assert (size <= available); /* Even if we had to hide everything */ /* If we've taken too much, return some size to the last visible tile */ if(sizemax += available - size; size = available; now = list_size(start,end); assert( size == now); } assert( size <= available); assert (size >= 0); return size; } wily-0.13.42/wily/buffer.c000064402366570000012000000051231033320152300150760ustar00ozstaff00004330000002#include "buffer.h" void buffer_delete(Buffer *b, Range r) { int removed = RLEN(r); Bnode *n = buffer_findnode(r.p0); while(n && r.p1 > n->off) n = bnode_delete(n, r); for (;n;n=n->next) n->off -= removed; } /* Delete relevant bit of 'r' from 'n', * and return next node to try. * We have to return the next node, because * we might have deleted this one before we're done. */ Bnode* bnode_delete(Bnode *n, Range r){ if(r.p0<= n->off && r.p1 >= n->next->off){ // delete the whole Bnode } } void buffer_add(Buffer *b, ulong p, Rstring s) { bnode_add(buffer_findnode(p),p, s)); } Bnode * getBnode(Bnode *prev, Bnode *next){ Bnode *n; n = (Bnode*)getchunk(); n->prev = prev; n->next = next; n->off = off; } void bnode_setgap(Bnode *n, ulong p) { assert(p>= n->off); assert (p <= n->off + bnsize(n)); p -= n->off; nmove = n->gap.p0 - p; if (nmove>0) memmove(n->buf+p+RLEN(n->gap), n->buf + p, nmove*sizeof(Rune)); else memmove (n->buf + n->gap.p0, n->buf + n->gap.p1,-nmove*sizeof(Rune)); n->gap.p1 -= nmove; n->gap.p0 = p; } /* split 'n' at p */ void bnode_split(Bnode *n, ulong p){ Node *n2; int oldsize = bnsize(n); n2 = getBnode(n, n->next); n2->next = n->next; if(n->next) n->next->prev = n2; n->next = n2; bnode_setgap(n, p); from = n->buf + n->gap.p1; nmove = (BUFFERSIZE-n->gap.p1); memmove(n2->buf, from, nmove*sizeof(Rune)); n2->gap = range(nmove, BUFFERSIZE); assert(bnsize(n) + bnsize(n2) == oldsize); } /* big addition gets its own chunk(s) */ void bnode_bigadd(Bnode *n, ulong p, Rstring s){ Bnode *head, *tail; head = tail = nil; while(RSLEN(s)){ tail = getBnode(tail, nil, p); if(!head) head = tail; int nmove = MIN(BUFFERSIZE, RSLEN(s)); memmove(tail->buf, s.r0, nmove*sizeof(Rune)); tail->gap = range(BUFFERSIZE-nmove, BUFFERSIZE); p += nmove; } // splice the newly created node(s) // in the split created in 'n' bnode_split(n, oldp); tail->next = n->next; n->next->prev = tail; n->next = head; head->prev = n; for(n=n->next; n; n=n->next) n->off += nadd; } Bnode* bnode_min(Bnode*a, Bnode*b) { return (RLEN(a->gap)>RLEN(b->gap)) ? a : b; } void bnode_add(Bnode *n, ulong p, Rstring s){ Rstring olds = s; int nadd = RSLEN(s); /* very big addition? */ if(RSLEN(s) >= BUFFERSIZE/2){ bnode_bigadd(n, p, s); return; } /* addition bigger than gap? */ if (RLEN(n->gap)next); } assert(RLEN(n->gap)>=RSLEN(s)); bnode_setgap(n, p); memmove(n->buf+n->gap.p0, s.r0, nadd*sizeof(Rune)); n->gap.p0 += nadd; for(n=n->next; n; n=n->next) n->off += nadd; } ); Bnode *n = buffer_findnode(r.p0); while(n && r.p1 > n->off) n = bnode_delete(n, r); for (;n;n=n->next) n->off -= removed; } /* Delete relevant bit of 'r' from 'n', * and return next node to try. * We have to return the next node, because * we might have deleted this one before we're done. */ Bnode* bnode_delete(Bnode *n, Range r){ if(r.p0<= n->off && r.p1 >= n->next->off){ // delete the whole Bnode } } wily-0.13.42/wily/buffer.h000064402366570000012000000003431033320152300151020ustar00ozstaff00004330000002typedef struct Bnode Bnode; typedef struct Buffer Buffer; struct Buffer { Bnode *head; }; struct Bnode { Bnode *next, *prev; ulong off; Range gap; Rune buf[BUFFERSIZE]; }; #define bnsize(n) ( BUFFERSIZE- RLEN(n->gap)) wily-0.13.42/wily/.wily.prcs_aux000064402366570000012000000002511033320152300162660ustar00ozstaff00004330000002;; This file is automatically generated, editing may cause PRCS to do ;; REALLY bad things. (Created-By-Prcs-Version 1 2 0) (wily/text.h 1487 862661653 d/23_text.h 1.3) wily-0.13.42/wily/text.c000064402366570000012000000147351033320152300146220ustar00ozstaff00004330000002/* We use a simple buffer-gap. This is not too good for working * with large files if we're simultaneously working at both ends of * the file, because everytime we make a change, we have to move * the gap to the position of the change. * * If we wanted to handle large files efficiently we should * probably use multiple gaps, or multiple separate buffers. * What we have is probably sufficient for most cases, though. * * If we wanted to worry about our memory footprint, instead * of keeping the whole file in memory as Runes, we could copy * it to a (or many) auxiliary files and convert to Runes on demand. * This would also help with latency of opening big files. It would * also be much more complex. Virtual memory is our friend. */ #include "wily.h" #include "text.h" #include static void setgap(Text *t, ulong p, int n); #ifndef NDEBUG static Rune * findnull(Rune*start, Rune*end) { Rune *p; for(p=start; pgap.p1 >= t->gap.p0); assert(t->gap.p1 <= t->alloced); assert(t->length <= t->alloced); assert(!(p=findnull(t->text, t->text + t->gap.p0))); assert(!(p=findnull(t->text + t->gap.p1, t->text + t->alloced))); assert( TEXT_ISTAG(t) || t->data); /* if we're not a tag, we have data */ #endif return true; } /* Read the contents of 't' from 'fd', which should have 'len' bytes. * Return 0 for success, -1 for failure */ int text_read(Text *t, int fd, int len) { int desired, nread; char buf[BUFFERSIZE]; extern int utftotext_unconverted; int offset, end, stop; /* Ensure we have enough rune space. Do it one * block to avoid fragmentation */ desired = len + GAPSIZE; if (t->alloced < desired) { t->alloced = desired; free(t->text); t->text = salloc(t->alloced * sizeof(Rune)); } t->length = 0; t->pos = 0; offset = 0; while (len > 0) { desired = MIN(len, BUFFERSIZE - offset - 1); nread = read(fd, buf + offset, desired); if (nread <= 0) return -1; len -= nread; stop = end = offset + nread; buf[end] = '\0'; if (len > 0) /* if this is not the end of the file */ stop -= unfullutfbytes(buf, end); t->length += utftotext(t->text+t->length, buf, buf + stop); /* * If there were bytes at the end of the buffer that * weren't a complete rune, copy them back to the * start of the buffer for the next time. */ offset = end - stop; if (offset > 0) memcpy(buf, buf + end - offset, offset); } assert(offset == 0); t->gap = range(t->length, t->alloced); undo_reset(t); undo_start(t); viewlist_refresh(t->v); return 0; } /** * Convert the runes in [r0, r1) to UTF and write to 'fd'. * Return 0 for success. **/ static int utfwrite(Rune *r0, Rune *r1, int fd) { char buf[BUFFERSIZE+UTFmax]; Rune *p; char *t; int nwrite, nwritten; assert(r1 >= r0); assert(fd >= 0); p = r0; while(p < r1) { t = buf; while(p 0; nwrite -= nwritten, t += nwritten) { nwritten = write(fd, t, nwrite); if (nwritten <= 0) return -1; } } return 0; } void gaptranslate (Range r, Range gap, Range *before, Range *after) { Range NULLRANGE = {0,0}; /* Before the gap */ *before = (r.p0 < gap.p0) ? range(r.p0, MIN(r.p1, gap.p0)) : NULLRANGE; /* After the gap */ *after = (r.p1 > gap.p0) ? range (MAX(gap.p1, r.p0 + RLEN(gap)), r.p1 + RLEN(gap)) : NULLRANGE; } /* Write section 'r' of 't' to 'fd'. Return 0 for success */ int text_write_range(Text*t, Range r, int fd) { Range b, a; /* before, after the gap */ gaptranslate(r, t->gap, &b, &a); return utfwrite(t->text + b.p0, t->text + b.p1, fd) || utfwrite(t->text + a.p0, t->text + a.p1, fd); } /* Fill 'buf' with (legal) range 'logical'. */ void text_copy(Text *t, Range r, Rune *buf) { Range b,a; /* before and after the gap */ ulong bsize; assert(text_invariants(t)); assert((r.p1 >= r.p0) && (r.p1 <= t->length)); gaptranslate(r, t->gap, &b, &a); bsize = RLEN(b); memcpy(buf, t->text +b.p0, bsize*sizeof(Rune)); buf += bsize; memcpy(buf, t->text + a.p0, RLEN(a)*sizeof(Rune)); } Text * text_alloc(Data *d, Bool isbody) { Text *t; t = NEW(Text); t->alloced = 0; t->text = 0; t->length = 0; t->pos = 0; t->gap = nr; t->data = d; t->isbody = isbody; t->v = 0; /* to be assigned later */ t->did = t->undone = t->mark = 0; t->undoing = NoUndo; t->needsbackup = false; return t; } /* Replace data in range 'r' of 't' with 's'. Update displays. * Return the range of the inserted text. */ Range text_replace(Text *t, Range r, Rstring s) { ulong rlen = RLEN(r); ulong rslen = RSLEN(s); int delta = rslen - rlen; assert(ROK(r) && RSOK(s) && r.p1 <= t->length); assert(text_invariants(t)); assert(!findnull(s.r0, s.r1)); if(!(RLEN(r) || RSLEN(s))) return r; undo_record(t, r, s); if(t->gap.p0 != r.p0 || RLEN(t->gap) < delta) setgap(t, r.p0, delta); memcpy(t->text + t->gap.p0, s.r0, rslen*sizeof(Rune)); t->gap.p1 += rlen; t->gap.p0 += rslen; t->length += delta; /* invalidate cache? */ viewlist_replace(t->v, r, s); if(t->data){ if(TEXT_ISTAG(t)) tag_modified(t, r.p0); else data_sendreplace(t->data, r, s); } r.p1 = r.p0 + rslen; assert(text_invariants(t)); assert(ROK(r)); return r; } /* Clean up any resources which t uses. */ void text_free(Text *t) { undo_free(t); if(t->text) free(t->text); } /************* static functions *********************/ static void movegap(Text *t, ulong p) { assert(text_invariants(t)); /* move the gap to 'p' */ if (p < t->gap.p0) { memmove(t->text + p + RLEN(t->gap), t->text + p, (t->gap.p0 - p)*sizeof(Rune)); t->gap.p1 -= t->gap.p0 - p; t->gap.p0 = p; } else if (p > t->gap.p0) { memmove (t->text + t->gap.p0, t->text + t->gap.p1, (p - t->gap.p0)*sizeof(Rune)); t->gap.p1 = p + RLEN(t->gap); t->gap.p0 = p; } assert(text_invariants(t)); } /* Move the gap for 't' to 'p', ensure we can grow by at least 'n' */ static void setgap(Text *t, ulong p, int n) { int extra; assert(text_invariants(t)); movegap(t,p); assert(text_invariants(t)); extra = n - RLEN(t->gap); if (extra <= 0) return; /* Expand the gap */ extra += GAPSIZE; t->alloced += extra; t->text = srealloc(t->text, t->alloced * sizeof(Rune) ); /* Add this to the gap */ memmove ( t->text + t->gap.p1 + extra, t->text + t->gap.p1, (t->alloced - extra - t->gap.p1)*sizeof(Rune) ); t->gap.p1 += extra; assert(text_invariants(t)); } wily-0.13.42/wily/text.h000064402366570000012000000027171033320152300146240ustar00ozstaff00004330000002/* * The Text is the non-visible counterpart to the View. It maintains * the internal data structure of the whole file, but has no knowledge * about how to display things. The Text is also responsible for * maintaining Undo information. * * There may be one or more Views of a particular piece of text. */ struct Text { Rune *text; /* where we store stuff */ ulong alloced,length; Range gap; /* buffer gap */ Data *data; /* 0 for wilytag or columntag */ Bool isbody; View *v; /* list of views of this text */ Bool needsbackup; /* this text can become dirty */ ulong pos; /* position for regexp search engine */ Undo *did,*undone, *mark; enum {NoUndo, StartUndo, MoreUndo} undoing; }; #define TEXT_ISTAG(t) ( !(t)->isbody ) /* A set of macros to traverse all the runes within a text, * useful for searching. * * To traverse forwards * Tgetcset(text, pos) sets a starting position * Tgetc(text) returns the next rune (or -1) * To traverse backwards, use Tbgetcset(t,p), Tbgetc(t) */ #define Tgetcset(t,p) ((t)->pos = (p)) #define Tgetc(t) ( \ ((t)->pos < (t)->gap.p0) ? \ ((t)->text[(t)->pos++] ) : \ (((t)->pos < (t)->length) ? \ (t)->text[(t)->pos++ + RLEN((t)->gap)] : \ -1)) #define Tbgetc(tp) ( ((tp)->pos > (tp)->gap.p0) ? \ (tp)->text[--(tp)->pos + RLEN((tp)->gap)] : \ ( (tp)->pos ? (tp)->text[--(tp)->pos] : -1) ) #define Tbgetcset(t,p) ( (t)->pos = (p)) /* TODO - a builtin literal search could be quite a bit quicker */ wily-0.13.42/wily/tile.c000064402366570000012000000232721033320152300145670ustar00ozstaff00004330000002/******************************************* * Tiling window manager *******************************************/ #include "tile.h" /* Is the tile hidden? */ Bool tile_hidden(Tile *t) { /* We are hidden, or one of our ancestors is hidden */ return t->ishidden || (t->up && tile_hidden(t->up)); } Bool tile_invariant(Tile *tile) { int size ,body,tag, diff; Tile *last; assert(tile); /* Can't have _both_ a body and and a child */ assert(!(tile->body && tile->down)); if(tile->ishidden) return true; /* Tests for non-hidden tiles */ size = TILESIZE(tile); assert( size >= tile->base); if (!tile->body) return true; /* Tests for tiles with bodies, i.e. windows */ /* * The size of the tile == the sum of the sizes of its body and * tag, except if we're the "bottom" tile, in which case the * size of the tile might be a _little_ bit bigger than that * sum. */ body = view_height(tile->body); tag = view_height(tile->tag); last = last_visible_body(tile, 0); if (tile != last) { assert(size == body + tag); } else { /* bottom tile might have a little 'slop' */ diff = size - (body + tag); assert(diff >= 0); assert (diff <= tag); } return true; } Bool list_invariant(Tile *list) { int prev; Tile *t; int diff; assert(tile_invariant(list)); /* A list is also a tile */ assert(!list->body); /* Lists don't have bodies */ for (prev = list->cmin, t= list->down; t; t=t->right) { assert(tile_invariant(t)); /* Every child is a valid tile */ if(t->ishidden) continue; /* Every visible tile abutts the previous one */ assert(t->min == prev); prev = t->max; } if(list->down) { diff = list->cmax - prev; /* slop at the bottom */ assert(diff >= 0); assert(diff <= list->down->base); } return true; } /* "Snap" the size of 't' to some "neat" value, * without increasing 't's size. */ static void quantize(Tile*t) { int tag, body,size; if (!t->body) return; /* only really makes sense for windows */ size = TILESIZE(t); tag = snapheight(t->tag, size); assert(size >= tag); /* or we should have been hidden */ body = snapheight( t->body, size -tag); t->max = t->min + tag + body; } /* Ensure 't' wil fit inside 'list'. */ static void crop(Tile*t, Tile *list) { int size = TILESIZE(t); int listsize = LISTSIZE(list); assert(t->up == list); assert (size >= 0); if(size > listsize) { t->max = t->min + listsize; size = listsize; } if (t->min < list->cmin) moveto(t, list->cmin); if (t->max > list->cmax) t->max = list->cmax; assert (t->max >= t->min); assert (t->max <= list->cmax); assert (t->min >= list->cmin); } /* 't's shape has changed. Redisplay it, and any of its children */ void tile_reshaped(Tile *t) { Rectangle r = rectangle(t); assert(!t->ishidden); /* we don't reshape hidden tiles */ cls(r); view_reshaped(t->tag, r); if(t->body) { r.min.y += view_height(t->tag); view_reshaped(t->body, r); } else { list_reshaped(t,0); } assert(tile_invariant(t)); } /* Add 'tile' to 'list' and redisplay the modified 'list' * Try to maintain 'tile's min and max, but also try to avoid hiding * other tiles. Make sure that 'tile' ends up with a reasonable amount * of space. */ void list_add(Tile *list, Tile *tile) { Tile *left; Tile *next; int max; assert(!list->ishidden); assert(!tile->ishidden); assert(list_invariant(list)); if(tile->body) { Path buf; Data *d; d = view_data(tile->body); data_getlabel(d, buf); placedcol( buf, list); } tile->up = list; crop(tile, list); if( (left = list_find(list, tile->min)) ) { /* Add 'tile' just to the right of 'left' */ left->max = tile->min; if(TILESIZE(left) < tile->base) left->ishidden = true; else quantize(left); tile->left = left; tile->right = left->right; left->right = tile; if (tile->right) tile->right->left = tile; } else { assert(!list->down); /* ...or we would have found a tile */ tile->right = tile->left = 0; list->down = tile; tile->min = list->cmin; tile->max = list->cmax; } /* Maybe expand tile->max */ next = next_visible(tile); max = next? next->min : list->cmax; tile->max = MAX(tile->max, max); tile->min = MIN(tile->max - tile->base, tile->min); list_reshaped(list, tile); } /* Adjust the position of 't', to try to make sure we don't * have to hide all of t's siblings. On the other hand, don't * move 't' _too_ much. */ static void adjust_position(Tile *t) { Tile *l = t->up; int size, available, before, after, minsize, diff, move; before = list_basesize(l->down, t); after = list_basesize(t->right, 0); size = TILESIZE(t); /* We're prepared to shrink to half our asked-for size, * or the minimum size for a tile of our type, whichever * is bigger. */ minsize = MAX(size/2, tile_minsize(t)); available = size - minsize; /* move t->min down a bit? */ diff = l->cmin + before - t->min; if (diff>0) { move= MIN(available, diff); if(move > 0) { t->min += move; available -= move; } } /* move t->max up a bit? */ diff = t->max - (l->cmax - after); if (diff>0) { move= MIN(available, diff); if(move > 0) { t->max -= move; } } } /* * Adjust the sizes of the children, redisplay them if necessary. * Avoid moving or resizing 't'. Ensure that 't' remains visible. * We can assume that all of the * tiles have the right approximate size, but that's it. */ void list_reshaped(Tile *l, Tile *tile) { Tile *t; int cmin, cmax; Tile *slop; int diff; assert(list_oksizes(l)); if (tile) { crop(tile,l); adjust_position(tile); adjust_sizes_in_range(l->down, tile, tile->min - l->cmin); adjust_sizes_in_range(tile->right, 0, l->cmax - tile->max); } else adjust_sizes_in_range(l->down, 0, LISTSIZE(l)); assert(list_oksizes(l)); assert(list_size(l->down, 0) <= LISTSIZE(l)); FOR_EACH_VISIBLE(l->down,0) { quantize(t); } diff = LISTSIZE(l) - list_size(l->down, 0); assert(diff>=0); /* Even things up a little bit */ if ((slop = last_visible_body(l->down,0)) || (slop = last_visible(l->down, 0)) ) { slop->max += diff; } list_slide(l); setcminmax(l, &cmin, &cmax); FOR_EACH_TILE(l->down,0) { t->cmin = cmin; t->cmax = cmax; if(!t->ishidden) tile_reshaped(t); } assert(list_invariant(l)); } /* * Find a good place to create a window to display 'path'. * Fill *col with the column to contain the window, * *min, *max with a suggested position within the column */ /* Change the font of 't' and t's children */ void tile_setfont(Tile *t,char* arg) { if(t->body) { view_setfont( t->body, arg); } else { FOR_EACH_TILE(t->down, 0) { tile_setfont(t, arg); } } } /* * Unlink 'tile' from its parent/child/siblings. */ void tile_unlink(Tile*tile){ /* Unlink tile */ if(tile->right) tile->right->left = tile->left; if(tile->left) { tile->left->right = tile->right; /* Give the preceding window all the space. */ tile->left->max = tile->max; } else { tile->up->down = tile->right; } list_unhide(tile->up); cls(rectangle(tile)); list_reshaped(tile->up, 0); } /* * Free up all the resources used by 'tile' */ void tile_free(Tile*tile){ /* Free tile's resources */ free(tile->body); free(tile->tag); free(tile); } /* * Unlink 'tile' from its parent/child/siblings. * Free up all the resources used by 'tile' */ void tile_del(Tile *tile) { tile_unlink(tile); tile_free(tile); } /* Find a new parent for 'tile' somewhere at point 'p' */ Tile* newparent(Tile*tile, Point p){ Tile *t = point2tile(wily, p); assert(t); while((t->ori == tile->ori) || t->body) t = t->up; return t; } void tile_move(Tile *tile, Point p){ Tile *parent; int dest; /* Make sure we'll have someplace worth moving to */ parent = point2tile(wily,p); if (parent == 0 || parent == wily) return; tile_unlink(tile); dest = (tile->ori == H) ? p.x : p.y; if (tile->min < dest && dest < tile->max) tile->min = dest; else moveto(tile, dest); parent = newparent(tile, p); list_add(parent, tile); cursorset(buttonpos(tile)); } void tile_show(Tile *tile) { if(tile->up) tile_show(tile->up); if (tile->ishidden || (TILESIZE(tile) < tile_minsize(tile))) tile_grow(tile, 1); } View* tile_body(Tile*t) { return t? t->body: 0; } View* tile_tag(Tile*t) { return t? t->tag: 0; } /* Fill in 'min' and 'max' with a subregion within 'tile' for creating a new tile */ static void tile_split(Tile *tile, int *min, int *max) { int lastline, average; *max = tile->max; average = (tile->max + tile->min)/ 2; if(tile->body) { lastline = view_lastlinepos(tile->body); assert(lastline <= tile->max); *min = MIN(average, lastline); } else { *min = average; } } /* Fill 'min' and 'max' with a good place to add a tile within 'list' */ void findplace(Tile*list, int *min, int *max) { /* Split the largest visible tile, or use all the available space. */ Tile*biggest; if ( (biggest=biggest_visible(list->down, 0)) ) { tile_split(biggest, min, max); } else { *max = list->cmax; *min = list->cmin; } } /* Change t's position, keeping its size. */ void moveto(Tile*t, int pos) { int size = TILESIZE(t); t->min = pos; t->max = t->min + size; } /* Create (but don't display) a new tile */ Tile* tile_new(Ori ori, int min, int max, int base, Tile*parent, Text *tagt, Text*bodyt) { Tile*tile = NEW(Tile); int minsize; tile->ishidden = false; tile->ori = ori; tile->min = min; tile->max = max; tile->base = base; tile->up = parent; setcminmax(parent, &tile->cmin, &tile->cmax); tile->down = tile->left = tile->right = 0; tile->tag = view_new(font, true, tagt, tile); tile->body = bodyt ? view_new(font, false, bodyt, tile): 0; minsize = tile_minsize(tile); if(TILESIZE(tile) < minsize) tile->max = tile->min + minsize; return tile; } /* The minimum comfortable viewing size for 't' */ int tile_minsize(Tile*t) { return 3 * t->base; } at the bottom */ assert(diff >= 0); assert(diff <= list->down->base); } return true; } /* "Snap" the size of 't' to some "neat" value, * without increasing 't's size. */ static void quantize(Tile*t) { int tag, body,size; if (!t->body) return; /* only really makes sense for windows */ size = TILESIZE(t); tagwily-0.13.42/wily/tile.h000064402366570000012000000042171033320152300145720ustar00ozstaff00004330000002#include "wily.h" typedef enum Ori { H, V } Ori; /* Windows and Wily itself have V orientation, * columns have H orientation */ struct Tile { View *tag; /* every tile has a tag */ View *body; /* window tiles also have a body */ int min,max; /* starting and ending location */ int base; /* Minimum size of tile. */ Ori ori; /* orientation of _our_ min and max */ Bool ishidden; /* is this tile currently hidden? */ Tile *up, *down; /* parent, child */ Tile *left, *right; /* siblings */ int cmin, cmax; /* start and end locations of children */ }; #define TILESIZE(tile) ((tile)->max - (tile)->min) #define LISTSIZE(list) ((list)->cmax - (list)->cmin) #define ISWIN(tile) ( (tile)->body!= 0 ) /* loop over every visible child in the halfopen range [start,end) */ #define FOR_EACH_VISIBLE(start,end)\ for(t=(start); t!=(end);t=t->right)\ if (!t->ishidden) #define FOR_EACH_TILE(start,end)\ for(t=(start); t!=(end);t=t->right) extern int tagheight; /* height of a tag */ extern Tile *wily; Bool tile_invariant(Tile *tile); Bool list_invariant(Tile *list); View * point2view(Point pt); void tile_reshaped(Tile *t); Tile* point2tile(Tile *tile, Point p); void list_unhide(Tile*list); Tile* last_visible_body(Tile*start, Tile*end); void list_reshaped(Tile *l, Tile *t); Tile* newparent(Tile*tile, Point p); Tile* point2tile(Tile *tile, Point p); View * point2view(Point p); void list_unhide(Tile*list); void findplace(Tile*list, int *min, int *max); void list_slide(Tile *t) ; Tile* biggest_visible(Tile*start, Tile*end); Tile* last_visible_body(Tile*start, Tile*end); Tile* last_visible(Tile*start, Tile*end); int list_size(Tile *start, Tile *end); int list_basesize(Tile*start, Tile*end); Tile* list_find(Tile*parent, int n); Tile* next_visible(Tile*t); void setcminmax(Tile *list, int*cmin, int*cmax); void moveto(Tile*t, int pos); Rectangle rectangle(Tile*t); int adjust_sizes_in_range(Tile*start, Tile*end, int available); Tile* tile_new(Ori, int, int, int, Tile*, Text *, Text*); int tile_minsize(Tile*t); void list_add(Tile *list, Tile *tile); Bool list_oksizes(Tile*list); Bool list_contains(Tile*start, Tile*end, Tile *want); wily-0.13.42/wily/undo.c000064402366570000012000000154101033320152300145720ustar00ozstaff00004330000002/******************************************* * Maintain Undo chains, Undo methods *******************************************/ #include "wily.h" #include "text.h" /* We currently manage our Undo chain as a linked list, * and separately alloc small buffers every time. * If we cared about efficiency, we'd make all the u->s * entries share bigger chunks of Runes. * * For now, it doesn't seem to be a problem, and simpler * is better. */ struct Undo { Undo *next; Range r; /* where to replace */ Rstring s; /* what to replace with */ ulong alloced; /* bytes alloced at s.p0 */ }; static Bool undoing = false; /* prevent recording undo ops */ static Range illegal_range = {10,1}; static Undo * reverse (Text*, Range, Rstring); static Bool append (Text*, Range r, Rstring s); static void reset (Undo**); static void save_state (Text *); static void update_state (Text *); static Range shift (Text *, Undo **, Undo **, Bool ); static void text_rmtool(Text*t, char*s) { if(t->data) tag_rmtool(data_tag(t->data), s); } static void text_addtool(Text*t, char*s) { tag_addtool(data_tag(t->data), s); } /* Record information allowing us to undo the replacement of * 'r' in 't' with 's'. This replacement hasn't happened yet. */ void undo_record (Text *t, Range r, Rstring s) { Undo *u; assert(ROK(r)); assert(RSOK(s)); assert(r.p1 <= t->length); if(undoing || t->undoing == NoUndo) return; save_state(t); if(!append(t, r, s)) { /* remove old t->undone trail */ reset(&t->undone); u = reverse(t, r, s); u->next = t->did; t->did = u; } t->undoing = MoreUndo; update_state(t); } /* Undo the top operation in the undo stack, and move it to the redo * stack. Keep going to mark if appropriate. * Return the range that was inserted. */ Range undo_undo(Text *t, Bool all) { Range r; if (!t->did) return illegal_range; save_state(t); do { r = shift(t, &t->did, &t->undone, true); } while (all && t->did && t->did != t->mark); update_state(t); return (all ? illegal_range : r); } /* The mirror of undo_undo */ Range undo_redo(Text *t, Bool all) { Range r; Undo *tmp; save_state(t); tmp = t->did; t->did = t->undone; t->undone = tmp; r = undo_undo(t, all); tmp = t->did; t->did = t->undone; t->undone = tmp; update_state(t); return r; } /* Throw away all the undo information. */ void undo_free(Text*t) { reset(&t->did); reset(&t->undone); } /* Throw away all the undo information, leave in NoUndo state. */ void undo_reset(Text*t) { undo_free(t); t->undoing = NoUndo; text_rmtool(t, "Put"); text_rmtool(t, "Undo"); text_rmtool(t, "Redo"); } /* Start undoing on this Text. */ void undo_start(Text*t) { t->undoing = StartUndo; } /* * Make sure we don't merge whatever's currently on top of the undo * stack with the next operation. */ void undo_break(Text*t) { if(t->undoing==MoreUndo) t->undoing = StartUndo; } /* Remember this point in the Undo history * for future reference. */ void undo_mark(Text*t) { t->mark = t->did; t->undoing = StartUndo; } /* Are we at the same point in the history as we marked earlier? */ Bool undo_atmark(Text*t) { return t->mark == t->did; } /********************************************************* INTERNAL STUFF *********************************************************/ static void tag (Text *, Bool , Bool , char *); static Bool undo_eq(Undo*u, Range r, Rstring s); /* * We are about to replace the text at 'r' with 's'. If we can record * the undo information for this by modifying t->undo, and/or t->undone, * do so, and return true. Otherwise, return false. */ static Bool append(Text *t, Range r, Rstring s) { Undo *u; Rune *buf; int rlen, slen; if (undo_eq(t->did, r, s)) { /* * What we're about to do is exactly what would happen by * an Undo operation. Therefore, we just move the front of * the undo queue to the front of the redo queue. */ save_state(t); shift(t, &t->did, &t->undone, false); update_state(t); return true; } if (!(t->did && t->undoing==MoreUndo && t->did != t->mark)) return false; u = t->did; if(u->r.p1 == r.p0 && RLEN(r)==0 && RSLEN(u->s)==0) { u->r.p1 += RSLEN(s); return true; } if (RLEN(u->r)==0 && RSLEN(s)==0 && u->r.p0 == r.p1) { slen = RSLEN(u->s); rlen = RLEN(r); buf = salloc ( (slen + rlen) * sizeof(Rune) ); text_copy( t, r, buf); memcpy(buf + rlen, u->s.r0, slen*sizeof(Rune)); free(u->s.r0); u->s.r0 = buf; u->s.r1 = buf + slen + rlen; u->r.p0 = u->r.p1 = r.p0; return true; } return false; } /* Free all the nodes in the list, set the head of the list to 0.*/ static void reset(Undo**head) { Undo *u, *next; for(u = *head; u; u = next){ next = u->next; free(u->s.r0); free(u); } *head = 0; } /* * We use save_state() and update_state() to compare our undo state * before and after operations. These two functions use 'did' and * 'undone' */ static Undo *did, *undone; static Bool state_count = 0; static void save_state(Text *t) { if(state_count++) return; did = t->did; undone = t->undone; } static void update_state(Text *t) { if(--state_count) return; if(t->needsbackup) { tag(t, did!=0, t->did!=0, "Undo"); tag(t, undone!=0, t->undone!=0, "Redo"); tag(t, t->did == t->mark, did==t->mark, "Put"); } } /* * If 'change_text', do the replacement at 'from'. * * Reverse the top of 'from', add it to 'to'. * * Returns the range of any text inserted, or gibberish if !change_text */ static Range shift(Text *t, Undo **from, Undo **to, Bool change_text) { Range r; Undo *u; Undo *rev; u = *from; assert(u); *from = u->next; rev = reverse(t, u->r, u->s); if(change_text){ undoing=true; r = text_replace(t, u->r, u->s); undoing = false; } free(u->s.r0); free(u); rev->next = *to; *to = rev; return r; } /*If the state has changed to (true/false), (add/remove) 's' * in all the tags associated with 't' */ static void tag(Text *t, Bool before, Bool after, char *s) { if(!before != !after) (after? text_addtool : text_rmtool)(t,s); } /* * Compare two rune strings. Return a number >0, <0 or 0 to indicate if * s1 is lexically after, before or equal to s2 */ int rstrcmp(Rstring s1, Rstring s2) { Rune *p1, *p2; int diff; for ( p1=s1.r0, p2 = s2.r0; p1r.p0 && r.p1 == u->r.p1 && !rstrcmp(u->s, s); } /* Return undo entry to undo the replacement of 'r' in 't' with 's' */ static Undo * reverse(Text*t, Range r, Rstring s) { Undo *u; assert(ROK(r)); assert(RSOK(s)); u = NEW(Undo); u->r.p0 = r.p0; u->r.p1 = r.p0 + RSLEN(s); u->alloced = RLEN(r); u->s.r0 = (Rune*)salloc(u->alloced*sizeof(Rune)); text_copy(t, r, u->s.r0); u->s.r1 = u->s.r0 + RLEN(r); return u; } ; return r; } /* Throw away all the undo information. */ void undo_free(Text*t) { reset(&t->did); reset(&t->undone); } /* Throw away all the undo information, leave in NoUndo state. */ void undo_reset(Text*t) { undo_free(t); t->undoing = NoUwily-0.13.42/wily/vgeom.c000064402366570000012000000103111033320152300147350ustar00ozstaff00004330000002/******************************************* * view size and reshaping *******************************************/ #include "wily.h" #include "view.h" static Rectangle snap(View*v, Rectangle r); static Rectangle resizebox(Rectangle r); static void rfill(Rectangle r, Fcode f); static void button_set(View *v); static void setrects(View*v, Rectangle r); void view_fillbutton(View*v, Fcode f){ rfill(resizebox(v->r), f); } /* PRE: v->visible.p0 is correct. The text which is currently displayed in the frame is correct, but there might not be enough. POST: The frame is displaying everything it should, and v->visible.p1 is set. */ void fill(View *v) { Frame *f = &v->f; ulong p; /* text position of last visible rune */ Rune buf[FILLCHUNK]; int n; Text *t = v->t; /* view_invariants may not hold at this point */ if(!f->b) return; /* Add runes until we exhaust the text or fill the frame */ p = v->visible.p0 + f->nchars; while (!frame_isfull(f) && (n = text_ncopy(t, buf, p, FILLCHUNK)) ) { frinsert(f, buf, buf+n, f->nchars); p += n; } v->visible.p1 = v->visible.p0 + f->nchars; if(v->scroll) scroll_set(v->scroll, v->visible.p0, f->nchars, text_length(v->t) ); else button_set(v); /* Ensure that if v->sel is in the visible area, it is selected */ frselectp(f, F&~D); f->p0 = clip(v->sel.p0 - v->visible.p0, 0, f->nchars); f->p1 = clip(v->sel.p1 - v->visible.p0, 0, f->nchars); frselectp(f, F&~D); assert(view_invariants(v)); } int snapheight(View*v, int h) { int lines; int fh = v->f.font->height; int brdr = 2*INSET; if (v->scroll) { lines = (h - brdr) / fh; if ((lines == 0) || (h < tagheight)) return 0; else return h; } else return brdr + fh; } /* Try to redraw 'v' inside 'r' */ void view_reshaped(View*v, Rectangle r) { Frame *f; Bool need_refresh = (Dx(r) != Dx(v->r)); assert(view_invariants(v)); r = snap(v,r); setrects(v, r); if (ISVISIBLE(v)) { if (need_refresh && text_refreshdir(v->t)) { v->visible.p0 = v->sel.p0 = v->sel.p1 = 0; frdelete(&v->f, 0, v->f.nchars); } fill(v); /* Clean up any trailing junk. */ f = &v->f; /* Last line. */ r.max = r.min = frptofchar(f, f->nchars + 1); r.max.x = f->r.max.x; r.max.y = MIN(r.max.y+f->font->height, v->r.max.y); if (r.min.x != r.max.x) cls(r); /* Below last line. */ r.min.x = f->r.min.x; r.min.y = r.max.y; r.max.y = v->r.max.y; if (r.min.y != r.max.y) cls(r); view_border(v, v == last_selection); } } /* Return point just after the last line in 'v' */ int view_lastlinepos(View*v) { Frame *f = &v->f; Point p = frptofchar(f, f->nchars); int y = p.y + f->font->height; return MIN(y, f->r.max.y); } /* Return the amount by which 'v' could be squeezed */ int view_stripwhitespace(View*v) { Frame *f; int blanklines; if(v && ISVISIBLE(v)) { f = &v->f; assert(Dy(v->r) >= f->maxlines * f->font->height); blanklines = f->maxlines - f->nlines; if(blanklines > 0) { return blanklines * f->font->height; } } return 0; } static Rectangle snap(View*v, Rectangle r) { r.max.y = r.min.y + snapheight(v, Dy(r)); return r; } /* Fill 'r' according to 'f' */ static void rfill(Rectangle r, Fcode f) { r = inset(r,2); bitblt(&screen, r.min, &screen, r, f); } static Rectangle resizebox(Rectangle r) { r = inset(r, INSET); r.max.x = r.min.x + SCROLLWIDTH; return r; } static void button_set(View *v) { Rectangle r; assert(ISTAG(v)); /* we're a tag */ r = resizebox(v->r); border(&screen, r, 1, F); if(data_isdirty(view_data(tile_body(v->tile)))) rfill(r, F); } /* Set the rectangles for 'v', v's frame and v's scrollbar. * Assumes that 'r' is already correct. * If we can be displayed, set up the frame and scrollbar. */ static void setrects(View*v, Rectangle r) { Frame *f = &v->f; Font *ft = f->font; Rectangle scrollr, framer; Bitmap *b; assert(Dx(r) >= MINWIDTH); /* Or our tile is bizarre */ scrollr = inset(r, INSET); scrollr.max.x = scrollr.min.x + SCROLLWIDTH; framer = inset(r, INSET); framer.min.x += SCROLLWIDTH; framer.min.x += INSET; /* If 'r' is too small, we're hidden: use null bitmap */ b = Dy(r) < tagheight ? 0 : &screen; v->r = r; scroll_setrects(v->scroll, b, scrollr); frclear(f); frinit(f, framer, ft, b); } wily-0.13.42/wily/view.c000064402366570000012000000166041033320152300146050ustar00ozstaff00004330000002/******************************************* * View methods *******************************************/ #include "wily.h" #include "view.h" #include static Rectangle nullrect = { {0,0}, {0,0}}; /* Store string representation of 'dot' for 'v' into 'buf'. * if 'isLine', we want a line address, otherwise we want * a character address. */ void view_getdot(View *v, char*buf, Bool isLine) { if(isLine) { sprintf(buf, ":%d,.", text_linenumber(v->t, v->sel.p0)); } else { /* character address */ sprintf(buf, ":#%lu,.", v->sel.p0); } } Range view_expand(View *v, Range r, char *s) { assert(ROK(r)); if(RLEN(r)) return r; if (RLEN(v->sel) && v->sel.p0 <= r.p0 && v->sel.p1 >= r.p1) return v->sel; else return text_expand(v->t, r, s); } /***************************************** Allocate, deallocate, invariants *****************************************/ /* Allocate and return a new View. Doesn't attempt to draw it. */ View* view_new(Font *f, Bool istag, Text *text, Tile *tile) { View*v = NEW(View); Bitmap*b = 0; ulong length; ulong sel; length = text_length(text); v->r = nullrect; frinit(&v->f, nullrect, f, b); v->visible = range(0,0); sel = istag? length : 0; v->sel = range(sel, sel); v->anchor = length; v->t = text; v->next = 0; v->selecting = false; v->autoindent = autoindent_enabled; text_addview(text, v); v->tile = tile; v->scroll = istag? 0 : scroll_alloc(b, nullrect); assert(view_invariants(v)); return v; } /* Delete v and free its resources. Return 0 for success */ int view_delete(View *v){ if (text_rmview(v->t, v)) return -1; if(v==last_selection) view_setlastselection(0); if (v == last_focus) last_focus = 0; frclear(&v->f); if(v->scroll) free(v->scroll); return 0; } Bool view_invariants(View*v) { Range r; ulong length; if(!v->f.b) return true; /* all bets are off if we're not visible */ length = text_length(v->t); /* The selection and visible region are sane */ assert(ROK(v->sel)); assert(ROK(v->visible)); assert(v->sel.p1 <= length); assert(v->visible.p1 <= length); /* We're either displaying at least one line, or we're quite hidden */ assert(RLEN(v->visible)==v->f.nchars); assert(v->f.nchars <= length); /* View height == integral number of lines assert(Dy(v->r) == 2*INSET + v->f.maxlines * v->f.font->height); */ if(!v->selecting) { /* The visible part of the View selection == the frame selection */ r = rclip(v->sel, v->visible); assert( (r.p0 - v->visible.p0) == v->f.p0); assert( (r.p1 - v->visible.p0) == v->f.p1); } return true; } /***************************************** Simple data hiding stuff *****************************************/ /* Return the 'Data' associated with 'v', or 0. */ Data* view_data(View *v) { return v ? text_data(v->t): 0; } /* Body associated with 'v' */ View* view_body(View*v) { if(!v) return 0; return ISBODY(v) ? v : tile_body(v->tile); } /* The window 'v' is a part of, or 0. */ Tile* view_win(View*v) { return v? tile_win(v->tile) : 0; } /* The tile 'v' is part of, or 0. */ Tile* view_tile(View*v) { return v? v->tile : 0; } Text* view_text(View*v) { return v? v->t : 0; } Range view_getsel(View*v) { return v->sel; } int view_height(View*v) { return (v && v->f.b) ? Dy(v->r) : 0; } void view_paste(View*v){ undo_break(v->t); view_select(v, paste(v->t, v->sel)); view_show(v, v->sel); } /* * Copy the range to the snarf buffer (unless it's empty). * Delete the text, update the View */ void view_cut(View*v, Range r) { assert(ROK(r)); if(RLEN(r)){ snarf(v->t, r); undo_break(v->t); text_replace(v->t, r, rstring(0,0)); } view_show(v, range(r.p0, r.p0)); } void view_append(View *v, char *s, int n) { Text *t; ulong len; Range end; t = v->t; len = text_length(t); end = range(len,len); n = stripnulls(s, n); s[n] = 0; text_replaceutf(v->t, end, s); } /* Append 'n' bytes at 's' to 'v'. If 'first' time, we replace * the selection, otherwise we append to the selection */ void view_pipe(View *v, Bool *first, char *s, int n) { ulong p0 = v->sel.p0; Range r; if (*first) { r = v->sel; *first = false; } else { r = range(v->sel.p1, v->sel.p1); } n = stripnulls(s, n); s[n]=0; text_replaceutf(v->t, r, s); r = range(p0, v->sel.p1); view_select(v, r); } /* * Change v's font. If 'arg' is not null, use it, otherwise * toggle between Fonts 'fixed' and 'font' */ void view_setfont(View *v, char*arg) { frfont(&v->f, (v->f.font==font)? fixed: font); if(ISVISIBLE(v)) view_reshaped(v, v->r); } /* * Perform the actual drawing of the border that indicates the * view is the last_selection. */ void view_border(View *v, Bool set) { Rectangle r; assert(v); r = v->r; r.min.x += SCROLLWIDTH + 4; if (tile_hidden(view_tile(v))) return; if (set) border(&screen, r, SELECTEDBORDER, F); else border(&screen, r, SELECTEDBORDER, 0); border(&screen, v->r, 1, F); } /* Indicate visually that 'v' is the 'last_selection' */ void view_setlastselection(View *v) { if (v == last_selection) return; if (last_selection) view_border(last_selection, false); if (v) view_border(v, true); last_selection = v; } /* Set the selection in 'v' to 'r'. Indicate on screen if necessary */ void view_select(View*v, Range r) { assert(ROK(r)); assert(view_invariants(v)); frselectp(&v->f, F&~D); v->sel = r; r = rclip(v->sel, v->visible); v->f.p0 = r.p0 - v->visible.p0; v->f.p1 = r.p1 - v->visible.p0; frselectp(&v->f, F&~D); assert(view_invariants(v)); } /* Warp the cursor to selection 'r' in 'v'. * PRE: 'v' is visible. Some of 'r' is visible. */ void view_warp (View *v, Range r) { Point pt; assert(view_invariants(v)); assert(ROK(r)); assert(RINTERSECT(r, v->visible)); assert(r.p1 <= text_length(v->t)); assert(ISVISIBLE(v)); pt = frptofchar(&v->f, r.p0 - v->visible.p0); pt.y += v->f.font->height/2; /* middle of char */ cursorset(pt); } /* * Replace Range 'r' with 's' in 'v'. We've already changed the underlying * text buffer, we now just have to change the display, and update * v->visible and v->sel. */ static void view_replace(View *v, Range r, Rstring s) { Range q = intersect(r, v->visible); /* visible part of change */ int len; Bool visible = ISVISIBLE(v); /* view_invariants don't hold at present because * v->t->length has changed but v->sel hasn't */ assert(ROK(r)); assert (RSOK(s)); assert(RLEN(r) || RSLEN(s)); /* or we wouldn't get here */ assert(r.p0 <= text_length(v->t)); /* even if we're deleting text, this will hold */ if(visible && q.p1 >= q.p0) { /* some of the replaced text is visible */ Frame *f = &v->f; q.p0 -= v->visible.p0; q.p1 -= v->visible.p0; if(RLEN(q)) frdelete(f, q.p0 , q.p1); if(RSLEN(s)) frinsert(f, s.r0, s.r1, q.p0); } /* adjust our counters */ len = RSLEN(s); v->visible.p0 = ladjust(v->visible.p0, r,len); v->visible.p1 = radjust(v->visible.p1, r,len); v->sel.p0 = radjust(v->sel.p0, r,len); v->sel.p1 = radjust(v->sel.p1, r,len); v->anchor= ladjust(v->anchor, r,len); if(visible) fill(v); assert(view_invariants(v)); } /* Refresh v because its text has changed arbitrarily. */ static void view_refresh(View*v) { if(ISVISIBLE(v)) { v->visible.p0 = 0; v->sel = range(v->visible.p0, v->visible.p0); frdelete(&v->f, 0, v->f.nchars); fill(v); } } void viewlist_refresh(View*v) { for(;v; v = v->next) view_refresh(v); } void viewlist_replace(View*v, Range r, Rstring s) { for(;v; v = v->next) view_replace(v, r, s); } wily-0.13.42/wily/view.h000064402366570000012000000024671033320152300146140ustar00ozstaff00004330000002/* * Both tags and bodies use a View as a display widget. The difference * between them is that bodies have scrollbars, whereas tags don't (but * tags automatically grow as required). A View uses a Text to keep * track of the text that is currently not on screen, and a Frame to * display text. A view keeps track of the visible area, the selected * area, and the place where we began typing (if we're in the middle of * typing). * * The View controls all aspects of viewing and selecting text, but has * no knowledge of how we store all the text. * If a view is not visible, v->r.max.y == v->r.min.y, and it's frame * will have been frcleared, i.e. not usable */ struct View { Rectangle r; /* of whole view */ Text *t; Frame f; Range visible, sel; /* visible, selected area */ ulong anchor; /* where we most recently started typing */ Scroll *scroll; /* 0 for tag */ Tile *tile; View *next; /* list of views displaying same Data */ Bool selecting; /* we're busy dragging out a selection */ Bool autoindent; /* autoindent in this view? */ }; #define ISTAG(v) ((v) && !(v)->scroll) #define ISBODY(v) ( (v) && (v)->scroll) #define ISVISIBLE(v) ( (v)->f.b!=0 ) /* Return true if 'p' is contained in 'v's scrollbar */ #define POINTINSCROLL(p,v) ( (p).x < (v)->r.min.x + SCROLLWIDTH + INSET ) wily-0.13.42/wily/util.c000064402366570000012000000242411033320152300146040ustar00ozstaff00004330000002/******************************************* * A few utilities *******************************************/ #include "wily.h" #include #include #include #include void dirnametrunc(char*s){ if((s=strrchr(s,'/'))) *(++s) = 0; } /* Combine 'add' with 'context', put the result in 'dest' */ void addcontext(char*dest, char*context, char*add){ char*s; if(strchr("/$~", add[0])){ strcpy(dest,add); return; } strcpy(dest, context); if(!(s = strrchr(dest, '/'))){ label2path(dest, context); if(!(s = strrchr(dest, '/'))){ s = dest + strlen(dest) -1; } } strcpy(s+1,add); labelclean(dest); } /* Set the name of the window where output from the context * of 'label' will appear. */ void olabel(char*out, char*label){ addcontext(out, label, "+Errors"); } /* Compares two stat buffers, returns 0 if they have * the same inode and device numbers. */ int statcmp(Stat*a, Stat*b) { if(a->st_ino != b->st_ino || a->st_dev != b->st_dev) return -1; else return 0; } Bool isdir(char*path) { struct stat buf; return !stat(path, &buf) && S_ISDIR(buf.st_mode); } /* ** Append bytes from `s' (of length `ns') to `r' (of length `nr') until ** `r' has a full rune. Stop if `s' ends or an illegal utf sequence ** is detected. Return the number of bytes appended. ** sizeof `r' must be at least UTFmax+1 bytes. */ int fillutfchar(char *r, int nr, char *s, int ns) { int c = 0; r += nr; while ((nr < UTFmax) && (ns > 0) && ((((uchar)*s)&0xC0) == 0x80)) *r++=*s++, nr++, ns--, c++; *r = '\0'; return c; } /* ** If utf string `s' of length `n' ends with an uncomplete rune, return ** the number of bytes in that rune. (If `s' ends with an illegal utf ** sequence, return zero.) */ int unfullutfbytes(char *s, int n) { int e = 1; for (e = 1; (e < n) && (e < UTFmax); ++e) { if (((uchar)s[n-e]&0xC0) != 0x80) { if (!fullrune(s+n-e, e)) return e; break; } } return 0; } /* * Return Rstring for utf. Either s.r0 == s.r1 == 0, * or s.r0 will need to be free */ Rstring utf2rstring(char*utf) { Rstring s; int len; if( (len = utflen(utf)) ) { s.r0 = salloc(len*sizeof(Rune)); s.r1 = s.r0 + utftotext(s.r0, utf, utf+strlen(utf)); } else s.r0 = s.r1 = 0; return s; } /* Write into 'back' the name of a file we can write to as a backup * for 'orig'. Return 0 for success. */ int backup_name(char *orig, char *back) { Path dir, guide; char *home; DIR *dirp; struct dirent *direntp; FILE *fp; int max,n; int init_guide = 0; if ( !(home=getenv("WILYBAK")) ) { if ( !(home=getenv("HOME")) ) { return diag(0, "getenv HOME"); } sprintf(dir, "%s/.wilybak", home); } else strcpy(dir, home); /* Make sure the directory exists. Create it if necessary. */ if(access(dir, W_OK) && (mkdir(dir, 0700)) ) return diag(0, "couldn't create backup directory %s", dir); /* Find directory entry with largest number. We will be one * greater than that. */ max=0; if(!(dirp = opendir(dir))) { return diag(0, "couldn't opendir %s", dir); } rewinddir(dirp); /* Workaround for FreeBSD. */ while ((direntp = readdir(dirp))) { if ( (n=atoi(direntp->d_name)) > max) max = n; } closedir(dirp); max++; sprintf(back, "%s/%d", dir, max); /* Record what is going where */ sprintf(guide,"%s/guide", dir); if(access(guide, W_OK) < 0) init_guide = 1; fp = fopen(guide, "a+"); if(fp) { /* if this fails, don't care all that much */ if(init_guide) fprintf(fp, "diff cp rm *\n"); fprintf(fp, "%3d\t%s\n", max, orig); fclose(fp); } else { diag(guide, "couldn't update backup guide file"); } return 0; } void noutput(char *context, char *base, int n) { Path errwin; View *v; Range r; char *s; Text *t; ulong p; strcpy(errwin, context? context : wilydir); if((s = strrchr(errwin, '/'))) s++; else s = errwin +strlen(errwin); strcpy(s, "+Errors"); v = openlabel(errwin, true); n = stripnulls(base, n); base[n] = 0; t = view_text(v); p = text_length(t); r = text_replaceutf(t, range(p,p), base); r.p0 = r.p1; /* most interested in the end bit */ view_show(v, r); } /* * Given strings stored in (null-terminated) 'item', arrange them in * columns to fit neatly in a window with given 'totalwidth', 'tabwidth' * and font 'f'. Return the finished, allocated, null-terminated * string. */ char * columnate(int totalwidth, int tabwidth, Font *f, char **item) { int rows, columns, row, column; int maxwidth; int j, widest,nitems, ntabs, biggest; int *width; char *buf, **c; int remaining; int bufsize = 1024; /* count the items */ nitems = 0; c= item; while(*c++) nitems++; if(!nitems) return strdup(""); /* width[j] - width of string j * widest - index of widest string * maxwidth - width of largest string plus a tab */ widest = 0; width = (int*)salloc(nitems*sizeof(int)); for(j=0; j< nitems; j++) { width[j] = strwidth(f, item[j]); if (width[j]>width[widest]) widest = j; } biggest = width[widest] + strwidth(f, "W"); ntabs = biggest/tabwidth; if (biggest % tabwidth) ntabs++; maxwidth = ntabs*tabwidth; columns = ((totalwidth -biggest) / maxwidth) +1; if (columns < 1) columns = 1; rows = nitems / columns; if (nitems % columns) rows++; buf = (char*)salloc(bufsize); j = 0; remaining = nitems; for(row=0; ; row++) { for(column = 0; column < columns; column++) { int current, deficit; current = column*rows + row; if (current >= nitems) break; deficit = maxwidth - width[current]; ntabs = deficit / tabwidth; if (deficit % tabwidth) ntabs++; if(column==columns-1) ntabs=0; /* no tabs for last column */ if (j+strlen(item[current])+ntabs+2 >= bufsize) { bufsize *= 2; buf = (char*) srealloc(buf, bufsize); } strcpy(&buf[j], item[current]); j += strlen(item[current]); while(ntabs-->0) buf[j++] = '\t'; if (!(--remaining)) goto done; } buf[j++] = '\n'; } done: if(column) buf[j++] = '\n'; buf[j]='\0'; assert(j < bufsize); free(width); return buf; } static void cleanup(void){ data_backupall(); fifo_cleanup(); } void cleanup_and_die(int n) { cleanup(); exit(0); } void cleanup_and_abort(int n) { perror("wily: something horrible happened:"); cleanup(); abort(); } /* Send a diagnostic message to the appropriate place, * given its context. */ int diag(char *context, char *fmt, ...) { va_list args; Path msg; char *err,*s; s = msg; if ( errno && (err=strerror(errno)) ) { sprintf(msg, "diag: %s: ", err); s += strlen(s); } va_start(args,fmt); vsprintf(s, fmt, args); va_end(args); strcat(msg, "\n"); assert(strlen(msg)<1024); noutput(context, msg, strlen(msg)); return 1; } Rstring rstring(Rune*r0, Rune*r1) { Rstring s; s.r0 = r0; s.r1 = r1; return s; } char* mybasename(char*f) { char *s; s=strrchr(f,'/'); return s ? s+1 : f; } ulong texttoutf(char *s, Rune *r1, Rune *r2) { Rune *q; char *t; if (r2 <= r1) return 0; for (t = s, q = r1; q < r2; q++) t += runetochar(t, q); return t-s; } int distance(Point p1, Point p2) { return (p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y); } /* Error we should be able to recover from */ void error(char *fmt, ...) { va_list args; perror("wily:"); va_start(args,fmt); vfprintf(stderr, fmt, args); va_end(args); fprintf(stderr, "\n"); } /* Error we cannot recover from */ void fatal(char *fmt, ...) { va_list args; perror("wily:"); va_start(args,fmt); vfprintf(stderr, fmt, args); fprintf(stderr, "\n"); cleanup_and_abort(0); } /* * dummy mouse driver for the frame library */ void frgetmouse(void) {} /* Store runes from 't' into X clipboard as UTF */ void snarf(Text *t, Range r) { char *buf; assert(t); if(RLEN(r)){ buf = text_duputf(t, r); select_put(buf); free(buf); } } /* Replace range 'r' of 't' with the snarf buffer, return * the range of the new text. */ Range paste(Text *t, Range r) { char *cbuf; Rune *rbuf; int n; Rstring s; assert(t); assert(ROK(r)); cbuf = select_get(); /* not to be freed */ rbuf = (Rune *)salloc(sizeof(Rune)*(utflen(cbuf)+1)); n = utftotext(rbuf, cbuf, cbuf+strlen(cbuf)); s.r0 = rbuf; s.r1 = rbuf + n; text_replace(t, r, s); r.p1 = r.p0 + n; free(rbuf); return r; } void add_slash(char*s) { int n; n = strlen(s); if(s[n-1] != '/'){ s[n++]='/'; s[n]='\0'; } } Bool frame_isfull(Frame*f) { return f->nlines == f->maxlines && f->lastlinefull; } Bool utfHadNulls; int utftotext_unconverted; /* bytes at the end which weren't converted */ /* Convert UTF from s1 to s2 into runes, store them at r * Returns the number of runes stored. * Sets utfHadNulls to indicate that some of the UTF contained nulls or bad UTF. * Bad UTF and nulls will be replaced with rune Runeerror (u0080). * Set utftotext_unconverted to the number of bytes before the end that * belongs to a char extending beyond the end and wasn't converted. * * This function will look beyond the end s2 if the last UTF combination * is not completely within the range. If converting an entire range * at once, it should have an extra '\0' at s2 (right after the end) * so that an incomplete (bad) multibyte UTF combination at the end * will be correctly detected. It converting a subrange of a larger UTF * sequence, make sure the end s2 is after a complete UTF combination, * OR leave enough bytes beyond the end to complete any multibyte UTF char * (UTFmax) and examine utftotext_unconverted after the call returns. * * Note: This function will be called multiple times during a big read, * so utfHadNulls must be preset to false by the caller as appropriate. */ ulong utftotext(Rune *r, char *s1, char *s2) { Rune *q; char *v; if (s2 <= s1) return 0; for (v = s1, q = r; v < s2; ) { if (!(*(uchar*)v)) { utfHadNulls = true; v++; *q =Runeerror; } else if (*(uchar *)v < Runeself) { *q = *v++; } else { v += chartorune(q, v); if (*q == Runeerror) utfHadNulls = true; } assert(*q); q++; } if (v > s2) { int length; q--; length = runelen(*q); utftotext_unconverted = s2 - (v-length); } else { utftotext_unconverted = 0; } return q-r; } int stripnulls(char *buf, int len) { char *s, *d, *e=buf+len; if (!(s = d = memchr(buf, '\0', len))) return len; while (++s < e) { if (*s == '\0') --len; else *d++ = *s; } return --len; } wily-0.13.42/wily/builtins.c000064402366570000012000000135021033320152300154560ustar00ozstaff00004330000002/******************************************* * Builtin functions *******************************************/ #include "wily.h" #include "view.h" #include #include /* Each of these functions takes a View used as the context * of the command, and an argument. The argument may be null. */ /* * If given arguments, Kill all the external processes matching * the arguments. * * If given no arguments, generate a list of possible 'Kill' commands. */ static void builtin_kill(View*v, char*s) { if (s) kill_all(s); else kill_list(); } /***************************************************** Dotfiles, Font, Indent Toggle operations. These probably _should_ all act similarly, but right now they don't. todo. *****************************************************/ static void dotfiles(View *v, char *arg) { show_dot_files = !show_dot_files; } static void builtin_font(View *v, char *arg) { tile_setfont(view_tile(v), arg); } static void builtin_autoindent(View *v, char *arg) { View *body; if ((body = view_body(v))) { body->autoindent = ! body->autoindent; } else { autoindent_enabled = !autoindent_enabled; } } /***************************************************** Undo, redo. If called with an argument, they each go 'all the way'. *****************************************************/ static void undo_ops(View *v, char*arg, Range (*undofn)(Text*, Bool)) { Range r; if(!(v = view_body(v))) return; r = (*undofn)(v->t, arg!=0); if ROK(r) { view_show(v, r); view_select(v, r); } } static void undo(View *v, char *arg){undo_ops(v, arg, undo_undo);} static void redo(View *v, char *arg) {undo_ops(v, arg, undo_redo);} /***************************************************** Get, Put. If called with an argument, they each go 'all the way'. *****************************************************/ /* Read or write the window associated with 'v', possibly using 'arg' */ static void getorput(View*v, char*arg, int(*fn)(Data*,char*)) { Data *d; Path dest; char *s; if (!(d = view_data(v))) return; if (arg && strlen(arg)) { data_addcontext(d, dest, arg); s = dest; } else { s = 0; } (*fn)(d, s); } static void put(View *v, char *arg) {getorput(v, arg, data_put);} static void get(View *v, char *arg) {getorput(v, arg, data_get);} /***************************************************** Quit/Putall ignore the context. *****************************************************/ static void putall(View *v, char *arg) { data_putall(); } static void quit(View *v, char *arg) { cleanup_and_die(0); } /***************************************************** Del, Delcol delete the window or column 'v' belongs to. *****************************************************/ static void del(View *v, char *arg) { win_del(view_win(v)); } static void delcol(View*v, char *arg) { col_del(tile_col(v->tile)); } /***************************************************** Cut/Snarf/Paste all act on last_selection *****************************************************/ static void cut(View *v, char *arg) { if((v=last_selection)) view_cut(v, v->sel); } static void builtin_snarf(View *v, char *arg) { if((v=last_selection)) snarf(v->t, v->sel); } static void builtin_paste(View *v, char *arg) { if((v=last_selection)) view_paste(v); } /***************************************************** Anchor, Split act on either the window of the current context, or the last selection. *****************************************************/ static void anchor(View *v, char *arg) { Tile *win; if ( (win=view_win(v)) || (win=view_win(last_selection)) ) { win_anchor(win, arg); } } /* If 'v' or 'last_selection' are in a window, split that window */ static void split(View *v, char *arg) { Tile *win; if( (win = view_win(v)) || (win = view_win(last_selection)) ) { win_clone(win); } } /***************************************************** Clear, Look act on the body of the current context. *****************************************************/ static void clear(View *v, char *arg) { View *body; if ((body = view_body(v))) text_replace(body->t, text_all(body->t), rstring(0,0)); } /* Look for 'arg' or the current selection in the body of 'v', * select and show the found thing if you find it. */ static void look(View *v, char *arg) { if((v=view_body(v))) view_look(v, arg); } /***************************************************** New window, possibly called 'arg'. Try to use a window for context. *****************************************************/ static void new(View *v, char *arg) { Path label; if(!arg) arg = "New"; /* If 'v' isn't part of a window, maybe last_selection is */ if(!view_win(v)) v = last_selection; data_addcontext(view_data(v), label, arg); if(!data_find(label)) data_open(label, true); } typedef struct Cmd Cmd; struct Cmd { char *name; void (*cmd)(View *, char *); }; /* _Must_ be kept in sorted order, we use bsearch on it */ static Cmd builtins[] = { {"Anchor", anchor}, {"Clear", clear}, {"Cut", cut}, {"Del", del}, {"Delcol", delcol}, {"Dotfiles", dotfiles}, {"Font", builtin_font}, {"Get", get}, {"Indent", builtin_autoindent}, {"Kill", builtin_kill}, {"Look", look}, {"New", new}, {"Newcol", col_new}, {"Paste", builtin_paste}, {"Put", put}, {"Putall", putall}, {"Quit", quit}, {"Redo", redo}, {"Snarf", builtin_snarf}, {"Split", split}, {"Undo", undo}, }; static int cmd_compare(Cmd *a,Cmd *b) { return strcmp(a->name, b->name); } /* * PRE: 'v' is the context, 'cmd' the command. * POST: return true if we recognise the builtin, false otherwise. */ Bool builtin(View *v, char *cmd, char *arg) { Cmd key, *c; assert(v); assert(cmd[0] && !isspace(cmd[0])); key.name = cmd; c = bsearch( &key, builtins, sizeof(builtins)/sizeof(Cmd), sizeof(Cmd), (int (*)(const void *,const void*))cmd_compare); if (c) (*c->cmd)(v, arg); return (Bool) c; } wily-0.13.42/wily/wily.c000064402366570000012000000073361033320152300146210ustar00ozstaff00004330000002/******************************************* * main(), parse arguments *******************************************/ #include "wily.h" #include "tile.h" static int ncolumns = 2; int tagheight; Tile *wily=0; /* encloses the whole application */ char *wilytools = "Kill | Newcol Quit Putall wily-0.13.42 Dotfiles Font "; /* version */ char *filetools = "Del Look ."; char *dirtools = "Del Look .."; char *columntools = "Delcol New Cut Paste Snarf Anchor Split | "; void _allocerror(char*s){ fprintf(stderr,"%s\n", s); abort(); } /* Add 'cmd' to the visible list of running processes. */ void addrunning(char *cmd){ tag_addrunning(view_text(wily->tag), cmd); } /* Remove 'cmd' from the visible list of running processes.*/ void rmrunning(char *cmd){ tag_rmtool(view_text(wily->tag), cmd); } /* Initialize info about what bits of text get added to various tags. * Reads $WILYTOOLS or $HOME/.wilytools for regexp/tool pairs, * uses $WMAINTAG, $WCOLTAG $WFILETAG, $WDIRTAG * as the tools for the wily tag, column tag, file tags and directory tags * respectively. */ static void tools_init(void){ char*s, t[200]; if ((s = getenv("WILYTOOLS"))) tag_init(s); else { Path p; sprintf(p, "%s/%s", getenv("HOME"), ".wilytools"); tag_init(p); } if ((s=getenv("WCOLTAG"))) columntools = strdup(s); if ((s=getenv("WMAINTAG"))) { strcpy(t, wilytools); strcat(t, s); wilytools = strdup(t); } if ((s=getenv("WFILETAG"))) filetools = strdup(s); if ((s=getenv("WDIRTAG"))) dirtools = strdup(s); } static void usage(void) { fprintf(stderr,"wily [-c ncolumns] [-a tabsize] [-e command] [file1 ...]\n"); exit(1); } static void args(int argc,char **argv, char **envp) { extern char *optarg; extern int optind; int c; char *cmd = 0; tabsize = 4; /* default */ /* init libXg */ xtbinit((Errfunc)error, "Wily", &argc, argv, 0); tagheight = font->height + 2*INSET; while ((c = getopt(argc, argv, "c:a:e:")) != EOF) { switch (c) { case 'c': ncolumns = atoi(optarg); break; case 'a': tabsize = atoi(optarg); break; case 'e': cmd = optarg; break; default: usage(); break; } } scroll_init(); einit(Ekeyboard | Emouse); cursorswitch(cursor); wily_init(); ex_init(); if (optindtag, cmd, 0); } /* Initialise the base tile, with some columns */ void wily_init(void) { Text *t; int j; t = text_alloc(0, false); text_replaceutf(t, nr, wilytools); wily = tile_new(V, 0, screen.r.max.y, 0, 0, t, 0); tile_reshaped(wily); last_selection = 0; view_setlastselection( wily->tag); for(j=0; j< ncolumns; j++) col_new(wily->tag, 0); } /* Reshape the base tile */ void ereshaped(Rectangle r) { if(!wily) return; /* not initialised yet */ wily->cmax = r.max.x; wily->max = r.max.y; tile_reshaped(wily); } /* Main event loop */ static void mainloop(void) { ulong type; Event e; Bool mouseaction=true; Point lastp={0,0}; while ((type = eread(~0, &e))) { switch(type){ case Ekeyboard: if(mouseaction) { last_focus = point2view(lastp); mouseaction=false; } if (last_focus) dokeyboard(last_focus, e.kbdc); break; case Emouse: lastp = e.mouse.xy; mouseaction=true; if(e.mouse.buttons && (last_focus = point2view(e.mouse.xy))) domouse(last_focus, &e.mouse); break; default: dofd(type, e.n, (char*)e.data); break; } } } int main(int argc,char **argv, char **envp) { if (!getcwd(wilydir,MAXPATH)) fatal("couldn't find out what directory this is"); add_slash(wilydir); env_init(envp); tools_init(); args(argc,argv, envp); mainloop(); return 0; } wily-0.13.42/wily/wily.h000064402366570000012000000021331033320152300146140ustar00ozstaff00004330000002/******************************************* * Includes a bunch of header files *******************************************/ #ifndef WILY_H #define WILY_H #include #include #include #include #include #include #define IMPLIES(a,b) (!(a)||(b)) #include #include #include "const.h" typedef struct stat Stat; typedef char Path[MAXPATH]; typedef Rune RPath[MAXPATH]; typedef struct View View; /* see view.h */ typedef struct Scroll Scroll; /* see scroll.c */ typedef struct Text Text; /* see text.h */ typedef struct Data Data; /* see data.h */ typedef struct Undo Undo; /* see undo.c */ typedef struct Tile Tile; /* see tile.h */ typedef struct Rstring Rstring; typedef struct Mbuf Mbuf; struct Mbuf { char *buf; /* alloced initially, never freed */ int alloced; int n; }; struct Rstring { Rune *r0, *r1; }; /* elements of the Rstring are >= r0 and < r1 */ #define RSLEN(r) ((r).r1 -(r).r0) #define RSOK(r) ((r).r1 >= (r).r0) #define RSFREE(r) free((r).r0) /* GLOBALS */ #include "global.h" #include "proto.h" #endif wily-0.13.42/wily/vshow.c000064402366570000012000000106561033320152300150020ustar00ozstaff00004330000002/******************************************* * view scrolling *******************************************/ #include "wily.h" #include "view.h" void view_linesdown(View *v, int n, Bool down) { Mouse m; Rectangle r; if(! (v = tile_body(view_win(v))) ) return; r = v->r; m.xy.x = r.min.x; m.xy.y = r.min.y + v->f.font->height * n; m.buttons = down? RIGHT : LEFT; view_scroll(v, &m); } void view_pagedown(View *v, Bool down) { Mouse m; Rectangle r; if(! (v = tile_body(view_win(v))) ) return; r = v->r; m.xy.x = r.min.x; m.xy.y = (r.min.y + r.max.y) /2; m.buttons = down? RIGHT : LEFT; view_scroll(v, &m); } /* Make 'n' the first rune displayed in 'v' */ static void view_set(View*v, ulong n) { ulong ndelete; assert(view_invariants(v)); assert(v->scroll); assert(n<= text_length(v->t)); if(n == v->visible.p0) return; ndelete = RCONTAINS(v->visible, n) ? n - v->visible.p0 : v->f.nchars; v->visible.p0 = n; if (ISVISIBLE(v)) { frdelete(&v->f, 0, ndelete); fill(v); } assert(view_invariants(v)); } static Bool tag_isfull(Frame*f) { Point pt = frptofchar(f, f->nchars); Point max = f->r.max; return max.x - pt.x < 30; } /* Try to get a tag to show as much as possible of 'r' */ static void tag_show(View*v, Range r) { Frame *f = &v->f; assert(ISTAG(v)); assert(r.p1 <= text_length(v->t)); /* If we're seeing all of r, * or if all that we're seeing is in r, we're happy */ if(RISSUBSET(r, v->visible) || RISSUBSET( v->visible,r)) goto done; /* Otherwise, it must be the case that EITHER * there's some of 'r' invisible off to the right or the left */ assert(r.p1 > v->visible.p1 || r.p0 < v->visible.p0); if (r.p1 > v->visible.p1) { /* remove stuff until we can see r.p1 */ while(r.p1 > v->visible.p1) { frdelete(f, 0, f->nchars); v->visible.p0 += 5; fill(v); } assert(r.p1 <= v->visible.p1); } else { /* add stuff until we can see r.p0 */ frdelete(f, 0, f->nchars); v->visible.p0 = r.p0; fill(v); assert(r.p0 >= v->visible.p0); } done: while (!tag_isfull(f) && v->visible.p0) { frdelete(f, 0, f->nchars); v->visible.p0--; fill(v); } } /* Make sure 'v' is showing at least some of 'r' */ void view_show(View *v, Range r) { assert(view_invariants(v)); assert(ROK(r)); assert(r.p1 <= text_length(v->t)); if (v->scroll) { tile_show(v->tile); } assert(ISVISIBLE(v)); if(!v->scroll) { tag_show(v,r); return; } if(!RISSUBSET(r, v->visible)) { ulong dest; /* try to position range in the middle of the screen */ dest = text_nl(v->t, r.p0, -((int)v->f.maxlines)/2); view_set(v, dest); if (!RINTERSECT(r, v->visible)) { /* lines are too long, quit being fancy, start with line contain 'r' */ dest = text_startOfLine(v->t, r.p0); view_set(v,dest); } if (!RINTERSECT(r, v->visible)) { /* goddamm! we can't even fit a whole line. no more mr nice guy */ view_set(v,r.p0); /* Now _that_ oughta do it! */ } } assert(RINTERSECT(r, v->visible)); assert(view_invariants(v)); assert(ISVISIBLE(v)); } /* Handle a mouse-click in 'v's scrollbar */ void view_scroll(View *v, Mouse *m) { long long y; ulong n,base = v->visible.p0; int lineheight = v->f.font->height; ulong runepos; assert(m->buttons); if (m->xy.y < v->f.r.min.y) m->xy.y = v->f.r.min.y; y = clip(m->xy.y - v->f.r.min.y, 0, Dy(v->f.r)); if (y < v->f.font->height && m->buttons != MIDDLE){ y = lineheight; m->xy.y += lineheight; } runepos = frcharofpt(&v->f, m->xy); /* * With left and middle buttons, we try to scroll back such that * we start at the start of a line. Sometimes that isn't possible, * if lines are too big, so we jump again to some fallback position. * TODO: work this stuff out offscreen. */ switch(m->buttons){ case RIGHT: view_set(v, base + runepos); break; case LEFT: n = back_height(v->t, v->visible.p0, v->f.font, Dx(v->f.r), m->xy.y - v->f.r.min.y); view_set(v, n); break; default: runepos = (text_length(v->t) * y) / Dy(v->f.r); n = text_startOfLine(v->t, runepos); view_set(v, n); if (runepos > v->visible.p1) { view_set(v, runepos); } } } /* Scroll 'v' to the left or right a bit, if possible */ void view_hscroll(View*v, Bool left) { ulong old = v->visible.p0; assert(!v->scroll); assert(ISTAG(v)); if(left){ if(v->visible.p0) v->visible.p0--; } else { if(v->visible.p1 < text_length(v->t)) v->visible.p0++; } if (old != v->visible.p0){ frdelete(&v->f, 0, v->f.nchars); fill(v); } } wily-0.13.42/wily/place.c000064402366570000012000000034351033320152300147150ustar00ozstaff00004330000002/******************************************* * Decide where to place new windows *******************************************/ #include "wily.h" #include "tile.h" enum {TSIZE=401}; static Tile* placetable[TSIZE]; /* hashed array of column tiles */ static Bool iserror(char*label); static Bool validcolumn(Tile*c); static unsigned long hashpath(char *path); static Tile * find(char *label); /* Save the window column for later lookup. */ void placedcol(char*label, Tile *c) { if (label && !iserror(label)) placetable[hashpath(label)] = c; } /* Return the column to use for a new window with label 'path' */ Tile* findcol(char*label) { Tile *c; if(!wily->down){ col_new(wily->tag,0); return wily->down; } if(iserror(label)) return last_visible(wily->down, 0); if (!(c= find(label))) { c = biggest_visible(wily->down, 0); assert(c); placedcol(label, c); } return c; } /****************************************************** static functions ******************************************************/ static Bool iserror(char*label) { static char *errors = "+Errors"; int elen = strlen(errors); int len = strlen(label); return (len >= elen && !strncmp(label + (len - elen), errors, elen)); } /* Is 'c' still a valid pointer for a visible column? */ static Bool validcolumn(Tile*c) { return list_contains(wily->down, 0, c); } /* Hash from directory name into 'placetable' */ static unsigned long hashpath(char *path) { char *s; unsigned long hash = 0; Path fullpath; assert(path); label2path(fullpath, path); path = fullpath; for (s = strrchr(path, '/'); path < s; path++) hash = (hash << 5) ^ *path; return hash % TSIZE; } static Tile * find(char *label) { Tile *c; if (label) { c = placetable[hashpath(label)]; if (validcolumn(c)) return c; } return 0; } wily-0.13.42/wily/keyboard.c000064402366570000012000000061551033320152300154330ustar00ozstaff00004330000002/******************************************* * Handle keystroke events *******************************************/ #include "wily.h" #include "view.h" static void view_cursor(View *v, Rune r); static void addrune(View*v, Rune r); static void tag_cr(View *v); static void backspace(View*v); static void deleteline(View*v); static void deleteword(View*v); static void esc(View*v); void dokeyboard(View *v, Rune r) { switch(r) { case 0: addrune(v,Runeerror); break; case DownArrow: case UpArrow: case Home: case End: case LeftArrow: case RightArrow: view_cursor(v, r); break; case PageDown: case PageUp: view_pagedown(v,r==PageDown); break; case Ctrlh: case Backspace: backspace(v); break; case Ctrlu: deleteline(v); break; case Ctrlw: deleteword(v); break; case Esc: esc(v); break; case '\n': if(!v->scroll){tag_cr(v); break; } default: addrune(v,r); } } /****************************************************** static functions ******************************************************/ /* Handle carriage-return in 'v' * * Select text as if we hit escape, * and either search (if selected text starts with ':') * or execute the selected text. */ static void tag_cr(View*v) { char*cmd; if(!RLEN(v->sel)){ view_select(v, maybereverserange(v->anchor, v->sel.p0)); } cmd = text_duputf(v->t, v->sel); if(cmd[0]==':'){ b3(v, v->sel); } else { if (!data_sendexec(view_data(v),cmd, 0)) run(v, cmd, 0); } free(cmd); } /* delete selection and rune before */ static void backspace(View*v){ Range del = v->sel; if(del.p0) del.p0--; view_cut(v, del); } /* delete selection and back to start of line */ static void deleteline(View*v){ Range del = v->sel; del.p0 = text_startOfLine(v->t, del.p0); view_cut(v, del); } /* delete back to start of word */ static void deleteword(View*v){ Range del = v->sel; del.p0 = text_startofword(v->t, del.p0); view_cut(v, del); } static void esc(View*v) { Range del = v->sel; if ((RLEN(del))) { /* delete selected text */ view_cut(v, del); } else { /* Select from v->anchor to v->sel.p0 */ view_select(v, maybereverserange(v->anchor, v->sel.p0)); view_setlastselection(v); } } static void addrune(View*v, Rune r) { Rstring s; if ( r == '\n' && v->autoindent) { s = text_autoindent(v->t, v->sel.p0); } else { s.r0 = &r; s.r1 = &r +1; } if(RLEN(v->sel)){ snarf(v->t, v->sel); } text_replace(v->t, v->sel, s); view_show(v, v->sel); } /* * We've hit a cursor key. * * Set the selection to something relative to previous sel.p0, and * make sure the new selection is visible. */ static void view_cursor(View *v, Rune r) { ulong p; Point pt; p = v->sel.p0; switch(r) { case LeftArrow: if(p) p--; break; case RightArrow: if (p < text_length(v->t)) p++; break; case DownArrow: case UpArrow: pt = frptofchar(&v->f, p - v->visible.p0); if (r==DownArrow) pt.y += v->f.font->height; else pt.y -= v->f.font->height; p = frcharofpt(&v->f, pt) + v->visible.p0; break; case Home: p = 0; break; case End: p = text_length(v->t); break; } view_select(v, range(p,p)); view_show(v, v->sel); } wily-0.13.42/wily/point.c000064402366570000012000000027631033320152300147650ustar00ozstaff00004330000002/******************************************* * geometry stuff for tiles and views *******************************************/ #include "tile.h" #include "view.h" /* Set 'cmin' and 'cmax' for any child of 'list' */ void setcminmax(Tile *list, int*cmin, int*cmax) { if(list) { *cmin = (list->ori == V)? list->tag->r.max.y + tagheight:list->min; *cmax = list->max; } else { *cmin = 0; *cmax = screen.r.max.x; } } /* Return the Rectangle to enclose 't' */ Rectangle rectangle(Tile*t) { if(t->ori==H) { return Rect(t->min, t->up->tag->r.max.y, t->max, t->up->max); } else if (t->up) { return Rect(t->up->min, t->min, t->up->max, t->max); } else { return Rect(0, t->min, t->cmax, t->max); } } /* Return a point somewhere in the middle of 'tile's button */ Point buttonpos(Tile*tile) { return add(tile->tag->r.min, Pt(SCROLLWIDTH/2, SCROLLWIDTH/2)); } /* Return the tile containing p (or 0) */ Tile* point2tile(Tile *tile, Point p) { int pos; Tile *t; assert(tile); if(tile->body || ptinrect(p, tile->tag->r)) return tile; pos = tile->ori==V ? p.x : p.y ; for (t =tile ->down; t; t=t->right) { if (!tile_hidden(t) && pos < t->max && pos >= t->min) break; } if (t && !tile_hidden(t) && pos > t->min) return point2tile(t,p); return tile; } /* Return the view containing p (or 0) */ View * point2view(Point p) { Tile *t; View *v; t = point2tile(wily, p); if (ptinrect(p, t->tag->r)) v= t->tag; else v = t->body; assert(IMPLIES(v, ptinrect(p, v->r))); return v; } wily-0.13.42/wily/proto.h000064402366570000012000000175711033320152300150070ustar00ozstaff00004330000002/******************************************* * Declarations of major functions and macros *******************************************/ #ifndef SAM_CODE void error(char *, ...); #endif void fatal(char*,...); /* builtins.c */ Bool builtin (View *, char *, char*); /* click.c */ Range text_doubleclick (Text *, ulong); Range text_expand (Text *, Range, char *); ulong text_startofword (Text *, ulong); /* col.c */ Tile* tile_col (Tile*); void col_new (View*v, char *arg); void col_del (Tile*); /* data.c */ Text* data_body (Data*); Text* data_tag (Data*); char** data_names (Data*d); Bool data_isdirty (Data *d); int data_putall (void); int data_backupall (void); int data_put (Data *d, char *path); int data_del (Data*); int data_backup (Data *d); /* env.c */ void env_init (char **); void pathcontract (char*, char *); /* event.c */ void event_wellknown (int); int event_outputstart (int , int , char*, char*, View *); void keytab_init (void); void dofd (ulong, int, char*); void kill_all (char *s); void kill_list (void); /* exec.c */ void ex_init (void); void run (View *, char *, char *); /* file.c */ View * data_open (char*, Bool); int data_get (Data *d, char *); /* include.c */ View* openinclude (View *v, Range r); /* keyboard.c */ void dokeyboard (View *, Rune); void view_pagedown (View *, Bool ); void view_linesdown (View *v, int n, Bool down); /* label.c */ void data_addcontext (Data*, char*, char*); void data_getlabel (Data*, char*); void data_setlabel (Data*, char *); View * data_find (char*); /* line.c */ int text_linenumber (Text *t, ulong ); Bool text_findline (Text *, Range *, ulong); Range text_lastline (Text *); ulong text_nl (Text *, ulong, int); ulong text_startOfLine (Text *, ulong); /* mouse.c */ void domouse (View*, Mouse*); /* msg.c */ void mbuf_init (Mbuf*); void mbuf_clear (Mbuf*); int partialmsg (Mbuf *, int , int , char*); Bool data_sendreplace (Data *,Range r, Rstring ); Bool data_sendgoto (Data *,Range r, char *); Bool data_sendexec (Data *,char*, char *); void data_fdstop (int ); /* path.c */ void labelclean (char*); void label2path (char*,char*); void envexpand (char*, char*); View* openlabel (char*,Bool); /* place.c */ Tile* findcol (char*); void placedcol (char*, Tile*); /* point.c */ Point buttonpos (Tile*tile); /* sam.c */ Bool text_regexp (Text *, Rstring , Range*, Bool ); Bool text_utfregexp (Text *, char*, Range*, Bool ); long Tchars (Text *, Rune *, ulong, ulong); /* scroll.c */ void scroll_update (Scroll *); void scroll_init (void); Scroll * scroll_alloc (Bitmap *, Rectangle); void scroll_setrects (Scroll*, Bitmap *, Rectangle); void scroll_set (Scroll *, ulong , ulong , ulong ); /* search.c */ Bool text_look (Text*, Range*, Range); Bool text_findliteralutf (Text*, Range*, char*); Bool text_findwordutf (Text*, Range*, char*); Bool text_findliteral (Text*, Range*, Rstring); Bool text_findword (Text*, Range*, Rstring); Bool text_search (Text*, Range*, char *, Range); /* select.c */ Range vselect (View *, Mouse *); /* tag.c */ void tag_set (Text *, char*s); void tag_rmtool (Text *, char *); void tag_addtool (Text *, char *); void tag_modified (Text *, ulong); void tag_reset (Text *); void tag_setlabel (Text *, char *); void tag_settools (Text *, char *); char* tag_gettools (Text *); void tag_addrunning (Text *t, char *cmd); /* tagmatch.c */ void tag_init (char *filename); char* tag_match (char*label); /* text.c */ int text_read (Text *, int fd, int len); int text_write_range (Text *, Range, int); void text_copy (Text *, Range, Rune *); Text* text_alloc (Data *, Bool); Range text_replace (Text *, Range, Rstring); void text_free (Text *); /* text2.c */ void text_allread (Text*t); Data* text_data (Text*); View* text_view (Text*t); ulong text_length (Text*); Bool text_needsbackup (Text*); View* text_body (Text*); void text_setneedsbackup(Text*t, Bool b); Bool text_badrange (Text *t, Range r); void text_addview (Text*, View*); int text_rmview (Text*, View*); int text_write (Text *, char *fname); int text_fd (Text*, Range); Rstring text_autoindent (Text *t, ulong p); int back_height (Text *t, ulong, Font *, int, int); Range text_all (Text*t); void text_fillbutton (Text*t, Fcode f); ulong text_ncopy (Text *, Rune*, ulong , ulong ); Range text_replaceutf (Text*, Range, char*); char* text_duputf (Text*, Range); int text_copyutf (Text *, Range, char *); Bool text_refreshdir (Text*t); void text_formatdir (Text *t, char**); /* tile.c */ Bool tile_hidden (Tile*tile); View* tile_body (Tile*tile); void ereshaped (Rectangle); void tile_del (Tile *); void tile_grow (Tile *, int ); void tile_move (Tile *, Point); void tile_setfont (Tile*, char*); void tile_show (Tile *); View* tile_tag (Tile*); void wily_init (void); /* undo.c */ void undo_record (Text*, Range, Rstring); Range undo_undo (Text*, Bool); Range undo_redo (Text*, Bool); void undo_free (Text*); void undo_reset (Text*); void undo_start (Text*); void undo_break (Text*); void undo_mark (Text*); Bool undo_atmark (Text*); /* util.c */ void dirnametrunc (char*); void addcontext (char*, char*, char*); void olabel (char*out, char*label); int statcmp (Stat*a, Stat*b); Bool isdir (char*path); int backup_name (char *orig, char *back); char * columnate (int, int, Font *, char **); void noutput (char *context, char *base, int n); void add_slash (char*); int distance (Point , Point ); Bool frame_isfull (Frame*); void frgetmouse (void); char* mybasename (char*f); Range paste (Text *, Range); Rstring rstring (Rune*r0, Rune*r1); char* select_get (void); void select_put (char*); void snarf (Text *, Range); int stripnulls (char *buf, int len); ulong texttoutf (char *, Rune *, Rune *); ulong utftotext (Rune *, char *, char *); int diag (char*,char*, ...); void cleanup_and_abort (int); void cleanup_and_die (int); int fillutfchar (char*,int,char*,int); int unfullutfbytes (char*,int); Rstring utf2rstring (char*utf); /* vgeom.c */ void filled (View*, Range ); void extend_selection (View*, Range ); void view_fillbutton (View*v, Fcode f); void fill (View*); void view_setscroll (View*); int snapheight (View*v, int h); void view_reshaped (View*, Rectangle); int view_lastlinepos (View*v); int view_stripwhitespace (View*v); /* view.c */ void view_getdot (View *v, char*buf, Bool isLine); void view_paste (View*v); Range view_expand (View *v, Range r, char *s); View* view_new (Font *, Bool, Text *, Tile *); int view_delete (View *v); Bool view_invariants (View*v); Data* view_data (View*); View* view_body (View*); Tile* view_win (View*); Tile* view_tile (View*); Text* view_text (View*); Range view_getsel (View*); int view_height (View*); void view_cut (View*, Range r); void view_append (View*, char *, int); void view_pipe (View*, Bool *, char *, int); void view_setfont (View*, char*arg); void view_border (View*, Bool); void view_select (View*, Range); void view_warp (View*, Range); void view_setlastselection(View *v); void viewlist_refresh (View*); void viewlist_replace (View*, Range, Rstring); /* vsearch.c */ void b3 (View*, Range r); void view_look (View*, char*); Bool view_goto (View**, Range *r, char *s); /* vshow.c */ void view_show (View*, Range); void view_scroll (View *, Mouse *); void view_hscroll (View*v, Bool left); /* wily.c */ void addrunning (char *cmd); void rmrunning (char *cmd); /* win.c */ int win_del (Tile*); Tile* tile_win (Tile*); void win_clone (Tile*); void win_anchor (Tile*, char *); void win_new (char*, Text*, Text*); #define RECTOK(r) (Dx(r)>=0 && Dy(r) >= 0) #define cls(r) bitblt(&screen, (r).min, &screen, (r), Zero) #define SETSIZE(buf, n, desired) {if(n literal, otherwise action */ union { int rsid; int rsubid; int class; struct Inst *rother; struct Inst *rright; } r; union{ struct Inst *lleft; struct Inst *lnext; } l; }; #define sid r.rsid #define subid r.rsubid #define rclass r.class #define other r.rother #define right r.rright #define left l.lleft #define next l.lnext #define NPROG 1024 Inst program[NPROG]; Inst *progp; Inst *startinst; /* First inst. of program; might not be program[0] */ Inst *bstartinst; /* same for backwards machine */ typedef struct Ilist Ilist; struct Ilist { Inst *inst; /* Instruction of the thread */ samRangeset se; Posn startp; /* first char of match */ }; #define NLIST 128 Ilist *tl, *nl; /* This list, next list */ Ilist list[2][NLIST]; static samRangeset sempty; /* * Actions and Tokens * * 0x100xx are operators, value == precedence * 0x200xx are tokens, i.e. operands for operators */ enum { OPERATOR = 0x10000, /* Bitmask of all operators */ START = 0x10000, /* Start, used for marker on stack */ RBRA = 0x10001, /* Right bracket, ) */ LBRA = 0x10002, /* Left bracket, ( */ OR = 0x10003, /* Alternation, | */ CAT = 0x10004, /* Concatentation, implicit operator */ STAR = 0x10005, /* Closure, * */ PLUS = 0x10006, /* a+ == aa* */ QUEST = 0x10007, /* a? == a|nothing, i.e. 0 or 1 a's */ ANY = 0x20000, /* Any character but newline, . */ NOP = 0x20001, /* No operation, internal use only */ BOL = 0x20002, /* Beginning of line, ^ */ EOL = 0x20003, /* End of line, $ */ CCLASS = 0x20004, /* Character class, [] */ NCCLASS = 0x20005, /* Negated character class, [^] */ END = 0x20077, /* Terminate: match found */ ISATOR = 0x10000, ISAND = 0x20000 }; /* * Parser Information */ typedef struct Node Node; struct Node { Inst *first; Inst *last; }; #define NSTACK 20 Node andstack[NSTACK]; Node *andp; int atorstack[NSTACK]; int *atorp; int lastwasand; /* Last token was operand */ int cursubid; int subidstack[NSTACK]; int *subidp; int backwards; int nbra; Rune *exprp; /* pointer to next character in source expression */ #define DCLASS 10 /* allocation increment */ int nclass; /* number active */ int Nclass; /* high water mark */ Rune **class; int negateclass; void addinst(Ilist *l, Inst *inst, samRangeset *sep); void newmatch(samRangeset*); void bnewmatch(samRangeset*); void pushand(Inst*, Inst*); void pushator(int); Node *popand(int); int popator(void); void startlex(Rune*); int lex(void); void operator(int); void operand(int); void evaluntil(int); void optimize(Inst*); void bldcclass(void); void regerror(Err e) { Strzero(&lastregexp); error(e); } void regerror_c(Err e, int c) { Strzero(&lastregexp); error_c(e, c); } Inst * newinst(int v) { if(progp >= &program[NPROG]) regerror(Etoolong); progp->type = v; progp->left = 0; progp->right = 0; return progp++; } Inst * realcompile(Rune *s) { int token; startlex(s); atorp = atorstack; andp = andstack; subidp = subidstack; cursubid = 0; lastwasand = FALSE; /* Start with a low priority operator to prime parser */ pushator(START-1); while((token=lex()) != END){ if((token&ISATOR) == OPERATOR) operator(token); else operand(token); } /* Close with a low priority operator */ evaluntil(START); /* Force END */ operand(END); evaluntil(START); if(nbra) regerror(Eleftpar); --andp; /* points to first and only operand */ return andp->first; } void compile(String *s) { int i; Inst *oprogp; if(Strcmp(s, &lastregexp)==0) return; for(i=0; is); optimize(program); oprogp = progp; backwards = TRUE; bstartinst = realcompile(s->s); optimize(oprogp); Strduplstr(&lastregexp, s); } void operand(int v) { Inst *i; if(lastwasand) operator(CAT); /* catenate is implicit */ i = newinst(v); if(v == CCLASS){ if(negateclass) i->type = NCCLASS; /* UGH */ i->rclass = nclass-1; /* UGH */ } pushand(i, i); lastwasand = TRUE; } void operator(int v) { if(v==RBRA && --nbra<0) regerror(Erightpar); if(v==LBRA){ /* * if(++cursubid >= NSUBEXP) * regerror(Esubexp); */ cursubid++; /* silently ignored */ nbra++; if(lastwasand) operator(CAT); }else evaluntil(v); if(v!=RBRA) pushator(v); lastwasand = FALSE; if(v==STAR || v==QUEST || v==PLUS || v==RBRA) lastwasand = TRUE; /* these look like operands */ } void cant(char *s) { char buf[100]; sprint(buf, "regexp: can't happen: %s", s); panic(buf); } void pushand(Inst *f, Inst *l) { if(andp >= &andstack[NSTACK]) cant("operand stack overflow"); andp->first = f; andp->last = l; andp++; } void pushator(int v) { if(atorp >= &atorstack[NSTACK]) cant("operator stack overflow"); *atorp++=v; if(cursubid >= NSUBEXP) *subidp++= -1; else *subidp++=cursubid; } Node * popand(int op) { if(andp <= &andstack[0]) if(op) regerror_c(Emissop, op); else regerror(Ebadregexp); return --andp; } int popator(void) { if(atorp <= &atorstack[0]) cant("operator stack underflow"); --subidp; return *--atorp; } void evaluntil(int pri) { Node *op1, *op2, *v; Inst *inst1, *inst2; while(pri==RBRA || atorp[-1]>=pri){ switch(popator()){ case LBRA: op1 = popand('('); inst2 = newinst(RBRA); inst2->subid = *subidp; op1->last->next = inst2; inst1 = newinst(LBRA); inst1->subid = *subidp; inst1->next = op1->first; pushand(inst1, inst2); return; /* must have been RBRA */ default: panic("unknown regexp operator"); break; case OR: op2 = popand('|'); op1 = popand('|'); inst2 = newinst(NOP); op2->last->next = inst2; op1->last->next = inst2; inst1 = newinst(OR); inst1->right = op1->first; inst1->left = op2->first; pushand(inst1, inst2); break; case CAT: op2 = popand(0); op1 = popand(0); if(backwards && op2->first->type!=END) v = op1, op1 = op2, op2 = v; op1->last->next = op2->first; pushand(op1->first, op2->last); break; case STAR: op2 = popand('*'); inst1 = newinst(OR); op2->last->next = inst1; inst1->right = op2->first; pushand(inst1, inst1); break; case PLUS: op2 = popand('+'); inst1 = newinst(OR); op2->last->next = inst1; inst1->right = op2->first; pushand(op2->first, inst1); break; case QUEST: op2 = popand('?'); inst1 = newinst(OR); inst2 = newinst(NOP); inst1->left = inst2; inst1->right = op2->first; op2->last->next = inst2; pushand(inst1, inst2); break; } } } void optimize(Inst *start) { Inst *inst, *target; for(inst=start; inst->type!=END; inst++){ target = inst->next; while(target->type == NOP) target = target->next; inst->next = target; } } #ifdef DEBUG void dumpstack(void){ Node *stk; int *ip; dprint("operators\n"); for(ip = atorstack; ipfirst->type, stk->last->type); } void dump(void){ Inst *l; l = program; do{ dprint("%d:\t0%o\v%d\v%d\n", l-program, l->type, l->left-program, l->right-program); }while(l++->type); } #endif void startlex(Rune *s) { exprp = s; nbra = 0; } int lex(void){ int c= *exprp++; switch(c){ case '\\': if(*exprp) if((c= *exprp++)=='n') c='\n'; break; case 0: c = END; --exprp; /* In case we come here again */ break; case '*': c = STAR; break; case '?': c = QUEST; break; case '+': c = PLUS; break; case '|': c = OR; break; case '.': c = ANY; break; case '(': c = LBRA; break; case ')': c = RBRA; break; case '^': c = BOL; break; case '$': c = EOL; break; case '[': c = CCLASS; bldcclass(); break; } return c; } long nextrec(void){ if(exprp[0]==0 || (exprp[0]=='\\' && exprp[1]==0)) regerror(Ebadclass); if(exprp[0] == '\\'){ exprp++; if(*exprp=='n'){ exprp++; return '\n'; } return *exprp++|0x10000; } return *exprp++; } void bldcclass(void) { long c1, c2, n, na; Rune *classp; classp = emalloc(DCLASS*RUNESIZE); n = 0; na = DCLASS; /* we have already seen the '[' */ if(*exprp == '^'){ classp[n++] = '\n'; /* don'v match newline in negate case */ negateclass = TRUE; exprp++; }else negateclass = FALSE; while((c1 = nextrec()) != ']'){ if(c1 == '-'){ Error: free(classp); regerror(Ebadclass); } if(n+4 >= na){ /* 3 runes plus NUL */ na += DCLASS; classp = erealloc(classp, na*RUNESIZE); } if(*exprp == '-'){ exprp++; /* eat '-' */ if((c2 = nextrec()) == ']') goto Error; classp[n+0] = 0xFFFF; classp[n+1] = c1; classp[n+2] = c2; n += 3; }else classp[n++] = c1; } classp[n] = 0; if(nclass == Nclass){ Nclass += DCLASS; class = erealloc(class, Nclass*sizeof(Rune*)); } class[nclass++] = classp; } int classmatch(int classno, int c, int negate) { Rune *w; w = class[classno]; while(*w){ if(*w == 0xFFFF){ if(w[1]<=c && c<=w[2]) return !negate; w += 3; }else if(*w++ == c) return !negate; } return negate; } /* * Note optimization in addinst: * *l must be pending when addinst called; if *l has been looked * at already, the optimization is a bug. */ void addinst(Ilist *l, Inst *inst, samRangeset *sep) { Ilist *w; for(w = l; w->inst; w++){ if(w->inst==inst){ if((sep)->w[0].p1 < w->se.w[0].p1) w->se= *sep; /* this would be bug */ return; /* It's already there */ } } w->inst = inst; w->se= *sep; (w+1)->inst = 0; } int execute(File *f, Posn startp, Posn eof) { int flag = 0; Inst *inst; Ilist *tlp; Posn w = startp; int nnl = 0, ntl; int c; int wrapped = 0; int startchar = startinst->typetype : 0; list[0][0].inst = list[1][0].inst = 0; sel.w[0].p1 = -1; Fgetcset(f, startp); /* Execute machine once for each character */ for(;;w++){ doloop: c = Fgetc(f); if(w>=eof || c<0){ switch(wrapped++){ case 0: /* let loop run one more click */ case 2: break; case 1: /* expired; wrap to beginning */ if(sel.w[0].p1>=0 || eof!=INFINITY) goto Return; list[0][0].inst = list[1][0].inst = 0; Fgetcset(f, (Posn)0); w = 0; goto doloop; default: goto Return; } }else if(((wrapped && w>=startp) || sel.w[0].p1>0) && nnl==0) break; /* fast check for first char */ if(startchar && nnl==0 && c!=startchar) continue; tl = list[flag]; nl = list[flag^=1]; nl->inst = 0; ntl = nnl; nnl = 0; if(sel.w[0].p1<0 && (!wrapped || w= NLIST) Overflow: error(Eoverflow); sempty.w[0].p1 = w; addinst(tl, startinst, &sempty); } /* Execute machine until this list is empty */ for(tlp = tl; (inst = tlp->inst) ; tlp++){ /* assignment = */ Switchstmt: switch(inst->type){ default: /* regular character */ if(inst->type==c){ Addinst: if(++nnl >= NLIST) goto Overflow; addinst(nl, inst->next, &tlp->se); } break; case LBRA: if(inst->subid>=0) tlp->se.w[inst->subid].p1 = w; inst = inst->next; goto Switchstmt; case RBRA: if(inst->subid>=0) tlp->se.w[inst->subid].w2 = w; inst = inst->next; goto Switchstmt; case ANY: if(c!='\n') goto Addinst; break; case BOL: if(w == 0){ Step: inst = inst->next; goto Switchstmt; } { Rune c2; if(Fchars(f, &c2, w-1, w)==1 && c2=='\n') goto Step; } break; case EOL: if(c == '\n') goto Step; break; case CCLASS: if(c>=0 && classmatch(inst->rclass, c, 0)) goto Addinst; break; case NCCLASS: if(c>=0 && classmatch(inst->rclass, c, 1)) goto Addinst; break; case OR: /* evaluate right choice later */ if(++ntl >= NLIST) goto Overflow; addinst(tlp, inst->right, &tlp->se); /* efficiency: advance and re-evaluate */ inst = inst->left; goto Switchstmt; case END: /* Match! */ tlp->se.w[0].w2 = w; newmatch(&tlp->se); break; } } } Return: return sel.w[0].p1>=0; } void newmatch(samRangeset *sp) { int i; if(sel.w[0].p1<0 || sp->w[0].p1w[0].p1==sel.w[0].p1 && sp->w[0].w2>sel.w[0].w2)) for(i = 0; iw[i]; } int bexecute(File *f, Posn startp) { int flag = 0; Inst *inst; Ilist *tlp; Posn w = startp; int nnl = 0, ntl; int c; int wrapped = 0; int startchar = bstartinst->typetype : 0; list[0][0].inst = list[1][0].inst = 0; sel.w[0].p1= -1; Fgetcset(f, startp); /* Execute machine once for each character, including terminal NUL */ for(;;--w){ doloop: if((c = Fbgetc(f))==-1){ switch(wrapped++){ case 0: /* let loop run one more click */ case 2: break; case 1: /* expired; wrap to end */ if(sel.w[0].p1>=0) case 3: goto Return; list[0][0].inst = list[1][0].inst = 0; Fgetcset(f, f->nrunes); w = f->nrunes; goto doloop; default: goto Return; } }else if(((wrapped && w<=startp) || sel.w[0].p1>0) && nnl==0) break; /* fast check for first char */ if(startchar && nnl==0 && c!=startchar) continue; tl = list[flag]; nl = list[flag^=1]; nl->inst = 0; ntl = nnl; nnl = 0; if(sel.w[0].p1<0 && (!wrapped || w>startp)){ /* Add first instruction to this list */ if(++ntl >= NLIST) Overflow: error(Eoverflow); /* the minus is so the optimizations in addinst work */ sempty.w[0].p1 = -w; addinst(tl, bstartinst, &sempty); } /* Execute machine until this list is empty */ for(tlp = tl; (inst = tlp->inst); tlp++){ /* assignment = */ Switchstmt: switch(inst->type){ default: /* regular character */ if(inst->type == c){ Addinst: if(++nnl >= NLIST) goto Overflow; addinst(nl, inst->next, &tlp->se); } break; case LBRA: if(inst->subid>=0) tlp->se.w[inst->subid].p1 = w; inst = inst->next; goto Switchstmt; case RBRA: if(inst->subid >= 0) tlp->se.w[inst->subid].w2 = w; inst = inst->next; goto Switchstmt; case ANY: if(c != '\n') goto Addinst; break; case BOL: if(c=='\n' || w==0){ Step: inst = inst->next; goto Switchstmt; } break; case EOL: if(wnrunes-1){ Rune c2; if(Fchars(f, &c2, w, w+1)==1 && c2=='\n') goto Step; } break; case CCLASS: if(c>=0 && classmatch(inst->rclass, c, 0)) goto Addinst; break; case NCCLASS: if(c>=0 && classmatch(inst->rclass, c, 1)) goto Addinst; break; case OR: /* evaluate right choice later */ if(++ntl >= NLIST) goto Overflow; addinst(tlp, inst->right, &tlp->se); /* efficiency: advance and re-evaluate */ inst = inst->left; goto Switchstmt; case END: /* Match! */ tlp->se.w[0].p1 = -tlp->se.w[0].p1; /* minus sign */ tlp->se.w[0].w2 = w; bnewmatch(&tlp->se); break; } } } Return: return sel.w[0].p1>=0; } void bnewmatch(samRangeset *sp) { int i; if(sel.w[0].p1<0 || sp->w[0].p1>sel.w[0].w2 || (sp->w[0].p1==sel.w[0].w2 && sp->w[0].w2w[i].w2; sel.w[i].w2 = sp->w[i].p1; } } wily-0.13.42/wily/click.c000064402366570000012000000066201033320152300147150ustar00ozstaff00004330000002/******************************************* * Handle double-click, etc. *******************************************/ #include "wily.h" #include "text.h" #include /* Matching brackets for double-click */ static Rune l1[] = { '{', '[', '(', '<', 0253, 0}; static Rune r1[] = {'}', ']', ')', '>', 0273, 0}; static Rune l2[] = { '\n', 0}; static Rune r2[] = {'\n', 0}; static Rune l3[] = { '\'', '"', '`', '>', 0}; static Rune r3[] = {'\'', '"', '`', '<', 0}; Rune *left[]= { l1, l2, l3, 0}; Rune *right[]= { r1, r2, r3, 0}; /* Return false if 'c' is obviously not an alphanumeric character, * or if it is in the stoplist. */ static Bool okchar(int c, char *stoplist) { /* * Hard to get absolutely right. Use what we know about ASCII * and assume anything above the Latin control characters is * potentially an alphanumeric. */ if(c <= ' ') return false; if(0x7F<=c && c<=0xA0) return false; if(utfrune(stoplist, c)) return false; return 1; } static int clickmatch(Text *t, int cl, int cr, int dir) { int c, nest; nest=1; while((c=(dir>0? Tgetc(t) : Tbgetc(t))) > 0) { if(cl=='\n' && c==0x04) /* EOT is trouble */ return 1; if(c == cr){ if(--nest == 0) return 1; }else if(c == cl) nest++; } return cl=='\n' && nest==1; } static Rune * strrune(Rune *s, Rune c) { Rune c1; if(c == 0) { while(*s++) ; return s-1; } while( (c1 = *s++)) if(c1 == c) return s-1; return 0; } /* Expand the selection (pp0-pp1) left and right, stopping * at characters that aren't alphanumeric or are in the stop list 's' */ Range text_expand(Text *t, Range r, char *s) { int c; assert(ROK(r)); Tgetcset(t, r.p1); while( (c = Tgetc(t)) !=-1 && okchar(c,s)) r.p1++; Tbgetcset(t, r.p0); while((c = Tbgetc(t)) != -1 && okchar(c,s)) r.p0--; return r; } /* * Expand a doubleclick at p0, return the resulting range. */ Range text_doubleclick(Text *t, ulong p0) { int c, i; Rune *r, *l; Range dot; assert (p0 <= t->length); dot.p0 = dot.p1 = p0; for(i=0; left[i]; i++){ l = left[i]; r = right[i]; /* try left match */ if(p0 == 0){ Tgetcset(t, p0); c = '\n'; }else{ Tgetcset(t, p0-1); c = Tgetc(t); } if(c!=-1 && strrune(l, c)){ if(clickmatch(t, c, r[strrune(l, c)-l], 1)){ dot.p0 = p0; dot.p1 = t->pos-(c!='\n'); } assert(ROK(dot)); return dot; } /* try right match */ if(p0 == t->length){ Tbgetcset(t, p0); c = '\n'; }else{ Tbgetcset(t, p0+1); c = Tbgetc(t); } if(c !=-1 && strrune(r, c)){ if(clickmatch(t, c, l[strrune(r, c)-r], -1)){ dot.p0 = t->pos; if(c!='\n' || t->pos!=0 || (Tgetcset(t, 0),Tgetc(t))=='\n') dot.p0++; dot.p1 = p0+(p0length && c=='\n'); } assert(ROK(dot)); return dot; } } /* try filling out word to right */ Tgetcset(t, p0); while((c=Tgetc(t))!=-1 && okchar(c, notdoubleclick)) dot.p1++; /* try filling out word to left */ Tbgetcset(t, p0); while((c=Tbgetc(t))!=-1 && okchar(c, notdoubleclick)) dot.p0--; assert(ROK(dot)); return dot; } /* * Find start of word, going back from p0. */ ulong text_startofword(Text *t, ulong p0) { int c; Tbgetcset(t, p0); /* skip over special chars then skip until special char */ while ( (c=Tbgetc(t))!=-1 && c != '\n' && !okchar(c, notdoubleclick) ) ; if(c=='\n' && (t->pos != p0-1)) return t->pos + 1; while ( (c=Tbgetc(t))!=-1 && okchar(c, notdoubleclick) ) ; return t->pos + (c!=-1); } wily-0.13.42/wily/Makefile000064402366570000012000000032151041526267400151400ustar00ozstaff00004330000002# Generated automatically from Makefile.in by configure. SHELL=/bin/sh srcdir=. prefix = /usr/local LIBS=-lsocket -lnsl exec_prefix = ${prefix} # Directory in which to install scripts. bindir = $(exec_prefix)/bin CC=gcc RANLIB=ranlib INCLUDES= -I.. -I$(srcdir)/../include -I/usr/openwin/include OPTS=-DNDEBUG CFLAGS= -g -O $(OPTS) $(INCLUDES) TARGET=wily OBJECTS= env.o include.o label.o file.o msg.o data.o line.o\ vgeom.o vsearch.o vshow.o \ tagmatch.o place.o event.o exec.o dir.o \ point.o global.o cursor.o scroll.o path.o keyboard.o \ wily.o tag.o view.o grow.o adjust.o win.o list.o col.o\ undo.o builtins.o util.o select.o\ mouse.o regexp.o text2.o \ sam.o text.o click.o tile.o search.o MYLIBS=../libmsg/libmsg.a ../libframe/libframe.a ../libXg/libXg.a XLIBS=$(LIBS) -L/usr/openwin/lib -R/usr/openwin/lib -lXt -lSM -lICE -lX11 -lnsl -lsocket all: $(TARGET) $(TARGET): $(OBJECTS) $(MYLIBS) $(CC) $(LDFLAGS) -o $(TARGET) $(OBJECTS) $(MYLIBS) $(XLIBS) pure: $(OBJECTS) $(MYLIBS) purify $(CC) $(LDFLAGS) -o $(TARGET) $(OBJECTS) $(MYLIBS) $(XLIBS) $(OBJECTS): wily.h const.h proto.h ../include/msg.h builtins.o keyboard.o mouse.o tag.o text.o text2.o tile.o view.o: view.h keyboard.o search.o tag.o text.o text2.o undo.o view.o line.o click.o : text.h tile.o grow.o adjust.o win.o col.o list.o: tile.h point.o: tile.h view.h sam.o regexp.o: sam.h file.o msg.o data.o label.o : data.h adjust.o builtins.o keyboard.o mouse.o point.o select.o tag.o text2.o tile.o vgeom.o view.o vsearch.o vshow.o : view.h clean: rm -f *.o core *pure* nuke: clean rm -f $(TARGET) dist: nuke cp -r `ls |grep -v RCS` ../dist/wily install: $(TARGET) cp $(TARGET) $(bindir) wily-0.13.42/.exclude000064402366570000012000000000521033320152300141230ustar00ozstaff00004330000002include/RCS wily/RCS libmsg/RCS libXg/RCS wily-0.13.42/aclocal.m4000064402366570000012000000007211033320152300143340ustar00ozstaff00004330000002dnl AC_CHECK_HAVE_TYPE(TYPE) AC_DEFUN(AC_CHECK_HAVE_TYPE, [AC_REQUIRE([AC_HEADER_STDC])dnl AC_MSG_CHECKING(for $1) AC_CACHE_VAL(ac_cv_type_$1, [ AC_EGREP_CPP($1 *;, [#include #if STDC_HEADERS #include #endif], ac_cv_type_$1=yes, ac_cv_type_$1=no)])dnl AC_MSG_RESULT($ac_cv_type_$1) if test $ac_cv_type_$1 = yes; then changequote(<,>)dnl ac_type=HAVE_`echo $1 | tr '[a-z]' '[A-Z]'` changequote([,])dnl AC_DEFINE_UNQUOTED($ac_type) fi ]) wily-0.13.42/libXg/000075502366570000012000000000001041526267400135605ustar00ozstaff00004330000002wily-0.13.42/libXg/libgint.h000064402366570000012000000053311033320152300153440ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ /* internal libg implementation file - include after libg */ /* * include defs of standard library routines, if possible, * and string routines */ #ifdef HAVE_STDLIB_H #include #endif #ifdef STDC_HEADERS #include #endif /* STDC_HEADERS */ /* * use defines to rename X11 types Cursor, Font, Event */ #define Cursor xCursor #define Font xFont #define Event xEvent #if defined(v10) || defined(HPUX) typedef char* caddr_t; #endif #include #include #include #undef Cursor #undef Font #undef Event /* Return a GCs for solid filling/strings/etc., segments/points, and tiling */ extern GC _getfillgc(Fcode, Bitmap*, unsigned long); extern GC _getcopygc(Fcode, Bitmap*, Bitmap*, int*); extern GC _getgc(Bitmap*, unsigned long, XGCValues *); /* convert between different bitmap depths */ extern void _ldconvert(char *, int, char *, int, int, int); /* balloc without zero init (which uses a gc!) */ extern Bitmap *_balloc(Rectangle, int); /* X Display for this application's connection */ extern Display *_dpy; /* screen depth foreground and background for this application */ extern unsigned long _fgpixel, _bgpixel; extern XColor _fgcolor, _bgcolor; /* indexed by log depth (0 <= ld <= 5), to give depth and planemask */ extern int _ld2d[]; extern unsigned long _ld2dmask[]; /* libg.h defines: * extern Bitmap screen; -- Bitmap for application Window after xbinit() * extern Font *font; -- Font for application default font after xbinit() */ /* * Conventions: * The .id field of a Bitmap is an X Pixmap unless the Bitmap is screen, * in which case it is a Window. * The .id field of a Cursor is set to the X xCursor the first time the * cursor is used. * The .id field of a Font is set to the X xFont. * * Coordinate conventions: libg bitmaps can have non (0,0) origins, * but not X Pixmaps, so we have to subtract the min point of a Bitmap * from coords in the Bitmap before using the point in the corresponding Pixmap. * The screen Bitmap, however, contains the rectangle in X coords of the * widget in which the application is started, relative to the window. * The origin may or may not be (0,0), but in any case, coordinates should * NOT be translated before using in X calls on the Window. */ /* values for bitmap flag field (see _getcopygc if change first two vals) */ enum { DP1= 0x1, /* depth == 1 (ldepth == 0) */ BL1= 0x2, /* black == 1 model */ SCR= 0x4, /* on screen */ ZORG= 0x8, /* r.min == Pt(0,0) */ SHIFT= 0x20, /* !SCR & !ZORG */ CLIP= 0x40 /* r != clipr */ }; /* values for return bltfunc arg of _getcopygc */ enum { UseCopyArea, UseCopyPlane, UseFillRectangle }; wily-0.13.42/libXg/rdbitmapfile.c000064402366570000012000000024271033320152300163540ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include "libgint.h" #define CHUNK 6000 Bitmap* rdbitmapfile(int fd) { char hdr[5*12+1]; unsigned char *data; long dy, px; unsigned long l, t, n; long miny, maxy; Rectangle r; int ld; Bitmap *b; if(read(fd, hdr, 5*12)!=5*12) berror("rdbitmapfile read"); ld = atoi(hdr+0*12); r.min.x = atoi(hdr+1*12); r.min.y = atoi(hdr+2*12); r.max.x = atoi(hdr+3*12); r.max.y = atoi(hdr+4*12); if(ld<0 || ld>1) berror("rdbitmapfile ldepth"); if(r.min.x>r.max.x || r.min.y>r.max.y) berror("rdbitmapfile rectangle"); miny = r.min.y; maxy = r.max.y; px = 1<<(3-ld); /* pixels per byte */ /* set l to number of bytes of data per scan line */ if(r.min.x >= 0) l = (r.max.x+px-1)/px - r.min.x/px; else{ /* make positive before divide */ t = (-r.min.x)+px-1; t = (t/px)*px; l = (t+r.max.x+px-1)/px; } b = balloc(r, ld); if(b == 0) return 0; data = (unsigned char *)malloc(CHUNK); if(data == 0) berror("rdbitmapfile malloc"); while(maxy > miny){ dy = maxy - miny; if(dy*l > CHUNK) dy = CHUNK/l; n = dy*l; if(read(fd, data, n) != n){ free(data); bfree(b); berror("rdbitmapfile read"); } wrbitmap(b, miny, miny+dy, data); miny += dy; } free(data); return b; } wily-0.13.42/libXg/GwinP.h000064402366570000012000000020751033320152300147420ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #ifndef GWINP_H #define GWINP_H #include "Gwin.h" /* Gwin is derived from Core */ /* Gwin instance part */ typedef struct { /* New resource fields */ Pixel foreground; Font font; Boolean forwardr; /* does right button scroll forward? */ Reshapefunc reshaped; /* Notify app of reshape */ Charfunc gotchar; /* Notify app of char arrival */ Mousefunc gotmouse; /* Notify app of mouse change */ String selection; /* Current selection */ String p9font; String p9fixed; int compose; } GwinPart; /* Full instance record */ typedef struct _GwinRec { CorePart core; GwinPart gwin; } GwinRec; /* New type for class methods */ typedef String (*SelSwapProc)(Widget, String); /* Class part */ typedef struct { SelSwapProc select_swap; XtPointer extension; } GwinClassPart; /* Full class record */ typedef struct _GwinClassRec { CoreClassPart core_class; GwinClassPart gwin_class; } GwinClassRec, *GwinWidgetClass; /* External definition for class record */ extern GwinClassRec gwinClassRec; #endif /* GWINP_H */ wily-0.13.42/libXg/bitblt.c000064402366570000012000000026101033320152300151640ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include "libgint.h" void bitblt(Bitmap *d, Point p, Bitmap *s, Rectangle r, Fcode f) { int sx, sy, dx, dy, bfunc; GC g; unsigned long plane; Bitmap *btmp; if(Dx(r)<=0 || Dy(r)<=0) return; sx = r.min.x; sy = r.min.y; if(s->flag&SHIFT){ sx -= s->r.min.x; sy -= s->r.min.y; } dx = p.x; dy = p.y; if(d->flag&SHIFT){ dx -= d->r.min.x; dy -= d->r.min.y; } g = _getcopygc(f, d, s, &bfunc); if(bfunc == UseCopyArea) XCopyArea(_dpy, (Drawable)s->id, (Drawable)d->id, g, sx, sy, Dx(r), Dy(r), dx, dy); else if(bfunc == UseFillRectangle){ XFillRectangle(_dpy, (Drawable)d->id, g, dx, dy, Dx(r), Dy(r)); }else{ /* bfunc == UseCopyPlane */ plane = _ld2dmask[s->ldepth]; plane &= ~(plane>>1); if(0/*f == S*/) XCopyPlane(_dpy, (Drawable)s->id, (Drawable)d->id, g, sx, sy, Dx(r), Dy(r), dx, dy, plane); else { /* * CopyPlane can only do func code S, * so copy src rect into a bitmap with the same depth * as the dest, then do the bitblt from the tmp. * This won't recurse again because we only get * UseCopyPlane with differing bitmap depths */ btmp = _balloc(Rect(0,0,Dx(r),Dy(r)), d->ldepth); XCopyPlane(_dpy, (Drawable)s->id, (Drawable)btmp->id, g, sx, sy, Dx(r), Dy(r), 0, 0, plane); bitblt(d, p, btmp, btmp->r, f); bfree(btmp); } } } wily-0.13.42/libXg/Gwin.h000064402366570000012000000022411033320152300146150ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #ifndef GWIN_H #define GWIN_H /* New resource names */ #define XtNscrollForwardR "scrollForwardR" #define XtCScrollForwardR "ScrollForwardR" #define XtNreshaped "reshaped" #define XtCReshaped "Reshaped" #define XtNgotchar "gotchar" #define XtCGotchar "Gotchar" #define XtNgotmouse "gotmouse" #define XtCGotmouse "Gotmouse" #define XtNp9font "p9font" #define XtCP9font "P9font" #define XtNp9fixed "p9fixed" #define XtCP9fixed "P9fixed" #define XtNcomposeMod "composeMod" #define XtCComposeMod "ComposeMod" /* External reference to the class record pointer */ extern WidgetClass gwinWidgetClass; /* Type definition for gwin widgets */ typedef struct _GwinRec *GwinWidget; /* Type definition for gwin resources */ typedef struct { int buttons; struct { int x; int y; } xy; unsigned long msec; } Gwinmouse; typedef void (*Reshapefunc)(int, int, int, int); typedef void (*Charfunc)(int); typedef void (*Mousefunc)(Gwinmouse*); /* Method declarations */ extern String GwinSelectionSwap(Widget, String); extern char* Gwinselect_get(Widget w); extern void Gwinselect_put(Widget w,char*s); #endif /* GWIN_H */ wily-0.13.42/libXg/menuhit.c000064402366570000012000000137451033320152300153700ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include #include "libgint.h" enum { Margin = 3, /* outside to text */ Border = 2, /* outside to selection boxes */ Blackborder = 1, /* width of outlining border */ Vspacing = 1, /* extra spacing between lines of text */ Maxunscroll = 25, /* maximum #entries before scrolling turns on */ Nscroll = 20, /* number entries in scrolling part */ Scrollwid = 14, /* width of scroll bar */ Gap = 4 /* between text and scroll bar */ }; static Bitmap *menutxt; static uchar menutxtbits[] = { 0x22, 0x22, 0x88, 0x88, 0x22, 0x22, 0x88, 0x88, 0x22, 0x22, 0x88, 0x88, 0x22, 0x22, 0x88, 0x88, 0x22, 0x22, 0x88, 0x88, 0x22, 0x22, 0x88, 0x88, 0x22, 0x22, 0x88, 0x88, 0x22, 0x22, 0x88, 0x88, }; /* * r is a rectangle holding the text elements. * return the rectangle, including its black edge, holding element i. */ static Rectangle menurect(Rectangle r, int i) { if(i < 0) return Rect(0, 0, 0, 0); r.min.y += (font->height+Vspacing)*i; r.max.y = r.min.y+font->height+Vspacing; return inset(r, Border-Margin); } /* * r is a rectangle holding the text elements. * return the element number containing p. */ static int menusel(Rectangle r, Point p) { if(!ptinrect(p, r)) return -1; return (p.y-r.min.y)/(font->height+Vspacing); } /* * menur is a rectangle holding all the highlightable text elements. * track mouse while inside the box, return what's selected when button * is raised, -1 as soon as it leaves box. * invariant: nothing is highlighted on entry or exit. */ static int menuscan(int but, Mouse *m, Rectangle menur, int lasti) { int i; Rectangle r; r = menurect(menur, lasti); bitblt(&screen, r.min, &screen, r, F&~D); *m = emouse(); while(m->buttons & (1<<(but-1))){ *m = emouse(); i = menusel(menur, m->xy); if(i == lasti) continue; bitblt(&screen, r.min, &screen, r, F&~D); if(i == -1) return i; r = menurect(menur, i); bitblt(&screen, r.min, &screen, r, F&~D); lasti = i; } return lasti; } void menupaint(Menu *menu, Rectangle textr, int off, int nitemdrawn) { int i; Point pt; Rectangle r; char *item; r = inset(textr, Border-Margin); bitblt(&screen, r.min, &screen, r, 0); pt = Pt(textr.min.x+textr.max.x, textr.min.y); for(i = 0; iheight+Vspacing){ item = menu->item? menu->item[i+off] : (*menu->gen)(i+off); string(&screen, Pt((pt.x-strwidth(font, item))/2, pt.y), font, item, S); } } static void menuscrollpaint(Rectangle scrollr, int off, int nitem, int nitemdrawn) { Rectangle r; bitblt(&screen, scrollr.min, &screen, scrollr, 0); r.min.x = scrollr.min.x; r.max.x = scrollr.max.x; r.min.y = scrollr.min.y + (Dy(scrollr)*off)/nitem; r.max.y = scrollr.min.y + (Dy(scrollr)*(off+nitemdrawn))/nitem; if(r.max.y < r.min.y+2) r.max.y = r.min.y+2; border(&screen, r, 1, F); if(menutxt == 0){ menutxt = balloc(Rect(0, 0, 16, 16), 0); if(menutxt) wrbitmap(menutxt, 0, 16, menutxtbits); } if(menutxt) texture(&screen, inset(r, 1), menutxt, S); } int menuhit(int but, Mouse *m, Menu *menu) { int i, nitem, nitemdrawn, maxwid, lasti, off, noff, wid, screenitem; int scrolling; Rectangle r, menur, sc, textr, scrollr; Bitmap *b; Point pt; char *item; sc = screen.clipr; clipr(&screen, screen.r); maxwid = 0; for(nitem = 0; item = menu->item? menu->item[nitem] : (*menu->gen)(nitem); nitem++){ i = strwidth(font, item); if(i > maxwid) maxwid = i; } if(menu->lasthit<0 || menu->lasthit>=nitem) menu->lasthit = 0; screenitem = (Dy(screen.r)-10)/(font->height+Vspacing); if(nitem>Maxunscroll || nitem>screenitem){ scrolling = 1; nitemdrawn = Nscroll; if(nitemdrawn > screenitem) nitemdrawn = screenitem; wid = maxwid + Gap + Scrollwid; off = menu->lasthit - nitemdrawn/2; if(off < 0) off = 0; if(off > nitem-nitemdrawn) off = nitem-nitemdrawn; lasti = menu->lasthit-off; }else{ scrolling = 0; nitemdrawn = nitem; wid = maxwid; off = 0; lasti = menu->lasthit; } r = inset(Rect(0, 0, wid, nitemdrawn*(font->height+Vspacing)), -Margin); r = rsubp(r, Pt(wid/2, lasti*(font->height+Vspacing)+font->height/2)); r = raddp(r, m->xy); pt = Pt(0, 0); if(r.max.x>screen.r.max.x) pt.x = screen.r.max.x-r.max.x; if(r.max.y>screen.r.max.y) pt.y = screen.r.max.y-r.max.y; if(r.min.xheight+Vspacing); if(scrolling){ scrollr = inset(menur, Border); scrollr.max.x = scrollr.min.x+Scrollwid; }else scrollr = Rect(0, 0, 0, 0); b = balloc(menur, screen.ldepth); if(b == 0) b = &screen; bitblt(b, menur.min, &screen, menur, S); bitblt(&screen, menur.min, &screen, menur, 0); border(&screen, menur, Blackborder, F); r = menurect(textr, lasti); cursorset(divpt(add(r.min, r.max), 2)); menupaint(menu, textr, off, nitemdrawn); if(scrolling) menuscrollpaint(scrollr, off, nitem, nitemdrawn); r = menurect(textr, lasti); cursorset(divpt(add(r.min, r.max), 2)); menupaint(menu, textr, off, nitemdrawn); if(scrolling) menuscrollpaint(scrollr, off, nitem, nitemdrawn); while(m->buttons & (1<<(but-1))){ lasti = menuscan(but, m, textr, lasti); if(lasti >= 0) break; while(!ptinrect(m->xy, textr) && (m->buttons & (1<<(but-1)))){ if(scrolling && ptinrect(m->xy, scrollr)){ noff = ((m->xy.y-scrollr.min.y)*nitem)/Dy(scrollr); noff -= nitemdrawn/2; if(noff < 0) noff = 0; if(noff > nitem-nitemdrawn) noff = nitem-nitemdrawn; if(noff != off){ off = noff; menupaint(menu, textr, off, nitemdrawn); menuscrollpaint(scrollr, off, nitem, nitemdrawn); } } *m = emouse(); } } bitblt(&screen, menur.min, b, menur, S); if(b != &screen) bfree(b); clipr(&screen, sc); if(lasti >= 0){ menu->lasthit = lasti+off; return menu->lasthit; } return -1; } wily-0.13.42/libXg/arc.c000064402366570000012000000016661033320152300144630ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include "libgint.h" #include #define rad2deg(x) 180*((x)/3.1415926535897932384626433832795028841971693993751) void arc(Bitmap *b, Point p0, Point p1, Point p2, int v, Fcode f) { unsigned int d; int x, y, r, start, end, delta; GC g; p1.x -= p0.x; p1.y -= p0.y; p2.x -= p0.x; p2.y -= p0.y; r = (int)sqrt((double)(p1.x*p1.x + p1.y*p1.y)); start = (int)(64*rad2deg(atan2(-p2.y, p2.x))); end = (int)(64*rad2deg(atan2(-p1.y, p1.x))); if(start < 0) start += 64*360; if(end < 0) end += 64*360; delta = end - start; if(delta < 0) delta += 64*360; x = p0.x - r; y = p0.y - r; if(b->flag&SHIFT){ x -= b->r.min.x; y -= b->r.min.y; } d = 2*r; g = _getfillgc(f, b, v); /* * delta is positive, so this draws counterclockwise arc * from start to start+delta */ XDrawArc(_dpy, (Drawable)b->id, g, x, y, d, d, start, delta); } wily-0.13.42/libXg/gcs.c000064402366570000012000000215361033320152300144700ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include "libgint.h" /* * Libg applications are written assuming that black is ~0 * and white is 0. Some screens use the reverse convention. * We get the effect the application desired by seeing what * happens if both the source and dest are converted to the * black==~0 convention, and then converting the dest back * to whatever convention it uses. * * Offscreen bitmaps of depth 1 use the black==~0 convention. * * Bitmaps of depth > 1 are probably in color. Libg operations that * would produce a 1 should produce the foreground color, and * libg operations that would produce a 0 should produce the background * color. Operations that use bitmaps of depth > 1 as source * should interpret the foreground pixel as "black" (1) and the * background pixel as "white" (0). It is hard to make this work, * but the important cases are Fcodes Zero, F, S, and S^D, so * we make sure that those work. When a fill value is given for * a bitmap of depth > 1, assume ~0 means foreground, but otherwise * take any other value literally (assume it came from rgbpix). * This may be wrong for the case of 0, but libg programmers * usually use Fcode Zero instead of passing 0 with Fcode S. * * We assume there are at most two depths of bitmaps: depth 1 * and depth of the screen. */ /* * gx func code corresponding to libg func code when both * source and dest use 1 for black. This is a straight translation. */ static int gx[16] = { GXclear, /* Zero */ GXnor, /* DnorS */ GXandInverted, /* DandnotS */ GXcopyInverted, /* notS */ GXandReverse, /* notDandS */ GXinvert, /* notD */ GXxor, /* DxorS */ GXnand, /* DnandS */ GXand, /* DandS */ GXequiv, /* DxnorS */ GXnoop, /* D */ GXorInverted, /* DornotS */ GXcopy, /* S */ GXorReverse, /* notDorS */ GXor, /* DorS */ GXset, /* F */ }; /* * gx func code corresponding to libg func code when 0 means black * in dst and 1 means black in src. These means the table has op' * where dst <- dst op' src == not ( not(dst) op src ). * The comment on each line is op, in Fcode terms. */ static int d0s1gx[16] = { GXset, /* Zero */ GXorReverse, /* DnorS */ GXor, /* DandnotS */ GXcopy, /* notS */ GXnand, /* notDandS */ GXinvert, /* notD */ GXxor, /* DxorS */ GXandReverse, /* DnandS */ GXorInverted, /* DandS */ GXequiv, /* DxnorS */ GXnoop, /* D */ GXand, /* DornotS */ GXcopyInverted, /* S */ GXnor, /* notDorS */ GXandInverted, /* DorS */ GXclear, /* F */ }; /* * gx func code corresponding to libg func code when 1 means black * in dst and 0 means black in src. These means the table has op' * where dst <- dst op' src == dst op not(src) ) * The comment on each line is op, in Fcode terms. */ static int d1s0gx[16] = { GXclear, /* Zero */ GXandReverse, /* DnorS */ GXand, /* DandnotS */ GXcopy, /* notS */ GXnor, /* notDandS */ GXinvert, /* notD */ GXequiv, /* DxorS */ GXorReverse, /* DnandS */ GXandInverted, /* DandS */ GXxor, /* DxnorS */ GXnoop, /* D */ GXor, /* DornotS */ GXcopyInverted, /* S */ GXnand, /* notDorS */ GXorInverted, /* DorS */ GXset, /* F */ }; /* * gx func code corresponding to libg func code when 0 means black * in both the src and the dst. These means the table has op' * where dst <- dst op' src == not (not(dst) op not(src)) ) * The comment on each line is op, in Fcode terms. */ static int d0s0gx[16] = { GXset, /* Zero */ GXnand, /* DnorS */ GXorInverted, /* DandnotS */ GXcopyInverted, /* notS */ GXorReverse, /* notDandS */ GXinvert, /* notD */ GXequiv, /* DxorS */ GXnor, /* DnandS */ GXor, /* DandS */ GXxor, /* DxnorS */ GXnoop, /* D */ GXandInverted, /* DornotS */ GXcopy, /* S */ GXandReverse, /* notDorS */ GXand, /* DorS */ GXclear, /* F */ }; /* * 1 for those Fcodes that are degenerate (don't involve src) */ static int degengc[16] = { 1, /* Zero */ 0, /* DnorS */ 0, /* DandnotS */ 0, /* notS */ 0, /* notDandS */ 1, /* notD */ 0, /* DxorS */ 0, /* DnandS */ 0, /* DandS */ 0, /* DxnorS */ 1, /* D */ 0, /* DornotS */ 0, /* S */ 0, /* notDorS */ 0, /* DorS */ 1, /* F */ }; /* * GCs are all for same screen, and depth is either 1 or screen depth. * Return a GC for the depth of b, with values as specified by gcv. * * Also, set (or unset) the clip rectangle if necessary. * (This implementation should be improved if setting a clip rectangle is not rare). */ GC _getgc(Bitmap *b, unsigned long gcvm, XGCValues *pgcv) { static GC gc0, gcn; static clipset = 0; GC g; XRectangle xr; g = (b->ldepth==0)? gc0 : gcn; if(!g){ g = XCreateGC(_dpy, (Drawable)b->id, gcvm, pgcv); if(b->ldepth==0) gc0 = g; else gcn = g; } else XChangeGC(_dpy, g, gcvm, pgcv); if(b->flag&CLIP){ xr.x = b->clipr.min.x; xr.y = b->clipr.min.y; xr.width = Dx(b->clipr); xr.height = Dy(b->clipr); if(b->flag&SHIFT){ xr.x -= b->r.min.x; xr.y -= b->r.min.y; } XSetClipRectangles(_dpy, g, 0, 0, &xr, 1, YXBanded); clipset = 1; }else if(clipset){ pgcv->clip_mask = None; XChangeGC(_dpy, g, GCClipMask, pgcv); clipset = 0; } return g; } /* * Return a GC that will fill bitmap b using a pixel value v and Fcode f. * Pixel value v is according to libg convention, so 0 means * white (or background) and ~0 means black (or foreground). */ GC _getfillgc(Fcode f, Bitmap *b, unsigned long val) { int xf, m; unsigned long v, fg, bg, spix, vmax; XGCValues gcv; f &= F; vmax = _ld2dmask[b->ldepth]; v = val & vmax; spix = v; xf = GXcopy; m = b->flag; if(m & DP1){ xf = (m&BL1)? gx[f] : d0s1gx[f]; }else{ fg = _fgpixel; bg = _bgpixel; switch(f){ case Zero: labZero: spix = bg; break; case F: labF: spix = fg; break; case D: labD: xf = GXnoop; break; case notD: labnotD: xf = GXxor; spix = fg^bg; break; case S: if(val == ~0) spix = fg; else spix = v; break; case notS: if(val == ~0) spix = bg; else spix = v; break; case DxorS: xf = GXxor; if(val == ~0) spix = fg^bg; else spix = v; break; case DxnorS: xf = GXxor; if(val == 0) spix = fg^bg; else spix = v; break; default: /* hard to do anything other than v==0 or v==~0 case */ if(v < vmax-v){ /* v is closer to 0 than vmax */ switch(f&~S){ case D&~S: goto labD; case notD&~S: goto labnotD; case Zero&~S: goto labZero; case F&~S: goto labF; } }else{ /* v is closer to vmax than 0 */ switch(f&S){ case D&S: goto labD; case notD&S: goto labnotD; case Zero&S: goto labZero; case F&S: goto labF; } } } } gcv.foreground = spix; gcv.function = xf; return _getgc(b, GCForeground|GCFunction, &gcv); } /* * Return a GC to be used to copy an area from bitmap sb to * bitmap db. Sometimes the calling function shouldn't use * XCopyArea, but instead should use XCopyPlane or XFillRectangle. * The *bltfunc arg is set to one of UseCopyArea, UseCopyPlane, * UseFillRectangle. */ GC _getcopygc(Fcode f, Bitmap *db, Bitmap *sb, int *bltfunc) { unsigned long spix, bg, fg, df, sf; int xf, c; XGCValues gcv; unsigned long gcvm; f &= F; gcvm = 0; df = db->flag; if(degengc[f]){ *bltfunc = UseFillRectangle; if(df&SCR || !(df&DP1)){ fg = _fgpixel; bg = _bgpixel; }else{ /* must be DP1 and BL1 */ fg = 1; bg = 0; } switch(f){ case Zero: xf = GXcopy; spix = bg; break; case F: xf = GXcopy; spix = fg; break; case D: xf = GXnoop; spix = fg; break; case notD: xf = GXxor; spix = fg^bg; break; } gcv.function = xf; gcv.foreground = spix; gcvm = GCFunction|GCForeground; }else{ /* src is involved in f */ #define code(f1,f2) ((((f1)&(DP1|BL1))<<2)|((f2)&(DP1|BL1))) sf = sb->flag; c = code(df,sf); *bltfunc = UseCopyArea; switch(code(df,sf)){ case code(DP1|BL1,DP1|BL1): case code(BL1,BL1): xf = gx[f]; break; case code(DP1|BL1,DP1): xf = d1s0gx[f]; break; case code(DP1,DP1|BL1): xf = d0s1gx[f]; break; case code(DP1,DP1): case code(0,0): xf = d0s0gx[f]; break; default: /* * One bitmap has depth 1, the other has screen depth. * We know the bitmap must have BL1. * CopyPlane must be used; it won't really work * for more than fcode==S. */ *bltfunc = UseCopyPlane; xf = GXcopy; switch(c){ case code(0,DP1|BL1): case code(BL1,DP1|BL1): fg = _fgpixel; bg = _bgpixel; break; case code(DP1|BL1,0): fg = 0; bg = 1; break; case code(DP1|BL1,BL1): fg = 1; bg = 0; break; default: berror("bad combination of copy bitmaps"); } gcv.foreground = fg; gcv.background = bg; gcvm |= GCForeground|GCBackground; } gcv.function = xf; gcvm |= GCFunction; #undef code } return _getgc(db, gcvm, &gcv); } wily-0.13.42/libXg/rdfontfile.c000064402366570000012000000042551033320152300160470ustar00ozstaff00004330000002#include #include #include #include "libgint.h" #include #include #include static char* skip(char *s) { while (*s==' ' || *s=='\n' || *s=='\t') s++; return s; } Font * rdfontfile(char *name, int ldepth) { Font *fnt; Cachesubf *c; int fd, i; char *buf, *s, *t; struct stat sbuf; unsigned long min, max; fd = open(name, O_RDONLY); if (fd < 0) return 0; if (fstat(fd, &sbuf) < 0) { Err0: close(fd); return 0; } buf = (char *)malloc(sbuf.st_size+1); if (buf == 0) goto Err0; buf[sbuf.st_size] = 0; i = read(fd, buf, sbuf.st_size); close(fd); if (i != sbuf.st_size) { Err1: free(buf); return 0; } s = buf; fnt = (Font *)malloc(sizeof(Font)); if (fnt == 0) goto Err1; memset((void*)fnt, 0, sizeof(Font)); fnt->name = (char *)malloc(strlen(name)+1); if (fnt->name==0) { Err2: free(fnt->name); free(fnt); goto Err1; } strcpy(fnt->name, name); fnt->height = strtol(s, &s, 0); s = skip(s); fnt->ascent = strtol(s, &s, 0); s = skip(s); if (fnt->height<=0 || fnt->ascent<=0) goto Err2; fnt->width = 0; fnt->ldepth = ldepth; fnt->id = 0; fnt->nsubf = 0; fnt->subf = 0; do { min = strtol(s, &s, 0); s = skip(s); max = strtol(s, &s, 0); s = skip(s); if(*s==0 || min>=65536 || max>=65536 || min>max) { Err3: ffree(fnt); return 0; } if (fnt->subf) fnt->subf = (Cachesubf *)realloc(fnt->subf, (fnt->nsubf+1)*sizeof(Cachesubf)); else fnt->subf = (Cachesubf *)malloc(sizeof(Cachesubf)); if (fnt->subf == 0) { /* realloc manual says fnt->subf may have been destroyed */ fnt->nsubf = 0; goto Err3; } c = &fnt->subf[fnt->nsubf]; c->min = min; c->max = max; t = s; while (*s && *s!=' ' && *s!='\n' && *s!='\t') s++; *s++ = 0; c->f = (Subfont *)0; c->name = (char *)malloc(strlen(t)+1); if (c->name == 0) { free(c); goto Err3; } strcpy(c->name, t); s = skip(s); fnt->nsubf++; } while(*s); free(buf); return fnt; } void ffree(Font *f) { int i; Cachesubf *c; unsigned char *b; for (i=0; insubf; i++){ c = f->subf+i; if (c->f) subffree(c->f); free(c->name); free(c); } free(f->subf); free(f); } ==' ' || *s=='\n' || *s=='\t') s++; return s; } Font * rdfontfile(char *name, int ldepth) { Font *fnt; Cachesubf *c; int fd, i; char *buf, *s, *t; struct stat sbuf; unsigned long min, max; fd = open(name, O_RDONLY); if (fd < 0) return 0; if (fstat(fd, &sbuf) < 0) { Err0: close(fd); return 0; } buf = (char *)malwily-0.13.42/libXg/wrbitmapfile.c000064402366570000012000000021011033320152300163640ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include "libgint.h" #define CHUNK 4096 void wrbitmapfile(int fd, Bitmap *b) { char hdr[5*12+1]; unsigned char *data; long dy, px; unsigned long l, t, n; long miny, maxy; sprint(hdr, "%11d %11d %11d %11d %11d ", b->ldepth, b->r.min.x, b->r.min.y, b->r.max.x, b->r.max.y); if(write(fd, hdr, 5*12) != 5*12) berror("wrbitmapfile write"); px = 1<<(3-b->ldepth); /* pixels per byte */ /* set l to number of bytes of data per scan line */ if(b->r.min.x >= 0) l = (b->r.max.x+px-1)/px - b->r.min.x/px; else{ /* make positive before divide */ t = (-b->r.min.x)+px-1; t = (t/px)*px; l = (t+b->r.max.x+px-1)/px; } miny = b->r.min.y; maxy = b->r.max.y; data = (unsigned char *)malloc(CHUNK); if(data == 0) berror("wrbitmapfile malloc"); while(maxy > miny){ dy = maxy - miny; if(dy*l > CHUNK) dy = CHUNK/l; rdbitmap(b, miny, miny+dy, data); n = dy*l; if(write(fd, data, n) != n){ free(data); berror("wrbitmapfile write"); } miny += dy; } free(data); } wily-0.13.42/libXg/clipline.c000064402366570000012000000071201033320152300155040ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include "libgint.h" typedef struct Linedesc { int x0; int y0; char xmajor; char slopeneg; long dminor; long dmajor; } Linedesc; int _clipline(Rectangle, Point*, Point*, Linedesc*); #define XYswap(p) t=(p)->x, (p)->x=(p)->y, (p)->y=t #define Swap(x, y) t=x, x=y, y=t static long lfloor(long x, long y) /* first integer <= x/y */ { if(y <= 0){ if(y == 0) return x; y = -y; x = -x; } if(x < 0){ /* be careful; C div. is undefined */ x = -x; x += y-1; return -(x/y); } return x/y; } static long lceil(long x, long y) /* first integer >= x/y */ { if(y <= 0){ if(y == 0) return x; y = -y; x = -x; } if(x < 0){ x = -x; return -(x/y); } x += y-1; return x/y; } int _gminor(long x, Linedesc *l) { long y; y = 2*(x-l->x0)*l->dminor + l->dmajor; y = lfloor(y, 2*l->dmajor) + l->y0; return l->slopeneg? -y : y; } int _gmajor(long y, Linedesc *l) { long x; x = 2*((l->slopeneg? -y : y)-l->y0)*l->dmajor - l->dminor; x = lceil(x, 2*l->dminor) + l->x0; if(l->dminor) while(_gminor(x-1, l) == y) x--; return x; } void gsetline(Point *pp0, Point *pp1, Linedesc *l) { long dx, dy, t; Point endpt; int swapped; Point p0, p1; swapped = 0; p0 = *pp0; p1 = *pp1; l->xmajor = 1; l->slopeneg = 0; dx = p1.x - p0.x; dy = p1.y - p0.y; if(abs(dy) > abs(dx)){ /* Steep */ l->xmajor = 0; XYswap(&p0); XYswap(&p1); Swap(dx, dy); } if(dx < 0){ swapped++; Swap(p0.x, p1.x); Swap(p0.y, p1.y); dx = -dx; dy = -dy; } if(dy < 0){ l->slopeneg = 1; dy = -dy; p0.y = -p0.y; } l->dminor = dy; l->dmajor = dx; l->x0 = p0.x; l->y0 = p0.y; p1.x = swapped? p0.x+1 : p1.x-1; p1.y = _gminor(p1.x, l); if(l->xmajor == 0){ XYswap(&p0); XYswap(&p1); } if(pp0->x > pp1->x){ *pp1 = *pp0; *pp0 = p1; }else *pp1 = p1; } /* * Modified clip-to-rectangle algorithm * works in bitmaps * Everything in SCREEN coordinates. * * Newman & Sproull 124 (1st edition) */ static code(Point *p, Rectangle *r) { return( (p->xmin.x? 1 : p->x>=r->max.x? 2 : 0) | (p->ymin.y? 4 : p->y>=r->max.y? 8 : 0)); } int clipline(Rectangle r, Point *p0, Point *p1) { Linedesc l; return _clipline(r, p0, p1, &l); } int _clipline(Rectangle r, Point *p0, Point *p1, Linedesc *l) { int c0, c1, n; long t, ret; Point temp; int swapped; if(p0->x==p1->x && p0->y==p1->y) return 0; gsetline(p0, p1, l); /* line is now closed */ if(l->xmajor == 0){ XYswap(p0); XYswap(p1); XYswap(&r.min); XYswap(&r.max); } c0 = code(p0, &r); c1 = code(p1, &r); ret = 1; swapped = 0; n = 0; while(c0 | c1){ if(c0 & c1){ /* no point of line in r */ ret = 0; goto Return; } if(++n > 10){ /* horrible points; overflow etc. etc. */ ret = 0; goto Return; } if(c0 == 0){ /* swap points */ temp = *p0; *p0 = *p1; *p1 = temp; Swap(c0, c1); swapped ^= 1; } if(c0 == 0) break; if(c0 & 1){ /* push towards left edge */ p0->x = r.min.x; p0->y = _gminor(p0->x, l); }else if(c0 & 2){ /* push towards right edge */ p0->x = r.max.x-1; p0->y = _gminor(p0->x, l); }else if(c0 & 4){ /* push towards top edge */ p0->y = r.min.y; if(l->slopeneg) p0->x = _gmajor(p0->y-1, l)-1; else p0->x = _gmajor(p0->y, l); }else if(c0 & 8){ /* push towards bottom edge */ p0->y = r.max.y-1; if(l->slopeneg) p0->x = _gmajor(p0->y, l); else p0->x = _gmajor(p0->y+1, l)-1; } c0 = code(p0, &r); } Return: if(l->xmajor == 0){ XYswap(p0); XYswap(p1); } if(swapped){ temp = *p0; *p0 = *p1; *p1 = temp; } return ret; } wily-0.13.42/libXg/copymasked.c000064402366570000012000000021241033320152300160430ustar00ozstaff00004330000002#include #include #include "libgint.h" /* * m should be a 1-bit-deep bitmap with origin (0,0) and the * same extents as r. s should have the same depth as d. * Rectangle r of s is copied to d wherever corresponding * bits of m are 1 */ void copymasked(Bitmap *d, Point p, Bitmap *s, Bitmap *m, Rectangle r) { int sx, sy, dx, dy; XGCValues gcv; GC g; if(Dx(r)<=0 || Dy(r)<=0) return; sx = r.min.x; sy = r.min.y; if(s->flag&SHIFT){ sx -= s->r.min.x; sy -= s->r.min.y; } dx = p.x; dy = p.y; if(d->flag&SHIFT){ dx -= d->r.min.x; dy -= d->r.min.y; } gcv.fill_style = FillStippled; gcv.stipple = (Pixmap)m->id; gcv.function = GXclear; gcv.ts_x_origin = dx; gcv.ts_y_origin = dy; gcv.fill_style = FillStippled; g = _getgc(d, GCFunction|GCStipple|GCTileStipXOrigin |GCTileStipYOrigin|GCFillStyle, &gcv); XFillRectangle(_dpy, (Drawable)d->id, g, dx, dy, Dx(r), Dy(r)); gcv.function = GXor; gcv.fill_style = FillSolid; g = _getgc(d, GCFunction|GCFillStyle, &gcv); XCopyArea(_dpy, (Drawable)s->id, (Drawable)d->id, g, sx, sy, Dx(r), Dy(r), dx, dy); } wily-0.13.42/libXg/cursorswitch.c000064402366570000012000000036151033320152300164510ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include "libgint.h" /* * Use the id field in Cursor to hold the X id corresponding * to the cursor, so that it doesn't have to be recreated on * each cursorswitch. This doesn't quite match the semantics * of Plan9 libg, since the user could create a cursor (say * with malloc) with garbage in the id field; or the user * could change the contents of the other fields and we * wouldn't know about it. Neither of these happen in * existing uses of libg. */ static Cursor arrow = { {-1, -1}, {0xFF, 0xE0, 0xFF, 0xE0, 0xFF, 0xC0, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x80, 0xFF, 0xC0, 0xFF, 0xE0, 0xE7, 0xF0, 0xE3, 0xF8, 0xC1, 0xFC, 0x00, 0xFE, 0x00, 0x7F, 0x00, 0x3E, 0x00, 0x1C, 0x00, 0x08, }, {0x00, 0x00, 0x7F, 0xC0, 0x7F, 0x00, 0x7C, 0x00, 0x7E, 0x00, 0x7F, 0x00, 0x6F, 0x80, 0x67, 0xC0, 0x43, 0xE0, 0x41, 0xF0, 0x00, 0xF8, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x1C, 0x00, 0x08, 0x00, 0x00, } }; static Bitmap *bsrc, *bmask; static Rectangle crect = { 0, 0, 16, 16 }; void cursorswitch(Cursor *c) { if(c == 0) c = &arrow; if(c->id == 0){ if(bsrc == 0){ bsrc = balloc(crect, 0); bmask = balloc(crect, 0); } /* * Cursor should have fg where "set" is 1, * and bg where "clr" is 1 and "set" is 0, * and should leave places alone where "set" and "clr" are both 0 */ wrbitmap(bsrc, 0, 16, c->set); #ifdef CURSORBUG /* * Some X servers (e.g., Sun X-on-news for some color * monitors) don't do XCreatePixmapCursor properly: * only the mask gets displayed, all black */ wrbitmap(bmask, 0, 16, c->set); #else wrbitmap(bmask, 0, 16, c->clr); bitblt(bmask, Pt(0,0), bsrc, crect, S|D); #endif c->id = (int) XCreatePixmapCursor(_dpy, (Pixmap)bsrc->id, (Pixmap)bmask->id, &_fgcolor, &_bgcolor, -c->offset.x, -c->offset.y); } XDefineCursor(_dpy, (Window)screen.id, (xCursor)c->id); } wily-0.13.42/libXg/ellipse.c000064402366570000012000000006671033320152300153530ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include "libgint.h" /* e(x,y) = b*b*x*x + a*a*y*y - a*a*b*b */ void ellipse(Bitmap *bp, Point p, int a, int b, int v, Fcode f) { int x, y; GC g; x = p.x - a; y = p.y - b; if (bp->flag&SHIFT){ x -= bp->r.min.x; y -= bp->r.min.y; } g = _getfillgc(f, bp, v); XDrawArc(_dpy, (Drawable)bp->id, g, x, y, 2*a, 2*b, 0, 23040/* 360 deg */); } wily-0.13.42/libXg/strwidth.c000064402366570000012000000007141033320152300155570ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include "libgint.h" long strwidth(Font *f, char *s) { int wid, twid; enum { Max = 128 }; Rune cbuf[Max]; unsigned short fbuf[Max]; Rune r; twid = 0; while (*s) { if (cachechars(f, &s, cbuf, Max, &wid, fbuf) <= 0) s += chartorune(&r, s); else twid += wid; } return twid; } Point strsize(Font *f, char *s) { return Pt(strwidth(f, s), f->height); } wily-0.13.42/libXg/polysegment.c000064402366570000012000000011061033320152300162510ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include "libgint.h" void polysegment(Bitmap *d, int n, Point *pp, int v, Fcode f) { XPoint *xp; int i; GC g; if (!(xp = (XPoint *)calloc(n, sizeof(XPoint)))) berror("polysegment: could not allocate XPoints"); for (i = 0; i < n; i++, pp++) if(d->flag&SHIFT){ xp[i].x = pp->x - d->r.min.x; xp[i].y = pp->y - d->r.min.y; } else { xp[i].x = pp->x; xp[i].y = pp->y; } g = _getfillgc(f, d, v); XDrawLines(_dpy, (Drawable)d->id, g, xp, n, CoordModeOrigin); free(xp); } wily-0.13.42/libXg/rdbitmap.c000064402366570000012000000027301033320152300155110ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include "libgint.h" void rdbitmap(Bitmap *b, int miny, int maxy, unsigned char *data) { XImage *gim, *eim; int x, y, w, h, pix, l, offset, px; int inld, outld; char *tdata; /* * The XGetImage returned image may be wrong in a number of ways: * wrong bit order, byte order, bit pad, scanline pad, * and constant shift. * So use a SLOW loop, for now */ w = Dx(b->r); h = maxy - miny; outld = b->ldepth; inld = (b->ldepth == 0) ? 0 : screen.ldepth; gim = XGetImage(_dpy, (Drawable)b->id, 0, miny - b->r.min.y, w, h, ~0, ZPixmap); px = 1<<(3-outld); /* pixels per byte */ /* set l to number of bytes of data per scan line */ if(b->r.min.x >= 0) offset = b->r.min.x % px; else offset = px - b->r.min.x % px; l = (-b->r.min.x+px-1)/px; if(b->r.max.x >= 0) l += (b->r.max.x+px-1)/px; else l -= b->r.max.x/px; l *= h; if(l <= 0) return; tdata = (char *)malloc(l); if (tdata == (char *) 0) berror("rdbitmap malloc"); eim = XCreateImage(_dpy, 0, 1 << inld, ZPixmap, 0, tdata, w+offset, h, 8, 0); eim->bitmap_pad = 8; eim->bitmap_bit_order = MSBFirst; eim->byte_order = MSBFirst; for(y = 0; y < h; y++) for(x = 0; x < w; x++) { pix = XGetPixel(gim, x, y); XPutPixel(eim, x+offset, y, pix); } if (inld == outld) memcpy((char *)data, tdata, l); else _ldconvert(tdata, inld, (char*)data, outld, w, h); XDestroyImage(gim); XDestroyImage(eim); } wily-0.13.42/libXg/disc.c000064402366570000012000000006221033320152300146270ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include "libgint.h" void disc(Bitmap *b, Point p, int r, int v, Fcode f) { unsigned int d; int x, y; GC g; x = p.x - r; y = p.y - r; if (b->flag&SHIFT){ x -= b->r.min.x; y -= b->r.min.y; } d = 2*r; g = _getfillgc(f, b, v); XFillArc(_dpy, (Drawable)b->id, g, x, y, d, d, 0, 23040/* 360 deg */); } wily-0.13.42/libXg/cursorset.c000064402366570000012000000005231033320152300157360ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include "libgint.h" /* * Only allow cursor to move within screen Bitmap */ void cursorset(Point p) { /* motion will be relative to window origin */ p = sub(p, screen.r.min); XWarpPointer(_dpy, None, (Window)screen.id, 0, 0, 0, 0, p.x, p.y); } wily-0.13.42/libXg/font.c000064402366570000012000000034051033320152300146550ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include "libgint.h" #define PJW 0 /* use NUL==pjw for invisible characters */ static Cachesubf *findsubfont(Font *f, Rune r, int *cn) { int n, i, c; Rune rx; Cachesubf *csf; Subfont *sf; for (i = 0, rx = r; i < 2; i++, rx = PJW) for (n=0, csf=f->subf; n < f->nsubf; n++, csf++) if (csf->min <= rx && rx <= csf->max) { if (!csf->f) { csf->f = getsubfont(csf->name); if (!csf->f) return 0; } sf = csf->f; c = rx-csf->min+sf->minchar; c = ((c>>8)-sf->minrow)*sf->width+(c&0xff)-sf->mincol; if ((c < 0) || (c >= sf->n)) break; /* ignore zero width characters */ if (sf->info[c].cwidth == 0 && sf->info[c].width == 0) break; *cn = c; return csf; } return 0; } int cachechars(Font *f, char **s, void *cp, int max, int *wp, unsigned short *fp) { int i, w, wid, charnum; Rune r; char *sp; Cachesubf *csf; sp = *s; wid = 0; for (i=0; *sp && if->info[charnum].width; fp[i] = csf-f->subf; /* subfont number */ ((XChar2b*)cp)[i].byte1 = charnum/csf->f->width+csf->f->minrow; ((XChar2b*)cp)[i].byte2 = charnum%csf->f->width+csf->f->mincol; i++; } *s = sp; *wp = wid; return i; } long charwidth(Font *f, Rune r) { Cachesubf *csf; int charnum; if (r == 0) berror("NUL in charwidth"); /* difficult BUG */ csf = findsubfont(f, r, &charnum); if (!csf) return 0; else return csf->f->info[charnum].width; } void subffree(Subfont *f) { if (f->info) free(f->info); /* note: f->info must have been malloc'ed! */ free(f); } wily-0.13.42/libXg/segment.c000064402366570000012000000006631033320152300153540ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include "libgint.h" void segment(Bitmap *d, Point p1, Point p2, int v, Fcode f) { int x1, y1, x2, y2; GC g; x1 = p1.x; y1 = p1.y; x2 = p2.x; y2 = p2.y; if(d->flag&SHIFT){ x1 -= d->r.min.x; y1 -= d->r.min.y; x2 -= d->r.min.x; y2 -= d->r.min.y; } g = _getfillgc(f, d, v); XDrawLine(_dpy, (Drawable)d->id, g, x1, y1, x2, y2); } wily-0.13.42/libXg/Makefile.in000064402366570000012000000011631033320152300156070ustar00ozstaff00004330000002srcdir=@srcdir@ VPATH=@srcdir@ CC=@CC@ RANLIB=@RANLIB@ INCLUDES=$(srcdir)/../include CFLAGS=@CFLAGS@ -I.. -I$(INCLUDES) @X_CFLAGS@ LIB=libXg.a OBJS=arc.o arith.o balloc.o bitblt.o bitbltclip.o border.o bscreenrect.o\ circle.o clipline.o clipr.o copymasked.o cursorset.o cursorswitch.o\ disc.o ellipse.o font.o gcs.o getrect.o gwin.o ldconvert.o latin1.o\ mkfont.o menuhit.o point.o polysegment.o rdbitmap.o rdbitmapfile.o\ rdfontfile.o rectclip.o rune.o segment.o string.o strwidth.o texture.o\ wrbitmap.o wrbitmapfile.o xtbinit.o include $(INCLUDES)/Makelib $(OBJS): $(INCLUDES)/u.h $(INCLUDES)/libc.h $(INCLUDES)/libg.h wily-0.13.42/libXg/bitbltclip.c000064402366570000012000000024011033320152300160320ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include "libgint.h" int bitbltclip(void *vp) { int dx, dy; int i; struct bbcarg{ Bitmap *dm; Point p; Bitmap *sm; Rectangle r; Fcode f; }*bp; bp = (struct bbcarg *)vp; dx = Dx(bp->r); dy = Dy(bp->r); if(bp->p.x < bp->dm->clipr.min.x){ i = bp->dm->clipr.min.x-bp->p.x; bp->r.min.x += i; bp->p.x += i; dx -= i; } if(bp->p.y < bp->dm->clipr.min.y){ i = bp->dm->clipr.min.y-bp->p.y; bp->r.min.y += i; bp->p.y += i; dy -= i; } if(bp->p.x+dx > bp->dm->clipr.max.x){ i = bp->p.x+dx-bp->dm->clipr.max.x; bp->r.max.x -= i; dx -= i; } if(bp->p.y+dy > bp->dm->clipr.max.y){ i = bp->p.y+dy-bp->dm->clipr.max.y; bp->r.max.y -= i; dy -= i; } if(bp->r.min.x < bp->sm->clipr.min.x){ i = bp->sm->clipr.min.x-bp->r.min.x; bp->p.x += i; bp->r.min.x += i; dx -= i; } if(bp->r.min.y < bp->sm->clipr.min.y){ i = bp->sm->clipr.min.y-bp->r.min.y; bp->p.y += i; bp->r.min.y += i; dy -= i; } if(bp->r.max.x > bp->sm->clipr.max.x){ i = bp->r.max.x-bp->sm->clipr.max.x; bp->r.max.x -= i; dx -= i; } if(bp->r.max.y > bp->sm->clipr.max.y){ i = bp->r.max.y-bp->sm->clipr.max.y; bp->r.max.y -= i; dy -= i; } return dx>0 && dy>0; } wily-0.13.42/libXg/gwin.c000064402366570000012000000320741033320152300146570ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include #include #include #include #include #ifndef XtSpecificationRelease #define R3 #define XtPointer caddr_t #define XtOffsetOf(s_type,field) XtOffset(s_type*,field) #define XtExposeCompressMultiple TRUE #endif #include "GwinP.h" /* Forward declarations */ static void Realize(Widget, XtValueMask *, XSetWindowAttributes *); static void Resize(Widget); static void Redraw(Widget, XEvent *, Region); static void Mappingaction(Widget, XEvent *, String *, Cardinal*); static void Keyaction(Widget, XEvent *, String *, Cardinal*); static void Mouseaction(Widget, XEvent *, String *, Cardinal*); static String SelectSwap(Widget, String); /* Data */ #define Offset(field) XtOffsetOf(GwinRec, gwin.field) static XtResource resources[] = { {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), Offset(foreground), XtRString, (XtPointer)XtDefaultForeground}, {XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *), Offset(font),XtRString, (XtPointer)XtDefaultFont}, {XtNscrollForwardR, XtCScrollForwardR, XtRBoolean, sizeof(Boolean), Offset(forwardr), XtRImmediate, (XtPointer)TRUE}, {XtNreshaped, XtCReshaped, XtRFunction, sizeof(Reshapefunc), Offset(reshaped), XtRFunction, (XtPointer) NULL}, {XtNgotchar, XtCGotchar, XtRFunction, sizeof(Charfunc), Offset(gotchar), XtRFunction, (XtPointer) NULL}, {XtNgotmouse, XtCGotmouse, XtRFunction, sizeof(Mousefunc), Offset(gotmouse), XtRFunction, (XtPointer) NULL}, {XtNselection, XtCSelection, XtRString, sizeof(String), Offset(selection), XtRString, (XtPointer) NULL}, {XtNp9font, XtCP9font, XtRString, sizeof(String), Offset(p9font), XtRString, (XtPointer) NULL}, {XtNp9fixed, XtCP9fixed, XtRString, sizeof(String), Offset(p9fixed), XtRString, (XtPointer) NULL}, {XtNcomposeMod, XtCComposeMod, XtRInt, sizeof(int), Offset(compose), XtRImmediate, (XtPointer) 0} }; #undef Offset static XtActionsRec actions[] = { {"key", Keyaction}, {"mouse", Mouseaction}, {"mapping", Mappingaction} }; static char tms[] = " : key() \n\ : mouse() \n\ : mouse() \n\ : mouse() \n\ : mapping() \n"; /* Class record declaration */ GwinClassRec gwinClassRec = { /* Core class part */ { /* superclass */ (WidgetClass)&widgetClassRec, /* class_name */ "Gwin", /* widget_size */ sizeof(GwinRec), /* class_initialize */ NULL, /* class_part_initialize*/ NULL, /* class_inited */ FALSE, /* initialize */ NULL, /* initialize_hook */ NULL, /* realize */ Realize, /* actions */ actions, /* num_actions */ XtNumber(actions), /* resources */ resources, /* num_resources */ XtNumber(resources), /* xrm_class */ NULLQUARK, /* compress_motion */ TRUE, /* compress_exposure */ XtExposeCompressMultiple, /* compress_enterleave*/ TRUE, /* visible_interest */ FALSE, /* destroy */ NULL, /* resize */ Resize, /* expose */ Redraw, /* set_values */ NULL, /* set_values_hook */ NULL, /* set_values_almost */ XtInheritSetValuesAlmost, /* get_values_hook */ NULL, /* accept_focus */ XtInheritAcceptFocus, /* version */ XtVersion, /* callback_offsets */ NULL, /* tm_table */ tms, /* query_geometry */ XtInheritQueryGeometry, /* display_accelerator */ NULL, /* extension */ NULL }, /* Gwin class part */ { /* select_swap */ SelectSwap, } }; /* Class record pointer */ WidgetClass gwinWidgetClass = (WidgetClass) &gwinClassRec; static XModifierKeymap *modmap; static int keypermod; static void Realize(Widget w, XtValueMask *valueMask, XSetWindowAttributes *attrs) { XtValueMask mask; *valueMask |= CWBackingStore; attrs->backing_store = Always; XtCreateWindow(w, InputOutput, (Visual *)0, *valueMask, attrs); XtSetKeyboardFocus(w->core.parent, w); if (modmap = XGetModifierMapping(XtDisplay(w))) keypermod = modmap->max_keypermod; Resize(w); } static void Resize(Widget w) { if(XtIsRealized(w)) (*(XtClass(w)->core_class.expose))(w, (XEvent *)NULL, (Region)NULL); } static void Redraw(Widget w, XEvent *e, Region r) { Reshapefunc f; static unsigned long last_serial = 0; if ((e) && (e->xexpose.count != 0)) return; if (e) { if (e->xexpose.serial == last_serial) return; else last_serial = e->xexpose.serial; } f = ((GwinWidget)w)->gwin.reshaped; if(f) (*f)(w->core.x, w->core.y, w->core.x+w->core.width, w->core.y+w->core.height); } static void Mappingaction(Widget w, XEvent *e, String *p, Cardinal *np) { if (modmap) XFreeModifiermap(modmap); modmap = XGetModifierMapping(e->xany.display); if (modmap) keypermod = modmap->max_keypermod; } #define STUFFCOMPOSE() \ f = ((GwinWidget)w)->gwin.gotchar; \ if (f) \ for (c = 0; c < composing; c++) \ (*f)(compose[c]) static void Keyaction(Widget w, XEvent *e, String *p, Cardinal *np) { static unsigned char compose[5]; static int composing = -2; int c, minmod; KeySym k, mk, l, u; Charfunc f; Modifiers md; /* * I tried using XtGetActionKeysym, but it didn't seem to * do case conversion properly * (at least, with Xterminal servers and R4 intrinsics) */ if(e->xany.type != KeyPress) return; XtTranslateKeycode(e->xany.display, (KeyCode)e->xkey.keycode, e->xkey.state, &md, &k); /* * The following song and dance is so we can have our chosen * modifier key behave like a compose key, i.e, press and release * and then type the compose sequence, like Plan 9. We have * to find out which key is the compose key first 'though. */ if (IsModifierKey(k) && ((GwinWidget)w)->gwin.compose && composing == -2 && modmap) { minmod = (((GwinWidget)w)->gwin.compose+2)*keypermod; for (c = minmod; c < minmod+keypermod; c++) { XtTranslateKeycode(e->xany.display, modmap->modifiermap[c], e->xkey.state, &md, &mk); if (k == mk) { composing = -1; break; } } return; } /* Handle Multi_key separately, since it isn't a modifier */ if(k == XK_Multi_key) { composing = -1; return; } if(k == NoSymbol) return; if(k&0xFF00){ switch(k){ case XK_BackSpace: case XK_Tab: case XK_Escape: case XK_Delete: case XK_KP_0: case XK_KP_1: case XK_KP_2: case XK_KP_3: case XK_KP_4: case XK_KP_5: case XK_KP_6: case XK_KP_7: case XK_KP_8: case XK_KP_9: case XK_KP_Divide: case XK_KP_Multiply: case XK_KP_Subtract: case XK_KP_Add: case XK_KP_Decimal: k &= 0x7F; break; case XK_Linefeed: k = '\r'; break; case XK_KP_Enter: case XK_Return: k = '\n'; break; case XK_Next: k = 0x80; /* (VIEW- scroll down)*/ break; case XK_Prior: k = 0x81; /* PREVIEW -- "Scroll back" */ break; case XK_Left: k = 0x82; /* LeftArrow */ break; case XK_Right: k = 0x83; /* RightArrow */ break; case XK_Down: k = 0x84; /* LeftArrow */ break; case XK_Up: k = 0x85; /* LeftArrow */ break; case XK_Home: k = 0x86; /* Home */ break; case XK_End: k = 0x87; /* End */ break; default: return; /* not ISO-1 or tty control */ } } /* Compensate for servers that call a minus a hyphen */ if(k == XK_hyphen) k = XK_minus; /* Do caps locking ourselves if translator doesn't */ if ((e->xkey.state&LockMask) && !(md&LockMask)) { XtConvertCase(e->xany.display, k, &l, &u); k = u; } /* Do control mapping ourselves if translator doesn't */ if((e->xkey.state&ControlMask) && !(md&ControlMask)) k &= 0x9f; if(k == NoSymbol) return; /* Check to see if we are in a composition sequence */ if (!((GwinWidget)w)->gwin.compose && (e->xkey.state & Mod1Mask) && composing == -2) composing = -1; if (composing > -2) { compose[++composing] = k; if ((*compose == 'X') && (composing > 0)) { if ((k < '0') || (k > 'f') || ((k > '9') && (k < 'a'))) { STUFFCOMPOSE(); c = (unsigned short)k; composing = -2; } else if (composing == 4) { c = (int)unicode(compose); if (c == -1) { STUFFCOMPOSE(); c = (unsigned short)compose[4]; } composing = -2; } } else if (composing == 1) { c = (int)latin1(compose); if (c == -1) { STUFFCOMPOSE(); c = (unsigned short)compose[1]; } composing = -2; } } else { if (composing >= 0) { composing++; STUFFCOMPOSE(); } c = (unsigned short)k; composing = -2; } if (composing >= -1) return; f = ((GwinWidget)w)->gwin.gotchar; if(f) (*f)(c); } static void LoseSel(Widget w, Atom *sel) { GwinWidget gw = (GwinWidget)w; if(gw->gwin.selection){ XtFree(gw->gwin.selection); gw->gwin.selection = 0; } } static void Mouseaction(Widget w, XEvent *e, String *p, Cardinal *np) { int s; XButtonEvent *be; XMotionEvent *me; Gwinmouse m; Mousefunc f; switch(e->type){ case ButtonPress: be = (XButtonEvent *)e; m.xy.x = be->x; m.xy.y = be->y; m.msec = be->time; s = be->state; /* the previous state */ switch(be->button){ case 1: s |= Button1Mask; break; case 2: s |= Button2Mask; break; case 3: s |= Button3Mask; break; } break; case ButtonRelease: be = (XButtonEvent *)e; m.xy.x = be->x; m.xy.y = be->y; m.msec = be->time; s = be->state; switch(be->button){ case 1: s &= ~Button1Mask; break; case 2: s &= ~Button2Mask; break; case 3: s &= ~Button3Mask; break; } break; case MotionNotify: me = (XMotionEvent *)e; s = me->state; m.xy.x = me->x; m.xy.y = me->y; m.msec = me->time; break; default: return; } m.buttons = 0; if(s & Button1Mask) m.buttons |= 1; if(s & Button2Mask) m.buttons |= 2; if(s & Button3Mask) m.buttons |= 4; f = ((GwinWidget)w)->gwin.gotmouse; if(f) (*f)(&m); } static void SelCallback(Widget w, XtPointer cldata, Atom *sel, Atom *seltype, XtPointer val, unsigned long *len, int *fmt) { String s; int n; GwinWidget gw = (GwinWidget)w; if(gw->gwin.selection) XtFree(gw->gwin.selection); if(*seltype != XA_STRING) n = 0; else n = (*len) * (*fmt/8); s = (String)XtMalloc(n+1); if(n > 0) memcpy(s, (char *)val, n); s[n] = 0; gw->gwin.selection = s; XtFree(val); } static Boolean SendSel(Widget w, Atom *sel, Atom *target, Atom *rtype, XtPointer *ans, unsigned long *anslen, int *ansfmt) { GwinWidget gw = (GwinWidget)w; static Atom targets = 0; XrmValue src, dst; char *s; if(*target == XA_STRING){ s = gw->gwin.selection; if(!s) s = ""; *rtype = XA_STRING; *ans = (XtPointer) XtNewString(s); *anslen = strlen(*ans); *ansfmt = 8; return TRUE; } #ifndef R3 if(targets == 0){ src.addr = "TARGETS"; src.size = strlen(src.addr)+1; dst.size = sizeof(Atom); dst.addr = (XtPointer) &targets; XtConvertAndStore(w, XtRString, &src, XtRAtom, &dst); } if(*target == targets){ *rtype = XA_ATOM; *ans = (XtPointer) XtNew(Atom); *(Atom*) *ans = XA_STRING; *anslen = 1; *ansfmt = 32; return TRUE; } #endif return FALSE; } static String SelectSwap(Widget w, String s) { GwinWidget gw; String ans; gw = (GwinWidget)w; if(!gw->gwin.selection){ #ifdef R3 XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, SelCallback, 0, CurrentTime); #else XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, SelCallback, 0, XtLastTimestampProcessed(XtDisplay(w))); #endif while(gw->gwin.selection == 0) XtAppProcessEvent(XtWidgetToApplicationContext(w) , XtIMAll); } ans = gw->gwin.selection; gw->gwin.selection = XtMalloc(strlen(s)+1); strcpy(gw->gwin.selection, s); #ifdef R3 XtOwnSelection(w, XA_PRIMARY, CurrentTime, SendSel, LoseSel, NULL); #else XtOwnSelection(w, XA_PRIMARY, XtLastTimestampProcessed(XtDisplay(w)), SendSel, LoseSel, NULL); #endif return ans; } /* The returned answer should be free()ed when no longer needed */ String GwinSelectionSwap(Widget w, String s) { XtCheckSubclass(w, gwinWidgetClass, NULL); return (*((GwinWidgetClass) XtClass(w))->gwin_class.select_swap)(w, s); } static void own_selection(Widget w) { #ifdef R3 XtOwnSelection(w, XA_PRIMARY, CurrentTime, SendSel, LoseSel, NULL); #else XtOwnSelection(w, XA_PRIMARY, XtLastTimestampProcessed(XtDisplay(w)), SendSel, LoseSel, NULL); #endif } static void get_selection(Widget w) { #ifdef R3 XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, SelCallback, 0, CurrentTime); #else XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, SelCallback, 0, XtLastTimestampProcessed(XtDisplay(w))); #endif } /* Get current selection. Returned string isn't yours to free or * keep - copy it and forget it. */ char* Gwinselect_get(Widget w) { GwinWidget gw = (GwinWidget)w; if(!gw->gwin.selection){ get_selection(w); while(gw->gwin.selection == 0) XtAppProcessEvent(XtWidgetToApplicationContext(w) , XtIMAll); } own_selection(w); return gw->gwin.selection; } /* Set current selection to 's' */ void Gwinselect_put(Widget w,char*s) { GwinWidget gw = (GwinWidget)w; if(gw->gwin.selection) XtFree(gw->gwin.selection); gw->gwin.selection = XtMalloc(strlen(s)+1); strcpy(gw->gwin.selection, s); own_selection(w); } wily-0.13.42/libXg/getrect.c000064402366570000012000000031221033320152300153400ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include "libgint.h" static Cursor sweep={ {-7, -7}, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE3, 0xF7, 0xE3, 0xF7, 0xE3, 0xE7, 0xE3, 0xF7, 0xE3, 0xFF, 0xE3, 0x7F, 0xE0, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,}, {0x00, 0x00, 0x7F, 0xFE, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x41, 0xE2, 0x41, 0xC2, 0x41, 0xE2, 0x41, 0x72, 0x40, 0x38, 0x40, 0x1C, 0x40, 0x0E, 0x7F, 0xE6, 0x00, 0x00,} }; static void grabcursor(void) { /* Grab X server with an limp wrist. */ while (XGrabPointer(_dpy, screen.id, False, ButtonPressMask|ButtonReleaseMask| ButtonMotionMask|StructureNotifyMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime) != GrabSuccess) sleep(2); /* Grab the keyboard too */ XSetInputFocus(_dpy, screen.id, RevertToParent, CurrentTime); } static void ungrabcursor(void) { XUngrabPointer(_dpy, CurrentTime); } Rectangle getrect(int but, Mouse *m){ Rectangle r, rc; but = 1<<(but-1); cursorswitch(&sweep); while(m->buttons) *m = emouse(); grabcursor(); while(!(m->buttons & but)){ *m = emouse(); if(m->buttons & (7^but)) goto Return; } r.min = m->xy; r.max = m->xy; do{ rc = rcanon(r); border(&screen, rc, 2, F&~D); *m = emouse(); border(&screen, rc, 2, F&~D); r.max = m->xy; }while(m->buttons & but); Return: cursorswitch((Cursor *)0); if(m->buttons & (7^but)){ rc.min.x = rc.max.x = 0; rc.min.y = rc.max.y = 0; while(m->buttons) *m = emouse(); } ungrabcursor(); return rc; } wily-0.13.42/libXg/bscreenrect.c000064402366570000012000000005341033320152300162060ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include "libgint.h" /* * The screen data structure should always be up to date * (Not true in the Plan 9 library, which is why this * function exists). */ Rectangle bscreenrect(Rectangle *clipr) { if(clipr) *clipr = screen.clipr; return screen.r; } wily-0.13.42/libXg/ldconvert.c000064402366570000012000000021671033320152300157130ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include "libgint.h" void _ldconvert(char *in, int inld, char *out, int outld, int w, int h) { int a, b, i, j, i1, j1, j2, mask; int ind, inl, outd, outl; int hh, ww; char *p, *q; i1 = 8 >> inld; j1 = 8 >> outld; ind = 1 << inld; outd = 1 << outld; inl = ((w << inld) + 7)/8; outl = ((w << outld) + 7)/8; b = 0; if (ind > outd) { mask = 256 - (256 >> outd); for (hh = 0; hh < h; hh++, in += inl, out += outl) for (p = in, q = out, ww = 0; ww < w; ww++) { for (j = j1; j > 0; ) { a = *p++; for (i = i1; i > 0; i--, j--) { b |= a & mask; a <<= ind; b <<= outd; } } *q++ = (b >> 8); } } else { j2 = 1 << (outld - inld); mask = 256 - (256 >> ind); for (hh = 0; hh < h; hh++, in += inl, out += outl) for (p = in, q = out, ww = 0; ww < w; ww++) { a = *p++; for (i = i1; i > 0; ) { for (j = j1; j > 0; j--, i--) { b |= a & mask; a <<= ind; b <<= outd; } for (j = j2; j > 0; j--) b |= (b << ind); *q++ = (b >> 8); } } } } wily-0.13.42/libXg/xtbinit.c000064402366570000012000000437731033320152300154040ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include #include "libgint.h" #define COMPRESSMOUSE #define Cursor xCursor #define Font xFont #define Event xEvent #include #include #include #include "Gwin.h" #ifndef XtSpecificationRelease #define R3 #define XtAppInitialize(a,b,c,d,e,f,g,h,i) XtInitialize(0,b,c,d,e,f) #define XtConvertAndStore(a,b,c,d,e) (XtConvert(a,b,c,d,e),1) #define XtAppPending(a) XtPending() #define XtAppProcessEvent(a,b) XtProcessEvent(b) #define XtAppAddTimeOut(a,b,c,d) XtAddTimeOut(b,c,d) #define XtAppAddInput(a,b,c,d,e) XtAddInput(b,c,d,e) #define XtPointer caddr_t #endif #undef Cursor #undef Font #undef Event /* libg globals */ Bitmap screen; Font *font, *fixed; /* implementation globals */ Display *_dpy; Widget _toplevel; unsigned long _fgpixel, _bgpixel; XColor _fgcolor, _bgcolor; int _ld2d[6] = { 1, 2, 4, 8, 16, 24 }; unsigned long _ld2dmask[6] = { 0x1, 0x3, 0xF, 0xFF, 0xFFFF, 0x00FFFFFF }; Colormap _libg_cmap; int _cmap_installed; /* xbinit implementation globals */ #ifndef R3 static XtAppContext app; #endif static Widget widg; static int exposed = 0; static Atom wm_take_focus; static Mouse lastmouse; typedef struct Ebuf { struct Ebuf *next; int n; unsigned char buf[2]; } Ebuf; typedef struct Esrc { int inuse; int size; int count; Ebuf *head; Ebuf *tail; XtInputId id; } Esrc; #define MAXINPUT 1024 /* number of queued input events */ #define MAXSRC 10 static Esrc esrc[MAXSRC]; static int nsrc; static int einitcalled = 0; static int Smouse = -1; static int Skeyboard = -1; static int Stimer = -1; static XtIntervalId timerid; static Font * initfont(char *, XFontStruct *, char *); static void reshaped(int, int, int, int); static void gotchar(int); static void gotmouse(Gwinmouse *); static int log2(int); static void pixtocolor(Pixel, XColor *); static Subfont *XFontStructtoSubfont(XFontStruct *); static Ebuf *ebread(Esrc *); static Ebuf *ebadd(Esrc *); static void focinit(Widget); static void wmproto(Widget, XEvent *, String *, Cardinal *); static void waitevent(void); static Errfunc onerr; String _fallbacks[] = { "*gwin.width: 800", "*gwin.height: 600", NULL }; #ifndef R3 static char *shelltrans = " WM_PROTOCOLS : WMProtocolAction()"; static XtActionsRec wmpactions[] = { {"WMProtocolAction", wmproto} }; #endif /* too many X options */ static XrmOptionDescRec optable[] = { {"-p9fn", "*p9font", XrmoptionSepArg, (caddr_t)NULL}, {"-p9font", "*p9font", XrmoptionSepArg, (caddr_t)NULL}, {"-p9fixed", "*p9fixed", XrmoptionSepArg, (caddr_t)NULL}, }; static int ioerr(Display *d) { if(onerr) (*onerr)("ioerr"); else exit(1); return 0; } void xtbinit(Errfunc f, char *class, int *pargc, char **argv, char **fallbacks) { int n; unsigned int depth; XFontStruct *xf; String fontname; String fixedname; Arg args[10]; char *p; XSetWindowAttributes attr; int compose; if(!class && argv[0]){ p = strrchr(argv[0], '/'); if(p) class = XtNewString(p+1); else class = XtNewString(argv[0]); if(class[0] >= 'a' && class[0] <= 'z') class[0] += 'A' - 'a'; } onerr = f; if (!fallbacks) fallbacks = _fallbacks; n = 0; XtSetArg(args[n], XtNinput, TRUE); n++; _toplevel = XtAppInitialize(&app, class, optable, sizeof(optable)/sizeof(optable[0]), pargc, argv, fallbacks, args, n); n = 0; XtSetArg(args[n], XtNreshaped, reshaped); n++; XtSetArg(args[n], XtNgotchar, gotchar); n++; XtSetArg(args[n], XtNgotmouse, gotmouse); n++; widg = XtCreateManagedWidget("gwin", gwinWidgetClass, _toplevel, args, n); n = 0; XtSetArg(args[n], XtNforeground, &_fgpixel); n++; XtSetArg(args[n], XtNbackground, &_bgpixel); n++; XtSetArg(args[n], XtNdepth, &depth); n++; XtSetArg(args[n], XtNfont, &xf); n++; XtSetArg(args[n], XtNp9font, &fontname); n++; XtSetArg(args[n], XtNp9fixed, &fixedname); n++; XtSetArg(args[n], XtNcomposeMod, &compose); n++; XtGetValues(widg, args, n); XSetIOErrorHandler(ioerr); XSetErrorHandler(ioerr); if (compose < 0 || compose > 5) { n = 0; XtSetArg(args[n], XtNcomposeMod, 0); n++; XtSetValues(widg, args, n); } _dpy = XtDisplay(widg); screen.id = 0; XtRealizeWidget(_toplevel); pixtocolor(_fgpixel, &_fgcolor); pixtocolor(_bgpixel, &_bgcolor); screen.id = (int) XtWindow(widg); screen.ldepth = log2(depth); screen.flag = SCR; if(_fgpixel != 0) screen.flag |= BL1; if(depth == 1) screen.flag |= DP1; font = initfont(fontname, xf, "variable"); fixed = initfont(fixedname, 0, "fixed"); /* leave screen rect at all zeros until reshaped() sets it */ while(!exposed) { XFlush(_dpy); XtAppProcessEvent(app, XtIMXEvent); } XFlush(_dpy); focinit(_toplevel); } static Font * initfont(char *name, XFontStruct *xf, char *backupname) { /* Given (in order of preference) * 'name' which may be the name of a font file, * 'backupfont' which may be an XFontStruct, * and 'backupname', which is the name of an X font. */ Font *f; if (name) { f = rdfontfile(name, screen.ldepth); if (f && charwidth(f, (Rune) ' ') != 0) return f; } if (xf) return mkfont(XFontStructtoSubfont(xf)); return mkfont(getsubfont(backupname)); /* just has to work */ } static void focinit(Widget w) { #ifndef R3 XrmValue src, dst; src.addr = "WM_TAKE_FOCUS"; src.size = strlen((char *)src.addr)+1; dst.addr = (XtPointer) &wm_take_focus; dst.size = sizeof(Atom); XtConvertAndStore(w, XtRString, &src, XtRAtom, &dst); XSetWMProtocols(XtDisplay(w), XtWindow(w), &wm_take_focus, 1); XtAppAddActions(app, wmpactions, XtNumber(wmpactions)); XtAugmentTranslations(w, XtParseTranslationTable(shelltrans)); #endif } #ifndef R3 static void wmproto(Widget w, XEvent *e , String *p, Cardinal *np) { Time t; if(e->type == ClientMessage && (Atom)(e->xclient.data.l[0]) == wm_take_focus) { t = (Time) e->xclient.data.l[1]; XtCallAcceptFocus(widg, &t); } } #endif static void reshaped(int minx, int miny, int maxx, int maxy) { Ebuf *eb; Mouse m; screen.r = Rect(minx, miny, maxx, maxy); screen.clipr = screen.r; if (screen.id) { exposed = 1; ereshaped(screen.r); } if(einitcalled){ /* * Cause a mouse event, so programs like sam * will get out of eread and REALLY do the reshape */ eb = ebadd(&esrc[Smouse]); if (eb == 0) berror("eballoc can't malloc"); memcpy((void*)eb->buf, (void*)&lastmouse, sizeof lastmouse); esrc[Smouse].count++; } } static void gotchar(int c) { Ebuf *eb; if(!einitcalled || Skeyboard == -1) return; eb = ebadd(&esrc[Skeyboard]); if (eb == 0) berror("eballoc can't malloc"); BPSHORT(eb->buf, (unsigned short)(c & 0xffff)); esrc[Skeyboard].count++; } static void gotmouse(Gwinmouse *gm) { Ebuf *eb; Mouse m; if(!einitcalled || Smouse == -1) return; m.buttons = gm->buttons; m.xy.x = gm->xy.x; m.xy.y = gm->xy.y; m.msec = gm->msec; lastmouse = m; eb = ebadd(&esrc[Smouse]); if (eb == 0) berror("eballoc can't malloc"); memcpy((void*)eb->buf, (void*)&m, sizeof m); esrc[Smouse].count++; } static void gotinput(XtPointer cldata, int *pfd, XtInputId *id) { Ebuf *eb, *lasttail, *newe; Esrc *es; int n; if(!einitcalled) return; es = (Esrc *)cldata; if (es->count >= MAXINPUT) return; lasttail = es->tail; eb = ebadd(es); if (eb == 0) return; if(es->size){ n = read(*pfd, (char *)eb->buf, es->size); if (n < 0) n = 0; if(n < es->size) { newe = realloc(eb, sizeof(Ebuf)+n); newe->n = n; if (es->head == eb) es->head = newe; else lasttail->next = newe; es->tail = newe; } } es->count++; } static void gottimeout(XtPointer cldata, XtIntervalId *id) { if(!einitcalled || Stimer == -1 || esrc[Stimer].id != *(XtInputId*) id) return; /* * Don't queue up timeouts, because there's * too big a danger that they might pile up * too quickly. */ esrc[Stimer].head = (Ebuf *)1; esrc[Stimer].count = 1; esrc[Stimer].id = (XtInputId) XtAppAddTimeOut(app, (long)cldata, gottimeout, cldata); } static int log2(int n) { int i, v; for(i=0, v=1; i < 32; i++, v<<=1) if(n <= v) break; return i; } static void pixtocolor(Pixel p, XColor *pc) { #ifdef R3 Colormap cmap; Arg args[2]; int n; n = 0; XtSetArg(args[n], XtNcolormap, &cmap); n++; XtGetValues(_toplevel, args, n); pc->pixel = p; XQueryColor(_dpy, cmap, pc); #else XrmValue xvf, xvt; xvf.size = sizeof(Pixel); xvf.addr = (XtPointer)&p; xvt.size = sizeof(XColor); xvt.addr = (XtPointer)pc; if(!XtConvertAndStore(_toplevel, XtRPixel, &xvf, XtRColor, &xvt)) pc->pixel = p; /* maybe that's enough */ #endif } unsigned long rgbpix(Bitmap *b, RGB col) { XColor c; Colormap cmap; Arg args[2]; int n, depth, dr, dg, db; RGB map[256], *m; unsigned long d, max, pixel; if (!_cmap_installed) { n = 0; XtSetArg(args[n], XtNcolormap, &cmap); n++; XtGetValues(_toplevel, args, n); c.red = col.red>>16; c.green = col.green>>16; c.blue = col.blue>>16; c.flags = DoRed|DoGreen|DoBlue; if(XAllocColor(_dpy, cmap, &c)) return (unsigned long)(c.pixel); } depth = _ld2d[screen.ldepth]; rdcolmap(&screen, map); max = -1; for (n = 0, m = map; n < (1 << depth); n++, m++) { dr = m->red - col.red; dg = m->green - col.green; db = m->blue - col.blue; d = dr*dr+dg*dg+db*db; if (d < max || max == -1) { max = d; pixel = n; } } return pixel; } void rdcolmap(Bitmap *b, RGB *map) { XColor cols[256]; int i, n, depth; Colormap cmap; Arg args[2]; if (_cmap_installed) { cmap = _libg_cmap; } else { i = 0; XtSetArg(args[i], XtNcolormap, &cmap); i++; XtGetValues(_toplevel, args, i); } depth = _ld2d[screen.ldepth]; n = 1 << depth; if (depth == 1) { map[0].red = map[0].green = map[0].blue = ~0; map[1].red = map[1].green = map[1].blue = 0; } else { if (n > 256) { berror("rdcolmap bitmap too deep"); return; } for (i = 0; i < n; i++) cols[i].pixel = i; XQueryColors(_dpy, cmap, cols, n); for (i = 0; i < n; i++) { map[i].red = (cols[i].red << 16) | cols[i].red; map[i].green = (cols[i].green << 16) | cols[i].green; map[i].blue = (cols[i].blue << 16) | cols[i].blue; } } } void wrcolmap(Bitmap *b, RGB *map) { int i, n, depth; Screen *scr; XColor cols[256]; Arg args[2]; XVisualInfo vi; Window w; scr = XtScreen(_toplevel); depth = _ld2d[screen.ldepth]; n = 1 << depth; if (n > 256) { berror("wrcolmap bitmap too deep"); return; } else if (depth > 1) { for (i = 0; i < n; i++) { cols[i].red = map[i].red >> 16; cols[i].green = map[i].green >> 16; cols[i].blue = map[i].blue >> 16; cols[i].pixel = i; cols[i].flags = DoRed|DoGreen|DoBlue; } if (!XMatchVisualInfo(_dpy, XScreenNumberOfScreen(scr), depth, PseudoColor, &vi)) { berror("wrcolmap can't get visual"); return; } w = XtWindow(_toplevel); _libg_cmap = XCreateColormap(_dpy, w, vi.visual, AllocAll); XStoreColors(_dpy, _libg_cmap, cols, n); i = 0; XtSetArg(args[i], XtNcolormap, _libg_cmap); i++; XtSetValues(_toplevel, args, i); _cmap_installed = 1; } } Subfont * getsubfont(char *s) { XFontStruct *fp; if(!s) return 0; fp = XLoadQueryFont(_dpy, s); if(!fp) return 0; return XFontStructtoSubfont(fp); } static Subfont * XFontStructtoSubfont(XFontStruct *fp) { XCharStruct *cp; Subfont *f; int min, max; int i; if(!fp) berror("no font"); f = (Subfont *)malloc(sizeof(Subfont)); if(!f) berror("XFontStructtoSubfont malloc"); min = fp->min_byte1; max = fp->max_byte1; f->minrow = min; f->mincol = fp->min_char_or_byte2; f->width = fp->max_char_or_byte2-fp->min_char_or_byte2+1; f->n = f->width; f->minchar = 0; f->maxchar = fp->max_char_or_byte2; if (min || max) { f->maxchar |= (max<<8); f->n *= (max-min+1); } f->id = fp->fid; f->height = fp->max_bounds.ascent + fp->max_bounds.descent; f->ascent = fp->max_bounds.ascent; f->info = (Fontchar *)malloc((f->n+1)*sizeof(Fontchar)); if(!f->info) berror("getsubfont malloc"); memset((void*)f->info, 0, (f->n+1)*sizeof(Fontchar)); for(i = 0; i < f->n; i++){ if(fp->per_char) cp = fp->per_char + i; else cp = &fp->max_bounds; f->info[i].left = cp->lbearing; f->info[i].cwidth = cp->rbearing - cp->lbearing; f->info[i].width = cp->width; f->info[i].top = 0; f->info[i].bottom = f->height; } XFreeFontInfo(0, fp, 0); return f; } int scrollfwdbut(void) { Arg arg; Boolean v; String s; XtSetArg(arg, XtNscrollForwardR, &v); XtGetValues(widg, &arg, 1); return v ? 3 : 1; } void einit(unsigned long keys) { /* * Make sure Smouse = log2(Emouse) and Skeyboard == log2(Ekeyboard) */ nsrc = 0; if(keys&Emouse){ Smouse = 0; esrc[Smouse].inuse = 1; esrc[Smouse].size = sizeof(Mouse); esrc[Smouse].count = 0; nsrc = Smouse+1; } if(keys&Ekeyboard){ Skeyboard = 1; esrc[Skeyboard].inuse = 1; esrc[Skeyboard].size = 1; esrc[Skeyboard].count = 0; if(Skeyboard >= nsrc) nsrc = Skeyboard+1; } einitcalled = 1; } unsigned long estart(unsigned long key, int fd, int n) { int i; if(fd < 0) berror("bad fd to estart"); if(n <= 0 || n > EMAXMSG) n = EMAXMSG; for(i=0; imouse = emouse(); else if(i == Skeyboard) e->kbdc = ekbd(); else if(i == Stimer) { esrc[i].head = 0; esrc[i].count = 0; } else { eb = ebread(&esrc[i]); e->n = eb->n; if(e->n > 0) memcpy((void*)e->data, (void*)eb->buf, e->n); free(eb); } return 1<next; free(eb); } esrc[i].count = 0; esrc[i].head = 0; esrc[i].tail = 0; } } Mouse emouse(void) { Mouse m; Ebuf *eb; if(!esrc[Smouse].inuse) berror("mouse events not selected"); eb = ebread(&esrc[Smouse]); memcpy((void*)&m, (void*)eb->buf, sizeof(Mouse)); free(eb); return m; } int ekbd(void) { Ebuf *eb; int c; if(!esrc[Skeyboard].inuse) berror("keyboard events not selected"); eb = ebread(&esrc[Skeyboard]); c = BGSHORT(eb->buf); free(eb); return c; } int ecanread(unsigned long keys) { int i; for(;;){ for(i=0; ihead == 0) waitevent(); eb = s->head; s->head = s->head->next; if(s->head == 0) { s->tail = 0; s->count = 0; } else s->count--; #ifdef COMPRESSMOUSE if ((s == &esrc[Smouse]) && (s->head)) { Ebuf *t = s->head; while(t->next && ((Mouse*) t->buf)->buttons == ((Mouse*) t->next->buf)->buttons) { s->head = t->next; s->count--; free(t); t = s->head; } } #endif return eb; } static Ebuf* ebadd(Esrc *s) { Ebuf *eb; int m; m = sizeof(Ebuf); if(s->size > 1) m += (s->size-1); /* overestimate, because of alignment */ eb = (Ebuf *)malloc(m); if(eb) { eb->next = 0; eb->n = s->size; if(s->tail){ s->tail->next = eb; s->tail = eb; }else s->head = s->tail = eb; } return eb; } void berror(char *s) { if(onerr) (*onerr)(s); else{ fprintf(stderr, "libg error: %s:\n", s); exit(1); } } void bflush(void) { while(XtAppPending(app) & XtIMXEvent) waitevent(); } static void waitevent(void) { XtInputMask mask; XFlush(_dpy); mask = XtAppPending(app); if (mask & XtIMXEvent) XtAppProcessEvent(app, XtIMXEvent); else XtAppProcessEvent(app, XtIMAll); } int snarfswap(char *s, int n, char **t) { *t = GwinSelectionSwap(widg, s); if (*t) return strlen(*t); return 0; } char* select_get(void) { return Gwinselect_get(widg); } void select_put(char*s) { Gwinselect_put(widg,s); } int scrpix(int *w, int *h) { if (w) *w = WidthOfScreen(XtScreen(_toplevel)); if (h) *h = HeightOfScreen(XtScreen(_toplevel)); return 1; } #ifdef DEBUG /* for debugging */ printgc(char *msg, GC g) { XGCValues v; XGetGCValues(_dpy, g, GCFunction|GCForeground|GCBackground|GCFont| GCTile|GCFillStyle|GCStipple, &v); fprintf(stderr, "%s: gc %x\n", msg, g); fprintf(stderr, " fg %d bg %d func %d fillstyle %d font %x tile %x stipple %x\n", v.foreground, v.background, v.function, v.fill_style, v.font, v.tile, v.stipple); } #endif atic wily-0.13.42/libXg/circle.c000064402366570000012000000006241033320152300151500ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include "libgint.h" void circle(Bitmap *b, Point p, int r, int v, Fcode f) { unsigned int d; int x, y; GC g; x = p.x - r; y = p.y - r; if (b->flag&SHIFT){ x -= b->r.min.x; y -= b->r.min.y; } d = 2*r; g = _getfillgc(f, b, v); XDrawArc(_dpy, (Drawable)b->id, g, x, y, d, d, 0, 23040/* 360 deg */); } wily-0.13.42/libXg/rune.c000064402366570000012000000053221033320152300146600ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include enum { Bit1 = 7, Bitx = 6, Bit2 = 5, Bit3 = 4, Bit4 = 3, T1 = ((1<<(Bit1+1))-1) ^ 0xFF, /* 0000 0000 */ Tx = ((1<<(Bitx+1))-1) ^ 0xFF, /* 1000 0000 */ T2 = ((1<<(Bit2+1))-1) ^ 0xFF, /* 1100 0000 */ T3 = ((1<<(Bit3+1))-1) ^ 0xFF, /* 1110 0000 */ T4 = ((1<<(Bit4+1))-1) ^ 0xFF, /* 1111 0000 */ Rune1 = (1<<(Bit1+0*Bitx))-1, /* 0000 0000 0111 1111 */ Rune2 = (1<<(Bit2+1*Bitx))-1, /* 0000 0111 1111 1111 */ Rune3 = (1<<(Bit3+2*Bitx))-1, /* 1111 1111 1111 1111 */ Maskx = (1< T1 */ c = *(uchar*)str; if(c < Tx) { *rune = c; return 1; } /* * two character sequence * 0080-07FF => T2 Tx */ c1 = *(uchar*)(str+1) ^ Tx; if(c1 & Testx) goto bad; if(c < T3) { if(c < T2) goto bad; l = ((c << Bitx) | c1) & Rune2; if(l <= Rune1) goto bad; *rune = l; return 2; } /* * three character sequence * 0800-FFFF => T3 Tx Tx */ c2 = *(uchar*)(str+2) ^ Tx; if(c2 & Testx) goto bad; if(c < T4) { l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3; if(l <= Rune2) goto bad; *rune = l; return 3; } /* * bad decoding */ bad: *rune = Bad; return 1; } int runetochar(char *str, Rune *rune) { long c; /* * one character sequence * 00000-0007F => 00-7F */ c = *rune; if(c <= Rune1) { str[0] = c; return 1; } /* * two character sequence * 0080-07FF => T2 Tx */ if(c <= Rune2) { str[0] = T2 | (c >> 1*Bitx); str[1] = Tx | (c & Maskx); return 2; } /* * three character sequence * 0800-FFFF => T3 Tx Tx */ str[0] = T3 | (c >> 2*Bitx); str[1] = Tx | ((c >> 1*Bitx) & Maskx); str[2] = Tx | (c & Maskx); return 3; } int runelen(long c) { Rune rune; char str[10]; rune = c; return runetochar(str, &rune); } int fullrune(char *str, int n) { int c; if(n > 0) { c = *(uchar*)str; if(c < Tx) return 1; if(n > 1) if(c < T3 || n > 2) return 1; } return 0; } char* utfrune(char *s, long c) { long c1; Rune r; int n; if(c < Runesync) /* not part of utf sequence */ return strchr(s, c); for(;;) { c1 = *(uchar*)s; if(c1 < Runeself) { /* one byte rune */ if(c1 == 0) return 0; if(c1 == c) return s; s++; continue; } n = chartorune(&r, s); if(r == c) return s; s += n; } return 0; } long utflen(char *s) { int c; long n; Rune rune; n = 0; for(;;) { c = *(uchar*)s; if(c < Runeself) { if(c == 0) return n; s++; } else s += chartorune(&rune, s); n++; } return 0; } wily-0.13.42/libXg/texture.c000064402366570000012000000020101033320152300153760ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include "libgint.h" void texture(Bitmap *d, Rectangle r, Bitmap *s, Fcode f) { int x, y, w, h, bfunc; GC g; x = r.min.x; y = r.min.y; if(d->flag&SHIFT){ x -= d->r.min.x; y -= d->r.min.y; } g = _getcopygc(f, d, s, &bfunc); if(d->flag&SHIFT){ XSetTSOrigin(_dpy, g, -d->r.min.x, -d->r.min.y); }else XSetTSOrigin(_dpy, g, 0, 0); w = Dx(r); h = Dy(r); if(bfunc == UseFillRectangle){ /* source isn't involved at all */ XFillRectangle(_dpy, (Drawable)d->id, g, x, y, w, h); }else if(bfunc == UseCopyArea){ XSetTile(_dpy, g, (Drawable)s->id); XSetFillStyle(_dpy, g, FillTiled); XFillRectangle(_dpy, (Drawable)d->id, g, x, y, w, h); XSetFillStyle(_dpy, g, FillSolid); }else{ if(s->ldepth != 0) berror("unsupported texture"); XSetStipple(_dpy, g, (Drawable)s->id); XSetFillStyle(_dpy, g, FillOpaqueStippled); XFillRectangle(_dpy, (Drawable)d->id, g, x, y, w, h); XSetFillStyle(_dpy, g, FillSolid); } } ight (c) 1992 AT&T - All rights reserved. */ #include #include #include "libgint.h" void texture(Bitmap *d, Rectangle r, Bitmap *s, Fcode f) { int x, y, w, h, bfunc; GC g; x = r.min.x; y = r.min.y; if(d->flag&SHIFT){ x -= d->r.min.x; y -= d->r.min.y; } g = _getcopygc(f, d, s, &bfunc); if(d->flag&SHIFT){ XSetTSOrigin(_dpy, g, -d->r.min.x, -d->r.min.y); }else XSetTSOrigin(_dpy, g, 0, 0); w = Dx(r); h = Dy(r); if(bfunc == UseFillRectangle){ /* source isn't invowily-0.13.42/libXg/test.c000064402366570000012000000133711033320152300146710ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #ifdef HAVE_STDLIB_H #include #endif #include #include void cont(char *); void putstring(char *); void colorinit(void); void printcolmap(void); void invertcolmap(void); unsigned char arrowset[] = {0x00, 0x00, 0x7F, 0xC0, 0x7F, 0x00, 0x7C, 0x00, 0x7E, 0x00, 0x7F, 0x00, 0x6F, 0x80, 0x67, 0xC0, 0x43, 0xE0, 0x41, 0xF0, 0x00, 0xF8, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x1C, 0x00, 0x08, 0x00, 0x00}; char *colors[] = { "Black", "Red", "Green", "Yellow", "Cyan", "Magenta", "Blue", "White" }; RGB colordefs[] = { { 0,0,0 }, /* black */ {0xFFFFFFFF, 0x00000000, 0x00000000}, /* red */ {0x00000000, 0xFFFFFFFF, 0x00000000}, /* green */ {0xFFFFFFFF, 0xFFFFFFFF, 0x00000000}, /* yellow */ {0x00000000, 0xFFFFFFFF, 0xFFFFFFFF}, /* cyan */ {0xFFFFFFFF, 0x00000000, 0xFFFFFFFF}, /* magenta */ {0x00000000, 0x00000000, 0xFFFFFFFF}, /* blue */ {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, /* white */ }; #define Ncol (sizeof(colordefs)/sizeof(colordefs[0])) unsigned long rgbval[Ncol]; Bitmap *rgbbitmap[Ncol]; main(int argc, char **argv) { Point p1,p2,p3; Mouse m; int r,rx,ry; int n, i; char *m3gen(int); static Menu menu3 = { (char **) 0, m3gen, 0 }; char *p, buf[200]; Bitmap *bm, *bm2; RGB cmap[256]; xtbinit(0,0,&argc,argv,0); einit(Ekeyboard|Emouse); p1 = add(screen.r.min, Pt(15,15)); p2 = sub(screen.r.max, Pt(15,15)); p3 = divpt(add(p1,p2),2); fprintf(stderr, "segment(&screen, (%d,%d), (%d,%d), ~0, S)\n", p1.x,p1.y,p2.x,p2.y); segment(&screen, p1, p2, ~0, S); cont("point"); fprintf(stderr, "point(&screen, (%d,%d), ~0, S)\n", p1.x,p1.y); point(&screen, p1, ~0, S); cont("circle"); rx = p3.x - p1.x; ry = p3.y - p1.y; r = (rx < ry)? rx : ry; fprintf(stderr, "circle(&screen, (%d,%d), %d, ~0, S)\n", p3.x,p3.y,r); circle(&screen, p3, r, ~0, S); cont("disc"); fprintf(stderr, "disc(&screen, (%d,%d), %d, ~0, S)\n", p3.x,p3.y,r); disc(&screen, p3, r, ~0, S); cont("clipped disc"); fprintf(stderr, "clipr(&screen, ((%d,%d)(%d,%d))\n", p1.x+30, p1.y+5, p3.x-30, p3.y-5); clipr(&screen, Rect(p1.x+30, p1.y+5, p3.x-30, p3.y-5)); fprintf(stderr, "disc(&screen, (%d,%d), %d, ~0, S)\n", p3.x,p3.y,r); disc(&screen, p3, r, ~0, S); clipr(&screen, screen.r); cont("ellipse"); fprintf(stderr, "ellipse(&screen, (%d,%d), %d, %d, ~0, S)\n", p3.x,p3.y,r,r/2); ellipse(&screen, p3, r, r/2, ~0, S); cont("arc"); fprintf(stderr, "arc(&screen, (%d,%d), (%d,%d), (%d,%d), ~0, S)\n", p3.x,p3.y, p3.x+r,p3.y, p3.x+r/2,p3.x-(int)(r*.866)); arc(&screen, p3, Pt(p3.x+r,p3.y), Pt(p3.x+r/2,p3.x-(int)(r*.866)), ~0, S); if(screen.ldepth > 1){ cont("color"); colorinit(); p3 = p1; rx *= 2; ry *= 2; for(i = 0; iheight), Zero); string(&screen, p, font, buf, F); if ((l = strwidth(font, buf)) > jmax) jmax = l; } void cont(char *msg) { Event ev; Point mp; while(event(&ev) != Ekeyboard) continue; bitblt(&screen, Pt(0,0), &screen, screen.r, Zero); mp = add(screen.r.min, Pt(20,20)); string(&screen, mp, font, msg, S); while(event(&ev) != Ekeyboard) continue; bitblt(&screen, Pt(0,0), &screen, screen.r, Zero); } char * m3gen(int n) { static char *m3[] ={ "quit", "thing1", "thing2" }; if (n < 0 || n > 2) return 0; else return m3[n]; } void ereshaped(Rectangle r) { } wily-0.13.42/libXg/wrbitmap.c000064402366570000012000000025021033320152300155310ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include "libgint.h" #include #ifndef XtSpecificationRelease #define R3 #endif #include void wrbitmap(Bitmap *b, int miny, int maxy, unsigned char *data) { XImage *im; int w, h, inld, outld, l, offset, px; GC g; char *tdata; w = Dx(b->r); h = maxy - miny; inld = b->ldepth; outld = (b->ldepth == 0) ? 0 : screen.ldepth; px = 1<<(3-outld); /* pixels per byte */ /* set l to number of bytes of data per scan line */ if(b->r.min.x >= 0) offset = b->r.min.x % px; else offset = px - b->r.min.x % px; l = (-b->r.min.x+px-1)/px; if(b->r.max.x >= 0) l += (b->r.max.x+px-1)/px; else l -= b->r.max.x/px; l *= h; tdata = (char *)malloc(l); if (tdata == (char *) 0) berror("wrbitmap malloc"); if (inld == outld) memcpy((void*)tdata, (void*)data, l); else _ldconvert((char*)data, inld, tdata, outld, w, h); im = XCreateImage(_dpy, 0, 1 << outld, ZPixmap, 0, tdata, w, h, 8, 0); /* Botched interface to XCreateImage doesn't let you set these: */ im->bitmap_bit_order = MSBFirst; im->byte_order = MSBFirst; g = _getfillgc(S, b, ~0); XSetBackground(_dpy, g, b->flag&DP1 ? 0 : _bgpixel); XPutImage(_dpy, (Drawable)b->id, g, im, offset, 0, 0, miny - b->r.min.y, w-offset, h); XDestroyImage(im); } wily-0.13.42/libXg/mkfont.c000064402366570000012000000020241033320152300152010ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include /* * Cobble fake font using existing subfont */ Font* mkfont(Subfont *subfont) { Font *font; unsigned char *gbuf; Cachesubf *c; char *cp; font = (Font *)malloc(sizeof(Font)); if(font == 0) return 0; memset((void*)font, 0, sizeof(Font)); cp = ""; font->name = (char *)malloc(strlen(cp)+1); if (font->name == 0) { free(font); return 0; } strcpy(font->name, cp); font->nsubf = 1; font->subf = (Cachesubf *)malloc(font->nsubf * sizeof(Cachesubf)); if(font->subf == 0) { free(font->name); free(font); return 0; } memset((void*)font->subf, 0, font->nsubf*sizeof(Cachesubf)); font->height = subfont->height; font->ascent = subfont->ascent; font->ldepth = screen.ldepth; c = font->subf; subfont->minchar = subfont->mincol; /* base font at first char */ c->min = subfont->minchar; c->max = subfont->maxchar; c->name = 0; /* noticed by freeup() */ font->subf[0].f = subfont; return font; } wily-0.13.42/libXg/arith.c000064402366570000012000000045401033320152300150170ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include Point add(Point a, Point b) { a.x += b.x; a.y += b.y; return a; } Point sub(Point a, Point b) { a.x -= b.x; a.y -= b.y; return a; } Rectangle inset(Rectangle r, int n) { r.min.x += n; r.min.y += n; r.max.x -= n; r.max.y -= n; return r; } Point divpt(Point a, int b) { a.x /= b; a.y /= b; return a; } Point mul(Point a, int b) { a.x *= b; a.y *= b; return a; } Rectangle rsubp(Rectangle r, Point p) { r.min.x -= p.x; r.min.y -= p.y; r.max.x -= p.x; r.max.y -= p.y; return r; } Rectangle raddp(Rectangle r, Point p) { r.min.x += p.x; r.min.y += p.y; r.max.x += p.x; r.max.y += p.y; return r; } Rectangle rmul(Rectangle r, int a) { if (a != 1) { r.min.x *= a; r.min.y *= a; r.max.x *= a; r.max.y *= a; } return r; } Rectangle rdiv(Rectangle r, int a) { if (a != 1) { r.min.x /= a; r.min.y /= a; r.max.x /= a; r.max.y /= a; } return r; } Rectangle rshift(Rectangle r, int a) { if (a > 0) { r.min.x <<= a; r.min.y <<= a; r.max.x <<= a; r.max.y <<= a; } else if (a < 0) { a = -a; r.min.x >>= a; r.min.y >>= a; r.max.x >>= a; r.max.y >>= a; } return r; } eqpt(Point p, Point q) { return p.x==q.x && p.y==q.y; } eqrect(Rectangle r, Rectangle s) { return r.min.x==s.min.x && r.max.x==s.max.x && r.min.y==s.min.y && r.max.y==s.max.y; } rectXrect(Rectangle r, Rectangle s) { return r.min.x=s.min.x && r.min.x=s.min.y && r.min.y=r.min.x && p.x=r.min.y && p.y #include #include "libgint.h" Bitmap* balloc(Rectangle r, int ldepth) { Bitmap *b; b = _balloc(r, ldepth); bitblt(b, r.min, b, r, Zero); return b; } Bitmap* _balloc(Rectangle r, int ldepth) { int id; Bitmap *b; int ld; Rectangle rx; b = (Bitmap *)malloc(sizeof(Bitmap)); if(b == 0) berror("balloc malloc"); if (ldepth == 0) ld = 0; else ld = screen.ldepth; rx = r; if (Dx(rx) == 0) rx.max.x++; if (Dy(rx) == 0) rx.max.y++; id = (int) XCreatePixmap(_dpy, (Drawable)screen.id, Dx(rx), Dy(rx), _ld2d[ld]); b->ldepth = ldepth; b->r = r; b->clipr = r; b->id = id; b->cache = 0; if(ldepth == 0) b->flag = DP1|BL1; else b->flag = screen.flag&BL1; if(r.min.x==0 && r.min.y ==0) b->flag |= ZORG; else b->flag |= SHIFT; return b; } void bfree(Bitmap *b) { XFreePixmap(_dpy, (Pixmap)b->id); free(b); } wily-0.13.42/libXg/latin1.c000064402366570000012000000167421033320152300151070ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ struct latin { unsigned short l; unsigned char c[2]; }latintab[] = { 0x00a1, '!','!', /* spanish initial ! */ 0x00a2, 'c','$', /* cent */ 0x00a3, 'l','$', /* pound sterling */ 0x00a4, 'g','$', /* general currency */ 0x00a5, 'y','$', /* yen */ 0x00a6, '|','|', /* broken vertical bar */ 0x00a7, 'S','S', /* section symbol */ 0x00a8, '\"','\"', /* dieresis */ 0x00a9, 'c','O', /* copyright */ 0x00aa, 's','a', /* super a, feminine ordinal */ 0x00ab, '<','<', /* left angle quotation */ 0x00ac, 'n','o', /* not sign, hooked overbar */ 0x00ad, '-','-', /* soft hyphen */ 0x00ae, 'r','O', /* registered trademark */ 0x00af, '_','_', /* macron */ 0x00b0, 'd','e', /* degree */ 0x00b1, '+','-', /* plus-minus */ 0x00b2, 's','2', /* sup 2 */ 0x00b3, 's','3', /* sup 3 */ 0x00b4, '\'','\'', /* acute accent */ 0x00b5, 'm','i', /* micron */ 0x00b6, 'p','g', /* paragraph (pilcrow) */ 0x00b7, '.','.', /* centered . */ 0x00b8, ',',',', /* cedilla */ 0x00b9, 's','1', /* sup 1 */ 0x00ba, 's','o', /* super o, masculine ordinal */ 0x00bb, '>','>', /* right angle quotation */ 0x00bc, '1','4', /* 1/4 */ 0x00bd, '1','2', /* 1/2 */ 0x00be, '3','4', /* 3/4 */ 0x00bf, '?','?', /* spanish initial ? */ 0x00c0, '`','A', /* A grave */ 0x00c1, '\'','A', /* A acute */ 0x00c2, '^','A', /* A circumflex */ 0x00c3, '~','A', /* A tilde */ 0x00c4, '\"','A', /* A dieresis */ 0x00c5, 'o','A', /* A circle */ 0x00c6, 'A','E', /* AE ligature */ 0x00c7, ',','C', /* C cedilla */ 0x00c8, '`','E', /* E grave */ 0x00c9, '\'','E', /* E acute */ 0x00ca, '^','E', /* E circumflex */ 0x00cb, '\"','E', /* E dieresis */ 0x00cc, '`','I', /* I grave */ 0x00cd, '\'','I', /* I acute */ 0x00ce, '^','I', /* I circumflex */ 0x00cf, '\"','I', /* I dieresis */ 0x00d0, 'D','-', /* Eth */ 0x00d1, '~','N', /* N tilde */ 0x00d2, '`','O', /* O grave */ 0x00d3, '\'','O', /* O acute */ 0x00d4, '^','O', /* O circumflex */ 0x00d5, '~','O', /* O tilde */ 0x00d6, '\"','O', /* O dieresis */ 0x00d7, 'm','u', /* times sign */ 0x00d8, '/','O', /* O slash */ 0x00d9, '`','U', /* U grave */ 0x00da, '\'','U', /* U acute */ 0x00db, '^','U', /* U circumflex */ 0x00dc, '\"','U', /* U dieresis */ 0x00dd, '\'','Y', /* Y acute */ 0x00de, '|','P', /* Thorn */ 0x00df, 's','s', /* sharp s */ 0x00e0, '`','a', /* a grave */ 0x00e1, '\'','a', /* a acute */ 0x00e2, '^','a', /* a circumflex */ 0x00e3, '~','a', /* a tilde */ 0x00e4, '\"','a', /* a dieresis */ 0x00e5, 'o','a', /* a circle */ 0x00e6, 'a','e', /* ae ligature */ 0x00e7, ',','c', /* c cedilla */ 0x00e8, '`','e', /* e grave */ 0x00e9, '\'','e', /* e acute */ 0x00ea, '^','e', /* e circumflex */ 0x00eb, '\"','e', /* e dieresis */ 0x00ec, '`','i', /* i grave */ 0x00ed, '\'','i', /* i acute */ 0x00ee, '^','i', /* i circumflex */ 0x00ef, '\"','i', /* i dieresis */ 0x00f0, 'd','-', /* eth */ 0x00f1, '~','n', /* n tilde */ 0x00f2, '`','o', /* o grave */ 0x00f3, '\'','o', /* o acute */ 0x00f4, '^','o', /* o circumflex */ 0x00f5, '~','o', /* o tilde */ 0x00f6, '\"','o', /* o dieresis */ 0x00f7, '-',':', /* divide sign */ 0x00f8, '/','o', /* o slash */ 0x00f9, '`','u', /* u grave */ 0x00fa, '\'','u', /* u acute */ 0x00fb, '^','u', /* u circumflex */ 0x00fc, '\"','u', /* u dieresis */ 0x00fd, '\'','y', /* y acute */ 0x00fe, '|','p', /* thorn */ 0x00ff, '\"','y', /* y dieresis */ 0x2654, 'w','k', /* chess white king */ 0x2655, 'w','q', /* chess white queen */ 0x2656, 'w','r', /* chess white rook */ 0x2657, 'w','b', /* chess white bishop */ 0x2658, 'w','n', /* chess white knight */ 0x2659, 'w','p', /* chess white pawn */ 0x265a, 'b','k', /* chess black king */ 0x265b, 'b','q', /* chess black queen */ 0x265c, 'b','r', /* chess black rook */ 0x265d, 'b','b', /* chess black bishop */ 0x265e, 'b','n', /* chess black knight */ 0x265f, 'b','p', /* chess black pawn */ 0x03b1, '*','a', /* alpha */ 0x03b2, '*','b', /* beta */ 0x03b3, '*','g', /* gamma */ 0x03b4, '*','d', /* delta */ 0x03b5, '*','e', /* epsilon */ 0x03b6, '*','z', /* zeta */ 0x03b7, '*','y', /* eta */ 0x03b8, '*','h', /* theta */ 0x03b9, '*','i', /* iota */ 0x03ba, '*','k', /* kappa */ 0x03bb, '*','l', /* lambda */ 0x03bc, '*','m', /* mu */ 0x03bd, '*','n', /* nu */ 0x03be, '*','c', /* xsi */ 0x03bf, '*','o', /* omicron */ 0x03c0, '*','p', /* pi */ 0x03c1, '*','r', /* rho */ 0x03c2, 't','s', /* terminal sigma */ 0x03c3, '*','s', /* sigma */ 0x03c4, '*','t', /* tau */ 0x03c5, '*','u', /* upsilon */ 0x03c6, '*','f', /* phi */ 0x03c7, '*','x', /* chi */ 0x03c8, '*','q', /* psi */ 0x03c9, '*','w', /* omega */ 0x0391, '*','A', /* Alpha */ 0x0392, '*','B', /* Beta */ 0x0393, '*','G', /* Gamma */ 0x0394, '*','D', /* Delta */ 0x0395, '*','E', /* Epsilon */ 0x0396, '*','Z', /* Zeta */ 0x0397, '*','Y', /* Eta */ 0x0398, '*','H', /* Theta */ 0x0399, '*','I', /* Iota */ 0x039a, '*','K', /* Kappa */ 0x039b, '*','L', /* Lambda */ 0x039c, '*','M', /* Mu */ 0x039d, '*','N', /* Nu */ 0x039e, '*','C', /* Xsi */ 0x039f, '*','O', /* Omicron */ 0x03a0, '*','P', /* Pi */ 0x03a1, '*','R', /* Rho */ 0x03a3, '*','S', /* Sigma */ 0x03a4, '*','T', /* Tau */ 0x03a5, '*','U', /* Upsilon */ 0x03a6, '*','F', /* Phi */ 0x03a7, '*','X', /* Chi */ 0x03a8, '*','Q', /* Psi */ 0x03a9, '*','W', /* Omega */ 0x2190, '<','-', /* left arrow */ 0x2191, 'u','a', /* up arrow */ 0x2192, '-','>', /* right arrow */ 0x2193, 'd','a', /* down arrow */ 0x2194, 'a','b', /* arrow both */ 0x21d0, 'V','=', /* left double-line arrow */ 0x21d2, '=','V', /* right double-line arrow */ 0x2200, 'f','a', /* forall */ 0x2203, 't','e', /* there exists */ 0x2202, 'p','d', /* partial differential */ 0x2205, 'e','s', /* empty set */ 0x2206, 'D','e', /* delta */ 0x2207, 'g','r', /* gradient */ 0x2208, 'm','o', /* element of */ 0x2209, '!','m', /* not element of */ 0x220d, 's','t', /* such that */ 0x2217, '*','*', /* math asterisk */ 0x2219, 'b','u', /* bullet */ 0x221a, 's','r', /* radical */ 0x221d, 'p','t', /* proportional */ 0x221e, 'i','f', /* infinity */ 0x2220, 'a','n', /* angle */ 0x2227, 'l','&', /* logical and */ 0x2228, 'l','|', /* logical or */ 0x2229, 'c','a', /* intersection */ 0x222a, 'c','u', /* union */ 0x222b, 'i','s', /* integral */ 0x2234, 't','f', /* therefore */ 0x2243, '~','=', /* asymptotically equal */ 0x2245, 'c','g', /* congruent */ 0x2248, '~','~', /* almost equal */ 0x2260, '!','=', /* not equal */ 0x2261, '=','=', /* equivalent */ 0x2266, '<','=', /* less than or equal */ 0x2267, '>','=', /* greater than or equal */ 0x2282, 's','b', /* proper subset */ 0x2283, 's','p', /* proper superset */ 0x2284, '!','b', /* not subset */ 0x2286, 'i','b', /* reflexive subset */ 0x2287, 'i','p', /* reflexive superset */ 0x2295, 'O','+', /* circle plus */ 0x2296, 'O','-', /* circle minus */ 0x2297, 'O','x', /* circle multiply */ 0x22a2, 't','u', /* turnstile */ 0x22a8, 'T','u', /* valid */ 0x22c4, 'l','z', /* lozenge */ 0x22ef, 'e','l', /* ellipses */ 0x2639, ':','(', /* saddy */ 0x263a, ':',')', /* white-face smiley */ 0x263b, ';',')', /* dark-face smiley */ 0, 0, }; long latin1(unsigned char *k) { struct latin *l; for(l=latintab; l->l; l++) if(k[0]==l->c[0] && k[1]==l->c[1]) return l->l; return -1; } long unicode(unsigned char *k) { long i, c; k++; /* skip 'X' */ c = 0; for(i=0; i<4; i++,k++){ c <<= 4; if('0'<=*k && *k<='9') c += *k-'0'; else if('a'<=*k && *k<='f') c += 10 + *k-'a'; else if('A'<=*k && *k<='F') c += 10 + *k-'A'; else return -1; } return c; } k */ 0x2657, 'w','b', /* cheswily-0.13.42/libXg/string.c000064402366570000012000000021051033320152300152110ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include "libgint.h" enum { Max = 128 }; Point string(Bitmap *b, Point p, Font *ft, char *s, Fcode f) { int x, y, wid, i, j, n, nti, cf; XChar2b cbuf[Max]; unsigned short fbuf[Max]; XTextItem16 ti[Max]; Rune r; GC g; x = p.x; y = p.y; if (b->flag&SHIFT){ x -= b->r.min.x; y -= b->r.min.y; } y += ft->ascent; g = _getfillgc(f, b, ~0); while (*s) { n = cachechars(ft, &s, cbuf, Max, &wid, fbuf); if (n <= 0) { s += chartorune(&r, s); continue; } nti = 0; cf = fbuf[0]; /* first font */ ti[0].chars = cbuf; ti[0].delta = 0; ti[0].font = (xFont)ft->subf[cf].f->id; for (i = 1, j = 1; i < n; i++, j++) { if (fbuf[i] != cf) { /* font change */ cf = fbuf[i]; ti[nti++].nchars = j; ti[nti].chars = &cbuf[i]; ti[nti].delta = 0; ti[nti].font = (xFont)ft->subf[cf].f->id; j = 0; } } ti[nti++].nchars = j; XDrawText16(_dpy, (Drawable)b->id, g, x, y, ti, nti); x += wid; } p.x = (b->flag&SHIFT) ? x + b->r.min.x : x; return p; } wily-0.13.42/libXg/border.c000064402366570000012000000016041033320152300151630ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include void border(Bitmap *l, Rectangle r, int i, Fcode c) { if(i > 0){ bitblt(l, r.min, l, Rect(r.min.x, r.min.y, r.max.x, r.min.y+i), c); bitblt(l, Pt(r.min.x, r.max.y-i), l, Rect(r.min.x, r.max.y-i, r.max.x, r.max.y), c); bitblt(l, Pt(r.min.x, r.min.y+i), l, Rect(r.min.x, r.min.y+i, r.min.x+i, r.max.y-i), c); bitblt(l, Pt(r.max.x-i, r.min.y+i), l, Rect(r.max.x-i, r.min.y+i, r.max.x, r.max.y-i), c); }else if(i < 0){ bitblt(l, Pt(r.min.x, r.min.y+i), l, Rect(r.min.x, r.min.y+i, r.max.x, r.min.y), c); bitblt(l, Pt(r.min.x, r.max.y), l, Rect(r.min.x, r.max.y, r.max.x, r.max.y-i), c); bitblt(l, Pt(r.min.x+i, r.min.y+i), l, Rect(r.min.x+i, r.min.y+i, r.min.x, r.max.y-i), c); bitblt(l, Pt(r.max.x, r.min.y+i), l, Rect(r.max.x, r.min.y+i, r.max.x-i, r.max.y-i), c); } } wily-0.13.42/libXg/point.c000064402366570000012000000005151033320152300150370ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include "libgint.h" void point(Bitmap *b, Point p, int v, Fcode f) { int x, y; GC g; x = p.x; y = p.y; if(b->flag&SHIFT){ x -= b->r.min.x; y -= b->r.min.y; } g = _getfillgc(f, b, v); XDrawPoint(_dpy, (Drawable)b->id, g, x, y); } wily-0.13.42/libXg/rectclip.c000064402366570000012000000011351033320152300155120ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include rectclip(Rectangle *rp, Rectangle b) /* first by reference, second by value */ { Rectangle *bp = &b; /* * Expand rectXrect() in line for speed */ if((rp->min.xmax.x && bp->min.xmax.x && rp->min.ymax.y && bp->min.ymax.y)==0) return 0; /* They must overlap */ if(rp->min.x < bp->min.x) rp->min.x = bp->min.x; if(rp->min.y < bp->min.y) rp->min.y = bp->min.y; if(rp->max.x > bp->max.x) rp->max.x = bp->max.x; if(rp->max.y > bp->max.y) rp->max.y = bp->max.y; return 1; } wily-0.13.42/libXg/clipr.c000064402366570000012000000005671033320152300150260ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include "libgint.h" int clipr(Bitmap *d, Rectangle r) { if(rectclip(&r, d->r) == 0) return 0; d->clipr = r; if(r.min.x != d->r.min.x || r.min.y != d->r.min.y || r.max.x != d->r.max.x || r.max.y != d->r.max.y) d->flag |= CLIP; else d->flag &= ~CLIP; return 1; } wily-0.13.42/libXg/Makefile000064402366570000012000000012351041526267400152210ustar00ozstaff00004330000002# Generated automatically from Makefile.in by configure. srcdir=. CC=gcc RANLIB=ranlib INCLUDES=$(srcdir)/../include CFLAGS=-g -O -I.. -I$(INCLUDES) -I/usr/openwin/include LIB=libXg.a OBJS=arc.o arith.o balloc.o bitblt.o bitbltclip.o border.o bscreenrect.o\ circle.o clipline.o clipr.o copymasked.o cursorset.o cursorswitch.o\ disc.o ellipse.o font.o gcs.o getrect.o gwin.o ldconvert.o latin1.o\ mkfont.o menuhit.o point.o polysegment.o rdbitmap.o rdbitmapfile.o\ rdfontfile.o rectclip.o rune.o segment.o string.o strwidth.o texture.o\ wrbitmap.o wrbitmapfile.o xtbinit.o include $(INCLUDES)/Makelib $(OBJS): $(INCLUDES)/u.h $(INCLUDES)/libc.h $(INCLUDES)/libg.h wily-0.13.42/tools/000075502366570000012000000000001033320152300136345ustar00ozstaff00004330000002wily-0.13.42/tools/old/000075502366570000012000000000001033320152300144125ustar00ozstaff00004330000002wily-0.13.42/tools/old/sh/000075502366570000012000000000001033320152300150245ustar00ozstaff00004330000002wily-0.13.42/tools/old/sh/rpc.c000064402366570000012000000014431033320152300157560ustar00ozstaff00004330000002#include #include #include #include #include #include int main(int argc, char **argv) { int fd; char *fdenv; char *type; Mtype mt; int t; Mqueue q; Msg *m; fdenv = getenv("WILYFD"); if(!fdenv) { fprintf(stderr,"$WILYFD must be set\n"); exit(1); } fd = atoi(fdenv); if(argc<2){ fprintf(stderr,"usage: %s message-type [args]", argv[0]); exit(1); } type = argv[1]; t = name2type(type); if(t<0) { fprintf(stderr,"couldn't recognise [%s] as a type of wily message\n", type); exit(1); } mt =t ; mq_init(&q, fd); fd_send_array(fd, mt, argv+2, argc-2); while( (m= mq_next(&q, 0)) ) { msg_print(m); if(m->mtype == mt || m->mtype == Merror || m->mtype == Mok) break; msg_free(m); free(m); } return 0; } wily-0.13.42/tools/old/sh/README000064402366570000012000000005411033320152300157040ustar00ozstaff00004330000002wcmd prog [args] connect to wily, set $WILYFD to be the file descriptor, then run 'prog' rpc type [args] packs its arguments up in the wily message format (currently headed by a length field, and separated by nulls) and sends the message out on WILYFD, waits for the response (printing and discarding events), and prints the response on stdout. wily-0.13.42/tools/old/sh/Makefile.in000064402366570000012000000010361033320152300170710ustar00ozstaff00004330000002srcdir=@srcdir@ VPATH=@srcdir@ OBJECTS= wcmd.o rpc.o TARGETS=wcmd rpc CC=@CC@ RANLIB=@RANLIB@ CFLAGS=@CFLAGS@ -I../include -I.. -I$(srcdir)/../include @X_CFLAGS@ MYLIBS=../libmsg/libmsg.a ../libXg/libXg.a all: $(TARGETS) $(TARGETS): $(MYLIBS) wcmd: wcmd.o $(CC) $(LDFLAGS) -o wcmd wcmd.o $(MYLIBS) $(LIBS) @X_EXTRA_LIBS@ rpc: rpc.o $(CC) $(LDFLAGS) -o rpc rpc.o $(MYLIBS) $(LIBS) @X_EXTRA_LIBS@ $(OBJECTS): ../include/libmsg.h clean: rm -f *.o core *pure* nuke: clean rm -f $(TARGETS) install: $(TARGET) cp $(TARGET) ../$(TARGET).$(SYS) wily-0.13.42/tools/old/sh/wcmd.c000064402366570000012000000007111033320152300161210ustar00ozstaff00004330000002#include #include #include #include #include #include void main(int argc, char **argv) { int fd; char buf[1024]; /* connect to wily */ fd = get_connect(); if(fd<0) { perror("get_connect"); exit(1); } /* make it file descriptor 3 */ sprintf(buf,"WILYFD=%d", fd); if(putenv(buf)){ perror("putenv"); exit(1); } /* start up the other program */ argv++; execvp(argv[0],argv); } wily-0.13.42/tools/old/edit/000075502366570000012000000000001033320152300153375ustar00ozstaff00004330000002wily-0.13.42/tools/old/edit/c.c000064402366570000012000000036411033320152300157310ustar00ozstaff00004330000002/* * c.c - this handles the c, i, a and d commands. */ #include "range.h" Bool debug = false; static Rune *rarg0, *rarg1; /* * Convert the supplied arg into Runes which can be inserted into the * new tmp file at appropriate points. */ static void argtorune(char *utfarg) { int len = strlen(utfarg); /* XXX - this is a guess - I'm assuming that n bytes of UTF won't take more than n Runes to store, but I'm allocing more here out of paranoia. */ rarg0 = salloc(len*(sizeof(Rune)+1)); for (rarg1 = rarg0; len--; rarg1++) if (*(uchar *)utfarg < Runeself) *rarg1 = *utfarg++; else utfarg += chartorune(rarg1, utfarg); return; } /* * change functions are simple - we're given the text to be * changed in, *r0 and *r1, and we change the two pairs of * pointers to what is to be written to the file, or to null, * if the given range isn't to be written. */ static int fn_c(Rune **r0, Rune **r1, Rune **r2, Rune **r3) { *r0 = rarg0; *r1 = rarg1; *r2 = *r3 = 0; return 1; } static int fn_i(Rune **r0, Rune **r1, Rune **r2, Rune **r3) { *r2 = *r0; *r3 = *r1; *r0 = rarg0; *r1 = rarg1; return 1; } static int fn_a(Rune **r0, Rune **r1, Rune **r2, Rune **r3) { *r2 = rarg0; *r3 = rarg1; return 1; } static int fn_d(Rune **r0, Rune **r1, Rune **r2, Rune **r3) { *r0 = *r1 = *r2 = *r3 = 0; return 1; } int main(int argc, char *argv[]) { char *p; size_t len; Subrange *r; int (*fn)(Rune **r0, Rune **r1, Rune **r2, Rune **r3); p = strrchr(argv[0], '/'); p = p? p+1 : argv[0]; switch (*p) { case 'c' : fn = fn_c; break; case 'i' : fn = fn_i; break; case 'd' : fn = fn_d; break; case 'a' : fn = fn_a; break; default: fprintf(stderr,"Uknown program name!\n"); exit(1); } if (*p != 'd') { if (argc < 2) { fprintf(stderr,"%c: need text argument\n", *p); exit(1); } argtorune(argv[1]); } read_info(0); /* don't reverse ranges */ do_changes(fn); list_changes(); exit(0); } wily-0.13.42/tools/old/edit/e.c000064402366570000012000000053141033320152300157320ustar00ozstaff00004330000002/* * e.c - set up editing file for wily. * some parts of this are swiped straight from gary's win.c. */ #include #include #include #include #include #include #include #include "libmsg.h" int towily, fromwily; /* file descriptors */ static char tmpfilename[FILENAME_MAX+1]; static ulong tmpp0, tmpp1; Msg m; Bool debug = false; Bool frommessage = true; static int gottext = 0; /* The lines that we asked for have arrived. */ void handleread(Msg *m) { char *s, *t; int len; FILE *fp; Rune r; tmpnam(tmpfilename); tmpp0 = m->p[0]; tmpp1 = m->p[1]; s = m->s[0]; t = s + strlen(s); if ((fp = fopen(tmpfilename,"w")) == 0) { perror(tmpfilename); exit(1); } while (s < t) { if (*(uchar *)s < (ulong)Runeself) r = *s++; else s += chartorune(&r, s); if (fwrite(&r, sizeof(r), 1, fp) != 1) { perror(tmpfilename); remove(tmpfilename); exit(1); } } fclose(fp); gottext = 1; return; } /* Handle all the messages coming from wily. */ void domsg(Msg *m) { switch(m->mtype) { case 'R': handleread(m); break; default: /* ignore whatever we don't specifically handle */ if(debug) { printf("message received and ignored: "); msg_print(m); } break; } } /* Open fifos to wily. */ void connect_wily(char *file, char *addr) { char envbuf[300]; msg_init(&m); towily = fromwily = get_connect(file); if(towily<0) { perror("connect failed\n"); exit(1); } DPRINT("in %d, out %d\n", fromwily, towily); wm_read(towily, true, 0, 0, addr); } static void rcv_text(void) { char buf[BUFSIZ]; int nread; while (gottext == 0) { nread = read(fromwily,buf,BUFSIZ); if (nread <= 0) { perror("e read"); exit(1); } if (empty_msg_buf(buf, nread, &m, domsg)) fprintf(stderr,"error from empty_msg_buf\n"); } } int main(int argc, char**argv) { char buf[BUFSIZ]; extern char *optarg; extern int optind; char *file, *addr; int c; while ((c = getopt(argc, argv, "d")) != EOF){ switch(c){ case 'd': debug = true; break; case '?': fprintf(stderr, "%s [-d] [prog...]\n", argv[0]); exit(1); } } if(debug) setbuf(stdout,0); file = argv[optind]; if (!file || !*file) { fprintf(stderr,"%s: no file!\n", argv[0]); exit(1); } if (addr = strchr(file, ':')) *addr++ = 0; else { /* XXX - really, we'd like to be able to ask wily what dot is, and read that explicitly, because doing a read of "." on file /path/name, if it's not already open, causes an eventual pane_openpath() which opens /path/. - daft, isn't it? */ addr = "."; } connect_wily(file, addr); rcv_text(); printf("%s\n%s\n%s\n0\n%d\n#0,#%d\n", file, addr, tmpfilename, tmpp0, tmpp1 - tmpp0); return 0; } wily-0.13.42/tools/old/edit/q.c000064402366570000012000000043311033320152300157440ustar00ozstaff00004330000002#include "range.h" int towily, fromwily; /* file descriptors */ Msg m; Bool debug = false; Bool frommessage = true; /* * load the relevant section of the file, convert it to UTF, and supply * the length of the resulting UTF string. */ static char * load_data(ulong p0, ulong p1, int *len) { ulong length = p1 - p0; size_t sz; static FILE *fp; Rune r; char *s; int n; /* XXX We make a guess about how much space the UTF version of the text will require... */ sz = length * (sizeof(Rune)+1); s = utffile = srealloc(utffile, sz); if (!fp && (fp = fopen(tmpfilename,"r")) == 0) { perror(tmpfilename); exit(1); } fseek(fp, p0 * sizeof(Rune), SEEK_SET); for (n = 0; n < length; n++) { fread(&r, sizeof(Rune), 1, fp); if ((uchar)r < Runeself) *s++ = r; else s += runetochar(s, &r); } *s = 0; *len = s - utffile; DPRINT("Read %d bytes\n",*len); return utffile; } static void send_data(void) { Subrange *r; char *buf; int len; if (!modified) { DPRINT("Not modified - not making changes\n"); return; } while (r = next_range()) { r->p0 += base; r->p1 += base; buf = load_data(r->q0, r->q1, &len); DPRINT("Removing old data\n"); wm_delete(towily, true, r->p0, r->p1); DPRINT("Inserting new data\n"); wm_insert(towily, true, r->p0, len, buf); } return; } /* Open fifos to wily. */ void connect_wily(char *file, char *addr) { char envbuf[300]; msg_init(&m); DPRINT("Connecting to wily\n"); towily = fromwily = get_connect(file); if(towily<0) { perror("connect failed\n"); exit(1); } DPRINT("in %d, out %d\n", fromwily, towily); DPRINT("Selecting given address\n"); wm_goto(towily, true, 0, 0, addr); } int main(int argc, char**argv) { char buf[BUFSIZ]; extern char *optarg; extern int optind; char *file, *addr; int c; while ((c = getopt(argc, argv, "d")) != EOF){ switch(c){ case 'd': debug = true; break; case '?': fprintf(stderr, "%s [-d] [prog...]\n", argv[0]); exit(1); } } if(debug) setbuf(stdout,0); read_info(1); /* reverse and coalese ranges */ if (!modified) { DPRINT("Not changed - just removing file\n"); remove(tmpfilename); return 0; } connect_wily(origfile, origaddr); send_data(); remove(tmpfilename); return 0; } wily-0.13.42/tools/old/edit/x.c000064402366570000012000000032301033320152300157500ustar00ozstaff00004330000002/* * x.c - this is actually the source for x, y, g and v. There's not a lot * of point having separate programs... */ #include "range.h" Bool debug = false; static const char *fmt = "#%lu,#%lu\n"; void fn_x(ulong p0, ulong p1) { ulong q0, q1; while (p0 < p1 && run_regexp(p0, p1, &q0, &q1)) { printf(fmt,q0,q1); p0 = q1; } } void fn_y(ulong p0, ulong p1) { ulong q0, q1; while (p0 < p1 && run_regexp(p0, p1, &q0, &q1)) { if (p0 < q0) printf(fmt,p0,q0); p0 = q1; } if (p0 < p1) printf(fmt,p0,p1); } void fn_g(ulong p0, ulong p1) { ulong q0, q1; if (p0 < p1 && run_regexp(p0, p1, &q0, &q1)) printf(fmt,p0,p1); } void fn_v(ulong p0, ulong p1) { ulong q0, q1; if (p0 < p1 && run_regexp(p0, p1, &q0, &q1)==0) printf(fmt,p0,p1); } int main(int argc, char *argv[]) { char *p, *re; size_t len; Subrange *r; void (*fn)(ulong p0, ulong p1); /* This isn't wonderful: assume that the regexp is delimited by // */ if (argc < 2 || *(re = argv[1]) != '/' || (len = strlen(re)) < 2) { fprintf(stderr,"Usage: x /regexp/\n"); exit(1); } if (re[--len] == '/') re[len] = 0; re++; /* skip / */ if (len == 0) { fprintf(stderr,"null regexp\n"); exit(1); } if (init_regexp(re)) { fprintf(stderr,"Invalid regexp\n"); exit(1); } p = strrchr(argv[0], '/'); p = p? p+1 : argv[0]; switch (*p) { case 'x' : fn = fn_x; break; case 'y' : fn = fn_y; break; case 'g' : fn = fn_g; break; case 'v' : fn = fn_v; break; default: fprintf(stderr,"Uknown program name!\n"); exit(1); } read_info(0); /* Don't reverse ranges */ Finit(&runefile, tmpfilename); write_info(); while (r = next_range()) (*fn)(r->p0, r->p1); exit(0); } = false; static const char *fmt = "#%lu,#%lu\n"; void fn_x(ulong p0, ulong p1) { ulong q0, q1; while (p0 < p1 && run_regexp(p0, p1, &q0, &q1)) { printf(fmt,q0,q1); p0 = q1; } } void fn_y(ulong p0, ulong p1) { ulong q0, q1; while (p0 < p1 && run_regexp(p0, p1, &q0, &q1)) { if (p0 < q0) printf(fmt,p0,q0); p0 = q1; } if (p0 < p1) printwily-0.13.42/tools/old/edit/range.c000064402366570000012000000050771033320152300166100ustar00ozstaff00004330000002#include #include #include "range.h" static Subrange *ranges, *range_ptr; static Subrange *shrink_ranges(int rev, Subrange *res); /* * This defines the number of Runes we're willing to have * in a single message to wily. */ #define MAXCHG 4000 /* * Functions for handling the ranges. Returns a subrange with * the min and max range of the whole set of ranges. Returns * 0 if no ranges were read. * Accepts either single ranges (from e, x) or pairs or ranges (from c). * Attempts to allow you to chain instances of c/i/a/d, but that's not * working properly yet. */ Subrange * read_ranges(int rev) { int nranges = 0; static Subrange res; Subrange *r, *l; ulong p0, p1, q0, q1; char buf[FILENAME_MAX+1]; while (fgets(buf, FILENAME_MAX, stdin)) { int npairs = sscanf(buf,"#%lu,#%lu #%lu,#%lu\n", &p0, &p1, &q0, &q1); switch (npairs) { default: return shrink_ranges(rev, nranges? &res : 0); case 4: if (nranges) { if (q0 < res.q0) res.q0 = q0; if (q1 > res.q1) res.q1 = q1; } else { res.q0 = q0; res.q1 = q1; } /* FALLTHROUGH */ case 2: if (nranges) { if (p0 < res.p0) res.p0 = p0; if (p1 > res.p1) res.p1 = p1; } else { res.p0 = p0; res.p1 = p1; } break; } r = salloc(sizeof(*r)); if (rev) { r->p0 = p0; r->p1 = p1; r->q0 = q0; r->q1 = q1; } else { if (npairs == 4) { r->p0 = q0; r->p1 = q1; } else { r->p0 = p0; r->p1 = p1; } } r->next = 0; if (nranges++) { l->next = r; l = r; } else l = ranges = r; } return shrink_ranges(rev, nranges? &res : 0); } Subrange * next_range(void) { Subrange *res = range_ptr; if (range_ptr) range_ptr = range_ptr->next; return res; } /* * If rev==0, then just return the min/max subrange that we've been given * (this is old, should just return a worked/failed flag). * If rev==1, then we're in "q", and will be sending the changes back to * wily. Reads the list of ranges, attempts to coalese them into single * updates, and reverses the order. */ static Subrange * shrink_ranges(int rev, Subrange *res) { Subrange *newranges = 0, *r0, *r1; range_ptr = ranges; if (rev == 0) return res; r0 = next_range(); while (r0) { while ((r1 = next_range()) && (r1->q1 - r0->q0) < MAXCHG) { /* can fit this change into the current message */ r0->p1 = r1->p1; r0->q1 = r1->q1; free(r1); } /* message is now too big to fit next range in. */ r0->next = newranges; newranges = r0; r0 = r1; } range_ptr = ranges = newranges; return res; } wily-0.13.42/tools/old/edit/range.h000064402366570000012000000013651033320152300166110ustar00ozstaff00004330000002#ifndef WILY_EDIT_H #define WILY_EDIT_H #include #include #include #include #include #include #include "sam.h" typedef struct Subrange Subrange; struct Subrange { ulong p0, p1, q0, q1; /* p is wily ref, q is new file ref */ struct Subrange *next; }; Subrange *read_ranges(int rev); Subrange *next_range(void); void do_changes(int (*changed)(Rune **r0, Rune **r1, Rune **r2, Rune **r3)); void write_info(void); void list_changes(void); extern char origfile[FILENAME_MAX+1], origaddr[FILENAME_MAX+1]; extern char tmpfilename[FILENAME_MAX+1]; extern Subrange *minmax; extern ulong base; extern char *utffile; extern int modified; extern File runefile; #endif /* ! WILY_EDIT_H */ wily-0.13.42/tools/old/edit/Makefile000064402366570000012000000011401033320152300167730ustar00ozstaff00004330000002TARGETS=e q x c LDFLAGS=-L../libmsg -L../libXg LDLIBS=-lmsg -lXg -lsocket -lnsl CPPFLAGS += -I../include -I../wily CFLAGS += -g ROBJS = range.o sam.o regexp.o COBJS = $(ROBJS) change.o all: $(TARGETS) q: q.o $(COBJS) $(CC) -o $@ $(CFLAGS) $(CPPFLAGS) q.o $(COBJS) $(LDFLAGS) $(LDLIBS) c: c.o $(COBJS) $(CC) -o $@ $(CFLAGS) $(CPPFLAGS) c.o $(COBJS) $(LDFLAGS) $(LDLIBS) $(RM) d i a ln c d ln c i ln c a x: x.o $(COBJS) $(CC) -o $@ $(CFLAGS) $(CPPFLAGS) x.o $(COBJS) $(LDFLAGS) $(LDLIBS) $(RM) y g v ln x y ln x g ln x v clean: rm -f *.o core *pure* nuke: clean rm -f $(TARGETS) g v y i a d wily-0.13.42/tools/old/edit/patch000064402366570000012000000063111033320152300163620ustar00ozstaff00004330000002*** text.c.orig Tue Sep 26 18:34:30 1995 --- text.c Tue Sep 26 17:40:49 1995 *************** *** 79,93 **** void doread(Text *t, char *addr) { ! ulong p0,p1; char *buf; int n; assert(t && t->xfd && t->datatype == Tpanetext); ! /* todo - stop cheating */ ! p0 = atoi(addr+1); ! p1 = t->length; n = p1 - p0 +1; assert(n>0); buf = salloc(2*n); --- 79,99 ---- void doread(Text *t, char *addr) { ! ulong p0,p1, t0, t1; char *buf; int n; assert(t && t->xfd && t->datatype == Tpanetext); ! if (!addr) ! return; ! t0 = t->p0; ! t1 = t->p1; ! /* addr is assumed to *not* have a preceding ":" here */ ! if (text_addr2sel(t, addr, &p0, &p1)) ! return; ! t->p0 = t0; ! t->p1 = t1; n = p1 - p0 +1; assert(n>0); buf = salloc(2*n); *************** *** 279,285 **** if (addr[0] == '.' && addr[1] == '\0') { *pp0 = t->p0; *pp1 = t->p1; ! return 0; /* todo - ask bill what should really be returned */ } n = atoi(addr); --- 285,291 ---- if (addr[0] == '.' && addr[1] == '\0') { *pp0 = t->p0; *pp1 = t->p1; ! return 1; /* smk - need to have this recognise '.' */ } n = atoi(addr); *************** *** 307,332 **** return 1; } ! /* PRE: 't' is the body of some pane, 'addr' is some string to search for. ! * 'addr' may be null. ! * POST: 't' is visible, the next occurrence of 'addr' is highlighted, ! * if it exists. */ ! void ! text_goaddr(Text *t, char *addr) { - ulong p0, p1; char *addr2; ! Pane *pane; - pane = (Pane*)t->data; - assert(pane_isgood(pane) && pane->text ==t); - - pane_raise(pane); - - if(!addr) - return; - /* * Find the second addr in the pair. Some complexity here: * (1) If the first addr is a regexp, must first find its end -- but watch --- 313,330 ---- return 1; } ! ! /* ! * given a Text and a string containing an address, return ! * the (p0,p1) that the address defines. */ ! ! int ! text_addr2sel(Text *t, char *addr, ulong *pp0, ulong *pp1) { char *addr2; ! ulong p0, p1; /* * Find the second addr in the pair. Some complexity here: * (1) If the first addr is a regexp, must first find its end -- but watch *************** *** 352,358 **** if (*addr == '\0') p0 = 0; else if (!findend(t, addr, &p0, &p1)) ! return; if (addr2) { ulong p2, pjunk; --- 350,356 ---- if (*addr == '\0') p0 = 0; else if (!findend(t, addr, &p0, &p1)) ! return 1; if (addr2) { ulong p2, pjunk; *************** *** 364,371 **** --- 362,397 ---- p1 = p2; } } + *pp0 = p0; + *pp1 = p1; + return 0; + } + + /* PRE: 't' is the body of some pane, 'addr' is some string to search for. + * 'addr' may be null. + * POST: 't' is visible, the next occurrence of 'addr' is highlighted, + * if it exists. + */ + void + text_goaddr(Text *t, char *addr) + { + ulong p0, p1; + char *addr2; + Pane *pane; + + pane = (Pane*)t->data; + assert(pane_isgood(pane) && pane->text ==t); + + pane_raise(pane); + + if(!addr) + return; + + if (text_addr2sel(t, addr, &p0, &p1)) + return; if (p1 < p0) return; + last_selection = t; textshow(t, p0+1, 1); texthighlight(t, p0, p1, F&~D); textwarp(t, (p0+p1)/2); t->p0 = t0; ! t->p1 = t1; n = p1 - p0 +1; assert(n>0); buf = salloc(2*n); *************** *** 279,285 **** if (addr[0] == '.' && addr[1] == '\0') { *pp0 = t->p0; *pp1 = t->p1; ! return 0; /* todo - ask bill what should really be returned */ } n = atoi(addr); --- 285,291 ---- wily-0.13.42/tools/old/edit/sam.c000064402366570000012000000105401033320152300162630ustar00ozstaff00004330000002/* * sam.c - some stubs and interface code to tie sam's regexp.c * to some standalone programs that hack a Rune-based file * extracted from a wily window. * S. Kilbane, 21/9/95. */ #include #define SAM_CODE #include "range.h" /* the File that we're going to operate on.. */ File runefile; /* * some global stuff that should be tidied up later... */ char origfile[FILENAME_MAX+1], origaddr[FILENAME_MAX+1]; char tmpfilename[FILENAME_MAX+1]; Subrange *minmax; ulong base; char *utffile; int modified; static jmp_buf regexp_state; static char *errs[] = { "Etoolong", "Eleftpar", "Erightpar", "Emissop", "Ebadregexp", "Ebadclass", "Eoverflow" }; /* * Initialise a File to the Text given. */ void Finit(File *f, char *filename) { /* load the file in. */ struct stat st; FILE *fp; ulong p0 = 0, p1; if (stat(filename,&st)) { perror(filename); exit(1); } p1 = st.st_size / RUNESIZE; if ((fp = fopen(filename,"r")) == 0) { perror(filename); exit(1); } f->nrunes = f->ngetc = p1; f->dot.r.p1 = 0; f->dot.r.p2 = p1; f->dot.f = f; f->getcbuf = salloc(p1*RUNESIZE); f->getci = f->getcp = 0; /* start at beginning of range */ fread(f->getcbuf, p1, RUNESIZE, fp); fclose(fp); return; } /* * stub routines */ int Fgetcload(File *f, Posn p) { return 0; } int Fbgetcload(File *f, Posn p) { return -1; } int Fbgetcset(File *f, Posn p) { f->getcp = f->getci = p; return f->ngetc = f->nrunes; } int Fgetcset(File *f, Posn p) { f->getcp = f->getci = p; return f->ngetc = f->nrunes; } long Fchars(File *f, Rune *r, Posn p0, Posn p1) { long n; if (p0 > f->nrunes) p0 = f->nrunes; if (p1 > f->nrunes) p1 = f->nrunes; if ((n = p1-p0) < 0) { fprintf(stderr, "regexp: Negative amount asked for by Fchars()"); return 0; } memcpy(r,f->getcbuf+p0, n*sizeof(Rune)); return n; } /* * compile the regexp * returns 0 for success. */ int init_regexp(char *re) { static String str; int l = strlen(re); if (str.n <= l) { str.n = ++l; l *= sizeof(Rune); str.s = srealloc(str.s,l); } if (setjmp(regexp_state)) return 0; /* error occurred */ str.s[utftotext(str.s, re, re+strlen(re))] = 0; compile(&str); return (startinst == 0); } /* * run_regexp(p0,p1) - the interface between wily and sam. * compile the regexp, and do a search from the current point. * If we find a match, set p0 and p1, and return true. Otherwise, * return false. */ int run_regexp(ulong q0, ulong q1, ulong *p0, ulong *p1) { if (setjmp(regexp_state)) return 0; /* error occurred */ if (execute(&runefile, q0, q1)) { *p0 = sel.p[0].p1; *p1 = sel.p[0].p2; return 1; } /* no match */ return 0; } void panic(char *str) { (void)fprintf(stderr,"panic:%s\n",str); exit(1); } void * emalloc(ulong len) { return salloc(len); } void * erealloc(void *ptr, ulong len) { return srealloc(ptr,len); } void samerror(Err e) { fprintf(stderr,"regexp error: %s\n",errs[e]); longjmp(regexp_state, 1); } void Strduplstr(String *s0, String *s1) { ulong n; n = s1->n * RUNESIZE; if (s0->n < s1->n) s0->s = erealloc(s0->s, n); s0->n = s1->n; memcpy(s0->s, s1->s, n); } int Strcmp(String *s0, String *s1) { Rune *i, *j; if (!s0->s || !s1->s) return 1; for (i = s0->s, j = s1->s; *i && (*i == *j); i++, j++) ; return *i != *j; } void error_c(Err e, int c) { fprintf(stderr,"regexp: %s, %c\n", errs[e], c); } void Strzero(String *s) { memset(s->s, 0, s->n*RUNESIZE); } /* * Read the information about the file from stdin. * returns 0 for success. */ void read_info(int rev) { static char ranges[FILENAME_MAX]; scanf("%s%s%s%d%lu\n",origfile,origaddr,tmpfilename, &modified,&base); DPRINT("of=%s,.=%s\n", origfile, origaddr); DPRINT("tf=%s,%s\n",tmpfilename, modified? "modified" : "unchanged"); /* this is a simple implementation - we just look at the ranges received, and take the widest area covered. */ if ((minmax = read_ranges(rev)) == 0) { fprintf(stderr,"failed to read ranges\n"); exit(1); } DPRINT("Chosen range: %lu-%lu\n",minmax->p0, minmax->p1); return; } /* * The following is copied from libtext/text.c, to prevent having * to link with the whole libtext library, and hence the libframe * library.c */ ulong utftotext(Rune *r, char *s1, char *s2) { Rune *q; char *t; if (s2 <= s1) return 0; for (t = s1, q = r; t < s2; q++) if (*(uchar *)t < Runeself) *q = *t++; else t += chartorune(q, t); return t-s1; } wily-0.13.42/tools/old/edit/sam.h000064402366570000012000000046631033320152300163010ustar00ozstaff00004330000002/* This source file is derived from the sam.h file in the sam distribution, which is: */ /* Copyright (c) 1992 AT&T - All rights reserved. */ /* * sam and wily both define an error() function. To avoid changing * anything in regexp.c, we use a macro to rename it. This relies * on other wily functions including wily.h before sam.h. */ #ifndef WILY_H #define error(X) samerror(X) #define SAM_CODE #endif #include #include #include #include "wily.h" #define NSUBEXP 10 /* number of () matches in a regexp */ typedef long Posn; /* file position or address */ typedef struct Address Address; typedef struct File File; typedef struct Range Range; typedef struct Rangeset Rangeset; typedef struct String String; typedef struct Inst Inst; typedef enum { Etoolong, Eleftpar, Erightpar, Emissop, Ebadregexp, Ebadclass, Eoverflow } Err; struct String { int n; Rune *s; }; struct Range { Posn p1, p2; }; struct Rangeset { Range p[NSUBEXP]; }; struct Address { Range r; File *f; }; #define FALSE 0 #define TRUE 1 #define RUNESIZE (sizeof(Rune)) #define NGETC 128 /* Shouldn't actually be used */ #define INFINITY 0x7FFFFFFFL /* * In the original sam.h, the File structure is that which manages * all the caches and buffers of the file being edited. We're not * concerned with any of that - we just want to make the contents * of a Text look like a File to sam. */ struct File { Text *t; /* the Text that we'll search */ Posn nrunes; /* total length of file */ Address dot; /* current position */ Rune *getcbuf; /* pointer to t->text */ int ngetc; /* must be ==nrunes */ int getci; /* index into getcbuf */ Posn getcp; /* must ==getci */ }; #define Fgetc(f) ((--(f)->ngetc<0)? Fgetcload(f, (f)->getcp) : (f)->getcbuf[(f)->getcp++, (f)->getci++]) #define Fbgetc(f) (((f)->getci<=0)? Fbgetcload(f, (f)->getcp) : (f)->getcbuf[--(f)->getcp, --(f)->getci]) int Fbgetcload(File*, Posn); int Fbgetcset(File*, Posn); long Fchars(File*, Rune*, Posn, Posn); int Fgetcload(File*, Posn); int Fgetcset(File*, Posn); int bexecute(File*, Posn); void compile(String*); int execute(File*, Posn, Posn); void nextmatch(File*, String*, Posn, int); void *emalloc(ulong); void *erealloc(void*, ulong); void error_c(Err, int); void panic(char*); void Strduplstr(String *, String *); int Strcmp(String *, String *); void Strzero(String *); void error(Err); /* really samerror() */ extern Rangeset sel; extern Inst *startinst; wily-0.13.42/tools/old/edit/README000064402366570000012000000026771033320152300162330ustar00ozstaff00004330000002This is far from complete, but I've had so little time to work on it this week, and wily's had so many releases, that I thought I may as well give others a chance to play with it. Besides, I was getting fed up with applying that patch to text.c. This includes regexp.c, but again, it's unchanged from the original. The sam.[ch] here are different from those in wily itself. This works on my machine with the pipeline: e file | x /regexp/ | c word | q but I haven't played with many combinations yet. As long as the text.c patch goes in, then it will be easier to test it, rather than trying to keep up with wily revisions. Couple of major points: - e asks wily for "." by default, if no address is given. During the resolution of this, wily attempts to open "/path/." where e has asked for "." in /path/name. This is kind of weird, and is part of the context rules. I'm not sure what to do about it. - "q" isn't really necessary, if we take acme's stance, and say that you can only have one of c,i,a,d in the pipeline. Seems a little mean to me, since they don't supply s. I've tried to arrange things so that you can pipe c,i,d,a into each other, but that's not working yet. Or we could just give up (combinations of i and a are ok, c and d don't make a lot of sense in combination), add s, and dump q. Which will probably for the best anyway. - I haven't done anything about arranging things so that Wily allows Undoing, yet. Haven't even looked into it. Steve wily-0.13.42/tools/old/edit/change.c000064402366570000012000000052211033320152300167300ustar00ozstaff00004330000002/* * routines for making changes to the temporary file. Actually, * the changes are made to a new temporary file. */ #include "range.h" static Subrange *changes; /* list of changes that we've made */ static Subrange *last; static FILE *tmpfp; static char newtmpfile[FILENAME_MAX+1]; static ulong copyfile(ulong p0, ulong p1, FILE *fp); static ulong save_change(ulong p0, Rune *r0, Rune *r1, Rune *r2, Rune *r3, FILE *fp); static void add_change(ulong p0, ulong p1, ulong q0, ulong q1) { Subrange *r; r = salloc(sizeof(*r)); r->p0 = p0; r->p1 = p1; r->q0 = q0; r->q1 = q1; r->next = 0; if (changes) { last->next = r; last = r; } else changes = last = r; return; } void do_changes(int (*changed)(Rune **r0, Rune **r1, Rune **r2, Rune **r3)) { ulong origpos = 0, pos = 0, len, newpos; Subrange *r; if (tmpfp == 0) { tmpnam(newtmpfile); if ((tmpfp = fopen(newtmpfile,"w")) == 0) { perror(newtmpfile); exit(1); } Finit(&runefile, tmpfilename); } /* for each range, copy the unchanged part of the file between the last range and this one, then pass the range to the fn, and if it's changed the text. write the two returned strings to the file */ while (r = next_range()) { Rune *r0, *r1, *r2, *r3; if (origpos < r->p0) { pos += copyfile(origpos, r->p0, tmpfp); origpos = r->p1; } r0 = runefile.getcbuf + r->p0; r1 = runefile.getcbuf + r->p1; if ((*changed)(&r0, &r1, &r2, &r3)) { modified = 1; newpos = save_change(pos,r0, r1, r2, r3, tmpfp); add_change(r->p0, r->p1, pos, newpos); pos = newpos; } } /* copy anything left after the last range */ if (origpos < runefile.nrunes) copyfile(origpos, runefile.nrunes, tmpfp); fclose(tmpfp); if (modified) { remove(tmpfilename); strcpy(tmpfilename, newtmpfile); } return; } /* * copy a section of file, unchanged. */ static ulong copyfile(ulong p0, ulong p1, FILE *fp) { fwrite(runefile.getcbuf + p0, p1-p0, RUNESIZE, fp); return (p1 - p0); } /* * a section of the file has been changed. write the changed * section to the file. */ static ulong save_change(ulong p0, Rune *r0, Rune *r1, Rune *r2, Rune *r3, FILE *fp) { ulong len; if (r0) { len = r1 - r0; if (len) fwrite(r0, len , RUNESIZE, fp); p0 += len; } if (r2) { len = r3 - r2; if (len) fwrite(r2, len , RUNESIZE, fp); p0 += len; } return p0; } void write_info(void) { printf("%s\n%s\n%s\n%d\n%d\n", origfile, origaddr, tmpfilename, modified, base); } /* * produce file info and a list of the changes */ void list_changes(void) { Subrange *r = changes; write_info(); for (; r; r = r->next) printf("#%lu,#%lu #%lu,#%lu\n", r->p0, r->p1, r->q0, r->q1); return; } wily-0.13.42/tools/old/edit/change.h000064402366570000012000000000001033320152300167230ustar00ozstaff00004330000002wily-0.13.42/tools/old/edit/regexp.c000064402366570000012000000366511033320152300170100ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include "sam.h" Rangeset sel; String lastregexp; /* * Machine Information */ struct Inst { long type; /* < 0x10000 ==> literal, otherwise action */ union { int rsid; int rsubid; int class; struct Inst *rother; struct Inst *rright; } r; union{ struct Inst *lleft; struct Inst *lnext; } l; }; #define sid r.rsid #define subid r.rsubid #define rclass r.class #define other r.rother #define right r.rright #define left l.lleft #define next l.lnext #define NPROG 1024 Inst program[NPROG]; Inst *progp; Inst *startinst; /* First inst. of program; might not be program[0] */ Inst *bstartinst; /* same for backwards machine */ typedef struct Ilist Ilist; struct Ilist { Inst *inst; /* Instruction of the thread */ Rangeset se; Posn startp; /* first char of match */ }; #define NLIST 128 Ilist *tl, *nl; /* This list, next list */ Ilist list[2][NLIST]; static Rangeset sempty; /* * Actions and Tokens * * 0x100xx are operators, value == precedence * 0x200xx are tokens, i.e. operands for operators */ #define OPERATOR 0x10000 /* Bitmask of all operators */ #define START 0x10000 /* Start, used for marker on stack */ #define RBRA 0x10001 /* Right bracket, ) */ #define LBRA 0x10002 /* Left bracket, ( */ #define OR 0x10003 /* Alternation, | */ #define CAT 0x10004 /* Concatentation, implicit operator */ #define STAR 0x10005 /* Closure, * */ #define PLUS 0x10006 /* a+ == aa* */ #define QUEST 0x10007 /* a? == a|nothing, i.e. 0 or 1 a's */ #define ANY 0x20000 /* Any character but newline, . */ #define NOP 0x20001 /* No operation, internal use only */ #define BOL 0x20002 /* Beginning of line, ^ */ #define EOL 0x20003 /* End of line, $ */ #define CCLASS 0x20004 /* Character class, [] */ #define NCCLASS 0x20005 /* Negated character class, [^] */ #define END 0x20077 /* Terminate: match found */ #define ISATOR 0x10000 #define ISAND 0x20000 /* * Parser Information */ typedef struct Node Node; struct Node { Inst *first; Inst *last; }; #define NSTACK 20 Node andstack[NSTACK]; Node *andp; int atorstack[NSTACK]; int *atorp; int lastwasand; /* Last token was operand */ int cursubid; int subidstack[NSTACK]; int *subidp; int backwards; int nbra; Rune *exprp; /* pointer to next character in source expression */ #define DCLASS 10 /* allocation increment */ int nclass; /* number active */ int Nclass; /* high water mark */ Rune **class; int negateclass; void addinst(Ilist *l, Inst *inst, Rangeset *sep); void newmatch(Rangeset*); void bnewmatch(Rangeset*); void pushand(Inst*, Inst*); void pushator(int); Node *popand(int); int popator(void); void startlex(Rune*); int lex(void); void operator(int); void operand(int); void evaluntil(int); void optimize(Inst*); void bldcclass(void); void regerror(Err e) { Strzero(&lastregexp); error(e); } void regerror_c(Err e, int c) { Strzero(&lastregexp); error_c(e, c); } Inst * newinst(int t) { if(progp >= &program[NPROG]) regerror(Etoolong); progp->type = t; progp->left = 0; progp->right = 0; return progp++; } Inst * realcompile(Rune *s) { int token; startlex(s); atorp = atorstack; andp = andstack; subidp = subidstack; cursubid = 0; lastwasand = FALSE; /* Start with a low priority operator to prime parser */ pushator(START-1); while((token=lex()) != END){ if((token&ISATOR) == OPERATOR) operator(token); else operand(token); } /* Close with a low priority operator */ evaluntil(START); /* Force END */ operand(END); evaluntil(START); if(nbra) regerror(Eleftpar); --andp; /* points to first and only operand */ return andp->first; } void compile(String *s) { int i; Inst *oprogp; if(Strcmp(s, &lastregexp)==0) return; for(i=0; is); optimize(program); oprogp = progp; backwards = TRUE; bstartinst = realcompile(s->s); optimize(oprogp); Strduplstr(&lastregexp, s); } void operand(int t) { Inst *i; if(lastwasand) operator(CAT); /* catenate is implicit */ i = newinst(t); if(t == CCLASS){ if(negateclass) i->type = NCCLASS; /* UGH */ i->rclass = nclass-1; /* UGH */ } pushand(i, i); lastwasand = TRUE; } void operator(int t) { if(t==RBRA && --nbra<0) regerror(Erightpar); if(t==LBRA){ /* * if(++cursubid >= NSUBEXP) * regerror(Esubexp); */ cursubid++; /* silently ignored */ nbra++; if(lastwasand) operator(CAT); }else evaluntil(t); if(t!=RBRA) pushator(t); lastwasand = FALSE; if(t==STAR || t==QUEST || t==PLUS || t==RBRA) lastwasand = TRUE; /* these look like operands */ } void cant(char *s) { char buf[100]; sprint(buf, "regexp: can't happen: %s", s); panic(buf); } void pushand(Inst *f, Inst *l) { if(andp >= &andstack[NSTACK]) cant("operand stack overflow"); andp->first = f; andp->last = l; andp++; } void pushator(int t) { if(atorp >= &atorstack[NSTACK]) cant("operator stack overflow"); *atorp++=t; if(cursubid >= NSUBEXP) *subidp++= -1; else *subidp++=cursubid; } Node * popand(int op) { if(andp <= &andstack[0]) if(op) regerror_c(Emissop, op); else regerror(Ebadregexp); return --andp; } int popator(void) { if(atorp <= &atorstack[0]) cant("operator stack underflow"); --subidp; return *--atorp; } void evaluntil(int pri) { Node *op1, *op2, *t; Inst *inst1, *inst2; while(pri==RBRA || atorp[-1]>=pri){ switch(popator()){ case LBRA: op1 = popand('('); inst2 = newinst(RBRA); inst2->subid = *subidp; op1->last->next = inst2; inst1 = newinst(LBRA); inst1->subid = *subidp; inst1->next = op1->first; pushand(inst1, inst2); return; /* must have been RBRA */ default: panic("unknown regexp operator"); break; case OR: op2 = popand('|'); op1 = popand('|'); inst2 = newinst(NOP); op2->last->next = inst2; op1->last->next = inst2; inst1 = newinst(OR); inst1->right = op1->first; inst1->left = op2->first; pushand(inst1, inst2); break; case CAT: op2 = popand(0); op1 = popand(0); if(backwards && op2->first->type!=END) t = op1, op1 = op2, op2 = t; op1->last->next = op2->first; pushand(op1->first, op2->last); break; case STAR: op2 = popand('*'); inst1 = newinst(OR); op2->last->next = inst1; inst1->right = op2->first; pushand(inst1, inst1); break; case PLUS: op2 = popand('+'); inst1 = newinst(OR); op2->last->next = inst1; inst1->right = op2->first; pushand(op2->first, inst1); break; case QUEST: op2 = popand('?'); inst1 = newinst(OR); inst2 = newinst(NOP); inst1->left = inst2; inst1->right = op2->first; op2->last->next = inst2; pushand(inst1, inst2); break; } } } void optimize(Inst *start) { Inst *inst, *target; for(inst=start; inst->type!=END; inst++){ target = inst->next; while(target->type == NOP) target = target->next; inst->next = target; } } #ifdef DEBUG void dumpstack(void){ Node *stk; int *ip; dprint("operators\n"); for(ip = atorstack; ipfirst->type, stk->last->type); } void dump(void){ Inst *l; l = program; do{ dprint("%d:\t0%o\t%d\t%d\n", l-program, l->type, l->left-program, l->right-program); }while(l++->type); } #endif void startlex(Rune *s) { exprp = s; nbra = 0; } int lex(void){ int c= *exprp++; switch(c){ case '\\': if(*exprp) if((c= *exprp++)=='n') c='\n'; break; case 0: c = END; --exprp; /* In case we come here again */ break; case '*': c = STAR; break; case '?': c = QUEST; break; case '+': c = PLUS; break; case '|': c = OR; break; case '.': c = ANY; break; case '(': c = LBRA; break; case ')': c = RBRA; break; case '^': c = BOL; break; case '$': c = EOL; break; case '[': c = CCLASS; bldcclass(); break; } return c; } long nextrec(void){ if(exprp[0]==0 || (exprp[0]=='\\' && exprp[1]==0)) regerror(Ebadclass); if(exprp[0] == '\\'){ exprp++; if(*exprp=='n'){ exprp++; return '\n'; } return *exprp++|0x10000; } return *exprp++; } void bldcclass(void) { long c1, c2, n, na; Rune *classp; classp = emalloc(DCLASS*RUNESIZE); n = 0; na = DCLASS; /* we have already seen the '[' */ if(*exprp == '^'){ classp[n++] = '\n'; /* don't match newline in negate case */ negateclass = TRUE; exprp++; }else negateclass = FALSE; while((c1 = nextrec()) != ']'){ if(c1 == '-'){ Error: free(classp); regerror(Ebadclass); } if(n+4 >= na){ /* 3 runes plus NUL */ na += DCLASS; classp = erealloc(classp, na*RUNESIZE); } if(*exprp == '-'){ exprp++; /* eat '-' */ if((c2 = nextrec()) == ']') goto Error; classp[n+0] = 0xFFFF; classp[n+1] = c1; classp[n+2] = c2; n += 3; }else classp[n++] = c1; } classp[n] = 0; if(nclass == Nclass){ Nclass += DCLASS; class = erealloc(class, Nclass*sizeof(Rune*)); } class[nclass++] = classp; } int classmatch(int classno, int c, int negate) { Rune *p; p = class[classno]; while(*p){ if(*p == 0xFFFF){ if(p[1]<=c && c<=p[2]) return !negate; p += 3; }else if(*p++ == c) return !negate; } return negate; } /* * Note optimization in addinst: * *l must be pending when addinst called; if *l has been looked * at already, the optimization is a bug. */ void addinst(Ilist *l, Inst *inst, Rangeset *sep) { Ilist *p; for(p = l; p->inst; p++){ if(p->inst==inst){ if((sep)->p[0].p1 < p->se.p[0].p1) p->se= *sep; /* this would be bug */ return; /* It's already there */ } } p->inst = inst; p->se= *sep; (p+1)->inst = 0; } int execute(File *f, Posn startp, Posn eof) { int flag = 0; Inst *inst; Ilist *tlp; Posn p = startp; int nnl = 0, ntl; int c; int wrapped = 0; int startchar = startinst->typetype : 0; list[0][0].inst = list[1][0].inst = 0; sel.p[0].p1 = -1; Fgetcset(f, startp); /* Execute machine once for each character */ for(;;p++){ doloop: c = Fgetc(f); if(p>=eof || c<0){ switch(wrapped++){ case 0: /* let loop run one more click */ case 2: break; case 1: /* expired; wrap to beginning */ if(sel.p[0].p1>=0 || eof!=INFINITY) goto Return; list[0][0].inst = list[1][0].inst = 0; Fgetcset(f, (Posn)0); p = 0; goto doloop; default: goto Return; } }else if(((wrapped && p>=startp) || sel.p[0].p1>0) && nnl==0) break; /* fast check for first char */ if(startchar && nnl==0 && c!=startchar) continue; tl = list[flag]; nl = list[flag^=1]; nl->inst = 0; ntl = nnl; nnl = 0; if(sel.p[0].p1<0 && (!wrapped || p= NLIST) Overflow: error(Eoverflow); sempty.p[0].p1 = p; addinst(tl, startinst, &sempty); } /* Execute machine until this list is empty */ for(tlp = tl; (inst = tlp->inst) ; tlp++){ /* assignment = */ Switchstmt: switch(inst->type){ default: /* regular character */ if(inst->type==c){ Addinst: if(++nnl >= NLIST) goto Overflow; addinst(nl, inst->next, &tlp->se); } break; case LBRA: if(inst->subid>=0) tlp->se.p[inst->subid].p1 = p; inst = inst->next; goto Switchstmt; case RBRA: if(inst->subid>=0) tlp->se.p[inst->subid].p2 = p; inst = inst->next; goto Switchstmt; case ANY: if(c!='\n') goto Addinst; break; case BOL: if(p == 0){ Step: inst = inst->next; goto Switchstmt; } if(f->getci > 1){ if(f->getcbuf[f->getci-2]=='\n') goto Step; }else{ Rune c; if(Fchars(f, &c, p-1, p)==1 && c=='\n') goto Step; } break; case EOL: if(c == '\n') goto Step; break; case CCLASS: if(c>=0 && classmatch(inst->rclass, c, 0)) goto Addinst; break; case NCCLASS: if(c>=0 && classmatch(inst->rclass, c, 1)) goto Addinst; break; case OR: /* evaluate right choice later */ if(++ntl >= NLIST) goto Overflow; addinst(tlp, inst->right, &tlp->se); /* efficiency: advance and re-evaluate */ inst = inst->left; goto Switchstmt; case END: /* Match! */ tlp->se.p[0].p2 = p; newmatch(&tlp->se); break; } } } Return: return sel.p[0].p1>=0; } void newmatch(Rangeset *sp) { int i; if(sel.p[0].p1<0 || sp->p[0].p1p[0].p1==sel.p[0].p1 && sp->p[0].p2>sel.p[0].p2)) for(i = 0; ip[i]; } int bexecute(File *f, Posn startp) { int flag = 0; Inst *inst; Ilist *tlp; Posn p = startp; int nnl = 0, ntl; int c; int wrapped = 0; int startchar = bstartinst->typetype : 0; list[0][0].inst = list[1][0].inst = 0; sel.p[0].p1= -1; Fgetcset(f, startp); /* Execute machine once for each character, including terminal NUL */ for(;;--p){ doloop: if((c = Fbgetc(f))==-1){ switch(wrapped++){ case 0: /* let loop run one more click */ case 2: break; case 1: /* expired; wrap to end */ if(sel.p[0].p1>=0) case 3: goto Return; list[0][0].inst = list[1][0].inst = 0; Fgetcset(f, f->nrunes); p = f->nrunes; goto doloop; default: goto Return; } }else if(((wrapped && p<=startp) || sel.p[0].p1>0) && nnl==0) break; /* fast check for first char */ if(startchar && nnl==0 && c!=startchar) continue; tl = list[flag]; nl = list[flag^=1]; nl->inst = 0; ntl = nnl; nnl = 0; if(sel.p[0].p1<0 && (!wrapped || p>startp)){ /* Add first instruction to this list */ if(++ntl >= NLIST) Overflow: error(Eoverflow); /* the minus is so the optimizations in addinst work */ sempty.p[0].p1 = -p; addinst(tl, bstartinst, &sempty); } /* Execute machine until this list is empty */ for(tlp = tl; (inst = tlp->inst); tlp++){ /* assignment = */ Switchstmt: switch(inst->type){ default: /* regular character */ if(inst->type == c){ Addinst: if(++nnl >= NLIST) goto Overflow; addinst(nl, inst->next, &tlp->se); } break; case LBRA: if(inst->subid>=0) tlp->se.p[inst->subid].p1 = p; inst = inst->next; goto Switchstmt; case RBRA: if(inst->subid >= 0) tlp->se.p[inst->subid].p2 = p; inst = inst->next; goto Switchstmt; case ANY: if(c != '\n') goto Addinst; break; case BOL: if(c=='\n' || p==0){ Step: inst = inst->next; goto Switchstmt; } break; case EOL: if(f->getcingetc-1){ if(f->getcbuf[f->getci+1]=='\n') goto Step; }else if(pnrunes-1){ Rune c; if(Fchars(f, &c, p, p+1)==1 && c=='\n') goto Step; } break; case CCLASS: if(c>=0 && classmatch(inst->rclass, c, 0)) goto Addinst; break; case NCCLASS: if(c>=0 && classmatch(inst->rclass, c, 1)) goto Addinst; break; case OR: /* evaluate right choice later */ if(++ntl >= NLIST) goto Overflow; addinst(tlp, inst->right, &tlp->se); /* efficiency: advance and re-evaluate */ inst = inst->left; goto Switchstmt; case END: /* Match! */ tlp->se.p[0].p1 = -tlp->se.p[0].p1; /* minus sign */ tlp->se.p[0].p2 = p; bnewmatch(&tlp->se); break; } } } Return: return sel.p[0].p1>=0; } void bnewmatch(Rangeset *sp) { int i; if(sel.p[0].p1<0 || sp->p[0].p1>sel.p[0].p2 || (sp->p[0].p1==sel.p[0].p2 && sp->p[0].p2p[i].p2; sel.p[i].p2 = sp->p[i].p1; } } p; op1->last->next = inst2; inst1 = newinst(LBRA); inst1->subid = *subidp; wily-0.13.42/tools/old/wilytoys/000075502366570000012000000000001033320152300163155ustar00ozstaff00004330000002wily-0.13.42/tools/old/wilytoys/man000064402366570000012000000002101033320152300170040ustar00ozstaff00004330000002#!/bin/rc { if (~ $1 *.[0-9]*) { nroff -man $* } else { PAGER='cat' exec /usr/bin/man $* } } | bold | perl -pe 's/\010.//g;' | wcat wily-0.13.42/tools/old/wilytoys/diff000064402366570000012000000003071033320152300171500ustar00ozstaff00004330000002#!/bin/rc # script to make line numbers from diff look like addresses # to Wily. f1 = $1 f2 = $2 exec /usr/bin/diff $* | perl -pe '$| = 1; s!^(([0-9]+)(.)([0-9]+).*)!\1 '^$f1^':\2 \3 '^$f2^':\4!;' wily-0.13.42/tools/old/wilytoys/http000064402366570000012000000007401033320152300172200ustar00ozstaff00004330000002#!/bin/rc # http - get an HTTP URL, retrieve the file, convert it into something that looks # vaguely nice, and send it to a Wily window. # Usage: http http://site/path/name.html url = $1 tmpfile = /tmp/http$pid switch ($url) { case http:* eval `{echo $url | sed -e 's!http://\([^/]*\)\(.*\)!host=(\1);file=(\2)!'} case * echo Only http URLs supported >[1=2] exit 1 } if (~ $file ()) file = /; fetchurl $host $file > $tmpfile html2wily $tmpfile $url | wcat rm $tmpfile wily-0.13.42/tools/old/wilytoys/make000064402366570000012000000002601033320152300171530ustar00ozstaff00004330000002#!/bin/rc # script to make errors from the C compiler look like addresses # to Wily. exec /usr/ccs/bin/make $* >[2=1] | perl -pe '$| = 1; s/"([^"]*)", line ([0-9]+)/\1:\2/;' wily-0.13.42/tools/old/wilytoys/tformat.pl000064402366570000012000000061421033320152300203310ustar00ozstaff00004330000002# Simple text formatter # Jim Davis 17 July 94 # current page, line, and column numbers. $page = 1; $line = 1; $column = 1; $left_margin = 1; $right_margin = 72; # lines on page before footer. or 0 if no limit. $bottom_margin = 58; # add newlines to make page be full length? $fill_page_length = 1; sub print_word_wrap { local ($word) = @_; if (($column + ($whitespace_significant ? 0 : 1) + length ($word) ) > ($right_margin + 1)) { &fresh_line();} if ($column > $left_margin && !$whitespace_significant) { print " "; $column++;} print $word; $column += length ($word);} sub print_whitespace { local ($char) = @_; if ($char eq " ") { $column++; print " ";} elsif ($char eq "\t") { &get_to_column (&tab_column($column));} elsif ($char eq "\n") { &new_line();} else { die "Unknown whitespace character \"$char\"\nStopped";} } sub tab_column { local ($c) = @_; (int (($c-1) / 8) + 1) * 8 + 1;} sub fresh_line { if ($column > $left_margin) {&new_line();} while ($column < $left_margin) { print " "; $column++;}} sub finish_page { # Add extra newlines to finish page. # You might not want to do this on the last page. if ($fill_page_length) { while ($line < $bottom_margin) {&cr();}} &do_footer (); $line = 1; $column = 1;} sub start_page { if ($page != 1) { &do_header ();}} sub print_n_chars { local ($n, $char) = @_; local ($i); for ($i = 1; $i <= $n; $i++) {print $char;} $column += $n;} # need one NL to end current line, and then N to get N blank lines. sub skip_n_lines { local ($n, $room_left) = @_; if ($bottom_margin > 0 && $line + $room_left >= $bottom_margin) { &finish_page(); &start_page();} else { local ($i); for ($i = 0; $i <= $n; $i++) {&new_line();}}} sub new_line { if ($bottom_margin > 0 && $line >= $bottom_margin) { &finish_page(); &start_page();} else {&cr();} &print_n_chars ($left_margin - 1, " ");} # used in footer and header where we don't respect the bottom margin. sub print_blank_lines { local ($n) = @_; local ($i); for ($i = 0; $i < $n; $i++) {&cr();}} sub cr { print "\n"; $line++; $column = 1;} # left, center, and right tabbed items sub print_lcr_line { local ($left, $center, $right) = @_; &print_tab_left (1, $left); &print_tab_center (($right_margin - $left_margin) / 2, $center); &print_tab_right ($right_margin, $right); &cr();} sub print_tab_left { local ($tab_column, $string) = @_; &get_to_column ($tab_column); print $string; $column += length ($string); } sub print_tab_center { local ($tab_column, $string) = @_; &get_to_column ($tab_column - (length($string) / 2)); print $string; $column += length ($string); } sub print_tab_right { local ($tab_column, $string) = @_; &get_to_column ($tab_column - length($string)); print $string; $column += length ($string); } sub get_to_column { local ($goal_column) = @_; if ($column > $goal_column) {print " "; $column++;} else { while ($column < $goal_column) { print " "; $column++;}}} wily-0.13.42/tools/old/wilytoys/toys/000075502366570000012000000000001033320152300173135ustar00ozstaff00004330000002wily-0.13.42/tools/old/wilytoys/toys/man000064402366570000012000000002101033320152300200020ustar00ozstaff00004330000002#!/bin/rc { if (~ $1 *.[0-9]*) { nroff -man $* } else { PAGER='cat' exec /usr/bin/man $* } } | bold | perl -pe 's/\010.//g;' | wcat wily-0.13.42/tools/old/wilytoys/toys/diff000064402366570000012000000003071033320152300201460ustar00ozstaff00004330000002#!/bin/rc # script to make line numbers from diff look like addresses # to Wily. f1 = $1 f2 = $2 exec /usr/bin/diff $* | perl -pe '$| = 1; s!^(([0-9]+)(.)([0-9]+).*)!\1 '^$f1^':\2 \3 '^$f2^':\4!;' wily-0.13.42/tools/old/wilytoys/toys/http000064402366570000012000000007401033320152300202160ustar00ozstaff00004330000002#!/bin/rc # http - get an HTTP URL, retrieve the file, convert it into something that looks # vaguely nice, and send it to a Wily window. # Usage: http http://site/path/name.html url = $1 tmpfile = /tmp/http$pid switch ($url) { case http:* eval `{echo $url | sed -e 's!http://\([^/]*\)\(.*\)!host=(\1);file=(\2)!'} case * echo Only http URLs supported >[1=2] exit 1 } if (~ $file ()) file = /; fetchurl $host $file > $tmpfile html2wily $tmpfile $url | wcat rm $tmpfile wily-0.13.42/tools/old/wilytoys/toys/make000064402366570000012000000002601033320152300201510ustar00ozstaff00004330000002#!/bin/rc # script to make errors from the C compiler look like addresses # to Wily. exec /usr/ccs/bin/make $* >[2=1] | perl -pe '$| = 1; s/"([^"]*)", line ([0-9]+)/\1:\2/;' wily-0.13.42/tools/old/wilytoys/toys/tformat.pl000064402366570000012000000061421033320152300213270ustar00ozstaff00004330000002# Simple text formatter # Jim Davis 17 July 94 # current page, line, and column numbers. $page = 1; $line = 1; $column = 1; $left_margin = 1; $right_margin = 72; # lines on page before footer. or 0 if no limit. $bottom_margin = 58; # add newlines to make page be full length? $fill_page_length = 1; sub print_word_wrap { local ($word) = @_; if (($column + ($whitespace_significant ? 0 : 1) + length ($word) ) > ($right_margin + 1)) { &fresh_line();} if ($column > $left_margin && !$whitespace_significant) { print " "; $column++;} print $word; $column += length ($word);} sub print_whitespace { local ($char) = @_; if ($char eq " ") { $column++; print " ";} elsif ($char eq "\t") { &get_to_column (&tab_column($column));} elsif ($char eq "\n") { &new_line();} else { die "Unknown whitespace character \"$char\"\nStopped";} } sub tab_column { local ($c) = @_; (int (($c-1) / 8) + 1) * 8 + 1;} sub fresh_line { if ($column > $left_margin) {&new_line();} while ($column < $left_margin) { print " "; $column++;}} sub finish_page { # Add extra newlines to finish page. # You might not want to do this on the last page. if ($fill_page_length) { while ($line < $bottom_margin) {&cr();}} &do_footer (); $line = 1; $column = 1;} sub start_page { if ($page != 1) { &do_header ();}} sub print_n_chars { local ($n, $char) = @_; local ($i); for ($i = 1; $i <= $n; $i++) {print $char;} $column += $n;} # need one NL to end current line, and then N to get N blank lines. sub skip_n_lines { local ($n, $room_left) = @_; if ($bottom_margin > 0 && $line + $room_left >= $bottom_margin) { &finish_page(); &start_page();} else { local ($i); for ($i = 0; $i <= $n; $i++) {&new_line();}}} sub new_line { if ($bottom_margin > 0 && $line >= $bottom_margin) { &finish_page(); &start_page();} else {&cr();} &print_n_chars ($left_margin - 1, " ");} # used in footer and header where we don't respect the bottom margin. sub print_blank_lines { local ($n) = @_; local ($i); for ($i = 0; $i < $n; $i++) {&cr();}} sub cr { print "\n"; $line++; $column = 1;} # left, center, and right tabbed items sub print_lcr_line { local ($left, $center, $right) = @_; &print_tab_left (1, $left); &print_tab_center (($right_margin - $left_margin) / 2, $center); &print_tab_right ($right_margin, $right); &cr();} sub print_tab_left { local ($tab_column, $string) = @_; &get_to_column ($tab_column); print $string; $column += length ($string); } sub print_tab_center { local ($tab_column, $string) = @_; &get_to_column ($tab_column - (length($string) / 2)); print $string; $column += length ($string); } sub print_tab_right { local ($tab_column, $string) = @_; &get_to_column ($tab_column - length($string)); print $string; $column += length ($string); } sub get_to_column { local ($goal_column) = @_; if ($column > $goal_column) {print " "; $column++;} else { while ($column < $goal_column) { print " "; $column++;}}} wily-0.13.42/tools/old/wilytoys/toys/html2wily000064402366570000012000000030661033320152300211760ustar00ozstaff00004330000002#!/usr/local/bin/perl -I/home/steve/bin/Wily # Program to generate ASCII text for HTML # Created by James R. Davis, July 15 1994 # Split a URL into its component parts sub split_url { local($method, $host, $port, $path); $_ = $_[0]; /^((http|ftp|news|mailto|gopher|telnet):)?(\/\/([^\/:]+)(:([0-9]+))?)?(.*)/; $method = $2; $host = $4; $port = $6; $path = $7; return ($method, $host, $port, $path); } # Convert a hyperlink URL into a FQU, if necessary. sub fqu { local($partial) = @_; local($full); local($pmethod, $phost, $pport, $ppath) = &split_url($partial); $pmethod = $basemethod if $pmethod eq ""; $phost = $basehost if $phost eq ""; $pport = $baseport if $pport eq ""; if ($pport eq "80") { $pport = ""; } else { $pport = ":" . $pport; } if ($phost eq $basehost) { if ($ppath !~ /^\//) { $ppath = $basepath . '/' . $ppath; } } $full = $pmethod . "://" . $phost . $pport . $ppath; return $full; } # get directory where this file is. {$0 =~ /^(.*)\/.*$/; $my_dir = $1; if ($my_dir !~ ?^/?) {$my_dir = $ENV{PWD} . "/" . $my_dir;} if ($my_dir =~ ?/$?) {chop ($my_dir);}} push(@INC, $my_dir); # Parse command line arguments. $file = shift; $baseurl = shift; ($basemethod, $basehost, $baseport, $basepath) = &split_url($baseurl); $baseport = "80" if $baseport eq ""; require "parse-html.pl" || die "Could not load parse-html.pl"; require "html-ascii.pl" || die "Could not load html-ascii.pl"; %wily_urls = (); $wily_url = 1; &parse_html ($file); foreach $k (keys %wily_urls) { $u = &fqu($wily_urls{$k}); print "[_u$k] [http $u]\n"; } am to generate ASCII text for HTML # Created by James R. Davis, July 15 1994 # Split a URL into its component parts sub split_url { local($method, $host, $port, $path); $_ = $_[0]; /^((http|ftp|news|mailto|gopher|telnet):)?(\/\/([^\/:]+)(:([0-9]+))?)?(.*)/; $method = $2; $host = $4; $port = $6; $path = $7; return ($method, $host, $port, $path); } # Convert a hyperlink URL into a FQU, if necessary. sub fqu { local($partial) = @_; local($fuwily-0.13.42/tools/old/wilytoys/toys/fonts.alias000064402366570000012000000005361033320152300214630ustar00ozstaff00004330000002wilynormal "-adobe-new century schoolbook-medium-r-normal--12-120-75-75-p-70-iso8859-1" wilybold "-adobe-new century schoolbook-bold-r-normal--12-120-75-75-p-70-iso8859-1" wilyitalic "-adobe-new century schoolbook-medium-i-normal--12-120-75-75-p-70-iso8859-1" wilybolditalic "-adobe-new century schoolbook-bold-i-normal--12-120-75-75-p-70-iso8859-1" wily-0.13.42/tools/old/wilytoys/toys/fixed.9.font000064402366570000012000000036211033320152300214530ustar00ozstaff0000433000000217 14 0x0000 0x00FF lucm.latin1.9 0x0100 0x017E lucm.latineur.9 0x0180 0x01F0 matty.latinext.9 0x0250 0x02E9 lucm.ipa.9 0x0300 0x0308 matty.gendiacritics.9 0x0370 0x0372 matty.greekpunc.9 0x0386 0x03F5 lucm.greek.9 0x0400 0x0475 misc.cyrillic.9 0x2000 0x2044 lucm.genpunc.9 0x2070 0x208E lucm.supsub.9 0x20A0 0x20AA lucm.currency.9 0x2100 0x2138 matty.letterlike.9 0x2190 0x21EA misc.arrows 0x2200 0x227F matty.math1 0x2280 0x22F1 matty.math2 0x2300 0x232C matty.tech 0x2500 0x257F matty.chart 0x2580 0x2595 matty.blocks 0x25a0 0x25ee matty.geometric 0x2600 0x266F misc.ding 0x3000 0x303f jis.jis3000.16 0x3041 0x309e jis.hiragana.16 0x30a1 0x30fe jis.katakana.16 0x4e00 0x4fff jis.jis4e00.16 0x5000 0x51ff jis.jis5000.16 0x5200 0x53ff jis.jis5200.16 0x5400 0x55ff jis.jis5400.16 0x5600 0x57ff jis.jis5600.16 0x5800 0x59ff jis.jis5800.16 0x5a00 0x5bff jis.jis5a00.16 0x5c00 0x5dff jis.jis5c00.16 0x5e00 0x5fff jis.jis5e00.16 0x6000 0x61ff jis.jis6000.16 0x6200 0x63ff jis.jis6200.16 0x6400 0x65ff jis.jis6400.16 0x6600 0x67ff jis.jis6600.16 0x6800 0x69ff jis.jis6800.16 0x6a00 0x6bff jis.jis6a00.16 0x6c00 0x6dff jis.jis6c00.16 0x6e00 0x6fff jis.jis6e00.16 0x7000 0x71ff jis.jis7000.16 0x7200 0x73ff jis.jis7200.16 0x7400 0x75ff jis.jis7400.16 0x7600 0x77ff jis.jis7600.16 0x7800 0x79ff jis.jis7800.16 0x7a00 0x7bff jis.jis7a00.16 0x7c00 0x7dff jis.jis7c00.16 0x7e00 0x7fff jis.jis7e00.16 0x8000 0x81ff jis.jis8000.16 0x8200 0x83ff jis.jis8200.16 0x8400 0x85ff jis.jis8400.16 0x8600 0x87ff jis.jis8600.16 0x8800 0x89ff jis.jis8800.16 0x8a00 0x8bff jis.jis8a00.16 0x8c00 0x8dff jis.jis8c00.16 0x8e00 0x8fff jis.jis8e00.16 0x9000 0x91ff jis.jis9000.16 0x9200 0x93ff jis.jis9200.16 0x9400 0x95ff jis.jis9400.16 0x9600 0x97ff jis.jis9600.16 0x9800 0x99ff jis.jis9800.16 0x9a00 0x9bff jis.jis9a00.16 0x9c00 0x9dff jis.jis9c00.16 0x9e00 0x9fff jis.jis9e00.16 0xe000 0xe05f matty.tengwar.9 0xfee0 0xff5e lucm.latin1.9 0xfffd 0xfffd pelm.fffd.9 wily-0.13.42/tools/old/wilytoys/toys/Makefile000064402366570000012000000004041033320152300207510ustar00ozstaff00004330000002W = /home/steve/src/9/orig/wily-0.9.8 CFLAGS = -Xc -g CPPFLAGS = -I$W -I$W/include -I$W/libXg LDFLAGS = -L$W/libXg -L$W/libmsg LDLIBS = -lmsg -lXg -lnsl -lsocket PROGS = bold wcat all: $(PROGS) install: cp $(PROGS) $(HOME)/bin/Wily nuke: $(RM) $(PROGS) wily-0.13.42/tools/old/wilytoys/toys/README000064402366570000012000000110151033320152300201710ustar00ozstaff00004330000002These files are a few toys that I thought I would share with other people. They're not at all polished, and one of them was only just finished today, but hey - that's life on the edge. What is here: - working wcat to shove files into wily. - filter to convert man pages into something pretty and readable. - some scripts to view HTML web pages with wily. - a couple of useful wily wrapper scripts. What you need: - perl. 4.036 is what I use, but you might get away with v5. - Expect, if you want to be able to download web pages. Actually, there are plain perl scripts around on the net to do this, but I couldn't get the damn things to work on my machine, and I was in a hurry. I recommend trying one of the existing perl things (get_url, etc.) before installing Expect, if you haven't already got it. - the fonts from Matty's 9term distribution (if you want pretty man pages). - wily 0.98. - luck. Major Credit where credit is due: - The Perl scripts used for converting HTML files into something vaguely readable is by James R. Davis. I grabbed it from the web, and made a few minor changes to make it function as a wily browser, but the proper work's all James'. To build wcat: - Fiddle with the Makefile, so that it can find your wily distribution. - make all. If you want, you might want to bodge ./make, and put it somewhere where wily can find it. I use it to mangle the output of Sun's ANSI compiler into wily-style file:line references. There isn't a lot of point including it here, except that perl allows you to see each error message as it appears, with minimal buffering. there's also a "diff" script which does much the same thing. Well, I like it... The Makefile also builds "bold". We'll come back to that shortly. Man page viewer: This is an horrendous cheat, as suggested by either myself or gary/matty a while ago in the list (I forget who). Basically, it uses the large Unicode character set to have normal, italic and bold versions of the same characters within your set, and just displays the appropriate one according to the output of nroff/man. This required a little bit of setting up and munging around with fonts. These are my notes which I scrawled at the time that I got this going: Unpacked matty's font distribution. ran mkfontdir in the bdf directory. Selected a font I liked using xfontsel(1). Created bdf/fonts.alias, containing the alias "wilynormal" for this preferred font. Put wilynormal as the first font in smk.9.font (which I'd copied from prop.9.font). Add the font directory to the X server's font path with xset fp+ /home/steve/lib/fonts/bdf Changed bin/acme to have smk.9.font and fixed.9.font args. Checked all was ok by viewing src/9/hacked/9term/utf.test I've included my font files and the fonts.alias file so that you can see what I've done. Note that the extra character sets appear in the 0x4000-odd range, and that this is hard-coded into the source for "bold.c". The man page viewer ("man") takes standard man arguments, and passes the output of normal man through bold, to get the pretty fonts, and then into wcat to display the file in wily. It doesn't get everything right, but it's good enough for what I use it for. You can also B2B1 on filename.1 files to view them directly. HTML web browser: This has three parts. The first is fetchurl, a quick Expect script that will grab the output of a telnet connection to some web server. Use a proper perl program to do this if you can get one. For starters, mine only handles http URLs. The second part is the driver, http. This takes as an argument a normal URL, e.g. "http http://www.w3.org". It uses fetchurl to grab the file, and then passes it to the final part, html2wily. Html2wily does the clever bit of generating readable ASCII out of the HTML. The bit I've added is to support URLs within the file: given a URL such as Some Text, you end up with this: [_u1][Some Text]. At the bottom of the file, you see: [_u1][http http://www.foo.com/file.html]. The idea is that you can B3 on the _u1 to move between the highlighted text and the URL that goes with it. If you decide to follow the URL, you double-click beside the [ or ], to select the whole command, and B2 it. The process then begins again. Incidentally, there are a few broken bits in this, especially where partial URLs are converted into full ones, but that's life. This thing took about 2 hours to write, this morning. Hope this of some use... Steve Kilbane, 12 March 1996. re a few toys that I thought I would share with other people. They're not at all polished, and one of them was only just finished today, but hey - that's life on the edge. What is here: - working wcat to shove files into wily. - filter to convert man pages into something pretty and readable. - some scripts to view HTML web pages with wily. - a couple of useful wily wrapper scripts. What you need: - perl. 4.036 is what I use, but you might get away with v5. - Expect, if you want to be abwily-0.13.42/tools/old/wilytoys/toys/prop.9.font000064402366570000012000000036121033320152300213340ustar00ozstaff0000433000000216 13 0x0000 0x00FF lubs14 0x0100 0x017E lucm.latineur.9 0x0180 0x01F0 matty.latinext.9 0x0250 0x02E9 lucm.ipa.9 0x0300 0x0308 matty.gendiacritics.9 0x0370 0x0372 matty.greekpunc.9 0x0386 0x03F5 lucm.greek.9 0x0400 0x0475 misc.cyrillic.9 0x2000 0x2044 lucm.genpunc.9 0x2070 0x208E lucm.supsub.9 0x20A0 0x20AA lucm.currency.9 0x2100 0x2138 matty.letterlike.9 0x2190 0x21EA misc.arrows 0x2200 0x227F matty.math1 0x2280 0x22F1 matty.math2 0x2300 0x232C matty.tech 0x2500 0x257F matty.chart 0x2580 0x2595 matty.blocks 0x25a0 0x25ee matty.geometric 0x2600 0x266F misc.ding 0x3000 0x303f jis.jis3000.16 0x3041 0x309e jis.hiragana.16 0x30a1 0x30fe jis.katakana.16 0x4e00 0x4fff jis.jis4e00.16 0x5000 0x51ff jis.jis5000.16 0x5200 0x53ff jis.jis5200.16 0x5400 0x55ff jis.jis5400.16 0x5600 0x57ff jis.jis5600.16 0x5800 0x59ff jis.jis5800.16 0x5a00 0x5bff jis.jis5a00.16 0x5c00 0x5dff jis.jis5c00.16 0x5e00 0x5fff jis.jis5e00.16 0x6000 0x61ff jis.jis6000.16 0x6200 0x63ff jis.jis6200.16 0x6400 0x65ff jis.jis6400.16 0x6600 0x67ff jis.jis6600.16 0x6800 0x69ff jis.jis6800.16 0x6a00 0x6bff jis.jis6a00.16 0x6c00 0x6dff jis.jis6c00.16 0x6e00 0x6fff jis.jis6e00.16 0x7000 0x71ff jis.jis7000.16 0x7200 0x73ff jis.jis7200.16 0x7400 0x75ff jis.jis7400.16 0x7600 0x77ff jis.jis7600.16 0x7800 0x79ff jis.jis7800.16 0x7a00 0x7bff jis.jis7a00.16 0x7c00 0x7dff jis.jis7c00.16 0x7e00 0x7fff jis.jis7e00.16 0x8000 0x81ff jis.jis8000.16 0x8200 0x83ff jis.jis8200.16 0x8400 0x85ff jis.jis8400.16 0x8600 0x87ff jis.jis8600.16 0x8800 0x89ff jis.jis8800.16 0x8a00 0x8bff jis.jis8a00.16 0x8c00 0x8dff jis.jis8c00.16 0x8e00 0x8fff jis.jis8e00.16 0x9000 0x91ff jis.jis9000.16 0x9200 0x93ff jis.jis9200.16 0x9400 0x95ff jis.jis9400.16 0x9600 0x97ff jis.jis9600.16 0x9800 0x99ff jis.jis9800.16 0x9a00 0x9bff jis.jis9a00.16 0x9c00 0x9dff jis.jis9c00.16 0x9e00 0x9fff jis.jis9e00.16 0xe000 0xe05f matty.tengwar.9 0xfee0 0xff5e lucm.latin1.9 0xfffd 0xfffd pelm.fffd.9 wily-0.13.42/tools/old/wilytoys/toys/bold.c000064402366570000012000000024001033320152300203730ustar00ozstaff00004330000002#include #include #include #include #include /* * XXX - current assumes that we won't be in mid-sequence when EOF is reached. */ #define MAGICBOLD 0x4000 #define MAGICITALIC 0x4100 #define MAGICITALICBOLD 0x4200 static long charset = MAGICITALIC; static void boldchar(int c, int overstrike) { char str[4], *s = str; Rune r = c + charset; switch (runetochar(s, &r)) { case 3: putchar(*s++); case 2: putchar(*s++); case 1: putchar(*s++); } } int main(int argc, char *argv[]) { int i = 0, b = 0,c; int state = 0; int outchar; int os = 0; while ((c = getopt(argc, argv, "ib")) != EOF) { switch (c) { case 'b': b++; break; case 'i': i++; break; default: exit(1); } } charset = b&&i? MAGICITALICBOLD : b? MAGICBOLD : MAGICITALIC; while ((c = getchar()) != EOF) { switch (state) { case 0: if (c == '_') state++; else putchar(c); break; case 1: if (c == 0x8) /* backspace */ state++; else { putchar('_'); putchar(c); state = 0; } break; case 2: boldchar(c,0); state = 0; break; default: fprintf(stderr,"We're screwed!\n"); exit(1); } } if (state) fprintf(stderr,"File was truncated!\n"); return 0; } wily-0.13.42/tools/old/wilytoys/toys/smk.9.font000064402366570000012000000037331033320152300211520ustar00ozstaff0000433000000216 13 0x0000 0x00FF wilynormal 0x0100 0x017E lucm.latineur.9 0x0180 0x01F0 matty.latinext.9 0x0250 0x02E9 lucm.ipa.9 0x0300 0x0308 matty.gendiacritics.9 0x0370 0x0372 matty.greekpunc.9 0x0386 0x03F5 lucm.greek.9 0x0400 0x0475 misc.cyrillic.9 0x2000 0x2044 lucm.genpunc.9 0x2070 0x208E lucm.supsub.9 0x20A0 0x20AA lucm.currency.9 0x2100 0x2138 matty.letterlike.9 0x2190 0x21EA misc.arrows 0x2200 0x227F matty.math1 0x2280 0x22F1 matty.math2 0x2300 0x232C matty.tech 0x2500 0x257F matty.chart 0x2580 0x2595 matty.blocks 0x25a0 0x25ee matty.geometric 0x2600 0x266F misc.ding 0x3000 0x303f jis.jis3000.16 0x3041 0x309e jis.hiragana.16 0x30a1 0x30fe jis.katakana.16 0x4000 0x40FF wilybold 0x4100 0x41FF wilyitalic 0x4200 0x42FF wilybolditalic 0x4e00 0x4fff jis.jis4e00.16 0x5000 0x51ff jis.jis5000.16 0x5200 0x53ff jis.jis5200.16 0x5400 0x55ff jis.jis5400.16 0x5600 0x57ff jis.jis5600.16 0x5800 0x59ff jis.jis5800.16 0x5a00 0x5bff jis.jis5a00.16 0x5c00 0x5dff jis.jis5c00.16 0x5e00 0x5fff jis.jis5e00.16 0x6000 0x61ff jis.jis6000.16 0x6200 0x63ff jis.jis6200.16 0x6400 0x65ff jis.jis6400.16 0x6600 0x67ff jis.jis6600.16 0x6800 0x69ff jis.jis6800.16 0x6a00 0x6bff jis.jis6a00.16 0x6c00 0x6dff jis.jis6c00.16 0x6e00 0x6fff jis.jis6e00.16 0x7000 0x71ff jis.jis7000.16 0x7200 0x73ff jis.jis7200.16 0x7400 0x75ff jis.jis7400.16 0x7600 0x77ff jis.jis7600.16 0x7800 0x79ff jis.jis7800.16 0x7a00 0x7bff jis.jis7a00.16 0x7c00 0x7dff jis.jis7c00.16 0x7e00 0x7fff jis.jis7e00.16 0x8000 0x81ff jis.jis8000.16 0x8200 0x83ff jis.jis8200.16 0x8400 0x85ff jis.jis8400.16 0x8600 0x87ff jis.jis8600.16 0x8800 0x89ff jis.jis8800.16 0x8a00 0x8bff jis.jis8a00.16 0x8c00 0x8dff jis.jis8c00.16 0x8e00 0x8fff jis.jis8e00.16 0x9000 0x91ff jis.jis9000.16 0x9200 0x93ff jis.jis9200.16 0x9400 0x95ff jis.jis9400.16 0x9600 0x97ff jis.jis9600.16 0x9800 0x99ff jis.jis9800.16 0x9a00 0x9bff jis.jis9a00.16 0x9c00 0x9dff jis.jis9c00.16 0x9e00 0x9fff jis.jis9e00.16 0xe000 0xe05f matty.tengwar.9 0xfee0 0xff5e lucm.latin1.9 0xfffd 0xfffd pelm.fffd.9 wily-0.13.42/tools/old/wilytoys/toys/wcat.c000064402366570000012000000015661033320152300204250ustar00ozstaff00004330000002#include #include #include #include #include #include #include void e(char *s) { perror(s); exit(1); } int main(int argc, char *argv[]) { char cwd[BUFSIZ+1], filename[BUFSIZ]; char *file; int isreal; Fd fd; Mqueue q[1]; Id id; int r; ulong len = 0; if (argc > 1) { file = argv[1]; isreal = 1; if (*file == '/') strcpy(filename, file); else { if (getcwd(cwd,BUFSIZ) == 0) e("getcwd"); sprintf(filename,"%s/%s", cwd, file); } } else { isreal = 0; sprintf(filename,"+stdin-%d",getpid()); } if ((fd = get_connect()) < 0) e("get_connect"); mq_init(q,fd); if (rpc_new(q, &id, filename, isreal)) e("rpc_new"); if (isreal) return 0; while ((r = fread(cwd, 1, BUFSIZ, stdin))) { cwd[r] = 0; if (rpc_insert(q, id, len, cwd)) e("rpc_insert"); len += r; } return 0; } wily-0.13.42/tools/old/wilytoys/toys/fetchurl000064402366570000012000000010051033320152300210460ustar00ozstaff00004330000002#!/usr/local/bin/expect -f # Download an HTML file in a simplistic fashion. # Usage: fetchurl hostname filename # (parse the URL yourself...) set hostname [lindex $argv 0] set filename [lindex $argv 1] log_user 0 spawn telnet $hostname http expect { "Connected" { expect "Escape character is '^]'." send "GET $filename\n" expect "GET $filename\r\n" log_user 1 interact -o "\r" {} "Connection closed by foreign host." {} exit 0 } timeout { send_user "Could not connect to $hostname\n" exit 1 } } r/local/bin/expect -f # Download an HTML file in a simplistic fashion. # Usage: fetchurl hostname filename # (parse the URL yourself...) set hostname [lindex $argv 0] set filename [lindex $argv 1] log_user 0 spawn telnet $hostname http expect { "Connected" { expect "Escape character is '^]'." send "GET $filename\n" expect "GET $filename\r\n" log_user 1 interact -o "\r" {} "Connection closed by foreign host." {} exit 0 } timeout { send_user "Could not connect to $hostname\n" exit 1 wily-0.13.42/tools/old/wilytoys/toys/html-ascii.pl000064402366570000012000000146741033320152300217160ustar00ozstaff00004330000002# Routines for HTML to ASCII. # (fixed width font, no font changes for size, bold, etc) with a little # BUGS AND MISSING FEATURES # font tags (e.g. CODE, EM) cause an extra whitespace # e.g. foo, -> foo , # Jim Davis July 15 1994 # modified 3 Aug 94 to support MENU and DIR require "tformat.pl" || die "Could not load tformat.pl: $@\nStopped"; # Can be set by command line arg if (! defined($columns_per_line)) { $columns_per_line = 72;} if (! defined($flush_last_page)) { $flush_last_page = 1;} # amount to add to indentation $indent_left = 5; $indent_right = 5; # ignore contents inside HEAD. $ignore_text = 0; # Set variables in tformat $left_margin = 1; $right_margin = $columns_per_line; $bottom_margin = 0; ## Routines called by html.pl $Begin{"HEAD"} = "begin_head"; $End{"HEAD"} = "end_head"; sub begin_head { local ($element, $tag) = @_; $ignore_text = 1;} sub end_head { local ($element) = @_; $ignore_text = 0;} $Begin{"BODY"} = "begin_document"; sub begin_document { local ($element, $tag) = @_; &start_page();} $End{"BODY"} = "end_document"; sub end_document { local ($element) = @_; &fresh_line();} ## Headers $Begin{"H1"} = "begin_header"; $End{"H1"} = "end_header"; $Begin{"H2"} = "begin_header"; $End{"H2"} = "end_header"; $Begin{"H3"} = "begin_header"; $End{"H3"} = "end_header"; $Begin{"H4"} = "begin_header"; $End{"H4"} = "end_header"; $Skip_Before{"H1"} = 1; $Skip_After{"H1"} = 1; $Skip_Before{"H2"} = 1; $Skip_After{"H2"} = 1; $Skip_Before{"H3"} = 1; $Skip_After{"H3"} = 0; sub begin_header { local ($element, $tag) = @_; &skip_n_lines ($Skip_Before{$element}, 5);} sub end_header { local ($element) = @_; &skip_n_lines ($Skip_After{$element});} $Begin{"BR"} = "line_break"; sub line_break { local ($element, $tag) = @_; &fresh_line();} $Begin{"P"} = "begin_paragraph"; # if fewer than this many lines left on page, start new page $widow_cutoff = 5; sub begin_paragraph { local ($element, $tag) = @_; &skip_n_lines (1, $widow_cutoff);} $Begin{"BLOCKQUOTE"} = "begin_blockquote"; $End{"BLOCKQUOTE"} = "end_blockquote"; sub begin_blockquote { local ($element, $tag) = @_; $left_margin += $indent_left; $right_margin = $columns_per_line - $indent_right; &skip_n_lines (1);} sub end_blockquote { local ($element) = @_; $left_margin -= $indent_left; $right_margin = $columns_per_line; &skip_n_lines (1);} $Begin{"PRE"} = "begin_pre"; $End{"PRE"} = "end_pre"; sub begin_pre { local ($element, $tag) = @_; $whitespace_significant = 1;} sub end_pre { local ($element) = @_; $whitespace_significant = 0;} $Begin{"INPUT"} = "form_input"; sub form_input { local ($element, $tag, *attributes) = @_; if ($attributes{"value"} ne "") { &print_word_wrap($attributes{"value"});}} $Begin{"HR"} = "horizontal_rule"; sub horizontal_rule { local ($element, $tag) = @_; &fresh_line (); &print_n_chars ($right_margin - $left_margin, "-");} # Add code for IMG (use ALT attribute) # Ignore I, B, EM, TT, CODE (no font changes) ## List environments $Begin{"UL"} = "begin_itemize"; $End{"UL"} = "end_list_env"; $Begin{"OL"} = "begin_enumerated"; $End{"OL"} = "end_list_env"; $Begin{"MENU"} = "begin_menu"; $End{"MENU"} = "end_list_env"; $Begin{"DIR"} = "begin_dir"; $End{"DIR"} = "end_list_env"; $Begin{"LI"} = "begin_list_item"; # application-specific initialization routine sub html_begin_doc { @list_stack = (); $list_type = "bullet"; $list_counter = 0;} sub push_list_env { push (@list_stack, join (":", $list_type, $list_counter));} sub pop_list_env { ($list_type, $list_counter) = split (":", pop (@list_stack)); $left_margin -= $indent_left;} sub begin_itemize { local ($element, $tag) = @_; &push_list_env(); $left_margin += $indent_left; $list_type = "bullet"; $list_counter = "*";} sub begin_menu { local ($element, $tag) = @_; &push_list_env(); $left_margin += $indent_left; $list_type = "bullet"; $list_counter = "*";} sub begin_dir { local ($element, $tag) = @_; &push_list_env(); $left_margin += $indent_left; $list_type = "bullet"; $list_counter = "*";} sub begin_enumerated { local ($element, $tag) = @_; &push_list_env(); $left_margin += $indent_left; $list_type = "enumerated"; $list_counter = 1;} sub end_list_env { local ($element) = @_; &pop_list_env(); # &fresh_line(); } sub begin_list_item { local ($element, $tag) = @_; $left_margin -= 2; &fresh_line(); &print_word_wrap("$list_counter "); if ($list_type eq "enumerated") {$list_counter++;} $left_margin += 2;} $Begin{"DL"} = "begin_dl"; sub begin_dl { local ($element, $tag) = @_; &skip_n_lines(1,5);} $Begin{"DT"} = "begin_defined_term"; $Begin{"DD"} = "begin_defined_definition"; $End{"DD"} = "end_defined_definition"; sub begin_defined_term { local ($element, $tag) = @_; &fresh_line();} sub begin_defined_definition { local ($element, $tag) = @_; $left_margin += $indent_left; &fresh_line();} sub end_defined_definition { local ($element) = @_; $left_margin -= $indent_left; &fresh_line();} $Begin{"META"} = "begin_meta"; # a META tag sets a value in the assoc array %Variable # i.e. sers $Variable{author} to "Rushdie" sub begin_meta { local ($element, $tag, *attributes) = @_; local ($variable, $value); $variable = $attributes{name}; $value = $attributes{content}; $Variable{$variable} = $value;} $Begin{"IMG"} = "begin_img"; sub begin_img { local ($element, $tag, *attributes) = @_; &print_word_wrap (($attributes{"alt"} ne "") ? $attributes{"alt"} : "[IMAGE]");} # URLs $Begin{"A"} = "begin_a"; sub begin_a { local ($element, $tag, *attributes) = @_; local ($href, $k); $href = $attributes{href}; $k = $main'wily_url++; $main'wily_urls{$k} = $href; &print_word_wrap ("[_u$k]["); } $End{"A"} = "end_a"; sub end_a { &print_word_wrap("]"); } # Content and whitespace. sub html_content { local ($string) = @_; unless ($ignore_text) { &print_word_wrap ($string);}} sub html_whitespace { local ($string) = @_; if (! $whitespace_significant) { die "Internal error, called html_whitespace when whitespace was not significant";} local ($i); for ($i = 0; $i < length ($string); $i++) { &print_whitespace (substr($string,$i,1));}} # called by tformat. Do nothing. sub do_footer { } sub do_header { } 1; wily-0.13.42/tools/old/wilytoys/toys/parse-html.pl000064402366570000012000000214501033320152300217260ustar00ozstaff00004330000002# HTML parser # Jim Davis, July 15 1994 # This is an HTML parser not an SGML parser. It does not parse a DTD, # The DTD is implicit in the code, and specific to HTML. # The processing of the HTML can be customized by the user by # 1) Defining routines to be called for various tags (see Begin and End arrays) # 2) Defining routines html_content and html_whitespace # This is not a validating parser. It does not check the content model # eg you can use DT outside a DL and it won't know. It is too liberal in # what tags are allowed to minimize what other tags. # Bugs - can't parse the prolog or whatever you call it # # # # %html; # ]> # modified 3 Aug to add a bunch of HTML 2.0 tags # modified 3 Sept to print HTML stack to STDERR not STDOUT, to add new # routines html_begin_doc and html_end_doc for application specific cleanup # and to break parse_html into two pieces. # modified 30 Sept 94. parse_attributes now handles tag attributes that # don't have values. thanks to Bill Simpson-Young # for the code. # modified 17 Apr 95 to support FORMS tags. $debug = 0; $whitespace_significant = 0; # global variables: # $line_buffer is line buffer # $line_count is input line number. $line_buffer = ""; $line_count = 0; sub parse_html { local ($file) = @_; open (HTML, $file) || die "Could not open $file: $!\nStopped"; &parse_html_stream (); close (HTML);} # Global input HTML is the handle to the stream of HTML sub parse_html_stream { local ($token, $new); ## initialization @stack=(); $line_count = 0; $line_buffer = ""; ## application specific initialization &html_begin_doc(); main: while (1) { # if whitespace does not matter, trim any leading space. if (! $whitespace_significant) { $line_buffer =~ s/^\s+//;} # now dispatch on the type of token if ($line_buffer =~ /^(\s+)/) { $token = $1; $line_buffer = $'; &html_whitespace ($token);} # This will lose if there is more than one comment on the line! elsif ($line_buffer =~ /^(\)/) { $token = $1; $line_buffer = $'; &html_comment ($token);} elsif ($line_buffer =~ /^(\]*\>)/) { $token = $1; $line_buffer = $'; &html_comment ($token);} elsif ($line_buffer =~ /^(\<\/[^\>]*\>)/) { $token = $1; $line_buffer = $'; &html_etag ($token);} elsif ($line_buffer =~ /^(\<[^!\/][^\>]*\>)/) { $token = $1; $line_buffer = $'; &html_tag ($token);} elsif ($line_buffer =~ /^([^\s<]+)/) { $token = $1; $line_buffer = $'; $token = &substitute_entities($token); &html_content ($token); } else { # No valid token in buffer. Maybe it's empty, or maybe there's an # incomplete tag. So get some more data. $new = ; if (! defined ($new)) {last main;} # if we're trying to find a match for a tag, then get rid of embedded newline # this is, I think, a kludge if ($line_buffer =~ /^\ -1) { print STDERR "Stack not empty at end of document\n"; &print_html_stack();} } sub html_tag { local ($tag) = @_; local ($element) = &tag_element ($tag); local (%attributes) = &tag_attributes ($tag); # the tag might minimize (be an implicit end) for the previous tag local ($prev_element); while (&Minimizes(&stack_top_element(), $element)) { $prev_element = &stack_pop_element (); if ($debug) { print STDERR "MINIMIZING $prev_element with $element on $line_count\n";} &html_end ($prev_element, 0);} push (@stack, $tag); &html_begin ($element, $tag, *attributes); if (&Empty($element)) { pop(@stack); &html_end ($element, 0);} } sub html_etag { local ($tag) = @_; local ($element) = &tag_element ($tag); # pop stack until find matching tag. This is probably a bad idea, # or at least too general. local ( $prev_element) = &stack_pop_element(); until ($prev_element eq $element) { if ($debug) { print STDERR "MINIMIZING $prev_element with /$element on $line_count \n";} &html_end ($prev_element, 0); if ($#stack == -1) { print STDERR "No match found for /$element. You will lose\n"; last;} $prev_element = &stack_pop_element();} &html_end ($element, 1); } # For each element, the names of elements which minimize it. # This is of course totally HTML dependent and probably I have it wrong too $Minimize{"DT"} = "DT:DD"; $Minimize{"DD"} = "DT"; $Minimize{"LI"} = "LI"; $Minimize{"P"} = "P:DT:LI:H1:H2:H3:H4:BLOCKQUOTE:UL:OL:DL"; # Does element E2 minimize E1? sub Minimizes { local ($e1, $e2) = @_; local ($value) = 0; foreach $elt (split (":", $Minimize{$e1})) { if ($elt eq $e2) {$value = 1;}} $value;} $Empty{"BASE"} = 1; $Empty{"BR"} = 1; $Empty{"HR"} = 1; $Empty{"IMG"} = 1; $Empty{"ISINDEX"} = 1; $Empty{"LINK"} = 1; $Empty{"META"} = 1; $Empty{"NEXTID"} = 1; $Empty{"INPUT"} = 1; # Empty tags have no content and hence no end tags sub Empty { local ($element) = @_; $Empty{$element};} sub print_html_stack { print STDERR "\n ==\n"; foreach $elt (reverse @stack) {print STDERR " $elt\n";} print STDERR " ==========\n";} # The element on top of stack, if any. sub stack_top_element { if ($#stack >= 0) { &tag_element ($stack[$#stack]);}} sub stack_pop_element { &tag_element (pop (@stack));} # The element from the tag, normalized. sub tag_element { local ($tag) = @_; $tag =~ /<\/?([^\s>]+)/; local ($element) = $1; $element =~ tr/a-z/A-Z/; $element;} # associative array of the attributes of a tag. sub tag_attributes { local ($tag) = @_; $tag =~ /^<[A-Za-z]+ +(.*)>$/; &parse_attributes($1);} # string should be something like # KEY="value" KEY2="longer value" KEY3="tags o doom" # output is an associative array (like a lisp property list) # attributes names are not case sensitive, do I downcase them # Maybe (probably) I should substitute for entities when parsing attributes. sub parse_attributes { local ($string) = @_; local (%attributes); local ($name, $val); get: while (1) { if ($string =~ /^ *([A-Za-z]+)=\"([^\"]*)\"/) { $name = $1; $val = $2; $string = $'; $name =~ tr/A-Z/a-z/; $attributes{$name} = $val; } elsif ($string =~ /^ *([A-Za-z]+)=(\S*)/) { $name = $1; $val = $2; $string = $'; $name =~ tr/A-Z/a-z/; $attributes{$name} = $val;} elsif ($string =~ /^ *([A-Za-z]+)/) { $name = $1; $val = ""; $string = $'; $name =~ tr/A-Z/a-z/; $attributes{$name} = $val;} else {last;}} %attributes;} sub substitute_entities { local ($string) = @_; $string =~ s/&/&/g; $string =~ s/<//g; $string =~ s/"/\"/g; $string;} @HTML_elements = ( "A", "ADDRESS", "B", "BASE", "BLINK", # Netscape addition :-( "BLOCKQUOTE", "BODY", "BR", "CITE", "CENTER", # Netscape addition :-( "CODE", "DD", "DIR", "DFN", "DL", "DT", "EM", "FORM", "H1", "H2", "H3", "H4", "H5", "H6", "HEAD", "HR", "HTML", "I", "ISINDEX", "IMG", "INPUT", "KBD", "LI", "LINK", "MENU", "META", "NEXTID", "OL", "OPTION", "P", "PRE", "SAMP", "SELECT", "STRIKE", "STRONG", "TITLE", "TEXTAREA", "TT", "UL", "VAR", ); sub define_element { local ($element) = @_; $Begin{$element} = "Noop"; $End{$element} = "Noop";} foreach $element (@HTML_elements) {&define_element($element);} # do nothing sub Noop { local ($element, $xxx) = @_; } # called when a tag begins. Dispatches using Begin sub html_begin { local ($element, $tag, *attributes) = @_; local ($routine) = $Begin{$element}; if ($routine eq "") { print STDERR "Unknown HTML element $element ($tag) on line $line_count\n";} else {eval "&$routine;"}} # called when a tag ends. Explicit is 0 if tag end is because of minimization # not that you should care. sub html_end { local ($element, $explicit) = @_; local ($routine) = $End{$element}; if ($routine eq "") { print STDERR "Unknown HTML element \"$element\" (END $explicit) on line $line_count\n";} else {eval "&$routine(\"$element\", $explicit)";}} sub html_content { local ($word) = @_; } sub html_whitespace { local ($whitespace) = @_;} sub html_comment { local ($tag) = @_;} # redefine these for application-specific initialization and cleanup sub html_begin_doc {} sub html_end_doc {} # return a "true value" when loaded by perl. 1; wily-0.13.42/tools/old/wilytoys/html2wily000064402366570000012000000030661033320152300202000ustar00ozstaff00004330000002#!/usr/local/bin/perl -I/home/steve/bin/Wily # Program to generate ASCII text for HTML # Created by James R. Davis, July 15 1994 # Split a URL into its component parts sub split_url { local($method, $host, $port, $path); $_ = $_[0]; /^((http|ftp|news|mailto|gopher|telnet):)?(\/\/([^\/:]+)(:([0-9]+))?)?(.*)/; $method = $2; $host = $4; $port = $6; $path = $7; return ($method, $host, $port, $path); } # Convert a hyperlink URL into a FQU, if necessary. sub fqu { local($partial) = @_; local($full); local($pmethod, $phost, $pport, $ppath) = &split_url($partial); $pmethod = $basemethod if $pmethod eq ""; $phost = $basehost if $phost eq ""; $pport = $baseport if $pport eq ""; if ($pport eq "80") { $pport = ""; } else { $pport = ":" . $pport; } if ($phost eq $basehost) { if ($ppath !~ /^\//) { $ppath = $basepath . '/' . $ppath; } } $full = $pmethod . "://" . $phost . $pport . $ppath; return $full; } # get directory where this file is. {$0 =~ /^(.*)\/.*$/; $my_dir = $1; if ($my_dir !~ ?^/?) {$my_dir = $ENV{PWD} . "/" . $my_dir;} if ($my_dir =~ ?/$?) {chop ($my_dir);}} push(@INC, $my_dir); # Parse command line arguments. $file = shift; $baseurl = shift; ($basemethod, $basehost, $baseport, $basepath) = &split_url($baseurl); $baseport = "80" if $baseport eq ""; require "parse-html.pl" || die "Could not load parse-html.pl"; require "html-ascii.pl" || die "Could not load html-ascii.pl"; %wily_urls = (); $wily_url = 1; &parse_html ($file); foreach $k (keys %wily_urls) { $u = &fqu($wily_urls{$k}); print "[_u$k] [http $u]\n"; } wily-0.13.42/tools/old/wilytoys/fonts.alias000064402366570000012000000005361033320152300204650ustar00ozstaff00004330000002wilynormal "-adobe-new century schoolbook-medium-r-normal--12-120-75-75-p-70-iso8859-1" wilybold "-adobe-new century schoolbook-bold-r-normal--12-120-75-75-p-70-iso8859-1" wilyitalic "-adobe-new century schoolbook-medium-i-normal--12-120-75-75-p-70-iso8859-1" wilybolditalic "-adobe-new century schoolbook-bold-i-normal--12-120-75-75-p-70-iso8859-1" wily-0.13.42/tools/old/wilytoys/fixed.9.font000064402366570000012000000036211033320152300204550ustar00ozstaff0000433000000217 14 0x0000 0x00FF lucm.latin1.9 0x0100 0x017E lucm.latineur.9 0x0180 0x01F0 matty.latinext.9 0x0250 0x02E9 lucm.ipa.9 0x0300 0x0308 matty.gendiacritics.9 0x0370 0x0372 matty.greekpunc.9 0x0386 0x03F5 lucm.greek.9 0x0400 0x0475 misc.cyrillic.9 0x2000 0x2044 lucm.genpunc.9 0x2070 0x208E lucm.supsub.9 0x20A0 0x20AA lucm.currency.9 0x2100 0x2138 matty.letterlike.9 0x2190 0x21EA misc.arrows 0x2200 0x227F matty.math1 0x2280 0x22F1 matty.math2 0x2300 0x232C matty.tech 0x2500 0x257F matty.chart 0x2580 0x2595 matty.blocks 0x25a0 0x25ee matty.geometric 0x2600 0x266F misc.ding 0x3000 0x303f jis.jis3000.16 0x3041 0x309e jis.hiragana.16 0x30a1 0x30fe jis.katakana.16 0x4e00 0x4fff jis.jis4e00.16 0x5000 0x51ff jis.jis5000.16 0x5200 0x53ff jis.jis5200.16 0x5400 0x55ff jis.jis5400.16 0x5600 0x57ff jis.jis5600.16 0x5800 0x59ff jis.jis5800.16 0x5a00 0x5bff jis.jis5a00.16 0x5c00 0x5dff jis.jis5c00.16 0x5e00 0x5fff jis.jis5e00.16 0x6000 0x61ff jis.jis6000.16 0x6200 0x63ff jis.jis6200.16 0x6400 0x65ff jis.jis6400.16 0x6600 0x67ff jis.jis6600.16 0x6800 0x69ff jis.jis6800.16 0x6a00 0x6bff jis.jis6a00.16 0x6c00 0x6dff jis.jis6c00.16 0x6e00 0x6fff jis.jis6e00.16 0x7000 0x71ff jis.jis7000.16 0x7200 0x73ff jis.jis7200.16 0x7400 0x75ff jis.jis7400.16 0x7600 0x77ff jis.jis7600.16 0x7800 0x79ff jis.jis7800.16 0x7a00 0x7bff jis.jis7a00.16 0x7c00 0x7dff jis.jis7c00.16 0x7e00 0x7fff jis.jis7e00.16 0x8000 0x81ff jis.jis8000.16 0x8200 0x83ff jis.jis8200.16 0x8400 0x85ff jis.jis8400.16 0x8600 0x87ff jis.jis8600.16 0x8800 0x89ff jis.jis8800.16 0x8a00 0x8bff jis.jis8a00.16 0x8c00 0x8dff jis.jis8c00.16 0x8e00 0x8fff jis.jis8e00.16 0x9000 0x91ff jis.jis9000.16 0x9200 0x93ff jis.jis9200.16 0x9400 0x95ff jis.jis9400.16 0x9600 0x97ff jis.jis9600.16 0x9800 0x99ff jis.jis9800.16 0x9a00 0x9bff jis.jis9a00.16 0x9c00 0x9dff jis.jis9c00.16 0x9e00 0x9fff jis.jis9e00.16 0xe000 0xe05f matty.tengwar.9 0xfee0 0xff5e lucm.latin1.9 0xfffd 0xfffd pelm.fffd.9 wily-0.13.42/tools/old/wilytoys/Makefile000064402366570000012000000004041033320152300177530ustar00ozstaff00004330000002W = /home/steve/src/9/orig/wily-0.9.8 CFLAGS = -Xc -g CPPFLAGS = -I$W -I$W/include -I$W/libXg LDFLAGS = -L$W/libXg -L$W/libmsg LDLIBS = -lmsg -lXg -lnsl -lsocket PROGS = bold wcat all: $(PROGS) install: cp $(PROGS) $(HOME)/bin/Wily nuke: $(RM) $(PROGS) wily-0.13.42/tools/old/wilytoys/reader2/000075502366570000012000000000001033320152300176415ustar00ozstaff00004330000002wily-0.13.42/tools/old/wilytoys/reader2/newsheaders.h000064402366570000012000000002371033320152300223240ustar00ozstaff00004330000002#ifndef WILYNEWS_H #define WILYNEWS_H #include "headers.h" #include "news.h" #include "newsrc.h" #include "nntp.h" #include "post.h" #endif /* WILYNEWS_H */ wily-0.13.42/tools/old/wilytoys/reader2/solaris.c000064402366570000012000000042601033320152300214630ustar00ozstaff00004330000002/* * solaris.c - the system-dependent routines for Solaris 2. */ #include "mailheaders.h" #include #include /* * load_mbox(mbox,rescan) - open the named file, and make it available * as a block of memory between mbox_start and mbox_end. If rescan * is true, we've already the mbox, and we want to see if there're more * messages in the file. */ int load_mbox(mMbox *mbox, int rescan) { const char *mode = mbox->readonly? "r" : "r+"; FILE *fp = fopen(mbox->name,mode); char *addr = 0; size_t len; struct stat st; if (fp == 0) { DPRINT("Could not open file"); goto broken; } if (stat(mbox->name,&st) == -1) { DPRINT("Could not stat file"); goto broken; } if (rescan) { if (st.st_size < mbox->size) { fprintf(stderr,"%s corrupt\n", mbox->name); goto broken; } if (st.st_mtime == mbox->mtime) { DPRINT("file hasn't changed"); fclose(fp); mbox->mbox_start = mbox->mbox_end = 0; return 0; } len = (size_t)(st.st_size - mbox->size); if (fseek(fp, mbox->size, SEEK_SET) == -1) { DPRINT("Could not seek to start of new messages"); } } else len = (size_t)st.st_size; mbox->size = st.st_size; mbox->mtime = st.st_mtime; if ((addr = mb_alloc(len+1)) == 0) { DPRINT("Could not allocate space for new messages"); goto broken; } addr[len] = 0; /* handy for debugging */ if (fread(addr, (size_t)1, len, fp) != len) { DPRINT("Could not read new messages"); goto broken; } fclose(fp); mbox->mbox_start = addr; mbox->mbox_end = mbox->mbox_start + len; return 0; broken: if (addr) free(addr); fclose(fp); return 1; } /* we failed to load the mbox. Check that it exists, if we need it to. */ int empty_mbox(mMbox *box, const char *filename, int mustexist) { int readable = !access(filename, R_OK); int exists = !access(filename, F_OK); if (readable || (exists && !readable) || (mustexist && !exists)) { fprintf(stderr,"%s not %s\n",filename, readable? "read" : exists? "readable" : "found"); return 1; } /* file doesn't exist, but that's ok - it doesn't need to in this case, so create an empty mbox */ box->size = 0; box->mbox_start = box->mbox_end = 0; /* XXX - likely to flush out some bugs */ return 0; } wily-0.13.42/tools/old/wilytoys/reader2/Makefile000064402366570000012000000020521033320152300213000ustar00ozstaff00004330000002W = /home/steve/src/9/orig/wily-0.9.8 O = /home/steve/src/9/orig/orig-0.9.8 # CC = /opt/CenterLine/bin/proof cc CFLAGS = -Xc -g -DUSE_SELECT #-DDEBUG CPPFLAGS = -I. -I$W/include -I$W LDFLAGS = -L$W/libmsg -L$W/libXg LDLIBS = -lmsg -lXg -lnsl -lsocket PATCHES = includepatches libmsgpatches wilypatches winpatches # You might not have all of the PROGs listed here - don't worry about # it - they're not ready yet, and it just means that I've forgotten to # strip them from the Makefile before shipping... PROGS = mreader nreader COBJS = getmsg.o reader.o utils.o addr.o MOBJS = mail.o membuf.o mbox.o solaris.o NOBJS = news.o nntp.o newsrc.o post.o all: $(PROGS) mreader: $(COBJS) $(MOBJS) $(LINK.c) -o $@ $(COBJS) $(MOBJS) $(LDLIBS) nreader: $(COBJS) $(NOBJS) $(LINK.c) -o $@ $(COBJS) $(NOBJS) $(LDLIBS) clean: $(RM) *.o core nuke: $(RM) *.o core $(PROGS) cleanpatches: $(RM) $(PATCHES) patches: $(PATCHES) includepatches: makepatch include > $@ libmsgpatches: makepatch libmsg > $@ wilypatches: makepatch wily > $@ winpatches: makepatch win > $@ /home/steve/src/9/orig/orig-0.9.8 # CC = /opt/CenterLine/bin/proof cc CFLAGS = -Xc -g -DUSE_SELECT #-DDEBUG CPPFLAGS = -I. -I$W/include -I$W LDFLAGS = -L$W/libmsg -L$W/libXg LDLIBS = -lmsg -lXg -lnsl -lsocket PATCHES = includepatches libmsgpatches wilypatches winpatches # You might not have all of the PROGs listed here - don't worry about # it - they're not ready yet, and it just means that I've forgotten to # strip them from the Makefile before shipping... PROGS =wily-0.13.42/tools/old/wilytoys/reader2/headers.h000064402366570000012000000013071033320152300214260ustar00ozstaff00004330000002#ifndef RD_HEADERS_H #define RD_HEADERS_H #include #include #include #include #include #include #include #include #include #ifdef __STDC__ char *strdup(char *); #endif #include #include #include #include #include "reader.h" #include "proto.h" #ifdef DEBUG #define DPRINT(X) (void)fprintf(stderr,"%s:%d:%s\n",__FILE__,__LINE__,X) #else #define DPRINT(X) #endif #define MAXFROMLINE 512 #define MAXDATE 24 #define MAXEMAIL 40 #define MAXFULLNAME 40 #define MAXSUBJECT 40 #define FROMEMAIL 0 #define FROMNAME 1 #define WHICHFROM FROMNAME #endif /* RD_HEADERS_H */ wily-0.13.42/tools/old/wilytoys/reader2/README000064402366570000012000000206771033320152300205350ustar00ozstaff00004330000002The mail and news reader software is for wily 0.98. I haven't got around to converting them to use the 1.0 beta, because I *use* them, and Gary thinks the beta isn't ready for daily use yet. MAIL READER USAGE Invoke with "mreader mailboxname". The "-ma" option of the previous version is still there, but it doesn't do anything. This is explained below. First window to appear is the list window. It shows all the articles from the given mailfile, one per line. The line contains the From and Subject fields, but it might be chopped to make things look nicer. You open an article by B3'ing on its subject line. What else? Commands supported: exit exit without doing anything to the mailfile. quit save any changes to the mailfile before quitting. delete delete the selected article. "selected" means the article which has dot in its subject line. This means you can click on the subject line with either B1 or B3, and then click on delete. If you sweep more than one subject line, then all the affected articles are deleted. Of course, if you click on delete within an article window, that article is the one that is deleted. Delete doesn't actually do anything except mark the article for deletion, and puts a "D" before at the start of the subject line. undelete reverses delete. comp compose a new message. You get a blank article window with From, To and Subject fields. Don't delete them. reply Reply to the article (I recommend that you only use this from within a particular article). The To field is filled in from the From field. You can use "inc" or "incall" to include the text of the article you're replying to. abort junk a comp/reply article without sending it. deliver post a complete comp/reply article (well, feed it to your mail agent). next Display the next message in the current window. prev Display the previous message in the current window. savefile sets the name of the file that "save" writes to. save appends the current message into the savefile. Creates the file if it doesn't exist. You can also sweep several articles in the list window, then click on save (in the list window), and it'll save all of them. allheaders toggles whether all header fields are displayed. By default, a particular set are suppressed (the set is in the array hidden_hdrs[] in mail.c). inc [n] Includes a message body into the current position of the current message. If you specify a message number, it'll include that message. incall Same as inc, but will include the headers of the message, too. commit Write changes back to the mailbox, but don't actually quit. rescan Load any new mail that has arrived. Doesn't write any changes done so far, though. Window Control The "multiart" mode in the last version didn't really work too well. I've adopted a compromise that fits with the way I read mail, and which may not work for you. Here's what happens: - When you B3 on an article's entry in the list, a window is opened for the article, unless there's already a window open and displaying that article, in which case you warp to it. - next and prev operate only in article windows, and replace the current window's contents with the next/previous message - composition articles (comp, reply) are always created from scratch, and exist until you explicitly close them with one of deliver, abort, quit, exit or Del. Configuration headers.h contains a few defines that you can twiddle - the maximum length of the sender and subject details can be set here, and you can also define whether the list shows the sender's email address or full name. The parsing of From lines is fairly broken, but it'll do for now. mail.c contains the hidden_hdrs[] array, which you can alter if you don't like the default set of displayed headers. mail.h defines MTU, which is your mail transfer utility. This has to be capable of accepting a fully-formed message on stdin, without needing to be told destination addresses on the command line. It also defines the directory where your mail files are, and the number of seconds it waits before rescanning the mailbox for changes. You can also set the name of the environmental variable you use to specify the default file to save messages to. Bugs Probably vast numbers of them... Ones I know about are.: Unlike most wily windows, it current has the tools *before* the window label. This is because of the broken tags problem. Right now, I'm cheating, and inserting the tools at the start of the tag, instead of the end - that seems to work... In one case, I have seen the mailer *LOSE* incoming mail. I use Faces to announce incoming mail, but a commit after the mail arrived didn't display it. I haven't been able to reproduce this, but be warned... If you have '.' in the message body, it's not escaped before the body is sent to sendmail, so that terminates the message. If you delete windows, view a deleted message, and then do a commit, the article window remains open. Since we're renaming the mailbox, instead of overwriting it, it's losing its original mode/group. Searching actions are not reflected back to wily correctly at the moment, so B3'ing within any of the reader windows won't work. Instead, select some text and B2B1 on Look. Next and Prev don't change the highlighting of the selected article in the list window. I couldn't get wily to do this without warping the cursor to the new highlighting, and that's *really* irritating, so I opted for the more comfortable, broken approach. Wily doesn't maintain the edit history when the window is owned by a client. NEWS READER USAGE Started with "nreader". This is an NNTP-only reader, I'm afraid. Those of you with local spool disks and no NNTP reader will have to hash up some scripts to browse the spool directory. It uses $NNTPSERVER to determine the server host name, and by default this is "news". I rely on the server supporting the XHDR extension. Innd does, and so does the "reference" implementation. The reader currently uses .testnewsrc, rather than .newsrc, because you might not want to blow away your news readership just because you want to try out some new software. The reader doesn't add or remove groups, or handle subscribing, etc. It just updates which articles you've read. The reader gives some feedback as it first queries the server for new article counts, and then displays a list of groups and articles. B3'ing on a group displays a list of articles, just like in the mail reader. B3'ing on an article's subject line brings up the article. Window control is mostly the same, except: - next/prev will walk off the end of one group, and onto the next. In addition to updating the article displayed in the current window, it also updates the list of articles in the group window. If you've got more than one list window open on the group, it might update the wrong one. Sorry. - catchup marks all articles in the group as read, and then moves to the next group. Closes all displayed-article windows for that group too. - There are followup and follrep commands as well as reply, and there's a post command instead of "comp". Behaviour is basically obvious, and follrep posts a followup and emails a reply at the same time. - there are markread and markunread commands, if this is important to you. - quit updates your .testnewsrc, but exit doesn't. It doesn't checkpoint the .testnewsrc at any point, right now. Configuration You can change the From display stuff, in headers.h. There isn't a list of restricted headers here, though. news.h needs your mailer defining again. FROMENV is the name of the environment variable which contains your full, real, email address. This is a bit of an abuse hole, but I can't be bothered to work out what it should be (it's a real pain getting *mine* from my surroundings...). LOADDISP is handy for feedback. If you've got an enormous amount of groups to check, this helps you stop panicking. If non-zero, then for every LOADDISP groups the server is queried about, the group's name is displayed in the main window. (note: unsubscribed groups are ignored in this count). Bugs Well, I've only just started using the newsreader, so it's bound to be bad. Really needs killfile support. Doesn't understand cross-posting concepts at all, so you read the same article twice. Sorry. I've managed to kill wily with "estart failed" at one point - probably out of fds... If you open article x, hit next a few times, and then reply, followup, etc, if you do "inc", you get article x, not the one you want to reply to. If you sweep more than one subject line, then all the affectedwily-0.13.42/tools/old/wilytoys/reader2/mailheaders.h000064402366570000012000000002151033320152300222660ustar00ozstaff00004330000002#ifndef WILYMAIL_H #define WILYMAIL_H #include "headers.h" #include "mbox.h" #include "mail.h" #include "membuf.h" #endif /* WILYMAIL_H */ wily-0.13.42/tools/old/wilytoys/reader2/Credits000064402366570000012000000002231033320152300211560ustar00ozstaff00004330000002Bjorn Helgaas change of FILENAME_MAX to MAXPATHLEN arnold@infographix.infographix.com (Arnold Robbins) Various suggestions. wily-0.13.42/tools/old/wilytoys/reader2/addr.c000064402366570000012000000056451033320152300207310ustar00ozstaff00004330000002/* * addr.c - parse email addresses into something more readable. * smk 6/3/96. */ #include "headers.h" #include static char *trimws(char *str); static void whatsleft(char *copy, char *found, char *foundend, char **rest); static int angle(char *copy, char **es, char **ee); static int paren(char *copy, char **ns, char **ne); static int quotes(char *copy, char **ns, char **ne); static int findchars(char *copy, char **s, char **e, char c1, char c2); static int at(char *copy, char **es, char **ee); /* * parseaddr(addr, len, email, name) - parses addr into an email address and a full * name, based rather vaguely on RFC822: * if <...> found * use it for email address * use what's left as name * else if () or "" found * use it for name * use what's left as email * else if @ found * use it for email address * use what's left as name * else * use everything as both email address and name. */ void parseaddr(char *addr, int len, char **email, char **name) { static char copy[MAXFROMLINE+1]; char *cp, *e, *n, *z; assert(addr && *addr && email && name); strncpy(copy, addr, len); copy[len] = 0; cp = trimws(copy); assert(*cp); if (angle(cp, &e, &z)) whatsleft(cp,e,z, &n); else if (paren(cp, &n, &z)) whatsleft(cp,n,z,&e); else if (quotes(cp, &n, &z)) whatsleft(cp,n,z,&e); else if (at(cp, &e, &z)) whatsleft(cp,e,z,&n); else e = n = copy; *email = trimws(e); *name = trimws(n); return; } static char * trimws(char *str) { char *s; assert(str); while (isspace(*str)) str++; s = str + strlen(str) - 1; while (str < s && isspace(*s)) *s-- = 0; return str; } /* * found points to the located item. foundend points to the character * after the end of the item (where we'd put the null char). * If we find any alphanumeric data between copy and found, * we assume that it's the other part of the address string. * Otherwise, we take any alphanumeric data after foundend. */ static void whatsleft(char *copy, char *found, char *foundend, char **rest) { char *s; assert(copy <= found); for (s = copy; s < found; s++) if (isalnum(*s)) { *rest = s; *(found - 1) = *foundend = 0; return; } for (s = foundend; *s; s++) if (isalnum(*s)) { *rest = s; *foundend = 0; return; } *rest = found; *foundend = 0; return; } static int angle(char *copy, char **es, char **ee) { return findchars(copy,es,ee,'<', '>'); } static int paren(char *copy, char **ns, char **ne) { return findchars(copy,ns,ne,'(', ')'); } static int quotes(char *copy, char **ns, char **ne) { return findchars(copy,ns,ne,'"', '"'); } static int findchars(char *copy, char **s, char **e, char c1, char c2) { return (*s = strchr(copy,c1)) && *++(*s) && (*e = strchr(*s,c2)); } static int at(char *copy, char **es, char **ee) { char *a; if ((a = strchr(copy,'@')) == 0) return 0; for (*es = a; copy < *es && !isspace(**es); --*es); for (*ee = a; **ee && !isspace(**ee); (*ee)++); return 1; } wily-0.13.42/tools/old/wilytoys/reader2/getmsg.c000064402366570000012000000010631033320152300212730ustar00ozstaff00004330000002/* * getmsg.c - handle message reception from wily. */ #include "headers.h" rdWin * getActiveWin(void) { rdWin *w; Msg *m; Id id; DPRINT("Waiting for next wily message"); while ((m = mq_next(wilyq, 0)) == 0) { if (rdAlarmEvent) { DPRINT("A rescan alarm occurred"); dorescan(); rdAlarmEvent = false; continue; } DPRINT("No message received from wily"); return 0; } id = msg_id(m); for (w = windows; w; w = w->next) if (id == w->id) { w->m = m; return w; } DPRINT("No window found matching message's Id"); return 0; } wily-0.13.42/tools/old/wilytoys/reader2/mail.c000064402366570000012000000467751033320152300207520ustar00ozstaff00004330000002#include "mailheaders.h" static void build_msg_list(); static char *getarttext(mMsg *m); mWin *allocMWin(int kind, int num); void freeMWin(mWin *w); mWin *findMWin(void *ptr); int artDisplayed(int n); void mDelete(rdWin *w, int first, int last, char *arg); void mUndelete(rdWin *w, int first, int last, char *arg); void mComp(rdWin *w, int first, int last, char *arg); void mExit(rdWin *w, int first, int last, char *arg); void mQuit(rdWin *w, int first, int last, char *arg); void mReply(rdWin *w, int first, int last, char *arg); void mAbort(rdWin *w, int first, int last, char *arg); void mDeliver(rdWin *w, int first, int last, char *arg); void mSavefile(rdWin *w, int first, int last, char *arg); void mSave(rdWin *w, int first, int last, char *arg); void dodeliver(rdWin *w, char *filename); void mAllheaders(rdWin *w, int first, int last, char *arg); void mIncludeall(rdWin *w, int first, int last, char *arg); void mInclude(rdWin *w, int first, int last, char *arg); void doinclude(rdWin *w, int first, int last, char *arg, int all); void mCommit(rdWin *w, int first, int last, char *arg); void mRescan(rdWin *w, int first, int last, char *arg); void mNext(rdWin *w, int first, int last, char *arg); void mPrev(rdWin *w, int first, int last, char *arg); static void chkhdr(mString *s, int *len, int max, char **rest); mMbox *mbox; static char mboxname[MAXPATHLEN]; mWin *mwindows; mWin *listwin; rdWin *rdlistwin; static char **msgs; static char *savefile; static int multiart = 0; static int show_all_headers = 0; static int whichfrom = WHICHFROM; static char *list_tools = " delete undelete comp reply quit exit commit rescan savefile "; static char *art_tools = " next prev delete reply save inc "; static char *comp_tools = " deliver abort inc incall "; static char *version = "X-Mailer: Wilymail 0.4\n"; /* * These are headers that we'd rather not see when the message gets displayed. */ static char *hidden_hdrs[] = { "Content-Length", "Content-Transfer-Encoding", "Content-Type", "In-Reply-To", "Message-Id", "Mime-Version", "Original-Sender", "Received", "Sender", "Status", "X-Lines", "X-Mailer", "X-Newsreader" }; static int nhidden_hdrs = sizeof(hidden_hdrs)/sizeof(hidden_hdrs[0]); int main(int argc, char *argv[]) { mWin *mw; int ma = 0; int mustexist = 0; int timer = RESCAN_TIME; if (readerInit()) { fprintf(stderr,"readerInit() failed\n"); exit(1); } if ((rdlistwin = readerLoading(0, (void *)0, 0, "Wilymail")) == 0) { fprintf(stderr,"No list window\n"); exit(1); } fflush(stdout); if (argc >=2 && strcmp(argv[1], "-ma")==0) { ma = 1; argc--; argv++; } multiart = ma; if (argc >= 2) { mustexist = 1; strcpy(mboxname, argv[1]); timer = 0; /* don't rescan named mboxes */ } else { char *u = getenv("USER"); if (!u || !*u) { fprintf(stderr,"Need $USER to find mailbox name\n"); exit(1); } sprintf(mboxname,"%s/%s", SPOOLDIR, u); } assert(mboxname); DPRINT("mailbox name is..."); DPRINT(mboxname); savefile = getenv(SAVEFILE_ENV); if (!savefile || !*savefile) { char s[MAXPATHLEN]; char *h; if ((h = getenv("HOME")) == 0 || !*h) savefile = sstrdup("mbox"); /* what planet are we on? */ else { sprintf(s,"%s/mbox",h); savefile = sstrdup(s); } } else savefile = sstrdup(savefile); assert(savefile); DPRINT("savefile is..."); DPRINT(savefile); set_hdr_filter(nhidden_hdrs, hidden_hdrs); if ((mbox = read_mbox((const char *)mboxname, 0, mustexist)) == 0) { DPRINT("Failed to read mailbox"); perror(mboxname); exit(1); } mw = listwin = allocMWin(mMsgList, 0); assert(mw); build_msg_list(); if (setWinUser(rdlistwin, 0, (void *)mw) || setWinTitle(rdlistwin, mboxname) || setWinTools(rdlistwin, list_tools) || setWinList(rdlistwin, msgs)) { DPRINT("Failed to initialise reader"); exit(1); } rdSetRescanTimer(timer); readerMainLoop(); DPRINT("readerMainLoop() returned"); exit(0); } mWin * allocMWin(int kind, int num) { mWin *w = salloc(sizeof(*w)); mWin **p = &mwindows; assert(kind == mMsgList || kind == mDispArt || kind == mCompArt); assert(num >= -1); w->kind = kind; w->msg = (kind == mDispArt || kind == mCompArt)? num : -1; w->mbox = mbox; w->next = 0; while (*p) p = &((*p)->next); *p = w; return w; } void freeMWin(mWin *w) { mWin **p = &mwindows; assert(w); while (*p != w) p = &((*p)->next); *p = w->next; free(w); } mWin * findMWin(void *ptr) { mWin *mw = mwindows; assert(ptr); while (mw && (mWin *)ptr != mw) mw = mw->next; return mw; } static void chkhdr(mString *s, int *len, int max, char **rest) { int l; assert(len); assert(rest); *rest = ""; /* default */ if (s == 0) { *len = 0; return; } assert(s->s0 && s->s1); l = s->s1 - s->s0; if (l > max) { l = max; *rest = "..."; } else if (l > 0) l--; /* skip newline */ *len = l; } static void parsefrom(mString *s, char **from, int *len, char **rest) { char *email, *name, *str; int max; *rest = ""; *from = ""; *len = 0; if (s == 0) return; parseaddr(s->s0, s->s1-s->s0, &email, &name); str = (whichfrom == FROMEMAIL)? email : name; max = (whichfrom == FROMEMAIL)? MAXEMAIL : MAXFULLNAME; if (str == 0) return; *from = str; if ((*len = strlen(str)) > max) { *len = max; *rest = "..."; } return; } static void build_msg_list(void) { int n; mMsg *m; ulong l; int lfrom, ldate, lsubject; char *fromstr, *rfrom, *rdate, *rsubject; mString *from; mString *date; mString *subject; int dc; assert(mbox); assert(mbox->nmsgs >= 0); if (msgs) for (n = 0; msgs[n]; n++) free(msgs[n]); msgs = (char **)srealloc(msgs, (mbox->nmsgs+1) * sizeof(char *)); for (n = 0; n < mbox->nmsgs; n++) { m = mbox->msgs[n]; assert(m); dc = m->deleted? 'D' : ' '; from = m->from; date = m->date; subject = m->subject; parsefrom(from, &fromstr, &lfrom, &rfrom); chkhdr(date, &ldate, MAXDATE, &rdate); chkhdr(subject, &lsubject, MAXSUBJECT, &rsubject); l = lfrom + ldate + lsubject + 10; msgs[n] = salloc(l); sprintf(msgs[n],"%c%d %.*s%s %.*s%s", dc, n+1, lfrom, fromstr, rfrom, lsubject, subject->s0, rsubject); } msgs[n] = 0; return; } void user_listSelection(rdWin *w, rdItemRange range) { static char title[300]; /* XXX standard silly guess */ int n = range.first; mMsg *m = mbox->msgs[n]; mString *from = m->from; mWin *mw; char *text; assert(w); /* XXX not sure if this is right */ DPRINT("User selected an article"); if (artDisplayed(n)) { DPRINT("Article is already displayed"); return; } DPRINT("Displaying article"); if (w && w->wintype == rdList) w = 0; mw = allocMWin(mDispArt,n); sprintf(title," %s/%d", mbox->name, n+1); title[50] = 0; /* XXX - to make sure it's not too long. */ text = getarttext(m); assert(text); getArtWin(n, mw, title, art_tools, text, w); } static char * getarttext(mMsg *m) { static char *text; static size_t textlen; size_t len; mString *body; assert(m); body = &m->whole; len = body->s1 - body->s0; if (len >= textlen) { textlen = len + 1; text = srealloc(text, textlen); } if (show_all_headers) { memcpy(text, body->s0, len); text[len] = 0; } else { char *p = text; int n, l; mHdr *h; for (n = 0; n < m->nhdrs; n++) { h = m->hdrs[n]; if (h->hide) continue; l = h->value.s1 - h->name.s0; memcpy(p, h->name.s0, l); p += l; } *p++ = '\n'; /* make sure there's a separating line */ body = &m->body; len = body->s1 - body->s0; memcpy(p, body->s0, len); p[len] = 0; } return text; } int artDisplayed(int n) { rdWin *w; mWin *mw; assert(n >= 0); for (mw = mwindows; mw; mw = mw->next) if (mw->kind == mDispArt && mw->msg == n) if ((w = userpWin(mw))) { rdGotoWin(w); return 1; } return 0; } static struct mCmd mcmds[] = { { "quit", MCANY, MNOARG, mQuit }, { "exit", MCANY, MNOARG, mExit }, { "reply", MCNOTCOMP, MARG, mReply }, { "delete", MCNOTCOMP, MARG, mDelete }, { "undelete", MCMSGLIST, MARG, mUndelete }, { "comp", MCMSGLIST, MNOARG, mComp }, { "abort", MCCOMPART, MARG, mAbort }, { "deliver", MCCOMPART, MARG, mDeliver }, { "savefile", MCANY, MARG, mSavefile }, { "save", MCANY, MARG, mSave }, { "allheaders", MCANY, MARG, mAllheaders}, { "inc", MCCOMPART, MARG, mInclude}, { "incall", MCCOMPART, MARG, mIncludeall}, { "commit", MCANY, MNOARG, mCommit }, { "rescan", MCANY, MNOARG, mRescan }, { "next", MCANY, MNOARG, mNext }, { "prev", MCANY, MNOARG, mPrev }, { 0, 0, 0, 0 } }; void user_cmdList(rdWin *w, char *cmd, ulong p0, ulong p1, rdItemRange r, char *arg) { int c; assert(w); assert(cmd); DPRINT("User entered a command in a list window..."); DPRINT(cmd); for (c = 0; mcmds[c].cmd; c++) if (strcmp(cmd, mcmds[c].cmd) == 0) break; if (mcmds[c].cmd == 0) { DPRINT("Command is not recognised - reflecting"); winReflectCmd(w,cmd,arg); return; } /* check that the command is valid in a list like this */ if ((mcmds[c].context & MCMSGLIST) == 0) { fprintf(stderr,"%s: only valid within the message list\n", cmd); return; } /* check we've been given an appropriate argument */ if (mcmds[c].req == MARG && r.first == -1) { fprintf(stderr,"%s: needs a message\n", cmd); return; } DPRINT("Calling chosen function..."); (*mcmds[c].fn)(w, r.first, r.last, arg); DPRINT("Function complete"); return; } void user_cmdArt(rdWin *w, char *cmd, ulong p0, ulong p1, char *arg) { int c; mWin *mw; unsigned short context; assert(w); assert(cmd); DPRINT("User entered a command in an article window..."); DPRINT(cmd); for (c = 0; mcmds[c].cmd; c++) if (strcmp(cmd, mcmds[c].cmd) == 0) break; if (mcmds[c].cmd == 0) { DPRINT("Command not recognised - reflecting"); winReflectCmd(w,cmd,arg); return; } /* check that the command is valid in this window */ if ((mw = findMWin(w->userp)) == 0) { fprintf(stderr,"%s: invalid window argument\n",cmd); return; } context = (mw->kind == mDispArt)? MCDISPART : MCCOMPART; if ((mcmds[c].context & context) == 0) { fprintf(stderr,"%s: not valid in that window\n", cmd); return; } DPRINT("Calling selected function..."); (*mcmds[c].fn)(w, mw->msg, mw->msg, arg); DPRINT("Called function complete"); return; } void mDelete(rdWin *w, int first, int last, char *arg) { mWin *mw; rdWin *ow; int n, i; rdWin *lp = userpWin(listwin); assert(w); assert(lp); assert(first >= 0 && last >= 0 && first <= last); DPRINT("Deleting articles"); for (i = first; i <= last; i++) { n = i; if ((mw = findMWin(w->userp)) == 0) { DPRINT("No mWin found for rdWin - aborting deletion"); return; } if (mw->mbox->msgs[n]->deleted) continue; mw->mbox->msgs[n]->deleted = 1; *msgs[n] = 'D'; rdChangeItem(lp, n, msgs[n]); mw->mbox->ndel++; if (mw->kind != mDispArt) /* might be the msg list */ for (mw = mwindows; mw; mw = mw->next) if (mw->kind == mDispArt && mw->msg == n) break; if (mw) { if ((ow = userpWin(mw))) { /* this msg is displayed; remove the pane */ DPRINT("Article has open window - closing"); closeWin(ow); } DPRINT("Article has allocated mWin - freeing"); freeMWin(mw); } } DPRINT("Articles deleted"); return; } void user_delWin(rdWin *w) { assert(w); DPRINT("Reader window was closed - freeing mWin"); freeMWin(findMWin(w->userp)); } void mUndelete(rdWin *w, int first, int last, char *arg) { mWin *mw; int n, i; rdWin *lp = userpWin(listwin); assert(w); assert(lp); DPRINT("Undeleting articles"); for (i = first; i <= last; i++) { n = i; if ((mw = findMWin(w->userp)) == 0) { DPRINT("nWin not found for window - aborting"); return; } if (!mw->mbox->msgs[n]->deleted) continue; mw->mbox->msgs[n]->deleted = 0; mw->mbox->ndel--; *msgs[n] = ' '; rdChangeItem(lp, n, msgs[n]); } DPRINT("Articles undeleted"); return; } void mReply(rdWin *w, int first, int last, char *arg) { int n = first; /* last ignored */ mWin *mw = allocMWin(mCompArt, n); char *title = "Reply abort deliver "; static char body[300]; /* XXX */ mString *from = mbox->msgs[n]->from; mString *subject = mbox->msgs[n]->subject; int lfrom, lsubject; char *me = getenv("USER"); char *re = "Re: "; assert(w); assert(mw); assert(from); assert(subject); DPRINT("Replying to an article"); if (!me || !*me) { DPRINT("$USER is not valid - fill in from address yourself!"); me = ""; } lfrom = (from->s1 - from->s0); /* include newline */ lsubject = (subject->s1 - subject->s0); if (lsubject > 4 && strncmp(subject->s0, re, 4)==0) re = ""; sprintf(body,"From: %s\nTo: %.*sSubject: %s%.*s%s\n", me, lfrom, from->s0, re, lsubject, subject->s0, version); if (getArtWin(n, mw, title, comp_tools, body, 0)) { DPRINT("Could not get Reply window - leaving a mess in memory"); return; /* XXX - should clear up */ } DPRINT("Reply window ready"); return; } void mAbort(rdWin *w, int first, int last, char *arg) { mWin *mw; assert(w); assert(w->userp); DPRINT("Aborting reply/comp"); if ((mw = findMWin(w->userp)) == 0) { DPRINT("Can't find associated window - aborting abort"); return; } if (mw->kind != mCompArt) { DPRINT("Abort isn't applied to a composition window - ignoring"); return; } fprintf(stderr,"Message aborted\n"); closeWin(w); freeMWin(mw); DPRINT("Abort done"); return; } void mDeliver(rdWin *w, int first, int last, char *arg) { mWin *mw; char *filename = tmpnam((char *)0); assert(w); assert(w->userp); assert(filename); DPRINT("Delivering message"); if ((mw = findMWin(w->userp)) == 0) { DPRINT("Couldn't find associated composition window - aborting"); return; } if (mw->kind != mCompArt) { DPRINT("Deliver not applied to composition window - ignored"); return; } rdBodyToFile(w, filename); dodeliver(w,filename); DPRINT("Deliver done"); return; } void mQuit(rdWin *w, int first, int last, char *arg) { DPRINT("Quitting - first flushing mbox changes"); update_mbox(mbox); mExit(w, first, last, arg); } void mExit(rdWin *w, int first, int last, char *arg) { mWin *mw; rdWin *rw; DPRINT("Exiting - closing msg windows"); /* close msg windows first */ for (mw = mwindows; mw; mw = mw->next) if (mw->kind == mCompArt || mw->kind == mDispArt) { if ((rw = userpWin(mw))) closeWin(rw); else { DPRINT("Could not find rdWin for mWin while closing"); } } DPRINT("Closing list windows"); for (mw = mwindows; mw; mw = mw->next) if (mw->kind != mCompArt && mw->kind != mDispArt) { if ((rw = userpWin(mw))) closeWin(rw); else { DPRINT("Could not find rdWin for mWin while closing"); } } DPRINT("Managed to close everything without dying..."); exit(0); /* not actually needed - reader will exit for us */ } void mComp(rdWin *w, int first, int last, char *arg) { int n = first; /* last ignored */ mWin *mw = allocMWin(mCompArt, n); char *title = "Compose abort deliver "; static char body[300]; /* XXX */ char *me = getenv("USER"); assert(mw); DPRINT("Composing new article"); if (!me || !*me) { DPRINT("$USER isn't set - fill in From: field yourself!"); me = ""; } sprintf(body,"From: %s\nTo: \nSubject: \n%s\n", me, version); if (getArtWin(n, mw, title, comp_tools, body, 0)) { DPRINT("Couldn't get new composition window"); return; /* XXX - should clear up */ } DPRINT("Composition window open"); return; } void dodeliver(rdWin *w, char *filename) { static char cmd[100]; /* XXX another guess */ mWin *mw; assert(w); assert(w->userp); assert(MTU && *MTU); assert(filename); DPRINT("Attempting to deliver an article"); if ((mw = findMWin(w->userp)) == 0) { DPRINT("Could not find mWin for this window - aborting"); return; } sprintf(cmd,"%s < %s", MTU, filename); DPRINT("Delivery command is...."); DPRINT(cmd); fflush(stdout); system(cmd); closeWin(w); freeMWin(mw); DPRINT("Seems to have delivered"); return; } void mSavefile(rdWin *w, int first, int last, char *arg) { assert(arg); if (savefile) { DPRINT("Savefile used to be...."); DPRINT(savefile); free(savefile); } savefile = sstrdup(arg); assert(savefile); DPRINT("Savefile now set to..."); DPRINT(savefile); } void mSave(rdWin *w, int first, int last, char *arg) { FILE *fp; mWin *mw; mMsg *m; mString *text; size_t len; int n; assert(w); assert(w->userp); assert(first >= 0); assert(first <= last); assert(last <= mbox->nmsgs); DPRINT("Saving articles"); if (savefile == 0) { fprintf(stderr,"No savefile yet: 'savefile filename'\n"); return; } if ((fp = fopen(savefile,"a")) == 0) { perror(savefile); DPRINT("Could not open savefile - article not saved"); return; } if ((mw = findMWin(w->userp)) == 0) { DPRINT("could not find mWin for indicated rdWin - not saved"); return; } for (n = first; n <= last; n++) { m = mw->mbox->msgs[n]; assert(m); text = &m->whole; assert(text->s1 && text->s0); len = text->s1 - text->s0; if (fwrite(text->s0, (size_t)1, len, fp) != len) { DPRINT("Failed to write the file"); perror("fwrite"); } fputc('\n',fp); printf("Written message %d to %s\n", n+1, savefile); /* count from 1 */ } fflush(stdout); fclose(fp); } void mAllheaders(rdWin *w, int first, int last, char *arg) { show_all_headers = !show_all_headers; DPRINT(show_all_headers? "All headers now on" : "All headers now off"); } void mInclude(rdWin *w, int first, int last, char *arg) { doinclude(w,first,last,arg,0); } void mIncludeall(rdWin *w, int first, int last, char *arg) { doinclude(w,first,last,arg,1); } void doinclude(rdWin *w, int first, int last, char *arg, int all) { mWin *mw; rdWin *ow; int msgnum; /* message we're going to include */ mMsg *m; mString *s; size_t len; int n; assert(w); assert(w->userp); assert(arg); DPRINT("Including article text"); if ((mw = findMWin(w->userp)) == 0) { DPRINT("Could not find mWin for rdWin - aborting"); return; } if (mw->kind != mCompArt) { DPRINT("Not a composition window - include ignored"); return; } msgnum = mw->msg; /* default value */ if (*arg) { if ((msgnum = atoi(arg)) < 1) { fprintf(stderr,"'%s' is an invalid message number\n", arg); return; } else { msgnum--; } } if (msgnum < 0 || msgnum >= mw->mbox->nmsgs) { fprintf(stderr,"Invalid msg number (1-%d)\n", mw->mbox->nmsgs); return; } m = mw->mbox->msgs[msgnum]; assert(m); s = all? &(m->whole) : &(m->body); assert(s && s->s0 && s->s1); len = s->s1 - s->s0; rdInclude(w, s->s0, len); DPRINT("Done include"); } void mCommit(rdWin *w, int first, int last, char *arg) { DPRINT("Doing commit - flushing any mailbox changes"); update_mbox(mbox); DPRINT("Commit - rebuilding message list"); build_msg_list(); DPRINT("Commit - redrawing message list"); setWinList(userpWin(listwin), msgs); DPRINT("Commit complete"); } void dorescan(void) { mRescan((rdWin *)0, 0, 0, (char *)0); } void mRescan(rdWin *w, int first, int last, char *arg) { rdWin *lp = userpWin(listwin); int n = mbox->nmsgs; assert(lp); DPRINT("Rescanning mailbox"); extend_mbox(mbox); if (n >= mbox->nmsgs) { DPRINT("No new messages (might be less, though...)"); return; } DPRINT("Rebuilding msg list"); build_msg_list(); DPRINT("Adding new messages to screen"); while (n < mbox->nmsgs) rdAddItem(lp, msgs[n++]); DPRINT("Rescan complete"); } static int nextArt(rdWin *w, int *num, int next, int first) { mWin *mw; int max = mbox->nmsgs-1; int n; assert(w); assert(w->userp); assert(num); mw = findMWin(w->userp); assert(mw); n = (mw->kind == mDispArt)? mw->msg : first; *num = n + (next? 1 : -1); return !((next && n < max) || (!next && n > 0)); } void mNext(rdWin *w, int first, int last, char *arg) { rdItemRange r; if (nextArt(w, &r.first, 1, first)) return; r.i0 = r.i1 = 0; user_listSelection(w, r); } void mPrev(rdWin *w, int first, int last, char *arg) { rdItemRange r; if (nextArt(w, &r.first, 0, first)) return; r.i0 = r.i1 = 0; user_listSelection(w, r); } argwily-0.13.42/tools/old/wilytoys/reader2/mail.h000064402366570000012000000033171033320152300207400ustar00ozstaff00004330000002/* * stuff needed for the mail client. * smk */ #ifndef MAIL_H #define MAIL_H #include "headers.h" #include "mbox.h" typedef struct _mWin mWin; /* * We know of several different kinds of window: mailbox lists, * message lists, displayed articles and messages being composed. */ enum { mMboxList, /* list of mailboxes */ mMsgList, /* list of msgs in a mailbox */ mDispArt, /* a displayed article within a mailbox */ mCompArt /* a new article being composed */ }; struct _mWin { int kind; /* what kind of window it is */ int msg; /* message number, if mDispArt, or mCompArt */ mMbox *mbox; /* the message box we're associated with */ struct _mWin *next; }; /* * These are the commands that the mailer recognises, and the * contexts that they are valid. */ #define MCMSGLIST 01 #define MCDISPART 02 #define MCCOMPART 04 #define MCNOTCOMP (MCMSGLIST|MCDISPART) #define MCANY (MCMSGLIST|MCDISPART|MCCOMPART) #define MNOARG 00 #define MARG 01 struct mCmd { char *cmd; unsigned short context; unsigned short req; void (*fn)(rdWin *, int, int, char *); /* pane, first msg, last msg, arg */ }; /* * The following must be the pathname of a program capable * of taking a complete message on stdin, with no arguments, * and delivering it. */ #define MTU "/usr/lib/sendmail -t" /* * Where do you keep your mail? Don't currently support anything other * than directly-accessible mail files.... */ #define SPOOLDIR "/var/mail" /* * How long we wait before rescanning. */ #define RESCAN_TIME 60 /* * Environment variable and default filename for savefile's * default parameter. */ #define SAVEFILE_ENV "SAVEFILE" #define SAVEFILE_DEF "mbox" /* in $HOME, if possible */ #endif /* ! MAIL_H */ box lists, * message lists, displayed articles and messages being composed. */ enum { mMboxList, /* list of mailboxes */ mMsgList, /* list of msgs in a mailbox */ mDispArt, /* a displayed article within a mailbox */ mCompArt /* a new article being composed */ }; struct _mWin { int kind;wily-0.13.42/tools/old/wilytoys/reader2/mbox.c000064402366570000012000000247741033320152300207700ustar00ozstaff00004330000002/* * mbox.c */ #include "mailheaders.h" #include #include #define COPYSIZE 8192 #define INCR 10 static mMbox *currmbox; /* current mbox being processed */ static mMsg *msg; /* current message */ static int nhdrs; /* number of current headers read so far. */ static int ahdrs; /* number of allocated hhdrs */ static mHdr **hdrs; /* current list */ static char **hiddenhdrs; /* names of header fields we don't want to see */ static int nhiddenhdrs; extern int load_mbox(mMbox *, int); static char *readhdrs(char *ptr); static void mkhdr(char *s0, char *s1); static void checkhide(mHdr *h); static int freehdrlist(int n, char **h); static void newmsg(char *s0); static char *readmsg(char *ptr); static int same(mString a, mString b); static int strsame(char *s, mString b); static void fillmsg(mMsg *msg); static void fillhdr(char *name, mMsg *msg, mString **ptr); static ulong getlength(void); static char *findend(char *ptr); static void freemsg(mMbox *mbox, int n); /* * readhdrs(ptr) - read the headers in a message, looking for * the terminating newline. Returns pointer to first char in body. */ static char * readhdrs(char *ptr) { char *nptr = ptr; assert(nptr); /* invariant is that nptr pts to first char of next header. when it doesn't (nptr==\n), we've reached the blank line at then end of the hdrs */ while (*nptr != '\n') { if ((nptr = strchr(nptr,'\n')) == 0) panic("No newlines in readhrds()"); if (nptr[1]==' ' || nptr[1]=='\t') { /* multi-line hdr */ nptr++; continue; } else { mkhdr(ptr, ++nptr); ptr = nptr; continue; } } assert(*nptr == '\n'); assert(nptr[1]); return ++nptr; /* skip blank line */ } /* * mkhdr(s0,s1) - add a new header to the current list. */ static void mkhdr(char *s0, char *s1) { size_t l; char *c = strchr(s0, ':'); mHdr *h; assert(s0); assert(s1); assert(c); if (c == 0) panic("no colon in hdr"); if (nhdrs >= ahdrs) { ahdrs += INCR; l = ahdrs * sizeof(*hdrs); hdrs = (mHdr **)(hdrs? realloc(hdrs,l) : malloc(l)); if (hdrs == 0) panic("resizing hdr list"); } h = hdrs[nhdrs++] = (mHdr *)malloc(sizeof(*h)); if (h == 0) panic("adding new hdr"); h->name.s0 = s0; h->name.s1 = c++; while (*c == ' ' || *c == '\t') c++; h->value.s0 = c; h->value.s1 = s1; checkhide(h); } static void checkhide(mHdr *h) { int n; int l; assert(h); assert(h->name.s0 && h->name.s1); l = h->name.s1 - h->name.s0; for (n = 0; n < nhiddenhdrs; n++) if (strncmp(hiddenhdrs[n], h->name.s0, l) == 0) { h->hide = 1; return; } h->hide = 0; /* default to showing header */ } int set_hdr_filter(int nhdrs, char **hdrs) { int n; assert(nhdrs >= 0); assert(hdrs); (void)freehdrlist(nhiddenhdrs, hiddenhdrs); /* clear out existing list */ if ((hiddenhdrs = (char **)realloc((void *)hiddenhdrs, (nhdrs+1)*sizeof(char *))) == 0) { DPRINT("Failed to allocate new hidden hdr list"); return 1; } for (n = 0; n < nhdrs; n++) { assert(hdrs[n]); if ((hiddenhdrs[n] = strdup(hdrs[n])) == 0) { DPRINT("Failed to copy hidden hdr item"); return freehdrlist(n, hiddenhdrs); } } hiddenhdrs[n] = 0; nhiddenhdrs = n; return 0; } static int freehdrlist(int n, char **h) { while (n--) free (*h++); return 1; } static void newmsg(char *s0) { size_t n; assert(s0); DPRINT("Adding new message"); if (currmbox->nmsgs >= currmbox->amsgs) { currmbox->amsgs += INCR; n = currmbox->amsgs*sizeof(*currmbox->msgs); currmbox->msgs = (mMsg **)(currmbox->msgs? realloc(currmbox->msgs,n) : malloc(n)); if (currmbox->msgs == 0) panic("newmsg msg"); } msg = currmbox->msgs[currmbox->nmsgs++] = (mMsg *)malloc(sizeof(*msg)); if (msg == 0) panic("adding new msg"); memset(msg,0,sizeof(*msg)); msg->whole.s0 = s0; if ((hdrs = (mHdr **)malloc((ahdrs = INCR)*sizeof(*hdrs)))==0) panic("newmsg hdrs"); nhdrs = 0; } /* * readmsg(ptr) - read a complete message. Assumes we're already pointing * to the F of the "From " */ static char * readmsg(char *ptr) { char *nptr; ulong contentlength; assert(ptr); assert(strncmp(ptr,"From ",5) == 0); newmsg(ptr); /* resets nhdrs and hdrs, too */ if ((nptr = strchr(ptr,'\n')) == 0) /* skip From line */ panic("From line broken"); nptr = readhdrs(nptr+1); assert(nptr); assert(hdrs); msg->nhdrs = nhdrs; msg->hdrs = hdrs; msg->body.s0 = nptr; if ((contentlength = getlength()) == 0) nptr = findend(nptr); else nptr += contentlength; assert(nptr); msg->whole.s1 = msg->body.s1 = nptr; fillmsg(msg); /* update from,date,subject fields */ mb_split(ptr, ++nptr); return nptr; } static int same(mString a, mString b) { assert(a.s0 && a.s1 && b.s0 && b.s1); if ((a.s1 - a.s0) != (b.s1 - b.s0)) return 0; return (strncmp(a.s0,b.s0,a.s1-a.s0) == 0); } static int strsame(char *s, mString b) { mString a; assert(s && b.s0 && b.s1); a.s0 = s; a.s1 = s + strlen(s); return same(a,b); } static void fillmsg(mMsg *msg) { assert(msg); fillhdr("From",msg,&msg->from); fillhdr("Date",msg,&msg->date); fillhdr("Subject",msg,&msg->subject); } static void fillhdr(char *name, mMsg *msg, mString **ptr) { int x; static mString empty; assert(name); assert(msg); assert(ptr); for (x = 0; x < msg->nhdrs; x++) if (strsame(name,msg->hdrs[x]->name)) { *ptr = &(msg->hdrs[x]->value); assert((*ptr)->s0 && (*ptr)->s1); return; } /* Sigh. This sort of thing is very irritating. */ empty.s0 = empty.s1 = msg->whole.s1; *ptr = ∅ /* (void)fprintf(stderr,"Message does not have a '%s' header\n",name); */ } static ulong getlength(void) { int x; ulong l; for (x = 0; x < nhdrs; x++) if (strsame("Content-Length",hdrs[x]->name)) goto found; return 0; found: /* use sscanf magic to skip whitespace, and stop at end */ if (sscanf(hdrs[x]->value.s0,"%lu",&l) != 1 || l==0) return 0; if ((msg->body.s0+l+1) == currmbox->mbox_end) return l; /* spot on */ if ((msg->body.s0+l+5) >= currmbox->mbox_end) { DPRINT("WARNING: Content-Length: field points to past end of box"); return 0; /* too long */ } if (strncmp("\nFrom ",(msg->body.s0+l),6) == 0) return l; else { DPRINT("WARNING: Content-Length field doesn't find start of next msg"); return 0; } } static char * findend(char *ptr) { assert(ptr); for (; ptr+5 <= currmbox->mbox_end && strncmp("\nFrom ",ptr,6); ptr++) if ((ptr = strchr(ptr,'\n')) == 0) panic("findend"); if (ptr+5 > currmbox->mbox_end) return currmbox->mbox_end-1; else return ptr; } mMbox * read_mbox(const char *filename, int readonly, int mustexist) { char *ptr; extern int empty_mbox(mMbox *box, const char *filename, int mustexist); assert(filename); DPRINT("Reading file called..."); DPRINT(filename); DPRINT(readonly? "(readonly mode)" : "(writable)"); DPRINT(mustexist? "(must exist)" : "(normal mbox)"); if ((currmbox = (mMbox *)malloc(sizeof(*currmbox))) == 0) { DPRINT("Could not allocate mbox structure"); return 0; } memset(currmbox,0,sizeof(*currmbox)); currmbox->readonly = readonly; if ((currmbox->name = strdup((char *)filename)) == 0) { DPRINT("Could not copy filename"); goto panic2; } if (load_mbox(currmbox, 0) && empty_mbox(currmbox, filename, mustexist)) { DPRINT("mbox failed to load"); goto panic1; } for (ptr = currmbox->mbox_start; ptr < currmbox->mbox_end; ) if ((ptr = readmsg(ptr)) == 0) { DPRINT("Failed to read a message - aborting mbox read"); goto panic1; } DPRINT("mbox read successfully"); return currmbox; panic1: free(currmbox->name); panic2: free(currmbox); return 0; } int extend_mbox(mMbox *mbox) { char *ptr; assert(mbox); DPRINT("Extending mbox"); if (load_mbox(mbox,1)) { DPRINT("Failed to read mbox"); return 1; } for (ptr = mbox->mbox_start; ptr < mbox->mbox_end; ) if ((ptr = readmsg(ptr)) == 0) { DPRINT("Failed to read message"); return 1; } DPRINT("mbox extended ok"); return 0; } /* * update_mbox(mbox) - write any changes back to the file. */ int update_mbox(mMbox *mbox) { static char lockname[MAXPATHLEN+1], newname[MAXPATHLEN+1]; int ntries, maxtries = 10; int fd, fd2; int x; struct stat st; int r = 0; int l; mMsg *m; assert(mbox); assert(mbox->name); assert(strlen(mbox->name)+5 < MAXPATHLEN); DPRINT("Updating mbox"); if (mbox->readonly || mbox->ndel == 0) { DPRINT(mbox->readonly? "mbox is readonly - not written" : "No changes"); return 0; } (void)sprintf(lockname,"%s.lock",mbox->name); (void)sprintf(newname,"%s.new",mbox->name); for (ntries = 0; ntries < maxtries; ntries++) { if (link(mbox->name,lockname) == 0) goto locked; DPRINT("Could not get lock - sleeping"); sleep(1); } (void)fprintf(stderr,"Could not get lockfile %s - skipping update\n", lockname); return 1; locked: DPRINT("Mailbox now locked"); if (stat(mbox->name,&st) == -1) { DPRINT("mailbox has vanished"); goto broken; } if (st.st_size < mbox->size) { fprintf(stderr,"Mail file corrupted - no changes made\n"); goto broken; } if ((fd = open(newname,O_RDWR|O_CREAT|O_TRUNC,st.st_mode)) < 0) { DPRINT("Could not open or fchmod new file..."); DPRINT(newname); goto broken; } DPRINT("Writing messages to new file"); for (x = 0; x < mbox->nmsgs; x++) { m = mbox->msgs[x]; if (m->deleted) continue; l = m->whole.s1 - m->whole.s0 + 1; if (write(fd,m->whole.s0,l) != l || write(fd,"\n",1) != 1) { fprintf(stderr,"write truncated, changes aborted\n"); goto broken; } } DPRINT("Messages written"); if (st.st_size > mbox->size) { static char buf[COPYSIZE]; DPRINT("mbox has grown since last read - copying new msgs"); if ((fd2 = open(mbox->name,O_RDONLY)) < 0 || lseek(fd2,mbox->size,SEEK_SET) == -1) { fprintf(stderr,"Can't open mbox for update!\n"); goto broken; } while ((l = read(fd2,buf,COPYSIZE)) > 0) if (write(fd,buf,l) != l) { fprintf(stderr,"Can't copy updated mbox\n"); close(fd2); goto broken; } close(fd2); DPRINT("New msgs copied"); } DPRINT("Replacing old mbox with new mbox"); assert(rename(newname,mbox->name) == 0); assert(stat(mbox->name, &st) == 0); mbox->mtime = st.st_mtime; mbox->size = st.st_size; goto unlock; broken: r = 1; if (fd >= 0) close(fd); unlink(newname); unlock: DPRINT("Unlocking mbox"); unlink(lockname); /* now update the list of messages in the mbox */ for (l = x = 0; x < mbox->nmsgs; x++) { m = mbox->msgs[x]; if (m->deleted) freemsg(mbox,x); else mbox->msgs[l++] = m; } mbox->nmsgs = l; mbox->ndel = 0; DPRINT("Update complete"); return r; } static void freemsg(mMbox *mbox, int n) { mMsg *m = mbox->msgs[n]; int h; mbox->msgs[n] = 0; for (h = 0; h < m->nhdrs; h++) free(m->hdrs[h]); free(m->hdrs); mb_free(m->whole.s0); free(m); } cowily-0.13.42/tools/old/wilytoys/reader2/mbox.h000064402366570000012000000034601033320152300207620ustar00ozstaff00004330000002/* * mbox.h - definitions for mailbox-handling library. */ #ifndef MBOX_H #define MBOX_H #include typedef struct mstring mString; typedef struct mhdr mHdr; typedef struct mmsg mMsg; typedef struct mhdrline mHdrLine; typedef struct mmbox mMbox; struct mstring { /* can include several \n characters */ char *s0; /* first char in string */ char *s1; /* char after last newline */ }; struct mhdr { /* includes ws if hdr is multiple lines */ mString name; /* s1 points to colon */ mString value; /* s0 pts to first non-ws, s1 to after \n */ int hide; /* don't display if true */ }; /* name,s0,value.s2 gives whole header */ struct mmsg { int nhdrs; /* number of headers */ mHdr **hdrs; /* headers themselves */ mString *from; /* points to value fields from mHdrs */ mString *date; mString *subject; mString whole; /* All of the message (headers and body) */ mString body; /* All of the body (not including first blank line) */ int deleted; /* marked for deletion */ int read; /* if has been read */ ulong pos; /* origin in window, if it's been read before. */ }; struct mhdrline { char *s0,*s1; /* buffer containing accumulated text */ ulong p0, p1; /* positions in hdrw for this piece of text */ }; struct mmbox { char *mbox_start; /* area of memory that the mailbox is */ char *mbox_end; /* loaded into */ int nmsgs; /* number of messages */ int amsgs; /* size of msgs array */ mMsg **msgs; /* the messages themselves */ int ndel; /* number of deleted messages */ int readonly; time_t mtime; /* time it was last modified */ off_t size; /* how big it was, last time we checked */ char *name; /* the filename */ }; mMbox *read_mbox(const char *filename, int readonly, int mustexist); int extend_mbox(mMbox *mbox); int set_hdr_filter(int nhdrs, char **hdrs); #endif /* ! MBOX_H */ wily-0.13.42/tools/old/wilytoys/reader2/news.c000064402366570000012000000410411033320152300207610ustar00ozstaff00004330000002/* * Simplistic driver for an NNTP news client for wily. */ #include "newsheaders.h" #define MAXFROMLEN MAXEMAIL #define MAXSUBJLEN MAXSUBJECT static int getGroupInfo(void); static void countUnread(nGroup *g); static int getGroupListItems(void); static int groupItems(nGroup *g); static void freeGroupItems(nGroup *g); static int getLen(char *str, unsigned int max); static void selectGroup(nWin *nw, rdWin *rdw, int item); static void selectArticle(nWin *nw, rdWin *rdw, int item); static void markread(nArticle *a, int read); static void nQuit(rdWin *w, nGroup *g, int first, int last, char *arg); static void nExit(rdWin *w, nGroup *g, int first, int last, char *arg); static void nNext(rdWin *w, nGroup *g, int first, int last, char *arg); static void nPrev(rdWin *w, nGroup *g, int first, int last, char *arg); static void nArtMarkRead(rdWin *w, nGroup *g, int first, int last, char *arg); static void nArtMarkUnread(rdWin *w, nGroup *g, int first, int last, char *arg); static void nCatchup(rdWin *w, nGroup *g, int first, int last, char *arg); static void markartsread(nGroup *g, int first, int last, int read); static int nextGroup(rdWin *w, int next, int *num); static nGroup *itemToGroup(int item); static void displayGroupList(nGroup *g, nWin *newnw, rdWin *newrdw); static void displayArticle(rdWin *w, nGroup *g, int i); static char **grouplistitems; static nGroup **grpptrs; static nGroup *groups; static int ngroups; static nWin *listwin; static rdWin *rdlistwin; static nWin *nwindows; static int whichfrom = WHICHFROM; static char *grouplist_tools = " next quit post exit "; static char *artlist_tools = " next prev catchup post "; static char *artdisp_tools = " next prev followup reply follrep save "; static struct nCmd ncmds[] = { { "quit", NCANY, NNOARG, nQuit }, { "exit", NCANY, NNOARG, nExit }, { "next", NCDISPART, NNOARG, nNext }, { "prev", NCDISPART, NNOARG, nPrev }, { "markread", NCMSGLIST, NNOARG, nArtMarkRead }, { "markunread", NCMSGLIST, NNOARG, nArtMarkUnread }, { "catchup", NCMSGLIST, NNOARG, nCatchup }, { "reply", NCDISPART, NNOARG, nReply }, { "post", NCANY, NNOARG, nPost }, { "followup", NCDISPART, NNOARG, nFollowUp }, { "follrep", NCDISPART, NNOARG, nFollRep }, { "savefile", NCANY, NARG, nSavefile }, { "save", NCDISPART, NNOARG, nSave }, { "deliver", NCCOMPART, NNOARG, nDeliver }, { "abort", NCCOMPART, NNOARG, nAbort }, { "inc", NCCOMPART, NNOARG, nInclude }, { "incall", NCCOMPART, NNOARG, nIncludeall }, { 0, 0, 0, 0 }, }; int main(int argc, char *argv[]) { nWin *nw; if (readerInit() || (rdlistwin = readerLoading(0,(void *)0, 0, "News")) == 0) { fprintf(stderr,"Could not initialise reader\n"); exit(1); } if ((groups = read_newsrc()) == 0) { fprintf(stderr,"Couldn't read .newsrc\n"); return 1; } unlock_newsrc(); if (nntpConnect()) { fprintf(stderr,"Could not connect to news server\n"); return 1; } if (getGroupInfo()) { fprintf(stderr,"Could not get group information\n"); return 1; } if (getGroupListItems()) return 1; DPRINT("Initialising news reader"); nw = listwin = allocNWin(nGroupList,0,0); if (setWinUser(rdlistwin, 0, (void *)nw) || setWinTitle(rdlistwin, "News") || setWinTools(rdlistwin, grouplist_tools) || setWinList(rdlistwin, grouplistitems)) { DPRINT("Could not start up main list window"); exit(1); } DPRINT("Entering main loop"); readerMainLoop(); DPRINT("Main loop exited!"); nntpQuit(); return 0; } /* * Find out how many articles there are in each group that we haven't read. */ static int getGroupInfo(void) { nGroup *g; int x = 0; (void)rdAddItem(rdlistwin, "Scanning..."); for (g = groups; g; g = g->next) { if (!g->issub || nntpSetGroup(g) || g->last==0 || (g->last < g->first)) g->first = g->last = g->nunread = 0; else countUnread(g); if (LOADDISP && g->issub && x-- == 0) { (void)rdChangeItem(rdlistwin, 0, g->name); x = LOADDISP; } } fputc('\n',stderr); return 0; } static void countUnread(nGroup *g) { int f, l, p0 = 0, p1 = 0, p2 = 0; nRange *r; assert(g); f = g->first; l = g->last; for (r = g->read; r; r = r->next) if (f <= r->n0 && r->n1 <= l) p1 += r->n1 - r->n0 + 1; else if (r->n0 <= f && f <= r->n1) p0 = r->n1 - f + 1; else if (r->n0 <= l && l <= r->n1) p2 = l - r->n0 + 1; g->nunread = (l - f + 1) - (p0 + p1 + p2); if (g->nunread < 0) g->nunread = 0; } /* * create the list of strings that we display in a group's subject list window. */ static int groupItems(nGroup *g) { int n, i; nArticle *a; assert(g); if (g->items) { freeGroupItems(g); g->items = 0; } if ((n = g->nunread) == 0) return 0; g->items = salloc((n+1) * sizeof(g->items[0])); g->artptrs = salloc((n+1) * sizeof(g->artptrs[0])); for (a = g->arts, i = 0; a && i < n; a = a->next) { int l, froml, subjl; char *from, *email, *name; if (a->read) continue; g->artptrs[i] = a; parseaddr(a->from, strlen(a->from), &email, &name); from = (whichfrom == FROMEMAIL)? email : name; froml = getLen(from, MAXFROMLEN); subjl = getLen(a->subj, MAXSUBJLEN); l = 10 + froml + subjl; g->items[i] = salloc(l); sprintf(g->items[i],"%c%-5d %.*s %.*s", a->read? 'R' : ' ', a->num, froml, from, subjl, a->subj); i++; } g->items[i] = 0; g->artptrs[i] = 0; return 0; } /* * Convert between item numbers in an artlist and article numbers. */ static int itemToArtnum(nGroup *g, int item) { assert(g && g->artptrs && g->artptrs[item]); return g->artptrs[item]->num; } int artnumToItem(nGroup *g, int artnum) { int item; assert(g && g->artptrs); for (item = 0; g->artptrs[item]; item++) if (g->artptrs[item]->num == artnum) return item; return -1; } /* * Get the listing of all groups */ static int getGroupListItems(void) { nGroup *g; int n; for (ngroups = 0, g = groups; g; g = g->next) if (g->nunread) ngroups++; n = ngroups + 1; grouplistitems = salloc(n * sizeof(*grouplistitems)); grpptrs = salloc(n * sizeof(*grpptrs)); for (n = 0, g = groups; g; g = g->next) { if (g->nunread == 0) continue; grouplistitems[n] = salloc(strlen(g->name) + 30); sprintf(grouplistitems[n],"%s %d articles", g->name, g->nunread); grpptrs[n] = g; n++; } grouplistitems[n] = 0; grpptrs[n] = 0; return 0; } static void freeGroupItems(nGroup *g) { int i; assert(g); if (g->items == 0) for (i = 0; g->items[i]; i++) free(g->items[i]); free(g->items); free(g->artptrs); g->items = 0; g->artptrs = 0; } static int getLen(char *str, unsigned int max) { int l; assert(str); l = strlen(str); return l < max? l : max; } void dorescan(void) { return; } void user_cmdArt(rdWin *w, char *cmd, ulong p0, ulong p1, char *arg) { int c; nWin *nw; unsigned short context; fflush(stdout); assert(w); assert(cmd); assert(arg); for (c = 0; ncmds[c].cmd; c++) if (strcmp(cmd, ncmds[c].cmd) == 0) break; if (ncmds[c].cmd == 0) { fflush(stdout); winReflectCmd(w,cmd,arg); return; } /* check that the command is valid in this window */ if ((nw = findNWin(w->userp)) == 0) { fprintf(stderr,"%s: invalid window argument\n",cmd); return; } switch (nw->kind) { case nGroupList: context = NCGRPLIST; break; case nArtList: context = NCMSGLIST; break; default: case nDispArt: context = NCDISPART; break; case nCompArt: context = NCCOMPART; break; } if ((ncmds[c].context & context) == 0) { fprintf(stderr,"%s: not valid in that window\n", cmd); return; } DPRINT("executing command..."); DPRINT(cmd); (*ncmds[c].fn)(w, nw->group, nw->artnum, nw->artnum, arg); DPRINT("Command complete"); return; } void user_cmdList(rdWin *w, char *cmd, ulong p0, ulong p1, rdItemRange r, char *arg) { int c; unsigned short context; nWin *nw; assert(w); assert(cmd); assert(arg); nw = findNWin(w->userp); fflush(stdout); for (c = 0; ncmds[c].cmd; c++) if (strcmp(cmd, ncmds[c].cmd) == 0) break; if (ncmds[c].cmd == 0) { fflush(stdout); winReflectCmd(w,cmd,arg); return; } /* check that the command is valid in a list like this */ context = (nw->kind == nGroupList)? NCGRPLIST : NCMSGLIST; if ((ncmds[c].context & context) == 0) { fprintf(stderr,"%s: only valid within list windows\n", cmd); return; } /* check we've been given an appropriate argument */ if (ncmds[c].req == NARG && r.first == -1) { fprintf(stderr,"%s: needs a message\n", cmd); return; } DPRINT("Calling command..."); DPRINT(cmd); (*ncmds[c].fn)(w, nw->group, r.first, r.last, arg); DPRINT("Command complete"); return; } void user_listSelection(rdWin *w, rdItemRange r) { nWin *nw; int item = r.first; assert(w); assert(nw = findNWin(w->userp)); switch (nw->kind) { case nGroupList: selectGroup(nw, w, item); break; case nArtList: selectArticle(nw, w, item); break; default: /* Shouldn't reach here */ assert(false); } return; } void user_delWin(rdWin *w) { nWin *nw; nArticle *a; assert(w); nw = findNWin(w->userp); assert(nw); /* * XXX We *dont't* free the group and article information. Instead, * we burn memory, assuming that swap space is cheaper than * downloading the info each time. I'm probably going to hell * for this. * * switch (nw->kind) { * case nArtList: * freeGroupItems(nw->group); * break; * case nDispArt: * for (a = nw->group->arts; a; a = a->next) * if (a->num == nw->artnum) { * free(a->body); * a->body = 0; * a->bodylen = 0; * break; * } * break; * } */ freeNWin(nw); } /* * canWarp(isart, g, artnum, nw, rdw) - search for an open rdWin that * contains displayed article g/artnum (is isart) or artlist of group g. * If we find one, return true, and set nw/rdw. Otherwise, return false. */ static int canWarp(int isart, nGroup *g, int artnum, nWin **nw, rdWin **rdw) { nWin *nwin; rdWin *rdwin; for (nwin = nwindows; nwin; nwin = nwin->next) if ((nwin->kind == nArtList || nwin->kind == nDispArt) && nwin->group == g && (isart == 0 || nwin->artnum == artnum)) if ((rdwin = userpWin(nwin))) { *nw = nwin; *rdw = rdwin; return 1; } *nw = 0; *rdw = 0; return 0; } static nGroup * itemToGroup(int item) { assert(item >= 0 && item <= ngroups); assert(grpptrs && grpptrs[item]); return grpptrs[item]; } static void selectGroup(nWin *nw, rdWin *rdw, int item) { nGroup *g; nWin *newnw; rdWin *newrdw; assert(g = itemToGroup(item)); if (canWarp(0, g, 0, &newnw, &newrdw)) { warpToWin(newrdw); return; } displayGroupList(g,newnw, newrdw); return; } static void displayGroupList(nGroup *g, nWin *newnw, rdWin *newrdw) { if (newnw == 0) assert(newnw = allocNWin(nArtList, g, 0)); if (newrdw == 0) assert(newrdw = getBlankListWin(0,(void *)newnw)); newnw->group = g; setWinTitle(newrdw, g->name); setWinTools(newrdw, artlist_tools); if (g->items == 0) { if (nntpGroupHdrs(g)) { DPRINT("Could not get group headers"); return; } if (groupItems(g)) { DPRINT("Could not get group items"); return; } } setWinList(newrdw, g->items); return; } static void selectArticle(nWin *nw, rdWin *rdw, int item) { nGroup *g; int artnum; nWin *newnw; rdWin *newrdw; nArticle *a; assert(nw && nw->kind == nArtList); g = nw->group; artnum = itemToArtnum(g, item); if (canWarp(1, g, artnum, &newnw, &newrdw)) { warpToWin(newrdw); return; } assert(newnw = allocNWin(nDispArt, g, artnum)); assert(newrdw = getBlankArtWin(item, (void *)newnw)); displayArticle(newrdw, g, item); return; } static void markread(nArticle *a, int read) { nGroup *g = a->group; int i; nWin *nw; rdWin *w; assert(a); g = a->group; if (a->read == read) return; a->read = read; if (read) newsrcMarkRead(g, a->num); else newsrcMarkUnread(g, a->num); i = artnumToItem(g, a->num); assert(i >= 0); g->items[i][0] = read? 'R' : ' '; for (nw = nwindows; nw; nw = nw->next) if (nw->kind == nArtList && nw->group == g) break; if (nw == 0) { DPRINT("No window found to mark article as read in"); return; /* user might have closed the window */ } w = userpWin(nw); assert(w); rdChangeItem(w, i, g->items[i]); } nWin * allocNWin(int kind, nGroup *g, int num) { nWin *n = salloc(sizeof(*n)); nWin **p = &nwindows; n->kind = kind; n->group = g; n->artnum = num; n->isrep = n->ispost = 0; n->next = 0; while (*p) p = &((*p)->next); *p = n; return n; } void freeNWin(nWin *w) { nWin **p = &nwindows; assert(w); while (*p != w) { assert (*p); p = &((*p)->next); } *p = w->next; free(w); } nWin * findNWin(void *ptr) { nWin *nw = nwindows; assert(ptr); while (nw && (nWin *)ptr != nw) nw = nw->next; return nw; } static void nQuit(rdWin *w, nGroup *g, int first, int last, char *arg) { DPRINT("Quitting"); update_newsrc(groups); nExit(w, g, first, last, arg); } static void nExit(rdWin *w, nGroup *g, int first, int last, char *arg) { nWin *nw; rdWin *rw; assert(w); assert(arg); unlock_newsrc(); /* close msg windows first */ for (nw = nwindows; nw; nw = nw->next) if (nw->kind == nCompArt || nw->kind == nDispArt) if ((rw = userpWin(nw))) closeWin(rw); for (nw = nwindows; nw; nw = nw->next) if (nw->kind != nCompArt && nw->kind != nDispArt) if ((rw = userpWin(nw))) closeWin(rw); exit(0); /* not actually needed - reader will exit for us */ } static int groupNum(nGroup *grp) { int n; for (n = 0; n < ngroups; n++) if (grpptrs[n] == grp) return n; assert(false); /* shouldn't run off the end */ } /* * Scan the list of groups for one which had some unread articles in it. */ static nGroup * findUnreadGroup(nGroup *grp, int fwd) { int n = groupNum(grp); if ((fwd && n >= ngroups-1) || (!fwd && !n)) return 0; /* out of groups */ n += fwd? 1 : -1; assert(n >= 0 && n < ngroups); assert(grpptrs[n]); return grpptrs[n]; } /* * XXX - this function deals with numbers that refer to an article's position * in the list window (0-n), not article numbers (xxx-yyy). */ static int nextArt(rdWin *w, nGroup **ng, int *num, int next) { nWin *artwin, *gwin; rdWin *rwin; nGroup *g = *ng, *nextgroup; int max, item; assert(w); assert(artwin = findNWin(w->userp)); max = g->nunread; item = artwin->itemnum; if ((next && item >= max-1) || (!next && !item)) { /* walking off one end of this newsgroup onto another (in either direction) */ nextgroup = findUnreadGroup(g, next); if (nextgroup == 0) return -1; (void)canWarp(0, g, 0, &gwin, &rwin); /* locate the group window */ displayGroupList(nextgroup, gwin, rwin); artwin->group = nextgroup; /* item number of article is first(last) in group */ if (next) item = 0; else item = nextgroup->nunread - 1; *ng = nextgroup; } else { /* still within this group - move to next article */ item += next? 1 : -1; } *num = item; return 0; } /* * displayArticle(w,g,i) - display article which is item i in group g, in * window w. */ static void displayArticle(rdWin *w, nGroup *g, int i) { nArticle *a; int artnum; nWin *nw; static char title[200]; /* XXX standard guess */ assert(w); assert(g); assert(nw = findNWin(w->userp)); artnum = itemToArtnum(g,i); a = g->artptrs[i]; if (a->body == 0) if (nntpGetArticle(a)) { DPRINT("Could not retrieve article"); return; } sprintf(title,"%s/%d", g->name, artnum); setWinTitle(w, title); setWinTools(w, artdisp_tools); setWinArt(w, a->body); nw->itemnum = i; markread(a, 1); return; } void nNext(rdWin *w, nGroup *g, int first, int last, char *arg) { assert(w); if (nextArt(w, &g, &first, 1)) { DPRINT("No more to select"); return; } displayArticle(w,g,first); } void nPrev(rdWin *w, nGroup *g, int first, int last, char *arg) { assert(w); if (nextArt(w, &g, &first, 0)) { DPRINT("No more to select"); return; } displayArticle(w,g,first); } void nArtMarkRead(rdWin *w, nGroup *g, int first, int last, char *arg) { markartsread(g, first, last, 1); } void nArtMarkUnread(rdWin *w, nGroup *g, int first, int last, char *arg) { markartsread(g, first, last, 0); } void nCatchup(rdWin *w, nGroup *g, int first, int last, char *arg) { nWin *nw, *t; rdWin *rdw; nGroup *nextgroup; assert(g); markartsread(g, 0, g->nunread-1, 1); /* Close any articles displayed from this group */ for (nw = nwindows; nw; nw = t) { t = nw->next; if (nw->kind == nDispArt && nw->group == g) if ((rdw = userpWin(nw)) != 0) { closeWin(rdw); freeNWin(nw); } } /* Move onto next group, if there is one. */ if ((nextgroup = findUnreadGroup(g, 1)) == 0) return; displayGroupList(nextgroup, findNWin(w->userp), w); return; } static void markartsread(nGroup *g, int first, int last, int read) { int i; nArticle *a; assert(g); assert(0 <= first && first <= last); assert(read == 0 || read == 1); for (i = first; i <= last; i++) { DPRINT("Marking article as (un)read"); if (g->artptrs[i]) markread(g->artptrs[i], read); } return; } { int c; nWin *nw; unsigned short context; fflush(stdout); assert(w); assert(cmd); assert(arg); for (c = 0; ncmds[c].cmd; c++) if (strcmp(cmd, ncmds[c].cmd) == 0) break; if (ncmds[c].cmd == 0) { fflush(stdout); winReflectCmd(w,cmd,arg); return; } /* check that the command is valid in this window */ if ((nw = findNWin(w->userp)) == 0) { fprintf(stderr,"%s: invalid window argument\n",cmd); return; } switch (nw->kind) { case nGroupList: contexwily-0.13.42/tools/old/wilytoys/reader2/news.h000064402366570000012000000067751033320152300210050ustar00ozstaff00004330000002/* * news.h - definitions of newsgroups and news articles. This is a simplistic * view - we ignore concepts like cross-posting. :-} */ #ifndef NEWS_H #define NEWS_H typedef struct _nGroup nGroup; typedef struct _nArticle nArticle; typedef struct _nWin nWin; typedef struct _nRange nRange; typedef struct _nString nString; /* * Kinds of window we understand. */ enum { nGroupList, /* list of newsgroups */ nArtList, /* list of articles within a group */ nDispArt, /* a displayed article, within a group */ nCompArt /* a new article being composed */ }; struct _nString { char *s0, *s1; }; struct _nRange { int n0, n1; struct _nRange *next; }; struct _nWin { int kind; /* what kind of window it is */ nGroup *group; /* null for nGroupList */ struct _nWin *gwin; /* For articles, this is the userp of the group list window */ int artnum; /* valid for nDispArt and nCompArt */ int itemnum; /* 0 - (n-1), where n==number of items in list */ int isrep; /* true if nCompArt and replying by email */ int ispost; /* true if nCompArt and following up */ struct _nWin *next; }; struct _nGroup { char *name; /* newsgroup name */ int first, last; /* range of articles in this group */ int nunread; /* number of articles left in this group to be read */ nArticle *arts; /* actual articles - null until fetched */ nArticle **artptrs; /* art ptrs, in sync with items */ char **items; /* list of items we pass to the window */ nRange *read; /* list of articles that we've read, from the .newsrc */ int canpost; /* true if posting is allowed to this group */ int issub; /* true if we're subscribed to this group */ struct _nGroup *next; }; /* * In the following structure, if nString.s0 == nString.s1 == 0, then * we haven't downloaded the relevant section yet. */ struct _nArticle { int num; /* article number within group */ int visible; /* true if the article is currently in a window */ nGroup *group; /* group this article is from */ int read; /* true if we've read it */ char *body; /* whole body of article */ int bodylen; /* length of body */ char *from; /* sender - points into hdr */ char *subj; /* subject - points into hdr */ struct _nArticle *next; }; /* * These are the commands that the news reader recognises, and the * contexts that they are valid. */ #define NCMSGLIST 0x1 #define NCDISPART 0x2 #define NCCOMPART 0x4 #define NCGRPLIST 0x8 #define NCNOTCOMP (NCMSGLIST|NCDISPART|NCGRPLIST) #define NCANY (NCMSGLIST|NCDISPART|NCCOMPART|NCGRPLIST) #define NNOARG 0x0 #define NARG 0x1 struct nCmd { char *cmd; unsigned short context; unsigned short req; void (*fn)(rdWin *, nGroup *, int, int, char *); /* pane, first msg, last msg, arg */ }; /* * MTU is your mailer program. It must be capable of reading a complete * mail message, with headers, on stdin. No arguments are added to the * command. */ #define MTU "/usr/lib/sendmail -t" /* * FROMENV gives the name of the environment variable to use to * obtain your real email address - it'll place this in the From: field * of mail messages and news articles. */ #define FROMENV "WILYFROM" /* * LOADDISP determines how much feedback you get when the * newsreader is initialising. It'll display the name of every * LOADDISPth group it asks the server about, unless it's * 0, in which case you don't get any feedback at all. */ #define LOADDISP 5 nWin *allocNWin(int kind, nGroup *g, int num); void freeNWin(nWin *w); nWin *findNWin(void *ptr); int artnumToItem(nGroup *g, int artnum); #endif /* !NEWS_H */ wily-0.13.42/tools/old/wilytoys/reader2/nntp.c000064402366570000012000000271521033320152300207730ustar00ozstaff00004330000002/* * NNTP client code. */ #include "newsheaders.h" #include #include #include #include #include #include #define NNTPMAXRESP 512 #define NNTPMAXPARAMS 256 #define GetChar() ((nntpBufPtr < nntpBufLen)? nntpBuf[nntpBufPtr++] : nntpFillBuf()) static void nntpErr(int quit, char *msg); static int iptoaddr(char *host, char **addr, size_t *len); static int gethost(char **addr, size_t *len); static int getport(void); static int getServerResp(void); static int nntpFillBuf(void); static char *getLine(int *len); static int getServerLine(void); static int splitServerLine(void); static int getLongText(void); static int sendCommand(const char *cmd, ...); static nGroup *getGroupLine(char **str); static int getFromHdrs(nGroup *g); static int doXhdr(nGroup *g, char *arg); static char *nextXhdr(char *s, int *n, char **t); static int getSubjHdrs(nGroup *g); static int haveRead(nGroup *g, int num); static int nextArtLine(FILE *fp, char **lineptr); /* * Messages sent to the server. */ static const char *articleComm = "ARTICLE", *bodyComm = "BODY", *headComm = "HEAD", *statComm = "STAT", *groupComm = "GROUP", *listComm = "LIST", *newgroupsComm = "NEWGROUPS", *newnewsComm = "NEWNEWS", *nextComm = "NEXT", *postComm = "POST", *quitComm = "QUIT", *xhdrComm = "XHDR"; /* * NNTP server status */ static nGroup *currgrp; static nArticle *currartp; static int currartnum; static int canpost; /* * connection to NNTP server. */ static int nntpfd; /* * Response information */ static char nntpBuf[BUFSIZ]; static int nntpBufLen; static int nntpBufPtr; static char nntpRespLine[NNTPMAXRESP+1]; static char *nntpRespWords[NNTPMAXPARAMS]; static char *nntpText; static int nntpRespLen; static int nntpRespNParams; static int nntpStatus; static int nntpTextMax; static int nntpTextLen; /* * Display an NNTP error message. */ static void nntpErr(int quit, char *msg) { int n; fprintf(stderr,"NNTP server error: %s\n", msg); for (n = 0; n < nntpRespNParams; n++) fprintf(stderr,"%s ", nntpRespWords[n]); fputc('\n',stderr); if (quit) exit(1); } /* * Functions to connect to the NNTP server. */ static int iptoaddr(char *host, char **addr, size_t *len) { unsigned long l = inet_addr((const char *)host); if (l == (unsigned long)-1) { perror("bad NNTP address"); return -1; } *addr = (char *)&l; *len = sizeof(l); return 0; } static int gethost(char **addr, size_t *len) { static struct hostent *hp; char *host = getenv("NNTPSERVER"); if (!host || !*host) { DPRINT("NNTPSERVER not set - using 'news'"); host = "news"; /* desparate guess */ } if ((hp = gethostbyname(host)) == 0) { DPRINT("Could not get host address"); if (isdigit(*host)) { DPRINT("Treating hostname as IP address"); return iptoaddr(host, addr, len); /* assume a.b.c.d */ } perror(host); return 1; } assert(hp); *addr = hp->h_addr; *len = hp->h_length; return 0; } static int getport(void) { struct servent *sp; char *srv = "nntp"; if ((sp = getservbyname(srv, "tcp")) == 0) { perror("getservbyname"); exit(1); } else return sp->s_port; } int nntpConnect() { int s; struct sockaddr_in saddr; char *haddr; size_t h_len; int port; if (gethost(&haddr, &h_len)) return -1; memcpy((char *)&saddr.sin_addr, haddr, h_len); if ((port = getport()) == -1) return -1; saddr.sin_port = htons((short)port); if ((s = socket( AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket: %m\n"); return -1; } saddr.sin_family = AF_INET; if (connect (s, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) { perror("connect: %m\n"); return -1; } nntpfd = s; if (getServerResp()) return -1; if (nntpStatus == nnServerOkPost || nntpStatus == nnServerOkNoPost) canpost = nntpStatus == nnServerOkPost; else nntpErr(1,"Failed to connect"); /* doesn't return */ return 0; } /* * Get a response from the server. */ static int getServerResp(void) { nntpRespLen = nntpRespNParams = nntpTextLen = 0; if (getServerLine()) { DPRINT("Could not read line from server"); return 1; } if (splitServerLine()) { DPRINT("Could not split line from server"); return 1; } return 0; } static int nntpFillBuf(void) { int r; nntpBufLen = nntpBufPtr = 0; do { r = read(nntpfd, nntpBuf, BUFSIZ); } while (r < 0 && r == EINTR); if (r == 0) { DPRINT("EOF from nntp server"); return EOF; } if (r < 0) { perror("NNTP read"); exit(1); } nntpBufLen = r; nntpBufPtr = 1; return *nntpBuf; } static char * getLine(int *len) { static char *str; static int max; int l = 0, c = 0, cr = 0; while ((c = GetChar()) != EOF) { if (l >= max) { max = l + NNTPMAXRESP; str = srealloc(str, max); } str[l++] = c; if (c == '\r') cr = 1; else if (cr && c == '\n') { str[--l] = 0; str[l-1] = '\n'; *len = l; return str; } else cr = 0; } return 0; } static int getServerLine(void) { int l; char *s = getLine(&l); if (!s || !*s) return 1; s[--l] = 0; /* chop newline */ if (l >= NNTPMAXRESP) { DPRINT("NNTP line chopped"); } l = l < NNTPMAXRESP? l : NNTPMAXRESP; strncpy(nntpRespLine,s,l); nntpRespLine[l] = 0; nntpRespLen = l; return 0; } static int splitServerLine(void) { char *s = nntpRespLine; assert(s); do { nntpRespWords[nntpRespNParams++] = s; if ((s = strchr(s,' '))) *s++ = 0; } while (s); nntpStatus = atoi(nntpRespWords[0]); assert(nntpStatus); return 0; } static int getLongText(void) { int l; char *s; nntpTextLen = 0; while ((s = getLine(&l))) { if (*s == '.' && s[1] == '\n') return 0; if (nntpTextLen + l > nntpTextMax) { nntpTextMax = nntpTextLen + l + BUFSIZ; nntpText = srealloc(nntpText, nntpTextMax); } strcpy(nntpText + nntpTextLen, s); nntpTextLen += l; } nntpErr(1,"EOF in middle of textual response!"); } /* * Send a command to the NNTP server. */ static int sendCommand(const char *cmd, ...) { static char cmdbuf[512]; int l = 0; char *s; va_list alist; va_start(alist, cmd); strcpy(cmdbuf,cmd); l = strlen(cmd); while ((s = va_arg(alist, char *))) { cmdbuf[l++] = ' '; /* XXX - doesn't check limit of string length */ strcpy(cmdbuf+l, s); l += strlen(s); } va_end(alist); cmdbuf[l++] = '\r'; cmdbuf[l++] = '\n'; if (write(nntpfd, cmdbuf, l) != l) { perror("write"); exit(1); } return 0; } /* * Get a listing of all the groups that the server supports. */ nGroup * nntpListGroups(void) { nGroup *groups = 0, *g; char *s; if (sendCommand(listComm, (char *)0)) return 0; if (getServerResp()) return 0; if (nntpStatus != nnListFollows) nntpErr(1,"Could not get newsgroup list"); if (getLongText()) return 0; for (s = nntpText; s; ) { if ((g = getGroupLine(&s))) { g->next = groups; groups = g; } else break; } return groups; } static nGroup * getGroupLine(char **str) { char *last, *first, *p; nGroup *g; assert(str); if ((last = strchr(*str,' ')) == 0) return 0; *last++ = 0; if ((first = strchr(last,' ')) == 0) return 0; *first++ = 0; if ((p = strchr(first,' ')) == 0) return 0; *p++ = 0; g = salloc(sizeof(*g)); g->name = sstrdup(*str); g->first = atoi(first); g->last = atoi(last); g->canpost = (*p == 'y' || *p == 'Y'); /* Y probably isn't valid but.... */ g->arts = 0; g->read = 0; g->next = 0; if ((*str = strchr(p,'\n'))) (*str)++; return g; } void nntpQuit(void) { (void)sendCommand(quitComm,(char *)0); (void)getServerResp(); close(nntpfd); return; } /* * Select a particular group, and also retrieve the info about that group. */ int nntpSetGroup(nGroup *g) { assert(g); if (sendCommand(groupComm,g->name,0)) return 1; if (getServerResp()) return 1; if (nntpStatus == nnGroupSel) { currgrp = g; currartp = 0; /* not defined yet */ currartnum = g->first = atoi(nntpRespWords[2]); g->last = atoi(nntpRespWords[3]); return 0; } nntpErr(0,"Could not select group"); return 1; } /* * Fill in the From and Subject fields for a group's articles. */ int nntpGroupHdrs(nGroup *g) { assert(g); if (g->nunread == 0) return 0; if (g != currgrp && nntpSetGroup(g)) return 1; if (getFromHdrs(g)) return 1; if (getSubjHdrs(g)) return 1; return 0; } static int getFromHdrs(nGroup *g) { char *s; nArticle **ap = &g->arts; nArticle *a; char *from; int num; assert(g); ap = &g->arts; if (doXhdr(g, "from")) return 1; *ap = 0; for (s = nextXhdr(nntpText, &num, &from); s; s = nextXhdr(s, &num, &from)) { a = salloc(sizeof(*a)); a->num = num; a->visible = 0; a->group = g; a->read = haveRead(g, a->num); a->body = 0; a->from = from; a->subj = 0; a->next = 0; *ap = a; ap = &a->next; } return 0; } static int doXhdr(nGroup *g, char *arg) { static char range[80]; /* XXX - more guesses */ sprintf(range,"%d-%d", g->first, g->last); if (sendCommand(xhdrComm,arg,range,0)) return 1; if (getServerResp()) return 1; if (nntpStatus != nnXhdrOk) return 1; if (getLongText()) return 1; return 0; } static char * nextXhdr(char *s, int *n, char **t) { char *text, *num = s; if (s >= nntpText + nntpTextLen) return 0; if ((text = strchr(s, ' ')) == 0) return 0; *text++ = 0; if ((s = strchr(text,'\n')) == 0) return 0; *s++ = 0; *n = atoi(num); *t = sstrdup(text); return s; } static int getSubjHdrs(nGroup *g) { int num; char *s, *subj; nArticle *a = g->arts; assert(g); a = g->arts; if (a == 0) return 0; if (doXhdr(g, "subject")) return 1; for (s = nextXhdr(nntpText, &num, &subj); s; s = nextXhdr(s, &num, &subj)) { if (num < a->num) continue; /* new article appeared from nowhere */ while (a && a->num < num) a = a->next; /* article has been cancelled */ if (a == 0) return 0; a->subj = subj; a = a->next; } return 0; } /* * Read the text for an article. */ int nntpGetArticle(nArticle *a) { static char arg[80]; /* XXX */ assert(a); if (a->body) return 0; /* already fetched */ if (a->group != currgrp && nntpSetGroup(a->group)) return 1; sprintf(arg,"%d", a->num); if (sendCommand(articleComm, arg, 0)) return 1; if (getServerResp()) return 1; if (getLongText()) return 1; a->body = sstrdup(nntpText); a->bodylen = nntpTextLen; return 0; } static int haveRead(nGroup *g, int num) { nRange *r; assert(g); for (r = g->read; r ; r = r->next) if (r->n0 <= num && num <= r->n1) return 1; return 0; } /* * Post an article to the server */ int nntpCanPost(void) { return canpost; } int nntpPost(char *filename) { FILE *fp; char *line; int len; assert(filename); assert(canpost); if ((fp = fopen(filename,"r")) == 0) { (void)fprintf(stderr,"Cannot read %s to post!\n", filename); return 1; } if (sendCommand(postComm,0)) goto broken; if (getServerResp()) goto broken; if (nntpStatus != nnSendArticle) { nntpErr(0,"Server refused article"); goto broken; } while ((len = nextArtLine(fp, &line)) > 0) if (write(nntpfd, line, len) != len) { perror("write"); goto broken; } if (len < 0) goto broken; (void)fclose(fp); if (write(nntpfd, ".\r\n",3) != 3) { perror("write"); return 1; } if (getServerResp()) return 1; if (nntpStatus == nnPostedOk) { DPRINT("Article posted"); } else { nntpErr(0,"Article not posted"); } return 0; broken: (void)fclose(fp); return 1; } static int nextArtLine(FILE *fp, char **lineptr) { static char text[NNTPMAXRESP+1]; int len = 0; int c; *lineptr = text; while ((c = fgetc(fp)) != EOF) { text[len++] = c; if (c == '\n') { text[len-1] = '\r'; text[len++] = '\n'; text[len] = 0; break; } if (len == NNTPMAXRESP-1) { /* line has got too long to put the \r\n sequence in - sent it now. */ text[len] = 0; return len; } } if (len == 3 && text[0] == '.') { len++; strcpy(text,"..\r\n"); } return len; } wily-0.13.42/tools/old/wilytoys/reader2/nntp.h000064402366570000012000000011341033320152300207700ustar00ozstaff00004330000002/* * Declarations of NNTP stuff. Pity there isn't a standard header file for this.... */ #ifndef NNTP_H #define NNTP_H /* * Numeric responses from the server. */ typedef enum { nnServerOkPost = 200, nnServerOkNoPost = 201, nnListFollows = 215, nnGroupSel = 211, nnXhdrOk = 221, nnSendArticle = 340, nnPostedOk = 240, nnPostFailed = 441 } nnServerResp; int nntpConnect(void); nGroup *nntpListGroups(void); void nntpQuit(void); int nntpSetGroup(nGroup *g); int nntpGroupHdrs(nGroup *g); int nntpGetArticle(nArticle *a); int nntpPost(char *filename); #endif /* !NNTP_H */ wily-0.13.42/tools/old/wilytoys/reader2/post.c000064402366570000012000000171071033320152300210000ustar00ozstaff00004330000002/* * This file handles posting of new articles, follow-ups to * existing ones, and emailed replies. It's ripped pretty * much as-is from the mailer. */ #include "newsheaders.h" static void genpost(rdWin *w, nGroup *g, int num, char *to, char *ng, char *subj); static char *getNewsGroups(char *text); static char *version = "X-NewsReader: wilynews 0.1\n"; static char *post_tools = " deliver abort inc "; static char *rep_tools = " deliver abort inc "; static char *savefile; static int getWinNum(rdWin *w, nGroup *g, int first, char *arg) { int n; nWin *nw; assert(w); assert(g); nw = findNWin(w->userp); assert(nw); if (nw->kind == nDispArt) return artnumToItem(g,nw->artnum); else if (arg && *arg && (n = atoi(arg)) && (n = artnumToItem(g,n)) != -1) return n; else return first; } void nReply(rdWin *w, nGroup *g, int first, int last, char *arg) { int num; nArticle *a; char *from; DPRINT("Replying to an article"); num = getWinNum(w,g,first,arg); assert(num >= 0); a = g->artptrs[num]; assert(a); from = a->from; genpost(w, g, num, from, (char *)0, a->subj); return; } void nFollowUp(rdWin *w, nGroup *g, int first, int last, char *arg) { int num; nArticle *a; char *groups; DPRINT("Following up an article"); if (nntpCanPost() == 0) { fprintf(stderr,"Posting not allowed to this server\n"); return; } num = getWinNum(w,g,first,arg); assert(num >= 0); a = g->artptrs[num]; assert(a); if ((groups = getNewsGroups(a->body)) == 0) { DPRINT("Could not get list of groups for article"); groups = "junk"; } genpost(w, g, num, (char *)0, groups, a->subj); return; } void nFollRep(rdWin *w, nGroup *g, int first, int last, char *arg) { int num; nArticle *a; char *groups; DPRINT("Following up and replying to an article"); if (nntpCanPost() == 0) { fprintf(stderr,"Posting not allowed to this server\n"); return; } num = getWinNum(w,g,first,arg); assert(num >= 0); a = g->artptrs[num]; assert(a); if ((groups = getNewsGroups(a->body)) == 0) { DPRINT("Could not get list of groups for article"); groups = "junk"; } genpost(w, g, num, a->from, groups, a->subj); return; } void nPost(rdWin *w, nGroup *g, int first, int last, char *arg) { DPRINT("Posting an article"); if (nntpCanPost() == 0) { fprintf(stderr,"Posting not allowed to this server\n"); return; } genpost(w,g,first, (char *)0, "", (char *)0); return; } static void genpost(rdWin *w, nGroup *g, int num, char *to, char *newsgroups, char *subj) { nWin *nw, *rnw; static char body[300]; /* XXX */ char *me = getenv(FROMENV); char *re = subj? "Re: " : ""; char *tohdr = to? "\nTo: " : ""; char *nghdr = newsgroups? "\nNewsgroups: " : ""; char *title = newsgroups? "Post" : "Reply"; char *tools = newsgroups? post_tools : rep_tools; assert(w); nw = findNWin(w->userp); assert(nw); rnw = allocNWin(nCompArt, g, num); assert(rnw); rnw->isrep = (to != 0); rnw->ispost = (newsgroups != 0); if (!me) me = getenv("USER"); if (!me || !*me) { DPRINT("$WILYFROM and $USER are not valid - fill in from address yourself!"); me = ""; } if (!subj || !*subj || strncmp(subj, "Re: ", 4)==0) re = ""; sprintf(body,"From: %s%s%s%s%s\nSubject: %s%s\n%s\n", me, tohdr, to? to : "", nghdr, newsgroups? newsgroups : "", re, subj? subj : "", version); if (getArtWin(num, rnw, title, tools, body, 0)) { DPRINT("Could not get Reply window - leaving a mess in memory"); return; /* XXX - should clear up */ } DPRINT("Reply window ready"); return; } void nAbort(rdWin *w, nGroup *g, int first, int last, char *arg) { nWin *nw; assert(w); assert(w->userp); DPRINT("Aborting reply/comp"); if ((nw = findNWin(w->userp)) == 0) { DPRINT("Can't find associated window - aborting abort"); return; } if (nw->kind != nCompArt) { DPRINT("Abort isn't applied to a composition window - ignoring"); return; } fprintf(stderr,"Message aborted\n"); closeWin(w); freeNWin(nw); DPRINT("Abort done"); return; } void nDeliver(rdWin *w, nGroup *g, int first, int last, char *arg) { nWin *nw; char *filename = tmpnam((char *)0); assert(w); assert(w->userp); assert(filename); DPRINT("Delivering message"); if ((nw = findNWin(w->userp)) == 0) { DPRINT("Couldn't find associated composition window - aborting"); return; } if (nw->kind != nCompArt) { DPRINT("Deliver not applied to composition window - ignored"); return; } rdBodyToFile(w, filename); if (nw->isrep) dodeliver(w,filename); if (nw->ispost) nntpPost(filename); (void)remove(filename); DPRINT("Deliver done"); closeWin(w); freeNWin(nw); return; } void dodeliver(rdWin *w, char *filename) { static char cmd[100]; /* XXX another guess */ nWin *nw; assert(w); assert(w->userp); assert(MTU && *MTU); assert(filename); DPRINT("Attempting to deliver an article"); if ((nw = findNWin(w->userp)) == 0) { DPRINT("Could not find nWin for this window - aborting"); return; } sprintf(cmd,"%s < %s", MTU, filename); DPRINT("Delivery command is...."); DPRINT(cmd); fflush(stdout); system(cmd); DPRINT("Seems to have delivered"); return; } void nSavefile(rdWin *w, nGroup *g, int first, int last, char *arg) { assert(arg); if (savefile) { DPRINT("Savefile used to be...."); DPRINT(savefile); free(savefile); } savefile = sstrdup(arg); assert(savefile); DPRINT("Savefile now set to..."); DPRINT(savefile); } void nSave(rdWin *w, nGroup *g, int first, int last, char *arg) { FILE *fp; nWin *nw; nArticle *a; int n; assert(w); assert(w->userp); assert(first >= 0); assert(first <= last); nw = findNWin(w->userp); assert(nw); assert(last <= g->nunread); DPRINT("Saving articles"); if (savefile == 0) { fprintf(stderr,"No savefile yet: 'savefile filename'\n"); return; } if ((fp = fopen(savefile,"a")) == 0) { perror(savefile); DPRINT("Could not open savefile - article not saved"); return; } for (n = first; n <= last; n++) { a = g->artptrs[n]; assert(a); (void)fprintf(fp,"%s\n", a->body); printf("Written message %d to %s\n", n+1, savefile); /* count from 1 */ } fflush(stdout); fclose(fp); } void nInclude(rdWin *w, nGroup *g, int first, int last, char *arg) { doinclude(w,g,first,last,arg,0); } void nIncludeall(rdWin *w, nGroup *g, int first, int last, char *arg) { doinclude(w,g,first,last,arg,1); } void doinclude(rdWin *w, nGroup *g, int first, int last, char *arg, int all) { nWin *nw; rdWin *ow; int msgnum; /* message we're going to include */ nArticle *a; char *s; int n; assert(w); assert(w->userp); assert(arg); DPRINT("Including article text"); if ((nw = findNWin(w->userp)) == 0) { DPRINT("Could not find nWin for rdWin - aborting"); return; } if (nw->kind != nCompArt) { DPRINT("Not a composition window - include ignored"); return; } msgnum = nw->artnum; /* default value */ if (*arg) { if ((msgnum = atoi(arg)) < 1) { fprintf(stderr,"'%s' is an invalid message number\n", arg); return; } else { msgnum = artnumToItem(g, msgnum); } } if (msgnum < 0 || msgnum >= g->nunread) { fprintf(stderr,"Invalid msg number (%d-%d)\n", g->first, g->last); return; } a = g->artptrs[msgnum]; assert(a); s = all? a->body : a->body; /* XXX should have one option skip headers */ assert(s); rdInclude(w, s, strlen(s)); DPRINT("Done include"); } static char * getNewsGroups(char *text) { static char *buff; char *s, *t, *ng = "\nNewsgroups: "; size_t len = strlen(ng); if (buff) free(buff); if ((s = strstr(text, ng))) s += len; else if (strncmp(text, ng+1, len-1) == 0) s = text + len - 1; else return 0; if ((t = strchr(s, '\n')) == 0) return 0; len = t - s + 1; buff = salloc(len); strncpy(buff, s, len); buff[len-1] = 0; return buff; } wily-0.13.42/tools/old/wilytoys/reader2/post.h000064402366570000012000000015341033320152300210020ustar00ozstaff00004330000002#ifndef WILYPOST_H #define WILYPOST_H void nReply(rdWin *w, nGroup *g, int first, int last, char *arg); void nPost(rdWin *w, nGroup *g, int first, int last, char *arg); void nFollowUp(rdWin *w, nGroup *g, int first, int last, char *arg); void nFollRep(rdWin *w, nGroup *g, int first, int last, char *arg); void nAbort(rdWin *w, nGroup *g, int first, int last, char *arg); void nDeliver(rdWin *w, nGroup *g, int first, int last, char *arg); void nSavefile(rdWin *w, nGroup *g, int first, int last, char *arg); void nSave(rdWin *w, nGroup *g, int first, int last, char *arg); void dodeliver(rdWin *w, char *filename); void nIncludeall(rdWin *w, nGroup *g, int first, int last, char *arg); void nInclude(rdWin *w, nGroup *g, int first, int last, char *arg); void doinclude(rdWin *w, nGroup *g, int first, int last, char *arg, int all); #endif /* !WILYPOST_H */ wily-0.13.42/tools/old/wilytoys/reader2/newsrc.c000064402366570000012000000133001033320152300213030ustar00ozstaff00004330000002/* * newsrc.c - loading, parsing and updating the list of newsgoups/articles * that have been read. */ #include "newsheaders.h" static void init_filenames(void); static FILE *lock_newsrc(void); static nGroup *newsrcLine(FILE *fp); static char *newsrcGroup(FILE *fp); static nRange *newsrcRanges(FILE *fp); static nRange *newsrcRange(FILE *fp, int *end); static void newsrcCompress(nGroup *g); static char newsrcname[MAXPATHLEN+1]; static char newsrctmp[MAXPATHLEN+1]; static char newsrcold[MAXPATHLEN+1]; static char lockname[MAXPATHLEN+1]; static int newsrcline; static void init_filenames(void) { char *h = getenv("HOME"); if (!h || !*h) { fprintf(stderr,"$HOME is not set\n"); exit(1); /* XXX- should really get pwdent */ } sprintf(newsrcname,"%s/%s", h, NEWSRC); sprintf(newsrctmp,"%s/%s.tmp", h, NEWSRC); sprintf(newsrcold,"%s/%s.old", h, NEWSRC); sprintf(lockname,"%s/%s", h, LOCKFILE); DPRINT("newsrc is..."); DPRINT(newsrcname); DPRINT("lockfile is..."); DPRINT(lockname); return; } static FILE * lock_newsrc(void) { FILE *fp; DPRINT("Locking .newsrc..."); if (link(newsrcname, lockname)) { perror(".newsrc link"); fprintf(stderr,"Could not lock %s with link to %s\n", newsrcname, lockname); return 0; } DPRINT("Newsrc locked - opening"); if ((fp = fopen(newsrcname,"r")) == 0) { DPRINT("could not open newsrc"); unlock_newsrc(); } atexit(unlock_newsrc); return fp; } void unlock_newsrc(void) { DPRINT("Unlocking newsrc"); remove(lockname); DPRINT("Newsrc unlocked"); } nGroup * read_newsrc(void) { FILE *fp; nGroup *groups = 0, *g; nGroup **p; DPRINT("Reading newsrc"); newsrcline = 1; init_filenames(); if ((fp = lock_newsrc()) == 0) { DPRINT("Could not lock newsrc"); return 0; } for (p = &groups; (g = newsrcLine(fp)); p = &g->next) *p = g; DPRINT("Closing newsrc"); fclose(fp); return groups; } static nGroup * newsrcLine(FILE *fp) { nGroup *g = salloc(sizeof(*g)); int c; memset(g,0,sizeof(*g)); if ((g->name = newsrcGroup(fp)) == 0) goto broken; switch ((c = fgetc(fp))) { case SUBSEP: g->issub = 1; break; case NOSUBSEP: g->issub = 0; break; default: DPRINT("Don't recognise group name delimiter in line"); goto broken; } g->read = newsrcRanges(fp); newsrcline++; return g; broken: if (g->name) free(g->name); free(g); return 0; } static char * newsrcGroup(FILE *fp) { int c, l = 0; static char str[MAXPATHLEN+1]; while ((c = fgetc(fp)) != SUBSEP && c != NOSUBSEP) { if (c == EOF || l == MAXPATHLEN) { if (l) fprintf(stderr,"%s corrupt: line %d\n", newsrcname, newsrcline); return 0; } str[l++] = c; } assert(l); ungetc(c, fp); str[l] = 0; return sstrdup(str); } static nRange * newsrcRanges(FILE *fp) { nRange *ranges = 0, *r; nRange **p; int c, end = 0; while (isspace((c = fgetc(fp))) && c!='\n') ; if (c == '\n') return 0; ungetc(c,fp); for (p = &ranges; r = newsrcRange(fp, &end); p = &r->next) { *p = r; if (end) break; } assert(ranges); return ranges; } static nRange * newsrcRange(FILE *fp, int *end) { nRange *r = salloc(sizeof(*r)); int c, l; static char num[80]; /* XXX wild guess */ r->next = 0; for (l = 0; isdigit((c = fgetc(fp))); num[l++] = c) ; num[l] = 0; r->n0 = r->n1 = atoi(num); if (c == '-') { for (l = 0; isdigit((c = fgetc(fp))); num[l++] = c) ; num[l] = 0; r->n1= atoi(num); } if (c != RANGESEP && c != '\n') while ((c = fgetc(fp)) != EOF && c != '\n'); if (c != RANGESEP) *end = 1; return r; } int update_newsrc(nGroup *groups) { nGroup *g; nRange *r; FILE *fp; assert(groups); DPRINT("Updating newsrc"); newsrcCompress(groups); if ((fp = fopen(newsrctmp,"w")) == 0) { perror(newsrctmp); return 1; } for (g = groups; g; g = g->next) { char *s = ""; char *fmt = g->read? "%s%c " : "%s%c"; fprintf(fp, fmt, g->name, g->issub? SUBSEP : NOSUBSEP); for (r = g->read; r; r= r->next, s = ",") if (r->n0 == r->n1) fprintf(fp, "%s%d",s,r->n0); else fprintf(fp,"%s%d-%d",s,r->n0, r->n1); fputc('\n',fp); } if (fclose(fp)) { perror(newsrctmp); remove(newsrctmp); return 1; } if (rename(newsrcname, newsrcold) || rename(newsrctmp, newsrcname)) { perror("renaming .newsrc"); return 1; } DPRINT("Newsrc updated"); return 0; } /* * Some routines for handling the list of ranges of read articles. */ void newsrcMarkRead(nGroup *g, int i) { nRange **p; nRange *r; assert(g); for (p = &g->read; *p && (*p)->n0 < i; p = &((*p)->next)) ; /* have now reached the end of the list, the range containing i, or the range that comes after i. */ if (!*p || i < (*p)->n0) { /* does insert at end, insert at start, or insert before a range */ r = salloc(sizeof(*r)); r->n0 = r->n1 = i; r->next = *p; *p = r; return; } /* only remaining case is that the current range already contains i */ assert(*p); assert((*p)->n0 <= i && i <= (*p)->n1); return; } void newsrcMarkUnread(nGroup *g, int i) { nRange **p; nRange *r, *n; assert(g); for (p = &g->read; *p && (*p)->n0 < i; p = &((*p)->next)) { r = *p; if (r->n0 == i && i == r->n1) { *p = r->next; free(r); return; } else if (r->n0 == i) { r->n0++; return; } else if (r->n1 == i) { r->n1--; return; } else if (r->n0 < i && i < r->n1) { n = salloc(sizeof(*n)); n->n1 = r->n1; n->n0 = i + 1; n->next = r->next; r->n1 = i - 1; r->next = n; return; } } /* i isn't in any of the items in the list */ return; } /* * compress the list, by combining adjacent ranges */ static void newsrcCompress(nGroup *g) { nRange *r, *n; assert(g); for (; g; g = g->next) for (r = g->read; r; r = r->next) for (n = r->next; n && n->n0 <= r->n1 + 1; n = r->next) { r->n1 = n->n1; r->next = n->next; free(n); } return; } wily-0.13.42/tools/old/wilytoys/reader2/newsrc.h000064402366570000012000000005711033320152300213160ustar00ozstaff00004330000002/* * newsrc.h - handling the list of newsgroups/articles that we've read. */ #define SUBSEP ':' #define NOSUBSEP '!' #define RANGESEP ',' #define NEWSRC ".testnewsrc" #define LOCKFILE ".testnewsrc.lock" nGroup *read_newsrc(void); void unlock_newsrc(void); int update_newsrc(nGroup *groups); void newsrcMarkRead(nGroup *g, int i); void newsrcMarkUnread(nGroup *g, int i); wily-0.13.42/tools/old/wilytoys/reader2/utils.c000064402366570000012000000005301033320152300211430ustar00ozstaff00004330000002/* * general utilities... */ #include "headers.h" char * sstrdup(char *str) { char *s; assert(str); s = salloc(strlen(str)+1); strcpy(s,str); return s; } void panic(const char *msg) { assert(msg); fprintf(stderr,"%s\n", msg); exit(1); } ulong atoul(char *str) { assert(str); return strtoul((const char *)str, (char **)0, 10); } wily-0.13.42/tools/old/wilytoys/reader2/CHANGES000064402366570000012000000062521033320152300206410ustar00ozstaff000043300000020.3 - 0.4 ======= Newsreader has been significantly improved, to the point where I actually use it for reading news. It's got a long way to go, but I can actually bear to use it, so it can't be all that bad. Both readers give feedback when they're loading - makes it slightly less stressful watching the newsreader load, anyway. Addresses are "parsed", for want of a better word, to give name or email address in the message lists. 0.2 - 0.3 ======= *BUG WARNING* In at least one case, I've noticed that this appears to have lost mail in a race condition. Faces announced that new mail had arrived, I did a commit, and nothing new appeared. :-( I'm not aware of this happening more than once, but how do you tell? I recommend using a .forward file or some similar mechanism to keep a separate copy of your mail, so that you've got a day or so's backlog in case someone claims something went missing. I don't know how to reproduce this, so I've got no idea how to fix it. Right now, I'm not too worried - no one else has appeared to send me anything which has vanished, and the message I did lose was from my boss. :-) Added lots more assertions and a DEBUG option for the Makefile, which produces lots of gibberish. Added "next" and "prev" commands, for advancing through the mailbox. This occasioned a change in how it determines which window to display a message in. The rule is: - if you next/prev in an article window, you'll re-use that window, and get the next/previous article according to the number of the article in that window. - if you next/prev in the list window, you'll get a new window, and it'll give you the next/previous article according to the line currently selected in the list. (BUG: doesn't change *which* item in the list is currently selected; this is because that causes a cursor warp, too). - If you B3 on a subject line, you get a new window for the article indicated. A News reader is included. This should read groups and articles ok, and allows you to post articles or reply via email. It works, but the behaviour of "next" and "prev" is broken. Right now, it uses .testnewsrc instead of .newsrc, because it's too broken for daily use. When posting a mail message, changes the tag to "Sending...", so you know something is happening. 0.1 -> 0.2 ======== Filters out most common garbage headers (toggle this with allheaders). Can delete/undelete/save multiple messages, by sweeping them. [Un]delete is a lot less effort on the screen updates. Commit now writes changes back to the mailbox, without quitting. Doesn't read in new mail, though. Rescan reads in any new mail that has arrived. Doesn't write any current changes, though. Rescans your mailbox for new mail automatically. Does this every 60 seconds, by default. You have to hack mail.h to change this... If you're running it in non-multiart mode (default), then it tries to avoid trashing your composition windows when you pull up a message window. savefile has a default parameter: $SAVEFILE if set, or $HOME/mbox otherwise. Sets the title of article windows to just mailboxname/msgnum, because the From: lines are too long. Uses MAXPATHLEN instead of FILENAME_MAX, because FILENAME_MAX is way too small on some machines. wily-0.13.42/tools/old/wilytoys/reader2/reader.c000064402366570000012000000456331033320152300212620ustar00ozstaff00004330000002/* * reader.c - functions for handling news/article reader windows. */ #include "headers.h" Bool debug = false; Bool frommessage = true; /* * The windows currently active. */ rdWin *windows = 0; /* * General wily comms stuff. */ Mqueue realwilyq; Mqueue *wilyq = &realwilyq; Fd wilyfd; /* * Amount of time we wait before causing a rescan event, in seconds. * If zero, then we don't rescan. */ static int rdRescanTimer = 0; Bool rdAlarmEvent = false; static void (*old_alarm_handler)(int) = 0; /* * default contents of tags */ char *rdListTagStr = " "; char *rdArtTagStr = " "; static rdWin *allocWin(rdWinType kind, const char *title); static int connectWin(rdWin *w, char *filename); static rdWin *getWin(int user, void *userp, rdWinType kind); static void clearWin(rdWin *w); static void freeItems(rdWin *w); static int initWin(int user, void *userp, rdWin *w, char *title, char *tools); static void anyEvent(rdWin *w); static void winDelete(rdWin *w, int which, ulong p0, ulong p1); static void winInsert(rdWin *w, int which, ulong p, char *str); static void updateBody(rdWin *w, ulong p0, ulong p1, char *str); static void winGoto(rdWin *w, ulong p0, char *str); static void winExec(rdWin *w, char *cmd, char *arg); static void DelWin(rdWin *w, char *arg); static int rdBuiltin(rdWin *w, char *cmd, char *str); static void addrEvent(rdWin *w); static void bodyEvent(rdWin *w); static size_t countlines(char *str, size_t len); static void prefixlines(char *str, size_t len, char *prefix, size_t plen, char *buf); static void alarm_handler(int signal); static void set_sig(void); static void updateItems(rdWin *w, rdItem *i, int len); /* * allocWin(kind, title) - create a new, blank window of a given kind. */ static rdWin * allocWin(rdWinType kind, const char *title) { rdWin *w = salloc(sizeof(*w)); assert(title); w->title = sstrdup((char *)title); w->wintype = kind; w->id = -1; w->m = 0; w->items = 0; w->body = 0; w->taglen = w->bodylen = 0; w->next = windows; windows = w; return w; } /* * connectWin(w, filename) - connect to wily, to create a new window. * If filename is true, then we get wily to open the given file. Otherwise, * we ask for a new, blank window. * Returns 0 for success. */ static int connectWin(rdWin *w, char *filename) { int fd; assert(w); if (filename == 0) filename = "New"; if (rpc_new(wilyq, &w->id, filename, false) < 0) { DPRINT("Could not get new window from wily"); freeWin(w); return -1; } return 0; } /* * setWinUser(w, user, userp) - change the user info for this window. */ int setWinUser(rdWin *w, int user, void *userp) { assert(w); w->user = user; w->userp = userp; return 0; } /* * randomTitle() - generate a one-off string to be the title for * this window, until we're given one by the user program. * XXX this is a static string, which is copied when it's written * into the window structure. */ static char * randomTitle(void) { int pid = getpid(); static int num; static char title[30]; /* XXX - usual guess */ sprintf(title,"+rdwin%d-%d", pid, num++); return title; } /* * setWinTitle(w, title) - set the title of a window. */ int setWinTitle(rdWin *w, char *title) { assert(w); assert(title); if (rpc_setname(wilyq, w->id, title)) { DPRINT("Wily couldn't set window title"); return 1; } if (w->title) free(w->title); assert(w->title = sstrdup(title)); return 0; } /* * setWinTools(w, tools) - set the tools for a window. */ int setWinTools(rdWin *w, char *tools) { assert(w); assert(tools); if (rpc_settag(wilyq, w->id, tools)) { DPRINT("wily couldn't set window tools"); return 1; } w->taglen = strlen(tools); return 0; } /* * getBlankArtWin(user, userp) - grab an article window. */ rdWin * getBlankArtWin(int user, void *userp) { return getWin(user, userp, rdArticle); } /* * getBlankListWin(user, userp) - grab a list window. */ rdWin * getBlankListWin(int user, void *userp) { return getWin(user, userp, rdList); } /* * getWin(user, userp, kind) - create a new window. */ rdWin * getWin(int user, void *userp, rdWinType kind) { rdWin *w; char *title; assert(title = randomTitle()); assert(w = allocWin(kind, title)); if (connectWin(w,title)) return 0; w->user = user; w->userp = userp; return w; } /* * discard all the items in the window's list */ static void freeItems(rdWin *w) { rdItem *i, *j; assert(w); for (i = w->items; i; i = j) { j = i->next; free(i); } w->items = 0; } /* * loadItems(w, items) - load an array of items into the list, and into the window. */ static int loadItems(rdWin *w, char **items) { rdItem *i, *j = 0; char *sep = "\n"; ulong p0 = 0; ulong len, seplen = strlen(sep); char *buf = 0; int n; assert(w); assert(items); while (*items) { i = salloc(sizeof(*i)); i->next = 0; i->p0 = p0; len = strlen(*items); if (j) j->next = i; else w->items = i; j = i; if (rpc_insert(wilyq, w->id, p0, *items)) { DPRINT("Failed to insert list item into wily"); freeItems(w); return -1; } p0 += len; if (rpc_insert(wilyq, w->id, p0, sep)) { DPRINT("Failed to insert list separator into wily"); freeItems(w); return -1; } i->p1 = (p0 += seplen); items++; } w->bodylen = p0; return 0; } /* * setWinList(w, items) - update the contents of a list window. */ int setWinList(rdWin *w, char **items) { assert(w); assert(items); if (w->wintype != rdList) { DPRINT("setWinList() called for non-list window"); return 1; } freeItems(w); if (w->bodylen) { if (rpc_delete(wilyq, w->id, 0, w->bodylen)) { DPRINT("Could not delete list body"); return 1; } w->bodylen = 0; } return loadItems(w, items); } /* * setWinArt(w,art) - replace the contents of article window w with text art. */ int setWinArt(rdWin *w, char *art) { assert(w); assert(art); assert(w->wintype == rdArticle); if (w->bodylen) { if (rpc_delete(wilyq, w->id, 0, w->bodylen)) { DPRINT("Failed to delete existing contents of window"); return 1; } } w->bodylen = strlen(art); if (rpc_insert(wilyq, w->id, 0, art)) { DPRINT("Failed to insert new body into window"); return 1; } return 0; } /* * getArtWin(title, text, filename) - get an article window, and load it with * either the given text, or from the given file. */ rdWin * getArtWin(int user, void *userp, char *title, char *tools, char *text, rdWin *oldwin) { rdWin *w; if (oldwin) { w = oldwin; setWinUser(w, user, userp); } else assert(w = getBlankArtWin(user, userp)); if (title && setWinTitle(w, title)) return 0; if (tools && setWinTools(w, tools)) return 0; if (text && setWinArt(w, text)) return 0; return w; } /* * get a List window, and load it with the items in the array (which * must be null-terminated). */ rdWin * getListWin(int user, void *userp, char *title, char *tools, rdWin *oldwin, char **items) { rdWin *w; if (oldwin) { w = oldwin; setWinUser(w, user, userp); } else assert(w = getBlankListWin(user, userp)); if (title && setWinTitle(w, title)) return 0; if (tools && setWinTools(w, tools)) return 0; if (items && setWinList(w, items)) return 0; return w; } /* * readerLoading(user, userp, int isart, title) - create a window of the * desired type and title that indicates that the program has started and is * working at something... */ rdWin * readerLoading(int user, void *userp, int isart, char *title) { rdWin *w; assert(title); assert(w = isart? getBlankArtWin(user, userp) : getBlankListWin(user, userp)); assert(setWinTitle(w,title)==0 && setWinTools(w,"Working...")==0); return w; } /* * readerInit() - general initialisation. */ int readerInit(void) { if ((wilyfd = get_connect()) < 0) { DPRINT("Could not connect to wily"); return 1; } mq_init(wilyq, wilyfd); return 0; } /* * readerMainLoop() - get messages from wily, and act upon them. */ int readerMainLoop(void) { rdWin *w; Msg *m; int istag; while (windows) { if ((w = getActiveWin()) == 0) { fprintf(stderr,"No message available\n"); return 1; } m = w->m; assert(m); switch (m->mtype) { char *cmd, *arg; ulong p0, p1; case EMexec: decode_exec_e(m, &cmd, &arg); winExec(w, cmd, arg); break; case EMgoto: decode_goto_e(m, &p0, &arg); winGoto(w, p0, arg); break; case EMinsert: istag = IsBody; decode_insert_e(m, &p0, &arg); winInsert(w, istag, p0, arg); break; case EMdelete: istag = IsBody; decode_delete_e(m, &p0, &p1); winDelete(w, istag, p0, p1); break; default: fprintf(stderr,"Unknown msg type!\n"); exit(1); } } return 1; } /* * delete item n from the list */ int rdDelItem(rdWin *w, int item) { rdItem **pi; rdItem *i; int len; assert(w); if (w->wintype != rdList || item < 0) { DPRINT("Invalid window or item for delete"); return 1; } for (pi = &w->items; *pi && item; pi = &((*pi)->next)) item--; if (item) { DPRINT("Could not find item to delete it"); return 1; /* not found */ } i = *pi; len = i->p1 - i->p0; if (rpc_delete(wilyq, w->id, i->p0, i->p1) < 0) { DPRINT("Could not delete item from list"); return 1; } *pi = i->next; free(i); updateItems(w, *pi, -len); return 0; } /* * add a new item to the end of the list */ int rdAddItem(rdWin *w, char *text) { rdItem **pi; rdItem *i; int len; char *sep = "\n"; assert(w); assert(text); len = (int)strlen(text); if (w->wintype != rdList || !text || !*text) { DPRINT("addItem() call for non-list window"); return 1; } i = salloc(sizeof(*i)); for (pi = &w->items; *pi; pi = &((*pi)->next)); *pi = i; i->p0 = w->bodylen; i->p1 = i->p0 + len; i->next = 0; if (rpc_insert(wilyq, w->id, i->p0, text) || rpc_insert(wilyq, w->id, i->p1++, sep)) { DPRINT("Could not insert item into window"); return 1; } len += strlen(sep); w->bodylen += len; return 0; } /* * change the text of an item */ int rdChangeItem(rdWin *w, int item, char *text) { rdItem **pi; rdItem *i; int len, oldlen, newlen; char *sep = "\n"; assert(w); assert(text); newlen = strlen(text); if (w->wintype != rdList || !text || !*text) { DPRINT("changeItem() called for non-list window"); return 1; } for (pi = &w->items; *pi && item; pi = &((*pi)->next)) item--; if (item) { DPRINT("item not found"); return 1; } i = *pi; oldlen = i->p1 - i->p0; if (rpc_delete(wilyq, w->id, i->p0, i->p1) || rpc_insert(wilyq, w->id, i->p0, text) || rpc_insert(wilyq, w->id, i->p0 + newlen, sep)) { DPRINT("Updates to wily window failed"); return 1; } newlen += strlen(sep); i->p1 = i->p0 + newlen; len = newlen - oldlen; updateItems(w, i->next, len); return 0; } static void updateItems(rdWin *w, rdItem *i, int len) { assert(w); w->bodylen += len; while (i) { i->p0 += len; i->p1 += len; i = i->next; } } /* * text has been deleted */ static void winDelete(rdWin *w, int which, ulong p0, ulong p1) { rdItem *i; ulong l = p1 - p0; assert(w); assert(p0 <= p1); if (which == IsTag) { w->taglen -= l; return; } if (w->wintype == rdArticle) { w->bodylen -= l; return; } for (i = w->items; i; i = i->next) if (i->p0 <= p0 && p1 <= i->p1) break; if (!i) return; i->p1 -= l; for (i = i->next; i; i = i->next) { i->p0 -= l; i->p1 -= l; } updateBody(w, p0, p1, (char *)0); return; } /* * text has been inserted */ static void winInsert(rdWin *w, int which, ulong p, char *str) { rdItem *i; int l; assert(w); assert(str); l = strlen(str); if (which == IsTag) { w->taglen += l; return; } if (w->wintype == rdArticle) { w->bodylen += l; return; } for (i = w->items; i; i = i->next) if (i->p0 <= p && p <= i->p1) break; if (!i) return; i->p1 += l; for (i = i->next; i; i = i->next) { i->p0 += l; i->p1 += l; } updateBody(w, p, (ulong)l, str); return; } /* * updateBody(w,p0,p1,str) - insert p1 chars of str at p0, or remove the text * between p0 and p1. * XXX - this is *utterly* revolting, and horrendously slow. But it's quick * and simple, and will do for now. */ static void updateBody(rdWin *w, ulong p0, ulong p1, char *str) { char *newbuf; ulong newlen; assert(w); if (w->body == 0) return; if (str) newlen = w->bodylen + p1; else newlen = w->bodylen - (p1 - p0); newbuf = salloc(newlen); strncpy(newbuf, w->body, p0); if (str) { strncpy(newbuf + p0, str, p1); strcpy(newbuf + p0 + p1, w->body + p0); } else { strcpy(newbuf + p0, w->body + p1); } free(w->body); w->body = newbuf; w->bodylen = newlen; } rdItemRange itemNumber(rdWin *w, ulong p0, ulong p1) { int n; rdItem *i; rdItemRange r; assert(w); r.first = r.last = -1; r.i0 = r.i1 = 0; if (w->wintype != rdList || p1 < p0) { DPRINT("itemNumber asked for in non-list window"); return r; } for (n = 0, i = w->items; i; i = i->next, n++) { if (i->p0 <= p0 && p0 <= i->p1) { r.first = r.last = n; r.i0 = r.i1 = i; } if (i->p0 <= p1 && p1 <= i->p1) { r.last = n; r.i1 = i; return r; } } DPRINT("Can't find item in list window"); return r; /* sigh */ } /* * Move the cursor to a particular window. */ void warpToWin(rdWin *w) { assert(w); /* XXX not implemented yet. */ } void highlightItem(rdWin *w, rdItemRange r) { static char addr[80]; /* XXX - overkill */ rdItem *i; ulong p0, p1; int n; assert(w); if (!r.i0 || !r.i1) { for (i = w->items, n = 0; n <= r.last; n++, i = i->next) { if (n == r.first) p0 = i->p0; if (n == r.last) p1 = i->p1; } } else { p0 = r.i0->p0; p1 = r.i1->p1; } sprintf(addr,"#%lu,#%lu", p0, p1); if (rpc_goto(wilyq, w->id, addr)) { DPRINT("highlighting failed"); } } /* * A B3 event has occured. */ static void winGoto(rdWin *w, ulong p0, char *str) { /* If this is a list, then it counts as a selection. Otherwise, we just reflect it back to wily as a normal B3 event. */ assert(w); assert(str); if (w->wintype == rdList) { rdItemRange r = itemNumber(w, p0, p0); if (r.first == -1) { DPRINT("Goto occurred outside range of items"); return; /* sigh */ } highlightItem(w, r); user_listSelection(w,r); return; } else { if (rpc_goto(wilyq, w->id, str)) { DPRINT("could not send goto to wily"); } } return; } /* * A B2(B1) command has been invoked. */ static void winExec(rdWin *w, char *cmd, char *arg) { ulong p0, p1; /* * Lots of options here: * - B2 with "|<>" - reflect back to wily. * - B2 cmd recognised by the reader routines - Del is about it. Execute * them ourselves. * - B2 not recognised by the reader routines - pass them onto the user, * after first getting the position of the argument within the body, if * necessary. * - B2B1 recognised by the reader routines - none spring to mind, but * I might add some. Execute them ourselves. * - B2B1 not recognised - pass onto user. */ assert(w); assert(cmd); assert(arg); DPRINT("Command received..."); DPRINT(cmd); if (!*cmd || strstr(cmd,"|<>")) { DPRINT("Reflecting command"); winReflectCmd(w,cmd, arg); return; } if (rdBuiltin(w,cmd,arg) == 0) { DPRINT("command is reader builtin - handled"); return; } if (rpc_addr(wilyq, w->id, ".", &p0, &p1)) { DPRINT("could not get address of dot"); return; } if (w->wintype == rdList) { rdItemRange r = itemNumber(w, p0, p1); if (r.first == -1) { p0 = p1 = 0; } else { highlightItem(w, r); p0 = r.i0->p0; p1 = r.i1->p1; } user_cmdList(w,cmd,p0,p1,r,arg); return; } user_cmdArt(w, cmd, p0, p1, arg); return; } void winReflectCmd(rdWin *w, char *cmd, char *arg) { if (rpc_exec(wilyq, w->id,cmd,arg)) { DPRINT("could not reflect command to wily"); } } /* * delete this particular window from the list. */ static void DelWin(rdWin *w, char *arg) { assert(w); user_delWin(w); closeWin(w); } void closeWin(rdWin *w) { assert(w); /* get wily to close the pane */ if (rpc_exec(wilyq, w->id, "Del", "")) { DPRINT("Could not close window"); } /* free up resources */ free(w->title); free(w->body); if (w->wintype == rdList) freeItems(w); /* XXX - currently leak the stateinfo stuff */ freeWin(w); return; } void freeWin(rdWin *w) { rdWin **wp = &windows; assert(w); /* remove from the window chain */ while ((*wp) != w) wp = &((*wp)->next); *wp = w->next; if (windows == 0) { DPRINT("All windows have been closed - exiting"); exit(0); } return; } static struct { char *cmd; void (*fn)(rdWin *, char *); } builtins[] = { { "Del", DelWin }, { 0, 0 } }; /* * check for builtin commands understood by the reader routines. */ static int rdBuiltin(rdWin *w, char *cmd, char *str) { int i; assert(w); assert(cmd); for (i = 0; builtins[i].cmd; i++) if (strcmp(builtins[i].cmd, cmd) == 0) { (*builtins[i].fn)(w, str); return 0; } return 1; } /* * "redisplay" a window that's already open. */ void rdGotoWin(rdWin *w) { if (rpc_goto(wilyq, w->id, ".")) { DPRINT("Could not redisplay open window"); } } rdWin * userpWin(void *ptr) { rdWin *w = windows; while (w && w->userp != ptr) w = w->next; return w; } /* * Some routines which attempt to extract the body of a window, * and store it in a file. if p0==p1==0, assume all the body is wanted. */ void rdBodyToFile(rdWin *w, char *filename) { FILE *fp; char *buf; assert(w); assert(filename); buf = salloc(w->bodylen+1); if (rpc_settag(wilyq, w->id, "Sending... ")) { DPRINT("Could not change tag"); return; } if (rpc_read(wilyq, w->id, 0, w->bodylen, buf)) { DPRINT("Could not retrieve body text"); return; } if ((fp = fopen(filename, "w"))) { (void)fprintf(fp,"%s",buf); fclose(fp); } else { DPRINT("Could not write body text to a file"); } free(buf); return; } static void alarm_handler(int signal) { if (signal != SIGALRM) { DPRINT("non-alarm signal received!"); return; } set_sig(); rdAlarmEvent = true; if (old_alarm_handler != SIG_DFL && old_alarm_handler != SIG_IGN) { DPRINT("Passing alarm onto previous handler"); (*old_alarm_handler)(signal); } alarm(rdRescanTimer); } static void set_sig(void) { (void)signal(SIGALRM, alarm_handler); } void rdSetRescanTimer(int secs) { rdRescanTimer = secs; if (old_alarm_handler == 0) { if ((old_alarm_handler = signal(SIGALRM, alarm_handler)) == SIG_ERR) { perror("signal"); rdRescanTimer = 0; return; } } alarm(rdRescanTimer); } void rdInclude(rdWin *w, char *str, size_t len) { size_t nlines; char *buf; char *prefix = "> "; size_t nlen, plen = strlen(prefix); ulong p0, p1; assert(w); assert(str); nlines = countlines(str, len); if (rpc_addr(wilyq, w->id, ".", &p0, &p1)) { DPRINT("Could not get address of dot"); return; } nlen = len + nlines*plen + 1; buf = salloc(nlen); prefixlines(str, len, prefix, plen, buf); if (rpc_insert(wilyq, w->id, p1, buf)) { DPRINT("Could not insert included text"); } w->bodylen += nlen; free(buf); } static size_t countlines(char *str, size_t len) { size_t nlines = 0; assert(str); while (len--) if (*str++ == '\n') nlines++; return nlines; } static void prefixlines(char *str, size_t len, char *prefix, size_t plen, char *buf) { assert(str && prefix); while (len) { strncpy(buf,prefix,plen); buf += plen; while (len-- && (*buf++ = *str++) != '\n') ; } *buf = 0; } , w->id, i->p0, i->p1) < 0) { DPRINT("Could not delete item from list"); return 1; } *pi = i->wily-0.13.42/tools/old/wilytoys/reader2/reader.h000064402366570000012000000026331033320152300212600ustar00ozstaff00004330000002/* * reader.h - declarations for a mail/news reader toolkit for wily. */ #ifndef READER_H #define READER_H /* * We support two kinds of window - a list (mailboxes, newsgroups, subject lines) * and an article display. There can be more than one instance of each. */ typedef enum _rdWinType { rdList, rdArticle } rdWinType; /* * This makes the messages clearer */ enum { IsTag = 0, IsBody = 1 }; typedef struct _rdWin rdWin; typedef struct _rdItem rdItem; typedef struct _rdItemRange rdItemRange; typedef struct _Msgq Msgq; extern int rdMultiList; extern int rdMultiArt; struct _rdItem { ulong p0, p1; /* address of this item in the window. */ struct _rdItem *next; /* next item in the list */ }; struct _rdItemRange { int first, last; /* inclusive */ rdItem *i0, *i1; }; struct _rdWin { rdWinType wintype; int user; /* user info */ void *userp; /* ditto */ Id id; struct _rdWin *next; /* list storage */ char *title; /* what we think the title of this window is */ ulong taglen; /* length of tag, in characters */ ulong bodylen; /* length of body, in characters */ Msg *m; /* message from wily */ char *body; /* UTF text of an article window */ rdItem *items; /* The items in a list */ int protect; /* The user is writing to this window */ }; extern rdWin *windows; extern Mqueue *wilyq; extern Bool rdAlarmEvent; #endif /* !READER_H */ wily-0.13.42/tools/old/wilytoys/reader2/membuf.c000064402366570000012000000052611033320152300212640ustar00ozstaff00004330000002/* * membuf.c - custom memory handler for mail messages. * XXX - This handler does *not* return buffers aligned for * anything larger than a byte! */ #include "mailheaders.h" #include #define MINBUF 512 /* limit for splitting */ static membuf *busy, *freed; static void *find_free(size_t len); /* * allocate a new buffer. */ void *mb_alloc(size_t len) { void *ptr; membuf *m; assert(len); if ((ptr = find_free(len))) return ptr; m = salloc(sizeof(*m)); m->len = len; m->start = salloc(len); m->end = m->start + len; m->next = busy; busy = m; return m->start; } /* * grab an existing buffer from the free list, if there is one * large enough. */ static void * find_free(size_t len) { membuf **pm = &freed; membuf **smallest = 0; membuf *m, *nm; assert(len); for (;*pm; pm = &((*pm)->next)) if ((*pm)->len >= len && (!smallest || (*pm)->len < (*smallest)->len)) smallest = pm; if (smallest == 0) return 0; /* no buffer big enough */ m = *smallest; /* found one - big enough to split? */ if (m->len > len+MINBUF) { /* yep */ nm = salloc(sizeof(*nm)); nm->len = len; nm->start = m->start; nm->len = len; nm->end = (m->start += len); m->len -= len; nm->next = busy; busy = nm; return nm->start; } /* nope - remove this one from the free queue, and return it */ *smallest = m->next; m->next = busy; busy = m; return m->start; } /* * A previously allocated buffer contains more than one mail message. * break the buffer into two, at the point indicated. */ void mb_split(void *old, void *new) { membuf *m, *nm; size_t len; assert(old); assert(new); assert (old < new); len = (char *)new - (char *)old; for (m = busy; m; m = m->next) if (m->start == old) break; assert(m); assert(m->len >= len); if (m->len == len) return; nm = salloc(sizeof(*nm)); nm->len = m->len - len; nm->end = m->end; m->end = nm->start = new; nm->len = m->len - len; m->len = len; nm->next = m->next; m->next = nm; } /* * discard the memory buffer, by placing it on the free list. */ void mb_free(void *ptr) { membuf **m; membuf *p; assert(ptr); for (m = &busy; *m; m = &((*m)->next)) if ((*m)->start == ptr) break; assert(*m); p = *m; *m = p->next; /* remove from the busy list */ /* search the free list for an adjacent buffer. If we find one, combine the two. */ for (m = &freed; *m; m = &((*m)->next)) { if ((*m)->end == p->start) { (*m)->end = p->end; (*m)->len += p->len; free(p); return; } if ((*m)->start == p->end) { (*m)->start = p->start; (*m)->len += p->len; free(p); return; } } /* didn't find one - just append the new buffer onto the free list. */ *m = p; p->next = 0; return; } wily-0.13.42/tools/old/wilytoys/reader2/membuf.h000064402366570000012000000005371033320152300212720ustar00ozstaff00004330000002/* * memory.h - defs for message memory handling. */ #ifndef MEMBUF_H #define MEMBUF_H typedef struct _membuf membuf; struct _membuf { char *start, *end; /* end points to first byte after buffer */ size_t len; struct _membuf *next; }; void *mb_alloc(size_t); void mb_free(void *); void mb_split(void *old, void *new); #endif /* !MEMBUF_H */ wily-0.13.42/tools/old/wilytoys/reader2/proto.h000064402366570000012000000032651033320152300211630ustar00ozstaff00004330000002#ifndef PROTO_H #define PROTO_H /* getmsg.c */ rdWin *getActiveWin(void); /* reader.c */ void closeWin(rdWin *w); void freeWin(rdWin *w); rdWin *getArtWin(int user, void *userp, char *title, char *tools, char *text, rdWin *oldwin); rdWin *getListWin(int user, void *userp, char *title, char *tools, rdWin *oldwin, char **items); void highlightItem(rdWin *w, rdItemRange r); void warpToWin(rdWin *w); rdItemRange itemNumber(rdWin *w, ulong p0, ulong p1); int rdAddItem(rdWin *w, char *text); int rdChangeItem(rdWin *w, int item, char *text); int rdDelItem(rdWin *w, int item); void rdGotoWin(rdWin *w); void rdInclude(rdWin *w, char *str, size_t len); void rdSetMulti(int list, int art); void rdSetRescanTimer(int secs); rdWin *readerLoading(int user, void *userp, int isart, char *title); int readerInit(); int readerMainLoop(void); rdWin *userpWin(void *ptr); void winReflectCmd(rdWin *w, char *cmd, char *arg); rdWin *getBlankListWin(int user, void *userp); rdWin *getBlankArtWin(int user, void *userp); int setWinUser(rdWin *w, int user, void *userp); int setWinTitle(rdWin *w, char *title); int setWinTools(rdWin *w, char *tools); int setWinList(rdWin *w, char **items); int setWinArt(rdWin *w, char *art); /* reader clients: mail.c, news.c */ void user_cmdArt(rdWin *w, char *cmd, ulong p0, ulong p1, char *arg); void user_cmdList(rdWin *w, char *cmd, ulong p0, ulong p1, rdItemRange items, char *arg); void user_listSelection(rdWin *w, rdItemRange r); void user_delWin(rdWin *w); #ifdef WILYMAIL_H /* mail.c */ void dorescan(void); #endif /* utils.c */ ulong atoul(char *str); char *sstrdup(char *str); /* addr.c */ void parseaddr(char *addr, int len, char **email, char **name); #endif /* !PROTO_H */ har *title, char *tools, char *text, rdWin *oldwin); rdWin *getListWin(int user, void *userp, char *title, char *tools, rdWin *oldwin, char **items); void highlightItem(rdWin *w, rdItemRange r); void warpToWin(rdWin *w); rdItemRange itemNumber(rdWin *w, ulong p0, ulong p1); int rdAddItem(rdWin *w, char *text); int rdChangeItem(rdwily-0.13.42/tools/old/wilytoys/README000064402366570000012000000110151033320152300171730ustar00ozstaff00004330000002These files are a few toys that I thought I would share with other people. They're not at all polished, and one of them was only just finished today, but hey - that's life on the edge. What is here: - working wcat to shove files into wily. - filter to convert man pages into something pretty and readable. - some scripts to view HTML web pages with wily. - a couple of useful wily wrapper scripts. What you need: - perl. 4.036 is what I use, but you might get away with v5. - Expect, if you want to be able to download web pages. Actually, there are plain perl scripts around on the net to do this, but I couldn't get the damn things to work on my machine, and I was in a hurry. I recommend trying one of the existing perl things (get_url, etc.) before installing Expect, if you haven't already got it. - the fonts from Matty's 9term distribution (if you want pretty man pages). - wily 0.98. - luck. Major Credit where credit is due: - The Perl scripts used for converting HTML files into something vaguely readable is by James R. Davis. I grabbed it from the web, and made a few minor changes to make it function as a wily browser, but the proper work's all James'. To build wcat: - Fiddle with the Makefile, so that it can find your wily distribution. - make all. If you want, you might want to bodge ./make, and put it somewhere where wily can find it. I use it to mangle the output of Sun's ANSI compiler into wily-style file:line references. There isn't a lot of point including it here, except that perl allows you to see each error message as it appears, with minimal buffering. there's also a "diff" script which does much the same thing. Well, I like it... The Makefile also builds "bold". We'll come back to that shortly. Man page viewer: This is an horrendous cheat, as suggested by either myself or gary/matty a while ago in the list (I forget who). Basically, it uses the large Unicode character set to have normal, italic and bold versions of the same characters within your set, and just displays the appropriate one according to the output of nroff/man. This required a little bit of setting up and munging around with fonts. These are my notes which I scrawled at the time that I got this going: Unpacked matty's font distribution. ran mkfontdir in the bdf directory. Selected a font I liked using xfontsel(1). Created bdf/fonts.alias, containing the alias "wilynormal" for this preferred font. Put wilynormal as the first font in smk.9.font (which I'd copied from prop.9.font). Add the font directory to the X server's font path with xset fp+ /home/steve/lib/fonts/bdf Changed bin/acme to have smk.9.font and fixed.9.font args. Checked all was ok by viewing src/9/hacked/9term/utf.test I've included my font files and the fonts.alias file so that you can see what I've done. Note that the extra character sets appear in the 0x4000-odd range, and that this is hard-coded into the source for "bold.c". The man page viewer ("man") takes standard man arguments, and passes the output of normal man through bold, to get the pretty fonts, and then into wcat to display the file in wily. It doesn't get everything right, but it's good enough for what I use it for. You can also B2B1 on filename.1 files to view them directly. HTML web browser: This has three parts. The first is fetchurl, a quick Expect script that will grab the output of a telnet connection to some web server. Use a proper perl program to do this if you can get one. For starters, mine only handles http URLs. The second part is the driver, http. This takes as an argument a normal URL, e.g. "http http://www.w3.org". It uses fetchurl to grab the file, and then passes it to the final part, html2wily. Html2wily does the clever bit of generating readable ASCII out of the HTML. The bit I've added is to support URLs within the file: given a URL such as Some Text, you end up with this: [_u1][Some Text]. At the bottom of the file, you see: [_u1][http http://www.foo.com/file.html]. The idea is that you can B3 on the _u1 to move between the highlighted text and the URL that goes with it. If you decide to follow the URL, you double-click beside the [ or ], to select the whole command, and B2 it. The process then begins again. Incidentally, there are a few broken bits in this, especially where partial URLs are converted into full ones, but that's life. This thing took about 2 hours to write, this morning. Hope this of some use... Steve Kilbane, 12 March 1996. wily-0.13.42/tools/old/wilytoys/prop.9.font000064402366570000012000000036121033320152300203360ustar00ozstaff0000433000000216 13 0x0000 0x00FF lubs14 0x0100 0x017E lucm.latineur.9 0x0180 0x01F0 matty.latinext.9 0x0250 0x02E9 lucm.ipa.9 0x0300 0x0308 matty.gendiacritics.9 0x0370 0x0372 matty.greekpunc.9 0x0386 0x03F5 lucm.greek.9 0x0400 0x0475 misc.cyrillic.9 0x2000 0x2044 lucm.genpunc.9 0x2070 0x208E lucm.supsub.9 0x20A0 0x20AA lucm.currency.9 0x2100 0x2138 matty.letterlike.9 0x2190 0x21EA misc.arrows 0x2200 0x227F matty.math1 0x2280 0x22F1 matty.math2 0x2300 0x232C matty.tech 0x2500 0x257F matty.chart 0x2580 0x2595 matty.blocks 0x25a0 0x25ee matty.geometric 0x2600 0x266F misc.ding 0x3000 0x303f jis.jis3000.16 0x3041 0x309e jis.hiragana.16 0x30a1 0x30fe jis.katakana.16 0x4e00 0x4fff jis.jis4e00.16 0x5000 0x51ff jis.jis5000.16 0x5200 0x53ff jis.jis5200.16 0x5400 0x55ff jis.jis5400.16 0x5600 0x57ff jis.jis5600.16 0x5800 0x59ff jis.jis5800.16 0x5a00 0x5bff jis.jis5a00.16 0x5c00 0x5dff jis.jis5c00.16 0x5e00 0x5fff jis.jis5e00.16 0x6000 0x61ff jis.jis6000.16 0x6200 0x63ff jis.jis6200.16 0x6400 0x65ff jis.jis6400.16 0x6600 0x67ff jis.jis6600.16 0x6800 0x69ff jis.jis6800.16 0x6a00 0x6bff jis.jis6a00.16 0x6c00 0x6dff jis.jis6c00.16 0x6e00 0x6fff jis.jis6e00.16 0x7000 0x71ff jis.jis7000.16 0x7200 0x73ff jis.jis7200.16 0x7400 0x75ff jis.jis7400.16 0x7600 0x77ff jis.jis7600.16 0x7800 0x79ff jis.jis7800.16 0x7a00 0x7bff jis.jis7a00.16 0x7c00 0x7dff jis.jis7c00.16 0x7e00 0x7fff jis.jis7e00.16 0x8000 0x81ff jis.jis8000.16 0x8200 0x83ff jis.jis8200.16 0x8400 0x85ff jis.jis8400.16 0x8600 0x87ff jis.jis8600.16 0x8800 0x89ff jis.jis8800.16 0x8a00 0x8bff jis.jis8a00.16 0x8c00 0x8dff jis.jis8c00.16 0x8e00 0x8fff jis.jis8e00.16 0x9000 0x91ff jis.jis9000.16 0x9200 0x93ff jis.jis9200.16 0x9400 0x95ff jis.jis9400.16 0x9600 0x97ff jis.jis9600.16 0x9800 0x99ff jis.jis9800.16 0x9a00 0x9bff jis.jis9a00.16 0x9c00 0x9dff jis.jis9c00.16 0x9e00 0x9fff jis.jis9e00.16 0xe000 0xe05f matty.tengwar.9 0xfee0 0xff5e lucm.latin1.9 0xfffd 0xfffd pelm.fffd.9 wily-0.13.42/tools/old/wilytoys/bold.c000064402366570000012000000024001033320152300173750ustar00ozstaff00004330000002#include #include #include #include #include /* * XXX - current assumes that we won't be in mid-sequence when EOF is reached. */ #define MAGICBOLD 0x4000 #define MAGICITALIC 0x4100 #define MAGICITALICBOLD 0x4200 static long charset = MAGICITALIC; static void boldchar(int c, int overstrike) { char str[4], *s = str; Rune r = c + charset; switch (runetochar(s, &r)) { case 3: putchar(*s++); case 2: putchar(*s++); case 1: putchar(*s++); } } int main(int argc, char *argv[]) { int i = 0, b = 0,c; int state = 0; int outchar; int os = 0; while ((c = getopt(argc, argv, "ib")) != EOF) { switch (c) { case 'b': b++; break; case 'i': i++; break; default: exit(1); } } charset = b&&i? MAGICITALICBOLD : b? MAGICBOLD : MAGICITALIC; while ((c = getchar()) != EOF) { switch (state) { case 0: if (c == '_') state++; else putchar(c); break; case 1: if (c == 0x8) /* backspace */ state++; else { putchar('_'); putchar(c); state = 0; } break; case 2: boldchar(c,0); state = 0; break; default: fprintf(stderr,"We're screwed!\n"); exit(1); } } if (state) fprintf(stderr,"File was truncated!\n"); return 0; } 0x4200 static long charset = MAGICITALIC; static void boldchar(int c, int overstrike) { char str[4], *s = str; Rune r = c + charset; switch (runetochar(s, &r)) { case 3: putchar(*s++); case 2: putchar(*s++); case 1: putchar(*s++); } } int maiwily-0.13.42/tools/old/wilytoys/reader/000075502366570000012000000000001033320152300175575ustar00ozstaff00004330000002wily-0.13.42/tools/old/wilytoys/reader/solaris.c000064402366570000012000000036401033320152300214020ustar00ozstaff00004330000002/* * solaris.c - the system-dependent routines for Solaris 2. */ #include "headers.h" #include "mbox.h" #include #include /* * load_mbox(mbox,rescan) - open the named file, and make it available * as a block of memory between mbox_start and mbox_end. If rescan * is true, we've already the mbox, and we want to see if there're more * messages in the file. */ int load_mbox(mMbox *mbox, int rescan) { const char *mode = mbox->readonly? "r" : "r+"; FILE *fp = fopen(mbox->name,mode); char *addr = 0; size_t len; struct stat st; if (fp == 0) goto broken; if (stat(mbox->name,&st) == -1) goto broken; if (rescan) { if (st.st_size < mbox->size) { fprintf(stderr,"%s corrupt\n", mbox->name); goto broken; } if (st.st_mtime == mbox->mtime) { fclose(fp); mbox->mbox_start = mbox->mbox_end = 0; return 0; } len = (size_t)(st.st_size - mbox->size); fseek(fp, mbox->size, SEEK_SET); } else len = (size_t)st.st_size; mbox->size = st.st_size; mbox->mtime = st.st_mtime; if ((addr = mb_alloc(len+1)) == 0) goto broken; addr[len] = 0; /* handy for debugging */ if (fread(addr, (size_t)1, len, fp) != len) goto broken; fclose(fp); mbox->mbox_start = addr; mbox->mbox_end = mbox->mbox_start + len; return 0; broken: if (addr) free(addr); fclose(fp); return 1; } /* we failed to load the mbox. Check that it exists, if we need it to. */ int empty_mbox(mMbox *box, const char *filename, int mustexist) { int readable = !access(filename, R_OK); int exists = !access(filename, F_OK); if (readable || (exists && !readable) || (mustexist && !exists)) { fprintf(stderr,"%s not %s\n",filename, readable? "read" : exists? "readable" : "found"); return 1; } /* file doesn't exist, but that's ok - it doesn't need to in this case, so create an empty mbox */ box->size = 0; box->mbox_start = box->mbox_end = 0; /* XXX - likely to flush out some bugs */ return 0; } wily-0.13.42/tools/old/wilytoys/reader/Makefile000064402366570000012000000012541033320152300212210ustar00ozstaff00004330000002W = /home/steve/src/9/orig/wily-0.9.5 O = /home/steve/src/9/orig/orig-0.9.5 CFLAGS = -Xc -g -DUSE_SELECT CPPFLAGS = -I. -I$W/include -I$W LDFLAGS = -L$W/libmsg -L$W/libXg LDLIBS = -lmsg -lXg -lnsl -lsocket PATCHES = includepatches libmsgpatches wilypatches winpatches PROGS = mreader browser OBJS = getmsg.o mail.o reader.o membuf.o mbox.o solaris.o utils.o all: $(PROGS) mreader: $(OBJS) $(LINK.c) -o $@ $(OBJS) $(LDLIBS) clean: $(RM) *.o core nuke: $(RM) *.o core $(PROGS) cleanpatches: $(RM) $(PATCHES) patches: $(PATCHES) includepatches: makepatch include > $@ libmsgpatches: makepatch libmsg > $@ wilypatches: makepatch wily > $@ winpatches: makepatch win > $@ wily-0.13.42/tools/old/wilytoys/reader/headers.h000064402366570000012000000006061033320152300213450ustar00ozstaff00004330000002#ifndef RD_HEADERS_H #define RD_HEADERS_H #include #include #include #include #include #include #include #ifdef __STDC__ char *strdup(char *); #endif #include #include #include #include #include "reader.h" #include "proto.h" #include "membuf.h" #endif /* RD_HEADERS_H */ wily-0.13.42/tools/old/wilytoys/reader/README000064402366570000012000000062051033320152300204420ustar00ozstaff00004330000002USAGE Invoke with "mreader [-ma] mailboxname". The "-ma" option allows you to have multiple article windows open at once. By default, it only has the one article window open, because it's easier to find where the article window is, once you've positioned it. Unfortunately, this means that you don't get to see the article you're replying to. To fix this, there's a "multiart" command, which toggles this value from within the reader. First window to appear is the list window. It shows all the articles from the given mailfile, one per line. The line contains the From and Subject fields, but it's currently chopped to make things look nicer. You open an article by B3'ing on its subject line. What else? Commands supported: exit exit without doing anything to the mailfile. quit save any changes to the mailfile before quitting. delete delete the selected article. "selected" means the article which has dot in its subject line. This means you can click on the subject line with either B1 or B3, and then click on delete. If you sweep more than one subject line, then all the affected articles are deleted. Of course, if you click on delete within an article window, that article is the one that is deleted. Delete doesn't actually do anything except mark the article for deletion, and puts a "D" before at the start of the subject line. undelete reverses delete. comp compose a new message. You get a blank article window with From, To and Subject fields. Don't delete them. reply Reply to the article (article is selected in the same fashion, i.e. B1/B3 list window, or just the article that the reply cmd was executed in). The To field is filled in from the From field. You can use "inc" or "incall" to include the text of the article you're replying to. abort junk a comp/reply article without sending it. deliver post a complete comp/reply article (well, feed it to sendmail). savefile sets the name of the file that "save" writes to. save appends the current message into the savefile. Creates the file if it doesn't exist. You can also sweep several articles in the list window, then click on save (also in the list window), and it'll save all of them. multiart toggles the "only one article window at once" flag. This is handy for viewing several articles or reading one article while replying to another. allheaders toggles whether all header fields are displayed. By default, a particular set are suppressed (the set is in the array hidden_hdrs[] in mail.c). inc [n] Includes a message into the current position of the current message. If you specify a message number, it'll include that message. incall Same as inc, but will include the headers of the message, too. commit Write changes back to the mailbox, but don't actually quit. rescan Load any new mail that has arrived. Doesn't write any changes done so far, though. Bugs Probably vast numbers of them... Unlike most windows, it current has the tools *before* the window label. This is because of the broken tags problem. Right now, I'm cheating, and inserting the tools at the start of the tag, instead of the end - that seems to work... wily-0.13.42/tools/old/wilytoys/reader/Credits000064402366570000012000000002231033320152300210740ustar00ozstaff00004330000002Bjorn Helgaas change of FILENAME_MAX to MAXPATHLEN arnold@infographix.infographix.com (Arnold Robbins) Various suggestions. wily-0.13.42/tools/old/wilytoys/reader/getmsg.c000064402366570000012000000006061033320152300212130ustar00ozstaff00004330000002/* * getmsg.c - handle message reception from wily. */ #include "headers.h" rdWin * getActiveWin(void) { rdWin *w; Msg *m; Id id; while ((m = mq_next(wilyq, 0)) == 0) { if (rdAlarmEvent) { dorescan(); rdAlarmEvent = false; continue; } return 0; } id = msg_id(m); for (w = windows; w; w = w->next) if (id == w->id) { w->m = m; return w; } return 0; } wily-0.13.42/tools/old/wilytoys/reader/mail.c000064402366570000012000000326041033320152300206520ustar00ozstaff00004330000002#include "headers.h" #include "mbox.h" #include "mail.h" static void build_msg_list(); static char *getarttext(mMsg *m); mWin *allocMWin(int kind, int num); void freeMWin(mWin *w); mWin *findMWin(void *ptr); int artDisplayed(rdWin *w, int n); void mDelete(rdWin *w, int first, int last, char *arg); void mUndelete(rdWin *w, int first, int last, char *arg); void mComp(rdWin *w, int first, int last, char *arg); void mExit(rdWin *w, int first, int last, char *arg); void mQuit(rdWin *w, int first, int last, char *arg); void mReply(rdWin *w, int first, int last, char *arg); void mAbort(rdWin *w, int first, int last, char *arg); void mDeliver(rdWin *w, int first, int last, char *arg); void mSavefile(rdWin *w, int first, int last, char *arg); void mSave(rdWin *w, int first, int last, char *arg); void dodeliver(rdWin *w, char *filename); void mMultiart(rdWin *w, int first, int last, char *arg); void mAllheaders(rdWin *w, int first, int last, char *arg); void mIncludeall(rdWin *w, int first, int last, char *arg); void mInclude(rdWin *w, int first, int last, char *arg); void doinclude(rdWin *w, int first, int last, char *arg, int all); void mCommit(rdWin *w, int first, int last, char *arg); void mRescan(rdWin *w, int first, int last, char *arg); mMbox *mbox; static char mboxname[MAXPATHLEN]; mWin *mwindows; mWin *listwin; static char **msgs; static char *savefile; static int multiart = 0; static int show_all_headers = 0; /* * These are headers that we'd rather not see when the message gets displayed. */ static char *hidden_hdrs[] = { "Content-Length", "Content-Transfer-Encoding", "Content-Type", "In-Reply-To", "Message-Id", "Mime-Version", "Original-Sender", "Received", "Sender", "Status", "X-Lines", "X-Mailer", "X-Newsreader" }; static int nhidden_hdrs = sizeof(hidden_hdrs)/sizeof(hidden_hdrs[0]); int main(int argc, char *argv[]) { mWin *mw; int ma = 0; int mustexist = 0; int timer = RESCAN_TIME; fflush(stdout); if (argc >=2 && strcmp(argv[1], "-ma")==0) { ma = 1; argc--; argv++; } multiart = ma; if (argc >= 2) { mustexist = 1; strcpy(mboxname, argv[1]); timer = 0; /* don't rescan named mboxes */ } else { char *u = getenv("USER"); if (!u || !*u) { fprintf(stderr,"Need $USER to find mailbox name\n"); exit(1); } sprintf(mboxname,"%s/%s", SPOOLDIR, u); } savefile = getenv(SAVEFILE_ENV); if (!savefile || !*savefile) { char s[MAXPATHLEN]; char *h; if ((h = getenv("HOME")) == 0 || !*h) savefile = sstrdup("mbox"); /* what planet are we on? */ else { sprintf(s,"%s/mbox",h); savefile = sstrdup(s); } } else savefile = sstrdup(savefile); set_hdr_filter(nhidden_hdrs, hidden_hdrs); if ((mbox = read_mbox((const char *)mboxname, 0, mustexist)) == 0) { perror(mboxname); exit(1); } mw = listwin = allocMWin(mMsgList, 0); build_msg_list(); if (readerInit(0, (char *)mw, mboxname, msgs, 0, ma, 0)) exit(1); rdSetRescanTimer(timer); readerMainLoop(); exit(0); } mWin * allocMWin(int kind, int num) { mWin *w = salloc(sizeof(*w)); mWin **p = &mwindows; w->kind = kind; w->msg = (kind == mDispArt || kind == mCompArt)? num : -1; w->mbox = mbox; w->next = 0; while (*p) p = &((*p)->next); *p = w; return w; } void freeMWin(mWin *w) { mWin **p = &mwindows; while (*p != w) p = &((*p)->next); *p = w->next; free(w); } mWin * findMWin(void *ptr) { mWin *mw = mwindows; while (mw && (mWin *)ptr != mw) mw = mw->next; return mw; } static void chkhdr(mString *s, int *len, char **rest) { int l; *rest = ""; /* default */ if (s == 0) { *len = 0; return; } l = s->s1 - s->s0; if (l > 20) { l = 20; *rest = "..."; } else if (l > 0) l--; /* skip newline */ *len = l; } static void build_msg_list(void) { int n; mMsg *m; ulong l; int lfrom, ldate, lsubject; char *rfrom, *rdate, *rsubject; mString *from; mString *date; mString *subject; int dc; if (msgs) for (n = 0; msgs[n]; n++) free(msgs[n]); msgs = (char **)srealloc(msgs, (mbox->nmsgs+1) * sizeof(char *)); for (n = 0; n < mbox->nmsgs; n++) { m = mbox->msgs[n]; dc = m->deleted? 'D' : ' '; from = m->from; date = m->date; subject = m->subject; chkhdr(from, &lfrom, &rfrom); chkhdr(date, &ldate, &rdate); chkhdr(subject, &lsubject, &rsubject); l = lfrom + ldate + lsubject + 10; msgs[n] = salloc(l); sprintf(msgs[n],"%c%d %.*s%s %.*s%s", dc, n+1, lfrom, from->s0, rfrom, lsubject, subject->s0, rsubject); } msgs[n] = 0; return; } void user_listSelection(rdWin *w, rdItemRange range) { static char title[300]; /* XXX standard silly guess */ int n = range.first; mMsg *m = mbox->msgs[n]; mString *from = m->from; mWin *mw; char *text; if (artDisplayed(w, n)) return; mw = allocMWin(mDispArt,n); sprintf(title," %s/%d", mbox->name, n+1); title[50] = 0; /* XXX - to make sure it's not too long. */ text = getarttext(m); getArtWin(n, mw, title, text, 0, 0, 0); } static char * getarttext(mMsg *m) { static char *text; static size_t textlen; size_t len; mString *body; body = &m->whole; len = body->s1 - body->s0; if (len >= textlen) { textlen = len + 1; text = srealloc(text, textlen); } if (show_all_headers) { memcpy(text, body->s0, len); text[len] = 0; } else { char *p = text; int n, l; mHdr *h; for (n = 0; n < m->nhdrs; n++) { h = m->hdrs[n]; if (h->hide) continue; l = h->value.s1 - h->name.s0; memcpy(p, h->name.s0, l); p += l; } *p++ = '\n'; /* make sure there's a separating line */ body = &m->body; len = body->s1 - body->s0; memcpy(p, body->s0, len); p[len] = 0; } return text; } int artDisplayed(rdWin *w, int n) { mWin *mw; for (mw = mwindows; mw; mw = mw->next) if (mw->kind == mDispArt && mw->msg == n) if ((w = userpWin(mw))) { rdGotoWin(w); return 1; } return 0; } static struct mCmd mcmds[] = { { "quit", MCANY, MNOARG, mQuit }, { "exit", MCANY, MNOARG, mExit }, { "reply", MCNOTCOMP, MARG, mReply }, { "delete", MCNOTCOMP, MARG, mDelete }, { "undelete", MCMSGLIST, MARG, mUndelete }, { "comp", MCMSGLIST, MNOARG, mComp }, { "abort", MCCOMPART, MARG, mAbort }, { "deliver", MCCOMPART, MARG, mDeliver }, { "savefile", MCANY, MARG, mSavefile }, { "save", MCANY, MARG, mSave }, { "multiart", MCANY, MARG, mMultiart}, { "allheaders", MCANY, MARG, mAllheaders}, { "inc", MCCOMPART, MARG, mInclude}, { "incall", MCCOMPART, MARG, mIncludeall}, { "commit", MCANY, MNOARG, mCommit }, { "rescan", MCANY, MNOARG, mRescan }, { 0, 0, 0 } }; void user_cmdList(rdWin *w, char *cmd, ulong p0, ulong p1, rdItemRange r, char *arg) { int c; fflush(stdout); for (c = 0; mcmds[c].cmd; c++) if (strcmp(cmd, mcmds[c].cmd) == 0) break; if (mcmds[c].cmd == 0) { fflush(stdout); winReflectCmd(w,cmd,arg); return; } /* check that the command is valid in a list like this */ if ((mcmds[c].context & MCMSGLIST) == 0) { fprintf(stderr,"%s: only valid within the message list\n", cmd); return; } /* check we've been given an appropriate argument */ if (mcmds[c].req == MARG && r.first == -1) { fprintf(stderr,"%s: needs a message\n", cmd); return; } (*mcmds[c].fn)(w, r.first, r.last, arg); return; } void user_cmdArt(rdWin *w, char *cmd, ulong p0, ulong p1, char *arg) { int c; mWin *mw; unsigned short context; fflush(stdout); for (c = 0; mcmds[c].cmd; c++) if (strcmp(cmd, mcmds[c].cmd) == 0) break; if (mcmds[c].cmd == 0) { fflush(stdout); winReflectCmd(w,cmd,arg); return; } /* check that the command is valid in this window */ if ((mw = findMWin(w->userp)) == 0) { fprintf(stderr,"%s: invalid window argument\n",cmd); return; } context = (mw->kind == mDispArt)? MCDISPART : MCCOMPART; if ((mcmds[c].context & context) == 0) { fprintf(stderr,"%s: not valid in that window\n", cmd); return; } (*mcmds[c].fn)(w, mw->msg, mw->msg, arg); return; } void mDelete(rdWin *w, int first, int last, char *arg) { mWin *mw; rdWin *ow; int n, i; rdWin *lp = userpWin(listwin); for (i = first; i <= last; i++) { n = i; if ((mw = findMWin(w->userp)) == 0) return; if (mw->mbox->msgs[n]->deleted) continue; mw->mbox->msgs[n]->deleted = 1; *msgs[n] = 'D'; rdChangeItem(lp, n, msgs[n]); mw->mbox->ndel++; if (mw->kind != mDispArt) /* might be the msg list */ for (mw = mwindows; mw; mw = mw->next) if (mw->kind == mDispArt && mw->msg == n) break; if (mw) { if ((ow = userpWin(mw))) /* this msg is displayed; remove the pane */ closeWin(ow); freeMWin(mw); } } return; } void mUndelete(rdWin *w, int first, int last, char *arg) { mWin *mw; int n, i; rdWin *lp = userpWin(listwin); for (i = first; i <= last; i++) { n = i; if ((mw = findMWin(w->userp)) == 0) return; if (!mw->mbox->msgs[n]->deleted) continue; mw->mbox->msgs[n]->deleted = 0; mw->mbox->ndel--; *msgs[n] = ' '; rdChangeItem(lp, n, msgs[n]); } return; } void mReply(rdWin *w, int first, int last, char *arg) { int n = first; /* last ignored */ mWin *mw = allocMWin(mCompArt, n); char *title = "Reply abort deliver "; static char body[300]; /* XXX */ mString *from = mbox->msgs[n]->from; mString *subject = mbox->msgs[n]->subject; int lfrom, lsubject; char *me = getenv("USER"); char *re = "Re: "; if (!me || !*me) me = ""; lfrom = (from->s1 - from->s0); /* include newline */ lsubject = (subject->s1 - subject->s0); if (lsubject > 4 && strncmp(subject->s0, re, 4)==0) re = ""; sprintf(body,"From: %s\nTo: %.*sSubject: %s%.*s\n", me, lfrom, from->s0, re, lsubject, subject->s0); if (getArtWin(n, mw, title, body, 0, 0, 1)) return; /* XXX - should clear up */ return; } void mAbort(rdWin *w, int first, int last, char *arg) { mWin *mw; if ((mw = findMWin(w->userp)) == 0) return; if (mw->kind != mCompArt) return; fprintf(stderr,"Message aborted\n"); closeWin(w); freeMWin(mw); return; } void mDeliver(rdWin *w, int first, int last, char *arg) { mWin *mw; char *filename = tmpnam((char *)0); if ((mw = findMWin(w->userp)) == 0) return; if (mw->kind != mCompArt) return; rdBodyToFile(w, filename); dodeliver(w,filename); return; } void mQuit(rdWin *w, int first, int last, char *arg) { update_mbox(mbox); mExit(w, first, last, arg); } void mExit(rdWin *w, int first, int last, char *arg) { mWin *mw; rdWin *rw; /* close msg windows first */ for (mw = mwindows; mw; mw = mw->next) if (mw->kind == mCompArt || mw->kind == mDispArt) if ((rw = userpWin(mw))) closeWin(rw); for (mw = mwindows; mw; mw = mw->next) if (mw->kind != mCompArt && mw->kind != mDispArt) if ((rw = userpWin(mw))) closeWin(rw); exit(0); /* not actually needed - reader will exit for us */ } void mComp(rdWin *w, int first, int last, char *arg) { int n = first; /* last ignored */ mWin *mw = allocMWin(mCompArt, n); char *title = "Compose abort deliver "; static char body[300]; /* XXX */ char *me = getenv("USER"); if (!me || !*me) me = ""; sprintf(body,"From: %s\nTo: \nSubject: \n\n", me); if (getArtWin(n, mw, title, body, 0, 0, 1)) return; /* XXX - should clear up */ return; } void dodeliver(rdWin *w, char *filename) { static char cmd[100]; /* XXX another guess */ mWin *mw; if ((mw = findMWin(w->userp)) == 0) return; sprintf(cmd,"%s < %s", MTU, filename); fflush(stdout); system(cmd); closeWin(w); freeMWin(mw); return; } void mSavefile(rdWin *w, int first, int last, char *arg) { if (savefile) free(savefile); savefile = sstrdup(arg); } void mSave(rdWin *w, int first, int last, char *arg) { FILE *fp; mWin *mw; mMsg *m; mString *text; size_t len; int n; if (savefile == 0) { fprintf(stderr,"No savefile yet: 'savefile filename'\n"); return; } if ((fp = fopen(savefile,"a")) == 0) { perror(savefile); return; } if ((mw = findMWin(w->userp)) == 0) return; for (n = first; n <= last; n++) { m = mw->mbox->msgs[n]; text = &m->whole; len = text->s1 - text->s0; if (fwrite(text->s0, (size_t)1, len, fp) != len) perror("fwrite"); fputc('\n',fp); printf("Written message %d to %s\n", n+1, savefile); /* count from 1 */ } fflush(stdout); fclose(fp); } void mMultiart(rdWin *w, int first, int last, char *arg) { multiart = !multiart; rdSetMulti(0, multiart); } void mAllheaders(rdWin *w, int first, int last, char *arg) { show_all_headers = !show_all_headers; } void mInclude(rdWin *w, int first, int last, char *arg) { doinclude(w,first,last,arg,0); } void mIncludeall(rdWin *w, int first, int last, char *arg) { doinclude(w,first,last,arg,1); } void doinclude(rdWin *w, int first, int last, char *arg, int all) { mWin *mw; rdWin *ow; int msgnum; /* message we're going to include */ mMsg *m; mString *s; size_t len; int n; if ((mw = findMWin(w->userp)) == 0) return; if (mw->kind != mCompArt) return; msgnum = mw->msg; /* default value */ if (*arg) { if ((msgnum = atoi(arg)) == 0) { fprintf(stderr,"'%s' is an invalid message number\n", arg); return; } else { msgnum--; } } if (msgnum >= mw->mbox->nmsgs) { fprintf(stderr,"Only %d messages\n", mw->mbox->nmsgs); return; } m = mw->mbox->msgs[msgnum]; s = all? &(m->whole) : &(m->body); len = s->s1 - s->s0; rdInclude(w, s->s0, len); } void mCommit(rdWin *w, int first, int last, char *arg) { update_mbox(mbox); build_msg_list(); changeItems(userpWin(listwin), msgs, 0); } void dorescan(void) { mRescan((rdWin *)0, 0, 0, (char *)0); } void mRescan(rdWin *w, int first, int last, char *arg) { rdWin *lp = userpWin(listwin); int n = mbox->nmsgs; extend_mbox(mbox); if (n >= mbox->nmsgs) return; build_msg_list(); while (n < mbox->nmsgs) rdAddItem(lp, msgs[n++]); } { "undelete", MCMSGLIST, MARG, mUndelete }, { "comp", MCMSGLIST, MNOARG, mComp }, { "abort", MCCOMPART, MARG, mAbort }, wily-0.13.42/tools/old/wilytoys/reader/mail.h000064402366570000012000000032311033320152300206510ustar00ozstaff00004330000002/* * stuff needed for the mail client. * smk */ #include "headers.h" #include "mbox.h" typedef struct _mWin mWin; /* * We know of several different kinds of window: mailbox lists, * message lists, displayed articles and messages being composed. */ enum { mMboxList, /* list of mailboxes */ mMsgList, /* list of msgs in a mailbox */ mDispArt, /* a displayed article within a mailbox */ mCompArt /* a new article being composed */ }; struct _mWin { int kind; /* what kind of window it is */ int msg; /* message number, if mDispArt, or mCompArt */ mMbox *mbox; /* the message box we're associated with */ struct _mWin *next; }; /* * These are the commands that the mailer recognises, and the * contexts that they are valid. */ #define MCMSGLIST 01 #define MCDISPART 02 #define MCCOMPART 04 #define MCNOTCOMP (MCMSGLIST|MCDISPART) #define MCANY (MCMSGLIST|MCDISPART|MCCOMPART) #define MNOARG 00 #define MARG 01 struct mCmd { char *cmd; unsigned short context; unsigned short req; void (*fn)(rdWin *, int, int, char *); /* pane, first msg, last msg, arg */ }; /* * The following must be the pathname of a program capable * of taking a complete message on stdin, with no arguments, * and delivering it. */ #define MTU "/usr/lib/sendmail -t" /* * Where do you keep your mail? Don't currently support anything other * than directly-accessible mail files.... */ #define SPOOLDIR "/var/mail" /* * How long we wait before rescanning. */ #define RESCAN_TIME 60 /* * Environment variable and default filename for savefile's * default parameter. */ #define SAVEFILE_ENV "SAVEFILE" #define SAVEFILE_DEF "mbox" /* in $HOME, if possible */ wily-0.13.42/tools/old/wilytoys/reader/mbox.c000064402366570000012000000207321033320152300206740ustar00ozstaff00004330000002/* * mbox.c */ #include "headers.h" #include "mbox.h" #include #include #define COPYSIZE 8192 #define INCR 10 static mMbox *currmbox; /* current mbox being processed */ static mMsg *msg; /* current message */ static int nhdrs; /* number of current headers read so far. */ static int ahdrs; /* number of allocated hhdrs */ static mHdr **hdrs; /* current list */ static char **hiddenhdrs; /* names of header fields we don't want to see */ static int nhiddenhdrs; extern int load_mbox(mMbox *, int); static char *readhdrs(char *ptr); static void mkhdr(char *s0, char *s1); static void checkhide(mHdr *h); static int freehdrlist(int n, char **h); static void newmsg(char *s0); static char *readmsg(char *ptr); static int same(mString a, mString b); static int strsame(char *s, mString b); static void fillmsg(mMsg *msg); static void fillhdr(char *name, mMsg *msg, mString **ptr); static ulong getlength(void); static char *findend(char *ptr); static void freemsg(mMbox *mbox, int n); /* * readhdrs(ptr) - read the headers in a message, looking for * the terminating newline. Returns pointer to first char in body. */ static char * readhdrs(char *ptr) { char *nptr = ptr; /* invariant is that nptr pts to first char of next header. when it doesn't (nptr==\n), we've reached the blank line at then end of the hdrs */ while (*nptr != '\n') { if ((nptr = strchr(nptr,'\n')) == 0) panic("No newlines in readhrds()"); if (nptr[1]==' ' || nptr[1]=='\t') { /* multi-line hdr */ nptr++; continue; } else { mkhdr(ptr, ++nptr); ptr = nptr; continue; } } return ++nptr; /* skip blank line */ } /* * mkhdr(s0,s1) - add a new header to the current list. */ static void mkhdr(char *s0, char *s1) { size_t l; char *c = strchr(s0, ':'); mHdr *h; if (c == 0) panic("no colon in hdr"); if (nhdrs >= ahdrs) { ahdrs += INCR; l = ahdrs * sizeof(*hdrs); hdrs = (mHdr **)(hdrs? realloc(hdrs,l) : malloc(l)); if (hdrs == 0) panic("resizing hdr list"); } h = hdrs[nhdrs++] = (mHdr *)malloc(sizeof(*h)); if (h == 0) panic("adding new hdr"); h->name.s0 = s0; h->name.s1 = c++; while (*c == ' ' || *c == '\t') c++; h->value.s0 = c; h->value.s1 = s1; checkhide(h); } static void checkhide(mHdr *h) { int n; int l = h->name.s1 - h->name.s0; for (n = 0; n < nhiddenhdrs; n++) if (strncmp(hiddenhdrs[n], h->name.s0, l) == 0) { h->hide = 1; return; } h->hide = 0; /* default to showing header */ } int set_hdr_filter(int nhdrs, char **hdrs) { int n; (void)freehdrlist(nhiddenhdrs, hiddenhdrs); /* clear out existing list */ if ((hiddenhdrs = (char **)realloc((void *)hiddenhdrs, (nhdrs+1)*sizeof(char *))) == 0) return 1; for (n = 0; n < nhdrs; n++) if ((hiddenhdrs[n] = strdup(hdrs[n])) == 0) return freehdrlist(n, hiddenhdrs); hiddenhdrs[n] = 0; nhiddenhdrs = n; return 0; } static int freehdrlist(int n, char **h) { while (n--) free (*h++); return 1; } static void newmsg(char *s0) { size_t n; if (currmbox->nmsgs >= currmbox->amsgs) { currmbox->amsgs += INCR; n = currmbox->amsgs*sizeof(*currmbox->msgs); currmbox->msgs = (mMsg **)(currmbox->msgs? realloc(currmbox->msgs,n) : malloc(n)); if (currmbox->msgs == 0) panic("newmsg msg"); } msg = currmbox->msgs[currmbox->nmsgs++] = (mMsg *)malloc(sizeof(*msg)); if (msg == 0) panic("adding new msg"); memset(msg,0,sizeof(*msg)); msg->whole.s0 = s0; if ((hdrs = (mHdr **)malloc((ahdrs = INCR)*sizeof(*hdrs)))==0) panic("newmsg hdrs"); nhdrs = 0; } /* * readmsg(ptr) - read a complete message. Assumes we're already pointing * to the F of the "From " */ static char * readmsg(char *ptr) { char *nptr; ulong contentlength; newmsg(ptr); /* resets nhdrs and hdrs, too */ if ((nptr = strchr(ptr,'\n')) == 0) /* skip From line */ panic("From line broken"); nptr = readhdrs(nptr+1); msg->nhdrs = nhdrs; msg->hdrs = hdrs; msg->body.s0 = nptr; if ((contentlength = getlength()) == 0) nptr = findend(nptr); else nptr += contentlength; msg->whole.s1 = msg->body.s1 = nptr; fillmsg(msg); /* update from,date,subject fields */ mb_split(ptr, ++nptr); return nptr; } static int same(mString a, mString b) { if ((a.s1 - a.s0) != (b.s1 - b.s0)) return 0; return (strncmp(a.s0,b.s0,a.s1-a.s0) == 0); } static int strsame(char *s, mString b) { mString a; a.s0 = s; a.s1 = s + strlen(s); return same(a,b); } static void fillmsg(mMsg *msg) { fillhdr("From",msg,&msg->from); fillhdr("Date",msg,&msg->date); fillhdr("Subject",msg,&msg->subject); } static void fillhdr(char *name, mMsg *msg, mString **ptr) { int x; static mString empty; for (x = 0; x < msg->nhdrs; x++) if (strsame(name,msg->hdrs[x]->name)) { *ptr = &(msg->hdrs[x]->value); return; } /* Sigh. This sort of thing is very irritating. */ empty.s0 = empty.s1 = msg->whole.s1; *ptr = ∅ (void)fprintf(stderr,"Message does not have a '%s' header\n",name); } static ulong getlength(void) { int x; ulong l; for (x = 0; x < nhdrs; x++) if (strsame("Content-Length",hdrs[x]->name)) goto found; return 0; found: /* use sscanf magic to skip whitespace, and stop at end */ if (sscanf(hdrs[x]->value.s0,"%lu",&l) != 1 || l==0) return 0; if ((msg->body.s0+l+1) == currmbox->mbox_end) return l; /* spot on */ if ((msg->body.s0+l+5) >= currmbox->mbox_end) return 0; /* too long */ if (strncmp("\nFrom ",(msg->body.s0+l),6) == 0) return l; else return 0; } static char * findend(char *ptr) { for (; ptr+5 <= currmbox->mbox_end && strncmp("\nFrom ",ptr,6); ptr++) if ((ptr = strchr(ptr,'\n')) == 0) panic("findend"); if (ptr+5 > currmbox->mbox_end) return currmbox->mbox_end-1; else return ptr; } mMbox * read_mbox(const char *filename, int readonly, int mustexist) { char *ptr; extern int empty_mbox(mMbox *box, const char *filename, int mustexist); if ((currmbox = (mMbox *)malloc(sizeof(*currmbox))) == 0) return 0; memset(currmbox,0,sizeof(*currmbox)); currmbox->readonly = readonly; if ((currmbox->name = strdup(filename)) == 0) goto panic2; if (load_mbox(currmbox, 0) && empty_mbox(currmbox, filename, mustexist)) goto panic1; for (ptr = currmbox->mbox_start; ptr < currmbox->mbox_end; ) if ((ptr = readmsg(ptr)) == 0) goto panic1; return currmbox; panic1: free(currmbox->name); panic2: free(currmbox); return 0; } int extend_mbox(mMbox *mbox) { char *ptr; if (load_mbox(mbox,1)) return 1; for (ptr = mbox->mbox_start; ptr < mbox->mbox_end; ) if ((ptr = readmsg(ptr)) == 0) return 1; return 0; } /* * update_mbox(mbox) - write any changes back to the file. */ int update_mbox(mMbox *mbox) { static char lockname[MAXPATHLEN+1], newname[MAXPATHLEN+1]; int ntries, maxtries = 10; int fd, fd2; int x; struct stat st; int r = 0; int l; mMsg *m; if (mbox->readonly || mbox->ndel == 0) return 0; (void)sprintf(lockname,"%s.lock",mbox->name); (void)sprintf(newname,"%s.new",mbox->name); for (ntries = 0; ntries < maxtries; ntries++) { if (link(mbox->name,lockname) == 0) goto locked; sleep(1); } locked: if (stat(mbox->name,&st) == -1) goto broken; if (st.st_size < mbox->size) { fprintf(stderr,"Mail file corrupted - no changes made\n"); goto broken; } if ((fd = open(newname,O_RDWR|O_CREAT|O_TRUNC)) < 0 || fchmod(fd,st.st_mode) == -1) goto broken; for (x = 0; x < mbox->nmsgs; x++) { m = mbox->msgs[x]; if (m->deleted) continue; l = m->whole.s1 - m->whole.s0 + 1; if (write(fd,m->whole.s0,l) != l || write(fd,"\n",1) != 1) { fprintf(stderr,"write truncated, changes aborted\n"); goto broken; } } if (st.st_size > mbox->size) { static char buf[COPYSIZE]; if ((fd2 = open(mbox->name,O_RDONLY)) < 0 || lseek(fd2,mbox->size,SEEK_SET) == -1) { fprintf(stderr,"Can't open mbox for update!\n"); goto broken; } while ((l = read(fd2,buf,COPYSIZE)) > 0) if (write(fd,buf,l) != l) { fprintf(stderr,"Can't copy updated mbox\n"); close(fd2); goto broken; } close(fd2); } rename(newname,mbox->name); stat(mbox->name, &st); mbox->mtime = st.st_mtime; mbox->size = st.st_size; goto unlock; broken: r = 1; if (fd >= 0) close(fd); unlink(newname); unlock: unlink(lockname); /* now update the list of messages in the mbox */ for (l = x = 0; x < mbox->nmsgs; x++) { m = mbox->msgs[x]; if (m->deleted) freemsg(mbox,x); else mbox->msgs[l++] = m; } mbox->nmsgs = l; mbox->ndel = 0; return r; } static void freemsg(mMbox *mbox, int n) { mMsg *m = mbox->msgs[n]; int h; mbox->msgs[n] = 0; for (h = 0; h < m->nhdrs; h++) free(m->hdrs[h]); free(m->hdrs); mb_free(m->whole.s0); free(m); } wily-0.13.42/tools/old/wilytoys/reader/mbox.h000064402366570000012000000034601033320152300207000ustar00ozstaff00004330000002/* * mbox.h - definitions for mailbox-handling library. */ #ifndef MBOX_H #define MBOX_H #include typedef struct mstring mString; typedef struct mhdr mHdr; typedef struct mmsg mMsg; typedef struct mhdrline mHdrLine; typedef struct mmbox mMbox; struct mstring { /* can include several \n characters */ char *s0; /* first char in string */ char *s1; /* char after last newline */ }; struct mhdr { /* includes ws if hdr is multiple lines */ mString name; /* s1 points to colon */ mString value; /* s0 pts to first non-ws, s1 to after \n */ int hide; /* don't display if true */ }; /* name,s0,value.s2 gives whole header */ struct mmsg { int nhdrs; /* number of headers */ mHdr **hdrs; /* headers themselves */ mString *from; /* points to value fields from mHdrs */ mString *date; mString *subject; mString whole; /* All of the message (headers and body) */ mString body; /* All of the body (not including first blank line) */ int deleted; /* marked for deletion */ int read; /* if has been read */ ulong pos; /* origin in window, if it's been read before. */ }; struct mhdrline { char *s0,*s1; /* buffer containing accumulated text */ ulong p0, p1; /* positions in hdrw for this piece of text */ }; struct mmbox { char *mbox_start; /* area of memory that the mailbox is */ char *mbox_end; /* loaded into */ int nmsgs; /* number of messages */ int amsgs; /* size of msgs array */ mMsg **msgs; /* the messages themselves */ int ndel; /* number of deleted messages */ int readonly; time_t mtime; /* time it was last modified */ off_t size; /* how big it was, last time we checked */ char *name; /* the filename */ }; mMbox *read_mbox(const char *filename, int readonly, int mustexist); int extend_mbox(mMbox *mbox); int set_hdr_filter(int nhdrs, char **hdrs); #endif /* ! MBOX_H */ wily-0.13.42/tools/old/wilytoys/reader/utils.c000064402366570000012000000004521033320152300210640ustar00ozstaff00004330000002/* * general utilities... */ #include "headers.h" char * sstrdup(char *str) { char *s = salloc(strlen(str)+1); strcpy(s,str); return s; } void panic(const char *msg) { fprintf(stderr,"%s\n", msg); exit(1); } ulong atoul(char *str) { return strtoul((const char *)str, (char **)0, 10); } wily-0.13.42/tools/old/wilytoys/reader/CHANGES000064402366570000012000000016751033320152300205630ustar00ozstaff000043300000020.1 -> 0.2 ======== Filters out most common garbage headers (toggle this with allheaders). Can delete/undelete/save multiple messages, by sweeping them. [Un]delete is a lot less effort on the screen updates. Commit now writes changes back to the mailbox, without quitting. Doesn't read in new mail, though. Rescan reads in any new mail that has arrived. Doesn't write any current changes, though. Rescans your mailbox for new mail automatically. Does this every 60 seconds, by default. You have to hack mail.h to change this... If you're running it in non-multiart mode (default), then it tries to avoid trashing your composition windows when you pull up a message window. savefile has a default parameter: $SAVEFILE if set, or $HOME/mbox otherwise. Sets the title of article windows to just mailboxname/msgnum, because the From: lines are too long. Uses MAXPATHLEN instead of FILENAME_MAX, because FILENAME_MAX is way too small on some machines. wily-0.13.42/tools/old/wilytoys/reader/reader.c000064402366570000012000000410341033320152300211670ustar00ozstaff00004330000002/* * reader.c - functions for handling news/article reader windows. */ #include "headers.h" Bool debug = false; Bool frommessage = true; /* * These determine whether we'll have one list and one article window, * that gets overwritten each time we change group/mailbox/article, * or whether we just spawn a new one. */ int rdMultiList = 0; int rdMultiArt = 0; /* * The windows currently active. */ rdWin *windows = 0; static rdWin *Listwin = 0; static rdWin *Artwin = 0; /* * General wily comms stuff. */ Mqueue realwilyq; Mqueue *wilyq = &realwilyq; Fd wilyfd; /* * Amount of time we wait before causing a rescan event, in seconds. * If zero, then we don't rescan. */ static int rdRescanTimer = 0; Bool rdAlarmEvent = false; static void (*old_alarm_handler)(int) = 0; /* * default contents of tags */ char *rdListTagStr = " delete undelete comp reply quit exit "; char *rdArtTagStr = " delete reply save inc "; static rdWin *allocWin(rdWinType kind, const char *title); static int connectWin(rdWin *w, char *filename); static rdWin *getWin(int user, void *userp, rdWinType kind, char *title, char *filename, int protect); static void clearWin(rdWin *w); static void freeItems(rdWin *w); static int loadItems(rdWin *w, char **items, int savecontents); static int initWin(int user, void *userp, rdWin *w, char *title, char *filename, int protect); static void anyEvent(rdWin *w); static void winDelete(rdWin *w, int which, ulong p0, ulong p1); static void winInsert(rdWin *w, int which, ulong p, char *str); static void updateBody(rdWin *w, ulong p0, ulong p1, char *str); static void winGoto(rdWin *w, ulong p0, char *str); static void winExec(rdWin *w, char *cmd, char *arg); static void DelWin(rdWin *w, char *arg); static int rdBuiltin(rdWin *w, char *cmd, char *str); static void addrEvent(rdWin *w); static void bodyEvent(rdWin *w); static size_t countlines(char *str, size_t len); static void prefixlines(char *str, size_t len, char *prefix, size_t plen, char *buf); static void alarm_handler(int signal); static void set_sig(void); static void updateItems(rdWin *w, rdItem *i, int len); /* * allocWin(kind, title) - create a new, blank window of a given kind. */ static rdWin * allocWin(rdWinType kind, const char *title) { rdWin *w = salloc(sizeof(*w)); w->title = sstrdup((char *)title); w->wintype = kind; w->id = -1; w->m = 0; w->items = 0; w->body = 0; w->protect = 0; w->taglen = w->bodylen = 0; w->next = windows; windows = w; return w; } /* * connectWin(w, filename) - connect to wily, to create a new window. * If filename is true, then we get wily to open the given file. Otherwise, * we ask for a new, blank window. * Returns 0 for success. */ static int connectWin(rdWin *w, char *filename) { int fd; if (filename == 0) filename = "New"; if (rpc_new(wilyq, &w->id, filename, false) < 0) { freeWin(w); return -1; } return 0; } /* * getWin(user, userp, kind, title, filename, protect) - grab a window of the appropriate type. */ static rdWin * getWin(int user, void *userp, rdWinType kind, char *title, char *filename, int protect) { rdWin *w; if ((kind == rdList && (!Listwin || rdMultiList)) || (kind == rdArticle && (!Artwin || Artwin->protect || protect || rdMultiArt))) { /* we can create a new window */ w = allocWin(kind, title); if (connectWin(w,filename)) return 0; if (kind == rdList) Listwin = w; else if (!protect) Artwin = w; } else { /* have to reuse the existing window */ w = (kind == rdList)? Listwin : Artwin; clearWin(w); } initWin(user, userp, w, title, filename, protect); return w; } /* * clearWin(w) - erase the tag and body of a window */ static void clearWin(rdWin *w) { if (w->taglen) (void) rpc_settag(wilyq, w->id, ""); w->taglen = 0; w->protect = 0; if (w->bodylen) { (void) rpc_delete(wilyq, w->id, 0, w->bodylen); w->bodylen = 0; if (w->wintype == rdList) freeItems(w); } } /* * discard all the items in the window's list */ static void freeItems(rdWin *w) { rdItem *i, *j; for (i = w->items; i; i = j) { j = i->next; free(i); } w->items = 0; } /* * loadItems(w, items) - load an array of items into the list, and into the window. */ static int loadItems(rdWin *w, char **items, int savecontents) { rdItem *i, *j = 0; char *sep = "\n"; ulong p0 = 0; ulong len, seplen = strlen(sep); char *buf = 0; int n; if (savecontents) { for (len = 0, n = 0; items[n]; n++) len += strlen(items[n]) + seplen; w->body = buf = salloc(len); } while (*items) { i = salloc(sizeof(*i)); i->next = 0; i->p0 = p0; len = strlen(*items); if (j) j->next = i; else w->items = i; j = i; if (rpc_insert(wilyq, w->id, p0, *items)) { freeItems(w); return -1; } p0 += len; if (rpc_insert(wilyq, w->id, p0, sep)) { freeItems(w); return -1; } i->p1 = (p0 += seplen); items++; } w->bodylen = p0; return 0; } /* * changeItems(w, items, savecontents) - update the contents of a list window. */ int changeItems(rdWin *w, char **items, int savecontents) { if (w->wintype != rdList) return 1; freeItems(w); if (w->bodylen) { if (rpc_delete(wilyq, w->id, 0, w->bodylen)) return 1; w->bodylen = 0; } return loadItems(w, items, savecontents); } /* * initWin(user, userp, w, title, filename, protect) - initialise the window's tag, label, etc. */ static int initWin(int user, void *userp, rdWin *w, char *title, char *filename, int protect) { char tag[300]; /* XXX guess */ char *tagstr = w->wintype == rdArticle? rdArtTagStr : rdListTagStr; if (rpc_setname(wilyq, w->id, title)) return 1; sprintf(tag,"%s", tagstr); /* XXX at the moment, we don't include the title */ if (rpc_settag(wilyq, w->id, tag)) return 1; w->taglen = strlen(tag); w->user = user; w->userp = userp; w->protect = protect; return 0; } /* * getArtWin(title, text, filename, savecontents, protect) - get an article window, and load it with * either the given text, or from the given file. */ int getArtWin(int user, void *userp, char *title, char *text, char *filename, int savecontents, int protect) { rdWin *w = getWin(user, userp, rdArticle, title, filename, protect); if (w == 0) return 1; if (text) { int l = strlen(text); w->bodylen = l; if (rpc_insert(wilyq, w->id, 0, text)) return 1; if (savecontents) { w->body = salloc(l); strcpy(w->body, text); } } return 0; } /* * get a List window, and load it with the items in the array (which * must be null-terminated). */ int getListWin(int user, void *userp, char *title, char **items, int savecontents) { rdWin *w = getWin(user, userp, rdList, title, (char *)0, 0); if (w == 0) return 1; return loadItems(w, items, savecontents); } /* * readerInit(title, items, ml, ma) - start things off by creating * a list window. Tell the reader whether we'll want one or more of * the list and article windows. */ int readerInit(int user, char *userp, char *title, char **items, int ml, int ma, int savecontents) { rdMultiList = ml; rdMultiArt = ma; if ((wilyfd = get_connect()) < 0) return 1; mq_init(wilyq, wilyfd); return getListWin(user, userp, title, items, savecontents); } /* * readerMainLoop() - get messages from wily, and act upon them. */ int readerMainLoop(void) { rdWin *w; Msg *m; int istag; while (windows) { if ((w = getActiveWin()) == 0) { fprintf(stderr,"No message available\n"); return 1; } m = w->m; switch (m->mtype) { char *cmd, *arg; ulong p0, p1; case EMexec: decode_exec_e(m, &cmd, &arg); winExec(w, cmd, arg); break; case EMgoto: decode_goto_e(m, &p0, &arg); winGoto(w, p0, arg); break; case EMinsert: istag = IsBody; decode_insert_e(m, &p0, &arg); winInsert(w, istag, p0, arg); break; case EMdelete: istag = IsBody; decode_delete_e(m, &p0, &p1); winDelete(w, istag, p0, p1); break; default: fprintf(stderr,"Unknown msg type!\n"); exit(1); } } return 1; } /* * delete item n from the list */ int rdDelItem(rdWin *w, int item) { rdItem **pi; rdItem *i; int len; if (w->wintype != rdList || item < 0) return 1; for (pi = &w->items; *pi && item; pi = &((*pi)->next)) item--; if (item) return 1; /* not found */ i = *pi; len = i->p1 - i->p0; if (rpc_delete(wilyq, w->id, i->p0, i->p1) < 0) return 1; *pi = i->next; free(i); updateItems(w, *pi, -len); return 0; } /* * add a new item to the end of the list */ int rdAddItem(rdWin *w, char *text) { rdItem **pi; rdItem *i; int len = (int)strlen(text); char *sep = "\n"; if (w->wintype != rdList || !text || !*text) return 1; i = salloc(sizeof(*i)); for (pi = &w->items; *pi; pi = &((*pi)->next)); *pi = i; i->p0 = w->bodylen; i->p1 = i->p0 + len; i->next = 0; if (rpc_insert(wilyq, w->id, i->p0, text) || rpc_insert(wilyq, w->id, i->p1++, sep)) return 1; len += strlen(sep); w->bodylen += len; return 0; } /* * change the text of an item */ int rdChangeItem(rdWin *w, int item, char *text) { rdItem **pi; rdItem *i; int len, oldlen, newlen = strlen(text); char *sep = "\n"; if (w->wintype != rdList || !text || !*text) return 1; for (pi = &w->items; *pi && item; pi = &((*pi)->next)) item--; if (item) return 1; i = *pi; oldlen = i->p1 - i->p0; if (rpc_delete(wilyq, w->id, i->p0, i->p1) || rpc_insert(wilyq, w->id, i->p0, text) || rpc_insert(wilyq, w->id, i->p0 + newlen, sep)) return 1; newlen += strlen(sep); i->p1 = i->p0 + newlen; len = newlen - oldlen; updateItems(w, i->next, len); return 0; } static void updateItems(rdWin *w, rdItem *i, int len) { w->bodylen += len; while (i) { i->p0 += len; i->p1 += len; i = i->next; } } /* * text has been deleted */ static void winDelete(rdWin *w, int which, ulong p0, ulong p1) { rdItem *i; ulong l = p1 - p0; if (which == IsTag) { w->taglen -= l; return; } if (w->wintype == rdArticle) { w->bodylen -= l; return; } for (i = w->items; i; i = i->next) if (i->p0 <= p0 && p1 <= i->p1) break; if (!i) return; i->p1 -= l; for (i = i->next; i; i = i->next) { i->p0 -= l; i->p1 -= l; } updateBody(w, p0, p1, (char *)0); return; } /* * text has been inserted */ static void winInsert(rdWin *w, int which, ulong p, char *str) { rdItem *i; int l = strlen(str); if (which == IsTag) { w->taglen += l; return; } if (w->wintype == rdArticle) { w->bodylen += l; return; } for (i = w->items; i; i = i->next) if (i->p0 <= p && p <= i->p1) break; if (!i) return; i->p1 += l; for (i = i->next; i; i = i->next) { i->p0 += l; i->p1 += l; } updateBody(w, p, (ulong)l, str); return; } /* * updateBody(w,p0,p1,str) - insert p1 chars of str at p0, or remove the text * between p0 and p1. * XXX - this is *utterly* revolting, and horrendously slow. But it's quick * and simple, and will do for now. */ static void updateBody(rdWin *w, ulong p0, ulong p1, char *str) { char *newbuf; ulong newlen; if (w->body == 0) return; if (str) newlen = w->bodylen + p1; else newlen = w->bodylen - (p1 - p0); newbuf = salloc(newlen); strncpy(newbuf, w->body, p0); if (str) { strncpy(newbuf + p0, str, p1); strcpy(newbuf + p0 + p1, w->body + p0); } else { strcpy(newbuf + p0, w->body + p1); } free(w->body); w->body = newbuf; w->bodylen = newlen; } rdItemRange itemNumber(rdWin *w, ulong p0, ulong p1) { int n; rdItem *i; rdItemRange r; r.first = r.last = -1; r.i0 = r.i1 = 0; if (w->wintype != rdList || p1 < p0) return r; for (n = 0, i = w->items; i; i = i->next, n++) { if (i->p0 <= p0 && p0 <= i->p1) { r.first = r.last = n; r.i0 = r.i1 = i; } if (i->p0 <= p1 && p1 <= i->p1) { r.last = n; r.i1 = i; return r; } } return r; /* sigh */ } void highlightItem(rdWin *w, rdItemRange r) { static char addr[80]; /* XXX - overkill */ rdItem *i; ulong p0, p1; int n; if (!r.i0 || !r.i1) { for (i = w->items, n = 0; n <= r.last; n++, i = i->next) { if (n == r.first) p0 = i->p0; if (n == r.last) p1 = i->p1; } } else { p0 = r.i0->p0; p1 = r.i1->p1; } sprintf(addr,"#%lu,#%lu", p0, p1); (void)rpc_goto(wilyq, w->id, addr); } /* * A B3 event has occured. */ static void winGoto(rdWin *w, ulong p0, char *str) { /* If this is a list, then it counts as a selection. Otherwise, we just reflect it back to wily as a normal B3 event. */ if (w->wintype == rdList) { rdItemRange r = itemNumber(w, p0, p0); if (r.first == -1) return; /* sigh */ highlightItem(w, r); user_listSelection(w,r); return; } else (void)rpc_goto(wilyq, w->id, str); return; } /* * A B2(B1) command has been invoked. */ static void winExec(rdWin *w, char *cmd, char *arg) { ulong p0, p1; /* * Lots of options here: * - B2 with "|<>" - reflect back to wily. * - B2 cmd recognised by the reader routines - Del is about it. Execute * them ourselves. * - B2 not recognised by the reader routines - pass them onto the user, * after first getting the position of the argument within the body, if * necessary. * - B2B1 recognised by the reader routines - none spring to mind, but * I might add some. Execute them ourselves. * - B2B1 not recognised - pass onto user. */ if (!*cmd || strstr(cmd,"|<>")) { winReflectCmd(w,cmd, arg); return; } if (rdBuiltin(w,cmd,arg) == 0) return; if (rpc_addr(wilyq, w->id, ".", &p0, &p1)) return; if (w->wintype == rdList) { rdItemRange r = itemNumber(w, p0, p1); if (r.first == -1) { p0 = p1 = 0; } else { highlightItem(w, r); p0 = r.i0->p0; p1 = r.i1->p1; } user_cmdList(w,cmd,p0,p1,r,arg); return; } user_cmdArt(w, cmd, p0, p1, arg); return; } void winReflectCmd(rdWin *w, char *cmd, char *arg) { (void)rpc_exec(wilyq, w->id,cmd,arg); } /* * delete this particular window from the list. */ static void DelWin(rdWin *w, char *arg) { closeWin(w); } void closeWin(rdWin *w) { /* get wily to close the pane */ (void)rpc_exec(wilyq, w->id, "Del", ""); /* free up resources */ free(w->title); free(w->body); if (w->wintype == rdList) freeItems(w); /* XXX - currently leak the stateinfo stuff */ freeWin(w); return; } void freeWin(rdWin *w) { rdWin **wp = &windows; /* remove from the window chain */ while ((*wp) != w) wp = &((*wp)->next); *wp = w->next; if (w == Artwin) Artwin = 0; if (w == Listwin) Listwin = 0; if (windows == 0) exit(0); return; } static struct { char *cmd; void (*fn)(rdWin *, char *); } builtins[] = { { "Del", DelWin }, { 0, 0 } }; /* * check for builtin commands understood by the reader routines. */ static int rdBuiltin(rdWin *w, char *cmd, char *str) { int i; for (i = 0; builtins[i].cmd; i++) if (strcmp(builtins[i].cmd, cmd) == 0) { (*builtins[i].fn)(w, str); return 0; } return 1; } /* * "redisplay" a window that's already open. */ void rdGotoWin(rdWin *w) { (void)rpc_goto(wilyq, w->id, "."); } rdWin * userpWin(void *ptr) { rdWin *w = windows; while (w && w->userp != ptr) w = w->next; return w; } /* * Some routines which attempt to extract the body of a window, * and store it in a file. if p0==p1==0, assume all the body is wanted. */ void rdBodyToFile(rdWin *w, char *filename) { FILE *fp; char *buf = salloc(w->bodylen+1); if (rpc_read(wilyq, w->id, 0, w->bodylen, buf)) return; if ((fp = fopen(filename, "w"))) { (void)fprintf(fp,"%s",buf); fclose(fp); } free(buf); return; } /* * change current settings for multi-list and multi-art windows. */ void rdSetMulti(int list, int art) { rdMultiList = list; rdMultiArt = art; } static void alarm_handler(int signal) { if (signal != SIGALRM) return; set_sig(); rdAlarmEvent = true; if (old_alarm_handler != SIG_DFL && old_alarm_handler != SIG_IGN) (*old_alarm_handler)(signal); alarm(rdRescanTimer); } static void set_sig(void) { (void)signal(SIGALRM, alarm_handler); } void rdSetRescanTimer(int secs) { rdRescanTimer = secs; if (old_alarm_handler == 0) { if ((old_alarm_handler = signal(SIGALRM, alarm_handler)) == SIG_ERR) { perror("signal"); rdRescanTimer = 0; return; } } alarm(rdRescanTimer); } void rdInclude(rdWin *w, char *str, size_t len) { size_t nlines = countlines(str, len); char *buf; char *prefix = "> "; size_t nlen, plen = strlen(prefix); ulong p0, p1; if (rpc_addr(wilyq, w->id, ".", &p0, &p1)) return; nlen = len + nlines*plen + 1; buf = salloc(nlen); prefixlines(str, len, prefix, plen, buf); rpc_insert(wilyq, w->id, p1, buf); w->bodylen += nlen; free(buf); } static size_t countlines(char *str, size_t len) { size_t nlines = 0; while (len--) if (*str++ == '\n') nlines++; return nlines; } static void prefixlines(char *str, size_t len, char *prefix, size_t plen, char *buf) { while (len) { strncpy(buf,prefix,plen); buf += plen; while (len-- && (*buf++ = *str++) != '\n') ; } *buf = 0; } wily-0.13.42/tools/old/wilytoys/reader/reader.h000064402366570000012000000025401033320152300211730ustar00ozstaff00004330000002/* * reader.h - declarations for a mail/news reader toolkit for wily. */ /* * We support two kinds of window - a list (mailboxes, newsgroups, subject lines) * and an article display. There can be more than one instance of each. */ typedef enum _rdWinType { rdList, rdArticle } rdWinType; /* * This makes the messages clearer */ enum { IsTag = 0, IsBody = 1 }; typedef struct _rdWin rdWin; typedef struct _rdItem rdItem; typedef struct _rdItemRange rdItemRange; typedef struct _Msgq Msgq; extern int rdMultiList; extern int rdMultiArt; struct _rdItem { ulong p0, p1; /* address of this item in the window. */ struct _rdItem *next; /* next item in the list */ }; struct _rdItemRange { int first, last; /* inclusive */ rdItem *i0, *i1; }; struct _rdWin { rdWinType wintype; int user; /* user info */ void *userp; /* ditto */ Id id; struct _rdWin *next; /* list storage */ char *title; /* what we think the title of this window is */ ulong taglen; /* length of tag, in characters */ ulong bodylen; /* length of body, in characters */ Msg *m; /* message from wily */ char *body; /* UTF text of an article window */ rdItem *items; /* The items in a list */ int protect; /* The user is writing to this window */ }; extern rdWin *windows; extern Mqueue *wilyq; extern Bool rdAlarmEvent; wily-0.13.42/tools/old/wilytoys/reader/membuf.c000064402366570000012000000052371033320152300212050ustar00ozstaff00004330000002/* * memory.c - custom memory handler for mail messages. * XXX - This handler does *not* return buffers aligned for * anything larger than a byte! */ #include "headers.h" #include #define MINBUF 512 /* limit for splitting */ static membuf *busy, *freed; static void *find_free(size_t len); /* * allocate a new buffer. */ void *mb_alloc(size_t len) { void *ptr; membuf *m; assert(len); if ((ptr = find_free(len))) return ptr; m = salloc(sizeof(*m)); m->len = len; m->start = salloc(len); m->end = m->start + len; m->next = busy; busy = m; return m->start; } /* * grab an existing buffer from the free list, if there is one * large enough. */ static void * find_free(size_t len) { membuf **pm = &freed; membuf **smallest = 0; membuf *m, *nm; for (;*pm; pm = &((*pm)->next)) if ((*pm)->len >= len && (!smallest || (*pm)->len < (*smallest)->len)) smallest = pm; if (smallest == 0) return 0; /* no buffer big enough */ m = *smallest; /* found one - big enough to split? */ if (m->len > len+MINBUF) { /* yep */ nm = salloc(sizeof(*nm)); nm->len = len; nm->start = m->start; nm->len = len; nm->end = (m->start += len); m->len -= len; nm->next = busy; busy = nm; return nm->start; } /* nope - remove this one from the free queue, and return it */ *smallest = m->next; m->next = busy; busy = m; return m->start; } /* * A previously allocated buffer contains more than one mail message. * break the buffer into two, at the point indicated. */ void mb_split(void *old, void *new) { membuf *m, *nm; size_t len; assert(old); assert(new); assert (old < new); len = (char *)new - (char *)old; for (m = busy; m; m = m->next) if (m->start == old) break; assert(m); assert(m->len >= len); if (m->len == len) return; nm = salloc(sizeof(*nm)); nm->len = m->len - len; nm->end = m->end; m->end = nm->start = new; nm->len = m->len - len; m->len = len; nm->next = m->next; m->next = nm; } /* * discard the memory buffer, by placing it on the free list. */ void mb_free(void *ptr) { membuf **m; membuf *p; assert(ptr); for (m = &busy; *m; m = &((*m)->next)) if ((*m)->start == ptr) break; assert(*m); p = *m; *m = p->next; /* remove from the busy list */ /* search the free list for an adjacent buffer. If we find one, combine the two. */ for (m = &freed; *m; m = &((*m)->next)) { if ((*m)->end == p->start) { (*m)->end = p->end; (*m)->len += p->len; free(p); return; } if ((*m)->start == p->end) { (*m)->start = p->start; (*m)->len += p->len; free(p); return; } } /* didn't find one - just append the new buffer onto the free list. */ *m = p; p->next = 0; return; } wily-0.13.42/tools/old/wilytoys/reader/membuf.h000064402366570000012000000004441033320152300212050ustar00ozstaff00004330000002/* * memory.h - defs for message memory handling. */ typedef struct _membuf membuf; struct _membuf { char *start, *end; /* end points to first byte after buffer */ size_t len; struct _membuf *next; }; void *mb_alloc(size_t); void mb_free(void *); void mb_split(void *old, void *new); wily-0.13.42/tools/old/wilytoys/reader/proto.h000064402366570000012000000023531033320152300210760ustar00ozstaff00004330000002void queueMsg(rdWin *w); void freeMsgq(rdWin *w); rdWin *getActiveWin(void); int changeItems(rdWin *w, char **items, int savecontents); void user_listSelection(rdWin *w, rdItemRange r); void user_cmdList(rdWin *w, char *cmd, ulong p0, ulong p1, rdItemRange items, char *arg); void user_cmdArt(rdWin *w, char *cmd, ulong p0, ulong p1, char *arg); char *sstrdup(char *str); int getArtWin(int user, void *userp, char *title, char *text, char *filename, int savecontents, int protect); int getListWin(int user, void *userp, char *title, char **items, int savecontents); int readerInit(int user, char *userp, char *title, char **items, int ml, int ma, int savecontents); int readerMainLoop(void); rdItemRange itemNumber(rdWin *w, ulong p0, ulong p1); void highlightItem(rdWin *w, rdItemRange r); void winReflectCmd(rdWin *w, char *cmd, char *arg); void closeWin(rdWin *w); void freeWin(rdWin *w); void msg_handler(rdWin *w); void rdGotoWin(rdWin *w); rdWin *userpWin(void *ptr); ulong atoul(char *str); void rdSetMulti(int list, int art); void rdInclude(rdWin *w, char *str, size_t len); void rdSetRescanTimer(int secs); void dorescan(void); int rdDelItem(rdWin *w, int item); int rdAddItem(rdWin *w, char *text); int rdChangeItem(rdWin *w, int item, char *text); wily-0.13.42/tools/old/wilytoys/smk.9.font000064402366570000012000000037331033320152300201540ustar00ozstaff0000433000000216 13 0x0000 0x00FF wilynormal 0x0100 0x017E lucm.latineur.9 0x0180 0x01F0 matty.latinext.9 0x0250 0x02E9 lucm.ipa.9 0x0300 0x0308 matty.gendiacritics.9 0x0370 0x0372 matty.greekpunc.9 0x0386 0x03F5 lucm.greek.9 0x0400 0x0475 misc.cyrillic.9 0x2000 0x2044 lucm.genpunc.9 0x2070 0x208E lucm.supsub.9 0x20A0 0x20AA lucm.currency.9 0x2100 0x2138 matty.letterlike.9 0x2190 0x21EA misc.arrows 0x2200 0x227F matty.math1 0x2280 0x22F1 matty.math2 0x2300 0x232C matty.tech 0x2500 0x257F matty.chart 0x2580 0x2595 matty.blocks 0x25a0 0x25ee matty.geometric 0x2600 0x266F misc.ding 0x3000 0x303f jis.jis3000.16 0x3041 0x309e jis.hiragana.16 0x30a1 0x30fe jis.katakana.16 0x4000 0x40FF wilybold 0x4100 0x41FF wilyitalic 0x4200 0x42FF wilybolditalic 0x4e00 0x4fff jis.jis4e00.16 0x5000 0x51ff jis.jis5000.16 0x5200 0x53ff jis.jis5200.16 0x5400 0x55ff jis.jis5400.16 0x5600 0x57ff jis.jis5600.16 0x5800 0x59ff jis.jis5800.16 0x5a00 0x5bff jis.jis5a00.16 0x5c00 0x5dff jis.jis5c00.16 0x5e00 0x5fff jis.jis5e00.16 0x6000 0x61ff jis.jis6000.16 0x6200 0x63ff jis.jis6200.16 0x6400 0x65ff jis.jis6400.16 0x6600 0x67ff jis.jis6600.16 0x6800 0x69ff jis.jis6800.16 0x6a00 0x6bff jis.jis6a00.16 0x6c00 0x6dff jis.jis6c00.16 0x6e00 0x6fff jis.jis6e00.16 0x7000 0x71ff jis.jis7000.16 0x7200 0x73ff jis.jis7200.16 0x7400 0x75ff jis.jis7400.16 0x7600 0x77ff jis.jis7600.16 0x7800 0x79ff jis.jis7800.16 0x7a00 0x7bff jis.jis7a00.16 0x7c00 0x7dff jis.jis7c00.16 0x7e00 0x7fff jis.jis7e00.16 0x8000 0x81ff jis.jis8000.16 0x8200 0x83ff jis.jis8200.16 0x8400 0x85ff jis.jis8400.16 0x8600 0x87ff jis.jis8600.16 0x8800 0x89ff jis.jis8800.16 0x8a00 0x8bff jis.jis8a00.16 0x8c00 0x8dff jis.jis8c00.16 0x8e00 0x8fff jis.jis8e00.16 0x9000 0x91ff jis.jis9000.16 0x9200 0x93ff jis.jis9200.16 0x9400 0x95ff jis.jis9400.16 0x9600 0x97ff jis.jis9600.16 0x9800 0x99ff jis.jis9800.16 0x9a00 0x9bff jis.jis9a00.16 0x9c00 0x9dff jis.jis9c00.16 0x9e00 0x9fff jis.jis9e00.16 0xe000 0xe05f matty.tengwar.9 0xfee0 0xff5e lucm.latin1.9 0xfffd 0xfffd pelm.fffd.9 .jis5e00.16 0x6000 0x61ff jis.jis6000wily-0.13.42/tools/old/wilytoys/wcat.c000064402366570000012000000015661033320152300174270ustar00ozstaff00004330000002#include #include #include #include #include #include #include void e(char *s) { perror(s); exit(1); } int main(int argc, char *argv[]) { char cwd[BUFSIZ+1], filename[BUFSIZ]; char *file; int isreal; Fd fd; Mqueue q[1]; Id id; int r; ulong len = 0; if (argc > 1) { file = argv[1]; isreal = 1; if (*file == '/') strcpy(filename, file); else { if (getcwd(cwd,BUFSIZ) == 0) e("getcwd"); sprintf(filename,"%s/%s", cwd, file); } } else { isreal = 0; sprintf(filename,"+stdin-%d",getpid()); } if ((fd = get_connect()) < 0) e("get_connect"); mq_init(q,fd); if (rpc_new(q, &id, filename, isreal)) e("rpc_new"); if (isreal) return 0; while ((r = fread(cwd, 1, BUFSIZ, stdin))) { cwd[r] = 0; if (rpc_insert(q, id, len, cwd)) e("rpc_insert"); len += r; } return 0; } wily-0.13.42/tools/old/wilytoys/fetchurl000064402366570000012000000010051033320152300200500ustar00ozstaff00004330000002#!/usr/local/bin/expect -f # Download an HTML file in a simplistic fashion. # Usage: fetchurl hostname filename # (parse the URL yourself...) set hostname [lindex $argv 0] set filename [lindex $argv 1] log_user 0 spawn telnet $hostname http expect { "Connected" { expect "Escape character is '^]'." send "GET $filename\n" expect "GET $filename\r\n" log_user 1 interact -o "\r" {} "Connection closed by foreign host." {} exit 0 } timeout { send_user "Could not connect to $hostname\n" exit 1 } } wily-0.13.42/tools/old/wilytoys/html-ascii.pl000064402366570000012000000146741033320152300207200ustar00ozstaff00004330000002# Routines for HTML to ASCII. # (fixed width font, no font changes for size, bold, etc) with a little # BUGS AND MISSING FEATURES # font tags (e.g. CODE, EM) cause an extra whitespace # e.g. foo, -> foo , # Jim Davis July 15 1994 # modified 3 Aug 94 to support MENU and DIR require "tformat.pl" || die "Could not load tformat.pl: $@\nStopped"; # Can be set by command line arg if (! defined($columns_per_line)) { $columns_per_line = 72;} if (! defined($flush_last_page)) { $flush_last_page = 1;} # amount to add to indentation $indent_left = 5; $indent_right = 5; # ignore contents inside HEAD. $ignore_text = 0; # Set variables in tformat $left_margin = 1; $right_margin = $columns_per_line; $bottom_margin = 0; ## Routines called by html.pl $Begin{"HEAD"} = "begin_head"; $End{"HEAD"} = "end_head"; sub begin_head { local ($element, $tag) = @_; $ignore_text = 1;} sub end_head { local ($element) = @_; $ignore_text = 0;} $Begin{"BODY"} = "begin_document"; sub begin_document { local ($element, $tag) = @_; &start_page();} $End{"BODY"} = "end_document"; sub end_document { local ($element) = @_; &fresh_line();} ## Headers $Begin{"H1"} = "begin_header"; $End{"H1"} = "end_header"; $Begin{"H2"} = "begin_header"; $End{"H2"} = "end_header"; $Begin{"H3"} = "begin_header"; $End{"H3"} = "end_header"; $Begin{"H4"} = "begin_header"; $End{"H4"} = "end_header"; $Skip_Before{"H1"} = 1; $Skip_After{"H1"} = 1; $Skip_Before{"H2"} = 1; $Skip_After{"H2"} = 1; $Skip_Before{"H3"} = 1; $Skip_After{"H3"} = 0; sub begin_header { local ($element, $tag) = @_; &skip_n_lines ($Skip_Before{$element}, 5);} sub end_header { local ($element) = @_; &skip_n_lines ($Skip_After{$element});} $Begin{"BR"} = "line_break"; sub line_break { local ($element, $tag) = @_; &fresh_line();} $Begin{"P"} = "begin_paragraph"; # if fewer than this many lines left on page, start new page $widow_cutoff = 5; sub begin_paragraph { local ($element, $tag) = @_; &skip_n_lines (1, $widow_cutoff);} $Begin{"BLOCKQUOTE"} = "begin_blockquote"; $End{"BLOCKQUOTE"} = "end_blockquote"; sub begin_blockquote { local ($element, $tag) = @_; $left_margin += $indent_left; $right_margin = $columns_per_line - $indent_right; &skip_n_lines (1);} sub end_blockquote { local ($element) = @_; $left_margin -= $indent_left; $right_margin = $columns_per_line; &skip_n_lines (1);} $Begin{"PRE"} = "begin_pre"; $End{"PRE"} = "end_pre"; sub begin_pre { local ($element, $tag) = @_; $whitespace_significant = 1;} sub end_pre { local ($element) = @_; $whitespace_significant = 0;} $Begin{"INPUT"} = "form_input"; sub form_input { local ($element, $tag, *attributes) = @_; if ($attributes{"value"} ne "") { &print_word_wrap($attributes{"value"});}} $Begin{"HR"} = "horizontal_rule"; sub horizontal_rule { local ($element, $tag) = @_; &fresh_line (); &print_n_chars ($right_margin - $left_margin, "-");} # Add code for IMG (use ALT attribute) # Ignore I, B, EM, TT, CODE (no font changes) ## List environments $Begin{"UL"} = "begin_itemize"; $End{"UL"} = "end_list_env"; $Begin{"OL"} = "begin_enumerated"; $End{"OL"} = "end_list_env"; $Begin{"MENU"} = "begin_menu"; $End{"MENU"} = "end_list_env"; $Begin{"DIR"} = "begin_dir"; $End{"DIR"} = "end_list_env"; $Begin{"LI"} = "begin_list_item"; # application-specific initialization routine sub html_begin_doc { @list_stack = (); $list_type = "bullet"; $list_counter = 0;} sub push_list_env { push (@list_stack, join (":", $list_type, $list_counter));} sub pop_list_env { ($list_type, $list_counter) = split (":", pop (@list_stack)); $left_margin -= $indent_left;} sub begin_itemize { local ($element, $tag) = @_; &push_list_env(); $left_margin += $indent_left; $list_type = "bullet"; $list_counter = "*";} sub begin_menu { local ($element, $tag) = @_; &push_list_env(); $left_margin += $indent_left; $list_type = "bullet"; $list_counter = "*";} sub begin_dir { local ($element, $tag) = @_; &push_list_env(); $left_margin += $indent_left; $list_type = "bullet"; $list_counter = "*";} sub begin_enumerated { local ($element, $tag) = @_; &push_list_env(); $left_margin += $indent_left; $list_type = "enumerated"; $list_counter = 1;} sub end_list_env { local ($element) = @_; &pop_list_env(); # &fresh_line(); } sub begin_list_item { local ($element, $tag) = @_; $left_margin -= 2; &fresh_line(); &print_word_wrap("$list_counter "); if ($list_type eq "enumerated") {$list_counter++;} $left_margin += 2;} $Begin{"DL"} = "begin_dl"; sub begin_dl { local ($element, $tag) = @_; &skip_n_lines(1,5);} $Begin{"DT"} = "begin_defined_term"; $Begin{"DD"} = "begin_defined_definition"; $End{"DD"} = "end_defined_definition"; sub begin_defined_term { local ($element, $tag) = @_; &fresh_line();} sub begin_defined_definition { local ($element, $tag) = @_; $left_margin += $indent_left; &fresh_line();} sub end_defined_definition { local ($element) = @_; $left_margin -= $indent_left; &fresh_line();} $Begin{"META"} = "begin_meta"; # a META tag sets a value in the assoc array %Variable # i.e. sers $Variable{author} to "Rushdie" sub begin_meta { local ($element, $tag, *attributes) = @_; local ($variable, $value); $variable = $attributes{name}; $value = $attributes{content}; $Variable{$variable} = $value;} $Begin{"IMG"} = "begin_img"; sub begin_img { local ($element, $tag, *attributes) = @_; &print_word_wrap (($attributes{"alt"} ne "") ? $attributes{"alt"} : "[IMAGE]");} # URLs $Begin{"A"} = "begin_a"; sub begin_a { local ($element, $tag, *attributes) = @_; local ($href, $k); $href = $attributes{href}; $k = $main'wily_url++; $main'wily_urls{$k} = $href; &print_word_wrap ("[_u$k]["); } $End{"A"} = "end_a"; sub end_a { &print_word_wrap("]"); } # Content and whitespace. sub html_content { local ($string) = @_; unless ($ignore_text) { &print_word_wrap ($string);}} sub html_whitespace { local ($string) = @_; if (! $whitespace_significant) { die "Internal error, called html_whitespace when whitespace was not significant";} local ($i); for ($i = 0; $i < length ($string); $i++) { &print_whitespace (substr($string,$i,1));}} # called by tformat. Do nothing. sub do_footer { } sub do_header { } 1; ore_text = 0;} $Begin{"BODY"} = "begin_document"; sub begin_documewily-0.13.42/tools/old/wilytoys/parse-html.pl000064402366570000012000000214501033320152300207300ustar00ozstaff00004330000002# HTML parser # Jim Davis, July 15 1994 # This is an HTML parser not an SGML parser. It does not parse a DTD, # The DTD is implicit in the code, and specific to HTML. # The processing of the HTML can be customized by the user by # 1) Defining routines to be called for various tags (see Begin and End arrays) # 2) Defining routines html_content and html_whitespace # This is not a validating parser. It does not check the content model # eg you can use DT outside a DL and it won't know. It is too liberal in # what tags are allowed to minimize what other tags. # Bugs - can't parse the prolog or whatever you call it # # # # %html; # ]> # modified 3 Aug to add a bunch of HTML 2.0 tags # modified 3 Sept to print HTML stack to STDERR not STDOUT, to add new # routines html_begin_doc and html_end_doc for application specific cleanup # and to break parse_html into two pieces. # modified 30 Sept 94. parse_attributes now handles tag attributes that # don't have values. thanks to Bill Simpson-Young # for the code. # modified 17 Apr 95 to support FORMS tags. $debug = 0; $whitespace_significant = 0; # global variables: # $line_buffer is line buffer # $line_count is input line number. $line_buffer = ""; $line_count = 0; sub parse_html { local ($file) = @_; open (HTML, $file) || die "Could not open $file: $!\nStopped"; &parse_html_stream (); close (HTML);} # Global input HTML is the handle to the stream of HTML sub parse_html_stream { local ($token, $new); ## initialization @stack=(); $line_count = 0; $line_buffer = ""; ## application specific initialization &html_begin_doc(); main: while (1) { # if whitespace does not matter, trim any leading space. if (! $whitespace_significant) { $line_buffer =~ s/^\s+//;} # now dispatch on the type of token if ($line_buffer =~ /^(\s+)/) { $token = $1; $line_buffer = $'; &html_whitespace ($token);} # This will lose if there is more than one comment on the line! elsif ($line_buffer =~ /^(\)/) { $token = $1; $line_buffer = $'; &html_comment ($token);} elsif ($line_buffer =~ /^(\]*\>)/) { $token = $1; $line_buffer = $'; &html_comment ($token);} elsif ($line_buffer =~ /^(\<\/[^\>]*\>)/) { $token = $1; $line_buffer = $'; &html_etag ($token);} elsif ($line_buffer =~ /^(\<[^!\/][^\>]*\>)/) { $token = $1; $line_buffer = $'; &html_tag ($token);} elsif ($line_buffer =~ /^([^\s<]+)/) { $token = $1; $line_buffer = $'; $token = &substitute_entities($token); &html_content ($token); } else { # No valid token in buffer. Maybe it's empty, or maybe there's an # incomplete tag. So get some more data. $new = ; if (! defined ($new)) {last main;} # if we're trying to find a match for a tag, then get rid of embedded newline # this is, I think, a kludge if ($line_buffer =~ /^\ -1) { print STDERR "Stack not empty at end of document\n"; &print_html_stack();} } sub html_tag { local ($tag) = @_; local ($element) = &tag_element ($tag); local (%attributes) = &tag_attributes ($tag); # the tag might minimize (be an implicit end) for the previous tag local ($prev_element); while (&Minimizes(&stack_top_element(), $element)) { $prev_element = &stack_pop_element (); if ($debug) { print STDERR "MINIMIZING $prev_element with $element on $line_count\n";} &html_end ($prev_element, 0);} push (@stack, $tag); &html_begin ($element, $tag, *attributes); if (&Empty($element)) { pop(@stack); &html_end ($element, 0);} } sub html_etag { local ($tag) = @_; local ($element) = &tag_element ($tag); # pop stack until find matching tag. This is probably a bad idea, # or at least too general. local ( $prev_element) = &stack_pop_element(); until ($prev_element eq $element) { if ($debug) { print STDERR "MINIMIZING $prev_element with /$element on $line_count \n";} &html_end ($prev_element, 0); if ($#stack == -1) { print STDERR "No match found for /$element. You will lose\n"; last;} $prev_element = &stack_pop_element();} &html_end ($element, 1); } # For each element, the names of elements which minimize it. # This is of course totally HTML dependent and probably I have it wrong too $Minimize{"DT"} = "DT:DD"; $Minimize{"DD"} = "DT"; $Minimize{"LI"} = "LI"; $Minimize{"P"} = "P:DT:LI:H1:H2:H3:H4:BLOCKQUOTE:UL:OL:DL"; # Does element E2 minimize E1? sub Minimizes { local ($e1, $e2) = @_; local ($value) = 0; foreach $elt (split (":", $Minimize{$e1})) { if ($elt eq $e2) {$value = 1;}} $value;} $Empty{"BASE"} = 1; $Empty{"BR"} = 1; $Empty{"HR"} = 1; $Empty{"IMG"} = 1; $Empty{"ISINDEX"} = 1; $Empty{"LINK"} = 1; $Empty{"META"} = 1; $Empty{"NEXTID"} = 1; $Empty{"INPUT"} = 1; # Empty tags have no content and hence no end tags sub Empty { local ($element) = @_; $Empty{$element};} sub print_html_stack { print STDERR "\n ==\n"; foreach $elt (reverse @stack) {print STDERR " $elt\n";} print STDERR " ==========\n";} # The element on top of stack, if any. sub stack_top_element { if ($#stack >= 0) { &tag_element ($stack[$#stack]);}} sub stack_pop_element { &tag_element (pop (@stack));} # The element from the tag, normalized. sub tag_element { local ($tag) = @_; $tag =~ /<\/?([^\s>]+)/; local ($element) = $1; $element =~ tr/a-z/A-Z/; $element;} # associative array of the attributes of a tag. sub tag_attributes { local ($tag) = @_; $tag =~ /^<[A-Za-z]+ +(.*)>$/; &parse_attributes($1);} # string should be something like # KEY="value" KEY2="longer value" KEY3="tags o doom" # output is an associative array (like a lisp property list) # attributes names are not case sensitive, do I downcase them # Maybe (probably) I should substitute for entities when parsing attributes. sub parse_attributes { local ($string) = @_; local (%attributes); local ($name, $val); get: while (1) { if ($string =~ /^ *([A-Za-z]+)=\"([^\"]*)\"/) { $name = $1; $val = $2; $string = $'; $name =~ tr/A-Z/a-z/; $attributes{$name} = $val; } elsif ($string =~ /^ *([A-Za-z]+)=(\S*)/) { $name = $1; $val = $2; $string = $'; $name =~ tr/A-Z/a-z/; $attributes{$name} = $val;} elsif ($string =~ /^ *([A-Za-z]+)/) { $name = $1; $val = ""; $string = $'; $name =~ tr/A-Z/a-z/; $attributes{$name} = $val;} else {last;}} %attributes;} sub substitute_entities { local ($string) = @_; $string =~ s/&/&/g; $string =~ s/<//g; $string =~ s/"/\"/g; $string;} @HTML_elements = ( "A", "ADDRESS", "B", "BASE", "BLINK", # Netscape addition :-( "BLOCKQUOTE", "BODY", "BR", "CITE", "CENTER", # Netscape addition :-( "CODE", "DD", "DIR", "DFN", "DL", "DT", "EM", "FORM", "H1", "H2", "H3", "H4", "H5", "H6", "HEAD", "HR", "HTML", "I", "ISINDEX", "IMG", "INPUT", "KBD", "LI", "LINK", "MENU", "META", "NEXTID", "OL", "OPTION", "P", "PRE", "SAMP", "SELECT", "STRIKE", "STRONG", "TITLE", "TEXTAREA", "TT", "UL", "VAR", ); sub define_element { local ($element) = @_; $Begin{$element} = "Noop"; $End{$element} = "Noop";} foreach $element (@HTML_elements) {&define_element($element);} # do nothing sub Noop { local ($element, $xxx) = @_; } # called when a tag begins. Dispatches using Begin sub html_begin { local ($element, $tag, *attributes) = @_; local ($routine) = $Begin{$element}; if ($routine eq "") { print STDERR "Unknown HTML element $element ($tag) on line $line_count\n";} else {eval "&$routine;"}} # called when a tag ends. Explicit is 0 if tag end is because of minimization # not that you should care. sub html_end { local ($element, $explicit) = @_; local ($routine) = $End{$element}; if ($routine eq "") { print STDERR "Unknown HTML element \"$element\" (END $explicit) on line $line_count\n";} else {eval "&$routine(\"$element\", $explicit)";}} sub html_content { local ($word) = @_; } sub html_whitespace { local ($whitespace) = @_;} sub html_comment { local ($tag) = @_;} # redefine these for application-specific initialization and cleanup sub html_begin_doc {} sub html_end_doc {} # return a "true value" when loaded by perl. 1; in and End arrays) # 2) Defining routines html_content and html_whitespace # This is not a validating parser. It does not check the content model # eg you can use DT outside a DL and it won't know. It is too liwily-0.13.42/tools/old/reader/000075502366570000012000000000001033320152300156545ustar00ozstaff00004330000002wily-0.13.42/tools/old/reader/solaris.c000064402366570000012000000027751033320152300175070ustar00ozstaff00004330000002/* * solaris.c - the system-dependent routines for Solaris 2. */ #include "headers.h" #include "mbox.h" #include #include #include /* * load_mbox(mbox) - open the named file, and make it available * as a block of memory between mbox_start and mbox_end. */ #ifdef USE_MMAP int load_mbox(mMbox *mbox) { mode_t mode = mbox->readonly? O_RDONLY : O_RDWR; int fd = open(mbox->name,mode); caddr_t addr; size_t len; int prot, flags; off_t off; struct stat st; if (fd < 0) return 1; if (fstat(fd,&st) == -1) return 1; len = (size_t)st.st_size; mbox->size = st.st_size; mbox->mtime = st.st_mtime; addr = 0; prot = PROT_READ; off = 0; flags = MAP_SHARED; if ((mbox->mbox_start = mmap(addr,len,prot,flags,fd,off)) == MAP_FAILED) return 1; close(fd); mbox->mbox_end = mbox->mbox_start + len; return 0; } #else /* USE_MMAP */ int load_mbox(mMbox *mbox) { const char *mode = mbox->readonly? "r" : "r+"; FILE *fp = fopen(mbox->name,mode); char *addr = 0; size_t len; struct stat st; if (fp == 0) goto broken; if (stat(mbox->name,&st) == -1) goto broken; len = (size_t)st.st_size; mbox->size = st.st_size; mbox->mtime = st.st_mtime; if ((addr = malloc(len+1)) == 0) goto broken; addr[len] = 0; /* handy for debugging */ if (fread(addr, (size_t)1, len, fp) != len) goto broken; fclose(fp); mbox->mbox_start = addr; mbox->mbox_end = mbox->mbox_start + len; return 0; broken: if (addr) free(addr); fclose(fp); return 1; } #endif /* USE_MMAP */ wily-0.13.42/tools/old/reader/headers.h000064402366570000012000000004321033320152300174370ustar00ozstaff00004330000002#ifndef RD_HEADERS_H #define RD_HEADERS_H #include #include #include #include #include #include #include #include #include #include "reader.h" #include "proto.h" #endif /* RD_HEADERS_H */ wily-0.13.42/tools/old/reader/README000064402366570000012000000126671033320152300165500ustar00ozstaff00004330000002First bash at a mail reader. There are two pieces of code here: First off, you've got the generalised reader/viewer thingy. This is intended to be used as the basis for a newsreader too, but I obviously haven't got that far yet. It's mostly either implemented or hooks, depending on which part you look at. It supports windows of articles and lists of subjects, and there can be lots of either type. However, I've only ever run it with one list window, so I've no idea if the code'll work if you try multiple articles. It has hooks for saving internal copies of window contents, but I don't use them at the moment (I can't be bothered to work out what to do if someone does a sweeping delete of half the contents of a list window). Makefile getmsg.c Gets messages from wily. Used to be ridiculously complicated, before libmsg took over msg queueing (thank you, gary). headers.h proto.h reader.c The generic reader thingy. Unpleasant. reader.h utils.c Coupla handy things. Then you've got the mail-specific stuff. This currently cheats for sending messages. For example, it uses the From: line, and just feeds articles into sendmail without caring what they look like. mail.c Main mail program. mail.h Definitions. Hack MTU to be something that accepts a complete article on stdin, including headers. mbox.c Mailbox handling routines. These are actually swiped from a 9term-like mail reader I wrote about a year ago, and never finished. I *think* they're ok at updating your mailbox, but, well, they might not be. Handle with care. mbox.h solaris.c The mbox routines assume that the whole mail file is accessible as a single string. This uses malloc/fread to do this. It used to use mmap(), but that's buggy over NFS. includepatches Changes to the libmsg prototypes. libmsgpatches Some additions to the msg library: - rpc_settag() and rpc_setname() added. - rpc_new() gets a "isreal" argument. wilypatches Hacks to wily, against 0.9.5. Looking through them, they do: - Add a "Dot" builtin, that toggles display of .* files. By default, they're not shown. B2 on Dot and Get to show them. - Adds support for rpc_goto() to wily. - Adds (very basic) support for rpc_settag() to wily. - Doesn't complain about virtual windows, or attempt to back them up. winpatches Just changes win to say its window isn't real. USAGE Invoke with "mreader [-ma] mailboxname". The "-ma" option allows you to have multiple article windows open at once. By default, it only has the one article window open, because it's easier to find where the article window is, once you've positioned it. Unfortunately, this means that you don't get to see the article you're replying to. To fix this, there's a "multiart" command, which toggles this value from within the reader. First window to appear is the list window. It shows all the articles from the given mailfile, one per line. The line contains the From and Subject fields, but it's currently chopped to make things look nicer. You open an article by B3'ing on its subject line. What else? Commands supported: exit exit without doing anything to the mailfile. quit save any changes to the mailfile before quitting. delete delete the selected article. "selected" means the article which has dot in its subject line. This means you can click on the subject line with either B1 or B3, and then click on delete. Of course, if you click on delete within an article window, that article is the one that is deleted. Delete doesn't actually do anything except mark the article for deletion, and puts a "D" before at the start of the subject line. undelete reverses delete. comp compose a new message. You get a blank article window with From, To and Subject fields. Don't delete them. reply Reply to the article (article is selected in the same fashion, i.e. B1/B3 list window, or just the article that the reply cmd was executed in). The To field is filled in from the From field. You can use "inc" or "incall" to include the text of the article you're replying to. abort junk a comp/reply article without sending it. deliver post a complete comp/reply article (well, feed it to sendmail). savefile sets the name of the file that "save" writes to. save appends the current message into the savefile. Creates the file if it doesn't exist. multiart toggles the "only one article window at once" flag. This is handy for viewing several articles or reading one article while replying to another. inc [n] Includes a message into the current position of the current message. It's supposed to accept a message number, too, but I haven't tried that. incall Same as inc, but will include the headers of the message, too. Bugs Vast numbers of them... Currently needs to have at least *something* in your mailbox, otherwise it exits. At the moment, it's one-shot - it never rescans your mailbox to see if more mail has arrived (except when writing changes back on "quit"; it *has* to then....). This means you still need another mail notification program. I recommend Faces. :-) The preferred means of reading the mailbox is with mmap(), but under Solaris 2.3, that's buggy for NFS-mounted directories, so right now it compiles with a malloc-and-fread method instead. Unlike most windows, it current has the tools *before* the window label. This is because of the broken tags problem. Right now, I'm cheating, and inserting the tools at the start of the tag, instead of the end - that seems to work... wily-0.13.42/tools/old/reader/getmsg.c000064402366570000012000000004571033320152300173140ustar00ozstaff00004330000002/* * getmsg.c - handle message reception from wily. */ #include "headers.h" rdWin * getActiveWin(void) { rdWin *w; Msg *m; Id id; if ((m = mq_next(wilyq, 0)) == 0) return 0; id = msg_id(m); for (w = windows; w; w = w->next) if (id == w->id) { w->m = m; return w; } return 0; } wily-0.13.42/tools/old/reader/Makefile.in000064402366570000012000000011231033320152300177160ustar00ozstaff00004330000002srcdir=@srcdir@ VPATH=@srcdir@ OBJECTS= getmsg.o mail.o reader.o mbox.o solaris.o utils.o TARGET=mreader CC=@CC@ CFLAGS=-I../include -I.. -I$(srcdir)/../include @X_CFLAGS@ MYLIBS=../libmsg/libmsg.a ../libXg/libXg.a all: $(TARGET) $(TARGET): $(OBJECTS) $(MYLIBS) $(CC) $(LDFLAGS) -o $(TARGET) $(OBJECTS) $(MYLIBS) $(LIBS) @X_LIBS@ -lXt @X_PRE_LIBS@ -lX11 @X_EXTRA_LIBS@ purify: $(OBJECTS) purify -userpath='.:../libtext:../libframe:../libXg' $(CC) $(LDFLAGS) -o $(TARGET) $(OBJECTS) $(MYLIBS) $(LIBS) $(OBJECTS): ../include/libmsg.h clean: rm -f *.o core *pure* nuke: clean rm -f $(TARGET) wily-0.13.42/tools/old/reader/mail.c000064402366570000012000000247621033320152300167550ustar00ozstaff00004330000002/* * some notes on how this is arranged. * call readerInit(title, msgs, 0, 1, 0) to create things. * call readerMainLoop(). * callbacks: * user_listSelection(w,n); * open new article win with getArtWin(title,text,0,0); * user_cmdExec(w,builtin,cp0,cp1,cmd,p0,p1,arg); */ #include "headers.h" #include "mbox.h" #include "mail.h" static void build_msg_list(); mWin *allocMWin(int kind, int num); void freeMWin(mWin *w); mWin *findMWin(void *ptr); int artDisplayed(rdWin *w, int n); void mDelete(rdWin *w, int n, char *arg); void mUndelete(rdWin *w, int n, char *arg); void mComp(rdWin *w, int n, char *arg); void mExit(rdWin *w, int n, char *arg); void mQuit(rdWin *w, int n, char *arg); void mReply(rdWin *w, int n, char *arg); void mAbort(rdWin *w, int n, char *arg); void mDeliver(rdWin *w, int n, char *arg); void mSavefile(rdWin *w, int n, char *arg); void mSave(rdWin *w, int n, char *arg); void dodeliver(rdWin *w, char *filename); void mMultiart(rdWin *w, int n, char *arg); void mIncludeall(rdWin *w, int n, char *arg); void mInclude(rdWin *w, int n, char *arg); void doinclude(rdWin *w, int n, char *arg, int all); mMbox *mbox; static char mboxname[FILENAME_MAX]; mWin *mwindows; mWin *listwin; static char **msgs; static char *savefile; static int multiart = 0; int main(int argc, char *argv[]) { mWin *mw; int ma = 0; printf("kill %d\n",getpid()); fflush(stdout); if (argc >=2 && strcmp(argv[1], "-ma")==0) { ma = 1; argc--; argv++; } multiart = ma; if (argc >= 2) strcpy(mboxname, argv[1]); else sprintf(mboxname,"/var/mail/%s", getenv("USER")); if ((mbox = read_mbox((const char *)mboxname, 0)) == 0) { perror(mboxname); exit(1); } mw = listwin = allocMWin(mMsgList, 0); build_msg_list(); if (readerInit(0, (char *)mw, mboxname, msgs, 0, ma, 0)) exit(1); readerMainLoop(); printf("Finished\n"); exit(0); } mWin * allocMWin(int kind, int num) { mWin *w = salloc(sizeof(*w)); mWin **p = &mwindows; w->kind = kind; w->msg = (kind == mDispArt || kind == mCompArt)? num : -1; w->mbox = mbox; w->next = 0; while (*p) p = &((*p)->next); *p = w; return w; } void freeMWin(mWin *w) { mWin **p = &mwindows; while (*p != w) p = &((*p)->next); *p = w->next; free(w); } mWin * findMWin(void *ptr) { mWin *mw = mwindows; while (mw && (mWin *)ptr != mw) mw = mw->next; return mw; } static void chkhdr(mString *s, int *len, char **rest) { int l; *rest = ""; /* default */ if (s == 0) { *len = 0; return; } l = s->s1 - s->s0; if (l > 20) { l = 20; *rest = "..."; } else if (l > 0) l--; /* skip newline */ *len = l; } static void build_msg_list(void) { int n; mMsg *m; ulong l; int lfrom, ldate, lsubject; char *rfrom, *rdate, *rsubject; mString *from; mString *date; mString *subject; int dc; if (msgs) for (n = 0; msgs[n]; n++) free(msgs[n]); msgs = (char **)srealloc(msgs, (mbox->nmsgs+1) * sizeof(char *)); for (n = 0; n < mbox->nmsgs; n++) { m = mbox->msgs[n]; dc = m->deleted? 'D' : ' '; from = m->from; date = m->date; subject = m->subject; chkhdr(from, &lfrom, &rfrom); chkhdr(date, &ldate, &rdate); chkhdr(subject, &lsubject, &rsubject); l = lfrom + ldate + lsubject + 10; msgs[n] = salloc(l); sprintf(msgs[n],"%c%d %.*s%s %.*s%s", dc, n+1, lfrom, from->s0, rfrom, lsubject, subject->s0, rsubject); } msgs[n] = 0; return; } void user_listSelection(rdWin *w, int n) { static char title[300]; mMsg *m = mbox->msgs[n]; mString *from = m->from; mString *body = &m->whole; static char *text; static size_t textlen; size_t len; mWin *mw; if (artDisplayed(w, n)) return; mw = allocMWin(mDispArt,n); sprintf(title," Mail/%d/%.*s ",n+1, from->s1 - from->s0, from->s0); title[50] = 0; /* XXX - to make sure it's not too long. */ len = body->s1 - body->s0; if (len >= textlen) { textlen = len + 1; text = srealloc(text, textlen); } memcpy(text, body->s0, len); text[len] = 0; getArtWin(n, mw, title, text, 0, 0); } int artDisplayed(rdWin *w, int n) { mWin *mw; for (mw = mwindows; mw; mw = mw->next) if (mw->kind == mDispArt && mw->msg == n) if ((w = userpWin(mw))) { rdGotoWin(w); return 1; } return 0; } static struct mCmd mcmds[] = { { "quit", MCANY, mQuit }, { "exit", MCANY, mExit }, { "reply", MCNOTCOMP, mReply }, { "delete", MCNOTCOMP, mDelete }, { "undelete", MCMSGLIST, mUndelete }, { "comp", MCMSGLIST, mComp }, { "abort", MCCOMPART, mAbort }, { "deliver", MCCOMPART, mDeliver }, { "savefile", MCANY, mSavefile }, { "save", MCANY, mSave }, { "multiart", MCANY, mMultiart}, { "inc", MCCOMPART, mInclude}, { "incall", MCCOMPART, mIncludeall}, { 0, 0, 0 } }; void user_cmdList(rdWin *w, char *cmd, ulong p0, ulong p1, int n, char *arg) { int c; printf("user_cmdList(w,%s,%lu,%lu, msg %d, %s)\n", cmd, p0, p1, n+1, arg); fflush(stdout); for (c = 0; mcmds[c].cmd; c++) if (strcmp(cmd, mcmds[c].cmd) == 0) break; if (mcmds[c].cmd == 0) { printf("%s reflected\n",cmd); fflush(stdout); winReflectCmd(w,cmd,arg); return; } /* check that the command is valid in a list like this */ if ((mcmds[c].context & MCMSGLIST) == 0) { fprintf(stderr,"%s: only valid within the message list\n", cmd); return; } (*mcmds[c].fn)(w, n, arg); return; } void user_cmdArt(rdWin *w, char *cmd, ulong p0, ulong p1, char *arg) { int c; mWin *mw; unsigned short context; printf("user_cmdArt(w, %s, %lu, %lu, %s)\n", cmd, p0, p1, arg); fflush(stdout); for (c = 0; mcmds[c].cmd; c++) if (strcmp(cmd, mcmds[c].cmd) == 0) break; if (mcmds[c].cmd == 0) { printf("%s reflected\n",cmd); fflush(stdout); winReflectCmd(w,cmd,arg); return; } /* check that the command is valid in this window */ if ((mw = findMWin(w->userp)) == 0) { fprintf(stderr,"%s: invalid window argument\n",cmd); return; } context = (mw->kind == mDispArt)? MCDISPART : MCCOMPART; if ((mcmds[c].context & context) == 0) { fprintf(stderr,"%s: not valid in that window\n", cmd); return; } (*mcmds[c].fn)(w, mw->msg, arg); return; } void mDelete(rdWin *w, int n, char *arg) { mWin *mw; rdWin *ow; if ((mw = findMWin(w->userp)) == 0) return; if (mw->mbox->msgs[n]->deleted) return; mw->mbox->msgs[n]->deleted = 1; mw->mbox->ndel++; if (mw->kind != mDispArt) /* might be the msg list */ for (mw = mwindows; mw; mw = mw->next) if (mw->kind == mDispArt && mw->msg == n) break; if (mw) { if ((ow = userpWin(mw))) /* this msg is displayed; remove the pane */ closeWin(ow); freeMWin(mw); } build_msg_list(); changeItems(userpWin(listwin), msgs, 0); return; } void mUndelete(rdWin *w, int n, char *arg) { mWin *mw; if ((mw = findMWin(w->userp)) == 0) return; if (!mw->mbox->msgs[n]->deleted) return; mw->mbox->msgs[n]->deleted = 0; mw->mbox->ndel--; build_msg_list(); changeItems(userpWin(listwin), msgs, 0); return; } void mReply(rdWin *w, int n, char *arg) { mWin *mw = allocMWin(mCompArt, n); char *title = "Reply abort deliver "; static char body[300]; /* XXX */ mString *from = mbox->msgs[n]->from; mString *subject = mbox->msgs[n]->subject; int lfrom, lsubject; char *me = getenv("USER"); char *re = "Re: "; if (!me || !*me) me = ""; lfrom = (from->s1 - from->s0); /* include newline */ lsubject = (subject->s1 - subject->s0); if (lsubject > 4 && strncmp(subject->s0, re, 4)==0) re = ""; sprintf(body,"From: %s\nTo: %.*sSubject: %s%.*s\n", me, lfrom, from->s0, re, lsubject, subject->s0); getArtWin(n, mw, title, body, 0, 0); return; } void mAbort(rdWin *w, int n, char *arg) { mWin *mw; if ((mw = findMWin(w->userp)) == 0) return; if (mw->kind != mCompArt) return; fprintf(stderr,"Message aborted\n"); closeWin(w); freeMWin(mw); return; } void mDeliver(rdWin *w, int n, char *arg) { mWin *mw; char *filename = tmpnam((char *)0); if ((mw = findMWin(w->userp)) == 0) return; if (mw->kind != mCompArt) return; fprintf(stderr,"Attempting to deliver message"); rdBodyToFile(w, filename); dodeliver(w,filename); return; } void mQuit(rdWin *w, int n, char *arg) { update_mbox(mbox); mExit(w, n, arg); } void mExit(rdWin *w, int n, char *arg) { mWin *mw; rdWin *rw; /* close msg windows first */ for (mw = mwindows; mw; mw = mw->next) if (mw->kind == mCompArt || mw->kind == mDispArt) if ((rw = userpWin(mw))) closeWin(rw); for (mw = mwindows; mw; mw = mw->next) if (mw->kind != mCompArt && mw->kind != mDispArt) if ((rw = userpWin(mw))) closeWin(rw); exit(0); /* not actually needed - reader will exit for us */ } void mComp(rdWin *w, int n, char *arg) { mWin *mw = allocMWin(mCompArt, n); char *title = "Compose abort deliver "; static char body[300]; /* XXX */ char *me = getenv("USER"); if (!me || !*me) me = ""; sprintf(body,"From: %s\nTo: \nSubject: \n\n", me); getArtWin(n, mw, title, body, 0, 0); return; } void dodeliver(rdWin *w, char *filename) { static char cmd[100]; /* XXX another guess */ mWin *mw; if ((mw = findMWin(w->userp)) == 0) return; sprintf(cmd,"%s < %s", MTU, filename); printf("command: '%s'\n",cmd); fflush(stdout); system(cmd); closeWin(w); freeMWin(mw); return; } void mSavefile(rdWin *w, int n, char *arg) { if (savefile) free(savefile); savefile = sstrdup(arg); } void mSave(rdWin *w, int n, char *arg) { FILE *fp; mWin *mw; mMsg *m; mString *text; size_t len; if (savefile == 0) { fprintf(stderr,"No savefile yet: 'savefile filename'\n"); return; } if ((fp = fopen(savefile,"a")) == 0) { perror(savefile); return; } if ((mw = findMWin(w->userp)) == 0) return; m = mw->mbox->msgs[n]; text = &m->whole; len = text->s1 - text->s0; if (fwrite(text->s0, (size_t)1, len, fp) != len) perror("fwrite"); fputc('\n',fp); printf("Written message %d to %s\n", n, savefile); fflush(stdout); fclose(fp); } void mMultiart(rdWin *w, int n, char *arg) { multiart = !multiart; rdSetMulti(0, multiart); } void mInclude(rdWin *w, int n, char *arg) { doinclude(w,n,arg,0); } void mIncludeall(rdWin *w, int n, char *arg) { doinclude(w,n,arg,1); } void doinclude(rdWin *w, int n, char *arg, int all) { mWin *mw; rdWin *ow; int msgnum; /* message we're going to include */ mMsg *m; mString *s; size_t len; if ((mw = findMWin(w->userp)) == 0) return; if (mw->kind != mCompArt) return; msgnum = mw->msg; /* default value */ if (*arg) { if ((msgnum = atoi(arg)) == 0) { fprintf(stderr,"'%s' is an invalid message number\n", arg); return; } else { msgnum--; } } if (msgnum >= mw->mbox->nmsgs) { fprintf(stderr,"Only %d messages\n", mw->mbox->nmsgs); return; } m = mw->mbox->msgs[msgnum]; s = all? &(m->whole) : &(m->body); len = s->s1 - s->s0; rdInclude(w, s->s0, len); } e_t len; mWinwily-0.13.42/tools/old/reader/mail.h000064402366570000012000000022721033320152300167520ustar00ozstaff00004330000002/* * stuff needed for the mail client. * smk */ #include "headers.h" #include "mbox.h" typedef struct _mWin mWin; /* * We know of several different kinds of window: mailbox lists, * message lists, displayed articles and messages being composed. */ enum { mMboxList, /* list of mailboxes */ mMsgList, /* list of msgs in a mailbox */ mDispArt, /* a displayed article within a mailbox */ mCompArt /* a new article being composed */ }; struct _mWin { int kind; /* what kind of window it is */ int msg; /* message number, if mDispArt, or mCompArt */ mMbox *mbox; /* the message box we're associated with */ struct _mWin *next; }; /* * These are the commands that the mailer recognises, and the * contexts that they are valid. */ #define MCMSGLIST 01 #define MCDISPART 02 #define MCCOMPART 04 #define MCNOTCOMP (MCMSGLIST|MCDISPART) #define MCANY (MCMSGLIST|MCDISPART|MCCOMPART) struct mCmd { char *cmd; unsigned short context; void (*fn)(rdWin *, int, char *); /* pane, msg num, arg */ }; /* * The following must be the pathname of a program capable * of taking a complete message on stdin, with no arguments, * and delivering it. */ #define MTU "/usr/lib/sendmail -t" wily-0.13.42/tools/old/reader/mbox.c000064402366570000012000000155201033320152300167700ustar00ozstaff00004330000002/* * mbox.c */ #include "headers.h" #include "mbox.h" #include #include #define COPYSIZE 8192 #define INCR 10 static mMbox *currmbox; /* current mbox being processed */ static mMsg *msg; /* current message */ static int nhdrs; /* number of current headers read so far. */ static int ahdrs; /* number of allocated hhdrs */ static mHdr **hdrs; /* current list */ static char *readhdrs(char *ptr); static void mkhdr(char *s0, char *s1); static void checkhide(mHdr *h); static void newmsg(char *s0); static char *readmsg(char *ptr); static int same(mString a, mString b); static int strsame(char *s, mString b); static void fillmsg(mMsg *msg); static void fillhdr(char *name, mMsg *msg, mString **ptr); static ulong getlength(void); static char *findend(char *ptr); /* * readhdrs(ptr) - read the headers in a message, looking for * the terminating newline. Returns pointer to first char in body. */ static char * readhdrs(char *ptr) { char *nptr = ptr; /* invariant is that nptr pts to first char of next header. when it doesn't (nptr==\n), we've reached the blank line at then end of the hdrs */ while (*nptr != '\n') { if ((nptr = strchr(nptr,'\n')) == 0) panic("No newlines in readhrds()"); if (nptr[1]==' ' || nptr[1]=='\t') { /* multi-line hdr */ nptr++; continue; } else { mkhdr(ptr, ++nptr); ptr = nptr; continue; } } return ++nptr; /* skip blank line */ } /* * mkhdr(s0,s1) - add a new header to the current list. */ static void mkhdr(char *s0, char *s1) { size_t l; char *c = strchr(s0, ':'); mHdr *h; if (c == 0) panic("no colon in hdr"); if (nhdrs >= ahdrs) { ahdrs += INCR; l = ahdrs * sizeof(*hdrs); hdrs = (mHdr **)(hdrs? realloc(hdrs,l) : malloc(l)); if (hdrs == 0) panic("resizing hdr list"); } h = hdrs[nhdrs++] = (mHdr *)malloc(sizeof(*h)); if (h == 0) panic("adding new hdr"); h->name.s0 = s0; h->name.s1 = c++; while (*c == ' ' || *c == '\t') c++; h->value.s0 = c; h->value.s1 = s1; checkhide(h); } static void checkhide(mHdr *h) { /* none are hidden, for now. */ h->hide = 0; } static void newmsg(char *s0) { size_t n; if (currmbox->nmsgs >= currmbox->amsgs) { currmbox->amsgs += INCR; n = currmbox->amsgs*sizeof(*currmbox->msgs); currmbox->msgs = (mMsg **)(currmbox->msgs? realloc(currmbox->msgs,n) : malloc(n)); if (currmbox->msgs == 0) panic("newmsg msg"); } msg = currmbox->msgs[currmbox->nmsgs++] = (mMsg *)malloc(sizeof(*msg)); if (msg == 0) panic("adding new msg"); memset(msg,0,sizeof(*msg)); msg->whole.s0 = s0; if ((hdrs = (mHdr **)malloc((ahdrs = INCR)*sizeof(*hdrs)))==0) panic("newmsg hdrs"); nhdrs = 0; } /* * readmsg(ptr) - read a complete message. Assumes we're already pointing * to the F of the "From " */ static char * readmsg(char *ptr) { char *nptr; ulong contentlength; newmsg(ptr); /* resets nhdrs and hdrs, too */ if ((nptr = strchr(ptr,'\n')) == 0) /* skip From line */ panic("From line broken"); nptr = readhdrs(nptr+1); msg->nhdrs = nhdrs; msg->hdrs = hdrs; msg->body.s0 = nptr; if ((contentlength = getlength()) == 0) nptr = findend(nptr); else nptr += contentlength; msg->whole.s1 = msg->body.s1 = nptr; fillmsg(msg); /* update from,date,subject fields */ return nptr+1; } static int same(mString a, mString b) { if ((a.s1 - a.s0) != (b.s1 - b.s0)) return 0; return (strncmp(a.s0,b.s0,a.s1-a.s0) == 0); } static int strsame(char *s, mString b) { mString a; a.s0 = s; a.s1 = s + strlen(s); return same(a,b); } static void fillmsg(mMsg *msg) { fillhdr("From",msg,&msg->from); fillhdr("Date",msg,&msg->date); fillhdr("Subject",msg,&msg->subject); } static void fillhdr(char *name, mMsg *msg, mString **ptr) { int x; static mString empty; for (x = 0; x < msg->nhdrs; x++) if (strsame(name,msg->hdrs[x]->name)) { *ptr = &(msg->hdrs[x]->value); return; } /* Sigh. This sort of thing is very irritating. */ empty.s0 = empty.s1 = msg->whole.s1; *ptr = ∅ (void)fprintf(stderr,"Message does not have a '%s' header\n",name); } static ulong getlength(void) { int x; ulong l; for (x = 0; x < nhdrs; x++) if (strsame("Content-Length",hdrs[x]->name)) goto found; return 0; found: /* use sscanf magic to skip whitespace, and stop at end */ if (sscanf(hdrs[x]->value.s0,"%lu",&l) != 1 || l==0) return 0; if ((msg->body.s0+l+1) == currmbox->mbox_end) return l; /* spot on */ if ((msg->body.s0+l+5) >= currmbox->mbox_end) return 0; /* too long */ if (strncmp("\nFrom ",(msg->body.s0+l),6) == 0) return l; else return 0; } static char * findend(char *ptr) { for (; ptr+5 <= currmbox->mbox_end && strncmp("\nFrom ",ptr,6); ptr++) if ((ptr = strchr(ptr,'\n')) == 0) panic("findend"); if (ptr+5 > currmbox->mbox_end) return currmbox->mbox_end-1; else return ptr; } mMbox * read_mbox(const char *filename, int readonly) { char *ptr; extern int load_mbox(mMbox *); if ((currmbox = (mMbox *)malloc(sizeof(*currmbox))) == 0) return 0; memset(currmbox,0,sizeof(*currmbox)); currmbox->readonly = readonly; if ((currmbox->name = strdup(filename)) == 0) goto panic2; if (load_mbox(currmbox)) goto panic1; for (ptr = currmbox->mbox_start; ptr < currmbox->mbox_end; ) if ((ptr = readmsg(ptr)) == 0) goto panic1; return currmbox; panic1: free(currmbox->name); panic2: free(currmbox); return 0; } /* * update_mbox(mbox) - write any changes back to the file. */ int update_mbox(mMbox *mbox) { static char lockname[FILENAME_MAX+1], newname[FILENAME_MAX+1]; int ntries, maxtries = 10; int fd, fd2; int x; struct stat st; int r = 0; int l; mMsg *m; if (mbox->readonly || mbox->ndel == 0) return 0; (void)sprintf(lockname,"%s.lock",mbox->name); (void)sprintf(newname,"%s.new",mbox->name); for (ntries = 0; ntries < maxtries; ntries++) { if (link(mbox->name,lockname) == 0) goto locked; sleep(1); } locked: if (stat(mbox->name,&st) == -1) goto broken; if (st.st_size < mbox->size) { fprintf(stderr,"Mail file corrupted - no changes made\n"); goto broken; } if ((fd = open(newname,O_RDWR|O_CREAT|O_TRUNC)) < 0 || fchmod(fd,st.st_mode) == -1) goto broken; for (x = 0; x < mbox->nmsgs; x++) { m = mbox->msgs[x]; if (m->deleted) continue; l = m->whole.s1 - m->whole.s0 + 1; if (write(fd,m->whole.s0,l) != l || write(fd,"\n",1) != 1) { fprintf(stderr,"write truncated, changes aborted\n"); goto broken; } } if (st.st_size > mbox->size) { static char buf[COPYSIZE]; if ((fd2 = open(mbox->name,O_RDONLY)) < 0 || lseek(fd2,mbox->size,SEEK_SET) == -1) { fprintf(stderr,"Can't open mbox for update!\n"); goto broken; } while ((l = read(fd2,buf,COPYSIZE)) > 0) if (write(fd,buf,l) != l) { fprintf(stderr,"Can't copy updated mbox\n"); close(fd2); goto broken; } close(fd2); } rename(newname,mbox->name); goto unlock; broken: r = 1; if (fd >= 0) close(fd); unlink(newname); unlock: unlink(lockname); return r; } rs, too */ if ((nptr = strchr(ptr,'\n')) == 0) /* skip From line */ panic("From line broken"); nptr = readhdrs(nptr+1); msg->nhdrs = nhdrs; msg->hdrs = hdrs; msg->body.swily-0.13.42/tools/old/reader/mbox.h000064402366570000012000000033271033320152300167770ustar00ozstaff00004330000002/* * mbox.h - definitions for mailbox-handling library. */ #ifndef MBOX_H #define MBOX_H #include typedef struct mstring mString; typedef struct mhdr mHdr; typedef struct mmsg mMsg; typedef struct mhdrline mHdrLine; typedef struct mmbox mMbox; struct mstring { /* can include several \n characters */ char *s0; /* first char in string */ char *s1; /* char after last newline */ }; struct mhdr { /* includes ws if hdr is multiple lines */ mString name; /* s1 points to colon */ mString value; /* s0 pts to first non-ws, s1 to after \n */ int hide; /* don't display if true */ }; /* name,s0,value.s2 gives whole header */ struct mmsg { int nhdrs; /* number of headers */ mHdr **hdrs; /* headers themselves */ mString *from; /* points to value fields from mHdrs */ mString *date; mString *subject; mString whole; /* All of the message (headers and body) */ mString body; /* All of the body (not including first blank line) */ int deleted; /* marked for deletion */ int read; /* if has been read */ ulong pos; /* origin in window, if it's been read before. */ }; struct mhdrline { char *s0,*s1; /* buffer containing accumulated text */ ulong p0, p1; /* positions in hdrw for this piece of text */ }; struct mmbox { char *mbox_start; /* area of memory that the mailbox is */ char *mbox_end; /* loaded into */ int nmsgs; /* number of messages */ int amsgs; /* size of msgs array */ mMsg **msgs; /* the messages themselves */ int ndel; /* number of deleted messages */ int readonly; time_t mtime; /* time it was last modified */ off_t size; /* how big it was, last time we checked */ char *name; /* the filename */ }; mMbox *read_mbox(const char *filename, int readonly); #endif /* ! MBOX_H */ wily-0.13.42/tools/old/reader/utils.c000064402366570000012000000004521033320152300171610ustar00ozstaff00004330000002/* * general utilities... */ #include "headers.h" char * sstrdup(char *str) { char *s = salloc(strlen(str)+1); strcpy(s,str); return s; } void panic(const char *msg) { fprintf(stderr,"%s\n", msg); exit(1); } ulong atoul(char *str) { return strtoul((const char *)str, (char **)0, 10); } wily-0.13.42/tools/old/reader/reader.c000064402366570000012000000331531033320152300172670ustar00ozstaff00004330000002/* * reader.c - functions for handling news/article reader windows. */ #include "headers.h" Bool debug = true; Bool frommessage = true; /* * These determine whether we'll have one list and one article window, * that gets overwritten each time we change group/mailbox/article, * or whether we just spawn a new one. */ int rdMultiList = 0; int rdMultiArt = 0; /* * The windows currently active. */ rdWin *windows = 0; static rdWin *Listwin = 0; static rdWin *Artwin = 0; /* * General wily comms stuff. */ Mqueue realwilyq; Mqueue *wilyq = &realwilyq; Fd wilyfd; /* * default contents of tags */ char *rdListTagStr = " delete undelete comp reply quit exit "; char *rdArtTagStr = " delete reply save inc "; static rdWin *allocWin(rdWinType kind, const char *title); static int connectWin(rdWin *w, char *filename); static rdWin *getWin(int user, void *userp, rdWinType kind, char *title, char *filename); static void clearWin(rdWin *w); static void freeItems(rdWin *w); static int loadItems(rdWin *w, char **items, int savecontents); static int initWin(int user, void *userp, rdWin *w, char *title, char *filename); static void anyEvent(rdWin *w); static void winDelete(rdWin *w, int which, ulong p0, ulong p1); static void winInsert(rdWin *w, int which, ulong p, char *str); static void updateBody(rdWin *w, ulong p0, ulong p1, char *str); static void winGoto(rdWin *w, ulong p0, char *str); static void winExec(rdWin *w, char *cmd, char *arg); static void DelWin(rdWin *w, char *arg); static int rdBuiltin(rdWin *w, char *cmd, char *str); static void addrEvent(rdWin *w); static void bodyEvent(rdWin *w); static size_t countlines(char *str, size_t len); static void prefixlines(char *str, size_t len, char *prefix, size_t plen, char *buf); /* * allocWin(kind, title) - create a new, blank window of a given kind. */ static rdWin * allocWin(rdWinType kind, const char *title) { rdWin *w = salloc(sizeof(*w)); w->title = sstrdup((char *)title); w->wintype = kind; w->id = -1; w->m = 0; if (kind == rdList) w->items = 0; else w->body = 0; w->taglen = w->bodylen = 0; w->next = windows; windows = w; return w; } /* * connectWin(w, filename) - connect to wily, to create a new window. * If filename is true, then we get wily to open the given file. Otherwise, * we ask for a new, blank window. * Returns 0 for success. */ static int connectWin(rdWin *w, char *filename) { int fd; if (filename == 0) filename = "New"; if (rpc_new(wilyq, &w->id, filename, false) < 0) { freeWin(w); return -1; } return 0; } /* * getWin(user, userp, kind, title, filename) - grab a window of the appropriate type. */ static rdWin * getWin(int user, void *userp, rdWinType kind, char *title, char *filename) { rdWin *w; if ((!Listwin || kind == rdList && rdMultiList) || (!Artwin || kind == rdArticle && rdMultiArt)) { /* we can create a new window */ w = allocWin(kind, title); if (connectWin(w,filename)) return 0; if (kind == rdList) Listwin = w; else Artwin = w; } else { /* have to reuse the existing window */ w = (kind == rdList)? Listwin : Artwin; clearWin(w); } initWin(user, userp, w, title, filename); return w; } /* * clearWin(w) - erase the tag and body of a window */ static void clearWin(rdWin *w) { if (w->taglen) (void) rpc_settag(wilyq, w->id, ""); w->taglen = 0; if (w->bodylen) { (void) rpc_delete(wilyq, w->id, 0, w->bodylen); w->bodylen = 0; if (w->wintype == rdList) freeItems(w); } } /* * discard all the items in the window's list */ static void freeItems(rdWin *w) { rdItem *i, *j; for (i = w->items; i; i = j) { j = i->next; free(i); } w->items = 0; } /* * loadItems(w, items) - load an array of items into the list, and into the window. */ static int loadItems(rdWin *w, char **items, int savecontents) { rdItem *i, *j = 0; char *sep = "\n"; ulong p0 = 0; ulong len, seplen = strlen(sep); char *buf = 0; int n; if (savecontents) { for (len = 0, n = 0; items[n]; n++) len += strlen(items[n]) + seplen; w->body = buf = salloc(len); } while (*items) { i = salloc(sizeof(*i)); i->next = 0; i->p0 = p0; len = strlen(*items); if (j) j->next = i; else w->items = i; j = i; if (rpc_insert(wilyq, w->id, p0, *items)) { freeItems(w); return -1; } p0 += len; if (rpc_insert(wilyq, w->id, p0, sep)) { freeItems(w); return -1; } i->p1 = (p0 += seplen); items++; } w->bodylen = p0; return 0; } /* * changeItems(w, items, savecontents) - update the contents of a list window. */ int changeItems(rdWin *w, char **items, int savecontents) { if (w->wintype != rdList) return 1; freeItems(w); if (w->bodylen) { if (rpc_delete(wilyq, w->id, 0, w->bodylen)) return 1; w->bodylen = 0; } return loadItems(w, items, savecontents); } /* * initWin(user, userp, w, title, filename) - initialise the window's tag, label, etc. */ static int initWin(int user, void *userp, rdWin *w, char *title, char *filename) { char tag[300]; /* XXX guess */ char *tagstr = w->wintype == rdArticle? rdArtTagStr : rdListTagStr; if (rpc_setname(wilyq, w->id, title)) return 1; sprintf(tag,"%s", tagstr); /* XXX at the moment, we don't include the title */ if (rpc_settag(wilyq, w->id, tag)) return 1; w->taglen = strlen(tag); w->user = user; w->userp = userp; return 0; } /* * getArtWin(title, text, filename, savecontents) - get an article window, and load it with * either the given text, or from the given file. */ int getArtWin(int user, void *userp, char *title, char *text, char *filename, int savecontents) { rdWin *w = getWin(user, userp, rdArticle, title, filename); if (w == 0) return 1; if (text) { int l = strlen(text); w->bodylen = l; if (rpc_insert(wilyq, w->id, 0, text)) return 1; if (savecontents) { w->body = salloc(l); strcpy(w->body, text); } } return 0; } /* * get a List window, and load it with the items in the array (which * must be null-terminated). */ int getListWin(int user, void *userp, char *title, char **items, int savecontents) { rdWin *w = getWin(user, userp, rdList, title, (char *)0); if (w == 0) return 1; return loadItems(w, items, savecontents); } /* * readerInit(title, items, ml, ma) - start things off by creating * a list window. Tell the reader whether we'll want one or more of * the list and article windows. */ int readerInit(int user, char *userp, char *title, char **items, int ml, int ma, int savecontents) { rdMultiList = ml; rdMultiArt = ma; if ((wilyfd = get_connect()) < 0) return 1; mq_init(wilyq, wilyfd); return getListWin(user, userp, title, items, savecontents); } /* * readerMainLoop() - get messages from wily, and act upon them. */ int readerMainLoop(void) { rdWin *w; Msg *m; int istag; while (windows) { if ((w = getActiveWin()) == 0) { fprintf(stderr,"No message available\n"); return 1; } m = w->m; switch (m->mtype) { char *cmd, *arg; ulong p0, p1; case EMexec: decode_exec_e(m, &cmd, &arg); winExec(w, cmd, arg); break; case EMgoto: decode_goto_e(m, &p0, &arg); winGoto(w, p0, arg); break; case EMinsert: istag = IsBody; decode_insert_e(m, &p0, &arg); winInsert(w, istag, p0, arg); break; case EMdelete: istag = IsBody; decode_delete_e(m, &p0, &p1); winDelete(w, istag, p0, p1); break; default: fprintf(stderr,"Unknown msg type!\n"); exit(1); } } return 1; } /* * text has been deleted */ static void winDelete(rdWin *w, int which, ulong p0, ulong p1) { rdItem *i; ulong l = p1 - p0; if (which == IsTag) { w->taglen -= l; return; } if (w->wintype == rdArticle) { w->bodylen -= l; return; } for (i = w->items; i; i = i->next) if (i->p0 <= p0 && p1 <= i->p1) break; if (!i) return; i->p1 -= l; for (i = i->next; i; i = i->next) { i->p0 -= l; i->p1 -= l; } updateBody(w, p0, p1, (char *)0); return; } /* * text has been inserted */ static void winInsert(rdWin *w, int which, ulong p, char *str) { rdItem *i; int l = strlen(str); if (which == IsTag) { w->taglen += l; return; } if (w->wintype == rdArticle) { w->bodylen += l; return; } for (i = w->items; i; i = i->next) if (i->p0 <= p && p <= i->p1) break; if (!i) return; i->p1 += l; for (i = i->next; i; i = i->next) { i->p0 += l; i->p1 += l; } updateBody(w, p, (ulong)l, str); return; } /* * updateBody(w,p0,p1,str) - insert p1 chars of str at p0, or remove the text * between p0 and p1. * XXX - this is *utterly* revolting, and horrendously slow. But it's quick * and simple, and will do for now. */ static void updateBody(rdWin *w, ulong p0, ulong p1, char *str) { char *newbuf; ulong newlen; if (w->body == 0) return; if (str) newlen = w->bodylen + p1; else newlen = w->bodylen - (p1 - p0); newbuf = salloc(newlen); strncpy(newbuf, w->body, p0); if (str) { strncpy(newbuf + p0, str, p1); strcpy(newbuf + p0 + p1, w->body + p0); } else { strcpy(newbuf + p0, w->body + p1); } free(w->body); w->body = newbuf; w->bodylen = newlen; } int itemNumber(rdWin *w, ulong p0, ulong p1, void **ptr) { int n; rdItem *i; if (w->wintype != rdList) return -1; for (n = 0, i = w->items; i; i = i->next, n++) if (i->p0 <= p0 && p1 <= i->p1) { *ptr = (void *)i; return n; } return -1; /* sigh */ } void highlightItem(rdWin *w, int n, void *ptr) { static char addr[80]; /* XXX - overkill */ rdItem *i = (rdItem *)ptr; if (i == 0) for (i = w->items; n--; i = i->next); sprintf(addr,"#%lu,#%lu", i->p0, i->p1); (void)rpc_goto(wilyq, w->id, addr); } /* * A B3 event has occured. */ static void winGoto(rdWin *w, ulong p0, char *str) { /* If this is a list, then it counts as a selection. Otherwise, we just reflect it back to wily as a normal B3 event. */ if (w->wintype == rdList) { int n; rdItem *i; fprintf(stderr,"Hit at (%lu)\n",p0); if ((n = itemNumber(w, p0, p0, (void **)&i)) == -1) return; /* sigh */ fprintf(stderr,"Is item %d expands to (%lu,%lu)\n",n, i->p0, i->p1); highlightItem(w, n, i); user_listSelection(w,n); return; } else (void)rpc_goto(wilyq, w->id, str); return; } /* * A B2(B1) command has been invoked. */ static void winExec(rdWin *w, char *cmd, char *arg) { ulong p0, p1; /* * Lots of options here: * - B2 with "|<>" - reflect back to wily. * - B2 cmd recognised by the reader routines - Del is about it. Execute * them ourselves. * - B2 not recognised by the reader routines - pass them onto the user, * after first getting the position of the argument within the body, if * necessary. * - B2B1 recognised by the reader routines - none spring to mind, but * I might add some. Execute them ourselves. * - B2B1 not recognised - pass onto user. */ if (!*cmd || strstr(cmd,"|<>")) { winReflectCmd(w,cmd, arg); return; } if (rdBuiltin(w,cmd,arg) == 0) return; if (rpc_addr(wilyq, w->id, ".", &p0, &p1)) return; if (w->wintype == rdList) { rdItem *i; int n; if ((n = itemNumber(w, p0, p1, (void *)&i)) != -1) { highlightItem(w, n, i); p0 = i->p0; p1 = i->p1; user_cmdList(w,cmd,p0,p1,n,arg); return; } } user_cmdArt(w, cmd, p0, p1, arg); return; } void winReflectCmd(rdWin *w, char *cmd, char *arg) { (void)rpc_exec(wilyq, w->id,cmd,arg); } /* * delete this particular window from the list. */ static void DelWin(rdWin *w, char *arg) { closeWin(w); } void closeWin(rdWin *w) { /* get wily to close the pane */ (void)rpc_exec(wilyq, w->id, "Del", ""); /* free up resources */ free(w->title); free(w->body); if (w->wintype == rdList) freeItems(w); /* XXX - currently leak the stateinfo stuff */ freeWin(w); return; } void freeWin(rdWin *w) { rdWin **wp = &windows; /* remove from the window chain */ while ((*wp) != w) wp = &((*wp)->next); *wp = w->next; if (w == Artwin) Artwin = 0; if (w == Listwin) Listwin = 0; if (windows == 0) exit(0); return; } static struct { char *cmd; void (*fn)(rdWin *, char *); } builtins[] = { { "Del", DelWin }, { 0, 0 } }; /* * check for builtin commands understood by the reader routines. */ static int rdBuiltin(rdWin *w, char *cmd, char *str) { int i; for (i = 0; builtins[i].cmd; i++) if (strcmp(builtins[i].cmd, cmd) == 0) { (*builtins[i].fn)(w, str); return 0; } return 1; } /* * "redisplay" a window that's already open. */ void rdGotoWin(rdWin *w) { (void)rpc_goto(wilyq, w->id, "."); } rdWin * userpWin(void *ptr) { rdWin *w = windows; while (w && w->userp != ptr) w = w->next; return w; } /* * Some routines which attempt to extract the body of a window, * and store it in a file. if p0==p1==0, assume all the body is wanted. */ void rdBodyToFile(rdWin *w, char *filename) { FILE *fp; char *buf = salloc(w->bodylen+1); if (rpc_read(wilyq, w->id, 0, w->bodylen, buf)) return; if ((fp = fopen(filename, "w"))) { (void)fprintf(fp,"%s",buf); fclose(fp); } free(buf); return; } /* * change current settings for multi-list and multi-art windows. */ void rdSetMulti(int list, int art) { rdMultiList = list; rdMultiArt = art; } void rdInclude(rdWin *w, char *str, size_t len) { size_t nlines = countlines(str, len); char *buf; char *prefix = "> "; size_t nlen, plen = strlen(prefix); ulong p0, p1; if (rpc_addr(wilyq, w->id, ".", &p0, &p1)) return; nlen = len + nlines*plen + 1; buf = salloc(nlen); prefixlines(str, len, prefix, plen, buf); rpc_insert(wilyq, w->id, p1, buf); w->bodylen += nlen; free(buf); } static size_t countlines(char *str, size_t len) { size_t nlines = 0; while (len--) if (*str++ == '\n') nlines++; return nlines; } static void prefixlines(char *str, size_t len, char *prefix, size_t plen, char *buf) { while (len) { strncpy(buf,prefix,plen); buf += plen; while (len-- && (*buf++ = *str++) != '\n') ; } *buf = 0; } oadItems(w, items) - load an array of items into the list, and into the window. */ static int loadItems(rdWin *w, char **items, int savecontents) { rdItem *i, *j = 0; char *sep = "\n"; ulong p0 = 0; ulong len, seplen = strlen(sep); char *buf = 0; int n; if (savecontents) { for (len = 0, n = 0; items[n]; n++) len += strlen(items[n]) + seplen; w->body = buf = salloc(len); } while (*itewily-0.13.42/tools/old/reader/reader.h000064402366570000012000000022201033320152300172630ustar00ozstaff00004330000002/* * reader.h - declarations for a mail/news reader toolkit for wily. */ /* * We support two kinds of window - a list (mailboxes, newsgroups, subject lines) * and an article display. There can be more than one instance of each. */ typedef enum _rdWinType { rdList, rdArticle } rdWinType; /* * This makes the messages clearer */ enum { IsTag = 0, IsBody = 1 }; typedef struct _rdWin rdWin; typedef struct _rdItem rdItem; typedef struct _Msgq Msgq; extern int rdMultiList; extern int rdMultiArt; struct _rdItem { ulong p0, p1; /* address of this item in the window. */ struct _rdItem *next; /* next item in the list */ }; struct _rdWin { rdWinType wintype; int user; /* user info */ void *userp; /* ditto */ Id id; struct _rdWin *next; /* list storage */ char *title; /* what we think the title of this window is */ ulong taglen; /* length of tag, in characters */ ulong bodylen; /* length of body, in characters */ Msg *m; /* message from wily */ char *body; /* UTF text of an article window */ rdItem *items; /* The items in a list */ }; extern rdWin *windows; extern Mqueue *wilyq; wily-0.13.42/tools/old/reader/proto.h000064402366570000012000000020411033320152300171650ustar00ozstaff00004330000002void queueMsg(rdWin *w); void freeMsgq(rdWin *w); rdWin *getActiveWin(void); int changeItems(rdWin *w, char **items, int savecontents); void user_listSelection(rdWin *w, int n); void user_cmdList(rdWin *w, char *cmd, ulong p0, ulong p1, int n, char *arg); void user_cmdArt(rdWin *w, char *cmd, ulong p0, ulong p1, char *arg); char *sstrdup(char *str); int getArtWin(int user, void *userp, char *title, char *text, char *filename, int savecontents); int getListWin(int user, void *userp, char *title, char **items, int savecontents); int readerInit(int user, char *userp, char *title, char **items, int ml, int ma, int savecontents); int readerMainLoop(void); int itemNumber(rdWin *w, ulong p0, ulong p1, void **ptr); void highlightItem(rdWin *w, int n, void *ptr); void winReflectCmd(rdWin *w, char *cmd, char *arg); void closeWin(rdWin *w); void freeWin(rdWin *w); void msg_handler(rdWin *w); void rdGotoWin(rdWin *w); rdWin *userpWin(void *ptr); ulong atoul(char *str); void rdSetMulti(int list, int art); void rdInclude(rdWin *w, char *str, size_t len); wily-0.13.42/tools/tcl/000075502366570000012000000000001033320152300144165ustar00ozstaff00004330000002wily-0.13.42/tools/tcl/wnew000064402366570000012000000003031033320152300153150ustar00ozstaff00004330000002#!wtcl # # $Header: /u/cvs/wtcl/wnew,v 1.1.1.1 1996/11/12 21:28:09 cvs Exp $ # wily init set wd [pwd] foreach i "$argv" { if [regexp "^/" $i] { wily new $i } else { wily new "$wd/$i" } } wily-0.13.42/tools/tcl/wtktest000064402366570000012000000005211033320152300160440ustar00ozstaff00004330000002#!wtk # # $Header: /u/cvs/wtcl/wtktest,v 1.1 1996/11/12 23:34:01 cvs Exp $ # wily init proc cmd {name} { set id [lindex [wily list] 0] wily exec $id $name } button .quit -text Quit -command {cmd Quit} button .putall -text Putall -command {cmd Putall} button .font -text Font -command {cmd Font } pack .quit .putall .font -side left wily-0.13.42/tools/tcl/Makefile000064402366570000012000000007721033320152300160640ustar00ozstaff00004330000002# # $Header: /u/cvs/wtcl/Makefile,v 1.2 1996/11/12 23:33:55 cvs Exp $ # CC=gcc W=$(TMPDIR)/wily-0.13.19/ WINC=-I$W -I$W/include -I$W/libXg -I$W/sam/include INC=-I/usr/local/include $(WINC) WLD=-L$W/sam/libXg -L$W/libmsg -lmsg -lXg CFLAGS=-Wall $(INC) LDFLAGS=-L/usr/local/lib -ltk -ltcl -lX11 -lm $(WLD) T=wtcl wtk S=wtcl.c wtk.c wily.c O=$(S:.c=.o) all : $T wtcl : wtcl.o wily.o $(CC) -o $@ wtcl.o wily.o $(LDFLAGS) wtk : wtk.o wily.o $(CC) -o $@ wtk.o wily.o $(LDFLAGS) clean : rm -f $T $O core wily-0.13.42/tools/tcl/wlist000064402366570000012000000002331033320152300155010ustar00ozstaff00004330000002#!wtcl # # $Header: /u/cvs/wtcl/wlist,v 1.2 1996/11/12 23:34:00 cvs Exp $ # wily init foreach i [wily list] { set name [wily name $i] puts "$i\t$name" } wily-0.13.42/tools/tcl/wname000064402366570000012000000003131033320152300154450ustar00ozstaff00004330000002#!wtcl # # $Header: /u/cvs/wtcl/wname,v 1.1.1.1 1996/11/12 21:28:10 cvs Exp $ # wily init if [expr $argc != 2] { puts "usage: $argv0 " exit 1 } wily name [lindex $argv 0] [lindex $argv 1] wily-0.13.42/tools/tcl/wtk.c000064402366570000012000000010221033320152300153620ustar00ozstaff00004330000002/* $Header: /u/cvs/wtcl/wtk.c,v 1.1.1.1 1996/11/12 21:28:10 cvs Exp $ */ #include #include #include "wtcl.h" extern int Tcl_AppInit( Tcl_Interp *interp ) { if(Tcl_Init(interp) == TCL_ERROR) return TCL_ERROR ; if(Tk_Init(interp) == TCL_ERROR) return TCL_ERROR ; if(Wily_Init(interp) == TCL_ERROR) return TCL_ERROR ; Tcl_SetVar(interp, "tcl_rcFileName", "~/.wtk", TCL_GLOBAL_ONLY) ; return TCL_OK ; } extern int main( int argc, char **argv ) { Tk_Main(argc, argv, Tcl_AppInit) ; return 0 ; } wily-0.13.42/tools/tcl/README000064402366570000012000000033301033320152300152750ustar00ozstaff00004330000002this is a package of tools for communicating with wily using the Tcl library. the file wily.c defines a thin veneer round wily's libmsg. this compiles with wily-0.13.1[89] with tclversion 7.4. the files wtcl.c and wtk.c compile against wily.c to give a tclsh alike with wily support called wtcl, and a wish alike with wily support called wtk. the only addition to standard tcl/tk is the ``wily'' command. this has several subcommands wily init connects to wily. should be called before any other wily command wily isconnected checks that we can still talk to wily. returns boolean. wily list returns a list of window ids (integers). wily name returns the name of the window with given id. wily new opens a new window with given filename. wily attach offer to collect events for window with given id. we collect _all_ events. wily setname set the name of window with given id to the given new name. wily settools appends the given tools to the tools for window with given id. wily read returns the text between points and in window . wily replace replaces the text between points and in window id with . wily exec just as if had been b2'd in window . wily goto as if string had been b3'd in windows . if is true then we jump to and select the result. wily length the length of the text in window wily wouldblock return boolean. true if there is no event in queue. false if there is. wily event returns a string describing the event. wily bounce return the last event received back to wily. wily-0.13.42/tools/tcl/wily.c000064402366570000012000000237701033320152300155570ustar00ozstaff00004330000002/* $Header: /u/cvs/wtcl/wily.c,v 1.2 1996/11/12 23:33:58 cvs Exp $ */ #include #include #include #include #include /* * dispatcher within Wily() routine */ typedef struct WCmd WCmd ; struct WCmd { char *name ; int (*proc)(Tcl_Interp*, int, char**) ; } ; /* * the handle to wily. should be 0 if not connected */ static Handle *h ; /* * the last event fetched by rpc_event() used * by bounce -- we can only bounce if we haveevent */ static Bool haveevent = false ; static Msg m ; static Bool iscon( void ) { if(h == 0 || rpc_isconnected(h) == false) { h = 0 ; return false ; } return true ; } /* * check args etc for Wily() sub command. * check that argc == argswanted. * if id != 0 then check that we have an id * and return it as *id. * check we are connected to wily. * if anything fails then set the result string */ static int chk( Tcl_Interp *interp, int argc, char **argv, int argswanted, char *usage, Id *id ) { int n ; if(argc != argswanted) { Tcl_SetResult(interp, usage, TCL_STATIC) ; return TCL_ERROR ; } if(iscon() == false) { Tcl_SetResult(interp, "not connected", TCL_STATIC) ; return TCL_ERROR ; } if(id != 0) { if(Tcl_GetInt(interp, argv[1], &n) != TCL_OK) { Tcl_SetResult(interp, "arg doesn't look like id", TCL_STATIC) ; return TCL_ERROR ; } *id = n ; } return TCL_OK ; } static int wrpc_init( Tcl_Interp *interp, int argc, char **argv ) { int fd ; if(argc != 1) { Tcl_SetResult(interp, "init requires no arguments", TCL_STATIC) ; return TCL_ERROR ; } fd = client_connect() ; if(fd < 0) { Tcl_SetResult(interp, "can't connect", TCL_STATIC) ; return TCL_ERROR ; } h = rpc_init(fd) ; if(h == 0) { Tcl_SetResult(interp, "can't init", TCL_STATIC) ; return TCL_ERROR ; } return TCL_OK ; } static int wrpc_isconnected( Tcl_Interp *interp, int argc, char **argv ) { if(argc != 1) { Tcl_AppendResult(interp, "isconnected requires no arguments", TCL_STATIC) ; return TCL_ERROR ; } if(iscon() == false) { Tcl_SetResult(interp, "0", TCL_STATIC) ; h = 0 ; } else Tcl_SetResult(interp, "1", TCL_STATIC) ; return TCL_OK ; } static int wrpc_list( Tcl_Interp *interp, int argc, char **argv ) { char *p ; char *emsg ; char *t ; char *s ; if(chk(interp, argc, argv, 1, "list requires no arguments", 0) != TCL_OK) return TCL_ERROR ; emsg = rpc_list(h, &p) ; if(emsg != 0) { Tcl_SetResult(interp, emsg, TCL_VOLATILE) ; return TCL_ERROR ; } /* * we trust p to be in a reasonable condition */ t = strtok(p, "\n") ; while(t != 0 && (s = strchr(t, '\t')) != 0) { s++ ; Tcl_AppendElement(interp, s) ; t = strtok(0, "\n") ; } free(p) ; return TCL_OK ; } static int wrpc_name( Tcl_Interp *interp, int argc, char **argv ) { char *p ; char *emsg ; char *t ; char *s ; if(chk(interp, argc, argv, 2, "name requires id", 0) != TCL_OK) return TCL_ERROR ; emsg = rpc_list(h, &p) ; if(emsg != 0) { Tcl_SetResult(interp, emsg, TCL_VOLATILE) ; return TCL_ERROR ; } /* * we trust p to be in a reasonable condition */ t = strtok(p, "\n") ; while(t != 0 && (s = strchr(t, '\t')) != 0) { *s++ = '\0' ; if(strcmp(argv[1], s) == 0) { Tcl_SetResult(interp, t, TCL_VOLATILE) ; free(p) ; return TCL_OK ; } t = strtok(0, "\n") ; } Tcl_SetResult(interp, "id not found", TCL_STATIC) ; free(p) ; return TCL_ERROR ; } static int wrpc_new( Tcl_Interp *interp, int argc, char **argv ) { char *emsg ; Id id ; if(chk(interp, argc, argv, 2, "new needs filename", 0) != TCL_OK) return TCL_ERROR ; emsg = rpc_new(h, argv[1], &id) ; if(emsg != 0) { Tcl_SetResult(interp, emsg, TCL_VOLATILE) ; return TCL_ERROR ; } sprintf(interp->result, "%ld", (long)id) ; return TCL_OK ; } static int wrpc_attach( Tcl_Interp *interp, int argc, char **argv ) { Id id ; char *emsg ; if(chk(interp, argc, argv, 2, "attach needs id", &id) != TCL_OK) return TCL_ERROR ; emsg = rpc_attach(h, id, WEexec | WEgoto | WEdestroy | WEreplace) ; if(emsg != 0) { Tcl_SetResult(interp, emsg, TCL_VOLATILE) ; return TCL_ERROR ; } return TCL_OK ; } static int wrpc_setname( Tcl_Interp *interp, int argc, char **argv ) { Id id ; char *emsg ; if(chk(interp, argc, argv, 3, "setname needs id and new name", &id) != TCL_OK) return TCL_ERROR ; emsg = rpc_setname(h, id, argv[2]) ; if(emsg != 0) { Tcl_SetResult(interp, emsg, TCL_VOLATILE) ; return TCL_ERROR ; } return TCL_OK ; } static int wrpc_settools( Tcl_Interp *interp, int argc, char **argv ) { Id id ; char *emsg ; if(chk(interp, argc, argv, 3, "settools needs id and new text", &id) != TCL_OK) return TCL_ERROR ; emsg = rpc_settools(h, id, argv[2]) ; if(emsg != 0) { Tcl_SetResult(interp, emsg, TCL_VOLATILE) ; return TCL_ERROR ; } return TCL_OK ; } static int wrpc_read( Tcl_Interp *interp, int argc, char **argv ) { Id id ; char *emsg ; Range r ; char *p ; int n ; if(chk(interp, argc, argv, 4, "read needs id, begin and end", &id) != TCL_OK) return TCL_ERROR ; r.p0 = Tcl_GetInt(interp, argv[2], &n) != TCL_OK ? -1 : n ; r.p1 = Tcl_GetInt(interp, argv[3], &n) != TCL_OK ? -1 : n ; if(r.p0 < 0 || r.p1 < 0 || r.p0 > r.p1) { Tcl_SetResult(interp, "strange numbers", TCL_STATIC) ; return TCL_ERROR ; } p = malloc(UTFmax * RLEN(r)) ; if(p == 0) { Tcl_SetResult(interp, "malloc fails", TCL_STATIC) ; return TCL_ERROR ; } emsg = rpc_read(h, id, r, p) ; if(emsg != 0) { free(p) ; Tcl_SetResult(interp, emsg, TCL_VOLATILE) ; return TCL_ERROR ; } /* * let tcl reclaim the string */ Tcl_SetResult(interp, p, TCL_DYNAMIC) ; return TCL_OK ; } static int wrpc_replace( Tcl_Interp *interp, int argc, char **argv ) { Id id ; char *emsg ; Range r ; int n ; if(chk(interp, argc, argv, 5, "replace needs id, begin, end and new text", &id) != TCL_OK) return TCL_ERROR ; r.p0 = Tcl_GetInt(interp, argv[2], &n) != TCL_OK ? -1 : n ; r.p1 = Tcl_GetInt(interp, argv[3], &n) != TCL_OK ? -1 : n ; if(r.p0 < 0 || r.p1 < 0 || r.p0 > r.p1) { Tcl_SetResult(interp, "strange numbers", TCL_STATIC) ; return TCL_ERROR ; } emsg = rpc_replace(h, id, r, argv[4]) ; if(emsg != 0) { Tcl_SetResult(interp, emsg, TCL_VOLATILE) ; return TCL_ERROR ; } return TCL_OK ; } static int wrpc_exec( Tcl_Interp *interp, int argc, char **argv ) { Id id ; char *emsg ; if(chk(interp, argc, argv, 3, "exec needs id and command", &id) != TCL_OK) return TCL_ERROR ; emsg = rpc_exec(h, id, argv[2]) ; if(emsg != 0) { Tcl_SetResult(interp, emsg, TCL_VOLATILE) ; return TCL_ERROR ; } return TCL_OK ; } static int wrpc_goto( Tcl_Interp *interp, int argc, char **argv ) { Id id ; char *emsg ; Range r ; int b ; if(chk(interp, argc, argv, 4, "goto needs id, string and flag", &id) != TCL_OK) return TCL_ERROR ; if(Tcl_GetBoolean(interp, argv[3], &b) != TCL_OK) b = 0 ; emsg = rpc_goto(h, &id, &r, argv[2], b != 0 ? true : false) ; if(emsg != 0) { Tcl_SetResult(interp, emsg, TCL_VOLATILE) ; return TCL_ERROR ; } sprintf(interp->result, "%ld %ld %ld", (long)id, (long)r.p0, (long)r.p1) ; return TCL_OK ; } static int wrpc_length( Tcl_Interp *interp, int argc, char **argv ) { Id id ; char *emsg ; Range r ; if(chk(interp, argc, argv, 2, "length needs id", &id) != TCL_OK) return TCL_ERROR ; emsg = rpc_goto(h, &id, &r, ":$", false) ; if(emsg != 0) { Tcl_SetResult(interp, emsg, TCL_VOLATILE) ; return TCL_ERROR ; } sprintf(interp->result, "%ld", (long)r.p0) ; return TCL_OK ; } static int wrpc_wouldblock( Tcl_Interp *interp, int argc, char **argv ) { if(chk(interp, argc, argv, 1, "wouldblock needs no args", 0) != TCL_OK) return TCL_ERROR ; Tcl_SetResult(interp, rpc_wouldblock(h) == false ? "1" : "0", TCL_STATIC) ; return TCL_OK ; } static int wrpc_event( Tcl_Interp *interp, int argc, char **argv ) { if(chk(interp, argc, argv, 1, "event needs no args", 0) != TCL_OK) return TCL_ERROR ; if(rpc_event(h, &m) == -1) { Tcl_SetResult(interp, "event fails", TCL_STATIC) ; return TCL_ERROR ; } haveevent = true ; switch(m.t) { case WEexec: sprintf(interp->result, "WMexec\t%ld\t%s", (long)m.w, m.s) ; break ; case WEgoto: sprintf(interp->result, "WMgoto\t%ld\t%ld\t%ld\t%s", (long)m.w, m.r.p0, m.r.p1, m.s) ; break ; case WEdestroy: sprintf(interp->result, "WMdestory\t%ld", (long)m.w) ; break ; case WEreplace: sprintf(interp->result, "WMreplace\t%ld\t%ld\t%ld\t%s", (long)m.w, m.r.p0, m.r.p1, m.s) ; break ; default: Tcl_SetResult(interp, "unknown message type", TCL_STATIC) ; return TCL_ERROR ; } return TCL_OK ; } static int wrpc_bounce( Tcl_Interp *interp, int argc, char **argv ) { if(chk(interp, argc, argv, 1, "bounce needs no args", 0) != TCL_OK) return TCL_ERROR ; if(haveevent != true) { Tcl_SetResult(interp, "nothing to bounce", TCL_STATIC) ; return TCL_ERROR ; } if(rpc_bounce(h, &m) != 0) { Tcl_SetResult(interp, "rpc_bounce fails", TCL_STATIC) ; return TCL_ERROR ; } return TCL_OK ; } static WCmd cmds[] = { "init", wrpc_init, "isconnected", wrpc_isconnected, "list", wrpc_list, "new", wrpc_new, "attach", wrpc_attach, "setname", wrpc_setname, "name", wrpc_name, "settools", wrpc_settools, "read", wrpc_read, "replace", wrpc_replace, "exec", wrpc_exec, "goto", wrpc_goto, "length", wrpc_length, "wouldblock", wrpc_wouldblock, "event", wrpc_event, "bounce", wrpc_bounce, } ; static int Wily( ClientData clientdata, Tcl_Interp *interp, int argc, char **argv ) { WCmd *p ; if(argc > 1) for(p = cmds ; p < cmds + sizeof cmds / sizeof cmds[0] ; p++) if(strcmp(argv[1], p->name) == 0) return (*p->proc)(interp, argc - 1, argv + 1) ; Tcl_AppendResult(interp, "usage: ", argv[0], ": ", (char*)0) ; for(p = cmds ; p < cmds + sizeof cmds / sizeof cmds[0] ; p++) Tcl_AppendResult(interp, "[", p->name, "] ", (char*)0) ; return TCL_ERROR ; } extern int Wily_Init( Tcl_Interp *interp ) { Tcl_CreateCommand(interp, "wily", Wily, (ClientData)0, (Tcl_CmdDeleteProc*)0) ; return TCL_OK ; } CL_OK) wily-0.13.42/tools/tcl/wtcl.c000064402366570000012000000007141033320152300155350ustar00ozstaff00004330000002/* $Header: /u/cvs/wtcl/wtcl.c,v 1.1.1.1 1996/11/12 21:28:09 cvs Exp $ */ #include #include "wtcl.h" extern int Tcl_AppInit( Tcl_Interp *interp ) { if(Tcl_Init(interp) == TCL_ERROR) return TCL_ERROR ; if(Wily_Init(interp) == TCL_ERROR) return TCL_ERROR ; Tcl_SetVar(interp, "tcl_rcFileName", "~/.wtcl", TCL_GLOBAL_ONLY) ; return TCL_OK ; } extern int main( int argc, char **argv ) { Tcl_Main(argc, argv, Tcl_AppInit) ; return 0 ; } wily-0.13.42/tools/tcl/wtcl.h000064402366570000012000000001571033320152300155430ustar00ozstaff00004330000002/* $Header: /u/cvs/wtcl/wtcl.h,v 1.1.1.1 1996/11/12 21:28:09 cvs Exp $ */ extern int Wily_Init(Tcl_Interp*) ; wily-0.13.42/tools/tcl/wtools000064402366570000012000000003151033320152300156670ustar00ozstaff00004330000002#!wtcl # # $Header: /u/cvs/wtcl/wtools,v 1.2 1996/11/12 23:34:03 cvs Exp $ # wily init if [expr $argc != 2] { puts "usage: $argv0 " exit 1 } wily settools [lindex $argv 0] [lindex $argv 1] wily-0.13.42/tools/tcl/wattach000064402366570000012000000004311033320152300157720ustar00ozstaff00004330000002#!wtcl # # $Header: /u/cvs/wtcl/wattach,v 1.1.1.1 1996/11/12 21:28:10 cvs Exp $ # wily init wily attach $argv while {1} { set event [wily event] if [string match [lindex $event 0] WMexec] { if [string match [lindex $event 2] Del] { wily bounce exit } } puts $event } wily-0.13.42/tools/win/000075502366570000012000000000001033320152300144315ustar00ozstaff00004330000002wily-0.13.42/tools/win/Makefile000064402366570000012000000036321033320152300160750ustar00ozstaff00004330000002# Generated automatically from Makefile.in by configure. SHELL = /bin/sh srcdir = . prefix = /usr/local exec_prefix = ${prefix} bindir = $(exec_prefix)/bin mandir = $(prefix)/man INSTALL = ./install-sh -c INSTALL_DATA = ${INSTALL} -m 644 CC = gcc CFLAGS = -g -O -I.. -I$(srcdir)/../include -I$(srcdir)/../sam/include DEFS = -DHAVE_LIBNSL=1 -DHAVE_LIBSOCKET=1 -DHAVE_DEV_PTMX=1 -DHAVE_SYS_PTEM_H=1 LIBS = -lsocket -lnsl ../libmsg/libmsg.a ../sam/libXg/libXg.a LDFLAGS = RC = /usr/pgrad/gary/bin/sun4d/rc SRCS = win.c wgoto.c wreplace.c Tag.rc mktags.rc Man.rc BINS = win wgoto wreplace Tag mktags Man MANS = win.1 wgoto.1 wreplace.1 Tag.1 mktags.1 Man.1 DISTFILES = \ README INSTALL \ configure configure.in Makefile.in install-sh mkinstalldirs \ $(SRCS) $(MANS) .SUFFIXES : .SUFFIXES : .c .rc .c : $(CC) $(CFLAGS) $(DEFS) $(LDFLAGS) -o $* $*.c $(LIBS) .rc : ( echo '#!' $(RC) ; cat $*.rc; ) >$* ; \ chmod a+x $* all : $(BINS) install : all installdirs for BIN in $(BINS) ; do \ $(INSTALL) $$BIN $(bindir)/$$BIN ; \ done for MAN in $(MANS) ; do \ $(INSTALL_DATA) $$MAN $(mandir)/man1/$$MAN ; \ done installdirs : mkinstalldirs $(srcdir)/mkinstalldirs $(bindir) $(mandir)/man1 clean : rm -f $(BINS) distclean : clean rm -f Makefile config.cache config.status config.log SCCSFILES = $(SRCS) $(MANS) SCCSDIR = SCCS admin : -test -d $(SCCSDIR) && rm -rfi $(SCCSDIR) mkdir $(SCCSDIR) for FILE in $(SCCSFILES) ; do \ echo $$FILE: ; \ admin -i $$FILE $(SCCSDIR)/s.$$FILE ; \ done rm -i $(SCCSFILES) get : for FILE in $(SCCSFILES) ; do \ echo $$FILE: ; \ get $(SCCSDIR)/s.$$FILE ; \ done edit : for FILE in $(SCCSFILES) ; do \ echo $$FILE: ; \ get -e $(SCCSDIR)/s.$$FILE ; \ done delta : for FILE in $(SCCSFILES) ; do \ echo $$FILE: ; \ delta -y '' $(SCCSDIR)/s.$$FILE ; \ done dist : ./mkdist $(DISTFILES) wily-0.13.42/tools/win/Man.1000064402366570000012000000021541033320152300152300ustar00ozstaff00004330000002.\" Dd distance to space vertically before a "display" .\" These are what n/troff use for interparagraph distance .\"------- .if t .nr Dd .4v .if n .nr Dd 1v .\"------- .\" Ds begin a display, indented .5 inches from the surrounding text. .\" .\" Note that uses of Ds and De may NOT be nested. .\"------- .de Ds .sp \\n(Ddu .RS \\$1 .nf .. .\"------- .\" De end a display (no trailing vertical spacing) .\"------- .de De .fi .RE .in .. .\" @(#) Man %R%.%L% of %D% .TH Man 1 "%R%.%L% of %D%" .SH NAME Man \- Displays reference pages .SH SYNOPSIS .B Man .RB [ \-v ] .I title ... .SH OPTIONS .TP .B \-v If the .B \-v option is present, .I Man prints its version number and date and exits. .PP Any .IR man (1) options are allowed. .SH DESCRIPTION .I Man must be able to connect to a running .I wily (1). .PP Man executes a .I man (1) command with the specified options and titles and displays the result in a window. The name of the window is .IR "+Man\ title" , where title is the last title specified. .SH EXAMPLES Display the man page for make .DS Man make .De .SH SEE ALSO .IR wily (1), .SH AUTHOR Alan Watson (alan@oldp.nmsu.edu) wily-0.13.42/tools/win/Tag.1000064402366570000012000000033201033320152300152240ustar00ozstaff00004330000002.\" Dd distance to space vertically before a "display" .\" These are what n/troff use for interparagraph distance .\"------- .if t .nr Dd .4v .if n .nr Dd 1v .\"------- .\" Ds begin a display, indented .5 inches from the surrounding text. .\" .\" Note that uses of Ds and De may NOT be nested. .\"------- .de Ds .sp \\n(Ddu .RS \\$1 .nf .. .\"------- .\" De end a display (no trailing vertical spacing) .\"------- .de De .fi .RE .in .. .\" @(#) Tag %R%.%L% of %D% .TH Tag 1 "%R%.%L% of %D%" .SH NAME Tag \- Search for and move to a tagged location .SH SYNOPSIS .B Tag .RB [ \-v ] .I name .SH OPTIONS .TP .B \-v If the .B \-v option is present, .I Tag prints its version number and date and exits. .SH DESCRIPTION .I Tag must be able to connect to a running .I wily (1). .PP .I Tag looks for a tag entry corresponding to .I name in the file .I Tags in the current directory. Each line in the .I Tags file is a tag entry consisting of a name, then a space, then a wily address. If .I Tag finds a unique entry corresponding to .I name , it executes a .I wgoto command to search for and move to the address. If .I Tag finds more than one entry corresponding to .I name , it prints the addresses to the .I +Errors window and executes a .I Goto command to move to the .I +Errors window. The correct address can then be selected. .SH RETURNS .I Tag returns zero if it was able to find a unique tag entry and execute the .I wgoto command successfully, otherwise it returns non-zero. No indication of the success or the failure of the actual search is given. .SH EXAMPLES Find the tag entry corresponding to main .DS Tag main .De .SH FILES .I Tags .SH SEE ALSO .IR wily (1), .IR mktags (1) .IR wgoto (1), .SH AUTHOR Alan Watson (alan@oldp.nmsu.edu) wily-0.13.42/tools/win/config.status000064402366570000012000000065751033320152300171600ustar00ozstaff00004330000002#! /bin/sh # Generated automatically by configure. # Run this file to recreate the current configuration. # This directory was configured as follows, # on host pgrad: # # ./configure # # Compiler output produced by configure, useful for debugging # configure, is in ./config.log if it exists. ac_cs_usage="Usage: ./config.status [--recheck] [--version] [--help]" for ac_option do case "$ac_option" in -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) echo "running ${CONFIG_SHELL-/bin/sh} ./configure --no-create --no-recursion" exec ${CONFIG_SHELL-/bin/sh} ./configure --no-create --no-recursion ;; -version | --version | --versio | --versi | --vers | --ver | --ve | --v) echo "./config.status generated by autoconf version 2.4" exit 0 ;; -help | --help | --hel | --he | --h) echo "$ac_cs_usage"; exit 0 ;; *) echo "$ac_cs_usage"; exit 1 ;; esac done ac_given_srcdir=. ac_given_INSTALL="./install-sh -c" trap 'rm -fr Makefile conftest*; exit 1' 1 2 15 # Protect against being on the right side of a sed subst in config.status. sed 's/%@/@@/; s/@%/@@/; s/%g$/@g/; /@g$/s/[\\&%]/\\&/g; s/@@/%@/; s/@@/@%/; s/@g$/%g/' > conftest.subs <<\CEOF /^[ ]*VPATH[ ]*=[^:]*$/d s%@CFLAGS@%-g -O%g s%@CPPFLAGS@%%g s%@CXXFLAGS@%%g s%@DEFS@% -DHAVE_LIBNSL=1 -DHAVE_LIBSOCKET=1 -DHAVE_DEV_PTMX=1 -DHAVE_SYS_PTEM_H=1 %g s%@LDFLAGS@%%g s%@LIBS@%-lsocket -lnsl %g s%@exec_prefix@%${prefix}%g s%@prefix@%/usr/local%g s%@program_transform_name@%s,x,x,%g s%@INSTALL_PROGRAM@%${INSTALL}%g s%@INSTALL_DATA@%${INSTALL} -m 644%g s%@CC@%gcc%g s%@RC@%/usr/pgrad/gary/bin/sun4d/rc%g s%@CPP@%gcc -E%g CEOF CONFIG_FILES=${CONFIG_FILES-"Makefile"} for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then # Support "outfile[:infile]", defaulting infile="outfile.in". case "$ac_file" in *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'` ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; *) ac_file_in="${ac_file}.in" ;; esac # Adjust relative srcdir, etc. for subdirectories. # Remove last slash and all that follows it. Not all systems have dirname. ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then # The file is in a subdirectory. test ! -d "$ac_dir" && mkdir "$ac_dir" ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" # A "../" for each directory in $ac_dir_suffix. ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` else ac_dir_suffix= ac_dots= fi case "$ac_given_srcdir" in .) srcdir=. if test -z "$ac_dots"; then top_srcdir=. else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; *) # Relative path. srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" top_srcdir="$ac_dots$ac_given_srcdir" ;; esac case "$ac_given_INSTALL" in [/$]*) INSTALL="$ac_given_INSTALL" ;; *) INSTALL="$ac_dots$ac_given_INSTALL" ;; esac echo creating "$ac_file" rm -f "$ac_file" configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." case "$ac_file" in *Makefile*) ac_comsub="1i\\ # $configure_input" ;; *) ac_comsub= ;; esac sed -e "$ac_comsub s%@configure_input@%$configure_input%g s%@srcdir@%$srcdir%g s%@top_srcdir@%$top_srcdir%g s%@INSTALL@%$INSTALL%g " -f conftest.subs $ac_given_srcdir/$ac_file_in > $ac_file fi; done rm -f conftest.subs exit 0 case "$ac_option" in -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) echo "running ${CONFIG_SHELLwily-0.13.42/tools/win/Man.rc000064402366570000012000000003711033320152300154730ustar00ozstaff00004330000002if ( ! ~ $#* 1 ) { echo >[1=2] 'usage: Man [-v] [options] title ...' exit 1 } if ( ~ $1 -v ) { # @(#) Man %R%.%L% of %D% echo Man %R%.%L% of %D% exit 0 } name = `{ echo $*($#*) } man $* >[2=1] | col -bx | wreplace -c '+Man '^$name^':,' exit wily-0.13.42/tools/win/win.1000064402366570000012000000100571033320152300153130ustar00ozstaff00004330000002.\" Dd distance to space vertically before a "display" .\" These are what n/troff use for interparagraph distance .\"------- .if t .nr Dd .4v .if n .nr Dd 1v .\"------- .\" Ds begin a display, indented .5 inches from the surrounding text. .\" .\" Note that uses of Ds and De may NOT be nested. .\"------- .de Ds .sp \\n(Ddu .RS \\$1 .nf .. .\"------- .\" De end a display (no trailing vertical spacing) .\"------- .de De .fi .RE .in .. .\" @(#) win %R%.%L% of %D% .TH win 1 "%R%.%L% of %D%" .SH NAME win \- Terminal emulator .SH SYNOPSIS .B win .RB [ \-v ] .RB [ -t .IB name ] .RI [ command .RI [ argument .IR ... ]] .I address .SH OPTIONS .TP .B \-v If the .B \-v option is present, .I win prints its version number and date and exits. .TP .BI \-t name If the .B \-t option is present, win uses .I +name as the final part of the tag name of its window. .SH DESCRIPTION .I win must be able to connect to a running .IR wily (1). .I win attaches to a window. If the .B \-t option is present, the final part of the tag name is .IR name . If .I command is present, the final part of the tag name is .IR +command . Otherwise, the final part of the tag name is .IR +win . The first part of the tag name is the current working directory. .PP win runs a program in a child process. The child process is the leader of a process group and is connected to .I win by a pseudo-terminal. If .I command is specified, the child process runs .Ds $SHELL -c 'command argument ...' .De otherwise it runs .Ds $SHELL -i .De If SHELL is not found in the environment, .I /bin/sh is used. .PP TERM=win is placed in the environment of the running program. .PP Output from the running command appears in the window. The point after the last output from the running command is known as the output point. Further output from the running command appears just before the output point. The output point is initially at the end of the window. .PP Normal wily editing commands work in the window. When a newline, interrupt character, or end-of-file character is created after the output point, the text between the output point and the last newline, interrupt character, or end-of-file character in the window (inclusive) is passed to the running program as input. .PP The interrupt character is control-C and the end-of-file character is control-D. The pseudo-terminal initially is configured so that these are recognized with their normal meanings. .PP The B2 commands beginning with the |, <, or > characters or an upper case letter are executed normally by wily. Other B2 are first terminated with a newline, if they are not already, and are then appended to the buffer (and thereafter passed to the running program). .SH RETURNS .I win returns zero if it is able to successfully create the child process, otherwise it returns non-zero. .SH EXAMPLES Run a terminal emulator within wily .Ds win .De .PP Run FTP within wily .Ds win ftp .De .PP Run rlogin within wily .Ds win -t host.domain rlogin -8 host.domain .De .SH SEE ALSO .IR wily (1) .IR Tag (1) .IR Man (1) .SH BUGS .I win doesn't follow changes to the terminal attributes. In particular, there is no way to stop echoing or to change its concept of the interrupt and eof characters. .PP .I rlogin seems to need -8 and, annoyingly, sets echo and onlcr. The latter can be fixed in your .rcrc: .Ds if ( ~ $TERM win ) { stty -echo -onlcr } .De .PP .I win doesn't follow changes to the terminal attributes. In particular, there is no way to stop echoing or to change its concept of the interrupt and eof characters. .PP WEdestroy messages aren't yet passed by wily. Thus, Del and Delcol can delete the window yet leave win running. .PP There is a race condition; the user can press newline and then delete text before win has a chance to read it. .SH AUTHOR .I win was originally written by Gary Capell (gary@cs.su.oz.au). Alan Watson (alan@oldp.nmsu.edu) rewrote it and added support for arguments, pseudo-terminals instead of pipes, and execution of certain B2 commands by wily. The pseudo-terminal support in 9term, written by Matty Farrow (matty@cs.su.oz.au), was a great help. wily-0.13.42/tools/win/win.c000064402366570000012000000325321033320152300153770ustar00ozstaff00004330000002#include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_SELECT_H #include #endif #include #include #include #include #if HAVE_SYS_PTEM_H #include #endif int shellpid; int master; int slave; char *slavename; const int ttymode = 0600; #define ctrl(c) (c & 0x1f) const char intchar = ctrl('c'); const char eofchar = ctrl('d'); int wilyfifo; Handle *handle; Id id; Bool shelloutput = false; ulong length; ulong outputpoint; void error(const char *, ...); char *getshell(void); char *flatlist(char **); void execshell(char **); void sigexit(int); void sigchld(int); void forkshell(char **); void ipcinit(char *); void ipcloop(void); ulong getlength(void); char *gettagname(char *); void handleshelloutput(void); Bool isbuiltin(char *); void handleWEexec(Msg *); void handleshellinput(Msg *); void handleWEreplace(Msg *); void handlemsg(void); void openmaster(void); void openslave(void); void setslaveattr(void); #define stringize2(x) #x #define stringize(x) stringize2(x) #if defined(__GNUC__) #define here " at " __FILE__ ":" stringize(__LINE__) " in " __FUNCTION__ "()" #else #define here " at " __FILE__ ":" stringize(__LINE__) #endif #define PROGRAMNAME "win" #define VERSIONNAME "%R%.%L% of %D%" char programname[] = PROGRAMNAME; char versioninfo[] = PROGRAMNAME " " VERSIONNAME; char usageinfo[] = "usage: " PROGRAMNAME " [-v] [-t tagname] [command [argument ...]]"; char whatinfo[] = "@(#)" PROGRAMNAME " " VERSIONNAME; void main(int argc, char **argv) { int c; extern char *optarg; extern int optind; extern int opterr; char *tagname; /* parse arguments */ tagname = 0; opterr = 0; while ((c = getopt(argc, argv, "vt:")) != -1) { switch (c) { case 'v': fprintf(stderr, "%s\n", versioninfo); exit(0); case 't': tagname = optarg; break; default: fprintf(stderr, "%s\n", usageinfo); exit(1); break; } } /* determine tag name */ if (tagname == 0) if (argv[optind] != 0) tagname = gettagname(argv[optind]); else tagname = "+win"; /* open pty and fork shell */ forkshell(&argv[optind]); /* handle ipc */ ipcinit(tagname); outputpoint = length = getlength(); ipcloop(); } /* * error(fmt, ...): * * Print "win: ", message, and a newline to stderr. */ void error(const char *fmt, ...) { va_list ap; fprintf(stderr, "win: "); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); } /* * getshell(): * * Return the name of the shell. * * Return value is a pointer to malloc()-ed storage. */ char * getshell(void) { char *path, *shell; path = getenv("SHELL"); if (path == 0) path = "/bin/sh"; shell = malloc(strlen(path) + 1); if (shell == 0) { error("malloc() failed" here); exit(1); } strcpy(shell, path); return shell; } /* * flatlist(v): * * Return a space-separated flattened representation of the * string list v. * * Return value is a pointer to malloc()-ed storage. */ char * flatlist(char **v) { char *s; size_t len; size_t i; len = strlen(v[0]); for (i = 1; v[i] != 0; ++i) { ++len; len += strlen(v[i]); } s = malloc(len + 1); if (s == 0) { error("malloc() failed" here); exit(1); } s[0] = 0; strcat(s, v[0]); for (i = 1; v[i] != 0; ++i) { strcat(s, " "); strcat(s, v[i]); } return s; } /* * execshell(argv): * * Exec a shell to execute the command in argv. * The shell should understand -i and -c. */ void execshell(char **argv) { char *arg0, *arg1, *arg2; arg0 = getshell(); if (*argv == 0) { arg1 = "-i"; arg2 = 0; } else { arg1 = "-c"; arg2 = flatlist(argv); } execl(arg0, arg0, arg1, arg2, 0); error("execl(%s, ...) failed" here, arg0); exit(1); } /* * sigexit(sig) * * Signal handler that simply exits. */ void sigexit(int sig) { exit(0); } /* * sigchld(sig) * * Signal handler that exits if the shell has exited. */ void sigchld(int sig) { signal(sig, sigchld); if (wait(0) == shellpid) exit(0); } /* * forkshell(argv): * * Open the master pty; fork. * In the master: set signal handlers. * In the child: set signal handlers; close the master pty; * start a new process group; open the slave pty; make the slave * the controlling terminal (if open() did not already); set the * attributes of the slave; put "TERM=win" into the environment; * exec the shell. */ void forkshell(char **argv) { openmaster(); switch (shellpid = fork()) { case -1: error("fork() failed" here); exit(1); case 0: signal(SIGCHLD, SIG_DFL); signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGTSTP, SIG_IGN); signal(SIGTTIN, SIG_IGN); signal(SIGTTOU, SIG_IGN); close(master); if (setsid() < 0) { error("setsid() failed" here); exit(1); } openslave(); setslaveattr(); #if defined(TIOCSCTTY) /* e.g., on Digital UNIX */ ioctl(slave, TIOCSCTTY, (void *) 0); #endif if(dup2(slave, 0) < 0 || dup2(slave, 1) < 0 || dup2(slave, 2) < 0) { error("dup2() failed" here); exit(1); } close(slave); putenv("TERM=win"); execshell(argv); default: signal(SIGHUP, sigexit); signal(SIGINT, sigexit); signal(SIGQUIT, sigexit); signal(SIGTERM, sigexit); signal(SIGCHLD, sigchld); } } /* * ipcinit(tagname): * * Initialize IPC to wily. */ void ipcinit(char *tagname) { char *msg; wilyfifo = client_connect(); if (wilyfifo < 0) { error("client_connect() failed" here); exit(1); } handle = rpc_init(wilyfifo); msg = rpc_new(handle, tagname, &id, 0); if (msg != 0) { error("rpc_new() failed" here ": %s", msg); exit(1); } msg = rpc_attach(handle, id, WEexec|WEreplace|WEdestroy); if (msg != 0) { error("rpc_attach() failed" here ": %s", msg); exit(1); } } /* * ipcloop(): * * Handle IPC with wily. */ void ipcloop(void) { fd_set readfds; int nready; for (;;) { while (!rpc_wouldblock(handle)) handlemsg(); FD_ZERO(&readfds); FD_SET(wilyfifo, &readfds); FD_SET(master, &readfds); nready = select(FD_SETSIZE, &readfds, 0, 0, 0); if (nready < 0) { error("select() failed" here); exit(1); } if (FD_ISSET(master, &readfds)) handleshelloutput(); else if (FD_ISSET(wilyfifo, &readfds)) handlemsg(); else { error("select() returned in error" here); exit(1); } } } /* * getlength(): * * Return the length of the body being handled in Runes. */ ulong getlength(void) { Range r; char *msg; msg = rpc_goto(handle, &id, &r, strdup(":,"), 0); if (msg != 0) { error("rpc_goto() failed " here ": %s", msg); exit(1); } return r.p1; } /* * gettagname(shorttagname): * * Return the tag name to use. * * Return value is a pointer to malloc()-ed storage. */ char * gettagname(char *shorttagname) { char *tagname; tagname = malloc(strlen(shorttagname) + 2); if (tagname == 0) { error("malloc() failed" here); exit(1); } sprintf(tagname, "+%s", shorttagname); return tagname; } /* * handleshelloutput(): * * Read output from the shell and pass it to wily. */ void handleshelloutput(void) { char buf[BUFSIZ + 1]; int nread; char *msg; nread = read(master, buf, BUFSIZ); if (nread < 0) { error("read() failed in shellinput()" here); exit(1); } if (nread == 0) exit(0); buf[nread] = '\0'; msg = rpc_replace(handle, id, range(outputpoint, outputpoint), buf); if (msg != 0) { error("rpc_replace() failed" here ": %s", msg); exit(1); } shelloutput = true; } /* * isbuiltin(s): * * Check to see if a command is a builtin command. * * Return true if it is, otherwise false. */ Bool isbuiltin(char *cmd) { char *whitespace = " \t\v\n"; char *first; first = cmd + strspn(cmd, whitespace); return *first == '|' || *first == '<' || *first == '>' || isupper(*first); } /* * handleexec(m): * * Handle a WEexec message m. */ void handleWEexec(Msg *m) { size_t nbytes; int addnewline; char *cmd; char *msg; if (isbuiltin(m->s)) { rpc_bounce(handle, m); return; } nbytes = strlen(m->s); if (nbytes == 0) return; addnewline = (m->s[nbytes - 1] != '\n'); cmd = malloc(nbytes + addnewline + 1); if (cmd == 0) { error("malloc() failed" here); exit(1); } strcpy(cmd, m->s); if (addnewline) strcat(cmd, "\n"); msg = rpc_replace(handle, id, range(length, length), cmd); if (msg != 0) { error("rpc_replace() failed " here ": %s", msg); exit(1); } free(cmd); } /* * handleshellinput(m): * * Send everything from the output point to the last newline * or ctrl-d in the message m to the shell, and adjust the * output point. */ void handleshellinput(Msg *m) { char *lastnewline, *lastintchar, *lasteofchar, *last; ulong lastpoint; char *buf; size_t len; lastnewline = strrchr(m->s, '\n'); lastintchar = strrchr(m->s, intchar); lasteofchar = strrchr(m->s, eofchar); last = lastnewline; if (lastintchar != 0 && (last == 0 || last < lastintchar)) last = lastintchar; if (lasteofchar != 0 && (last == 0 || last < lasteofchar)) last = lasteofchar; *last = '\0'; lastpoint = m->r.p0 + utflen(m->s) + 1; buf = malloc(UTFmax * (lastpoint - outputpoint + 1)); if (buf == 0) { error("malloc() failed" here); exit(1); } rpc_read(handle, id, range(outputpoint, lastpoint), buf); len = strlen(buf); if (write(master, buf, len) != len) { error("write() failed" here); exit(1); } free(buf); outputpoint = lastpoint; } /* * handleWEreplace(m): * * Handle a WEreplace message m. */ void handleWEreplace(Msg *m) { length = length - RLEN(m->r) + utflen(m->s); if (shelloutput) { shelloutput = false; outputpoint = m->r.p0 - RLEN(m->r) + utflen(m->s); #if 0 { /* * This doesn't work. It's an idea for implementing scrolling * on output. What we need is msg.c to execute view_show() * but not view_select() or view_warp(). However, making that * modification would case view_show() to happen even if you * are not setting dot. What we need to do is separate the * functions show, select, and warp. */ char *msg; char buf[100]; Range r; sprintf(buf, ":#%lu", outputpoint); msg = rpc_goto(handle, &id, &r, strdup(buf), 0); if (msg != 0) { error("rpc_goto() failed " here ": %s", msg); exit(1); } } #endif } else { if (outputpoint > m->r.p0) outputpoint = outputpoint - RLEN(m->r) + utflen(m->s); if (m->r.p0 + utflen(m->s) > outputpoint && (strchr(m->s, '\n') || strchr(m->s, intchar) || strchr(m->s, eofchar))) handleshellinput(m); } } /* * handlemsg(): * * Handle a message from wily. */ void handlemsg(void) { Msg m; if (rpc_event(handle, &m) != 0) { error("rpc_event() failed" here); exit(1); } switch (m.t) { case WEdestroy: exit(0); case WEexec: handleWEexec(&m); break; case WEreplace: handleWEreplace(&m); break; default: error("unexpected message type" here); } } /* * openmaster(): * * Open the master end of a pty; determine the name of * the slave end but do not open it. */ void openmaster(void) { #if HAVE__GETPTY /* e.g., on IRIX */ { extern char *_getpty(); slavename = _getpty(&master, O_RDWR, ttymode, 0); if (slavename == 0) { error("_getpty() failed" here); exit(1); } } #elif HAVE_DEV_PTMX /* e.g., on Digital UNIX or Solaris */ { extern char *ptsname(); extern int grantpt(); extern int unlockpt(); master = open("/dev/ptmx", O_RDWR); if (master < 0) { error("open() failed" here); exit(1); } if (grantpt(master) < 0) { error("grantpt() failed" here); exit(1); } if (unlockpt(master) < 0) { error("unlockpt() failed" here); exit(1); } fchmod(master, ttymode); slavename = ptsname(master); if (slavename == 0) { error("ptsname() failed" here); exit(1); } } #else /* e.g., on BSD */ { static char name[]= "/dev/ptyXX"; char *c1, *c2; master = -1; c1 = "pqrstuvwxyzABCDE"; do { c2 = "0123456789abcdef"; do { sprintf(name, "/dev/pty%c%c", *c1, *c2); master = open(name, O_RDWR); } while (master < 0 && *++c2 != 0); } while (master < 0 && *++c1 != 0); if (master < 0) { error("unable to open master pty" here); exit(1); } fchmod(master, ttymode); sprintf(name, "/dev/tty%c%c", *c1, *c2); slavename = name; } #endif } /* * openslave(): * * Open the slave pty. */ void openslave(void) { slave = open(slavename, O_RDWR); if (slave < 0) { error("open() failed" here); exit(1); } fchmod(slave, ttymode); #if HAVE_SYS_PTEM_H /* e.g., on Solaris */ ioctl(slave, I_PUSH, "ptem"); ioctl(slave, I_PUSH, "ldterm"); #endif } /* * setslaveattr() * * Set the slave attributes. */ void setslaveattr(void) { struct termios attr; int i; #if defined(TIOCSETD) && defined(TERMIODISC) /* e.g., on Ultrix */ { /* use termios line discipline */ int ldisc = TERMIODISC; ioctl(slave, TIOCSETD, (void *) &ldisc); } #endif if (tcgetattr(slave, &attr) < 0) { error("tcgetattr() failed" here); exit(1); } attr.c_iflag = 0; attr.c_oflag = ~OPOST; attr.c_lflag = ISIG | ICANON; for (i = 0; i < sizeof(attr.c_cc) / sizeof(*attr.c_cc); ++i) attr.c_cc[i] = 0; attr.c_cc[VINTR] = intchar; attr.c_cc[VEOF] = eofchar; if (tcsetattr(slave, TCSANOW, &attr) < 0) { error("tcsetattr() failed" here); exit(1); } } here); exit(1); } s[0] = 0; strcat(s, v[0]); for (i = 1; v[i] != 0; ++i) { strcat(s, " "); strcat(s, v[i]); } return s; } /* * execshell(argv): *wily-0.13.42/tools/win/README000064402366570000012000000020101033320152300153020ustar00ozstaff00004330000002This is a collection of tools for wily. It should be unpacked in the base wily directory (i.e., in the same directory as libmsg). It includes a pseudo-terminal based terminal emulator, commands to search for and replace text, a manual page interface, and a tags interface. See INSTALL for instructions on compiling and installing. Please send bug reports to the author at alan@oldp.nmsu.edu. Copyright (c) 1996 by Alan Watson (alan@oldp.nmsu.edu). Written by Alan Watson. Not derived from licensed software. Permission is granted to anyone to use this software for any purpose on any computer system, and to redistribute it freely, subject to the following restrictions: 1. The author is not responsible for the consequences of use of this software, no matter how awful, even if they arise from defects in it. 2. The origin of this software must not be misrepresented, either by explicit claim or by omission. 3. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. wily-0.13.42/tools/win/configure000064402366570000012000000754451033320152300163540ustar00ozstaff00004330000002#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated automatically using autoconf version 2.4 # Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc. # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. # Defaults: ac_help= ac_default_prefix=/usr/local # Any additions from configure.in: # Initialize some variables set by options. # The variables have the same names as the options, with # dashes changed to underlines. build=NONE cache_file=./config.cache exec_prefix=NONE host=NONE no_create= nonopt=NONE no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= target=NONE verbose= x_includes=NONE x_libraries=NONE # Initialize some other variables. subdirs= ac_prev= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval "$ac_prev=\$ac_option" ac_prev= continue fi case "$ac_option" in -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; *) ac_optarg= ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case "$ac_option" in -build | --build | --buil | --bui | --bu | --b) ac_prev=build ;; -build=* | --build=* | --buil=* | --bui=* | --bu=* | --b=*) build="$ac_optarg" ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file="$ac_optarg" ;; -disable-* | --disable-*) ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } fi ac_feature=`echo $ac_feature| sed 's/-/_/g'` eval "enable_${ac_feature}=no" ;; -enable-* | --enable-*) ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } fi ac_feature=`echo $ac_feature| sed 's/-/_/g'` case "$ac_option" in *=*) ;; *) ac_optarg=yes ;; esac eval "enable_${ac_feature}='$ac_optarg'" ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix="$ac_optarg" ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he) # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat << EOF Usage: configure [options] [host] Options: [defaults in brackets after descriptions] Configuration: --cache-file=FILE cache test results in FILE --help print this message --no-create do not create output files --quiet, --silent do not print \`checking...' messages --version print the version of autoconf that created configure Directory and file names: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=PREFIX install architecture-dependent files in PREFIX [same as prefix] --srcdir=DIR find the sources in DIR [configure dir or ..] --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names Host type: --build=BUILD configure for building on BUILD [BUILD=HOST] --host=HOST configure for HOST [guessed] --target=TARGET configure for TARGET [TARGET=HOST] Features and packages: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --x-includes=DIR X include files are in DIR --x-libraries=DIR X library files are in DIR --enable and --with options recognized:$ac_help EOF exit 0 ;; -host | --host | --hos | --ho) ac_prev=host ;; -host=* | --host=* | --hos=* | --ho=*) host="$ac_optarg" ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix="$ac_optarg" ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix="$ac_optarg" ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix="$ac_optarg" ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name="$ac_optarg" ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site="$ac_optarg" ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir="$ac_optarg" ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target="$ac_optarg" ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers) echo "configure generated by autoconf version 2.4" exit 0 ;; -with-* | --with-*) ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } fi ac_package=`echo $ac_package| sed 's/-/_/g'` case "$ac_option" in *=*) ;; *) ac_optarg=yes ;; esac eval "with_${ac_package}='$ac_optarg'" ;; -without-* | --without-*) ac_package=`echo $ac_option|sed -e 's/-*without-//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } fi ac_package=`echo $ac_package| sed 's/-/_/g'` eval "with_${ac_package}=no" ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes="$ac_optarg" ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries="$ac_optarg" ;; -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } ;; *) if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then echo "configure: warning: $ac_option: invalid host type" 1>&2 fi if test "x$nonopt" != xNONE; then { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } fi nonopt="$ac_option" ;; esac done if test -n "$ac_prev"; then { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } fi trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 # File descriptor usage: # 0 standard input # 1 file creation # 2 errors and warnings # 3 some systems may open it to /dev/tty # 4 used on the Kubota Titan # 6 checking for... messages and results # 5 compiler messages saved in config.log if test "$silent" = yes; then exec 6>/dev/null else exec 6>&1 fi exec 5>./config.log echo "\ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. " 1>&5 # Strip out --no-create and --no-recursion so they do not pile up. # Also quote any args containing shell metacharacters. ac_configure_args= for ac_arg do case "$ac_arg" in -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c) ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) ac_configure_args="$ac_configure_args '$ac_arg'" ;; *) ac_configure_args="$ac_configure_args $ac_arg" ;; esac done # NLS nuisances. # Only set LANG and LC_ALL to C if already set. # These must not be set unconditionally because not all systems understand # e.g. LANG=C (notably SCO). if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi if test "${LANG+set}" = set; then LANG=C; export LANG; fi # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -rf conftest* confdefs.h # AIX cpp loses on an empty file, so make sure it contains at least a newline. echo > confdefs.h # A filename unique to this package, relative to the directory that # configure is in, which we can look for to find out if srcdir is correct. ac_unique_file=../../wily/wily.c # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then its parent. ac_prog=$0 ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. srcdir=$ac_confdir if test ! -r $srcdir/$ac_unique_file; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r $srcdir/$ac_unique_file; then if test "$ac_srcdir_defaulted" = yes; then { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } else { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } fi fi srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` # Prefer explicitly selected file to automatically selected ones. if test -z "$CONFIG_SITE"; then if test "x$prefix" != xNONE; then CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" else CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then echo "loading site script $ac_site_file" . "$ac_site_file" fi done if test -r "$cache_file"; then echo "loading cache $cache_file" . $cache_file else echo "creating cache $cache_file" > $cache_file fi ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5 2>&5' ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5 2>&5' if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then ac_n= ac_c=' ' ac_t=' ' else ac_n=-n ac_c= ac_t= fi else ac_n= ac_c='\c' ac_t= fi ac_aux_dir= for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do if test -f $ac_dir/install-sh; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f $ac_dir/install.sh; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break fi done if test -z "$ac_aux_dir"; then { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } fi ac_config_guess=$ac_aux_dir/config.guess ac_config_sub=$ac_aux_dir/config.sub ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # ./install, which can be erroneously created by make from ./install.sh. echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 if test -z "$INSTALL"; then if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" for ac_dir in $PATH; do # Account for people who put trailing slashes in PATH elements. case "$ac_dir/" in /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. for ac_prog in ginstall installbsd scoinst install; do if test -f $ac_dir/$ac_prog; then if test $ac_prog = install && grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. # OSF/1 installbsd also uses dspmsg, but is usable. : else ac_cv_path_install="$ac_dir/$ac_prog -c" break 2 fi fi done ;; esac done IFS="$ac_save_ifs" # As a last resort, use the slow shell script. test -z "$ac_cv_path_install" && ac_cv_path_install="$ac_install_sh" fi INSTALL="$ac_cv_path_install" fi echo "$ac_t""$INSTALL" 1>&6 # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_CC="gcc" break fi done IFS="$ac_save_ifs" test -z "$ac_cv_prog_CC" && ac_cv_prog_CC="cc" fi fi CC="$ac_cv_prog_CC" if test -n "$CC"; then echo "$ac_t""$CC" 1>&6 else echo "$ac_t""no" 1>&6 fi echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.c <&5 | egrep yes >/dev/null 2>&1; then ac_cv_prog_gcc=yes else ac_cv_prog_gcc=no fi fi echo "$ac_t""$ac_cv_prog_gcc" 1>&6 if test $ac_cv_prog_gcc = yes; then GCC=yes if test "${CFLAGS+set}" != set; then echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_prog_gcc_g'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else echo 'void f(){}' > conftest.c if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then ac_cv_prog_gcc_g=yes else ac_cv_prog_gcc_g=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_prog_gcc_g" 1>&6 if test $ac_cv_prog_gcc_g = yes; then CFLAGS="-g -O" else CFLAGS="-O" fi fi else GCC= test "${CFLAGS+set}" = set || CFLAGS="-g" fi echo $ac_n "checking for working const""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; } ; return 0; } EOF if eval $ac_compile; then rm -rf conftest* ac_cv_c_const=yes else rm -rf conftest* ac_cv_c_const=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_c_const" 1>&6 if test $ac_cv_c_const = no; then cat >> confdefs.h <<\EOF #define const EOF fi for ac_prog in rc RC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_path_RC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else case "$RC" in /*) ac_cv_path_RC="$RC" # Let the user override the test with a path. ;; *) IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_path_RC="$ac_dir/$ac_word" break fi done IFS="$ac_save_ifs" ;; esac fi RC="$ac_cv_path_RC" if test -n "$RC"; then echo "$ac_t""$RC" 1>&6 else echo "$ac_t""no" 1>&6 fi test -n "$RC" && break done echo $ac_n "checking for -lnsl""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_lib_nsl'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lnsl $LIBS" cat > conftest.$ac_ext <&6 ac_tr_lib=HAVE_LIB`echo nsl | tr '[a-z]' '[A-Z]'` cat >> confdefs.h <&6 fi echo $ac_n "checking for -lsocket""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_lib_socket'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lsocket $LIBS" cat > conftest.$ac_ext <&6 ac_tr_lib=HAVE_LIB`echo socket | tr '[a-z]' '[A-Z]'` cat >> confdefs.h <&6 fi for ac_func in _getpty do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ char $ac_func(); int main() { return 0; } int t() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else $ac_func(); #endif ; return 0; } EOF if eval $ac_link; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else rm -rf conftest* eval "ac_cv_func_$ac_func=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_func=HAVE_`echo $ac_func | tr '[a-z]' '[A-Z]'` cat >> confdefs.h <&6 fi done echo $ac_n "checking for /dev/ptmx""... $ac_c" 1>&6 if /bin/test -e /dev/ptmx ; then echo "$ac_t""yes" 1>&6 cat >> confdefs.h <<\EOF #define HAVE_DEV_PTMX 1 EOF else echo "$ac_t""no" 1>&6 fi echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else # This must be in double quotes, not single quotes, because CPP may get # substituted into the Makefile and "${CC-cc}" will confuse make. CPP="${CC-cc} -E" # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. cat > conftest.$ac_ext < Syntax Error EOF eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then : else echo "$ac_err" >&5 rm -rf conftest* CPP="${CC-cc} -E -traditional-cpp" cat > conftest.$ac_ext < Syntax Error EOF eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then : else echo "$ac_err" >&5 rm -rf conftest* CPP=/lib/cpp fi rm -f conftest* fi rm -f conftest* ac_cv_prog_CPP="$CPP" fi CPP="$ac_cv_prog_CPP" else ac_cv_prog_CPP="$CPP" fi echo "$ac_t""$CPP" 1>&6 for ac_hdr in sys/ptem.h do ac_safe=`echo "$ac_hdr" | tr './\055' '___'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_hdr=HAVE_`echo $ac_hdr | tr '[a-z]./\055' '[A-Z]___'` cat >> confdefs.h <&6 fi done trap '' 1 2 15 cat > confcache <<\EOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs. It is not useful on other systems. # If it contains results you don't want to keep, you may remove or edit it. # # By default, configure uses ./config.cache as the cache file, # creating it if it does not exist already. You can give configure # the --cache-file=FILE option to use a different cache file; that is # what configure does when it calls configure scripts in # subdirectories, so they share the cache. # Giving --cache-file=/dev/null disables caching, for debugging configure. # config.status only pays attention to the cache file if you give it the # --recheck option to rerun configure. # EOF # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. (set) 2>&1 | sed -n "s/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=\${\1='\2'}/p" \ >> confcache if cmp -s $cache_file confcache; then : else if test -w $cache_file; then echo "updating cache $cache_file" cat confcache > $cache_file else echo "not updating unwritable cache $cache_file" fi fi rm -f confcache trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Any assignment to VPATH causes Sun make to only execute # the first set of double-colon rules, so remove it if not needed. # If there is a colon in the path, we need to keep it. if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' fi trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. cat > conftest.defs <<\EOF s%#define \([A-Za-z_][A-Za-z0-9_]*\) \(.*\)%-D\1=\2%g s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g s%\[%\\&%g s%\]%\\&%g s%\$%$$%g EOF DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '` rm -f conftest.defs # Without the "./", some shells look in PATH for config.status. : ${CONFIG_STATUS=./config.status} echo creating $CONFIG_STATUS rm -f $CONFIG_STATUS cat > $CONFIG_STATUS </dev/null | sed 1q`: # # $0 $ac_configure_args # # Compiler output produced by configure, useful for debugging # configure, is in ./config.log if it exists. ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" for ac_option do case "\$ac_option" in -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; -version | --version | --versio | --versi | --vers | --ver | --ve | --v) echo "$CONFIG_STATUS generated by autoconf version 2.4" exit 0 ;; -help | --help | --hel | --he | --h) echo "\$ac_cs_usage"; exit 0 ;; *) echo "\$ac_cs_usage"; exit 1 ;; esac done ac_given_srcdir=$srcdir ac_given_INSTALL="$INSTALL" trap 'rm -fr `echo "Makefile" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 # Protect against being on the right side of a sed subst in config.status. sed 's/%@/@@/; s/@%/@@/; s/%g$/@g/; /@g$/s/[\\\\&%]/\\\\&/g; s/@@/%@/; s/@@/@%/; s/@g$/%g/' > conftest.subs <<\CEOF $ac_vpsub $extrasub s%@CFLAGS@%$CFLAGS%g s%@CPPFLAGS@%$CPPFLAGS%g s%@CXXFLAGS@%$CXXFLAGS%g s%@DEFS@%$DEFS%g s%@LDFLAGS@%$LDFLAGS%g s%@LIBS@%$LIBS%g s%@exec_prefix@%$exec_prefix%g s%@prefix@%$prefix%g s%@program_transform_name@%$program_transform_name%g s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g s%@INSTALL_DATA@%$INSTALL_DATA%g s%@CC@%$CC%g s%@RC@%$RC%g s%@CPP@%$CPP%g CEOF EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then # Support "outfile[:infile]", defaulting infile="outfile.in". case "$ac_file" in *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'` ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; *) ac_file_in="${ac_file}.in" ;; esac # Adjust relative srcdir, etc. for subdirectories. # Remove last slash and all that follows it. Not all systems have dirname. ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then # The file is in a subdirectory. test ! -d "$ac_dir" && mkdir "$ac_dir" ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" # A "../" for each directory in $ac_dir_suffix. ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` else ac_dir_suffix= ac_dots= fi case "$ac_given_srcdir" in .) srcdir=. if test -z "$ac_dots"; then top_srcdir=. else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; *) # Relative path. srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" top_srcdir="$ac_dots$ac_given_srcdir" ;; esac case "$ac_given_INSTALL" in [/$]*) INSTALL="$ac_given_INSTALL" ;; *) INSTALL="$ac_dots$ac_given_INSTALL" ;; esac echo creating "$ac_file" rm -f "$ac_file" configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." case "$ac_file" in *Makefile*) ac_comsub="1i\\ # $configure_input" ;; *) ac_comsub= ;; esac sed -e "$ac_comsub s%@configure_input@%$configure_input%g s%@srcdir@%$srcdir%g s%@top_srcdir@%$top_srcdir%g s%@INSTALL@%$INSTALL%g " -f conftest.subs $ac_given_srcdir/$ac_file_in > $ac_file fi; done rm -f conftest.subs exit 0 EOF chmod +x $CONFIG_STATUS rm -fr confdefs* $ac_clean_files test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 LIBS="-lsocket $LIBS" cat > conftest.$ac_ext <[1=2] usage: Tag [-v] name exit 1 } if ( ~ $1 -v ) { # @(#) Tag %R%.%L% of %D% echo Tag %R%.%L% of %D% exit 0 } if ( ! test -f Tags ) { echo >[1=2] Tag: no Tags file exit 1 } name = $1 ifs = ' ' tags = `{ egrep '^'^$name^' ' Tags | sed 's/[^ ]* //' } switch ( $#tags ) { case 0 echo >[1=2] Tag: no tag for $name exit 1 case 1 wgoto $tags exit case * echo >[1=2] Tag: multiple tags for $name: wgoto '+Errors:$' for (tag in $tags) { echo >[1=2] $tag } exit 1 } wily-0.13.42/tools/win/configure.in000064402366570000012000000006731033320152300167500ustar00ozstaff00004330000002AC_INIT(../../wily/wily.c) dnl Checks for programs. AC_PROG_INSTALL AC_PROG_CC AC_C_CONST AC_PATH_PROGS(RC, rc RC) dnl Checks for libraries. AC_CHECK_LIB(nsl, gethostbyname) AC_CHECK_LIB(socket, connect) dnl Checks for pty stuff AC_CHECK_FUNCS(_getpty) AC_MSG_CHECKING(for /dev/ptmx) if /bin/test -e /dev/ptmx ; then AC_MSG_RESULT(yes) AC_DEFINE(HAVE_DEV_PTMX) else AC_MSG_RESULT(no) fi AC_CHECK_HEADERS(sys/ptem.h) AC_OUTPUT(Makefile) wily-0.13.42/tools/win/mktags.rc000064402366570000012000000017551033320152300162550ustar00ozstaff00004330000002if ( ~ $#* 0 ) { echo >[1=2] 'usage: mktags [-v] file ...' exit 1 } if ( ~ $1 -v ) { # @(#) mktags %R%.%L% of %D% echo mktags %R%.%L% of %D% exit 0 } tab = ' ' nawk >Tags ' BEGIN { status = 0; } END { exit(status); } function error(msg) { system("echo 1>&2 " msg); } function checkname(name) { if (file[name] != "") { error(sprintf("mktags: %s is defined in %s and %s", name, file[name], FILENAME)); status = 1; } file[name] = FILENAME; } /^[a-zA-Z_][a-zA-Z_0-9]*\(/ { name = $0; sub("\\(.*", "", name); ere = $0; sub("\\(.*", "\\(", ere); sub("^", "^", ere); checkname(name); printf("%s %s:/%s/\n", name, FILENAME, ere); next; } /^#[ ]*define[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*\(/ { name = $0; sub("#[ ]*define[ ][ ]*", "", name); sub("\\(.*", "", name); ere = $0; sub("\\(.*", "\\(", ere); sub("^", "^", ere); checkname(name); printf("%s %s:/%s/\n", name, FILENAME, ere); next; } ' $* exit wily-0.13.42/tools/win/confdefs.h000064402366570000012000000000011033320152300163600ustar00ozstaff00004330000002 wily-0.13.42/tools/win/config.cache000064402366570000012000000027741033320152300166750ustar00ozstaff00004330000002# This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs. It is not useful on other systems. # If it contains results you don't want to keep, you may remove or edit it. # # By default, configure uses ./config.cache as the cache file, # creating it if it does not exist already. You can give configure # the --cache-file=FILE option to use a different cache file; that is # what configure does when it calls configure scripts in # subdirectories, so they share the cache. # Giving --cache-file=/dev/null disables caching, for debugging configure. # config.status only pays attention to the cache file if you give it the # --recheck option to rerun configure. # ac_cv_c_const=${ac_cv_c_const='yes'} ac_cv_func__getpty=${ac_cv_func__getpty='no'} ac_cv_header_sys_ptem_h=${ac_cv_header_sys_ptem_h='yes'} ac_cv_lib_nsl=${ac_cv_lib_nsl='yes'} ac_cv_lib_nsl_gethostbyname=${ac_cv_lib_nsl_gethostbyname='yes'} ac_cv_lib_socket=${ac_cv_lib_socket='yes'} ac_cv_lib_socket_connect=${ac_cv_lib_socket_connect='yes'} ac_cv_path_RC=${ac_cv_path_RC='/usr/pgrad/gary/bin/sun4d/rc'} ac_cv_path_install=${ac_cv_path_install='./install-sh -c'} ac_cv_prog_CC=${ac_cv_prog_CC='gcc'} ac_cv_prog_CPP=${ac_cv_prog_CPP='gcc -E'} ac_cv_prog_cc_cross=${ac_cv_prog_cc_cross='no'} ac_cv_prog_cc_g=${ac_cv_prog_cc_g='yes'} ac_cv_prog_cc_works=${ac_cv_prog_cc_works='yes'} ac_cv_prog_gcc=${ac_cv_prog_gcc='yes'} ac_cv_prog_gcc_g=${ac_cv_prog_gcc_g='yes'} calwily-0.13.42/tools/win/install-sh000064402366570000012000000112431033320152300164330ustar00ozstaff00004330000002#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. # # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" tranformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 wily-0.13.42/tools/win/wreplace.1000064402366570000012000000027651033320152300163270ustar00ozstaff00004330000002.\" Dd distance to space vertically before a "display" .\" These are what n/troff use for interparagraph distance .\"------- .if t .nr Dd .4v .if n .nr Dd 1v .\"------- .\" Ds begin a display, indented .5 inches from the surrounding text. .\" .\" Note that uses of Ds and De may NOT be nested. .\"------- .de Ds .sp \\n(Ddu .RS \\$1 .nf .. .\"------- .\" De end a display (no trailing vertical spacing) .\"------- .de De .fi .RE .in .. .\" @(#) wreplace %R%.%L% of %D% .TH wreplace 1 "%R%.%L% of %D%" .SH NAME wreplace \- Replace an address with the contents of stdin. .SH SYNOPSIS .B Goto .RB [ \-v ] .RB [ \-c ] .RB [ \-b ] .I address .SH OPTIONS .TP .B \-v If the .B \-v option is present, .I Goto prints its version number and date and exits. .TP .B \-c If the .B \-c option is present, .I wreplace creates the window if necessary. .TP .B \-b If the .B \-b option is present, .I wreplace sets the backup flag on any windows it creates. .TP .B \-d .SH DESCRIPTION .I wreplace must be able to connect to a running .IR wily (1). .PP .I wreplace searches for .IR address and replaces it with the contents of the standard input. .I address must be a valid wily address. .SH RETURNS .I Goto returns zero if it was able to execute the remote goto command, otherwise it returns non-zero. No indication of the success or the failure of the actual search is given. .SH EXAMPLES .PP Create a manifest file: .Ds ls | wreplace -c -b MANIFEST:, .De .SH SEE ALSO .IR wily (1) .IR wgoto (1) .SH AUTHOR Alan Watson (alan@oldp.nmsu.edu) wily-0.13.42/tools/win/wreplace.c000064402366570000012000000067521033320152300164110ustar00ozstaff00004330000002#include #include #include #include #include #include int wilyfd; Handle *handle; Id id; void error(const char *, ...); char *getfilename(char *); char *readfd(int); #define STRINGIZE2(x) #x #define STRINGIZE(x) STRINGIZE2(x) #ifdef __GNUC__ #define here " at " __FILE__ ":" STRINGIZE(__LINE__) " in " __FUNCTION__ "()" #else #define here " at " __FILE__ ":" STRINGIZE(__LINE__) #endif #define PROGRAMNAME "wreplace" #define VERSIONNAME "%R%.%L% of %D%" char programname[] = PROGRAMNAME; char versioninfo[] = PROGRAMNAME " " VERSIONNAME; char usageinfo[] = "usage: " PROGRAMNAME " [-v] [-c] [-b] address"; char whatinfo[] = "@(#)" PROGRAMNAME " " VERSIONNAME; void main(int argc, char **argv) { int c; extern char *optarg; extern int optind; extern int opterr; char *msg; char *address; char *filename; Range r; Bool create, backup; /* parse arguments */ opterr = 0; create = false; backup = false; while ((c = getopt(argc, argv, "vcb")) != -1) { switch (c) { case 'v': fprintf(stderr, "%s\n", versioninfo); exit(0); case 'c': create = true; break; case 'b': backup = true; break; default: fprintf(stderr, "%s\n", usageinfo); exit(1); break; } } if (argv[optind] == 0 || argv[optind + 1] != 0) { fprintf(stderr, "%s\n", usageinfo); exit(1); } address = argv[optind]; /* open connection */ wilyfd = client_connect(); if (wilyfd < 0) { error("client_connect() failed" here); exit(1); } handle = rpc_init(wilyfd); /* create window if requested */ if (create) { filename = getfilename(address); msg = rpc_new(handle, filename, &id, backup); if (msg != 0) { error("rpc_new() failed" here ": %s", msg); exit(1); } } /* get address */ msg = rpc_goto(handle, &id, &r, strdup(address), 1); if (msg != 0) { error("rpc_goto() failed" here ": %s", msg); exit(1); } if (r.p0 > r.p1) { error("unable to find %s", address); exit(1); } /* do replacement */ msg = rpc_replace(handle, id, r, readfd(0)); if (msg != 0) { error("rpc_replace() failed " here ": %s", msg); exit(1); } exit(0); } /* * error(fmt, ...): * * Print program name, ": ", message, and a newline to stderr. */ void error(const char *fmt, ...) { va_list ap; fprintf(stderr, "%s: ", programname); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); } /* * getfilename(address): * * Return the filename part of an address or 0 * if there is none. * * Returned value is a pointer to malloc()-ed storage. */ char * getfilename(char *address) { char *colon; char *filename; size_t len; colon = strchr(address, ':'); if (colon == 0) len = strlen(address); else len = colon - address; filename = malloc(len + 1); if (filename == 0) { error("malloc() failed" here); exit(1); } memcpy(filename, address, len); filename[len] = 0; return filename; } /* * readfd(fd): * * Read from a fd into a malloc()-ed string. */ char * readfd(int fd) { char *buf; size_t bufsize, buflen; const size_t bufquantum = BUFSIZ; ssize_t nread; buflen = 0; bufsize = 0; buf = 0; do { if (buflen + 1 >= bufsize) { bufsize += bufquantum; buf = realloc(buf, bufsize); if (buf == 0) { error("realloc() failed" here); exit(1); } } nread = read(fd, buf + buflen, bufsize - buflen - 1); if (nread < 0) { error("read() failed" here); exit(1); } buflen += nread; } while (nread != 0); buf[buflen] = 0; return buf; } wily-0.13.42/tools/win/config.log000064402366570000012000000001771033320152300164060ustar00ozstaff00004330000002This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. wily-0.13.42/tools/win/mkinstalldirs000064402366570000012000000012111033320152300172270ustar00ozstaff00004330000002#!/bin/sh # mkinstalldirs --- make directory hierarchy # Author: Noah Friedman # Created: 1993-05-16 # Last modified: 1994-03-25 # Public domain errstatus=0 for file in ${1+"$@"} ; do set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` shift pathcomp= for d in ${1+"$@"} ; do pathcomp="$pathcomp$d" case "$pathcomp" in -* ) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" 1>&2 mkdir "$pathcomp" || errstatus=$? fi pathcomp="$pathcomp/" done done exit $errstatus # mkinstalldirs ends here wily-0.13.42/tools/win/Makefile.in000064402366570000012000000034341033320152300165020ustar00ozstaff00004330000002SHELL = /bin/sh srcdir = @srcdir@ VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = $(exec_prefix)/bin mandir = $(prefix)/man INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ CC = @CC@ CFLAGS = @CFLAGS@ -I.. -I$(srcdir)/../include -I$(srcdir)/../sam/include DEFS = @DEFS@ LIBS = @LIBS@ ../libmsg/libmsg.a ../sam/libXg/libXg.a LDFLAGS = @LDFLAGS@ RC = @RC@ SRCS = win.c wgoto.c wreplace.c Tag.rc mktags.rc Man.rc BINS = win wgoto wreplace Tag mktags Man MANS = win.1 wgoto.1 wreplace.1 Tag.1 mktags.1 Man.1 DISTFILES = \ README INSTALL \ configure configure.in Makefile.in install-sh mkinstalldirs \ $(SRCS) $(MANS) .SUFFIXES : .SUFFIXES : .c .rc .c : $(CC) $(CFLAGS) $(DEFS) $(LDFLAGS) -o $* $*.c $(LIBS) .rc : ( echo '#!' $(RC) ; cat $*.rc; ) >$* ; \ chmod a+x $* all : $(BINS) install : all installdirs for BIN in $(BINS) ; do \ $(INSTALL) $$BIN $(bindir)/$$BIN ; \ done for MAN in $(MANS) ; do \ $(INSTALL_DATA) $$MAN $(mandir)/man1/$$MAN ; \ done installdirs : mkinstalldirs $(srcdir)/mkinstalldirs $(bindir) $(mandir)/man1 clean : rm -f $(BINS) distclean : clean rm -f Makefile config.cache config.status config.log SCCSFILES = $(SRCS) $(MANS) SCCSDIR = SCCS admin : -test -d $(SCCSDIR) && rm -rfi $(SCCSDIR) mkdir $(SCCSDIR) for FILE in $(SCCSFILES) ; do \ echo $$FILE: ; \ admin -i $$FILE $(SCCSDIR)/s.$$FILE ; \ done rm -i $(SCCSFILES) get : for FILE in $(SCCSFILES) ; do \ echo $$FILE: ; \ get $(SCCSDIR)/s.$$FILE ; \ done edit : for FILE in $(SCCSFILES) ; do \ echo $$FILE: ; \ get -e $(SCCSDIR)/s.$$FILE ; \ done delta : for FILE in $(SCCSFILES) ; do \ echo $$FILE: ; \ delta -y '' $(SCCSDIR)/s.$$FILE ; \ done dist : ./mkdist $(DISTFILES) wily-0.13.42/tools/win/INSTALL000064402366570000012000000164461033320152300154750ustar00ozstaff00004330000002Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, a file `config.cache' that saves the results of its tests to speed up reconfiguring, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.in' is used to create `configure' by a program called `autoconf'. You only need `configure.in' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. You can give `configure' initial values for variables by setting them in the environment. Using a Bourne-compatible shell, you can do that on the command line like this: CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure Or on systems that have the `env' program, you can do it like this: env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not supports the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' can not figure out automatically, but needs to determine by the type of host the package will run on. Usually `configure' can figure that out, but if it prints a message saying it can not guess the host type, give it the `--host=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name with three fields: CPU-COMPANY-SYSTEM See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the host type. If you are building compiler tools for cross-compiling, you can also use the `--target=TYPE' option to select the type of system they will produce code for and the `--build=TYPE' option to select the type of system on which you are compiling the package. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Operation Controls ================== `configure' recognizes the following options to control how it operates. `--cache-file=FILE' Use and save the results of the tests in FILE instead of `./config.cache'. Set FILE to `/dev/null' to disable caching, for debugging `configure'. `--help' Print a summary of the options to `configure', and exit. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--version' Print the version of Autoconf used to generate the `configure' script, and exit. `configure' also accepts some other, not widely useful, options. wily-0.13.42/tools/win/wgoto.1000064402366570000012000000022461033320152300156560ustar00ozstaff00004330000002.\" Dd distance to space vertically before a "display" .\" These are what n/troff use for interparagraph distance .\"------- .if t .nr Dd .4v .if n .nr Dd 1v .\"------- .\" Ds begin a display, indented .5 inches from the surrounding text. .\" .\" Note that uses of Ds and De may NOT be nested. .\"------- .de Ds .sp \\n(Ddu .RS \\$1 .nf .. .\"------- .\" De end a display (no trailing vertical spacing) .\"------- .de De .fi .RE .in .. .\" @(#) wgoto %R%.%L% of %D% .TH wgoto 1 "%R%.%L% of %D%" .SH NAME wgoto \- Search for and move to an address .SH SYNOPSIS .B wgoto .RB [ \-v ] .I address .SH OPTIONS .TP .B \-v If the .B \-v option is present, .I wgoto prints its version number and date and exits. .SH DESCRIPTION .I wgoto must be able to connect to a running .IR wily (1). .PP .I wgoto searches for .IR address . which must be a .IR wily (1) address. If the search is successful, dot is set. .SH RETURNS .I wgoto returns zero if it was able to find the address, otherwise it returns non-zero. .SH EXAMPLES Find the superuser entry in /etc/passwd: .Ds wgoto '/etc/passwd:/^root:/' .De .SH SEE ALSO .IR wily (1) .IR wreplace (1) .IR Tag (1) .SH AUTHOR Alan Watson (alan@oldp.nmsu.edu) wily-0.13.42/tools/win/wgoto.c000064402366570000012000000035451033320152300157430ustar00ozstaff00004330000002#include #include #include #include #include #include int wilyfd; Handle *handle; Id id; void error(const char *, ...); char *getfilename(char *); char *readfd(int); #define STRINGIZE2(x) #x #define STRINGIZE(x) STRINGIZE2(x) #ifdef __GNUC__ #define here " at " __FILE__ ":" STRINGIZE(__LINE__) " in " __FUNCTION__ "()" #else #define here " at " __FILE__ ":" STRINGIZE(__LINE__) #endif #define PROGRAMNAME "wgoto" #define VERSIONNAME "%R%.%L% of %D%" char programname[] = PROGRAMNAME; char versioninfo[] = PROGRAMNAME " " VERSIONNAME; char usageinfo[] = "usage: " PROGRAMNAME " [-v] address"; char whatinfo[] = "@(#)" PROGRAMNAME " " VERSIONNAME; void main(int argc, char **argv) { int c; extern char *optarg; extern int optind; extern int opterr; char *msg; char *address; Range r; /* parse arguments */ opterr = 0; while ((c = getopt(argc, argv, "v")) != -1) { switch (c) { case 'v': fprintf(stderr, "%s\n", versioninfo); exit(0); default: fprintf(stderr, "%s\n", usageinfo); exit(1); break; } } if (argv[optind] == 0 || argv[optind + 1] != 0) { fprintf(stderr, "%s\n", usageinfo); exit(1); } address = argv[optind]; /* open connection */ wilyfd = client_connect(); if (wilyfd < 0) { error("client_connect() failed" here); exit(1); } handle = rpc_init(wilyfd); /* get address */ msg = rpc_goto(handle, &id, &r, strdup(address), 1); if (msg != 0) { error("rpc_goto() failed" here ": %s", msg); exit(1); } if (r.p0 > r.p1) { error("unable to find %s", address); exit(1); } exit(0); } /* * error(fmt, ...): * * Print program name, ": ", message, and a newline to stderr. */ void error(const char *fmt, ...) { va_list ap; fprintf(stderr, "%s: ", programname); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); } wily-0.13.42/tools/win/mktags.1000064402366570000012000000027731033320152300160120ustar00ozstaff00004330000002.\" Dd distance to space vertically before a "display" .\" These are what n/troff use for interparagraph distance .\"------- .if t .nr Dd .4v .if n .nr Dd 1v .\"------- .\" Ds begin a display, indented .5 inches from the surrounding text. .\" .\" Note that uses of Ds and De may NOT be nested. .\"------- .de Ds .sp \\n(Ddu .RS \\$1 .nf .. .\"------- .\" De end a display (no trailing vertical spacing) .\"------- .de De .fi .RE .in .. .\" @(#) mktags %R%.%L% of %D% .TH mktags 1 "%R%.%L% of %D%" .SH NAME mktags \- Create a tag file .SH SYNOPSIS .B mktags .RB [ \-v ] .IB file [ ... ] .SH OPTIONS .TP .B \-v If the .B \-v option is present, .I mktags prints its version number and date and exits. .SH DESCRIPTION .I mktags creates a tag file called .I Tags file suitable for used by .IR Tag (1). Each line in the tags file is a tag entry consisting of a name, then a space, then a .IR wily (1) address. .PP .I mktags recognizes certain C constructions by matching extended regular expressions. In the following, \et represents the tab character and parentheses enclose the name .TP Function definitions ^([a-zA-Z_][a-zA-Z_0-9]*)\e( .TP Function-like macro definitions ^#[\ \et]*define[\ \et][\ \et]*([a\-zA\-Z_][a\-zA\-Z_0\-9]*)\e( .SH RETURNS .I mktags returns zero if it executes successfully, otherwise it returns non-zero. .SH EXAMPLES Make tags from all of the C source files in the current directory .DS mktags *.c *.h .De .SH FILES .I Tags .SH SEE ALSO .IR wily (1) .IR Tag (1) .SH AUTHOR Alan Watson (alan@oldp.nmsu.edu) wily-0.13.42/tools/shell/000075502366570000012000000000001033320152300147435ustar00ozstaff00004330000002wily-0.13.42/tools/shell/Makefile000064402366570000012000000006741033320152300164120ustar00ozstaff00004330000002# 9term CC=gcc WILY=$(h)/src/wily BINDIR=$(h)/obj/sun4d/wily CFLAGS=-g -Wall -I. -I$(WILY)/include -I$(WILY)/sam/include -I$(BINDIR) LIBS=-L$(BINDIR)/libmsg -lmsg -lsocket -lnsl -lintl TARGETS= Wgoto Wexec Wins OBJECTS=$(TARGETS:%=%.o) $(TARGETS): Wins: Wins.o gcc -o Wins Wins.o $(LIBS) Wexec: Wexec.o gcc -o Wexec Wexec.o $(LIBS) Wgoto: Wgoto.o gcc -o Wgoto Wgoto.o $(LIBS) clean: - rm $(OBJECTS) nuke: - rm $(OBJECTS) $(TARGETS) wily-0.13.42/tools/shell/Wexec.c000064402366570000012000000012501033320152300161600ustar00ozstaff00004330000002#include #include #include #include #include static void ehandle(char*msg) { fprintf(stderr, "%s\n", msg); exit(1); } int main(int argc, char**argv) { int fd; Handle *handle; char *cmd; char *idstr; Id id; char *errstr; if( argc != 3 ) { ehandle("usage: Wexec cmd id"); } cmd = argv[1]; idstr = argv[2]; id = atoi(idstr); /* Obtain file descriptor */ fd = client_connect(); if (fd<0) { ehandle("client_connect"); } /* Obtain handle */ handle = rpc_init(fd); assert(handle != 0); /* send the command */ errstr = rpc_exec (handle, id, cmd); if(errstr) { ehandle(errstr); } return 0; } wily-0.13.42/tools/shell/README000064402366570000012000000010061033320152300156200ustar00ozstaff00004330000002Some simple C programs to use as wrappers around shell scripts to interact with Wily. Having to know window id's is pretty cumbersome, I know, and I'm open to suggestions on how to improve things. Wins print list of 'filename winid' lines to stdout Wexec cmd id Execute cmd (as if selected with b2), in context of id Wgoto path id Goto 'path' (as if selected with b3), in context of id # NB this is *guaranteed* _not_ to compile "out of the box", you'll need a Makefile that isn't stupid, like the current one. wily-0.13.42/tools/shell/Wgoto.c000064402366570000012000000014761033320152300162160ustar00ozstaff00004330000002#include #include #include #include #include static void ehandle(char*msg) { fprintf(stderr, "%s\n", msg); exit(1); } int main(int argc, char**argv) { int fd; Handle *handle; char *path; char *idstr; Id id; char *errstr; ushort selectit; Range rangefound; if( argc != 3 ) { ehandle("usage: Wexec path id"); } path = argv[1]; idstr = argv[2]; id = atoi(idstr); /* Obtain file descriptor */ fd = client_connect(); if (fd<0) { ehandle("client_connect"); } /* Obtain handle */ handle = rpc_init(fd); assert(handle != 0); /* send the command */ selectit = 1; errstr = rpc_goto (handle, &id, &rangefound, path, selectit); if(errstr) { ehandle(errstr); } else { printf("%d %lu, %lu\n", id, rangefound.p0, rangefound.p1); } return 0; } wily-0.13.42/tools/shell/Wins.c000064402366570000012000000011001033320152300160170ustar00ozstaff00004330000002#include #include #include #include #include static void ehandle(char*msg) { fprintf(stderr, "%s\n", msg); exit(1); } int main(int argc, char**argv) { int fd; Handle *handle; char *wins; char *errstr; /* Obtain file descriptor */ fd = client_connect(); if (fd<0) { ehandle("client_connect"); } /* Obtain handle */ handle = rpc_init(fd); assert(handle != 0); /* Grab the list */ errstr = rpc_list(handle, &wins); if(errstr) { ehandle(errstr); } /* Print it */ printf("%s\n", wins); return 0; } wily-0.13.42/tools/README000064402366570000012000000004251033320152300145150ustar00ozstaff00004330000002A bunch of programs that use wily for their user interface, and tools to create such programs. old stuff pre wily-0.11 quanstro tools from erik quanstrom python python interface for wily messages win simple terminal wpnews wily/python news reader wily-0.13.42/tools/python/000075502366570000012000000000001033320152300151555ustar00ozstaff00004330000002wily-0.13.42/tools/python/testwily.py000064402366570000012000000020451033320152300174140ustar00ozstaff00004330000002#!/usr/local/bin/python -u # -u == unbuffered output import wily print 'get connection' c = wily.Connection() print 'get window "fish"' w = c.win('fish', 1) print 'new window', w print 'get list of windows' print 'listing', c.list() print 'change name from "fish" to "newname"' c.setname(w, 'newname') print 'insert some text' c.replace(w, 0, 0, 'pack my box with five dozen liquor jugs') print 'search for the text "box"' w2,f,t = c.goto(w, 0, 0, 'box', 0) print 'found at', w2, f, t print 'replace "box" with "crate"' c.replace(w, f, t, 'crate') print 'search for the whole window' w2,f,t = c.goto(w, 0, 0, ':,', 0) print 'whole file is', w2, f, t print 'replace the whole window with another phrase' c.replace(w, f, t, 'the quick brown fox jumped over the lazy dog') print 'read the range [10,15) from the window' #s = c.read(w, 10, 15) # print 'read ', s print 'attach to the window, grab EXEC messages only' c.attach(w, wily.EXEC) print 'print the next ten events' for j in range(10): print 'waiting' print 'got', c.event() print 'done' wily-0.13.42/tools/python/Makefile000064402366570000012000000007571033320152300166260ustar00ozstaff00004330000002# 9term CC=gcc PYTHONINC=/n/staff/srce/usr/local/bin/python/Python-1.4/Include/ CFLAGS=-g -Wall -I. -I/usr/pgrad/gary/src/wily/include -I/usr/pgrad/gary/src/wily/sam/include -I$(PYTHONINC) -DNDEBUG XLIBS=-L/usr/pgrad/gary/obj/sun4d/wily/libmsg -l msg -lsocket -lnsl -lintl target: wilymodule.so OBJS=wilymodule.o wilymodule.so: $(OBJS) Makefile /usr/pgrad/gary/obj/sun4d/wily/libmsg/libmsg.a ld -G -o wilymodule.so wilymodule.o $(XLIBS) wilymodule.o: /usr/pgrad/gary/src/wily/include/msg.h wily-0.13.42/tools/python/wilymodule.c000064402366570000012000000255541033320152300175260ustar00ozstaff00004330000002#include "Python.h" #ifndef NDEBUG #define NDEBUG #endif #include #include #include static PyObject *ErrorObject; /* Declarations for objects of type Connection */ typedef struct { PyObject_HEAD /* XXXX Add your own stuff here */ Handle *h; } conobject; staticforward PyTypeObject Contype; static char con_list__doc__[] = "List currently open windows list() Returns list of (name, id) tuples representing currently open windows" ; static PyObject * con_list(conobject *self, PyObject *args) { char *err; char *buf; if (!PyArg_ParseTuple(args, "")) return NULL; if((err = rpc_list(self->h, &buf))) { PyErr_SetString(ErrorObject, err); return NULL; } return Py_BuildValue("s", buf); } static char con_win__doc__[] = "open a window win(name:string, isBackedUp:integer) Returns an integer window identifier, to be used for later operations on the window " ; static PyObject * con_win(conobject *self, PyObject *args) { char *s; Id id; char *err; int isbackedup; if (!PyArg_ParseTuple(args, "si", &s, &isbackedup)) { return NULL; } if((err = rpc_new(self->h, s, &id, (ushort)isbackedup))) { PyErr_SetString(ErrorObject, err); return NULL; } return Py_BuildValue("i", id); } static char con_event__doc__[] = "event() returns an event tuple (w, t, r0, r1, s), whose fields are: w: window identifier t: event type r0, r1: affected range s: string The meaning (if any) of the values of r0, r1 and s depend on the event type 't' " ; static PyObject * con_event(conobject *self, PyObject *args) { Msg m; char *err; PyObject *o; if (!PyArg_ParseTuple(args, "")) return NULL; if(rpc_event(self->h, &m)){ PyErr_SetString(ErrorObject, err); return NULL; } o = Py_BuildValue("(iills)", m.w, m.t, m.r.p0, m.r.p1, m.s); free(m.s); return o; } static char con_eventwouldblock__doc__[] = "eventwouldblock() If eventwouldblock() returns true, calling event() might have to wait. If eventwouldblock() returns false, calling event() would return immediately because an event is already queued up and waiting"; static PyObject * con_eventwouldblock(conobject *self, PyObject *args) { if (!PyArg_ParseTuple(args, "")) return NULL; return Py_BuildValue("b", rpc_wouldblock(self->h)); } static char con_bounce__doc__[] = "bounce(tuple) Called with an event tuple as returned by event(). Returns None" ; static PyObject * con_bounce(conobject *self, PyObject *args) { Msg m; char *err; if (!PyArg_ParseTuple(args, "(iills)", &m.w, &m.t, &m.r.p0, &m.r.p1, &m.s)) return NULL; if(rpc_bounce(self->h, &m)){ PyErr_SetString(ErrorObject, err); return NULL; } Py_INCREF(Py_None); return Py_None; } static char con_attach__doc__[] = "attach(w:integer, mask:integer) 'w' is a window identifier as obtained by new() or list(). 'mask' is a bitmask of event types. Sets the mask of events to be sent to us. "; static PyObject * con_attach(conobject *self, PyObject *args) { Id id; int mask; char *err; if (!PyArg_ParseTuple(args, "ii",&id, &mask)) return NULL; if((err = rpc_attach(self->h, id, (ushort) mask))) { PyErr_SetString(ErrorObject, err); return NULL; } Py_INCREF(Py_None); return Py_None; } static char con_setname__doc__[] = "setname(w:integer, s:string) Set w's name to 's'"; static PyObject * con_setname(conobject *self, PyObject *args) { char *err; char *name; Id id; if (!PyArg_ParseTuple(args, "is", &id, &name)) return NULL; if ((err = rpc_setname(self->h, id, name))) { PyErr_SetString(ErrorObject, err); return NULL; } Py_INCREF(Py_None); return Py_None; } static char con_settools__doc__[] = "settools(w:integer, s:string) Set w's tools to 's' "; static PyObject * con_settools(conobject *self, PyObject *args) { char *err; char *name; Id id; if (!PyArg_ParseTuple(args, "is", &id, &name)) return NULL; if ((err = rpc_settools(self->h, id, name))) { PyErr_SetString(ErrorObject, err); return NULL; } Py_INCREF(Py_None); return Py_None; } static char con_gettools__doc__[] = "gettools(w:integer) : string Return the tools currently visible in w's tag"; static PyObject * con_gettools(conobject *self, PyObject *args) { char *err; char *tools; Id id; if (!PyArg_ParseTuple(args, "i", &id)) return NULL; if ((err = rpc_gettools(self->h, id, &tools))) { PyErr_SetString(ErrorObject, err); return NULL; } return Py_BuildValue("s", tools); } static char con_getname__doc__[] = "getname(w:integer) : string Return the name currently visible in w's tag"; static PyObject * con_getname(conobject *self, PyObject *args) { char *err; char *name; Id id; if (!PyArg_ParseTuple(args, "i", &id)) return NULL; if ((err = rpc_getname(self->h, id, &name))) { PyErr_SetString(ErrorObject, err); return NULL; } return Py_BuildValue("s", name); } static char con_read__doc__[] = "read(w:integer, from:integer, to:integer) returns a (UTF) string "; static PyObject * con_read(conobject *self, PyObject *args) { int from,to; Id id; Range r; char *buf,*err; PyObject *retval; if (!PyArg_ParseTuple(args, "iii", &id, &from, &to)) return NULL; r.p0 = from; r.p1 = to; buf = malloc(UTFmax *(r.p1 -r.p0)); if(!buf) { PyErr_NoMemory(); return NULL; } err = rpc_read(self->h, id, r, buf); if(err) { PyErr_SetString(ErrorObject, err); retval= NULL; } else { retval= Py_BuildValue("s", buf); } free(buf); return retval; } static char con_replace__doc__[] = "replace(w:integer, from:integer, to:integer, s:string) replace the text in 'w' from 'from' to 'to' with 's' "; static PyObject * con_replace(conobject *self, PyObject *args) { char *err; int p0, p1; char *replace; Id id; Range r; if (!PyArg_ParseTuple(args, "iiis",&id, &p0, &p1,&replace)) return NULL; if (p0>p1 || p1<0 || p0<0) { PyErr_SetString(ErrorObject, "range out of bounds"); return NULL; } r.p0 = p0; r.p1 = p1; if((err = rpc_replace(self->h, id, r, replace))) { PyErr_SetString(ErrorObject, err); return NULL; } Py_INCREF(Py_None); return Py_None; } static char con_run__doc__[] = "run(w:integer, s:string) has the same effect as sweeping 's' with B2 in window 'w' "; static PyObject * con_run(conobject *self, PyObject *args) { char *err; char *name; Id id; if (!PyArg_ParseTuple(args, "is",&id, &name)) return NULL; if((err = rpc_exec(self->h, id, name))) { PyErr_SetString(ErrorObject, err); return NULL; } Py_INCREF(Py_None); return Py_None; } static char con_goto__doc__[] = "goto(w:integer, from:long, to:long, s:string, flag:integer) has the same effect as sweeping 's' with B3 in window 'w', and starting any search at range(from,to), except that we only warp and select text if 'flag' is set. Returns a tuple (w:integer, from:long, to:long), which represents the window and selection that was opened. "; static PyObject * con_goto(conobject *self, PyObject *args) { char *err; char *name; Id id; Range r; long from,to; int flag; if (!PyArg_ParseTuple(args, "illsi",&id, &from, &to, &name,&flag)) return NULL; r.p0 = from; r.p1 = to; if((err = rpc_goto(self->h, &id, &r, name, flag))) { PyErr_SetString(ErrorObject, err); return NULL; } return Py_BuildValue("(ill)", id, r.p0, r.p1); } static struct PyMethodDef con_methods[] = { {"list", con_list, 1, con_list__doc__}, {"win", con_win, 1, con_win__doc__}, {"event", con_event, 1, con_event__doc__}, {"eventwouldblock", con_eventwouldblock, 1, con_eventwouldblock__doc__}, {"bounce", con_bounce, 1, con_bounce__doc__}, {"attach", con_attach, 1, con_attach__doc__}, {"setname", con_setname, 1, con_setname__doc__}, {"getname", con_getname, 1, con_getname__doc__}, {"settools", con_settools, 1, con_settools__doc__}, {"gettools", con_gettools, 1, con_gettools__doc__}, {"read", con_read, 1, con_read__doc__}, {"replace", con_replace, 1, con_replace__doc__}, {"run", con_run, 1, con_run__doc__}, {"goto", con_goto, 1, con_goto__doc__}, {NULL, NULL} /* sentinel */ }; /* ---------- */ static conobject * newconobject() { conobject *self; int fd; self = PyObject_NEW(conobject, &Contype); if (self == NULL) return NULL; /* XXXX Add your own initializers here */ /* todo - handle errors */ fd = client_connect(); if(fd<0) { PyErr_SetString(ErrorObject, "client_connect"); return NULL; } self->h = rpc_init(fd); if (!self->h) { PyErr_SetString(ErrorObject, "rpc_init"); return NULL; } return self; } static void con_dealloc(self) conobject *self; { /* XXXX Add your own cleanup code here */ PyMem_DEL(self); } static PyObject * con_getattr(self, name) conobject *self; char *name; { /* XXXX Add your own getattr code here */ return Py_FindMethod(con_methods, (PyObject *)self, name); } static char Contype__doc__[] = "Wily connection Holds the state for a connection to Wily " ; static PyTypeObject Contype = { PyObject_HEAD_INIT(&PyType_Type) 0, /*ob_size*/ "Connection", /*tp_name*/ sizeof(conobject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)con_dealloc, /*tp_dealloc*/ (printfunc)0, /*tp_print*/ (getattrfunc)con_getattr, /*tp_getattr*/ (setattrfunc)0, /*tp_setattr*/ (cmpfunc)0, /*tp_compare*/ (reprfunc)0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ (hashfunc)0, /*tp_hash*/ (binaryfunc)0, /*tp_call*/ (reprfunc)0, /*tp_str*/ /* Space for future expansion */ 0L,0L,0L,0L, Contype__doc__ /* Documentation string */ }; /* End of code for Connection objects */ /* -------------------------------------------------------- */ static char wily_Connection__doc__[] = "Connection() Return a connection object. Uses $WILYFIFO if set" ; static PyObject * wily_Connection(PyObject *self, PyObject *args) { if (!PyArg_ParseTuple(args, "")) return NULL; return (PyObject*) newconobject(); } /* List of methods defined in the module */ static struct PyMethodDef wily_methods[] = { {"Connection", wily_Connection, 1, wily_Connection__doc__}, {NULL, NULL} /* sentinel */ }; /* Initialization function for the module (*must* be called initwily) */ static char wily_module_documentation[] = "Open, manipulate, monitor Wily windows Everything is accessed through a Connection object. Windows are represented by an integer. GOTO, EXEC, DESTROY and REPLACE are event bitmask values."; void initwily() { PyObject *m, *d; /* Create the module and add the functions */ m = Py_InitModule4("wily", wily_methods, wily_module_documentation, (PyObject*)NULL,PYTHON_API_VERSION); /* Add some symbolic constants to the module */ d = PyModule_GetDict(m); ErrorObject = PyString_FromString("wily.error"); PyDict_SetItemString(d, "error", ErrorObject); /* XXXX Add constants here */ PyDict_SetItemString(d, "GOTO", Py_BuildValue("i", WEgoto)); PyDict_SetItemString(d, "EXEC", Py_BuildValue("i", WEexec)); PyDict_SetItemString(d, "DESTROY", Py_BuildValue("i", WEdestroy)); PyDict_SetItemString(d, "REPLACE", Py_BuildValue("i", WEreplace)); /* Check for errors */ if (PyErr_Occurred()) Py_FatalError("can't initialize module wily"); } elf, PyObject *args) { int from,to; Id id; Range r; char *buf,*err; PyObject *retval; if (!PyArg_ParseTuple(args, "iii", &id, &from, &to)) wily-0.13.42/tools/python/config.h000064402366570000012000000043651033320152300166030ustar00ozstaff00004330000002/* config.h. Generated automatically by configure. */ /* config.h.in. Generated automatically from configure.in by autoheader. */ #define HAVE_ULONG 1 #define HAVE_USHORT 1 #define HAVE_UINT 1 /* #undef HAVE_UCHAR */ #define HAVE_CADDR_T 1 /* Define this if your sprintf returns char * instead of int */ #define BROKEN_SPRINTF 1 /* Define to empty if the keyword does not work. */ /* #undef const */ /* Define if you don't have vprintf but do have _doprnt. */ /* #undef HAVE_DOPRNT */ /* Define if you have that is POSIX.1 compatible. */ #define HAVE_SYS_WAIT_H 1 /* Define if you have the vprintf function. */ #define HAVE_VPRINTF 1 /* Define if you need to in order for stat and other things to work. */ /* #undef _POSIX_SOURCE */ /* Define as the return type of signal handlers (int or void). */ #define RETSIGTYPE void /* Define to `unsigned' if doesn't define. */ /* #undef size_t */ /* Define if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define if you can safely include both and . */ #define TIME_WITH_SYS_TIME 1 /* Define if you have the memmove function. */ #define HAVE_MEMMOVE 1 /* Define if you have the realpath function. */ #define HAVE_REALPATH 1 /* Define if you have the remove function. */ #define HAVE_REMOVE 1 /* Define if you have the strerror function. */ #define HAVE_STRERROR 1 /* Define if you have the header file. */ #define HAVE_DIRENT_H 1 /* Define if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define if you have the header file. */ #define HAVE_LIMITS_H 1 /* Define if you have the header file. */ #define HAVE_MALLOC_H 1 /* Define if you have the header file. */ /* #undef HAVE_NDIR_H */ /* Define if you have the header file. */ #define HAVE_STDARG_H 1 /* Define if you have the header file. */ /* #undef HAVE_SYS_DIR_H */ /* Define if you have the header file. */ /* #undef HAVE_SYS_NDIR_H */ /* Define if you have the header file. */ #define HAVE_SYS_SELECT_H 1 /* Define if you have the header file. */ #define HAVE_SYS_TIME_H 1 /* Define if you have the header file. */ #define HAVE_UNISTD_H 1 wily-0.13.42/tools/python/Makefile.in000064402366570000012000000007471033320152300172320ustar00ozstaff00004330000002CC=gcc PYTHONINC=/n/staff/srce/usr/local/bin/python/Python-1.4/Include/ CFLAGS=-g -Wall -I. -I/usr/pgrad/gary/src/wily/include -I/usr/pgrad/gary/src/wily/sam/include -I$(PYTHONINC) -DNDEBUG XLIBS=-L/usr/pgrad/gary/obj/sun4d/wily/libmsg -l msg -lsocket -lnsl -lintl target: wilymodule.so OBJS=wilymodule.o wilymodule.so: $(OBJS) Makefile /usr/pgrad/gary/obj/sun4d/wily/libmsg/libmsg.a ld -G -o wilymodule.so wilymodule.o $(XLIBS) wilymodule.o: /usr/pgrad/gary/src/wily/include/msg.h wily-0.13.42/tools/quanstro/000075502366570000012000000000001033320152300155105ustar00ozstaff00004330000002wily-0.13.42/tools/quanstro/Makefile000064402366570000012000000005421033320152300171510ustar00ozstaff00004330000002W = $(HOME)/src/plan9/wily/wily-0.11.1 CPPFLAGS = -I$W -I$W/include -I$W/libXg -I$W/sam/include LDFLAGS = -L$W/sam/libXg -L$W/libmsg LDLIBS = -lmsg -lXg # gmake CFLAGS = -g -Wall -ansi CFLAGS = -g -Wall -ansi $(CPPFLAGS) $(LDLIBS) CC=gcc PROGS = wcat windows wreplace wattach wread all: $(PROGS) install: cp $(PROGS) $(binpath) clean: rm $(PROGS) wily-0.13.42/tools/quanstro/windows.c000064402366570000012000000012041033320152300173430ustar00ozstaff00004330000002#include #include #include #include #include #include #include volatile Bool control_c = false; void e(const char *s) { perror(s); exit(1); } void catch(int sig){ signal(sig, catch); control_c = true; } void main(int c, char**v){ int fd; Handle *h; Bool status; char *p; signal(SIGHUP, catch); signal(SIGINT, catch); signal(SIGQUIT, catch); signal(SIGTERM, catch); fd = client_connect(); if (-1 == fd){ e("can't open wilyfifo"); } h = rpc_init(fd); status = true; rpc_list(h, &p); printf("%s", p); free(p); rpc_freehandle(h); exit(!status); } wily-0.13.42/tools/quanstro/wattach.c000064402366570000012000000027241033320152300173140ustar00ozstaff00004330000002#include #include #include #include #include #include #include volatile Bool control_c = false; void catch(int sig){ signal(sig, catch); control_c = true; } void exits(const char*whine){ if (*whine){ fprintf(stderr, "%s\n", whine); exit(1); } exit(0); } const char* decode(Msg* m){ switch(m->t){ default: return "unknown message type"; case WEexec: if (!strcmp(m->s, "Del")){ exit(1);} printf("exec %5.5d %s\n", m->w, m->s); break; case WEgoto: printf("goto %5.5d {%lu,%lu} %s\n", m->w, m->r.p0, m->r.p1, m->s); break; case WEdestroy: printf("dest %5.5d \n", m->w); break; case WEreplace: printf("repl %5.5d {%lu,%lu} %s\n", m->w, m->r.p0, m->r.p1, m->s); break; } fflush(stdout); return 0; } void main(int c, char**v){ Msg m; int fd; Handle *h; Id id; char* r; const char* s; c--; v++; if (c != 1){ exits("usage: wattach "); } id = strtoul(*v, &r, 0); if (*r){ exits("doesn't look integerish"); } signal(SIGHUP, catch); signal(SIGINT, catch); signal(SIGQUIT, catch); signal(SIGTERM, catch); fd = client_connect(); if (-1 == fd){ exits("can't open wilyfifo"); } h = rpc_init(fd); s = rpc_attach(h, id, WEexec | WEgoto | WEreplace | WEdestroy); if (s){ exits(s); } while (0 == rpc_event(h,&m)){ decode(&m); free(m.s); if (control_c){ break; } } /* rpc_detach(h, id);*/ rpc_freehandle(h); exit(control_c ? 0 : -1); } wily-0.13.42/tools/quanstro/wreplace.c000064402366570000012000000040261033320152300174600ustar00ozstaff00004330000002#include #include #include #include #include #include #include volatile Bool control_c = false; enum { BLOCK = 8 * 1024 }; void e(const char *s) { perror(s); exit(1); } void catch(int sig){ signal(sig, catch); control_c = true; } Bool map_stream(int fd, Handle* h, long id, const char* range){ char block[BLOCK]; ulong len; long r; const char*s; Range R; s=rpc_goto(h, (Id*)&id, &R, (char*)range, true); if (s){ fprintf(stderr, "rpc_goto -> %s\n", s); return false; } fprintf(stderr, "%ld\n", id); for (len = 0; (r = read(fd, block, BLOCK))>0; len += r){ block[r] = 0; if (rpc_replace(h, id, R, block)){ fprintf(stderr, "rpc_insert(q,%ld,%ld,%ld, ) fails\n", id, len, len); return 0; } R.p0 = R.p1 = len; } return 0; } long getLong(const char* s){ char* r; ulong l; l = strtoul(s,&r,0); if (*r){ e("want long integer"); } return l; } void main(int c, char**v){ int fd; int f; Handle* h; Bool taetig; Bool status; long id; const char* range; signal(SIGHUP, catch); signal(SIGINT, catch); signal(SIGQUIT, catch); signal(SIGTERM, catch); fd = client_connect(); if (-1 == fd){ e("can't open wilyfifo"); } h = rpc_init(fd); status = true; taetig = false; for (v++; *v; v++){ id = -1; range = ":,"; if (0 == strcmp(*v, "-i")){ v++; if (*v){ id = getLong(*v++); } } if (0 == strcmp(*v, "-r")){ v++; if (*v){ range = *v++; } } if (-1 == id){ e("missing id"); } if (!*v){ break; } taetig = true; if (0 == strcmp(*v, "-")){ status |= map_stream(0, h, id, range); } else { f = open(*v, 0, 0666); if (-1 == f){ fprintf(stderr, "can't open file %s\n", *v); } else { status |= map_stream(f, h, id, range); close(f); } } if (control_c){ goto out; } } if (!taetig){ if (-1 == id){ e("missing id"); } status |= map_stream(0, h, id, range); } out: status |= control_c; rpc_freehandle(h); if (status){ exit(0); } exit(1); } wily-0.13.42/tools/quanstro/wcat.c000064402366570000012000000046371033320152300166240ustar00ozstaff00004330000002#include #include #include #include #include #include #include volatile Bool control_c = false; enum { BLOCK = 8 * 1024 }; void e(const char *s) { perror(s); exit(1); } void catch(int sig){ signal(sig, catch); control_c = true; } Bool map_file(const char* file, Handle* q, const char* title){ char* p; char filename[PATH_MAX+1]; char cwd[PATH_MAX+1]; Id id; if (!title){ if (*file == '/'){ strcpy(filename, file); } else { p = getcwd(cwd, PATH_MAX); if (!p){ fprintf(stderr, "can't get cwd()"); return false; } } } else { sprintf(filename, "+%s", title); } sprintf(filename,"%s/%s", cwd, file); if (rpc_new(q, filename, &id)){ fprintf(stderr, "rpc_new(q, %s, 0, id) fails\n", filename); return false; } fprintf(stderr, "%d\n", id); return true; } Bool map_stream(int fd, Handle* q, const char* title){ char block[BLOCK]; char winname[50]; Id id; ulong len; long r; Range R; const char* s; if (!title){ sprintf(winname,"+stdin-%d",getpid()); } else { sprintf(winname, "+%s", title); } if (rpc_new(q, winname, &id)){ fprintf(stderr, "rpc_new(q, %s, 0, id) fails\n", winname); return false; } fprintf(stderr, "%d\n", id); R.p0 = 0; R.p1 = 0; for (len = 0; (r = read(fd, block, BLOCK))>0; len += r){ block[r] = 0; s = rpc_replace(q, id, R, block); if (s){ fprintf(stderr, "rpc_replace(q,%d,{%lu,%lu}, ) fails with %s\n", id, len, len, s); return false; } s = rpc_goto(q, &id, &R, (char*)":$", false); if (s){ fprintf(stderr, "rpc_goto(q,%d,{%lu,%lu}, ':$') fails with %s\n", id, R.p0, R.p0, s); return false; } } return true; } void main(int c, char**v){ int fd; Handle *h; Bool taetig; Bool status; char* title; signal(SIGHUP, catch); signal(SIGINT, catch); signal(SIGQUIT, catch); signal(SIGTERM, catch); fd = client_connect(); if (-1 == fd){ e("can't open wilyfifo"); } h = rpc_init(fd); status = true; taetig = false; title = 0; for (v++; *v; v++){ if (0 == strcmp(*v, "-t")){ v++; if (*v){ title = *v; } continue; } taetig = true; if (0 == strcmp(*v, "-")){ status |= map_stream(0, h, title); } else { status |= map_file(*v, h, title); } if (control_c){ goto out; } } if (!taetig){ status |= map_stream(0, h, title); } out: status |= control_c; rpc_freehandle(h); if (status){ exit(0); } exit(1); } wily-0.13.42/tools/quanstro/wread.c000064402366570000012000000026461033320152300167660ustar00ozstaff00004330000002#include #include #include #include #include #include #include volatile Bool control_c = false; enum { BLOCK = 8 * 1024 }; void exits(const char*whine){ if (*whine){ fprintf(stderr, "%s\n", whine); exit(1); } exit(0); } void catch(int sig){ signal(sig, catch); control_c = true; } const char* read_buf(Handle *h, long id, long len){ Range R; long p; char buf[UTFmax * BLOCK]; const char* s; int delta; for(p = 0; p + BLOCK <= len; p += BLOCK){ R.p0 = p; R.p1 = p + BLOCK-1; s = rpc_read(h, id, R, buf); if (s){ return s; } delta=strlen(&buf[BLOCK-1]); write(1, buf, BLOCK+delta); } R.p0 = p; R.p1 = len; s = rpc_read(h, id, R, buf); if (s){ return s; } delta=strlen(&buf[len-p]); write(1, buf, R.p1 - R.p0 + delta); /* wrong! */ return 0; } void main(int c, char**v){ int fd; Handle *h; Bool status; const char* s; Range R; long id; char* r; c--; v++; if (c != 1){ exits("usage: wread "); } id = strtoul(*v, &r, 0); if (*r){ exits("doesn't look integerish"); } signal(SIGHUP, catch); signal(SIGINT, catch); signal(SIGQUIT, catch); signal(SIGTERM, catch); fd = client_connect(); if (-1 == fd){ exits("can't open wilyfifo"); } h = rpc_init(fd); s=rpc_goto(h, (Id*)&id, &R, (char*)":$", false); if (s){ exits(s); } read_buf(h, id, R.p1); rpc_freehandle(h); exit(!status); } wily-0.13.42/README000064402366570000012000000041061033320152300133550ustar00ozstaff00004330000002 * The author of this software is Gary Capell. * Copyright (c) 1995, 1996 by Gary Capell. * Permission to use, copy, modify, and distribute this software for any * purpose without fee is hereby granted, provided that this entire notice * is included in all copies of any software which is or includes a copy * or modification of this software and in all copies of the supporting * documentation for such software. * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED * WARRANTY. IN PARTICULAR, THE AUTHOR DOES NOT MAKE ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. Wily is an emulation of Acme. Acme was written by Rob Pike. Nearly all of the nifty ideas (but none of the source code) in Wily are taken from Acme. Read INSTALL for hints on how to build. Ignore error messages like "no libXg configuration in dir sam" If 'make' fails, try 'gmake' (GNU make). Mail wilyfans-request@jli.com to subscribe to a list discussing wily (and to find out about new releases). Please mail gary@cs.su.oz.au if you get this working and you like it, or mail wilyfans@jli.com if you have problems getting something to work. Some Wily documentation is in wily/Doc and more will soon follow. Start with wily/Doc/00README README.sam contains some info about Sam and libXg, from which a bunch of code for wily was grabbed. Wily is Unicode aware, so with the right font files it will display all sorts of international characters. See http://www.cs.su.oz.au/~matty/9term/index.html for documentation on another Unicode-aware program (using the same libraries), including some screen shots showing some of the characters available, and a bundle of (mono-space) Unicode fonts. Wily is nicest to use with a proportional font. Use wily -fn or use X defaults. Wily.ad is my application defaults file, prop.9.font and fixed.9.font are my two font files. These refer to some fonts distributed with 9term. I would be _very_ happy if someone contributed a full set of proportional Unicode fonts. wily-0.13.42/configure000075502366570000012000001674111033320152300144150ustar00ozstaff00004330000002#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated automatically using autoconf version 2.4 # Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc. # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. # Defaults: ac_help= ac_default_prefix=/usr/local # Any additions from configure.in: ac_help="$ac_help --with-x use the X Window System" # Initialize some variables set by options. # The variables have the same names as the options, with # dashes changed to underlines. build=NONE cache_file=./config.cache exec_prefix=NONE host=NONE no_create= nonopt=NONE no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= target=NONE verbose= x_includes=NONE x_libraries=NONE # Initialize some other variables. subdirs= ac_prev= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval "$ac_prev=\$ac_option" ac_prev= continue fi case "$ac_option" in -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; *) ac_optarg= ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case "$ac_option" in -build | --build | --buil | --bui | --bu | --b) ac_prev=build ;; -build=* | --build=* | --buil=* | --bui=* | --bu=* | --b=*) build="$ac_optarg" ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file="$ac_optarg" ;; -disable-* | --disable-*) ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } fi ac_feature=`echo $ac_feature| sed 's/-/_/g'` eval "enable_${ac_feature}=no" ;; -enable-* | --enable-*) ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } fi ac_feature=`echo $ac_feature| sed 's/-/_/g'` case "$ac_option" in *=*) ;; *) ac_optarg=yes ;; esac eval "enable_${ac_feature}='$ac_optarg'" ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix="$ac_optarg" ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he) # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat << EOF Usage: configure [options] [host] Options: [defaults in brackets after descriptions] Configuration: --cache-file=FILE cache test results in FILE --help print this message --no-create do not create output files --quiet, --silent do not print \`checking...' messages --version print the version of autoconf that created configure Directory and file names: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=PREFIX install architecture-dependent files in PREFIX [same as prefix] --srcdir=DIR find the sources in DIR [configure dir or ..] --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names Host type: --build=BUILD configure for building on BUILD [BUILD=HOST] --host=HOST configure for HOST [guessed] --target=TARGET configure for TARGET [TARGET=HOST] Features and packages: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --x-includes=DIR X include files are in DIR --x-libraries=DIR X library files are in DIR --enable and --with options recognized:$ac_help EOF exit 0 ;; -host | --host | --hos | --ho) ac_prev=host ;; -host=* | --host=* | --hos=* | --ho=*) host="$ac_optarg" ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix="$ac_optarg" ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix="$ac_optarg" ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix="$ac_optarg" ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name="$ac_optarg" ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site="$ac_optarg" ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir="$ac_optarg" ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target="$ac_optarg" ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers) echo "configure generated by autoconf version 2.4" exit 0 ;; -with-* | --with-*) ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } fi ac_package=`echo $ac_package| sed 's/-/_/g'` case "$ac_option" in *=*) ;; *) ac_optarg=yes ;; esac eval "with_${ac_package}='$ac_optarg'" ;; -without-* | --without-*) ac_package=`echo $ac_option|sed -e 's/-*without-//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } fi ac_package=`echo $ac_package| sed 's/-/_/g'` eval "with_${ac_package}=no" ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes="$ac_optarg" ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries="$ac_optarg" ;; -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } ;; *) if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then echo "configure: warning: $ac_option: invalid host type" 1>&2 fi if test "x$nonopt" != xNONE; then { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } fi nonopt="$ac_option" ;; esac done if test -n "$ac_prev"; then { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } fi trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 # File descriptor usage: # 0 standard input # 1 file creation # 2 errors and warnings # 3 some systems may open it to /dev/tty # 4 used on the Kubota Titan # 6 checking for... messages and results # 5 compiler messages saved in config.log if test "$silent" = yes; then exec 6>/dev/null else exec 6>&1 fi exec 5>./config.log echo "\ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. " 1>&5 # Strip out --no-create and --no-recursion so they do not pile up. # Also quote any args containing shell metacharacters. ac_configure_args= for ac_arg do case "$ac_arg" in -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c) ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) ac_configure_args="$ac_configure_args '$ac_arg'" ;; *) ac_configure_args="$ac_configure_args $ac_arg" ;; esac done # NLS nuisances. # Only set LANG and LC_ALL to C if already set. # These must not be set unconditionally because not all systems understand # e.g. LANG=C (notably SCO). if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi if test "${LANG+set}" = set; then LANG=C; export LANG; fi # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -rf conftest* confdefs.h # AIX cpp loses on an empty file, so make sure it contains at least a newline. echo > confdefs.h # A filename unique to this package, relative to the directory that # configure is in, which we can look for to find out if srcdir is correct. ac_unique_file=wily/wily.c # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then its parent. ac_prog=$0 ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. srcdir=$ac_confdir if test ! -r $srcdir/$ac_unique_file; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r $srcdir/$ac_unique_file; then if test "$ac_srcdir_defaulted" = yes; then { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } else { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } fi fi srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` # Prefer explicitly selected file to automatically selected ones. if test -z "$CONFIG_SITE"; then if test "x$prefix" != xNONE; then CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" else CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then echo "loading site script $ac_site_file" . "$ac_site_file" fi done if test -r "$cache_file"; then echo "loading cache $cache_file" . $cache_file else echo "creating cache $cache_file" > $cache_file fi ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5 2>&5' ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5 2>&5' if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then ac_n= ac_c=' ' ac_t=' ' else ac_n=-n ac_c= ac_t= fi else ac_n= ac_c='\c' ac_t= fi ac_aux_dir= for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do if test -f $ac_dir/install-sh; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f $ac_dir/install.sh; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break fi done if test -z "$ac_aux_dir"; then { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } fi ac_config_guess=$ac_aux_dir/config.guess ac_config_sub=$ac_aux_dir/config.sub ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # ./install, which can be erroneously created by make from ./install.sh. echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 if test -z "$INSTALL"; then if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" for ac_dir in $PATH; do # Account for people who put trailing slashes in PATH elements. case "$ac_dir/" in /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. for ac_prog in ginstall installbsd scoinst install; do if test -f $ac_dir/$ac_prog; then if test $ac_prog = install && grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. # OSF/1 installbsd also uses dspmsg, but is usable. : else ac_cv_path_install="$ac_dir/$ac_prog -c" break 2 fi fi done ;; esac done IFS="$ac_save_ifs" # As a last resort, use the slow shell script. test -z "$ac_cv_path_install" && ac_cv_path_install="$ac_install_sh" fi INSTALL="$ac_cv_path_install" fi echo "$ac_t""$INSTALL" 1>&6 # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_CC="gcc" break fi done IFS="$ac_save_ifs" test -z "$ac_cv_prog_CC" && ac_cv_prog_CC="cc" fi fi CC="$ac_cv_prog_CC" if test -n "$CC"; then echo "$ac_t""$CC" 1>&6 else echo "$ac_t""no" 1>&6 fi echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.c <&5 | egrep yes >/dev/null 2>&1; then ac_cv_prog_gcc=yes else ac_cv_prog_gcc=no fi fi echo "$ac_t""$ac_cv_prog_gcc" 1>&6 if test $ac_cv_prog_gcc = yes; then GCC=yes if test "${CFLAGS+set}" != set; then echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_prog_gcc_g'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else echo 'void f(){}' > conftest.c if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then ac_cv_prog_gcc_g=yes else ac_cv_prog_gcc_g=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_prog_gcc_g" 1>&6 if test $ac_cv_prog_gcc_g = yes; then CFLAGS="-g -O" else CFLAGS="-O" fi fi else GCC= test "${CFLAGS+set}" = set || CFLAGS="-g" fi echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else rm -f conftestdata if ln -s X conftestdata 2>/dev/null then rm -f conftestdata ac_cv_prog_LN_S="ln -s" else ac_cv_prog_LN_S=ln fi fi LN_S="$ac_cv_prog_LN_S" if test "$ac_cv_prog_LN_S" = "ln -s"; then echo "$ac_t""yes" 1>&6 else echo "$ac_t""no" 1>&6 fi # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_RANLIB="ranlib" break fi done IFS="$ac_save_ifs" test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" fi fi RANLIB="$ac_cv_prog_RANLIB" if test -n "$RANLIB"; then echo "$ac_t""$RANLIB" 1>&6 else echo "$ac_t""no" 1>&6 fi echo $ac_n "checking for POSIXized ISC""... $ac_c" 1>&6 if test -d /etc/conf/kconfig.d && grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1 then echo "$ac_t""yes" 1>&6 ISC=yes # If later tests want to check for ISC. cat >> confdefs.h <<\EOF #define _POSIX_SOURCE 1 EOF if test "$GCC" = yes; then CC="$CC -posix" else CC="$CC -Xp" fi else echo "$ac_t""no" 1>&6 ISC= fi echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else # This must be in double quotes, not single quotes, because CPP may get # substituted into the Makefile and "${CC-cc}" will confuse make. CPP="${CC-cc} -E" # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. cat > conftest.$ac_ext < Syntax Error EOF eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then : else echo "$ac_err" >&5 rm -rf conftest* CPP="${CC-cc} -E -traditional-cpp" cat > conftest.$ac_ext < Syntax Error EOF eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then : else echo "$ac_err" >&5 rm -rf conftest* CPP=/lib/cpp fi rm -f conftest* fi rm -f conftest* ac_cv_prog_CPP="$CPP" fi CPP="$ac_cv_prog_CPP" else ac_cv_prog_CPP="$CPP" fi echo "$ac_t""$CPP" 1>&6 # If we find X, set shell vars x_includes and x_libraries to the # paths, otherwise set no_x=yes. # Uses ac_ vars as temps to allow command line to override cache and checks. # --without-x overrides everything else, but does not touch the cache. echo $ac_n "checking for X""... $ac_c" 1>&6 # Check whether --with-x or --without-x was given. withval="$with_x" if test -n "$withval"; then : fi if test "x$with_x" = xno; then no_x=yes else if test "x$x_includes" != xNONE && test "x$x_libraries" != xNONE; then no_x= else if eval "test \"`echo '$''{'ac_cv_path_x'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else # One or both of the vars are not set, and there is no cached value. no_x=yes rm -fr conftestdir if mkdir conftestdir; then cd conftestdir # Make sure to not put "make" in the Imakefile rules, since we grep it out. cat > Imakefile <<'EOF' acfindx: @echo 'ac_im_incroot="${INCROOT}"; ac_im_usrlibdir="${USRLIBDIR}"; ac_im_libdir="${LIBDIR}"' EOF if (xmkmf) >/dev/null 2>/dev/null && test -f Makefile; then no_x= # GNU make sometimes prints "make[1]: Entering...", which would confuse us. eval `make acfindx 2>/dev/null | grep -v make` # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. for ac_extension in a so sl; do if test ! -f $ac_im_usrlibdir/libX11.$ac_extension && test -f $ac_im_libdir/libX11.$ac_extension; then ac_im_usrlibdir=$ac_im_libdir; break fi done # Screen out bogus values from the imake configuration. case "$ac_im_incroot" in /usr/include) ;; *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes="$ac_im_incroot" ;; esac case "$ac_im_usrlibdir" in /usr/lib | /lib) ;; *) test -d "$ac_im_usrlibdir" && ac_x_libraries="$ac_im_usrlibdir" ;; esac fi cd .. rm -fr conftestdir fi if test "$no_x" = yes; then test -z "$x_direct_test_library" && x_direct_test_library=Xt test -z "$x_direct_test_function" && x_direct_test_function=XtMalloc test -z "$x_direct_test_include" && x_direct_test_include=X11/Intrinsic.h cat > conftest.$ac_ext < EOF eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* no_x= ac_x_includes= else echo "$ac_err" >&5 rm -rf conftest* for ac_dir in \ /usr/X11R6/include \ /usr/X11R5/include \ /usr/X11R4/include \ \ /usr/include/X11R6 \ /usr/include/X11R5 \ /usr/include/X11R4 \ \ /usr/local/X11R6/include \ /usr/local/X11R5/include \ /usr/local/X11R4/include \ \ /usr/local/include/X11R6 \ /usr/local/include/X11R5 \ /usr/local/include/X11R4 \ \ /usr/X11/include \ /usr/include/X11 \ /usr/local/X11/include \ /usr/local/include/X11 \ \ /usr/X386/include \ /usr/x386/include \ /usr/XFree86/include/X11 \ \ /usr/include \ /usr/local/include \ /usr/unsupported/include \ /usr/athena/include \ /usr/local/x11r5/include \ /usr/lpp/Xamples/include \ \ /usr/openwin/include \ /usr/openwin/share/include \ ; \ do if test -r "$ac_dir/$x_direct_test_include"; then no_x= ac_x_includes=$ac_dir break fi done fi rm -f conftest* # Check for the libraries. # See if we find them without any special options. # Don't add to $LIBS permanently. ac_save_LIBS="$LIBS" LIBS="-l$x_direct_test_library $LIBS" cat > conftest.$ac_ext <&6 else test "x$x_includes" = xNONE && x_includes=$ac_x_includes test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries ac_cv_path_x="no_x= ac_x_includes=$x_includes ac_x_libraries=$x_libraries" echo "$ac_t""libraries $x_libraries, headers $x_includes" 1>&6 fi if test "$no_x" = yes; then # Not all programs may use this symbol, but it does not hurt to define it. X_CFLAGS="$X_CFLAGS -DX_DISPLAY_MISSING" else if test -n "$x_includes"; then X_CFLAGS="$X_CFLAGS -I$x_includes" fi # It would be nice to have a more robust check for the -R ld option than # just checking for Solaris. # It would also be nice to do this for all -L options, not just this one. if test -n "$x_libraries"; then X_LIBS="$X_LIBS -L$x_libraries" if test "`(uname) 2>/dev/null`" = SunOS && uname -r | grep '^5' >/dev/null; then X_LIBS="$X_LIBS -R$x_libraries" fi fi # Check for libraries that X11R6 Xt/Xaw programs need. ac_save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -L$x_libraries" # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to # check for ICE first), but we must link in the order -lSM -lICE or # we get undefined symbols. So assume we have SM if we have ICE. # These have to be linked with before -lX11, unlike the other # libraries we check for below, so use a different variable. # --interran@uluru.Stanford.EDU, kb@cs.umb.edu. echo $ac_n "checking for -lICE""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_lib_ICE'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lICE $LIBS" cat > conftest.$ac_ext <&6 X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE" else echo "$ac_t""no" 1>&6 fi LDFLAGS="$ac_save_LDFLAGS" # Check for system-dependent libraries X programs must link with. if test "$ISC" = yes; then X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet" else # Martyn.Johnson@cl.cam.ac.uk says this is needed for Ultrix, if the X # libraries were built with DECnet support. And karl@cs.umb.edu says # the Alpha needs dnet_stub (dnet does not exist). echo $ac_n "checking for -ldnet""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_lib_dnet'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-ldnet $LIBS" cat > conftest.$ac_ext <&6 X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet" else echo "$ac_t""no" 1>&6 fi if test $ac_cv_lib_dnet = no; then echo $ac_n "checking for -ldnet_stub""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_lib_dnet_stub'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-ldnet_stub $LIBS" cat > conftest.$ac_ext <&6 X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub" else echo "$ac_t""no" 1>&6 fi fi # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT, # to get the SysV transport functions. # Not sure which flavor of 386 UNIX this is, but it seems harmless to # check for it. echo $ac_n "checking for -lnsl""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_lib_nsl'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lnsl $LIBS" cat > conftest.$ac_ext <&6 X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl" else echo "$ac_t""no" 1>&6 fi # lieder@skyler.mavd.honeywell.com says without -lsocket, # socket/setsockopt and other routines are undefined under SCO ODT 2.0. # But -lsocket is broken on IRIX, according to simon@lia.di.epfl.ch. if test "`(uname) 2>/dev/null`" != IRIX; then echo $ac_n "checking for -lsocket""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_lib_socket'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lsocket $LIBS" cat > conftest.$ac_ext <&6 X_EXTRA_LIBS="$X_EXTRA_LIBS -lsocket" else echo "$ac_t""no" 1>&6 fi fi fi fi echo $ac_n "checking for -lm""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_lib_m'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lm $LIBS" cat > conftest.$ac_ext <&6 ac_tr_lib=HAVE_LIB`echo m | tr '[a-z]' '[A-Z]'` cat >> confdefs.h <&6 fi echo $ac_n "checking for -lnsl""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_lib_nsl'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lnsl $LIBS" cat > conftest.$ac_ext <&6 ac_tr_lib=HAVE_LIB`echo nsl | tr '[a-z]' '[A-Z]'` cat >> confdefs.h <&6 fi echo $ac_n "checking for -lsocket""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_lib_socket'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lsocket $LIBS" cat > conftest.$ac_ext <&6 ac_tr_lib=HAVE_LIB`echo socket | tr '[a-z]' '[A-Z]'` cat >> confdefs.h <&6 fi ac_header_dirent=no for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h do ac_safe=`echo "$ac_hdr" | tr './\055' '___'` echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include <$ac_hdr> int main() { return 0; } int t() { DIR *dirp = 0; ; return 0; } EOF if eval $ac_compile; then rm -rf conftest* eval "ac_cv_header_dirent_$ac_safe=yes" else rm -rf conftest* eval "ac_cv_header_dirent_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_hdr=HAVE_`echo $ac_hdr | tr '[a-z]./\055' '[A-Z]___'` cat >> confdefs.h <&6 fi done # Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. if test $ac_header_dirent = dirent.h; then echo $ac_n "checking for -ldir""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_lib_dir'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-ldir $LIBS" cat > conftest.$ac_ext <&6 LIBS="$LIBS -ldir" else echo "$ac_t""no" 1>&6 fi else echo $ac_n "checking for -lx""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_lib_x'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lx $LIBS" cat > conftest.$ac_ext <&6 LIBS="$LIBS -lx" else echo "$ac_t""no" 1>&6 fi fi # If we cannot run a trivial program, we must be cross compiling. echo $ac_n "checking whether cross-compiling""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_c_cross'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$cross_compiling" = yes; then ac_cv_c_cross=yes else cat > conftest.$ac_ext </dev/null; then ac_cv_c_cross=no else ac_cv_c_cross=yes fi fi rm -fr conftest* fi cross_compiling=$ac_cv_c_cross echo "$ac_t""$ac_cv_c_cross" 1>&6 echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include #include #include EOF eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* ac_cv_header_stdc=yes else echo "$ac_err" >&5 rm -rf conftest* ac_cv_header_stdc=no fi rm -f conftest* if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat > conftest.$ac_ext < EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "memchr" >/dev/null 2>&1; then : else rm -rf conftest* ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat > conftest.$ac_ext < EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "free" >/dev/null 2>&1; then : else rm -rf conftest* ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then ac_cv_header_stdc=no else cat > conftest.$ac_ext < #define ISLOWER(c) ('a' <= (c) && (c) <= 'z') #define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); exit (0); } EOF eval $ac_link if test -s conftest && (./conftest; exit) 2>/dev/null; then : else ac_cv_header_stdc=no fi fi rm -fr conftest* fi fi echo "$ac_t""$ac_cv_header_stdc" 1>&6 if test $ac_cv_header_stdc = yes; then cat >> confdefs.h <<\EOF #define STDC_HEADERS 1 EOF fi echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_header_sys_wait_h'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include #ifndef WEXITSTATUS #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) #endif #ifndef WIFEXITED #define WIFEXITED(stat_val) (((stat_val) & 255) == 0) #endif int main() { return 0; } int t() { int s; wait (&s); s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; ; return 0; } EOF if eval $ac_compile; then rm -rf conftest* ac_cv_header_sys_wait_h=yes else rm -rf conftest* ac_cv_header_sys_wait_h=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_header_sys_wait_h" 1>&6 if test $ac_cv_header_sys_wait_h = yes; then cat >> confdefs.h <<\EOF #define HAVE_SYS_WAIT_H 1 EOF fi for ac_hdr in fcntl.h limits.h malloc.h sys/time.h unistd.h sys/select.h stdarg.h stdlib.h do ac_safe=`echo "$ac_hdr" | tr './\055' '___'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_hdr=HAVE_`echo $ac_hdr | tr '[a-z]./\055' '[A-Z]___'` cat >> confdefs.h <&6 fi done echo $ac_n "checking for working const""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; } ; return 0; } EOF if eval $ac_compile; then rm -rf conftest* ac_cv_c_const=yes else rm -rf conftest* ac_cv_c_const=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_c_const" 1>&6 if test $ac_cv_c_const = no; then cat >> confdefs.h <<\EOF #define const EOF fi echo $ac_n "checking for size_t""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS #include #endif EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "size_t" >/dev/null 2>&1; then rm -rf conftest* ac_cv_type_size_t=yes else rm -rf conftest* ac_cv_type_size_t=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_type_size_t" 1>&6 if test $ac_cv_type_size_t = no; then cat >> confdefs.h <<\EOF #define size_t unsigned EOF fi echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include #include int main() { return 0; } int t() { struct tm *tp; ; return 0; } EOF if eval $ac_compile; then rm -rf conftest* ac_cv_header_time=yes else rm -rf conftest* ac_cv_header_time=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_header_time" 1>&6 if test $ac_cv_header_time = yes; then cat >> confdefs.h <<\EOF #define TIME_WITH_SYS_TIME 1 EOF fi echo $ac_n "checking for ulong""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_type_ulong'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS #include #endif EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "ulong *;" >/dev/null 2>&1; then rm -rf conftest* ac_cv_type_ulong=yes else rm -rf conftest* ac_cv_type_ulong=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_type_ulong" 1>&6 if test $ac_cv_type_ulong = yes; then ac_type=HAVE_`echo ulong | tr '[a-z]' '[A-Z]'` cat >> confdefs.h <&6 if eval "test \"`echo '$''{'ac_cv_type_ushort'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS #include #endif EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "ushort *;" >/dev/null 2>&1; then rm -rf conftest* ac_cv_type_ushort=yes else rm -rf conftest* ac_cv_type_ushort=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_type_ushort" 1>&6 if test $ac_cv_type_ushort = yes; then ac_type=HAVE_`echo ushort | tr '[a-z]' '[A-Z]'` cat >> confdefs.h <&6 if eval "test \"`echo '$''{'ac_cv_type_uint'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS #include #endif EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "uint *;" >/dev/null 2>&1; then rm -rf conftest* ac_cv_type_uint=yes else rm -rf conftest* ac_cv_type_uint=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_type_uint" 1>&6 if test $ac_cv_type_uint = yes; then ac_type=HAVE_`echo uint | tr '[a-z]' '[A-Z]'` cat >> confdefs.h <&6 if eval "test \"`echo '$''{'ac_cv_type_uchar'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS #include #endif EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "uchar *;" >/dev/null 2>&1; then rm -rf conftest* ac_cv_type_uchar=yes else rm -rf conftest* ac_cv_type_uchar=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_type_uchar" 1>&6 if test $ac_cv_type_uchar = yes; then ac_type=HAVE_`echo uchar | tr '[a-z]' '[A-Z]'` cat >> confdefs.h <&6 if eval "test \"`echo '$''{'ac_cv_type_caddr_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS #include #endif EOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | egrep "caddr_t *;" >/dev/null 2>&1; then rm -rf conftest* ac_cv_type_caddr_t=yes else rm -rf conftest* ac_cv_type_caddr_t=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_type_caddr_t" 1>&6 if test $ac_cv_type_caddr_t = yes; then ac_type=HAVE_`echo caddr_t | tr '[a-z]' '[A-Z]'` cat >> confdefs.h <&6 if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include #ifdef signal #undef signal #endif #ifdef __cplusplus extern "C" #endif void (*signal ()) (); int main() { return 0; } int t() { int i; ; return 0; } EOF if eval $ac_compile; then rm -rf conftest* ac_cv_type_signal=void else rm -rf conftest* ac_cv_type_signal=int fi rm -f conftest* fi echo "$ac_t""$ac_cv_type_signal" 1>&6 cat >> confdefs.h <&6 if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ char vprintf(); int main() { return 0; } int t() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_vprintf) || defined (__stub___vprintf) choke me #else vprintf(); #endif ; return 0; } EOF if eval $ac_link; then rm -rf conftest* eval "ac_cv_func_vprintf=yes" else rm -rf conftest* eval "ac_cv_func_vprintf=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then echo "$ac_t""yes" 1>&6 cat >> confdefs.h <<\EOF #define HAVE_VPRINTF 1 EOF else echo "$ac_t""no" 1>&6 fi if test "$ac_cv_func_vprintf" != yes; then echo $ac_n "checking for _doprnt""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ char _doprnt(); int main() { return 0; } int t() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub__doprnt) || defined (__stub____doprnt) choke me #else _doprnt(); #endif ; return 0; } EOF if eval $ac_link; then rm -rf conftest* eval "ac_cv_func__doprnt=yes" else rm -rf conftest* eval "ac_cv_func__doprnt=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then echo "$ac_t""yes" 1>&6 cat >> confdefs.h <<\EOF #define HAVE_DOPRNT 1 EOF else echo "$ac_t""no" 1>&6 fi fi for ac_func in strerror memmove remove do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ char $ac_func(); int main() { return 0; } int t() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else $ac_func(); #endif ; return 0; } EOF if eval $ac_link; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else rm -rf conftest* eval "ac_cv_func_$ac_func=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_func=HAVE_`echo $ac_func | tr '[a-z]' '[A-Z]'` cat >> confdefs.h <&6 fi done trap '' 1 2 15 cat > confcache <<\EOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs. It is not useful on other systems. # If it contains results you don't want to keep, you may remove or edit it. # # By default, configure uses ./config.cache as the cache file, # creating it if it does not exist already. You can give configure # the --cache-file=FILE option to use a different cache file; that is # what configure does when it calls configure scripts in # subdirectories, so they share the cache. # Giving --cache-file=/dev/null disables caching, for debugging configure. # config.status only pays attention to the cache file if you give it the # --recheck option to rerun configure. # EOF # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. (set) 2>&1 | sed -n "s/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=\${\1='\2'}/p" \ >> confcache if cmp -s $cache_file confcache; then : else if test -w $cache_file; then echo "updating cache $cache_file" cat confcache > $cache_file else echo "not updating unwritable cache $cache_file" fi fi rm -f confcache trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Any assignment to VPATH causes Sun make to only execute # the first set of double-colon rules, so remove it if not needed. # If there is a colon in the path, we need to keep it. if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' fi trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 DEFS=-DHAVE_CONFIG_H # Without the "./", some shells look in PATH for config.status. : ${CONFIG_STATUS=./config.status} echo creating $CONFIG_STATUS rm -f $CONFIG_STATUS cat > $CONFIG_STATUS </dev/null | sed 1q`: # # $0 $ac_configure_args # # Compiler output produced by configure, useful for debugging # configure, is in ./config.log if it exists. ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" for ac_option do case "\$ac_option" in -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; -version | --version | --versio | --versi | --vers | --ver | --ve | --v) echo "$CONFIG_STATUS generated by autoconf version 2.4" exit 0 ;; -help | --help | --hel | --he | --h) echo "\$ac_cs_usage"; exit 0 ;; *) echo "\$ac_cs_usage"; exit 1 ;; esac done ac_given_srcdir=$srcdir ac_given_INSTALL="$INSTALL" trap 'rm -fr `echo "Makefile wily/Makefile libXg/Makefile libframe/Makefile libmsg/Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 # Protect against being on the right side of a sed subst in config.status. sed 's/%@/@@/; s/@%/@@/; s/%g$/@g/; /@g$/s/[\\\\&%]/\\\\&/g; s/@@/%@/; s/@@/@%/; s/@g$/%g/' > conftest.subs <<\CEOF $ac_vpsub $extrasub s%@CFLAGS@%$CFLAGS%g s%@CPPFLAGS@%$CPPFLAGS%g s%@CXXFLAGS@%$CXXFLAGS%g s%@DEFS@%$DEFS%g s%@LDFLAGS@%$LDFLAGS%g s%@LIBS@%$LIBS%g s%@exec_prefix@%$exec_prefix%g s%@prefix@%$prefix%g s%@program_transform_name@%$program_transform_name%g s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g s%@INSTALL_DATA@%$INSTALL_DATA%g s%@CC@%$CC%g s%@LN_S@%$LN_S%g s%@RANLIB@%$RANLIB%g s%@CPP@%$CPP%g s%@X_CFLAGS@%$X_CFLAGS%g s%@X_PRE_LIBS@%$X_PRE_LIBS%g s%@X_LIBS@%$X_LIBS%g s%@X_EXTRA_LIBS@%$X_EXTRA_LIBS%g CEOF EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then # Support "outfile[:infile]", defaulting infile="outfile.in". case "$ac_file" in *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'` ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; *) ac_file_in="${ac_file}.in" ;; esac # Adjust relative srcdir, etc. for subdirectories. # Remove last slash and all that follows it. Not all systems have dirname. ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then # The file is in a subdirectory. test ! -d "$ac_dir" && mkdir "$ac_dir" ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" # A "../" for each directory in $ac_dir_suffix. ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` else ac_dir_suffix= ac_dots= fi case "$ac_given_srcdir" in .) srcdir=. if test -z "$ac_dots"; then top_srcdir=. else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; *) # Relative path. srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" top_srcdir="$ac_dots$ac_given_srcdir" ;; esac case "$ac_given_INSTALL" in [/$]*) INSTALL="$ac_given_INSTALL" ;; *) INSTALL="$ac_dots$ac_given_INSTALL" ;; esac echo creating "$ac_file" rm -f "$ac_file" configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." case "$ac_file" in *Makefile*) ac_comsub="1i\\ # $configure_input" ;; *) ac_comsub= ;; esac sed -e "$ac_comsub s%@configure_input@%$configure_input%g s%@srcdir@%$srcdir%g s%@top_srcdir@%$top_srcdir%g s%@INSTALL@%$INSTALL%g " -f conftest.subs $ac_given_srcdir/$ac_file_in > $ac_file fi; done rm -f conftest.subs # These sed commands are passed to sed as "A NAME B NAME C VALUE D", where # NAME is the cpp macro being defined and VALUE is the value it is being given. # # ac_d sets the value in "#define NAME VALUE" lines. ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' ac_dC='\3' ac_dD='%g' # ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' ac_uB='\([ ]\)%\1#\2define\3' ac_uC=' ' ac_uD='\4%g' # ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' ac_eB='$%\1#\2define\3' ac_eC=' ' ac_eD='%g' CONFIG_HEADERS=${CONFIG_HEADERS-"config.h"} for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then # Support "outfile[:infile]", defaulting infile="outfile.in". case "$ac_file" in *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'` ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; *) ac_file_in="${ac_file}.in" ;; esac echo creating $ac_file rm -f conftest.frag conftest.in conftest.out cp $ac_given_srcdir/$ac_file_in conftest.in EOF # Transform confdefs.h into a sed script conftest.vals that substitutes # the proper values into config.h.in to produce config.h. And first: # Protect against being on the right side of a sed subst in config.status. # Protect against being in an unquoted here document in config.status. rm -f conftest.vals cat > conftest.hdr <<\EOF s/[\\&%]/\\&/g s%[\\$`]%\\&%g s%#define \([A-Za-z_][A-Za-z0-9_]*\) \(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp s%ac_d%ac_u%gp s%ac_u%ac_e%gp EOF sed -n -f conftest.hdr confdefs.h > conftest.vals rm -f conftest.hdr # This sed command replaces #undef with comments. This is necessary, for # example, in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. cat >> conftest.vals <<\EOF s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% EOF # Break up conftest.vals because some shells have a limit on # the size of here documents, and old seds have small limits too. # Maximum number of lines to put in a single here document. ac_max_here_lines=12 rm -f conftest.tail while : do ac_lines=`grep -c . conftest.vals` # grep -c gives empty output for an empty file on some AIX systems. if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi # Write a limited-size here document to conftest.frag. echo ' cat > conftest.frag <> $CONFIG_STATUS sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS echo 'CEOF sed -f conftest.frag conftest.in > conftest.out rm -f conftest.in mv conftest.out conftest.in ' >> $CONFIG_STATUS sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail rm -f conftest.vals mv conftest.tail conftest.vals done rm -f conftest.vals cat >> $CONFIG_STATUS <<\EOF rm -f conftest.frag conftest.h echo "/* $ac_file. Generated automatically by configure. */" > conftest.h cat conftest.in >> conftest.h rm -f conftest.in if cmp -s $ac_file conftest.h 2>/dev/null; then echo "$ac_file is unchanged" rm -f conftest.h else rm -f $ac_file mv conftest.h $ac_file fi fi; done exit 0 EOF chmod +x $CONFIG_STATUS rm -fr confdefs* $ac_clean_files test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 cat > conftest.$ac_ext < /* Override any gcc2 interwily-0.13.42/configure.in000064402366570000012000000016521033320152300150110ustar00ozstaff00004330000002dnl Process this file with autoconf to produce a configure script. AC_INIT(wily/wily.c) AC_CONFIG_HEADER(config.h) dnl Checks for programs. AC_PROG_INSTALL AC_PROG_CC AC_PROG_LN_S AC_PROG_RANLIB AC_ISC_POSIX AC_PATH_XTRA dnl Checks for libraries. AC_CHECK_LIB(m, sin) AC_CHECK_LIB(nsl, gethostent) AC_CHECK_LIB(socket, connect) dnl Checks for header files. AC_HEADER_DIRENT AC_HEADER_STDC AC_HEADER_SYS_WAIT AC_CHECK_HEADERS(fcntl.h limits.h malloc.h sys/time.h unistd.h sys/select.h stdarg.h stdlib.h) dnl Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_TYPE_SIZE_T AC_HEADER_TIME AC_CHECK_HAVE_TYPE(ulong) AC_CHECK_HAVE_TYPE(ushort) AC_CHECK_HAVE_TYPE(uint) AC_CHECK_HAVE_TYPE(uchar) AC_CHECK_HAVE_TYPE(caddr_t) dnl Checks for library functions. AC_TYPE_SIGNAL AC_FUNC_VPRINTF AC_CHECK_FUNCS(strerror memmove remove) AC_OUTPUT(Makefile wily/Makefile libXg/Makefile libframe/Makefile libmsg/Makefile) wily-0.13.42/install-sh000064402366570000012000000112441033320152300144770ustar00ozstaff00004330000002#! /bin/sh # # install - install a program, script, or datafile # This comes from X11R5. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. # # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" tranformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 o "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`ecwily-0.13.42/Artistic000064402366570000012000000137401033320152300142060ustar00ozstaff00004330000002 The "Artistic License" Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder as specified below. "Copyright Holder" is whoever is named in the copyright or copyrights for the package. "You" is you, if you're thinking about copying or distributing this Package. "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as uunet.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) give non-standard executables non-standard names, and clearly document the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. You may embed this Package's interpreter within an executable of yours (by linking); this shall be construed as a mere form of aggregation, provided that the complete Standard Version of the interpreter is so embedded. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this Package. If such scripts or library files are aggregated with this Package via the so-called "undump" or "unexec" methods of producing a binary executable image, then distribution of such an image shall neither be construed as a distribution of this Package nor shall it fall under the restrictions of Paragraphs 3 and 4, provided that you do not represent such an executable image as a Standard Version of this Package. 7. C subroutines (or comparably compiled subroutines in other languages) supplied by you and linked into this Package in order to emulate subroutines and variables of the language defined by this Package shall not be considered part of this Package, but are the equivalent of input as in Paragraph 6, provided these subroutines do not change the language in any way that would cause it to fail the regression tests for the language. 8. Aggregation of this Package with a commercial distribution is always permitted provided that the use of this Package is embedded; that is, when no overt attempt is made to make this Package's interfaces visible to the end user of the commercial distribution. Such use shall not be construed as a distribution of this Package. 9. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End wily-0.13.42/Makefile.in000064402366570000012000000011631041526262700145570ustar00ozstaff00004330000002SHELL=/bin/sh srcdir=@srcdir@ VPATH=@srcdir@ SUBDIRS=libXg libframe libmsg wily all: wily/wily wily/wily: libXg/libXg.a libframe/libframe.a libmsg/libmsg.a cd wily; $(MAKE) $(MFLAGS) libXg/libXg.a: cd libXg; $(MAKE) $(MFLAGS) libframe/libframe.a: cd libframe; $(MAKE) $(MFLAGS) all libmsg/libmsg.a: cd libmsg; $(MAKE) $(MFLAGS) all install: all cd wily; $(MAKE) $(MFLAGS) install clean: for i in $(SUBDIRS); do \ (cd $$i; $(MAKE) $(MFLAGS) $@); \ done nuke: for i in $(SUBDIRS); do \ (cd $$i; $(MAKE) $(MFLAGS) $@); \ done -rm -f wily.* config.cache config.h config.log config.status Makefile distclean: nuke libXg.a libframe/libframe.a libmsg/libmsg.a cd wily; $(MAKE) $(MFLAGS) libXg/libXg.a: cd libXg; $(MAKE) $(MFLAGS) libframe/libframe.a: cd libframe; $(MAKE) $(MFLAGS) all libmsg/libmsg.a: cd libmsg; $(MAKE) $(MFLAGS) all install: all cd wily; $(MAKE) $(MFLAGS) install clean: for i in $(SUBDIRS); do \ (cd $$i; $(MAKE) $(MFLAGS) $@); \ done nuke: for i in $(SUBDIRS); do \ (cd $$i; $(Mwily-0.13.42/libmsg/000075502366570000012000000000001041526267400137705ustar00ozstaff00004330000002wily-0.13.42/libmsg/msg.c000064402366570000012000000106301033320152300147030ustar00ozstaff00004330000002#include #include #include #include #include #include #include #include #include /* ../include/msg.h */ /* NOTE: msg_flatten and msg_init need to remain in sync. * Preferably the msg_flatten and msg_init functions of different * versions should still be able to talk to one another, i.e. the * message protocol on the wire should stay the same. off bytes value 0 2 0xfeed (cookie) 2 2 message type 4 4 total message length (len) 8 2 message id 10 2 window id 12 4 r.p0 16 4 r.p1 20 2 flag 22 len-22 null-terminated utf string */ enum { HEADERSIZE = 22, COOKIE = 0xfeed, DEBUG=0 }; static ushort get2(uchar*); static ulong get4(uchar*); static void put2(uchar*, ushort); static void put4(uchar*, ulong); void msg_fill(Msg*m, Mtype t, Id w, Range r, ushort flag, char*s) { m->t = t; m->w = w; m->r = r; m->flag = flag; m->s = s; } /* Return number of bytes which would be needed to * flatten 'm' */ int msg_size(Msg *m) { assert(m); return HEADERSIZE + 1 + (m->s? strlen(m->s) : 0); } /* Flatten 'm' into 'buf', which has at least msg_size(m) bytes of space. */ void msg_flatten (Msg*m, uchar*buf) { if(DEBUG) { printf("flattening "); msg_print(m); } put2(buf, COOKIE); put2(buf+2, m->t); put4(buf+4, msg_size(m)); put2(buf+8, m->m); put2(buf+10, m->w); put4(buf+12, m->r.p0); put4(buf+16, m->r.p1); put2(buf+20, m->flag); strcpy(buf+22, m->s?m->s:""); } /* Fill in the fields of 'm', using 'buf', which has 'size' bytes. * PRE: at least msg_bufsize() bytes in 'buf' * * POST: m's fields are filled in. m.s points to a null-terminated * string WITHIN BUF. We return 0. * If there was some internal inconsistency, we return -1, and * the contents of 'm' are undefined. * * WARNING: We may point to a string inside 'buf', rather than * copying it. This means you should not free 'buf' until you've * finished with 'm'. */ int msg_init (Msg*m, uchar*buf) { ulong len; len = get4(buf+4); if (get2(buf)!=COOKIE || lent = get2(buf+2); m->m = get2(buf+8); m->w = get2(buf+10); m->r.p0 = get4(buf+12); m->r.p1 = get4(buf+16); m->flag = get2(buf+20); m->s = buf+22; buf[len-1]='\0'; /* ENSURE m->s is null-terminated */ if(DEBUG) { printf("initialized "); msg_print(m); } return 0; } /* Return number of bytes needed for the complete message, * of which the beginning is in the buffer. There must be * at least 8 bytes in the buffer already, or we get garbage. */ ulong msg_bufsize (uchar*buf) { return get4(buf+4); } void msg_print(Msg *m) { printf("("); switch(m->t) { case WRerror : printf("(WRerror"); break; case WMlist : printf("WMlist"); break; case WRlist : printf("WRlist"); break; case WMnew : printf("WMnew"); break; case WRnew : printf("WRnew"); break; case WMattach : printf("WMattach"); break; case WRattach : printf("WRattach"); break; case WMsetname : printf("WMsetname"); break; case WMgetname : printf("WMgetname"); break; case WRsetname : printf("WRsetname"); break; case WRgetname : printf("WRgetname"); break; case WMsettools : printf("WMsettools"); break; case WMgettools : printf("WMgettools"); break; case WRsettools : printf("WRsettools"); break; case WRgettools : printf("WRgettools"); break; case WMread : printf("WMread"); break; case WRread : printf("WRread"); break; case WMreplace : printf("WMreplace"); break; case WRreplace : printf("WRreplace"); break; case WMexec : printf("WMexec"); break; case WRexec : printf("WRexec"); break; case WMgoto : printf("WMgoto"); break; case WRgoto : printf("WRgoto"); break; case WMfencepost : printf("WMfencepost"); break; case WEexec : printf("WEexec"); break; case WEreplace : printf("WEreplace"); break; case WEgoto : printf("WEgoto"); break; case WEdestroy : printf("WEdestroy"); break; case WEfencepost : printf("WEfencepost"); break; default : printf("Unknown"); break; } printf(", %d", m->m); printf(", %d", m->w); printf(", %d", m->flag); printf(", (%lu,%lu)", m->r.p0, m->r.p1); printf(", [%s]) ", m->s?m->s:""); } static ushort get2(uchar*p) { return (p[0]<<8) + p[1]; } static ulong get4(uchar*p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } static void put2(uchar*p, ushort n) { p[0] = (n>>8)&0xff; p[1] = n &0xff; } static void put4(uchar*p, ulong n) { p[0] = (n>>24)&0xff; p[1] = (n>>16)&0xff; p[2] = (n>>8)&0xff; p[3] = (n)&0xff; } wily-0.13.42/libmsg/rpc.c000064402366570000012000000177121033320152300147110ustar00ozstaff00004330000002#include #include #include #include /* see ../include/msg.h */ /* Send messages, receive replies, queue events until we're asked for them. */ enum { Qmax = 20 }; typedef struct MsgQ MsgQ; typedef struct MsgSet MsgSet; struct MsgQ { Msg msg[Qmax]; int read,write; }; static void msgq_init (MsgQ*); static Bool msgq_empty (MsgQ*); static Bool msgq_full (MsgQ*); static Msg msgq_pop (MsgQ*); static void msgq_push (MsgQ*,Msg); struct MsgSet { Msg msg [Qmax]; Bool inuse [Qmax]; int n; }; static void msgset_init (MsgSet*); static Bool msgset_full (MsgSet*); static Bool msgset_find (MsgSet*, Id, Msg*); static void msgset_push (MsgSet*,Msg); struct Handle { int fd; /* connection to wily */ char err[MAXERRMSG]; Id id; /* of last message */ /* temporary buffer for packing and unpacking messages */ char *buf; int n; int alloced; MsgQ event; MsgSet reply; }; static char* rpc (Handle*, Msg*); static int getbytes (Handle*); static char* simple(Handle*h, Mtype t, Id w, Range r, char *s,ushort); Range nr = {0,0}; /* PRE: fd an open connection to wily * POST: return a handle ready for RPCs */ Handle* rpc_init(int fd) { Handle *h = NEW(Handle); assert(fd>=0); h->fd = fd; h->alloced = 128; h->buf = salloc(h->alloced); h->n = 0; h->id = 0; msgset_init(&h->reply); msgq_init(&h->event); return h; } int rpc_fileno(Handle *h) { return h->fd; } Bool rpc_isconnected(Handle*h) { return h->fd>=0; } void rpc_freehandle(Handle*h) { free(h->buf); close(h->fd); free(h); } Bool rpc_wouldblock(Handle*h) { return msgq_empty(&h->event); } /* Get the next event pending on 'h', store it in 'm' * Return 0 for success, -1 if we've lost the connection. */ int rpc_event(Handle*h, Msg *m) { while (msgq_empty(&h->event)) if(getbytes(h)) return -1; *m = msgq_pop(&h->event); return 0; } /* Bounce an event back: we didn't want it. */ int rpc_bounce(Handle*h, Msg *m) { int size; if (m->t > WEfencepost) { fprintf(stderr,"can only bounce events\n"); return -1; } /* send the request */ size = msg_size(m); if (h->n + size > h->alloced) { h->alloced = h->n + size + 128; h->buf = srealloc(h->buf, h->alloced); } msg_flatten(m, h->buf + h->n); if(write(h->fd, h->buf+h->n, size) != size){ perror ("rpc write"); close(h->fd); h->fd = -1; return -1; } return 0; } char* rpc_fill(Handle*h, Msg *msg, Mtype t, Id w, Range r, ushort flag, char*s) { msg_fill(msg, t, w, r, flag, s); return rpc(h, msg); } /* Each of the rpc_* functions returns either 0 for success, * or an error message in static storage, which can be used until * you call another function using the same handle. */ char* rpc_list(Handle*h, char **bufptr) { Msg m; char *err; if (!(err=rpc_fill(h,&m, WMlist, 0, nr, 0, 0))) *bufptr = m.s; return err; } char* rpc_new(Handle*h, char *s, Id*id, ushort backup ) { Msg m; char *err; if (!(err=rpc_fill(h,&m, WMnew, 0, nr, backup, s))) { *id = m.w; free(m.s); } return err; } char* rpc_read(Handle*h, Id w, Range r, char*buf) { Msg m; char *err; assert(ROK(r)); if (!(err=rpc_fill(h,&m, WMread, w, r, 0, 0))) { strcpy(buf, m.s); free(m.s); } return err; } char* rpc_goto(Handle*h, Id *w, Range*r, char*s, Bool setdot) { Msg m; char *err; if (!(err=rpc_fill(h,&m, WMgoto, *w, *r, setdot, s))) { *w = m.w; *r = m.r; free(m.s); } return err; } char* rpc_getname(Handle*h, Id w, char**s){ Msg m; char *err; if (!(err=rpc_fill(h,&m, WMgetname, w, nr, 0,0))) { *s = m.s; /* let the client free it later */ } return err; } char* rpc_gettools(Handle*h, Id w, char**s) { Msg m; char *err; if (!(err=rpc_fill(h,&m, WMgettools, w, nr, 0,0))) { *s = m.s; /* let the client free it later */ } return err; } char* rpc_replace(Handle*h, Id w, Range r, char*s) { assert(ROK(r)); return simple(h, WMreplace, w, r, s, 0); } char* rpc_exec(Handle*h, Id w, char *s) { return simple(h, WMexec, w, nr, s, 0); } char* rpc_attach(Handle*h, Id w, ushort mask) { return simple(h, WMattach, w, nr, 0, mask); } char* rpc_setname(Handle*h, Id w, char *name) { return simple(h, WMsetname, w, nr, name, 0); } char* rpc_settools(Handle*h, Id w, char *name) { return simple(h, WMsettools, w, nr, name, 0); } /************************************************************/ /* rpc(h, &m) if successful, return 0, fill in m, m->s will need to be freed if not, return a static string, m contains garbage. */ static char* rpc(Handle*h, Msg*m) { int size; if(h->fd<0) return "handle not connected"; m->m = h->id++; /* message sequence */ size = msg_size(m); if (h->n + size > h->alloced) { h->alloced = h->n + size + 128; h->buf = srealloc(h->buf, h->alloced); } /* send the request */ msg_flatten(m, h->buf + h->n); if(write(h->fd, h->buf+h->n, size) != size){ perror ("rpc write"); close(h->fd); h->fd = -1; } /* wait for the reply */ while (!msgset_find(&h->reply, m->m, m)) if(getbytes(h)) return "lost connection"; if (m->t == WRerror) { strcpy(h->err, m->s); free(m->s); return h->err; } else return 0; } /* RPC which doesn't need to return any more information * than an error message. */ static char* simple(Handle*h, Mtype t, Id w, Range r, char *s, ushort flag) { char *err; Msg m; m.t = t; m.w = w; m.r = r; m.s = s; m.flag = flag; if (!(err=rpc(h,&m))) free(m.s); return err; } /* Read from the fd, form some messages, store them. * Returns 0 for success, -1 if we've lost the connection somehow. */ static int getbytes (Handle*h) { int left,nread; char *ptr; int size; /* try to fill our buffer */ if(h->fd<0) return -1; /* not connected */ if ((nread = read(h->fd, h->buf + h->n, h->alloced - h->n)) < 1) return -1; h->n += nread; /* interpret any full messages */ ptr = h->buf; left = h->n; while(FULLMSG(ptr, left)) { Msg m; size = msg_bufsize(ptr); /* eat one message */ if(msg_init(&m, ptr)) { perror("msg_init failed: closing connection"); close(h->fd); h->fd = -1; /* poison */ return -1; } ptr += size; left -= size; m.s = strdup(m.s); /* put it somewhere */ if (m.t < WEfencepost) { MsgQ *q = &h->event; if (msgq_full(q)) { fprintf(stderr, "rpc event queue overflow\n"); free(m.s); } else { msgq_push(q,m); } } else { MsgSet *set= &h->reply; if (msgset_full(set)) { fprintf(stderr, "rpc reply set overflow\n"); free(m.s); } else { msgset_push(set,m); } } } /* move any partial messages to front of buffer */ if (left && left != h->n) memmove(h->buf, ptr, left); h->n = left; /* make sure we have room for the next message */ if (left > HSIZE) { size = msg_bufsize(h->buf); if (size > h->alloced) { h->alloced = size + 128; h->buf = srealloc(h->buf, h->alloced); } } return 0; } /********************************** MsgQ functions ***********************************/ static void msgq_init(MsgQ *q) { q->read= q->write = 0; } static Bool msgq_full(MsgQ *q) { return (q->write +1) % Qmax == q->read; } static Bool msgq_empty(MsgQ *q) { return q->write == q->read; } static Msg msgq_pop(MsgQ *q) { Msg m; assert(!msgq_empty(q)); m = q->msg[q->read]; q->read = (q->read+1) % Qmax; return m; } static void msgq_push(MsgQ *q, Msg m) { assert(!msgq_full(q)); q->msg[q->write] = m; q->write = (q->write+1) % Qmax; } /********************************** MsgSet functions ***********************************/ static void msgset_init(MsgSet *s) { int j; for(j=0; j< Qmax; j++) s->inuse[j]=false; s->n = 0; } static void msgset_push(MsgSet *s, Msg m) { int j; assert(!msgset_full(s)); for(j=0; j< Qmax; j++) if (!s->inuse[j]) { s->msg[j] = m; s->inuse[j] = true; s->n++; return; } assert(false); } static Bool msgset_find(MsgSet *s, Id m, Msg *msg) { int j; if(!s->n) return false; for(j=0; j< Qmax; j++) if (s->inuse[j] && s->msg[j].m ==m){ s->inuse[j] = false; s->n--; *msg = s->msg[j]; return true; } return false; } static Bool msgset_full(MsgSet*s) { return s->n == Qmax; } wily-0.13.42/libmsg/connect.c000064402366570000012000000074041033320152300155530ustar00ozstaff00004330000002#include #include #include #include #include #include #include /* for MAXPATHLEN */ #include #include #include #include #include #include /* ../include/msg.h */ enum { MAXTRIES = 10 /* number of names to try for fifo */ }; static int findname(char *); static void addenv(char*key, char *val); static char *myfifo=0; /* Return file descriptor open for reading connection requests, * returns negative value for failure. * Sets environment variable WILYFIFO */ int wilyfifolisten(void) { int fd=-1; char name[MAXPATHLEN]; if (findname(name)) return -1; if(mkfifo(name, 0600)) { fprintf(stderr, "try\n\trm %s\n", name); perror(name); return -1; } fd = open(name, O_RDONLY|O_NONBLOCK); if (fd<0) { perror(name); return -1; } /* dummy fd to hold the read fd open */ if (open(name, O_WRONLY) < 0) { perror(name); return -1; } addenv(WILYFIFO, name); myfifo = strdup(name); return fd; } /* remove the fifo if we can. */ void fifo_cleanup(void) { if(myfifo) if (unlink(myfifo)) perror(myfifo); } /* Return file descriptor open for write to wily, or a negative number. */ int wilyfifotalk(void) { char name[MAXPATHLEN]; if(findname(name)) return -1; return open(name, O_WRONLY); } /* Return file descriptor connected to wily, or <0 on failure. * Opens a UNIX-domain socket for listening, connects to wily * and sends it the name of the socket, then accepts a connection * on our listening socket. * * Returns -1 for failure. * * TODO - this is where we could compare version numbers, * to make sure both client and server are speaking the same * language. */ int client_connect(void) { int s , fd, size; struct sockaddr_un addr; int len; int nwritten; char *path; /* create a socket */ if (! (s= socket(AF_UNIX, SOCK_STREAM, 0))) return -1; /* bind it to a unix-domain at a temporary address */ addr.sun_family = AF_UNIX; tmpnam(addr.sun_path); path = strdup(addr.sun_path); len = strlen(addr.sun_path); if (bind(s, (struct sockaddr *) &addr, sizeof addr) < 0){ perror("bind"); return -1; } listen(s, 1); /* Get ready for wily to talk to us */ fd = wilyfifotalk(); /* fifo to wily */ if(fd<0) return -1; nwritten = write(fd, addr.sun_path, len); close(fd); if(nwritten !=len){ perror("write to wily"); return -1; } size = sizeof(addr); fd = accept(s, (struct sockaddr *) &addr, &size); close(s); if(unlink(path)) perror(path); free(path); return fd; } /* Given 'addrname' of length 'n', (from some client), connect to it, * and return the file descriptor, or -1 */ int wily_connect(char*addrname, int n) { int s; struct sockaddr_un addr; /* create a socket */ s= socket(AF_UNIX, SOCK_STREAM, 0); if (s<0) return -1; addr.sun_family = AF_UNIX; memcpy(addr.sun_path, addrname, n); addr.sun_path[n]='\0'; if( connect(s, (struct sockaddr*)&addr, sizeof addr)) return -1; return s; } /* Find a name to use as a wily fifo. Use $WILYFIFO if * set, otherwise use wily$USER$DISPLAY in $TMPDIR or /tmp, * * Copy the name into buf. Return 0 for success. */ static int findname(char *buf) { char *name = 0; struct passwd *pw; char *disp; char *dir; if ((name = getenv(WILYFIFO))){ strcpy(buf, name); return 0; } if(!(pw = getpwuid( getuid() )) ) { perror("getpwuid or getuid"); return -1; } if(!(disp = getenv("DISPLAY"))) { fprintf(stderr, "$DISPLAY not set"); return -1; } if(!(dir = getenv("TMPDIR"))) { dir = "/tmp"; } sprintf(buf, "%s/wily%s%s", dir, pw->pw_name, disp); return 0; } static void addenv(char*key, char *val) { char *buf; buf = salloc(strlen(key) + strlen(val) + 2); sprintf(buf, "%s=%s", key, val); putenv(buf); } wily-0.13.42/libmsg/Makefile.in000064402366570000012000000003551033320152300160210ustar00ozstaff00004330000002SHELL=/bin/sh srcdir=@srcdir@ VPATH=@srcdir@ CC=@CC@ RANLIB=@RANLIB@ INCLUDES=$(srcdir)/../include CFLAGS=@CFLAGS@ -I.. -I$(INCLUDES) LIB=libmsg.a OBJS= connect.o msg.o util.o rpc.o include $(INCLUDES)/Makelib $(OBJS): $(INCLUDES)/msg.h wily-0.13.42/libmsg/util.c000064402366570000012000000033741033320152300151010ustar00ozstaff00004330000002#include #include #include #include #include #include /* ../include/msg.h */ ulong ladjust(ulong val, Range r, int len) { assert(ROK(r)); if( val>r.p1) return val + len - RLEN(r); else if ( val>r.p0) return r.p0; else return val; } ulong radjust(ulong val, Range r, int len) { assert(ROK(r)); if( val >r.p1) return val + len - RLEN(r); else if ( val>=r.p0) return r.p0 + len; else return val; } /* Clip a value to be between two other values */ int clip(int orig, int low, int high) { assert(low<= high); if(orighigh) orig=high; return orig; } Range rclip(Range r, Range c) { return range( pclipr(r.p0, c), pclipr(r.p1, c)); } ulong pclipr(ulong p, Range r) { return clip(p, r.p0, r.p1); } Range intersect (Range a, Range b) { return range(MAX(a.p0, b.p0), MIN(a.p1, b.p1)); } Range range(ulong p0, ulong p1) { Range r; r.p0 = p0; r.p1 = p1; return r; } Range maybereverserange(ulong p0, ulong p1) { return (p0 <= p1)? range(p0,p1) : range(p1,p0); } /* "Safe" realloc. Currently all it does is crash cleanly * if it runs out of memory. */ void * srealloc(void *orig, int size) { void *p; assert(size>=0); size = size? size: 2; p = orig? realloc(orig, size) : malloc(size); if (!p){ perror("alloc"); abort(); } return p; } /* "Safe" alloc. Currently all it does is crash cleanly * if it runs out of memory. */ void * salloc(int size) { void *p; assert(size>=0); /* make sure we'll have something to free */ size = size? size : sizeof(int); p = malloc(size); if (!p) abort(); /* todo */ return p; } /* Print to stderr */ void eprintf(char *fmt, ...) { va_list args; va_start(args,fmt); vfprintf(stderr, fmt, args); } wily-0.13.42/libmsg/Makefile000064402366570000012000000004121041526267400154250ustar00ozstaff00004330000002# Generated automatically from Makefile.in by configure. SHELL=/bin/sh srcdir=. CC=gcc RANLIB=ranlib INCLUDES=$(srcdir)/../include CFLAGS=-g -O -I.. -I$(INCLUDES) LIB=libmsg.a OBJS= connect.o msg.o util.o rpc.o include $(INCLUDES)/Makelib $(OBJS): $(INCLUDES)/msg.h wily-0.13.42/config.h.in000064402366570000012000000044321033320152300145220ustar00ozstaff00004330000002/* config.h.in. Generated automatically from configure.in by autoheader. */ #undef HAVE_ULONG #undef HAVE_USHORT #undef HAVE_UINT #undef HAVE_UCHAR #undef HAVE_CADDR_T /* Defined if sprintf returns char * instead of int */ #undef BROKEN_SPRINTF /* Define to empty if the keyword does not work. */ #undef const /* Define if you don't have vprintf but do have _doprnt. */ #undef HAVE_DOPRNT /* Define if you have that is POSIX.1 compatible. */ #undef HAVE_SYS_WAIT_H /* Define if you have the vprintf function. */ #undef HAVE_VPRINTF /* Define as the return type of signal handlers (int or void). */ #undef RETSIGTYPE /* Define to `unsigned' if doesn't define. */ #undef size_t /* Define if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define if you can safely include both and . */ #undef TIME_WITH_SYS_TIME /* Define if the X Window System is missing or not being used. */ #undef X_DISPLAY_MISSING /* Define if you have the memmove function. */ #undef HAVE_MEMMOVE /* Define if you have the remove function. */ #undef HAVE_REMOVE /* Define if you have the strerror function. */ #undef HAVE_STRERROR /* Define if you have the header file. */ #undef HAVE_DIRENT_H /* Define if you have the header file. */ #undef HAVE_FCNTL_H /* Define if you have the header file. */ #undef HAVE_LIMITS_H /* Define if you have the header file. */ #undef HAVE_MALLOC_H /* Define if you have the header file. */ #undef HAVE_NDIR_H /* Define if you have the header file. */ #undef HAVE_STDARG_H /* Define if you have the header file. */ #undef HAVE_STDLIB_H /* Define if you have the header file. */ #undef HAVE_SYS_DIR_H /* Define if you have the header file. */ #undef HAVE_SYS_NDIR_H /* Define if you have the header file. */ #undef HAVE_SYS_SELECT_H /* Define if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define if you have the header file. */ #undef HAVE_UNISTD_H /* Define if you have the m library (-lm). */ #undef HAVE_LIBM /* Define if you have the nsl library (-lnsl). */ #undef HAVE_LIBNSL /* Define if you have the socket library (-lsocket). */ #undef HAVE_LIBSOCKET wily-0.13.42/.wily.prcs_aux000064402366570000012000000536621033320152300153200ustar00ozstaff00004330000002;; This file is automatically generated, editing may cause PRCS to do ;; REALLY bad things. (Created-By-Prcs-Version 1 2 1) (wily/env.c 2280 862661013 d/4_env.c 1.2) (Doc/pythonpaper.html 21296 878734159 c/34_pythonpape 1.2) (libXg/texture.c 1032 821786488 b/2_texture.c 1.1) (tools/old/wilytoys/reader2/nntp.h 604 826535146 f/19_nntp.h 1.1) (tools/win/wgoto.1 1190 849509053 g/0_wgoto.1 1.1) (Doc/sam/balloc.3 3581 821786484 h/20_balloc.3 1.1) (libframe/frselect.c 1985 821786489 38_frselect.c 1.1) (tools/old/edit/c.c 1953 814094625 g/45_c.c 1.1) (libmsg/util.c 1656 861776089 2_util.c 1.1) (acconfig.h 177 815447372 29_acconfig.h 1.1) (tools/win/acconfig.h 177 827851486 e/27_acconfig.h 1.1) (Doc/sam/font.4 1944 821786485 h/15_font.4 1.1) (Doc/sam/rune.3 2629 821786485 h/0_rune.3 1.1) (Doc/sam/sam.1 20162 821786484 h/24_sam.1 1.1) (Doc/sam/frame.3 6336 821786485 h/14_frame.3 1.1) (tools/old/sh/README 353 815816105 g/18_README 1.1) (misc/wily.xpm 2690 819260437 47_wily.xpm 1.1) (tools/tcl/wlist 155 847842152 e/14_wlist 1.1) (libXg/ellipse.c 439 821786487 b/22_ellipse.c 1.1) (tools/old/wilytoys/toys/html2wily 1590 826654813 e/51_html2wily 1.1) (Doc/announce/1996.11 2520 848558814 c/4_1996.11 1.1) (tools/old/wilytoys/toys/fonts.alias 350 826656086 e/41_fonts.alia 1.1) (tools/old/edit/patch 3273 814094626 g/34_patch 1.1) (tools/shell/Wins.c 576 871289140 g/0_Wins.c 1.1) (tools/win/Man.rc 249 849509053 h/2_Man.rc 1.1) (wily/vshow.c 4465 862662922 c/44_vshow.c 1.3) (tools/old/wilytoys/man 136 826654933 g/6_man 1.1) (tools/old/reader/Makefile.in 595 816600359 g/23_Makefile.i 1.1) (libmsg/msg.c 4504 849429656 4_msg.c 1.1) (misc/Wily.ad 225 816770462 44_Wily.ad 1.1) (tools/old/wilytoys/smk.9.font 2011 826655241 g/0_smk.9.font 1.1) (tools/old/wilytoys/reader/mbox.c 8666 817721232 f/44_mbox.c 1.1) (sam/doc/graphics.3 10644 821786485 14_graphics.3 1.1) (configure.in 938 862640844 5_configure. 1.2) (tools/tools-dev/Makefile.in 1820 849509053 e/2_Makefile.i 1.1) (tools/old/wilytoys/reader/Credits 147 817721819 f/37_Credits 1.1) (Doc/download.html 708 849229306 c/12_download.h 1.1) (tools/tcl/wtcl.c 460 847842153 e/11_wtcl.c 1.1) (tools/tools-dev/Tag.1 1744 849509053 d/42_Tag.1 1.1) (tools/tcl/wnew 195 847842152 e/12_wnew 1.1) (Doc/LSM 1142 848559407 c/36_LSM 1.1) (libXg/arc.c 950 821786486 b/36_arc.c 1.1) (libXg/disc.c 402 821786487 b/23_disc.c 1.1) (Doc/sam/bitblt.3 7047 821786484 h/19_bitblt.3 1.1) (tools/old/wilytoys/reader/mbox.h 1840 817721233 f/43_mbox.h 1.1) (tools/old/wilytoys/reader/membuf.c 2719 817580770 f/35_membuf.c 1.1) (wily/exec.c 8100 862661465 c/49_exec.c 1.2) (tools/win/config.status 3453 866003440 h/25_config.sta 1.1) (wily/data.c 2900 863853324 d/34_data.c 1.3) (tools/tcl/wtcl.h 111 847842153 e/10_wtcl.h 1.1) (wily/scroll.c 2709 862661267 c/40_scroll.c 1.2) (tools/old/wilytoys/toys/fetchurl 517 826654813 f/1_fetchurl 1.1) (tools/old/wilytoys/toys/parse-html.pl 9000 826654814 e/49_parse-html 1.1) (tools/win/configure 31525 866003431 e/30_configure 1.3) (tools/old/wilytoys/reader/membuf.h 292 817580658 f/34_membuf.h 1.1) (tools/README 277 862642419 g/46_README 1.2) (sam/doc/keyboard.4 4066 821786485 13_keyboard.4 1.1) (libXg/polysegment.c 582 821786487 b/11_polysegmen 1.1) (libframe/frptofchar.c 2008 821786489 34_frptofchar 1.1) (tools/quanstro/wreplace.c 2070 830811923 e/34_wreplace.c 1.1) (wily/data.h 2043 862660834 c/46_data.h 1.2) (wily/text2.c 7330 862662654 d/8_text2.c 1.4) (Doc/Tcl.txt 1752 848384420 c/18_Tcl.txt 1.1) (libframe/frinsert.c 5722 861772963 39_frinsert.c 1.1) (sam/doc/add.3 3758 821786484 22_add.3 1.1) (README 2118 849663845 h/1_README 1.1) (tools/tcl/wtools 205 847842154 e/7_wtools 1.1) (tools/shell/Wgoto.c 830 871290342 d/0_Wgoto.c 1.1) (tools/shell/Makefile 444 871290661 f/0_Makefile 1.1) (tools/old/reader/README 5559 816426149 g/31_README 1.1) (wily/tile.c 9914 876051095 d/1_tile.c 1.6) (wily/msg.c 7520 862660995 c/45_msg.c 1.2) (include/Makelib 160 850295845 b/44_Makelib 1.1) (libXg/strwidth.c 460 821786488 b/3_strwidth.c 1.1) (libXg/rdbitmap.c 1496 821786487 b/10_rdbitmap.c 1.1) (wily/file.c 4765 876047314 c/42_file.c 1.5) (wily/tile.h 2306 866800259 d/21_tile.h 1.4) (sam/doc/bitmap.6 2711 821786484 19_bitmap.6 1.1) (Doc/hack.html 1872 849179743 c/35_hack.html 1.1) (tools/old/edit/x.c 1688 814094626 g/35_x.c 1.1) (libXg/cursorset.c 339 821786487 b/25_cursorset. 1.1) (tools/tools-dev/mkinstalldirs 649 849509053 e/0_mkinstalld 1.1) (misc/fixed.9.font 1937 816770511 46_fixed.9.fo 1.1) (sam/doc/rgbpix.3 2593 821786485 11_rgbpix.3 1.1) (tools/old/sh/Makefile.in 542 817703130 g/16_Makefile.i 1.1) (tools/old/reader/utils.c 298 816338964 g/20_utils.c 1.1) (Makefile.in 563 862641437 48_Makefile.i 1.2) (tools/win/win.c 13658 849509053 e/32_win.c 1.2) (tools/win/config.cache 1532 866003439 h/26_config.cac 1.1) (sam/doc/regexp.6 2520 821786485 12_regexp.6 1.1) (libXg/xtbinit.c 18256 832269946 51_xtbinit.c 1.1) (Doc/old/wily.html 19749 878734546 c/29_wily.html 1.2) (wily/undo.c 6893 862661032 c/37_undo.c 1.2) (Doc/tute/send_to_gary 75 817093094 c/21_send_to_ga 1.1) (tools/old/wilytoys/reader2/proto.h 1717 826535148 f/13_proto.h 1.1) (.exclude 42 850294795 h/0_.exclude 1.1) (tools/tools-dev/Tag.rc 506 849509053 d/48_Tag.rc 1.1) (Doc/sam/regexp.6 2520 821786485 h/11_regexp.6 1.1) (tools/tools-dev/wreplace.c 3562 849509053 d/49_wreplace.c 1.1) (wily/label.c 1713 862660950 c/38_label.c 1.2) (tools/win/README 1032 849509053 h/9_README 1.1) (Doc/demo.utf 333 829406030 c/17_demo.utf 1.1) (Doc/announce/1995.8 921 827853814 c/3_1995.8 1.1) (wily/textpage.c 3742 866799571 b/0_textpage.c 1.1) (wily/path.c 2213 867660568 d/35_path.c 1.4) (tools/old/reader/mail.c 10738 816340790 g/28_mail.c 1.1) (tools/tools-dev/wgoto.c 1893 849509053 d/50_wgoto.c 1.1) (Doc/sam/version 47 821786493 d/0_version 1.1) (libXg/gcs.c 9054 821786487 b/20_gcs.c 1.1) (libXg/ldconvert.c 1143 821786487 b/16_ldconvert. 1.1) (libXg/GwinP.h 1085 821861442 b/37_GwinP.h 1.1) (libframe/frdelete.c 2610 861773219 40_frdelete.c 1.1) (tools/win/Makefile.in 1820 849509053 e/28_Makefile.i 1.2) (libXg/wrbitmap.c 1346 821786488 b/1_wrbitmap.c 1.1) (tools/old/wilytoys/reader2/utils.c 344 826535146 f/21_utils.c 1.1) (tools/tcl/wname 203 847842152 e/13_wname 1.1) (Doc/sam/boilerplate 712 821786493 e/0_boilerplat 1.1) (tools/old/reader/mail.h 1210 816338955 g/27_mail.h 1.1) (tools/python/Makefile 495 862643267 g/50_Makefile 1.2) (libXg/bscreenrect.c 348 821786487 b/30_bscreenrec 1.1) (tools/shell/Wexec.c 680 871289844 e/0_Wexec.c 1.1) (tools/old/wilytoys/reader2/README 8639 826535145 f/26_README 1.1) (Doc/old/python.sgml 3858 829476449 c/26_python.sgm 1.1) (tools/win/Tag.rc 506 849509053 h/4_Tag.rc 1.1) (libframe/frutil.c 1901 821786489 32_frutil.c 1.1) (misc/wily2.xpm 2176 846915374 43_wily2.xpm 1.1) (tools/python/Makefile.in 487 862643344 c/0_Makefile.i 1.1) (tools/tcl/Makefile 506 847842149 e/18_Makefile 1.1) (tools/win/config.h.in 2120 827851332 e/31_config.h.i 1.1) (tools/tcl/wily.c 10232 847842151 e/15_wily.c 1.1) (libXg/clipline.c 3664 821786487 b/28_clipline.c 1.1) (Doc/AcmeVsWily.html 2869 848221251 c/6_AcmeVsWily 1.1) (tools/old/wilytoys/reader2/solaris.c 2224 826535147 f/15_solaris.c 1.1) (wily/click.c 3401 862660621 c/41_click.c 1.2) (tools/old/wilytoys/reader2/Credits 147 817721819 f/17_Credits 1.1) (tools/old/wilytoys/reader/mail.c 13700 817721230 f/46_mail.c 1.1) (tools/old/reader/headers.h 282 816601340 g/29_headers.h 1.1) (Doc/sam/Sam.ad 104 821786484 h/22_Sam.ad 1.1) (Doc/old/auug.tex 12496 833798562 c/33_auug.tex 1.1) (tools/old/wilytoys/fetchurl 517 826654813 g/11_fetchurl 1.1) (Doc/sam/keyboard.4 4066 821786485 h/12_keyboard.4 1.1) (wily/win.c 1494 877241695 d/18_win.c 1.4) (libXg/Gwin.h 1185 823599321 b/38_Gwin.h 1.1) (tools/old/wilytoys/reader2/news.c 16929 826535146 f/22_news.c 1.1) (wily/include.c 1928 862661514 d/6_include.c 1.2) (tools/old/wilytoys/reader/mail.h 1689 817721231 f/45_mail.h 1.1) (libXg/getrect.c 1618 821786487 b/19_getrect.c 1.1) (libXg/circle.c 404 821786487 b/29_circle.c 1.1) (tools/old/wilytoys/toys/html-ascii.pl 6588 826654813 f/0_html-ascii 1.1) (tools/old/wilytoys/reader/Makefile 684 817580034 f/41_Makefile 1.1) (tools/old/wilytoys/reader2/news.h 3581 826535146 f/20_news.h 1.1) (wily/point.c 1523 862661228 d/29_point.c 1.2) (libXg/bitblt.c 1416 821786486 b/33_bitblt.c 1.1) (libXg/rune.c 2770 821788685 50_rune.c 1.1) (tools/old/wilytoys/diff 199 826654964 g/4_diff 1.1) (Doc/tute/findword 103 817093065 c/22_findword 1.1) (libframe/frbox.c 2943 821786905 37_frbox.c 1.1) (libXg/rectclip.c 605 821786488 b/7_rectclip.c 1.1) (Doc/credits.html 2691 890011849 c/8_credits.ht 1.2) (tools/tools-dev/win.1 4143 849509053 d/45_win.1 1.1) (tools/win/aclocal.m4 465 827851486 e/26_aclocal.m4 1.1) (tools/old/edit/change.c 2705 814094625 g/44_change.c 1.1) (tools/old/sh/rpc.c 803 815581101 g/15_rpc.c 1.1) (sam/doc/event.3 5872 821786485 17_event.3 1.1) (tools/win/install-sh 4771 849509053 e/29_install-sh 1.2) (tools/old/wilytoys/reader2/newsheaders.h 159 826535147 f/9_newsheader 1.1) (libXg/copymasked.c 1108 821786487 b/26_copymasked 1.1) (wily/place.c 1758 862660980 c/47_place.c 1.2) (tools/old/wilytoys/toys/Makefile 260 826656874 f/4_Makefile 1.1) (sam/README 15426 821786483 26_README 1.1) (sam/doc/bitblt.3 7047 821786484 20_bitblt.3 1.1) (Doc/C.html 11957 876045098 c/5_C.html 1.2) (tools/quanstro/wcat.c 2463 830811922 e/37_wcat.c 1.1) (tools/old/edit/change.h 0 814094625 g/43_change.h 1.1) (libXg/font.c 1779 821786487 b/21_font.c 1.1) (include/libc.h 1438 821789634 b/42_libc.h 1.1) (tools/old/wilytoys/reader/README 3205 817721243 f/49_README 1.1) (tools/old/wilytoys/toys/bold.c 1280 826654768 f/3_bold.c 1.1) (tools/win/INSTALL 7462 849509053 h/8_INSTALL 1.1) (libXg/test.c 5881 850293980 b/4_test.c 1.1) (tools/old/wilytoys/reader/reader.c 16924 817721237 f/40_reader.c 1.1) (Doc/cartoon.gif 20583 832581058 c/15_cartoon.gi 1.1) (tools/old/wilytoys/reader/solaris.c 1952 817721240 f/36_solaris.c 1.1) (wily/MANIFEST 2048 850082990 d/26_MANIFEST 1.1) (tools/shell/README 518 871291007 h/0_README 1.1) (wily/col.c 943 866998538 d/0_col.c 1.4) (Doc/sam/event.3 5872 821786485 h/16_event.3 1.1) (tools/old/wilytoys/toys/http 480 826654813 e/50_http 1.1) (tools/tools-dev/INSTALL 7462 849509053 e/5_INSTALL 1.1) (Doc/sam/add.3 3758 821786484 h/21_add.3 1.1) (tools/old/wilytoys/reader2/post.c 7751 826535149 f/7_post.c 1.1) (tools/old/wilytoys/reader/reader.h 1376 817721238 f/39_reader.h 1.1) (libframe/frinit.c 811 847619873 35_frinit.c 1.1) (tools/win/win 99512 849447671 e/20_win 1.1) (libmsg/rpc.c 8104 876045082 3_rpc.c 1.2) (tools/old/wilytoys/wcat.c 886 826654768 g/12_wcat.c 1.1) (wily/keyboard.c 3150 862662499 d/9_keyboard.c 1.3) (tools/old/wilytoys/reader2/headers.h 711 826535144 f/30_headers.h 1.1) (Doc/old/msg.sgml 10805 830862844 c/27_msg.sgml 1.1) (tools/old/wilytoys/toys/man 136 826654933 e/48_man 1.1) (tools/old/wilytoys/reader2/post.h 860 826535149 f/6_post.h 1.1) (wily/util.c 8187 871284799 d/10_util.c 1.3) (tools/old/wilytoys/reader2/getmsg.c 563 826535144 f/31_getmsg.c 1.1) (tools/old/reader/proto.h 1057 816338959 g/24_proto.h 1.1) (Doc/perl.txt 16417 848221025 b/48_perl.txt 1.1) (aclocal.m4 465 814267500 28_aclocal.m4 1.1) (wily/adjust.c 3009 876053862 d/20_adjust.c 1.5) (Doc/sam/rgbpix.3 2593 821786485 h/10_rgbpix.3 1.1) (tools/old/wilytoys/http 480 826654813 g/8_http 1.1) (wily/line.c 2310 862662943 c/39_line.c 1.3) (tools/old/wilytoys/reader2/mail.c 19965 826535144 f/32_mail.c 1.1) (libXg/menuhit.c 6117 821793266 b/13_menuhit.c 1.1) (Doc/sam/bitmap.6 2711 821786484 h/18_bitmap.6 1.1) (Doc/sam/utf.4 2723 821786485 g/0_utf.4 1.1) (sam/doc/rune.3 2629 821786485 10_rune.3 1.1) (tools/tcl/wattach 281 847842150 e/16_wattach 1.1) (sam/doc/utf.4 2723 821786485 9_utf.4 1.1) (wily/cursor.c 1172 862661524 d/16_cursor.c 1.2) (tools/tcl/wtk.c 530 847842153 e/9_wtk.c 1.1) (sam/doc/cachechars.3 5708 821786485 18_cachechars 1.1) (Doc/sam/cachechars.3 5708 821786485 h/17_cachechars 1.1) (tools/old/wilytoys/reader2/mail.h 1743 826535144 f/29_mail.h 1.1) (libXg/Makefile.in 627 850294313 b/39_Makefile.i 1.1) (Doc/winmanager.html 1472 862558062 c/0_winmanager 1.1) (tools/old/wilytoys/toys/make 176 826654964 e/47_make 1.1) (include/frame.h 2173 847619880 b/43_frame.h 1.1) (tools/old/wilytoys/toys/tformat.pl 3170 826655086 e/45_tformat.pl 1.1) (libXg/latin1.c 7650 821786487 b/17_latin1.c 1.1) (libXg/gwin.c 13008 844145868 b/18_gwin.c 1.1) (wily/select.c 6344 871452861 d/13_select.c 1.5) (Doc/TODO 1376 876047927 c/9_TODO 1.8) (tools/old/reader/solaris.c 1533 816338963 g/19_solaris.c 1.1) (tools/old/wilytoys/reader2/mailheaders.h 141 826535147 f/10_mailheader 1.1) (INSTALL 7606 849663821 49_INSTALL 1.1) (libXg/wrbitmapfile.c 1089 821786488 b/0_wrbitmapfi 1.1) (tools/old/edit/Makefile 608 814094626 g/33_Makefile 1.1) (Doc/sam/sam.tut.ms 40250 821786484 h/23_sam.tut.ms 1.1) (sam/doc/sam.1 20162 821786484 25_sam.1 1.1) (tools/tools-dev/confdefs.h 1 849515863 d/38_confdefs.h 1.1) (include/libg.h 7511 890012498 b/41_libg.h 1.1.1.1) (tools/old/edit/e.c 2764 814094625 g/42_e.c 1.1) (tools/old/wilytoys/toys/smk.9.font 2011 826655241 e/42_smk.9.font 1.1) (Artistic 6112 839557540 42_Artistic 1.1) (tools/tools-dev/wreplace.1 1525 849509053 d/43_wreplace.1 1.1) (wily/builtins.c 5957 862660714 d/14_builtins.c 1.2) (tools/old/wilytoys/bold.c 1280 826654768 g/13_bold.c 1.1) (libXg/string.c 1093 821786488 b/5_string.c 1.1) (tools/python/testwily.py 1061 848324946 g/47_testwily.p 1.1) (tools/old/wilytoys/parse-html.pl 9000 826654814 g/7_parse-html 1.1) (tools/tools-dev/wgoto.1 1190 849509053 d/44_wgoto.1 1.1) (tools/old/reader/mbox.c 6992 816338957 g/26_mbox.c 1.1) (misc/prop.9.font 2001 818000315 45_prop.9.fon 1.1) (libXg/libgint.h 2777 850293969 b/14_libgint.h 1.1) (Doc/old/wily.bib 5812 829595748 c/30_wily.bib 1.1) (tools/old/wilytoys/fixed.9.font 1937 826655241 g/2_fixed.9.fo 1.1) (libXg/bitbltclip.c 1281 821786487 b/32_bitbltclip 1.1) (Doc/thumb.gif 1238 848124223 b/50_thumb.gif 1.1) (libXg/segment.c 435 821786488 b/6_segment.c 1.1) (tools/old/reader/reader.c 13931 816338961 g/22_reader.c 1.1) (tools/old/wilytoys/reader2/addr.c 2981 826535149 f/5_addr.c 1.1) (tools/tools-dev/win.c 13658 849509053 d/51_win.c 1.1) (Doc/fonts 1377 858822693 b/46_fonts 1.1) (tools/old/reader/mbox.h 1751 816338958 g/25_mbox.h 1.1) (wily/tagmatch.c 2567 862661295 d/5_tagmatch.c 1.2) (wily/.wily.prcs_aux 169 866799654 c/0_.wily.prcs 1.1) (Doc/sam/README 15426 821786483 f/0_README 1.1) (libframe/misc.c 1679 821787371 31_misc.c 1.1) (libXg/arith.c 2400 821786486 b/35_arith.c 1.1) (libXg/rdfontfile.c 2221 861774051 b/8_rdfontfile 1.1) (tools/old/reader/reader.h 1168 816338962 g/21_reader.h 1.1) (tools/tools-dev/README 1032 849509053 e/6_README 1.1) (libXg/border.c 900 821786487 b/31_border.c 1.1) (wily/Makefile.in 1598 866800686 d/12_Makefile.i 1.2) (sam/doc/balloc.3 3581 821786484 21_balloc.3 1.1) (tools/win/confdefs.h 1 861774426 b/0_confdefs.h 1.1) (tools/python/wilywin.py 1212 831424122 g/48_wilywin.py 1.1) (wily/regexp.c 15778 862660965 d/24_regexp.c 1.2) (sam/version 47 821786493 8_version 1.1) (tools/old/edit/q.c 2265 814094625 g/41_q.c 1.1) (tools/old/wilytoys/reader/CHANGES 957 817721627 f/33_CHANGES 1.1) (tools/old/wilytoys/prop.9.font 1930 826655241 g/1_prop.9.fon 1.1) (tools/quanstro/Makefile 354 830811922 e/39_Makefile 1.1) (tools/tools-dev/configure.in 440 849509053 e/3_configure. 1.1) (tools/old/edit/sam.c 4448 814094626 g/37_sam.c 1.1) (tools/tcl/wtktest 337 847842154 e/8_wtktest 1.1) (tools/old/wilytoys/reader2/reader.c 19355 826535148 f/11_reader.c 1.1) (tools/old/wilytoys/toys/wcat.c 886 826654768 f/2_wcat.c 1.1) (libmsg/Makefile.in 237 850294160 1_Makefile.i 1.1) (libframe/frdraw.c 1027 821786489 36_frdraw.c 1.1) (tools/old/wilytoys/reader/proto.h 1259 817721235 f/42_proto.h 1.1) (wily/vsearch.c 4528 890805820 c/50_vsearch.c 1.5.1.1) (wily/text.c 6462 862661653 d/32_text.c 1.4) (tools/old/edit/sam.h 2483 814094626 g/36_sam.h 1.1) (Doc/onepage.html 3824 848980082 c/7_onepage.ht 1.1) (Doc/user.html 24432 849319049 c/10_user.html 1.1) (tools/old/wilytoys/reader2/reader.h 1435 826535148 f/8_reader.h 1.1) (tools/old/wilytoys/reader2/CHANGES 3242 826535077 f/12_CHANGES 1.1) (tools/win/win2.c 13658 849516097 e/19_win2.c 1.1) (wily/text.h 1487 862661653 d/23_text.h 1.3) (tools/old/wilytoys/tformat.pl 3170 826655086 g/3_tformat.pl 1.1) (tools/old/wilytoys/toys/fixed.9.font 1937 826655241 e/44_fixed.9.fo 1.1) (Doc/old/user.sgml 17962 833797382 c/28_user.sgml 1.1) (Doc/old/tile.html 39747 836318715 c/32_tile.html 1.1) (wily/wily.c 3873 890806015 d/36_wily.c 1.6.1.1) (tools/win/mkinstalldirs 649 849509053 h/7_mkinstalld 1.1) (tools/win/wreplace.1 1525 849509053 f/0_wreplace.1 1.1) (tools/old/wilytoys/toys/README 4621 826656842 e/40_README 1.1) (tools/win/configure.in 443 866003398 e/33_configure. 1.3) (configure 61193 862640850 41_configure 1.2) (wily/proto.h 7982 877241770 d/27_proto.h 1.5) (tools/old/wilytoys/html-ascii.pl 6588 826654813 g/10_html-ascii 1.1) (sam/doc/Sam.ad 104 821786484 23_Sam.ad 1.1) (tools/old/wilytoys/reader/headers.h 390 817721228 f/47_headers.h 1.1) (tools/tools-dev/install-sh 4771 849509053 e/1_install-sh 1.1) (wily/wily.h 1115 872836145 d/31_wily.h 1.2) (tools/win/mktags.rc 1005 849509053 h/3_mktags.rc 1.1) (wily/event.c 5916 862661531 c/48_event.c 1.2) (Doc/example.gif 11011 829500546 c/14_example.gi 1.1) (Doc/tute/typescript 84 829122365 c/20_typescript 1.1) (libXg/clipr.c 375 821786487 b/27_clipr.c 1.1) (wily/NOTES 1553 862662486 d/17_NOTES 1.3) (tools/old/wilytoys/html2wily 1590 826654813 g/9_html2wily 1.1) (tools/win/wgoto.c 1893 849509053 h/6_wgoto.c 1.1) (tools/old/edit/range.c 2623 814094625 g/40_range.c 1.1) (tools/old/wilytoys/reader2/membuf.c 2737 826535145 f/24_membuf.c 1.1) (tools/old/wilytoys/make 176 826654964 g/5_make 1.1) (install-sh 4772 814266641 6_install-sh 1.1) (sam/doc/sam.tut.ms 40250 821786484 24_sam.tut.ms 1.1) (wily/mouse.c 4408 862661371 d/37_mouse.c 1.2) (Doc/sam/graphics.3 10644 821786485 h/13_graphics.3 1.1) (tools/old/edit/README 1471 814094626 g/32_README 1.1) (Doc/announce/1995.11 2255 848554704 c/2_1995.11 1.1) (tools/tools-dev/Man.1 1132 849509053 d/40_Man.1 1.1) (Doc/tute/start 9573 871736711 c/25_start 1.2) (wily/sam.c 3513 850126508 d/25_sam.c 1.1) (tools/old/edit/range.h 757 814094625 g/39_range.h 1.1) (tools/old/wilytoys/reader2/membuf.h 351 826535145 f/23_membuf.h 1.1) (Doc/python.html 3342 876044119 c/1_python.htm 1.2) (tools/tools-dev/Man.rc 249 849509053 d/46_Man.rc 1.1) (libXg/rdbitmapfile.c 1303 821786488 b/9_rdbitmapfi 1.1) (tools/old/wilytoys/README 4621 826656842 f/50_README 1.1) (wily/view.c 7473 876052331 d/11_view.c 1.3) (tools/tools-dev/mktags.1 1531 849509053 d/41_mktags.1 1.1) (wily/sam.h 2457 862660818 d/28_sam.h 1.2) (misc/README 267 862642295 b/0_README 1.1) (tools/old/wilytoys/fonts.alias 350 826656086 f/51_fonts.alia 1.1) (tools/tools-dev/configure 44678 849509053 e/4_configure 1.1) (Doc/tute/script 461 817093082 c/23_script 1.1) (tools/win/Man.1 1132 849509053 c/0_Man.1 1.1) (tools/tcl/README 1752 847842149 e/17_README 1.1) (wily/view.h 1335 872836134 d/33_view.h 1.2) (Doc/intro.html 4100 849253443 c/11_intro.html 1.1) (tools/win/Makefile 1946 866003440 h/27_Makefile 1.1) (Doc/Credits 1490 833914116 c/13_Credits 1.1) (Doc/old/wily.1 12662 833166562 c/31_wily.1 1.1) (tools/win/Tag.1 1744 849509053 e/0_Tag.1 1.1) (tools/old/wilytoys/reader2/mbox.c 10748 826535145 f/28_mbox.c 1.1) (tools/old/wilytoys/reader2/Makefile 1066 826535417 f/25_Makefile 1.1) (tools/win/config.h 2293 849317178 e/21_config.h 1.1) (Doc/README 133 848559150 c/19_README 1.1) (wily/const.h 1017 862660775 d/2_const.h 1.2) (Doc/changes.txt 3537 849448152 b/47_changes.tx 1.1) (tools/old/sh/wcmd.c 457 815578400 g/17_wcmd.c 1.1) (tools/tools-dev/mktags.rc 1005 849509053 d/47_mktags.rc 1.1) (sam/boilerplate 712 821786493 7_boilerplat 1.1) (tools/old/reader/getmsg.c 303 816338952 g/30_getmsg.c 1.1) (tools/quanstro/wread.c 1446 830811923 e/35_wread.c 1.1) (Doc/idioms.html 5452 848234791 b/51_idioms.htm 1.1) (Doc/FAQ.txt 2829 862558487 b/0_FAQ.txt 1.1) (tools/old/edit/regexp.c 15785 814094625 g/38_regexp.c 1.1) (libXg/balloc.c 925 821786486 b/34_balloc.c 1.1) (tools/old/wilytoys/toys/prop.9.font 1930 826655241 e/43_prop.9.fon 1.1) (Doc/Tcl.html 2276 848384715 c/0_Tcl.html 1.1) (sam/doc/font.4 1944 821786485 16_font.4 1.1) (tools/old/wilytoys/Makefile 260 826656874 g/14_Makefile 1.1) (tools/old/wilytoys/reader2/mbox.h 1840 826535145 f/27_mbox.h 1.1) (wily/vgeom.c 4192 876050861 d/15_vgeom.c 1.3) (Doc/FAQ.html 3863 849958420 b/49_FAQ.html 1.1) (tools/win/mktags.1 1531 849509053 d/0_mktags.1 1.1) (wily/global.c 694 862661550 d/19_global.c 1.2) (tools/old/wilytoys/reader/getmsg.c 390 817721226 f/48_getmsg.c 1.1) (include/msg.h 2948 850295436 b/45_msg.h 1.1) (libframe/frstr.c 703 821786489 33_frstr.c 1.1) (Doc/tute/hello.c 49 814094638 c/24_hello.c 1.1) (config.h.in 2330 850293882 27_config.h.i 1.1) (libframe/Makefile.in 330 850294147 30_Makefile.i 1.1) (tools/old/wilytoys/toys/diff 199 826654964 e/46_diff 1.1) (wily/list.c 2431 862661381 d/3_list.c 1.2) (wily/tag.c 3779 862661352 d/22_tag.c 1.3) (wily/global.h 618 862660925 c/43_global.h 1.2) (libmsg/connect.c 3844 849432200 0_connect.c 1.1) (tools/python/config.h 2293 828528911 g/49_config.h 1.1) (tools/old/wilytoys/reader/utils.c 298 817721241 f/38_utils.c 1.1) (tools/win/config.log 127 866003436 e/25_config.log 1.2) (tools/tools-dev/config.log 127 849515863 d/39_config.log 1.1) (include/u.h 717 821789722 b/40_u.h 1.1) (libXg/mkfont.c 1044 821786487 b/12_mkfont.c 1.1) (tools/win/win.1 4143 849509053 h/0_win.1 1.1) (tools/old/wilytoys/reader2/newsrc.c 5824 826535146 f/16_newsrc.c 1.1) (tools/quanstro/wattach.c 1492 830811922 e/38_wattach.c 1.1) (wily/search.c 4630 862905333 d/7_search.c 1.4) (wily/grow.c 1987 862661089 d/30_grow.c 1.2) (tools/python/wilymodule.c 11116 876045055 g/51_wilymodule 1.1) (libXg/point.c 333 821786487 b/15_point.c 1.1) (wily/dir.c 2003 871284503 c/51_dir.c 1.3) (tools/old/wilytoys/reader2/nntp.c 11882 826535147 f/18_nntp.c 1.1) (sam/doc/frame.3 6336 821786485 15_frame.3 1.1) (Doc/index.html 1329 862558521 c/16_index.html 1.2) (tools/win/wreplace.c 3562 849509053 h/5_wreplace.c 1.1) (tools/old/wilytoys/reader2/newsrc.h 377 826535147 f/14_newsrc.h 1.1) (tools/quanstro/windows.c 644 830811923 e/36_windows.c 1.1) (libXg/cursorswitch.c 1933 821786487 b/24_cursorswit 1.1) 7_make 1.1) (include/frame.h 2173 847619880 b/43_frame.h 1.1) (tools/old/wilytwily-0.13.42/INSTALL000064402366570000012000000166661033320152300135440ustar00ozstaff00004330000002Wily-specific hint ================== Ignore error messages like "no libXg configuration in dir sam" If 'make' fails, try 'gmake' (GNU make). Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, a file `config.cache' that saves the results of its tests to speed up reconfiguring, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.in' is used to create `configure' by a program called `autoconf'. You only need `configure.in' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. You can give `configure' initial values for variables by setting them in the environment. Using a Bourne-compatible shell, you can do that on the command line like this: CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure Or on systems that have the `env' program, you can do it like this: env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not supports the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' can not figure out automatically, but needs to determine by the type of host the package will run on. Usually `configure' can figure that out, but if it prints a message saying it can not guess the host type, give it the `--host=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name with three fields: CPU-COMPANY-SYSTEM See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the host type. If you are building compiler tools for cross-compiling, you can also use the `--target=TYPE' option to select the type of system they will produce code for and the `--build=TYPE' option to select the type of system on which you are compiling the package. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Operation Controls ================== `configure' recognizes the following options to control how it operates. `--cache-file=FILE' Use and save the results of the tests in FILE instead of `./config.cache'. Set FILE to `/dev/null' to disable caching, for debugging `configure'. `--help' Print a summary of the options to `configure', and exit. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--version' Print the version of Autoconf used to generate the `configure' script, and exit. `configure' also accepts some other, not widely useful, options. wily-0.13.42/libframe/000075502366570000012000000000001041526267400142745ustar00ozstaff00004330000002wily-0.13.42/libframe/frinsert.c000064402366570000012000000131311033320152300162540ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include #include #define DELTA 25 #define TMPSIZE 256 static Frame frame; static Point bxscan(Frame *f, Rune *sp, Rune *ep, Point *ppt) { int w, c, nb, delta, nl, nr, rw; Frbox *b; char *s, tmp[TMPSIZE+3]; /* +3 for rune overflow */ uchar *p; frame.r = f->r; frame.b = f->b; frame.font = f->font; frame.maxtab = f->maxtab; frame.left = f->left; frame.nbox = 0; frame.nchars = 0; delta = DELTA; nl = 0; for(nb=0; spmaxlines; nb++,frame.nbox++){ if(nb == frame.nalloc){ _frgrowbox(&frame, delta); if(delta < 10000) delta *= 2; } b = &frame.box[nb]; c = *sp; if(c=='\t' || c=='\n'){ b->a.b.bc = c; b->wid = 5000; b->a.b.minwid = (c=='\n')? 0 : charwidth(frame.font, ' '); b->nrune = -1; if(c=='\n') nl++; frame.nchars++; sp++; }else{ s = tmp; nr = 0; w = 0; while(sp < ep){ c = *sp; if(c=='\t' || c=='\n') break; rw = runetochar(s, sp); if(s+rw >= tmp+TMPSIZE) break; w += charwidth(frame.font, c); sp++; s += rw; nr++; } *s++ = 0; p = _frallocstr(s-tmp); b = &frame.box[nb]; b->a.ptr = p; memmove(p, tmp, s-tmp); b->wid = w; b->nrune = nr; frame.nchars += nr; } } _frcklinewrap0(f, ppt, &frame.box[0]); return _frdraw(&frame, *ppt); } static void chopframe(Frame *f, Point pt, ulong p, int bn) { Frbox *b; for(b = &f->box[bn]; ; b++){ if(b >= &f->box[f->nbox]) berror("endofframe"); _frcklinewrap(f, &pt, b); if(pt.y >= f->r.max.y) break; p += NRUNE(b); _fradvance(f, &pt, b); } f->nchars = p; f->nlines = f->maxlines; if(b<&f->box[f->nbox]) /* BUG */ _frdelbox(f, (int)(b-f->box), f->nbox-1); } void frinsert(Frame *f, Rune *sp, Rune *ep, ulong p0) { Point pt0, pt1, ppt0, ppt1, pt; Frbox *b; int n, n0, nn0, y; Rectangle r; static struct{ Point pt0, pt1; }*pts; static int nalloc=0; int npts; if(p0>f->nchars || sp==ep || f->b==0) return; n0 = _frfindbox(f, 0, 0, p0); nn0 = n0; pt0 = _frptofcharnb(f, p0, n0); ppt0 = pt0; pt1 = bxscan(f, sp, ep, &ppt0); ppt1 = pt1; if(n0 < f->nbox){ _frcklinewrap(f, &pt0, b = &f->box[n0]); /* for frselectf() */ _frcklinewrap0(f, &ppt1, b); } f->modified = 1; /* * ppt0 and ppt1 are start and end of insertion as they will appear when * insertion is complete. pt0 is current location of insertion position * (p0); pt1 is terminal point (without line wrap) of insertion. */ if(p0==f->p0 && p0==f->p1) /* quite likely */ frselectf(f, pt0, pt0, F&~D); else frselectp(f, F&~D); /* * Find point where old and new x's line up * Invariants: * pt0 is where the next box (b, n0) is now * pt1 is where it will be after the insertion * If pt1 goes off the rectangle, we can toss everything from there on */ for(b = &f->box[n0],npts=0; pt1.x!=pt0.x && pt1.y!=f->r.max.y && n0nbox; b++,n0++,npts++){ _frcklinewrap(f, &pt0, b); _frcklinewrap0(f, &pt1, b); if(b->nrune > 0){ n = _frcanfit(f, pt1, b); if(n == 0) berror("_frcanfit==0"); if(n != b->nrune){ _frsplitbox(f, n0, n); b = &f->box[n0]; } } if(npts == nalloc){ pts = pts? realloc(pts, (npts+DELTA)*sizeof(pts[0])) : malloc((npts+DELTA)*sizeof(pts[0])) ; nalloc += DELTA; b = &f->box[n0]; } pts[npts].pt0 = pt0; pts[npts].pt1 = pt1; /* has a text box overflowed off the frame? */ if(pt1.y == f->r.max.y) break; _fradvance(f, &pt0, b); pt1.x += _frnewwid(f, pt1, b); } if(pt1.y > f->r.max.y) berror("frinsert pt1 too far"); if(pt1.y==f->r.max.y && n0nbox){ f->nchars -= _frstrlen(f, n0); _frdelbox(f, n0, f->nbox-1); } if(n0 == f->nbox) f->nlines = (pt1.y-f->r.min.y)/f->font->height+(pt1.x>f->left); else if(pt1.y!=pt0.y){ int q0, q1; y = f->r.max.y; q0 = pt0.y+f->font->height; q1 = pt1.y+f->font->height; f->nlines += (q1-q0)/f->font->height; if(f->nlines > f->maxlines) chopframe(f, ppt1, p0, nn0); if(pt1.y < y){ r = f->r; r.min.y = q0; r.max.y = y-(q1-q0); if(q1 < y) bitblt(f->b, Pt(f->r.min.x, q1), f->b, r, S); r.min = pt0; r.max.y = q0; bitblt(f->b, pt1, f->b, r, S); } } /* * Move the old stuff down to make room. The loop will move the stuff * between the insertion and the point where the x's lined up. * The bitblts above moved everything down after the point they lined up. */ for((y=pt1.y==f->r.max.y?pt1.y:0),b = &f->box[n0-1]; --npts>=0; --b){ pt = pts[npts].pt1; if(b->nrune > 0){ r.min = pts[npts].pt0; r.max = r.min; r.max.x += b->wid; r.max.y += f->font->height; bitblt(f->b, pt, f->b, r, S); if(pt.y < y){ /* clear bit hanging off right */ r.min = pt; r.max = pt; r.min.x += b->wid; r.max.x = f->r.max.x; r.max.y += f->font->height; bitblt(f->b, r.min, f->b, r, 0); } y = pt.y; }else{ r.min = pt; r.max = pt; r.max.x += b->wid; r.max.y += f->font->height; if(r.max.x >= f->r.max.x) r.max.x = f->r.max.x; bitblt(f->b, r.min, f->b, r, 0); y = (pt.x == f->left)? pt.y : 0; } } frselectf(f, ppt0, ppt1, 0); _frredraw(&frame, ppt0); _fraddbox(f, nn0, frame.nbox); for(n=0; nbox[nn0+n] = frame.box[n]; if(nn0>0 && f->box[nn0-1].nrune>=0 && ppt0.x-f->box[nn0-1].wid>=(int)f->left){ --nn0; ppt0.x -= f->box[nn0].wid; } n0 += frame.nbox; _frclean(f, ppt0, nn0, n0nbox-1? n0+1 : n0); f->nchars += frame.nchars; if(f->p0 >= p0) f->p0 += frame.nchars; if(f->p0 > f->nchars) f->p0 = f->nchars; if(f->p1 >= p0) f->p1 += frame.nchars; if(f->p1 > f->nchars) f->p1 = f->nchars; frselectp(f, F&~D); } wily-0.13.42/libframe/frbox.c000064402366570000012000000055771033320152300155570ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include #include #define SLOP 25 void _fraddbox(Frame *f, int bn, int n) /* add n boxes after bn, shift the rest up, * box[bn+n]==box[bn] */ { int i; if(bn > f->nbox) berror("_fraddbox"); if(f->nbox+n > f->nalloc) _frgrowbox(f, n+SLOP); for(i=f->nbox; --i>=bn; ) f->box[i+n] = f->box[i]; f->nbox+=n; } void _frclosebox(Frame *f, int n0, int n1) /* inclusive */ { int i; if(n0>=f->nbox || n1>=f->nbox || n1nbox; i++) f->box[i-(n1-n0)] = f->box[i]; f->nbox -= n1-n0; } void _frdelbox(Frame *f, int n0, int n1) /* inclusive */ { if(n0>=f->nbox || n1>=f->nbox || n1=f->nbox || n1>=f->nbox) berror("_frfreebox"); n1++; for(i=n0; ibox[i].nrune >= 0) free(f->box[i].a.ptr); } void _frgrowbox(Frame *f, int delta) { f->nalloc += delta; f->box = f->box ? realloc(f->box, f->nalloc*sizeof(Frbox)) : malloc(f->nalloc*sizeof(Frbox)); if(f->box == 0) berror("_frgrowbox"); } static void dupbox(Frame *f, int bn) { uchar *p; if(f->box[bn].nrune < 0) berror("dupbox"); _fraddbox(f, bn, 1); if(f->box[bn].nrune >= 0){ p = _frallocstr(NBYTE(&f->box[bn])+1); strcpy((char*)p, (char*)f->box[bn].a.ptr); f->box[bn+1].a.ptr = p; } } static uchar* runeindex(uchar *p, int n) { int i, w; Rune rune; for(i=0; inrune<0 || b->nrunenrune -= n; runeindex(b->a.ptr, b->nrune)[0] = 0; b->wid = strwidth(f->font, (char *)b->a.ptr); } static void chopbox(Frame *f, Frbox *b, int n) /* drop first n chars; no allocation done */ { if(b->nrune<0 || b->nrunea.ptr, (char*)runeindex(b->a.ptr, n)); b->nrune -= n; b->wid = strwidth(f->font, (char *)b->a.ptr); } void _frsplitbox(Frame *f, int bn, int n) { dupbox(f, bn); truncatebox(f, &f->box[bn], f->box[bn].nrune-n); chopbox(f, &f->box[bn+1], n); } void _frmergebox(Frame *f, int bn) /* merge bn and bn+1 */ { Frbox *b; b = &f->box[bn]; _frinsure(f, bn, NBYTE(&b[0])+NBYTE(&b[1])+1); strcpy((char*)runeindex(b[0].a.ptr, b[0].nrune), (char*)b[1].a.ptr); b[0].wid += b[1].wid; b[0].nrune += b[1].nrune; _frdelbox(f, bn+1, bn+1); } int _frfindbox(Frame *f, int bn, ulong p, ulong q) /* find box containing q and put q on a box boundary */ { Frbox *b; for(b = &f->box[bn]; bnnbox && p+NRUNE(b)<=q; bn++, b++) p += NRUNE(b); if(p != q) _frsplitbox(f, bn++, (int)(q-p)); return bn; } wily-0.13.42/libframe/Makefile.in000064402366570000012000000005121033320152300163200ustar00ozstaff00004330000002srcdir=@srcdir@ VPATH=@srcdir@ CC=@CC@ RANLIB=@RANLIB@ INCLUDES=$(srcdir)/../include CFLAGS=@CFLAGS@ -I.. -I$(INCLUDES) LIB=libframe.a OBJS=frbox.o frdelete.o frdraw.o frinit.o frinsert.o frptofchar.o\ frselect.o frstr.o frutil.o misc.o include $(INCLUDES)/Makelib $(OBJS): $(INCLUDES)/u.h $(INCLUDES)/libc.h $(INCLUDES)/frame.h wily-0.13.42/libframe/frstr.c000064402366570000012000000012771033320152300155700ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include #include /* * The code here and elsewhere requires that strings not be gcalloc()ed */ #define CHUNK 16 #define ROUNDUP(n) ((n+CHUNK)&~(CHUNK-1)) uchar * _frallocstr(unsigned n) { uchar *p; p = malloc(ROUNDUP(n)); if(p == 0) berror("out of memory"); return p; } void _frinsure(Frame *f, int bn, unsigned n) { Frbox *b; uchar *p; b = &f->box[bn]; if(b->nrune < 0) berror("_frinsure"); if(ROUNDUP(b->nrune) > n) /* > guarantees room for terminal NUL */ return; p = _frallocstr(n); b = &f->box[bn]; memmove(p, b->a.ptr, NBYTE(b)+1); free(b->a.ptr); b->a.ptr = p; } wily-0.13.42/libframe/frptofchar.c000064402366570000012000000037301033320152300165620ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include #include Point _frptofcharptb(Frame *f, ulong p, Point pt, int bn) { uchar *s; Frbox *b; int w, l; Rune r; for(b = &f->box[bn]; bnnbox; bn++,b++){ _frcklinewrap(f, &pt, b); if(p < (l=NRUNE(b))){ if(b->nrune > 0) for(s=b->a.ptr; p>0; s+=w, p--){ if((r = *s) < Runeself) w = 1; else w = chartorune(&r, (char*)s); pt.x += charwidth(f->font, r); if(r==0 || pt.x>f->r.max.x) berror("frptofchar"); } break; } p -= l; _fradvance(f, &pt, b); } return pt; } Point frptofchar(Frame *f, ulong p) { return _frptofcharptb(f, p, Pt(f->left, f->r.min.y), 0); } Point _frptofcharnb(Frame *f, ulong p, int nb) /* doesn't do final _fradvance to next line */ { Point pt; int nbox; nbox = f->nbox; f->nbox = nb; pt = _frptofcharptb(f, p, Pt(f->left, f->r.min.y), 0); f->nbox = nbox; return pt; } static Point _frgrid(Frame *f, Point p) { p.y -= f->r.min.y; p.y -= p.y%f->font->height; p.y += f->r.min.y; if(p.x > f->r.max.x) p.x = f->r.max.x; return p; } ulong frcharofpt(Frame *f, Point pt) { Point qt; int w, bn; uchar *s; Frbox *b; ulong p; Rune r; pt = _frgrid(f, pt); qt.x = f->left; qt.y = f->r.min.y; for(b=f->box,bn=0,p=0; bnnbox && qt.y= pt.y) break; _fradvance(f, &qt, b); p += NRUNE(b); } for(; bnnbox && qt.x<=pt.x; bn++,b++){ _frcklinewrap(f, &qt, b); if(qt.y > pt.y) break; if(qt.x+b->wid > pt.x){ if(b->nrune < 0) _fradvance(f, &qt, b); else{ s = b->a.ptr; for(;;){ if((r = *s) < Runeself) w = 1; else w = chartorune(&r, (char*)s); if(r == 0) berror("end of string in frcharofpt"); s += w; qt.x += charwidth(f->font, r); if(qt.x > pt.x) break; p++; } } }else{ p += NRUNE(b); _fradvance(f, &qt, b); } } return p; } wily-0.13.42/libframe/misc.c000064402366570000012000000032171033320152300153570ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include #ifdef HAVE_STDARG_H #include #else #include #endif #ifdef HAVE_STDARG_H void fprint(int fd, char *z, ...) { va_list args; char buf[2048]; /* pick reasonable blocksize */ va_start(args, z); vsprintf(buf, z, args); write(fd, buf, strlen(buf)); va_end(args); } #else /* !HAVE_STDARG_H */ void fprint(va_alist) va_dcl { int fd; char *fmt; va_list args; char buf[2048]; /* pick reasonable blocksize */ va_start(args); fd = va_arg(args, int); fmt = va_arg(args, char *); vsprintf(buf, fmt, args); write(fd, buf, strlen(buf)); va_end(args); } #endif /* HAVE_STDARG_H */ #ifndef HAVE_STRERROR char * strerror(int n) { extern char *sys_errlist[]; return sys_errlist[n]; } #endif /* HAVE_STRERROR */ int errstr(char *buf) { extern int errno; strncpy(buf, strerror(errno), ERRLEN); return 1; } char* getuser(void) { struct passwd *p; static char *user = 0; if (!user) { p = getpwuid(getuid()); if (p && p->pw_name) { user = malloc(strlen(p->pw_name)+1); if (user) strcpy(user, p->pw_name); } } if(!user) user = "unknown"; return user; } #ifndef HAVE_MEMMOVE /* * memcpy is probably fast, but may not work with overlap */ void* memmove(void *a1, const void *a2, size_t n) { char *s1; const char *s2; s1 = a1; s2 = a2; if(s1 > s2) goto back; if(s1 + n <= s2) return memcpy(a1, a2, n); while(n > 0) { *s1++ = *s2++; n--; } return a1; back: s2 += n; if(s2 <= s1) return memcpy(a1, a2, n); s1 += n; while(n > 0) { *--s1 = *--s2; n--; } return a1; } #endif /* HAVE_MEMMOVE */ wily-0.13.42/libframe/frdraw.c000064402366570000012000000020031033320152300157010ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include #include void _frredraw(Frame *f, Point pt) { Frbox *b; int nb; for(nb=0,b=f->box; nbnbox; nb++, b++){ _frcklinewrap(f, &pt, b); if(b->nrune >= 0) string(f->b, pt, f->font, (char *)b->a.ptr, S); pt.x += b->wid; } } Point _frdraw(Frame *f, Point pt) { Frbox *b; int nb, n; for(b=f->box,nb=0; nbnbox; nb++, b++){ _frcklinewrap0(f, &pt, b); if(pt.y == f->r.max.y){ f->nchars -= _frstrlen(f, nb); _frdelbox(f, nb, f->nbox-1); break; } if(b->nrune > 0){ n = _frcanfit(f, pt, b); if(n == 0) berror("draw: _frcanfit==0"); if(n != b->nrune){ _frsplitbox(f, nb, n); b = &f->box[nb]; } pt.x += b->wid; }else{ if(b->a.b.bc == '\n') pt.x = f->left, pt.y+=f->font->height; else pt.x += _frnewwid(f, pt, b); } } return pt; } int _frstrlen(Frame *f, int nb) { int n; for(n=0; nbnbox; nb++) n += NRUNE(&f->box[nb]); return n; } wily-0.13.42/libframe/frinit.c000064402366570000012000000014531033320152300157170ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include #include int tabsize = 4; /* tabsize as number of 0s */ void frinit(Frame *f, Rectangle r, Font *ft, Bitmap *b) { frfont(f, ft); f->nbox = 0; f->nalloc = 0; f->nchars = 0; f->nlines = 0; f->p0 = 0; f->p1 = 0; f->box = 0; f->lastlinefull = 0; frsetrects(f, r, b); } void frfont(Frame *f, Font *ft) { f->font = ft; f->maxtab = tabsize*charwidth(ft, '0'); } void frsetrects(Frame *f, Rectangle r, Bitmap *b) { f->b = b; f->entire = r; f->r = r; f->r.max.y -= (r.max.y-r.min.y)%f->font->height; f->left = r.min.x+1; f->maxlines = (r.max.y-r.min.y)/f->font->height; } void frclear(Frame *f) { if(f->nbox) _frdelbox(f, 0, f->nbox-1); if(f->box) free(f->box); f->box = 0; } wily-0.13.42/libframe/frutil.c000064402366570000012000000035551033320152300157360ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include #include int _frcanfit(Frame *f, Point pt, Frbox *b) { int left, w, nr; uchar *p; Rune r; left = f->r.max.x-pt.x; if(b->nrune < 0) return b->a.b.minwid <= left; if(left >= b->wid) return b->nrune; for(nr=0,p=b->a.ptr; *p; p+=w,nr++){ r = *p; if(r < Runeself) w = 1; else w = chartorune(&r, (char*)p); left -= charwidth(f->font, r); if(left < 0) return nr; } berror("_frcanfit can't"); return 0; } void _frcklinewrap(Frame *f, Point *p, Frbox *b) { if((b->nrune<0? b->a.b.minwid : b->wid) > f->r.max.x-p->x){ p->x = f->left; p->y += f->font->height; } } void _frcklinewrap0(Frame *f, Point *p, Frbox *b) { if(_frcanfit(f, *p, b) == 0){ p->x = f->left; p->y += f->font->height; } } void _fradvance(Frame *f, Point *p, Frbox *b) { if(b->nrune<0 && b->a.b.bc=='\n'){ p->x = f->left; p->y += f->font->height; }else p->x += b->wid; } int _frnewwid(Frame *f, Point pt, Frbox *b) { int c, x; c = f->r.max.x; x = pt.x; if(b->nrune >= 0) return b->wid; if(b->a.b.bc == '\t'){ if(x+b->a.b.minwid > c) x = pt.x = f->left; x += f->maxtab; x -= (x-f->left)%f->maxtab; if(x-pt.xa.b.minwid || x>c) x = pt.x+b->a.b.minwid; b->wid = x-pt.x; } return b->wid; } void _frclean(Frame *f, Point pt, int n0, int n1) /* look for mergeable boxes */ { Frbox *b; int nb, c; c = f->r.max.x; for(nb=n0; nbbox[nb]; _frcklinewrap(f, &pt, b); while(b[0].nrune>=0 && nb=0 && pt.x+b[0].wid+b[1].widbox[nb]; } _fradvance(f, &pt, &f->box[nb]); } for(; nbnbox; nb++){ b = &f->box[nb]; _frcklinewrap(f, &pt, b); _fradvance(f, &pt, &f->box[nb]); } f->lastlinefull = 0; if(pt.y >= f->r.max.y) f->lastlinefull = 1; } p, Frbox *b) { if(b->nrune<0 && b->a.b.bc=='\n'){ p->x = f->left; p->y += f->font->height; }else p->x += b->wid; } int _frnewwid(Frame *f,wily-0.13.42/libframe/frdelete.c000064402366570000012000000050621033320152300162160ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include #include int frdelete(Frame *f, ulong p0, ulong p1) { Point pt0, pt1, ppt0; Frbox *b; int n0, n1, n; Rectangle r; int nn0; if(p0>=f->nchars || p0==p1 || f->b==0) return 0; if(p1 > f->nchars) p1 = f->nchars; n0 = _frfindbox(f, 0, (unsigned long)0, p0); n1 = _frfindbox(f, n0, p0, p1); pt0 = _frptofcharnb(f, p0, n0); pt1 = frptofchar(f, p1); if(f->p0!=p0 || f->p1!=p1) /* likely they ARE equal */ frselectp(f, F&~D); /* can do better some day */ frselectf(f, pt0, pt1, 0); if(n0 == f->nbox) berror("off end in frdelete"); nn0 = n0; ppt0 = pt0; _frfreebox(f, n0, n1-1); f->modified = 1; /* * Invariants: * pt0 points to beginning, pt1 points to end * n0 is box containing beginning of stuff being deleted * n1, b are box containing beginning of stuff to be kept after deletion * region between pt0 and pt1 is clear */ b = &f->box[n1]; while(pt1.x!=pt0.x && n1nbox){ _frcklinewrap0(f, &pt0, b); _frcklinewrap(f, &pt1, b); if(b->nrune > 0){ n = _frcanfit(f, pt0, b); if(n==0) berror("_frcanfit==0"); if(n != b->nrune){ _frsplitbox(f, n1, n); b = &f->box[n1]; } r.min = pt1; r.max = pt1; r.max.x += b->wid; r.max.y += f->font->height; bitblt(f->b, pt0, f->b, r, S); if(pt0.y == pt1.y) r.min.x = r.max.x-(pt1.x-pt0.x); bitblt(f->b, r.min, f->b, r, 0); } _fradvance(f, &pt1, b); pt0.x += _frnewwid(f, pt0, b); f->box[n0++] = f->box[n1++]; b++; } if(pt1.y != pt0.y){ Point pt2; pt2 = _frptofcharptb(f, 32767, pt1, n1); if(pt2.y > f->r.max.y) berror("frptofchar in frdelete"); if(n1 < f->nbox){ int q0, q1, q2; q0 = pt0.y+f->font->height; q1 = pt1.y+f->font->height; q2 = pt2.y+f->font->height; bitblt(f->b, pt0, f->b, Rect(pt1.x, pt1.y, f->r.max.x, q1), S); bitblt(f->b, Pt(f->r.min.x, q0), f->b, Rect(f->r.min.x, q1, f->r.max.x, q2), S); frselectf(f, Pt(pt2.x, pt2.y-(pt1.y-pt0.y)), pt2, 0); }else frselectf(f, pt0, pt2, 0); } _frclosebox(f, n0, n1-1); if(nn0>0 && f->box[nn0-1].nrune>=0 && ppt0.x-f->box[nn0-1].wid>=(int)f->left){ --nn0; ppt0.x -= f->box[nn0].wid; } _frclean(f, ppt0, nn0, n0nbox-1? n0+1 : n0); if(f->p1 > p1) f->p1 -= p1-p0; else if(f->p1 > p0) f->p1 = p0; if(f->p0 > p1) f->p0 -= p1-p0; else if(f->p0 > p0) f->p0 = p0; frselectp(f, F&~D); f->nchars -= p1-p0; pt0 = frptofchar(f, f->nchars); n = f->nlines; f->nlines = (pt0.y-f->r.min.y)/f->font->height+(pt0.x>f->left); return n - f->nlines; } wily-0.13.42/libframe/frselect.c000064402366570000012000000037011033320152300162310ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include #include void frselect(Frame *f, Mouse *m) /* when called, button 1 is down */ { ulong p0, p1, q; Point mp, pt0, pt1, qt; int b; b = m->buttons; mp = m->xy; Again: f->modified = 0; frselectp(f, F&~D); p0 = p1 = frcharofpt(f, mp); pt0 = frptofchar(f, p0); pt1 = frptofchar(f, p1); frselectf(f, pt0, pt1, F&~D); do{ if(f->modified) /* special hack so 8½ can frselect in parallel */ goto Again; q = frcharofpt(f, m->xy); if(p1 != q){ if(p0 == p1) frselectf(f, pt0, pt1, F&~D); qt = frptofchar(f, q); if(p1 < q) frselectf(f, pt1, qt, F&~D); else frselectf(f, qt, pt1, F&~D); p1 = q; pt1 = qt; if(p0 == p1) frselectf(f, pt0, pt1, F&~D); } f->modified = 0; if(p0 < p1) f->p0 = p0, f->p1 = p1; else f->p0 = p1, f->p1 = p0; frgetmouse(); }while(m->buttons == b); } /* it is assumed p0<=p1 and both were generated by frptofchar() */ void frselectf(Frame *f, Point p0, Point p1, Fcode c) { int n; Point q0, q1; if(p0.x == f->left) p0.x = f->r.min.x; if(p1.x == f->left) p1.x = f->r.min.x; q0 = p0; q1 = p1; q0.y += f->font->height; q1.y += f->font->height; n = (p1.y-p0.y)/f->font->height; if(f->b == 0) berror("frselectf b==0"); if(p0.y == f->r.max.y) return; if(n == 0){ if(p0.x == p1.x) if(p0.x == f->r.min.x) q1.x++; else p0.x--; bitblt(f->b, p0, f->b, Rpt(p0, q1), c); }else{ if(p0.x >= f->r.max.x) p0.x = f->r.max.x-1; bitblt(f->b, p0, f->b, Rect(p0.x, p0.y, f->r.max.x, q0.y), c); if(n > 1) bitblt(f->b, Pt(f->r.min.x, q0.y), f->b, Rect(f->r.min.x, q0.y, f->r.max.x, p1.y), c); bitblt(f->b, Pt(f->r.min.x, p1.y), f->b, Rect(f->r.min.x, p1.y, q1.x, q1.y), c); } } void frselectp(Frame *f, Fcode c) { Point pt0, pt1; pt0 = frptofchar(f, f->p0); pt1 = (f->p0==f->p1)? pt0 : frptofchar(f, f->p1); frselectf(f, pt0, pt1, c); } wily-0.13.42/libframe/Makefile000064402366570000012000000005471041526267400157420ustar00ozstaff00004330000002# Generated automatically from Makefile.in by configure. srcdir=. CC=gcc RANLIB=ranlib INCLUDES=$(srcdir)/../include CFLAGS=-g -O -I.. -I$(INCLUDES) LIB=libframe.a OBJS=frbox.o frdelete.o frdraw.o frinit.o frinsert.o frptofchar.o\ frselect.o frstr.o frutil.o misc.o include $(INCLUDES)/Makelib $(OBJS): $(INCLUDES)/u.h $(INCLUDES)/libc.h $(INCLUDES)/frame.h wily-0.13.42/include/000075502366570000012000000000001033320152300141175ustar00ozstaff00004330000002wily-0.13.42/include/u.h000064402366570000012000000013151033320152300145340ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ /* #ifdef */ #include #include #include #include #include #include #include #include #ifdef HAVE_MALLOC_H #include #endif /* HAVE_MALLOC_H */ #ifndef HAVE_ULONG typedef unsigned long ulong; #endif #ifndef HAVE_USHORT typedef unsigned short ushort; #endif #ifndef HAVE_UINT typedef unsigned int uint; #endif #ifndef HAVE_UCHAR typedef unsigned char uchar; #endif #ifndef HAVE_CADDR_T typedef char *caddr_t; #endif #ifndef HAVE_REMOVE #define remove(x) unlink(x) #endif #ifdef BROKEN_SPRINTF int Asprintf(char*,char*,...); #else #define Asprintf sprintf #endif wily-0.13.42/include/msg.h000064402366570000012000000056601033320152300150650ustar00ozstaff00004330000002/* see ../Doc/C.html */ typedef struct Msg Msg; typedef int Id; /* Window identifier */ typedef enum Bool {false, true} Bool; typedef struct Range Range; /* name of environment variable */ #define WILYFIFO "WILYFIFO" enum { HSIZE= 12, /* minimum length of a message fragment to be able to determine the length of the full message. */ MAXERRMSG = 1024 /* maximum length of an error message */ }; typedef enum Mtype { /* EVENTS: also used for event masks. */ WEexec = 1, WEgoto = 2, WEdestroy = 4, WEreplace = 8, WEfencepost, /* REQUESTS AND RESPONSES */ WRerror, WMlist, WRlist, WMnew, WRnew, WMattach, WRattach, WMsetname, WRsetname, WMgetname, WRgetname, WMsettools,WRsettools, WMgettools,WRgettools, WMread, WRread, WMreplace, WRreplace, WMexec, WRexec, WMgoto, WRgoto, WMfencepost } Mtype; struct Range { ulong p0,p1; }; #define RLEN(r) ((r).p1 -(r).p0) #define RCONTAINS(r, p) ( ((p)>=(r).p0) && ((p) < (r).p1) ) #define RINTERSECT(r0, r1) ( ((r0).p1 >= (r1).p0) && ((r0).p0 <= (r1).p1) ) #define RISSUBSET(q,r) ( ((q).p0 >= (r).p0) && ((q).p1 <= (r).p1) ) #define ROK(r) ((r).p1 >= (r).p0) struct Msg { Mtype t; Id m; /* message */ Id w; /* window */ Range r; ushort flag; char * s; }; /* ../libmsg/connect.c */ int client_connect (void); int wilyfifolisten (void); int wilyfifotalk (void); void fifo_cleanup (void); int wily_connect (char*,int); /* ../libmsg/msg.c */ int msg_size (Msg *m); void msg_flatten (Msg*, uchar*); int msg_init (Msg*, uchar*); ulong msg_bufsize (uchar*); void msg_print (Msg *); void msg_fill (Msg*, Mtype , Id w, Range r, ushort flag, char*s) ; #define FULLMSG(ptr,n) ( (n) >= HSIZE && (n) >= msg_bufsize(ptr) ) /* ../libmsg/rpc.c */ typedef struct Handle Handle; extern Range nr; /* null range */ Handle* rpc_init (int); int rpc_fileno(Handle *h); Bool rpc_isconnected(Handle*); void rpc_freehandle (Handle*); char* rpc_list (Handle*h, char **bufptr); char* rpc_new (Handle*, char *, Id*, ushort); char* rpc_attach (Handle*, Id, ushort); char* rpc_setname (Handle*, Id, char *); char* rpc_getname (Handle*, Id, char **); char* rpc_settools (Handle*, Id, char *); char* rpc_gettools (Handle*, Id, char **); char* rpc_read (Handle*, Id, Range, char*); char* rpc_replace (Handle*, Id, Range, char*); char* rpc_exec (Handle*, Id , char *); char* rpc_goto (Handle*, Id * , Range*, char*, Bool); int rpc_event (Handle*, Msg *); int rpc_bounce (Handle*, Msg *); Bool rpc_wouldblock(Handle*); #define MAX(a,b)(((a)>(b))?(a):(b)) #define MIN(a,b)(((a)<(b))?(a):(b)) #define NEW(t) ((t*)salloc(sizeof(t))) /* ../libmsg/util.c */ int clip(int , int , int ); void eprintf(char *, ...); void * salloc(int ); void * srealloc(void *, int); Range intersect (Range, Range); Range rclip (Range, Range); ulong pclipr(ulong p, Range r); Range range(ulong , ulong ); Range maybereverserange(ulong,ulong); ulong ladjust(ulong , Range , int ); ulong radjust(ulong , Range , int ); wily-0.13.42/include/frame.h000064402366570000012000000041751033320152300153710ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ typedef struct Frbox Frbox; typedef struct Frame Frame; struct Frbox { long wid; /* in pixels */ long nrune; /* <0 ==> negate and treat as break char */ union{ uchar *ptr; struct{ short bc; /* break char */ short minwid; }b; }a; }; struct Frame { Font *font; /* of chars in the frame */ Bitmap *b; /* on which frame appears */ Rectangle r; /* in which text appears */ Rectangle entire; /* of full frame */ Frbox *box; ulong p0, p1; /* selection */ short left; /* left edge of text */ ushort nbox, nalloc; ushort maxtab; /* max size of tab, in pixels */ ushort nchars; /* # runes in frame */ ushort nlines; /* # lines with text */ ushort maxlines; /* total # lines in frame */ ushort lastlinefull; /* last line fills frame */ ushort modified; /* changed since frselect() */ }; ulong frcharofpt(Frame*, Point); Point frptofchar(Frame*, ulong); int frdelete(Frame*, ulong, ulong); void frinsert(Frame*, Rune*, Rune*, ulong); void frselect(Frame*, Mouse*); void frselectp(Frame*, Fcode); void frselectf(Frame*, Point, Point, Fcode); void frinit(Frame*, Rectangle, Font*, Bitmap*); void frsetrects(Frame*, Rectangle, Bitmap*); void frclear(Frame*); void frgetmouse(void); void frfont(Frame*, Font*); uchar *_frallocstr(unsigned); void _frinsure(Frame*, int, unsigned); Point _frdraw(Frame*, Point); void _frgrowbox(Frame*, int); void _frfreebox(Frame*, int, int); void _frmergebox(Frame*, int); void _frdelbox(Frame*, int, int); void _frsplitbox(Frame*, int, int); int _frfindbox(Frame*, int, ulong, ulong); void _frclosebox(Frame*, int, int); int _frcanfit(Frame*, Point, Frbox*); void _frcklinewrap(Frame*, Point*, Frbox*); void _frcklinewrap0(Frame*, Point*, Frbox*); void _fradvance(Frame*, Point*, Frbox*); int _frnewwid(Frame*, Point, Frbox*); void _frclean(Frame*, Point, int, int); void _frredraw(Frame*, Point); void _fraddbox(Frame*, int, int); Point _frptofcharptb(Frame*, ulong, Point, int); Point _frptofcharnb(Frame*, ulong, int); int _frstrlen(Frame*, int); #define NRUNE(b) ((b)->nrune<0? 1 : (b)->nrune) #define NBYTE(b) strlen((char*)(b)->a.ptr) wily-0.13.42/include/libc.h000064402366570000012000000026361033320152300152100ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ /* Plan 9 C library interface */ typedef unsigned short Rune; #define sprint sprintf /* Not used and conflicts */ #if 0 #define dup(a,b) dup2(a,b) #endif #define seek(a,b,c) lseek(a,b,c) #define create(name, mode, perm) creat(name, perm) #define exec(a,b) execv(a,b) #define USED(a) #define SET(a) #define _exits(v) if (v!=0) _exit(1); else _exit(0) enum { OREAD = 0, /* open for read */ OWRITE = 1, /* open for write */ ORDWR = 2, /* open for read/write */ ERRLEN = 64 /* length of error message */ }; enum { UTFmax = 3, /* maximum bytes per rune */ Runesync = 0x80, /* cannot represent part of a utf sequence (<) */ Runeself = 0x80, /* rune and utf sequences are the same (<) */ Runeerror = 0x80 /* decoding error in utf */ }; /* * new rune routines */ extern int runetochar(char*, Rune*); extern int chartorune(Rune*, char*); extern int runelen(long); extern int fullrune(char*, int); /* * rune routines from converted str routines */ extern long utflen(char*); /* was countrune */ extern char* utfrune(char*, long); extern char* utfrrune(char*, long); extern char* utfutf(char*, char*); /* * Miscellaneous functions */ #ifdef NEEDVARARG extern void fprint(); #else extern void fprint(int, char *, ...); #endif extern int notify (void(*)(void *, char *)); extern int errstr(char *); extern char* getuser(void); extern void exits(char*); wily-0.13.42/include/libg.h000064402366570000012000000165161033320152300152160ustar00ozstaff00004330000002/* Copyright (c) 1992 AT&T - All rights reserved. */ #ifndef _LIBG_H #define _LIBG_H /* * Like Plan9's libg.h, but suitable for inclusion on non-Plan9 machines */ enum{ EMAXMSG = 128+8192 }; /* max event size */ /* * Types */ typedef struct Bitmap Bitmap; typedef struct Point Point; typedef struct Rectangle Rectangle; typedef struct Cursor Cursor; typedef struct Mouse Mouse; typedef struct Menu Menu; typedef struct Font Font; typedef struct Fontchar Fontchar; typedef struct Subfont Subfont; typedef struct Cachesubf Cachesubf; typedef struct Event Event; typedef struct RGB RGB; struct Point { int x; int y; }; struct Rectangle { Point min; Point max; }; struct Bitmap { Rectangle r; /* rectangle in data area, local coords */ Rectangle clipr; /* clipping region */ int ldepth; int id; /* as known by the X server */ Bitmap *cache; /* zero; distinguishes bitmap from layer */ int flag; /* flag used by X implementation of libg */ }; struct Mouse { int buttons; /* bit array: LMR=124 */ Point xy; unsigned long msec; }; struct Cursor { Point offset; unsigned char clr[2*16]; unsigned char set[2*16]; int id; /* init to zero; used by library */ }; struct Menu { char **item; char *(*gen)(int); int lasthit; }; /* * Subfonts: * * The "true width", cwidth, is the sum of the left and right * bearings of the character - the number of pixels actually * occupied by the glyph. The width, supplied by the server and * stored in field "width", is the number of pixels to advance to * the right beyond the origin of the current character to the origin * of the next character. */ struct Fontchar { short cwidth; /* width of glyph */ unsigned char top; /* first non-zero scan-line */ unsigned char bottom; /* last non-zero scan-line */ signed char left; /* offset of baseline */ unsigned char width; /* advance to next char's origin */ }; struct Subfont { int minrow; /* first character row in font (for X subfonts) */ int mincol; /* first character col in font (for X subfonts) */ int minchar; /* first char code in subfont */ int maxchar; /* last char code in subfont */ int width; /* number of chars in row */ int n; /* number of chars in font */ unsigned char height; /* height of bitmap */ char ascent; /* top of bitmap to baseline */ Fontchar *info; /* n+1 character descriptors */ int id; /* of font */ }; struct Cachesubf { Rune min; /* rune value of 0th char in subfont */ Rune max; /* rune value+1 of last char in subfont */ char *name; Subfont *f; /* attached subfont */ }; struct Font { char *name; unsigned char height; /* max height of bitmap, interline spacing */ char ascent; /* top of bitmap to baseline */ char width; /* widest so far; used in caching only */ char ldepth; /* of images */ short id; /* of font */ unsigned short nsubf; /* number of subfonts */ Cachesubf *subf; /* as read from file */ }; struct Event { int kbdc; Mouse mouse; int n; /* number of characters in mesage */ unsigned char data[EMAXMSG]; /* message from an arbitrary file descriptor */ }; struct RGB { unsigned long red; unsigned long green; unsigned long blue; }; /* * Codes for bitblt etc. * * D * 0 1 * --------- * 0 | 1 | 2 | * S |---|---| * 1 | 4 | 8 | * --------- * * Usually used as D|S; DorS is so tracebacks are readable. */ typedef enum Fcode { Zero = 0x0, DnorS = 0x1, DandnotS = 0x2, notS = 0x3, notDandS = 0x4, notD = 0x5, DxorS = 0x6, DnandS = 0x7, DandS = 0x8, DxnorS = 0x9, D = 0xA, DornotS = 0xB, S = 0xC, notDorS = 0xD, DorS = 0xE, F = 0xF } Fcode; /* * Miscellany */ typedef void (*Errfunc)(char *); extern Point add(Point, Point); extern Point sub(Point, Point); extern Point mul(Point, int); extern Point divpt(Point, int); extern Rectangle rsubp(Rectangle, Point); extern Rectangle raddp(Rectangle, Point); extern Rectangle inset(Rectangle, int); extern Rectangle rmul(Rectangle, int); extern Rectangle rdiv(Rectangle, int); extern Rectangle rshift(Rectangle, int); extern int rectinrect(Rectangle , Rectangle ); extern Rectangle rcanon(Rectangle); extern Bitmap* balloc(Rectangle, int); extern void bfree(Bitmap*); extern int rectclip(Rectangle*, Rectangle); extern void xtbinit(Errfunc, char*, int*, char**, char**); extern void bclose(void); extern void berror(char*); extern void bitblt(Bitmap*, Point, Bitmap*, Rectangle, Fcode); extern void copymasked(Bitmap*, Point, Bitmap*, Bitmap*, Rectangle); extern int bitbltclip(void*); extern Subfont* getsubfont(char*); extern Font *rdfontfile(char*, int); extern void ffree(Font*); extern Font *mkfont(Subfont*); extern void subffree(Subfont*); extern int cachechars(Font*, char**, void*, int, int*, unsigned short*); extern Point string(Bitmap*, Point, Font*, char*, Fcode); extern void segment(Bitmap*, Point, Point, int, Fcode); extern void point(Bitmap*, Point, int, Fcode); extern void arc(Bitmap*, Point, Point, Point, int, Fcode); extern void circle(Bitmap*, Point, int, int, Fcode); extern void disc(Bitmap*, Point, int, int, Fcode); extern void ellipse(Bitmap*, Point, int, int, int, Fcode); extern void polysegment(Bitmap *, int, Point *, int, Fcode); extern long strwidth(Font*, char*); extern Point strsize(Font*, char*); extern long charwidth(Font*, Rune); extern void texture(Bitmap*, Rectangle, Bitmap*, Fcode); extern void wrbitmap(Bitmap*, int, int, unsigned char*); extern void rdbitmap(Bitmap*, int, int, unsigned char*); extern void wrbitmapfile(int, Bitmap*); extern Bitmap* rdbitmapfile(int); extern int ptinrect(Point, Rectangle); extern int rectXrect(Rectangle, Rectangle); extern int eqpt(Point, Point); extern int eqrect(Rectangle, Rectangle); extern void border(Bitmap*, Rectangle, int, Fcode); extern void cursorswitch(Cursor*); extern void cursorset(Point); extern Rectangle bscreenrect(Rectangle*); extern void bflush(void); extern int clipline(Rectangle, Point*, Point*); extern int clipr(Bitmap*, Rectangle); extern int scrpix(int*,int*); extern void einit(unsigned long); extern unsigned long estart(unsigned long, int, int); extern void estop(unsigned long); extern unsigned long etimer(unsigned long, long); extern void estoptimer(unsigned long); extern unsigned long event(Event*); extern unsigned long eread(unsigned long, Event*); extern Mouse emouse(void); extern int ekbd(void); extern int ecanread(unsigned long); extern int ecanmouse(void); extern int ecankbd(void); extern void ereshaped(Rectangle); /* supplied by user */ extern void eflush(unsigned long); extern int menuhit(int, Mouse*, Menu*); extern Rectangle getrect(int, Mouse*); extern unsigned long rgbpix(Bitmap*, RGB); extern void rdcolmap(Bitmap*, RGB*); extern void wrcolmap(Bitmap*, RGB*); /* Extra functions supplied by libXg */ extern int snarfswap(char*, int, char**); char* select_get(void); void select_put(char*); extern int scrollfwdbut(void); enum{ Emouse = 1, Ekeyboard = 2 }; extern Point Pt(int, int); extern Rectangle Rect(int, int, int, int); extern Rectangle Rpt(Point, Point); #define Dx(r) ((r).max.x-(r).min.x) #define Dy(r) ((r).max.y-(r).min.y) extern Bitmap screen; extern Font *font, *fixed; #define BGSHORT(p) (((p)[0]<<0) | ((p)[1]<<8)) #define BGLONG(p) ((BGSHORT(p)<<0) | (BGSHORT(p+2)<<16)) #define BPSHORT(p, v) ((p)[0]=(v), (p)[1]=((v)>>8)) #define BPLONG(p, v) (BPSHORT(p, (v)), BPSHORT(p+2, (v)>>16)) #endif wily-0.13.42/include/Makelib000064402366570000012000000002401033320152300154020ustar00ozstaff00004330000002all install: $(LIB) clean: rm -f *.o *pure* .pure test nuke: clean rm -f $(LIB) $(LIB): $(OBJS) $(AR) rv $(LIB) $(OBJS) $(RANLIB) $(LIB) # $(LIB)(%.o): %.o wily-0.13.42/acconfig.h000064402366570000012000000002611033320152300144150ustar00ozstaff00004330000002#undef HAVE_ULONG #undef HAVE_USHORT #undef HAVE_UINT #undef HAVE_UCHAR #undef HAVE_CADDR_T /* Defined if sprintf returns char * instead of int */ #undef BROKEN_SPRINTF @TOP@