6 HowTo: DBFAWK
Tom Russo edited this page 2026-01-05 14:13:56 -07:00

As much about dbfawk as you are likely to get anywhere else

DBFAWK is a powerful feature of Xastir that allows the user to specify the display properties of an ESRI Shapefile on a file-by-file or type-by-type basis. I found, though, that I needed to write down a procedure for producing new DBFAWK configuration files.

This wiki page has ended up being pretty much the only documentation there is about dbfawk. If you can't find the answer to your question here, please open an issue report on github at https://github.com/Xastir/Xastir/issues.

What's a dbfawk file for?

The basic task of the DBFAWK file is to tell xastir how to display various shapes contained in the corresponding shapefile.

What's in a dbfawk file?

A dbfawk file contains pattern matching rules and variable assignments. When a dbf record (the attributes associated with a shapefile) has an attribute that matches a pattern in the dbfawk file, the code within braces is executed to set variables that xastir uses to determine how (or if) to display the associated shape (line, polygon, or point).

How are dbfawk files located and used?

There are two techniques used by xastir to figure out what dbfawk file to use with a given shapefile. The techniques allow Xastir to use a general dbfawk file for all maps that match a certain pattern, but also allow you to specify alternate rendering options for specific maps on a case-by-case basis.

If a file with the same base name as the map but with".dbfawk" at the end exists in the same directory as the map (e.g. "mymap.shp" and "mymap.dbfawk") then it is used by Xastir for rendering that one particular map. Otherwise, xastir scans the dbfawk files in the "/usr/local/share/xastir/config" directory for one with a matching "signature."

The dbf signature is the list of all the attribute names in the dbf file concatenated together with ":" separating them. Generally, when one obtains collections of shapefiles of a particular type from a single source (e.g., OpenStreetMaps road shapefiles, or U.S. National Map Hydrography Features), the signatures are usually the same for all the files in the collection. Thus, one could create a single DBFAWK file that renders all of these maps the same way by matching the signatures.

If you want to override the default rendering of a map for which Xastir already has an existing signature-matching dbfawk file, simply create a new dbfawk file in the same directory as the shapefile, and give it the same base name as the shapefile, but with a ".dbfawk" suffix.

What display functions can I tweak with dbfawk?

dbfawk variableuse
colorsets the color of lines drawn (see below)
lanessets width of lines drawn
namesets the text that will be used as the label for the feature
symbolsets the symbol that will be used for point data (using group/symbol/overlay specification)
fill_colorsets color used to fill area features --- uses same numbers as color variable (below)
fill_stylechooses fill style. At this time only 0 and 2 are worth using. 0 is "solid" and "2" is stippled, per XSetFillStyle. See below.
fill_stippleWhen fill_style is 2, chooses stipple pattern. 0 is a 13 percent stipple, 1 is 25%, 2 is 50%.
patternsets line pattern. 0=solid, 1=dashed, 2="double dash" (per XSetLineAttributes)
display_levelsets zoom above which the feature will be stop being displayed
min_display_levelsets zoom below which the feature will stop being displayed
label_levelsets zoom above which labels will be stop being displayed
label_colorsets color of labels. (see section on selecting colors, below)
font_sizechooses font size. (0="Tiny", 4="Huge", per settings in Map->Configure->Map label fonts menu)
label_methodselects how to choose label points for polygon maps. 0=default, 1="use specified lat/lon"
label_lonthe longitude at which to place the label if label_method=1 and this is a polygon map. Ignored otherwise.
label_latthe latitude for label placement (see label_lon)

This table of dbfawk variables above was taken from map_shp.c on 12 Dec 2025. I don't guarantee that it'll be accurate for long after that. Check map_shp.c for the definitive answer.

I have a new shapefile. How do I get it to display nicely in Xastir with DBFAWK enabled?

If its signature doesn't match an existing dbfawk file, you pretty much have to write your own. Here are the steps I go through when I need to do this.

In a nutshell:

  1. determine what fields the DBF file has
  2. create a dbfawk file to use, possibly copying an existing one and editing the copy
  3. use the list of fields you found in step 1 to set the "dbfinfo" variable in your new dbfawk
  4. decide which of those fields are relevant to your rendering needs and set the "dbffields" variable to include those few fields
  5. craft a dbfawk file that assigns rendering variables (as described above) based on field values it finds
  6. look at how your map renders in Xastir
  7. refine your dbfawk until it looks good

How that works out in detail is described below with an example of how I did it for a shapefile I obtained somewhere and wanted to use as a map.

Given a shapefile and associated DBF file with attributes:

Step 1:

Use "testdbfawk" that is built in the xastir source tree when you compile xastir with DBFAWK enabled to list the fields. For example, I have a set of shapefiles converted from US Forest Service trails, and testdbfawk told me this:

  > testdbfawk -D /usr/local/share/xastir/config -d /usr/local/share/xastir/maps/misc_vector/USFS_SandiaRD
  67 Columns,  544 Records in file
 sig:  FNODE_:TNODE_:LPOLY_:RPOLY_:LENGTH:TRAIL_:TRAIL_ID:TYPE:CODE:CODE_MEMO:METHOD:MISC:TE_UNIT:EXISTVEG:FS_OWN:TRAIL:ROAD:WATER:STREAM:PLSS:ADM_DIST:ADM_UNIT:PASTURE:SPEC_MGT:HRTGSRVY:RD_RTE_NO:TR_RTE_NO:STRM_NAME:SURVEY_NUM:CFF1:CFF2:CFF3:CFF4:CFF5:CFF6:CFF7:CFF8:CFF9:CFF10:NUMBER:NUMBER0:LEVE:TYPE0:ROAD_TYPE:LANES:SURFACE:PROBLEM:CLOSURE:DATE:TIME:OPERATOR:COMMENTS:MAX_PDOP:GPS_DATE:GPS_TIME:GPS_LENGTH:HORZ_PREC:VERT_PREC:HORZ_PRE0:VERT_PRE0:TRAIL_NO:SOURCE:MAPUSE:NAME:MILES2:COOID:STATUS  
[etc.]

The information following "sig:" that this produces is in a format that can be cut and pasted into your dbfawk file to set the dbfinfo value (don't include the "sig:" part!).

This list of attributes will be used in the DBFAWK file to recognize files to which the dbfawk file applies.

Other ways to see the signature It is also possible to use "dbfinfo" (it's part of the shapelib install) to reveal the list of attributes in the DBF file. There's no real benefit do doing that, since the fields are not printed in a way that is easily copied into your dbfawk file, but, hey, you do you.
testdbfawk details testdbfawk is a simple program that expects its arguments to be specified in exactly a certain way. `-D ` is how you tell testdbfawk where to look for signature-based dbfawk files. `-f ` tells it to take the rules directly from the named file. `-d ` gives the filename of the dbf file it should check against the dbfawk rules.

The program requires a space between the flag and the file name in all three cases. It also expects them in a specific order and will not function properly if they are out of order. Give the -D or -f flag first, then the -d.

You can get usage instructions by running testdbfawk -h.

Step 2:

Copy a dbfawk file for a type of map that is close (e.g. tgrlk.dbfawk is a reasonable starting point for line type shapefiles, but it is fairly complex and handles a lot of feature types).

Step 3:

Replace the contents of the "dbfinfo" variable with the fields you found in step 0. e.g., for my USFS shapefiles above, the dbfinfo variable is:

dbfinfo="FNODE_:TNODE_:LPOLY_:RPOLY_:LENGTH:TRAIL_:TRAIL_ID:TYPE:CODE:CODE_MEMO:METHOD:MISC:TE_UNIT:EXISTVEG:FS_OWN:TRAIL:ROAD:WATER:STREAM:PLSS:ADM_DIST:ADM_UNIT:PASTURE:SPEC_MGT:HRTGSRVY:RD_RTE_NO:TR_RTE_NO:STRM_NAME:SURVEY_NUM:CFF1:CFF2:CFF3:CFF4:CFF5:CFF6:CFF7:CFF8:CFF9:CFF10:NUMBER:NUMBER0:LEVE:TYPE0:ROAD_TYPE:LANES:SURFACE:PROBLEM:CLOSURE:DATE:TIME:OPERATOR:COMMENTS:MAX_PDOP:GPS_DATE:GPS_TIME:GPS_LENGTH:HORZ_PREC:VERT_PREC:HORZ_PRE0:VERT_PRE0:TRAIL_NO:SOURCE:MAPUSE:NAME:MILES2:COOID:STATUS";

It is important to put a semicolon at the end of this. Xastir will be confused if you don't.

Step 4:

Figure out which of the godzillion attributes you actually need to examine to get your rendering right. In my case I needed a concatenation of the "NAME" and "TRAIL_NO" fields to form line lables, and the CFF1 field to determine what type of feature I was dealing with. You then make sure the "dbffields" variable has those fields in it. It is best to keep this list to the smallest number of fields you really need to get your rendering right; the rendering code reads only these fields in from the shapefile, so the more fields you put here the more file IO Xastir will be doing for every shape it tries to render. In my case this minimum set was:

       dbffields="CFF1:NAME:TRAIL_NO";

This selects the feature code (CFF), name and trail number. Again, don't forget the semicolon at the end.

NOTE: THE SEMICOLON AT THE END OF DBFFIELDS IS REQUIRED due to a bug in the dbfawk parser. Leaving it off will cause dbfawk to mis-parse the dbffields variable to include all characters up to the closing brace in the BEGIN block. This bug is hidden if there are no characters between the closing quote and brace, but mysteriously shows up if there is a newline. So just put a semicolon at the end for correctness.

Step 5:

Create rules in your dbfawk file that match various patterns that can show up in the attributes. Here's where you set the "name" variable to the appropriate thing you want xastir to display as well as things like line type, color, label color, and how far out you can be zoomed and still see the labels. In my case, sometimes trails are listed in the dbf file as "UNK" and I don't want that name displayed, other times they're listed with a trail number only and I want it to show up as "Tr. #". So I do:

  # Use this rule to re-initialize variables between records.
  # These will be your defaults
  # My defaults are "1 lane, color brown, pattern "LineDoubleDash" (see the 
  #  XSetLineAttributes man page), always display the line, display labels if
  #  zoomed in to level 32 or smaller, black labels, large font) 
  # The defaults are overridden by specific rules below
  BEGIN_RECORD {key=""; lanes=1; color=4; name=""; filled=0; pattern=2; display_level=1; label_level=32; label_color=8; symbol=""; font_size=3}


  # Render hiking trails and unimproved roads
  # This sets the color of the line and pattern based on the feature type
  # Hiking trails are CFF 107.  We'll render these as "two lane" (so they get nice, thick lines), brown (color 69), dashed lines (pattern 1), and only display
  # them if we're zoomed in to levels lower than 128
  /^CFF1=107$/ {lanes=2; color=69; pattern=1;display_level=128;}
  # dashed steel blue lines for class 4 unimproved roads.  These have CFF that start with 106.
  /^CFF1=106*$/ {lanes=2; color=26; pattern=1;display_level=128;}
  # Now look for a name number and/or trail number
  # Never display "UNK" as a trail name
  /^NAME=[uU][nN][kK]$/ {skip;}
  /^TRAIL_NO=[uU][nN][kK]$/ {skip;}
  # Otherwise, select the name given in the record
  /^NAME=(.+)$/ {name="$1";}
  # and append the trail number to the name
  /^TRAIL_NO=(.+)$/ {name="$name (Tr. $1)";}

In this example I set most variables to some default at the beginning of each DBF record, and then look for particular patterns. The USFS maps have an attribute called "CFF1" (CFF stands for Cartographic Feature File) that contains an ID code for the feature type of the corresponding shape. CFF=107 means it's a hiking trail, so I set the zoom level at which the trail will show up to 128, the color to 69 (which is mapped to "brown1" in main.c), and 2 "lanes" that last seems odd, but I found that at zoom level 128 my background rasters always seemed to make "one lane" trails invisible.

Some detail to note about how dbfawk files are structured
  • The `BEGIN` section is really just there for setting dbfinfo and dbffields.
  • The `BEGIN_RECORD` section is executed on every record of the DBF file, before any other rules are processed. It is used to initialize variables that will apply to every shape in the file unless overriden by specific rules later
  • Lines that begin with a pattern starting and ending with "/" are pattern matching rules.
    • On the left side of the equal sign is a field name in your DBF file, on the right a pattern to match using regular expressions.
    • Stuff in the regular expression delimited by parentheses can be referenced in the rule by the strings "$1" through "$9", with "$1" referring to the first parenthesized match, and "$9" the ninth. So in my name-matching line, where I have
      /NAME=(.+)$/"
      "$0" refers to whatever value was matched by ".+" (one or more characters of any type).
  • the stuff in braces following the pattern match are actions to be taken. The only actions available are those that set dbfawk variables, or "next" or "skip".
    • "name=$1" means "set the dbfawk variable 'name' to the value of the string matched by the first parenthesized pattern"
    • "next" means "we're done processing this record", which you would use when a pattern match of this pattern means you should stop considering any other rules in the file for this shape.
    • "skip" means "we're done processing any rules for the field currently being tested, go get the next one". Use this when you don't want any other rules in the file that might also match to apply to this field.

Step 6:

Place your DBFAWK file somewhere where it'll be found. If you have a dbfawk file that applies to many shapefiles, name it something generic and put it in {base}/share/xastir/config. If it's specific to one shapefile, give it the same base name as the shapefile and a .dbfawk suffix and put it in the same directory as the shapefile.

Some caveats There are some dbfawk files in the Xastir repo or that you might find along side users' shapefile collections that don't properly initialize *all* the dbfawk variables in the BEGIN_RECORD line, and sometimes that results in defaults being taken from whatever was used last.

The shape rendering code is written so that each map begins with default values in all variables, so this is less of a problem than it was in the early days of dbfawk. Having the code initialize every variable like this is important as well, because it means that when we add a new feature users don't have to go back and add initialization of those new variables to every dbfawk file ever created.

But you can still wind up with wierd behavior if you fail to reinitialize variables in BEGIN_RECORD when some rule changes a value that isn't reinitialized because a developer added a new feature and forgot to initialize variables --- all subsequent records will then have that changed value until another rule changes it again. If you see weird stuff like that happening, it's a bug. Report it!

The best practice, however, is for the writer of a dbfawk file to make sure to initialize every rendering variable in the BEGIN_RECORD block.

Where do I find out what number corresponds to what color?

Sadly, Xastir's color handling is rather old-school, and you can't just specify a color by giving its RGB values. That's because Xastir still has code designed to work on ancient 8-bit X displays that used a pseudocolor table. Xastir allocates a number of specific colors from the X server when it starts up by calling "GetPixelByName" from color.c and storing them into a "colors" array, and these colors are accessed when needed by their index into that array.

Xastir allocates the colors using the names that are defined in the "xastir.rgb" file that is installed into the "config" directory along with other Xastir files. This file contains the RGB values in the first three columns and a name for that color in the fourth column. If you really want to know what the RGB values of these colors are, find the color name in that file.

The only place you can find information about what index number into the color array corresponds to what color is in main.c. There is no rhyme or reason to the numbering --- colors are simply allocated in whatever order a developer added them, and the numbers are essentially random. Finding the right number for a color you want can be a challenge. For your convenience I've made the following table based on what was in main.c on the day I wrote this section (14 Dec 2025 was the last update), but main.c is the definitive source and I am not going to guarantee that this table will stay up-to-date:

Hex value decimal Color (as xastir.rgb calls it)
0x00 0 DarkGreen DarkGreen
0x01 1 purple purple
0x02 2 DarkGreen DarkGreen
0x03 3 cyan cyan
0x04 4 brown brown
0x05 5 plum plum
0x06 6 orange orange
0x07 7 darkgray darkgray
0x08 8 black
0x09 9 blue blue
0x0a 10 green green
0x0b 11 mediumorchid mediumorchid
0x0c 12 red red
0x0d 13 magenta magenta
0x0e 14 yellow yellow
0x0f 15 white white
0x10 16 black black
0x11 17 black black
0x12 18 black black
0x13 19 black black
0x14 20 lightgray lightgray
0x15 21 magenta magenta
0x16 22 mediumorchid mediumorchid
0x17 23 lightblue lightblue
0x18 24 purple purple
0x19 25 orange2 orange2
0x1a 26 SteelBlue SteelBlue
0x20 32 white white
0x21 33 black black
0x22 34 blue blue
0x23 35 green green
0x24 36 cyan3 cyan3
0x25 37 red red
0x26 38 magenta magenta
0x27 39 yellow yellow
0x28 40 gray35 gray35
0x29 41 gray27 gray27
0x2a 42 blue4 blue4
0x2b 43 green4 green4
0x2c 44 cyan4 cyan4
0x2d 45 red4 red4
0x2e 46 magenta4 magenta4
0x2f 47 yellow4 yellow4
0x30 48 gray53 gray53
0x40 64 yellow yellow
0x41 65 DarkOrange3 DarkOrange3
0x42 66 purple purple
0x43 67 gray80 gray80
0x44 68 red3 red3
0x45 69 brown1 brown1
0x46 70 brown3 brown3
0x47 71 blue4 blue4
0x48 72 DeepSkyBlue DeepSkyBlue
0x49 73 DarkGreen DarkGreen
0x4a 74 red2 red2
0x4b 75 green3 green3
0x4c 76 MediumBlue MediumBlue
0x4d 77 white white
0x4e 78 gray53 gray53
0x4f 79 gray35 gray35
0x50 80 gray27 gray27
0x51 81 black black
0x52 82 LimeGreen LimeGreen
0x60 96 HotPink HotPink
0x61 97 RoyalBlue RoyalBlue
0x62 98 orange3 orange3
0x63 99 yellow3 yellow3
0x64 100 ForestGreen ForestGreen
0x65 101 DodgerBlue DodgerBlue
0x66 102 cyan2 cyan2
0x67 103 plum2 plum2
0x68 104 MediumBlue MediumBlue
0x69 105 gray86 gray86
0x6a 106 tgr_prird_1 tgr_prird_1
0x6b 107 tgr_prird_2 tgr_prird_2
108-111 unset and used
0x70 112 RosyBrown2 RosyBrown2
0x71 113 gray81 gray81
0x72 114 tgr_park_1 tgr_park_1
0x73 115 tgr_city_1 tgr_city_1
0x74 116 tgr_forest_1 tgr_forest_1
0x75 117 tgr_water_1 tgr_water_1
0x76 118 cividis_1 cividis_1
0x77 119 cividis_2 cividis_2
0x78 120 cividis_3 cividis_3
0x79 121 cividis_4 cividis_4
0x7a 122 cividis_5 cividis_5
0x7b 123 cividis_6 cividis_6
0x7c 124 cividis_7 cividis_7
0x7d 125 cividis_8 cividis_8
0x7e 126 cividis_9 cividis_9
0x7f 127 set1_1 set1_1
0x80 128 set1_2 set1_2
0x81 129 set1_3 set1_3
0x82 130 set1_4 set1_4
0x83 131 set1_5 set1_5
0x84 132 set1_6 set1_6
0x85 133 set1_7 set1_7
0x86 134 set1_8 set1_8
0x87 135 set1_9 set1_9
136-253 unset and unused
0xfe 254 pink pink