[GRASS-SVN] r37413 - in grass-addons/ps: . ps.output

svn_grass at osgeo.org svn_grass at osgeo.org
Sun May 24 07:11:46 EDT 2009


Author: ejtizado
Date: 2009-05-24 07:11:46 -0400 (Sun, 24 May 2009)
New Revision: 37413

Added:
   grass-addons/ps/ps.output/
   grass-addons/ps/ps.output/Makefile
   grass-addons/ps/ps.output/cat_val.c
   grass-addons/ps/ps.output/colors.c
   grass-addons/ps/ps.output/colors.h
   grass-addons/ps/ps.output/conversion.h
   grass-addons/ps/ps.output/description.html
   grass-addons/ps/ps.output/draws.h
   grass-addons/ps/ps.output/eps.c
   grass-addons/ps/ps.output/fonts.c
   grass-addons/ps/ps.output/fonts.h
   grass-addons/ps/ps.output/frames.c
   grass-addons/ps/ps.output/frames.h
   grass-addons/ps/ps.output/grids.h
   grass-addons/ps/ps.output/input.c
   grass-addons/ps/ps.output/legends.c
   grass-addons/ps/ps.output/legends.h
   grass-addons/ps/ps.output/lines.c
   grass-addons/ps/ps.output/lines.h
   grass-addons/ps/ps.output/load_raster.c
   grass-addons/ps/ps.output/local_proto.h
   grass-addons/ps/ps.output/main.c
   grass-addons/ps/ps.output/notes.h
   grass-addons/ps/ps.output/palettes.c
   grass-addons/ps/ps.output/palettes.h
   grass-addons/ps/ps.output/papers.c
   grass-addons/ps/ps.output/papers.h
   grass-addons/ps/ps.output/proj_geo.c
   grass-addons/ps/ps.output/ps.output.tmp.html
   grass-addons/ps/ps.output/ps3_map.c
   grass-addons/ps/ps.output/ps_info.h
   grass-addons/ps/ps.output/r_draw.c
   grass-addons/ps/ps.output/r_font.c
   grass-addons/ps/ps.output/r_frame.c
   grass-addons/ps/ps.output/r_grid.c
   grass-addons/ps/ps.output/r_line.c
   grass-addons/ps/ps.output/r_maparea.c
   grass-addons/ps/ps.output/r_note.c
   grass-addons/ps/ps.output/r_palette.c
   grass-addons/ps/ps.output/r_paper.c
   grass-addons/ps/ps.output/r_raster.c
   grass-addons/ps/ps.output/r_rlegend.c
   grass-addons/ps/ps.output/r_scalebar.c
   grass-addons/ps/ps.output/r_vareas.c
   grass-addons/ps/ps.output/r_vlegend.c
   grass-addons/ps/ps.output/r_vlines.c
   grass-addons/ps/ps.output/r_vpoints.c
   grass-addons/ps/ps.output/raster.c
   grass-addons/ps/ps.output/raster.h
   grass-addons/ps/ps.output/rlegend.h
   grass-addons/ps/ps.output/scalebar.h
   grass-addons/ps/ps.output/scanners.c
   grass-addons/ps/ps.output/set_draw.c
   grass-addons/ps/ps.output/set_geogrid.c
   grass-addons/ps/ps.output/set_grid.c
   grass-addons/ps/ps.output/set_mask.c
   grass-addons/ps/ps.output/set_note.c
   grass-addons/ps/ps.output/set_outline.c
   grass-addons/ps/ps.output/set_ps.c
   grass-addons/ps/ps.output/set_raster.c
   grass-addons/ps/ps.output/set_rlegend.c
   grass-addons/ps/ps.output/set_scalebar.c
   grass-addons/ps/ps.output/set_vector.c
   grass-addons/ps/ps.output/set_vlegend.c
   grass-addons/ps/ps.output/start_map.c
   grass-addons/ps/ps.output/symbol.c
   grass-addons/ps/ps.output/val_list.c
   grass-addons/ps/ps.output/vareas.h
   grass-addons/ps/ps.output/vector.c
   grass-addons/ps/ps.output/vector.h
   grass-addons/ps/ps.output/vlegend.h
   grass-addons/ps/ps.output/vlines.h
   grass-addons/ps/ps.output/vpoints.h
Log:
Output postscript-3 maps 


Added: grass-addons/ps/ps.output/Makefile
===================================================================
--- grass-addons/ps/ps.output/Makefile	                        (rev 0)
+++ grass-addons/ps/ps.output/Makefile	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,20 @@
+MODULE_TOPDIR = ../..
+
+PGM=ps.output
+PROLOG=$(ETC)/paint/prolog.ps
+
+LIBES     = $(VECTLIB) $(GPROJLIB) $(SYMBLIB) $(GISLIB) $(DATETIMELIB) $(IMAGERYLIB) $(GMATHLIB)
+DEPENDENCIES = $(VECTDEP) $(SYMBDEP) $(GISDEP) $(DATETIDEP) $(IMAGERYDEP) $(GMATHDEP) \
+               colors.h fonts.h lines.h frames.h ps_info.h local_proto.h
+
+EXTRA_INC = $(VECT_INC) $(PROJINC)
+EXTRA_CFLAGS = $(VECT_CFLAGS)
+
+include $(MODULE_TOPDIR)/include/Make/Module.make
+
+default: cmd patt
+
+patt:
+	$(MKDIR) $(ETC)/paint/patterns/
+	$(INSTALL_DATA) patterns/*.eps $(ETC)/paint/patterns/
+

Added: grass-addons/ps/ps.output/cat_val.c
===================================================================
--- grass-addons/ps/ps.output/cat_val.c	                        (rev 0)
+++ grass-addons/ps/ps.output/cat_val.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,105 @@
+/* File: cat_val.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+
+#include <grass/dbmi.h>
+#include <grass/glocale.h>
+#include "vector.h"
+
+/* LOAD CAT_VAL */
+int load_catval_array(VECTOR *vector, const char *colname, dbCatValArray *cvarr)
+{
+    int n_records;
+    struct field_info *Fi;
+    dbDriver *driver;
+
+    db_CatValArray_init(cvarr);
+
+    Fi = Vect_get_field(&(vector->Map), vector->layer);
+    if (Fi == NULL) {
+        G_fatal_error(_("Unable to get layer info for vector map"));
+    }
+
+    driver = db_start_driver_open_database(Fi->driver, Fi->database);
+    if (driver == NULL)
+        G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
+                      Fi->database, Fi->driver);
+
+    n_records = db_select_CatValArray(driver, Fi->table, Fi->key, colname, NULL, cvarr);
+
+    if (n_records < 0)
+        G_fatal_error(_("Unable to select data from table"));
+
+    db_close_database_shutdown_driver(driver);
+
+    return n_records;
+}
+
+
+/* GET CAT_VAL */
+
+/* return a double number from a dbCatValArray */
+int get_number(dbCatValArray *cvarr, int cat, double *d)
+{
+    int ret, int_val;
+    dbCatVal *cv = NULL;
+
+    *d = -1.;
+
+    if (cvarr->ctype == DB_C_TYPE_INT)
+    {
+        ret = db_CatValArray_get_value_int(cvarr, cat, &int_val);
+        if (ret != DB_OK) {
+            G_warning(_("No record for category [%d]"), cat);
+        }
+        else
+            *d = (double)int_val;
+    }
+    else if (cvarr->ctype == DB_C_TYPE_DOUBLE)
+    {
+        ret = db_CatValArray_get_value_double(cvarr, cat, d);
+        if (ret != DB_OK) {
+            G_warning(_("No record for category [%d]"), cat);
+        }
+    }
+    else if (cvarr->ctype == DB_C_TYPE_STRING)
+    {
+        ret = db_CatValArray_get_value(cvarr, cat, &cv);
+        if (ret != DB_OK) {
+            G_warning(_("No record for category [%d]"), cat);
+        }
+        else
+            *d = atof(db_get_string(cv->val.s));
+    }
+
+    return 1;
+}
+
+/* return a string from a dbCatValArray */
+char * get_string(dbCatValArray *cvarr, int cat)
+{
+    int ret;
+    dbCatVal *cv = NULL;
+    char *str = NULL;
+
+    if (cvarr->ctype == DB_C_TYPE_STRING)
+    {
+        ret = db_CatValArray_get_value(cvarr, cat, &cv);
+        if (ret != DB_OK) {
+            G_warning(_("No record for category [%d]"), cat);
+        }
+        else
+            str = db_get_string(cv->val.s);
+    }
+    else {
+        G_warning(_("It is not a string field [%d]"), cat);
+    }
+    return str;
+}

Added: grass-addons/ps/ps.output/colors.c
===================================================================
--- grass-addons/ps/ps.output/colors.c	                        (rev 0)
+++ grass-addons/ps/ps.output/colors.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,81 @@
+/* File: colors.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <grass/gis.h>
+#include "colors.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+
+void unset_color(PSCOLOR *color)
+{
+    color->none = 1;
+    color->r = color->g = color->b = 0.;
+}
+
+int set_color_name(PSCOLOR *color, char *name)
+{
+    int R, G, B;
+
+    if (strcmp(name, "none") == 0)
+    {
+        unset_color(color);
+        return 1;
+    }
+    /* standard GRASS colors */
+    if (G_str_to_color(name, &R, &G, &B) == 1)
+    {
+        set_color_rgb(color, R, G, B);
+        return 1;
+    }
+    /* PS3 palette colors */
+    if (PS_str_to_color(name, color) == 1)
+    {
+        return 1;
+    }
+    unset_color(color);
+    return 0;
+}
+
+void set_color_rgb(PSCOLOR *color, int r, int g, int b)
+{
+    color->none = 0;
+
+    color->r = (double)r / 255.;
+    color->g = (double)g / 255.;
+    color->b = (double)b / 255.;
+}
+
+/* PostScript shortcut */
+
+void set_ps_color(PSCOLOR *color)
+{
+    if (!color->none)
+        fprintf(PS.fp, "%.3f %.3f %.3f C ",
+                color->r, color->g, color->b);
+}
+
+int set_ps_grey(PSCOLOR *color)
+{
+    if (!color->none)
+        fprintf(PS.fp, "%.3f %.3f %.3f CG ",
+                color->r, color->g, color->b);
+    return 0;
+}
+
+void set_ps_rgb(int R, int G, int B)
+{
+    fprintf(PS.fp, "%.3f %.3f %.3f C ",
+            (double)R/255., (double)G/255., (double)B/255.);
+}
+
+

Added: grass-addons/ps/ps.output/colors.h
===================================================================
--- grass-addons/ps/ps.output/colors.h	                        (rev 0)
+++ grass-addons/ps/ps.output/colors.h	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,21 @@
+#ifndef _PSCOLOR_H_
+#define _PSCOLOR_H_
+
+/* Header file: colors.h
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+typedef struct
+{
+    int none;
+    double r, g, b;
+    double a;
+} PSCOLOR;
+
+#endif

Added: grass-addons/ps/ps.output/conversion.h
===================================================================
--- grass-addons/ps/ps.output/conversion.h	                        (rev 0)
+++ grass-addons/ps/ps.output/conversion.h	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,23 @@
+#ifndef __CONVERSION_H__
+#define __CONVERSION_H__
+
+#define KILOMETERS_TO_METERS    1000.0
+#define FEET_TO_METERS          0.3048
+#define MILES_TO_METERS         1609.344
+#define NAUT_MILES_TO_METERS    1852.0
+
+#define METERS_TO_INCHES        (1./0.0254)
+#define FEET_TO_INCHES          12.
+#define MILES_TO_INCHES         63360.
+#define NAUT_MILES_TO_INCHES    (9260000./127)
+#define YARD_TO_INCHES          36.
+
+#define INCH_TO_POINT           72.
+#define MM_TO_POINT             (360./127.)
+#define CM_TO_POINT             (3600./127.)
+#define MT_TO_POINT             (360000./127.)
+
+#define POINT_TO_MM             (127./360.)
+#define POINT_TO_MT             (127./360000.)
+
+#endif

Added: grass-addons/ps/ps.output/description.html
===================================================================
--- grass-addons/ps/ps.output/description.html	                        (rev 0)
+++ grass-addons/ps/ps.output/description.html	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,638 @@
+<H2>DESCRIPTION</H2>
+
+<EM>ps.output</EM> is a cartographic mapping program for producing high quality
+hardcopy maps in PostScript-3 format. Output can include a raster map, any
+number of vector overlays, notes, decorations, and other spatial data.
+
+<P>
+A file of mapping instructions that describes the various spatial and textual
+information to be printed must be prepared prior to running <EM>ps.output</EM>.
+
+
+<H2>NOTES</H2>
+
+<P>
+The order of commands is generally unimportant but may affect how some layers
+are drawn. For example to plot <B>vpoints</B> above <B>vareas</B> list the
+<B>vpoints</B> entry first. Raster maps are always drawn first, and only a
+single raster map and an optional background may be used
+(or 3 if part of a RGB group).
+
+<P>
+The hash character ('<tt>#</tt>') may be used at the beginning of a line
+to indicate that the line is a comment. Blank lines will also be ignored.
+
+<P>
+Be aware that some mapping instructions require the <i>end</i> command
+and some do not. Any instruction that allows subcommands will require
+it, any instruction that does not allow subcommands will not.
+
+<P>
+The resolution and extent of raster maps plotted with <EM>ps.output</EM> are controlled by the current region settings via the <a href="g.region.html">g.region</a> module. The output filesize is largely a function of the region resolution, so special care should be taken if working with large raster datasets.
+For example if the desired output is Letter sized paper at 300dpi, with 1" margins and the raster filling the entire page, the usable area on the page will be 6.5" x 9", which at 300 dots/inch is equivalent to a region of 1950 columns x 2700 rows (see "<tt>g.region -p</tt>"). Any higher resolution settings will make the output file larger, but with a consumer printer you probably won't be able to resolve any better detail in the hardcopy.
+
+<P>
+The user can specify negative or greater than 100 percentage values for positioning several map decorations and embedded EPS-files, to move them outside the current map box region (for example to position a caption, barscale, or legend above or below the map box).
+
+<P>
+One "pixel" is 1/72 of an inch or 127/360 (~ 0.35) of a millimetre.
+
+<P>
+For users wanting to use special characters (such as accented characters) it is important to note that <em>ps.output</em> uses <tt>ISO-8859-1</tt> encoding. This means that your instructions file will have to be encoded in this encoding. If you normally work in a different encoding environment (such as <tt>UTF-8</tt>), you have to transform your file to the <tt>ISO-8859-1</tt> encoding, for example by using the <tt>iconv</tt> utility:
+</P>
+<DIV class="code"><PRE>
+iconv -f UTF-8 -t ISO_8859-1 utf_file > iso_file
+</PRE></DIV>
+
+
+<P><P>
+
+<H2>MAPPING INSTRUCTIONS</H2>
+
+The mapping instructions allow the user to specify various spatial data to be plotted. These instructions are normally prepared in a regular text file using a system editor. Except <em>scale</em>, all instructions are multiple line followed by a subsection of one or more additional instructions and are terminated with an <i>end</i> instruction.
+<P>
+
+<h3>Instruction keywords:</h3>
+
+<a href="#draw">draw</a>&nbsp;<BR>
+<a href="#geogrid">geogrid</a>&nbsp; ERROR IN SOUTH HEMISPHERE<BR>
+<a href="#grid">grid</a>&nbsp;<BR>
+<a href="#maparea">maparea</a>&nbsp;<BR>
+<a href="#note">note</a>&nbsp;<BR>
+<a href="#palette">palette</a>&nbsp; CHECK<BR>
+<a href="#paper">paper</a>&nbsp;<BR>
+<a href="#raster">raster</a>&nbsp;<BR>
+<a href="#rlegend">rlegend</a>&nbsp;<BR>
+<a href="#scale">scale</a>&nbsp;<BR>
+<a href="#scalebar">scalebar</a>&nbsp;<BR>
+<a href="#vareas">vareas</a>&nbsp;<BR>
+<a href="#vlines">vlines</a>&nbsp;<BR>
+<a href="#vpoints">vpoints</a>&nbsp;<BR>
+<a href="#vlegend">vlegend</a>&nbsp;<BR>
+
+
+<h3>Convention in description of instructions:</h3>
+
+<DL>
+<DT><B>#</B> <EM>number</EM>
+<P>
+<DT><B>#-</B> <EM>dimension</EM> name (number with units)
+<DD> Acceptable units are <em>mm</em> (millimeters), <em>cm</em> (centimeters), and <em>inch</em> (inches).
+</DD><P>
+<DT><B>CAT</B> <EM>List of categories</EM> e.g. 1,3,5-7
+<P>
+<DT><B>SQL</B> <EM>SQL where statement</EM> like: vlastnik = 'Cimrman'
+<P>
+<DT><b>T</b> <em>Text</em>
+<P>
+<DT><b>R</b> <em>Raster</em> file or group name if first character is ':'
+<P>
+<DT><b>V</b> <em>Vector</em> file
+<P>
+
+<DT><b>color</b> <em>Color</em> name
+<DD>The color may be either a standard <a name="NAMED_COLORS">GRASS color</a>, a <tt>R:G:B</tt> triplet (e.g '<tt>255:0:0</tt>'), or <tt>none</tt>.
+The following colors names are accepted by <EM>ps.output</EM>:
+<tt>aqua, black, blue, brown, cyan, gray, grey, green, indigo, magenta, orange, purple, red, violet, white, yellow</tt>.
+</DD><P>
+
+<DT><B>font</B> command:
+<PRE>
+font
+    name   [T]
+    size   [#-]
+    color  (color)
+    extend [#]
+end
+</PRE>
+
+<DD>
+The name of the PostScript font. Fonts present in all PostScript implementations are:
+<tt>
+Times-Roman,
+Times-Italic,
+Times-Bold,
+Times-BoldItalic,
+Helvetica,
+Helvetica-Oblique,
+Helvetica-Bold,
+Helvetica-BoldOblique,
+Courier,
+Courier-Oblique,
+Courier-Bold,
+and
+Courier-BoldOblique
+</tt>.
+</DD><P>
+
+<DT><B>frame</B> command:
+<PRE>
+frame
+    where  [#- #-]
+    ref    [left|right|center upper|lower|center]
+    offset [# #]
+    border [#-]
+    color  (color)
+    fcolor (color)
+    margin [#-]
+end
+</PRE>
+
+<DT><B>line</B> command:
+<PRE>
+line
+    width [#-]
+    color (color)
+    style [solid|dashed|dotted|dashdotted|#...]
+    cap   [butt|round|extended_butt]
+end
+</PRE>
+
+<DT><b>COOR</b> <em>Coordinates</em> as pair of <b>east north</b>
+<P>
+
+
+
+
+</DL>
+<P>
+
+
+
+
+<H2>COMPOSE THE MAP</H2>
+
+
+<h3>paper</h3>
+<a name="paper"></a>
+Specifies paper size, margins and orientation.
+
+<PRE>
+USAGE
+<B>paper</B> [paper type], default: A4
+    <B>height</B> [#-]
+    <B>width</B>  [#-]
+    <B>left</B>   [#-], default 0.5inch
+    <B>right</B>  [#-], default 0.5inch
+    <B>bottom</B> [#-], default 1.0inch
+    <B>top</B>    [#-], default 1.0inch
+    <B>landscape</B> [y|N], default N
+<B>end</B>
+</PRE>
+
+<P>
+Paper types: A0-6, B0-6, Executive, Folio, Ledger, Legal, Letter, Tabloid.<BR>
+
+<PRE>
+<i>EXAMPLE</i>
+paper A4
+    left 2cm
+    top 4cm
+    landscape y
+end
+</PRE>
+<P>
+
+
+<h3>scale</h3>
+Selects a scale for the output map.
+
+<PRE>
+USAGE
+<B>scale</B> 1:[#]
+</PRE>
+
+The scale is selected as a relative ratio, e.g. 1:25000. Use maparea to select a specific width of map.
+
+<PRE>
+<i>EXAMPLE</i>
+    scale 1:25000
+</PRE>
+<P>
+
+This example would set the scale of the map to 1 unit = 25000 units.
+
+
+<h3>maparea</h3>
+
+Positions the map area on the page.
+
+<PRE>
+USAGE
+<B>maparea</B>
+    <B>left</B>   [#-]
+    <B>top</B>    [#-]
+    <B>width</B>  [#-]
+    <B>height</B> [#-]
+    <B>border</B> [#-]
+    <B>color</B>  [color]
+ <B>end</B>
+</PRE>
+
+The upper left corner of the map will be positioned <EM>left</EM> units from the left edge of the page and <EM>top</EM> units from the top of the page. If <EM>width</EM> and <EM>height</EM> are present, the map will be rescaled, if necessary, to fit.
+<P>
+
+<em>border</em> and <em>color</em> controls the which and color of the line is drawn around the map area.
+<P>
+
+<PRE>
+<i>EXAMPLE</i>
+maparea
+	left 2cm
+	top 3.5cm
+	border 1mm
+	color black
+end
+</PRE>
+
+This example positions the upper left corner of the map 2.0 cm from the left edge and 3.5 cm from the top edge of the map. And draw a black border of 1 mm of width around the map area.
+
+<h3>palette</h3>
+
+
+
+
+<H2>ADDING COMPONENTS</H2>
+
+<h3>grid</h3>
+<a name="grid"></a>
+Overlays a coordinate grid onto the output map.
+
+<PRE>
+USAGE
+<B>grid</B>
+    <B>major</B>  [#] (line)
+    <B>minor</B>  [#] (line)
+    <B>cross</B>  [#]
+    <B>font</B>   [font]
+    <B>fcolor</B> [color]
+    <B>format</B> [#], number (0-2) or 'in', 'out' or 'iho'
+    <B>round</B>  [#]
+ <B>end</B>
+</PRE>
+
+The <B>line separation</B> of the grid is given (in the geographic coordinate system units) on the main instruction line.  The subsection instructions allow the user to specify the properties of the <B>grid line</B>, whether coordinate <B>numbers</B> should appear on the grid lines, and if they should appear every grid line (1), every other grid line (2), etc., and what <B>font</B> the numbers should be.
+The <B>cross</B> argument draws grid intersection crosses instead of grid lines, with cross size given in geographic coordinate system units. The defaults are black grid lines, unnumbered.
+<P>
+
+<PRE>
+<I>EXAMPLE</I>
+grid
+    major 1000
+        width .1mm
+        color gray
+        style 12
+    end
+    minor 200
+        width .05mm
+        color gray
+        style 12
+    end
+    font
+        name Univers
+        size 7
+        color white
+    end
+    fcolor black
+    format 0
+    round 3
+end
+</PRE>
+
+This example would overlay a gray grid with a spacing of 10000 meters (for a metered database, like UTM) onto the output map.  Alternate grid lines would be numbered with white numbers on black boxes.
+
+
+<h3>geogrid</h3>
+<a name="geogrid"></a>
+
+<PRE>
+USAGE
+<B>geogrid</B>
+    <B>major</B>  [#] (line)
+    <B>minor</B>  [#] (line)
+    <B>font</B>   [font]
+    <B>fcolor</B> [color]
+    <B>format</B> [#], number (0-1) or 'in' or 'out'
+ <B>end</B>
+</PRE>
+
+<PRE>
+<I>EXAMPLE</I>
+geogrid
+    format out
+    major 30'
+        width .3
+        color magenta
+    end
+    minor 5'
+        width .1
+        color magenta
+        style 1
+    end
+    font
+        name Univers
+        size 5
+        color black
+        extend 1.2
+    end
+    fcolor none
+end
+</PRE>
+
+
+<H3>scalebar</H3>
+<a name="scalebar"></a>
+
+<PRE>
+<I>USAGE</I>
+<B>scalebar</B>   [scalebar type]
+    <B>length</B> [#]
+    <B>units</B>  [code T]
+    <B>major</B>  [# #], divisions and seperation text label
+    <B>minor</B>  [# #], divisions and seperation text label
+    <B>frame</B>  [frame]
+    <B>font</B>   [font]
+    <B>height</B> [#-]
+    <B>fcolor</B> [color]
+<B>end</B>
+</PRE>
+
+Scalebar types: I F f S s
+
+<PRE>
+<I>EXAMPLE</I>
+scalebar f
+    frame
+        where 50% 0%
+        offset 0 12
+        ref center upper
+        border 0.5mm
+        color black
+        fcolor gray
+    end
+    font
+        name Univers
+        size 8
+        color black
+    end
+    length 20
+    units km Kilometers
+    major 5 2
+    minor 2 2
+    height 2mm
+end
+</PRE>
+
+
+<h3>note</h3>
+<a name="note"></a>
+
+<PRE>
+USAGE
+<B>note</B> [code T]
+    <B>frame</B> [frame]
+    <B>font</B> [font]
+    <B>angle</B> [#] in degrees
+ <B>end</B>
+</PRE>
+
+Note codes: :file (filename),
+    :maplim,
+    :dimen,
+    :scale (pre-text)
+    or simple text use '|' to break lines (max 1024 characters)
+
+
+<PRE>
+<I>EXAMPLE</I>
+note :scale scale
+    frame
+        where 0% 0%
+        offset -12 -4
+        ref left lower
+        border 0
+        fcolor none
+    end
+    angle 90
+    font
+        name Univers
+        size 6
+        extend 1.25
+        color gray
+    end
+end
+</PRE>
+
+
+
+<h2>ADDING RASTER MAPS</h2>
+
+<a name="raster"><H3>raster</H3></a>
+Selects a raster map for output.
+
+<PRE>
+<I>USAGE</I>
+<B>raster</B> [R|R R R], required: one raster, one group name (:name) or three raster (RGB)
+    <B>grey</B>      [y|N]. Output in shades of grey.
+    <B>maskcolor</B> [color]. Color to be used for mask.
+    <B>maskcell</B>  [R (R)]. Raster used as mask and optionally a raster for background.
+    <B>outline</B>   [line]. Specifications of outline.
+    <B>setcolor</B>  [cat color]. Overrides the color of cat
+end
+</PRE>
+
+<PRE>
+<I>EXAMPLE</I>
+raster geology
+    grey n
+    maskcolor none
+    maskcell geo_mask elev_state_500m
+    outline
+        width .01
+        color black
+    end
+    setcolor 28 200:123:200
+end
+</PRE>
+
+
+<h2>ADDING VECTOR MAPS</h2>
+
+<a name="vareas"><H3>vareas</H3></a>
+
+<PRE>
+USAGE
+<B>vareas</B> [V]. Vector map name
+    <b>width</b>  [#-], default 0 (positive or negative, permit draw a line as area).
+    <b>layer</b>  [#], default: 1. Layer number used with cats/where option
+    <b>cats</b>   [CAT]
+    <b>where</b>  [SQL].
+    <b>line</b>   (line)
+    <b>fcolor</b> (color) ([T]). Fill color and, optionally RGB column name (also apply to pattern).
+    <b>pat</b>    [T]. Pattern EPS file.
+    <b>scale</b>  [#]
+    <b>pwidth</b> [#]
+    <b>masked</b> [y|N]. Masked by raster mask
+    <b>label</b>  [T]. For description in vlegend
+    <b>lpos</b>   [#]. Position vector is plotted in legend
+<b>end</b>
+</PRE>
+
+<a name="vlines"><H3>vlines</H3></a>
+
+<PRE>
+USAGE
+<B>vlines</B> [V]. Vector map name
+    <b>type</b>   [line|boundary], default: line
+    <b>layer</b>  [#], default: 1. Layer number used with cats/where option
+    <b>cats</b>   [CAT]
+    <b>where</b>  [SQL]
+    <b>line</b>   (line)
+    <b>rgbcol</b> [T]. Column name with line color data
+    <b>hline</b>  [# (line)], default: 0; and enter line command. Offset dimen from midline
+    <b>masked</b> [y|N]. Masked by raster mask
+    <b>label</b>  [T]. For description in vlegend
+    <b>lpos</b>   [#]. Position vector is plotted in legend
+<b>end</b>
+</PRE>
+
+<PRE>
+<i>EXAMPLE</i>
+vlines railroads
+    type line
+    label Rail roads
+    line
+        width .4mm
+        color green
+    end
+    hline
+        width .1mm
+        color black
+    end
+    masked n
+end
+</PRE>
+
+<a name="vpoints"><H3>vpoints</H3></a>
+
+<PRE>
+USAGE
+<B>vpoints</B> [V]. Vector map name
+    <b>type</b>   [point|centroid], default: point
+    <b>layer</b>  [#], default: 1. Layer number used with cats/where option
+    <b>cats</b>   [CAT]
+    <b>where</b>  [SQL]
+    <b>symbol</b> [T]. Symbol standard or EPS file.
+    <b>line</b>   (line)
+    <b>fcolor</b> (color). Fillcolor
+    <b>size</b>   [# ([T])]. Size and optionally size column.
+    <b>scale</b>  [#]. Scale
+    <b>rotate</b> [# ([T])]. Rotate and optionally rotate column.
+    <b>masked</b> [y|N]. Masked by raster mask
+    <b>label</b>  [T]. For description in vlegend
+    <b>lpos</b>   [#]. Position vector is plotted in legend
+<b>end</b>
+</PRE>
+
+<PRE>
+<i>EXAMPLE</i>
+vpoints precip_30ynormals
+    type centroid
+    symbol basic/circle
+    fcolor red
+    line
+        width .2
+        color black
+    end
+    size 10 ANNUAL
+    scale .01
+end
+</PRE>
+
+<h2>ADDING LEGENDS</h2>
+
+<a name="rlegend"><H3>rlegend</H3></a>
+
+<PRE>
+USAGE
+<B>rlegend</B>
+    <b>raster</b>
+    <b>title</b>
+    <b>frame</b>
+    <b>font</b>
+    <b>cols</b>
+    <b>width</b>
+    <b>height</b>
+    <b>tick</b>
+    <b>whiteframe</b>
+<b>end</b>
+</PRE>
+
+<PRE>
+<i>EXAMPLE</i>
+rlegend
+    title Land Class 1996
+        name Univers Bold
+        size 12
+        extend 0.85
+        color black
+    end
+    raster landclass96
+    cols 1 0
+    frame
+        where 100% 100%
+        ref right upper
+        offset 0 0
+        border 2
+        color  black
+        fcolor white
+        margin 8
+    end
+    font
+        name Univers
+        size 9
+        color black
+    end
+    width 8mm
+    height 7cm
+    tick 3
+    whiteframe 1
+end
+</PRE>
+
+<a name="vlegend"><H3>vlegend</H3></a>
+
+<PRE>
+USAGE
+<B>vlegend</B>
+    <b>title</b> (first char point to center)
+    <b>frame</b>
+    <b>font</b>
+    <b>cols</b>
+    <b>width</b>
+    <b>order</b>
+<b>end</b>
+</PRE>
+
+<PRE>
+<i>EXAMPLE</i>
+vlegend
+    title .Leyenda
+        name Univers-Bold
+        size 10
+        extend 1.1
+    end
+    frame
+        where 100% 100%
+        ref left upper
+        offset 10 0
+        border 1
+    end
+    font
+        name Univers
+        size 9
+    end
+#   cols 1
+#   width 1cm
+end
+</PRE>
\ No newline at end of file

Added: grass-addons/ps/ps.output/draws.h
===================================================================
--- grass-addons/ps/ps.output/draws.h	                        (rev 0)
+++ grass-addons/ps/ps.output/draws.h	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,25 @@
+#ifndef _PSDRAW_H_
+#define _PSDRAW_H_
+
+/* Header file: draws.h
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include "fonts.h"
+
+#define MAX_DRAWS    100
+
+typedef struct
+{
+    char * key[MAX_DRAWS];
+    char * data[MAX_DRAWS];
+
+} PSDRAW;
+
+#endif

Added: grass-addons/ps/ps.output/eps.c
===================================================================
--- grass-addons/ps/ps.output/eps.c	                        (rev 0)
+++ grass-addons/ps/ps.output/eps.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,151 @@
+/* File: eps.c
+ *
+ *  COPYRIGHT: (c) GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <math.h>
+#include <string.h>
+#include "ps_info.h"
+#include "local_proto.h"
+
+/*  test if file is realy EPS file and find bbox
+ *  returns  1 if OK
+ *           0 on error
+ */
+int eps_bbox(char *eps, double *llx, double *lly, double *urx, double *ury)
+{
+    char buf[201];
+    FILE *fp;
+    int v1, v2, v3, v4;
+
+    /* test if file is realy eps and find bbox */
+    if ((fp = fopen(eps, "r")) == NULL) {
+	    fprintf(stderr, "can't open eps file <%s>\n", eps);
+	return (0);
+    }
+    /* test if first row contains '%!PS-Adobe-m.n EPSF-m.n' string */
+    fgets(buf, 200, fp);
+    if (sscanf(buf, "%%!PS-Adobe-%d.%d EPSF-%d.%d", &v1, &v2, &v3, &v4) < 4) {
+    	fprintf(stderr, "file <%s> is not in EPS format\n", eps);
+	    fclose(fp);
+	return (0);
+    }
+    /* looking for bbox */
+    while (fgets(buf, 200, fp) != NULL) {
+	    if (sscanf(buf, "%%%%BoundingBox: %lf %lf %lf %lf", llx, lly, urx, ury) == 4) {
+	        fclose(fp);
+	        return (1);
+	    }
+    }
+    fprintf(stderr, "Bounding box in eps file <%s> was not found\n", eps);
+    fclose(fp);
+    return (0);
+}
+
+/* calculate translation for EPS file
+ * rotate is in degrees
+ */
+int eps_trans(double llx, double lly, double urx, double ury,
+	      double x, double y, double scale, double rotate,
+	      double *xt, double *yt)
+{
+    double xc, yc, angle;
+
+    xc = (llx + urx) / 2;
+    yc = (lly + ury) / 2;
+
+    angle = M_PI * rotate / 180;
+    *xt = x + scale * (yc * sin(angle) - xc * cos(angle));
+    *yt = y - scale * (yc * cos(angle) + xc * sin(angle));
+
+    return (1);
+}
+
+/* save EPS file into PS file for later use */
+int eps_save(FILE * fp, char *epsf, char *name)
+{
+    char buf[1024];
+    FILE *epsfp;
+
+    if ((epsfp = fopen(epsf, "r")) == NULL)
+	return (0);
+
+    fprintf(fp, "\n/%s {\n", name);
+    while (fgets(buf, 1024, epsfp) != NULL)
+	fprintf(fp, "%s", buf);
+    fprintf(fp, "} def\n");
+    fclose(epsfp);
+
+    return (1);
+}
+
+/* draw EPS file saved by eps_save */
+int eps_draw_saved(FILE * fp, char *name, double x, double y, double scale,
+		   double rotate)
+{
+    fprintf(PS.fp, "\nBeginEPSF\n");
+    fprintf(PS.fp, "%.5f %.5f translate\n", x, y);
+    fprintf(PS.fp, "%.5f rotate\n", rotate);
+    fprintf(PS.fp, "%.5f %.5f scale\n", scale, scale);
+    fprintf(PS.fp, "%%BeginDocument: %s\n", name);
+
+    fprintf(PS.fp, "%s\n", name);
+
+    fprintf(PS.fp, "%%EndDocument\n");
+    fprintf(PS.fp, "EndEPSF\n");
+
+    return (1);
+}
+
+
+/* write EPS file into PS file */
+int eps_draw(FILE * fp, char *eps, double x, double y, double scale,
+	     double rotate)
+{
+    char buf[1024];
+    FILE *epsfp;
+
+    if ((epsfp = fopen(eps, "r")) == NULL)
+	return (0);
+
+    fprintf(PS.fp, "\nBeginEPSF\n");
+    fprintf(PS.fp, "%.5f %.5f translate\n", x, y);
+    fprintf(PS.fp, "%.5f rotate\n", rotate);
+    fprintf(PS.fp, "%.5f %.5f scale\n", scale, scale);
+    fprintf(PS.fp, "%%BeginDocument: %s\n", eps);
+
+    while (fgets(buf, 1024, epsfp) != NULL)
+	fprintf(fp, "%s", buf);
+
+    fprintf(PS.fp, "%%EndDocument\n");
+    fprintf(PS.fp, "EndEPSF\n");
+    fclose(epsfp);
+
+    return (1);
+}
+
+/* save EPS patter file into PS file for later use */
+/* For pattern we have to remove header comments */
+int pat_save(FILE * fp, char *epsf, char *name)
+{
+    char buf[1024];
+    FILE *epsfp;
+
+    if ((epsfp = fopen(epsf, "r")) == NULL)
+	return (0);
+
+    fprintf(fp, "\n/%s {\n", name);
+    while (fgets(buf, 1024, epsfp) != NULL) {
+	if (strncmp(buf, "%!PS-Adobe", 10) == 0 ||
+	    strncmp(buf, "%%BoundingBox", 13) == 0)
+	    continue;
+	fprintf(fp, "%s", buf);
+    }
+    fprintf(fp, "} def\n");
+    fclose(epsfp);
+
+    return (1);
+}

Added: grass-addons/ps/ps.output/fonts.c
===================================================================
--- grass-addons/ps/ps.output/fonts.c	                        (rev 0)
+++ grass-addons/ps/ps.output/fonts.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,36 @@
+/* File: fonts.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "ps_info.h"
+#include "local_proto.h"
+#include "fonts.h"
+
+double set_ps_font_nocolor(PSFONT *font)
+{
+    if (font->extend == 1. || font->extend <= 0.)
+    {
+        fprintf(PS.fp, "(%s) FN %.1f FS\n",
+                font->name, font->size);
+    }
+    else
+    {
+        fprintf(PS.fp, "(%s) FN %.1f %.2f FE\n",
+                font->name, font->size, font->extend);
+    }
+    return font->size;
+}
+
+double set_ps_font(PSFONT *font)
+{
+    set_ps_color(&(font->color));
+    set_ps_font_nocolor(font);
+}

Added: grass-addons/ps/ps.output/fonts.h
===================================================================
--- grass-addons/ps/ps.output/fonts.h	                        (rev 0)
+++ grass-addons/ps/ps.output/fonts.h	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,24 @@
+#ifndef _PSFONT_H_
+#define _PSFONT_H_
+
+/* Header file: fonts.h
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include "colors.h"
+
+typedef struct
+{
+    char name[50];
+    double size;
+    double extend;
+    PSCOLOR color;
+} PSFONT;
+
+#endif

Added: grass-addons/ps/ps.output/frames.c
===================================================================
--- grass-addons/ps/ps.output/frames.c	                        (rev 0)
+++ grass-addons/ps/ps.output/frames.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,159 @@
+/* File: frames.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include "frames.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+
+/* Postscipt variables: -- */
+void set_box_orig(PSFRAME *box)
+{
+	double x, y;
+
+	if (box->x <= 0.0) {
+        box->x = PS.map_x - PS.map_w * (box->x/100.);
+    }
+    /*
+    else {
+        box->x = 0 + box->x;
+    }
+    */
+	if (box->y <= 0.0) {
+        box->y = PS.map_y - PS.map_h * (box->y/100.);
+    }
+    else {
+		box->y = PS.page.height - box->y;
+    }
+}
+
+/* Postscript variables: mg hg chg wd cwd  */
+void set_box_size(PSFRAME * box, double width, double height)
+{
+    /* Margin "mg" */
+    if (box->margin < 0.)
+        box->margin = 0.;
+    fprintf(PS.fp, "/mg %.4f def\n", box->margin);
+
+    /* Height "hg" and content height "chg" */
+    if (height > 0.) {
+        fprintf(PS.fp, "/hg %.4f def\n", height); /* height */
+        fprintf(PS.fp, "/chg hg mg 2 mul sub def\n"); /* content height */
+    }
+
+    /* Width "wd" and content width "cwd" */
+    if (width > 0.) {
+        fprintf(PS.fp, "/wd %.4f def\n", width);  /* width */
+        fprintf(PS.fp, "/cwd wd mg 2 mul sub def\n"); /* content width */
+    }
+}
+
+/* Draw the box with outer border */
+void set_box_draw(PSFRAME *box)
+{
+    /* Re-location */
+    if (box->xref == RIGHT)
+        fprintf(PS.fp, "/xo %.4f wd sub def\n",
+                box->x + box->xset);
+    else if (box->xref == CENTER)
+        fprintf(PS.fp, "/xo %.4f wd 2 div sub def\n",
+                box->x + box->xset);
+    else
+        fprintf(PS.fp, "/xo %.4f def\n",
+                box->x + box->xset);
+
+    if (box->yref == LOWER)
+        fprintf(PS.fp, "/yo %.4f hg add def\n",
+                box->y + box->yset);
+    else if (box->yref == CENTER)
+        fprintf(PS.fp, "/yo %.4f hg 2 div add def\n",
+                box->y + box->yset);
+    else
+        fprintf(PS.fp, "/yo %.4f def\n",
+                box->y + box->yset);
+
+    /* Draw the border, if set */
+    if (box->border > 0.)
+    {
+        set_ps_color(&(box->color));
+        fprintf(PS.fp, "%.4f LW xo yo wd hg neg RO\n",
+                box->border);
+    }
+
+    /* Make color background, if set */
+    if (!box->fcolor.none)
+    {
+        set_ps_color(&(box->fcolor));
+        fprintf(PS.fp, "xo yo wd hg neg RF\n");
+    }
+}
+
+
+
+/* Postscript auto size with ARh y ARw */
+void set_box_auto(PSFRAME *box, PSFONT *font, double factor)
+{
+    if (factor <= 0.)
+        factor = 0.5; /* standard row height by fontsize */
+
+    /* Initialize */
+    if (box->margin < 0.)
+        box->margin = 0.4 * font->size;
+
+    /* Margins "mg" */
+    fprintf(PS.fp, "/mg %.8f def\n", box->margin);
+
+    /* Height "hg", content height "chg", and interline "dy" */
+    fprintf(PS.fp, "/dy %.4f def\n", factor * font->size); /* standard row sep */
+    fprintf(PS.fp, "/chg dy neg ARh {add dy add} forall def\n"); /* content height */
+    fprintf(PS.fp, "/hg chg mg 2 mul add def\n"); /* height */
+
+    /* Width "wd", content width "cwd", and intercolum "dx" */
+    fprintf(PS.fp, "/dx mg def\n"); /* standard col sep */
+    fprintf(PS.fp, "/cwd dx neg ARw {add dx add} forall def\n"); /* content width */
+    fprintf(PS.fp, "/wd cwd mg 2 mul add def\n"); /* width */
+}
+
+/* Postscript space for a top title  */
+void set_box_readjust_title(PSFRAME *box, const char *title)
+{
+    fprintf(PS.fp, "(%s) SWH ", title);
+    fprintf(PS.fp, "mg add dup hg add /hg XD mg add /mgy XD "); /* adjust height */
+    fprintf(PS.fp, "pop\n"); /* TODO: adjust width */
+}
+
+
+/* Readjust the size of a box with new margins */
+void set_box_readjust(PSFRAME *box,
+                      double left, double top,
+                      double width, double height)
+{
+    if (left > 0.) {
+        if (width >= 0.)
+            width += left;
+        else
+            width = left;
+        fprintf(PS.fp, "/mgx mg %.4f add def\n", left);
+    }
+    if (top > 0.) {
+        if (height >= 0.)
+            height += top;
+        else
+            height = top;
+        fprintf(PS.fp, "/mgy mg %.4f add def\n", top);
+    }
+    if (height > 0.) {
+        fprintf(PS.fp, "/hg hg %.4f add def\n", height);
+    }
+    if (width > 0.) {
+        fprintf(PS.fp, "/wd wd %.4f add def\n", width);
+    }
+}
+

Added: grass-addons/ps/ps.output/frames.h
===================================================================
--- grass-addons/ps/ps.output/frames.h	                        (rev 0)
+++ grass-addons/ps/ps.output/frames.h	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,29 @@
+#ifndef _PSFRAME_H_
+#define _PSFRAME_H_
+
+/* Header file: frames.h
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+
+#include "colors.h"
+
+typedef struct
+{
+    double x, y;          /* left-top corner */
+    double xset, yset;    /* x and y offset */
+    int xref, yref;       /* reference point */
+    double border;        /* outer border width */
+    PSCOLOR color;        /* border color */
+    PSCOLOR fcolor;       /* fill color */
+    double margin;        /* inner margin */
+    double rotate;
+} PSFRAME;
+
+#endif

Added: grass-addons/ps/ps.output/grids.h
===================================================================
--- grass-addons/ps/ps.output/grids.h	                        (rev 0)
+++ grass-addons/ps/ps.output/grids.h	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,34 @@
+#ifndef _PSGRID_H_
+#define _PSGRID_H_
+
+/* Header file: grids.h
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+
+#include "fonts.h"
+#include "lines.h"
+
+typedef struct
+{
+    int sep;         /* major separation between lines */
+    PSLINE line;
+
+    PSFONT font;
+    PSCOLOR fcolor;
+
+    int msep;        /* minor separation between lines */
+    PSLINE mline;
+
+    int format;      /* formats: 0 inner, 1 outer, ... */
+    int round;       /* digits to cut if zero */
+    double cross;    /* length of crosses */
+} GRID;
+
+#endif

Added: grass-addons/ps/ps.output/input.c
===================================================================
--- grass-addons/ps/ps.output/input.c	                        (rev 0)
+++ grass-addons/ps/ps.output/input.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,94 @@
+/* File: input.c
+ *
+ *  COPYRIGHT: (c) GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <grass/gis.h>
+#include "local_proto.h"
+
+extern FILE *inputfd;
+
+/* Get line to buffer */
+int input(int level, char *buf)
+{
+    int i;
+    char command[10], empty[3];
+
+    if (level && isatty(fileno(inputfd)))
+    	fprintf(stdout, "enter 'end' when done, 'exit' to quit\n");
+
+    do
+    {
+        if (level && isatty(fileno(inputfd)))
+        {
+            fprintf(stdout, "%s ", level == 1 ? ">" : ">>");
+        }
+        if (!G_getl2(buf, 1024, inputfd))
+        {
+            if (inputfd != stdin) {
+                fclose(inputfd);
+                inputfd = stdin;
+            }
+            return 0;
+        }
+        if (sscanf(buf, "%5s %1s", command, empty) == 1)
+        {
+            if (strcmp(command, "end") == 0)
+                return 0;
+            if (strcmp(command, "exit") == 0)
+                exit(0);
+        }
+    }
+    while (*buf == '#');
+
+    return 1;
+}
+
+/* Point to key and data */
+int key_data(char *buf, char **k, char **d)
+{
+    char *key, *data;
+
+    key = buf;
+    while (*key && *key <= ' ') key++;
+
+    if (*key == 0) {
+        *k = *d = key;
+        return 0;
+    }
+
+    data = key;
+    while (*data && *data > ' ') data++;
+
+    if (*data)
+        *data++ = 0;
+
+    *k = key;
+    *d = data;
+
+    return 1;
+}
+
+/* Print a error message, and stop */
+int error(char *a, char *b, char *c)
+{
+    char msg[2000];
+
+    sprintf(msg, "%s%s%s : %s", a, *b ? " " : "", b, c);
+
+    if (isatty(0))
+        fprintf(stderr, "%s\n", msg);
+    else
+        G_fatal_error(msg);
+
+    exit(0);
+
+    return 0;
+}

Added: grass-addons/ps/ps.output/legends.c
===================================================================
--- grass-addons/ps/ps.output/legends.c	                        (rev 0)
+++ grass-addons/ps/ps.output/legends.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,63 @@
+/* File: legends.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include "ps_info.h"
+#include "legends.h"
+#include "local_proto.h"
+
+
+void set_legend_adjust(LEGEND *legend, double height)
+{
+	/* Initialize */
+    if (legend->box.margin < 0.)
+        legend->box.margin = 0.4 * legend->font.size;
+
+    if (legend->width < 0.)
+        legend->width = 2.4 * legend->font.size;
+
+    /* Margins "mg", "mgx" and "mgy" */
+    fprintf(PS.fp, "/mg %.5f def\n", legend->box.margin); /* inner box margin */
+    fprintf(PS.fp, "/mgx mg def\n"); /* to RESET and COL */
+    fprintf(PS.fp, "/mgy mg def\n"); /* to RESET and ROW */
+
+    /* Symbol width "syw" and adding to all width columns */
+    fprintf(PS.fp, "/syw %.5f def\n", legend->width); /* symbol width */
+    fprintf(PS.fp, "0 1 ARw length 1 sub {ARw exch dup ARw exch get syw add put} for\n");
+    /* fprintf(PS.fp, "0 1 ARw length -- {ARw exch 2 copy get syw add put} for\n"); */
+
+    /* Height "hg", content height "chg", and interline "dy" */
+    if (height > 0.)
+    {
+        fprintf(PS.fp, "/hg %.5f def\n", height); /* height */
+        fprintf(PS.fp, "/chg hg mg 2 mul sub def\n"); /* content height */
+        fprintf(PS.fp, "/dy ARh length 1 eq {0} {chg ARh {sub} forall ARh length 1 sub div} ifelse def\n"); /* rowsep */
+    }
+    else
+    {
+        fprintf(PS.fp, "/dy %.5f def\n", .5 * legend->font.size); /* standard row sep */
+        fprintf(PS.fp, "/chg dy neg ARh {add dy add} forall def\n"); /* content height */
+        fprintf(PS.fp, "/hg chg mg 2 mul add def\n"); /* height */
+    }
+
+    /* Width "wd", content width "cwd", and colspan "dx" */
+    if (legend->span < 0.) { /* auto-adjust */
+        fprintf(PS.fp, "/wd %.5f def ", -(PS.map_w * legend->span)); /* width */
+        fprintf(PS.fp, "/cwd wd mg 2 mul sub def\n"); /* content width */
+        fprintf(PS.fp, "/dx ARw length 1 eq {0} {cwd ARw {sub} forall ARw length 1 sub div} ifelse def\n"); /* colspan */
+    }
+    else {
+        if (legend->span == 0.)
+            legend->span = legend->box.margin;
+        fprintf(PS.fp, "/dx %.4f def\n", legend->span); /* colspan */
+        fprintf(PS.fp, "/cwd dx neg ARw {add dx add} forall def\n"); /* content width */
+        fprintf(PS.fp, "/wd cwd mg 2 mul add def\n"); /* width */
+    }
+}
+

Added: grass-addons/ps/ps.output/legends.h
===================================================================
--- grass-addons/ps/ps.output/legends.h	                        (rev 0)
+++ grass-addons/ps/ps.output/legends.h	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,32 @@
+#ifndef _LEGEND_H_
+#define _LEGEND_H_
+
+/* Header file: legends.h
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+
+
+#include "fonts.h"
+#include "frames.h"
+
+typedef struct
+{
+    PSFRAME box;        /* frame box */
+    PSFONT font;        /* legend font */
+
+	int cols;           /* column number */
+    double span;        /* column separation */
+    double width;       /* symbol width  */
+
+    char title[51];     /* text title */
+    PSFONT title_font;  /* title font */
+} LEGEND;
+
+#endif

Added: grass-addons/ps/ps.output/lines.c
===================================================================
--- grass-addons/ps/ps.output/lines.c	                        (rev 0)
+++ grass-addons/ps/ps.output/lines.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,53 @@
+/* File: lines.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "ps_info.h"
+#include "local_proto.h"
+#include "lines.h"
+
+/* PostScript shortcut */
+
+int set_ps_linewidth(double width)
+{
+    if (width > 0.)
+        fprintf(PS.fp, "%.3f LW ", width);
+    return 0;
+
+}
+
+int set_ps_line(PSLINE *line)
+{
+    set_ps_color(&(line->color));
+    set_ps_linewidth(line->width);
+
+    fprintf(PS.fp, "[%s] 0 LD ", line->dash);
+    if (line->cap > 0)
+        fprintf(PS.fp, "%d LC ", line->cap);
+    if (line->join > 0)
+        fprintf(PS.fp, "%d LJ ", line->join);
+
+    fprintf(PS.fp, "\n");
+    return 0;
+}
+
+int set_ps_line_no_color(PSLINE *line)
+{
+    set_ps_linewidth(line->width);
+
+    fprintf(PS.fp, "[%s] 0 LD ", line->dash);
+    if (line->cap > 0)
+        fprintf(PS.fp, "%d LC ", line->cap);
+    if (line->join > 0)
+        fprintf(PS.fp, "%d LJ ", line->join);
+
+    return 0;
+}

Added: grass-addons/ps/ps.output/lines.h
===================================================================
--- grass-addons/ps/ps.output/lines.h	                        (rev 0)
+++ grass-addons/ps/ps.output/lines.h	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,37 @@
+#ifndef _PSLINE_H_
+#define _PSLINE_H_
+
+/* Header file: lines.h
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+
+#include "colors.h"
+
+/* line end style */
+#define LINECAP_BUTT    0
+#define LINECAP_ROUND   1
+#define LINECAP_EXTBUTT 2
+
+/* line join style */
+#define LINEJOIN_MITER  0
+#define LINEJOIN_ROUND  1
+#define LINEJOIN_BEVEL  2
+
+
+typedef struct
+{
+    double width;   /* width of line */
+    PSCOLOR color;  /* color of line */
+    int cap;        /* linecap style */
+    int join;       /* linejoin style */
+    char *dash;     /* dash ps format */
+} PSLINE;
+
+#endif

Added: grass-addons/ps/ps.output/load_raster.c
===================================================================
--- grass-addons/ps/ps.output/load_raster.c	                        (rev 0)
+++ grass-addons/ps/ps.output/load_raster.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,140 @@
+/* File: load_raster.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+
+#include <string.h>
+#include <grass/gis.h>
+#include <grass/glocale.h>
+#include "raster.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+/* load three files as RGB */
+int load_rgb(char *red, char *green, char *blue)
+{
+    /* close rasters open */
+    raster_close();
+
+    G_message(_("Reading RGB files ..."));
+
+    load_cell(0, red);
+    load_cell(1, green);
+    load_cell(2, blue);
+
+    PS.rst.title = "RGB Group";
+
+    return 3;
+}
+
+/* load a group as RGB */
+int load_group(char *name)
+{
+    int i;
+    struct Ref ref;
+    char fullname[100];
+
+    /* close open rasters */
+    raster_close();
+
+    I_init_group_ref(&ref);
+
+    /* get group info */
+    if (I_get_group_ref(PS.rst.title, &ref) == 0) {
+        G_fatal_error(_("Can't get group information"));
+    }
+
+    G_message(_("Reading map group <%s> ..."), name);
+
+    /* get filenames for R, G, and B */
+    I_init_ref_color_nums(&ref);
+    PS.rst.name[0]   = G_store(ref.file[ref.red.n].name);
+    PS.rst.mapset[0] = G_store(ref.file[ref.red.n].mapset);
+    PS.rst.name[1]   = G_store(ref.file[ref.grn.n].name);
+    PS.rst.mapset[1] = G_store(ref.file[ref.grn.n].mapset);
+    PS.rst.name[2]   = G_store(ref.file[ref.blu.n].name);
+    PS.rst.mapset[2] = G_store(ref.file[ref.blu.n].mapset);
+
+    /* check load colors */
+    for (i = 0; i < 3; i++)
+    {
+        if (G_read_colors(PS.rst.name[i], PS.rst.mapset[i], &(PS.rst.colors[i])) == -1) {
+            sprintf(fullname, "%s in %s", PS.rst.name[i], PS.rst.mapset[i]);
+            error(fullname, "", "can't load color table");
+            return 0;
+        }
+    }
+
+    /* check open raster maps */
+    for (i = 0; i < 3; i++)
+    {
+        if ((PS.rst.fd[i] = G_open_cell_old(PS.rst.name[i], PS.rst.mapset[i])) < 0) {
+            sprintf(fullname, "%s in %s", PS.rst.name[i], PS.rst.mapset[i]);
+            error(fullname, "", "can't open raster map");
+            G_free_colors(&(PS.rst.colors[i]));
+            return 0;
+        }
+    }
+
+    I_free_group_ref(&ref);
+    return 3;
+}
+
+/* load a cell file in a slot */
+int load_cell(int slot, char *name)
+{
+    char *mapset, *ptr;
+    char fullname[100];
+
+    /* close raster cell, if any */
+    if (PS.rst.fd[slot] >= 0) {
+        G_close_cell(PS.rst.fd[slot]);
+        G_free(PS.rst.name[slot]);
+        G_free(PS.rst.mapset[slot]);
+        G_free_colors(&(PS.rst.colors[slot]));
+        PS.rst.fd[slot] = -1;
+    }
+
+    /* get mapset */
+    ptr = strchr(name, '@');
+    if (ptr) {
+        *ptr = '\0';
+        mapset = ptr + 1;
+    }
+    else {
+        mapset = G_find_file2("cell", name, "");
+        if (!mapset) {
+            error(name, "", "not found");
+            return 0;
+        }
+    }
+
+    /* store data of cell */
+    PS.rst.name[slot] = G_store(name);
+    PS.rst.mapset[slot] = G_store(mapset);
+    sprintf(fullname, "%s in %s", name, mapset);
+
+    G_message(_("  Reading raster map <%s> ..."), fullname);
+
+    /* load colors */
+    if (G_read_colors(name, mapset, &PS.rst.colors[slot]) == -1) {
+		error(fullname, "", "can't load color table");
+		return 0;
+    }
+    G_get_color_range(&(PS.rst.min), &(PS.rst.max), &(PS.rst.colors[slot]));
+
+    /* open raster map */
+    if ((PS.rst.fd[slot] = G_open_cell_old(name, mapset)) < 0) {
+		error(fullname, "", "can't open raster map");
+		G_free_colors(&PS.rst.colors[slot]);
+    	return 0;
+    }
+
+    return 1;
+}

Added: grass-addons/ps/ps.output/local_proto.h
===================================================================
--- grass-addons/ps/ps.output/local_proto.h	                        (rev 0)
+++ grass-addons/ps/ps.output/local_proto.h	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,248 @@
+
+#define LEFT    0
+#define RIGHT   1
+#define LOWER   0
+#define UPPER   1
+#define CENTER  2
+
+#define NONE   0
+#define POINTS 1
+#define LINES  2
+#define AREAS  3
+
+#define DEF_FONT "Helvetica"
+
+/* cat_val.c */
+#ifdef DBMIN_H
+int load_catval_array(VECTOR *, const char *, dbCatValArray *);
+int get_number(dbCatValArray *, int, double *);
+char * get_string(dbCatValArray *, int);
+#endif
+
+/* colors.c */
+#ifdef _PSCOLOR_H_
+int set_color_name(PSCOLOR *, char *);
+void set_color_rgb(PSCOLOR *, int, int, int);
+void unset_color(PSCOLOR *);
+void set_ps_color(PSCOLOR *);
+int set_ps_grey(PSCOLOR *);
+void set_ps_rgb(int, int, int);
+#endif
+
+/* eps.c */
+int eps_bbox(char *, double *, double *, double *, double *);
+int eps_trans(double, double, double, double, double, double,
+              double, double, double *, double *);
+#ifdef _STDIO_H
+int eps_save(FILE *, char *, char *);
+int eps_draw_saved(FILE *, char *, double, double, double, double);
+int eps_draw(FILE *, char *, double, double, double, double);
+int pat_save(FILE *, char *, char *);
+#endif
+
+/* fonts.c */
+#ifdef _PSFONT_H_
+double set_ps_font(PSFONT *);
+double set_ps_font_nocolor(PSFONT *);
+#endif
+
+/* frames.c */
+#ifdef _PSFRAME_H_
+void set_box_orig(PSFRAME *);
+void set_box_size(PSFRAME *, double, double);
+void set_box_draw(PSFRAME *);
+void set_box_auto(PSFRAME *, PSFONT *, double);
+void set_box_readjust_title(PSFRAME *, const char *);
+void set_box_readjust(PSFRAME *, double, double, double, double);
+#endif
+
+/* input.c */
+int input(int, char *);
+int key_data(char *, char **, char **);
+int error(char *, char *, char *);
+
+/* legends.c */
+#ifdef _LEGENG_H_
+void set_legend_adjust(LEGEND *, double);
+#endif
+
+/* lines.c */
+#ifdef _PSLINE_H_
+int set_ps_linewidth(double);
+int set_ps_line(PSLINE *);
+int set_ps_line_no_color(PSLINE *);
+#endif
+
+/* load_raster.c */
+int load_group(char *);
+int load_cell(int, char *);
+int load_rgb(char *, char *, char *);
+
+/* paper.c */
+int set_paper(char *);
+
+/* ps3_map.c */
+int PS3_map(void);
+
+/* proj_geo.c */
+#ifdef _GPROJECTS_H
+void init_proj(struct pj_info *, struct pj_info *);
+int find_limits(double *, double *, double *, double *, struct pj_info *, struct pj_info *);
+#endif
+
+/* r_draw.c */
+int read_draw(char *);
+
+/* r_font.c */
+int get_font(char *);
+#ifdef _PSFONT_H_
+int default_font(PSFONT *);
+int read_font(char *, PSFONT *);
+#endif
+
+/* r_frame.c */
+#ifdef _PSFRAME_H_
+int default_frame(PSFRAME *, int, int);
+int read_frame(PSFRAME *);
+#endif
+
+/* r_grid.c */
+#ifdef _GRID_H_
+int read_grid(GRID *, int);
+#endif
+
+/* r_line.c */
+#ifdef _PSLINE_H_
+int default_psline(PSLINE *);
+int read_psline(char *, PSLINE *);
+#endif
+
+/* r_maparea.c */
+int read_maparea(void);
+
+/* r_note.c */
+int read_note(char *);
+
+/* r_paper.c */
+int read_paper(char *);
+
+/* r_raster.c */
+int read_raster(char *);
+
+/* r_rlegend.c */
+int read_rlegend(char *);
+
+/* r_vareas.c */
+int r_vareas(char *);
+
+/* r_vlegend.c */
+int read_vlegend(char *);
+
+/* r_vlines.c */
+int r_vlines(char *);
+
+/* r_vpoints.c */
+int r_vpoints(char *);
+
+/* raster.c */
+int raster_close(void);
+
+/* scanners.c */
+int scan_easting(char *, double *);
+int scan_northing(char *, double *);
+int scan_resolution(char *, double *);
+int scan_percent(char *, double *, double, double);
+int scan_ref(char *, int *, int *);
+int scan_yesno(char *, char *);
+#ifdef _PSCOLOR_H_
+int scan_color(char *, PSCOLOR *);
+#endif
+int scan_dimen(char *, double *);
+int scan_second(char *, double *);
+
+/* set_draw.c */
+int set_draw(char *, char*);
+
+/* set_geogrid.c */
+int set_lines_geogrid(void);
+int set_numbers_geogrid(void);
+#ifdef _PSLINE_H_
+int set_geogrid_lines(PSLINE *, int);
+#endif
+int set_geogrid_inner_numbers(void);
+int set_geogrid_outer_numbers(void);
+
+/* set_grid.c */
+int set_lines_grid(void);
+int set_numbers_grid(void);
+#ifdef _PSLINE_H_
+int set_grid_lines(char, PSLINE *, int);
+#endif
+int set_grid_inner_numbers(void);
+int set_grid_outer_numbers(void);
+int set_grid_iho_numbers(void);
+int set_grid_fine_border(double, double);
+int set_grid_minor_border(double, double, double);
+int set_grid_major_border(double, double);
+int set_grid_corners(double, double);
+
+/* set_mask.c */
+int set_mask(void);
+
+/* set_note.c */
+int note_int_file(char *);
+int set_note(int);
+
+/* set_ps.c */
+void set_ps_rect(double, double, double, double);
+int set_ps_where(char, double, double);
+int set_xy_where(char *, double, double, char*);
+#ifdef _VECTOR_H_
+int set_ps_pattern(int, char *, VAREAS *);
+int set_ps_symbol_eps(int, VPOINTS *, char *);
+#endif
+
+/* set_raster.c */
+int set_raster(void);
+int set_raster_cell(void);
+int set_raster_rgb(void);
+int set_raster_maskcell(void);
+int set_raster_maskcolor(void);
+
+/* set_rlegend.c */
+int set_rlegend_cats(void);
+int set_rlegend_gradient(void);
+static double nice_step(double, int);
+
+/* set_scalebar.c */
+char *strnumber(double);
+int set_scalebar(void);
+
+/* set_vector.c */
+int set_vector(int, int);
+#ifdef GRASS_VECT_H
+int set_vareas(VECTOR, VAREAS *);
+int set_vpoints(VECTOR, VPOINTS *);
+int set_vlines(VECTOR, VLINES *, int);
+int vector_line(struct line_pnts *);
+#endif
+
+/* start_map.c */
+int start_map(void);
+
+/* symbol.c */
+#if defined GRASS_SYMB_H
+int draw_chain(SYMBCHAIN *, double);
+int symbol_save(int, VPOINTS *, SYMBOL *);
+#endif
+
+/* val_list.c */
+#ifdef GRASS_GIS_H
+int parse_val_list(char *, DCELL **);
+int sort_list(char *, int, CELL **);
+#endif
+
+/* vector.c */
+int vector_new(void);
+int where_moveto(double, double);
+int where_lineto(double, double);

Added: grass-addons/ps/ps.output/main.c
===================================================================
--- grass-addons/ps/ps.output/main.c	                        (rev 0)
+++ grass-addons/ps/ps.output/main.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,260 @@
+/* File: main.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#define MAIN
+
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <errno.h>
+#include <grass/gis.h>
+#include <grass/glocale.h>
+
+#include "papers.h"
+#include "palettes.h"
+#include "draws.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+#define KEY(x) (strcmp(key,x)==0)
+
+FILE *inputfd;
+
+int main(int argc, char *argv[])
+{
+    struct Option *input_file;
+    struct Option *output_file;
+    struct GModule *module;
+    struct Flag *draft;
+
+    G_gisinit(argv[0]);
+
+    /* Set description */
+    module = G_define_module();
+    module->keywords = _("postscript, map, printing");
+    module->description = _("PostScript-3 Output.");
+
+    input_file = G_define_option();
+    input_file->key = "input";
+    input_file->type = TYPE_STRING;
+    input_file->description = _("File containing mapping instructions");
+    input_file->gisprompt = "code_file,file,input";
+    input_file->required = NO;
+
+    output_file = G_define_option();
+    output_file->key = "output";
+    output_file->type = TYPE_STRING;
+    output_file->gisprompt = "new_file,file,output";
+    output_file->description = _("PostScript output file");
+    output_file->required = YES;
+
+    draft = G_define_flag();
+    draft->key = 'd';
+    draft->description =
+            _("Create a 1x1cm grid on paper to easy place and drawing");
+
+    if (G_parser(argc, argv))
+        exit(EXIT_FAILURE);
+
+    inputfd = stdin;
+    signal(SIGINT, exit);
+    signal(SIGTERM, exit);
+    setbuf(stderr, NULL);
+
+    if (!isatty(0))
+        G_disable_interactive();
+
+    if (output_file->answer)
+    {
+        if ((PS.fp = fopen(output_file->answer, "w")) == NULL)
+            G_fatal_error("%s - %s: %s", G_program_name(),
+                          output_file->answer, strerror(errno));
+    }
+    else
+    {
+        G_message(_("\nERROR: Required parameter <%s> not set:\n    (%s).\n"),
+                  output_file->key, output_file->description);
+        exit(EXIT_FAILURE);
+    }
+
+    /* get current mapset */
+    PS.mapset = G_mapset();
+
+    /* set current window */
+    G_get_set_window(&PS.map);
+    if (G_set_window(&PS.map) == -1)
+        G_fatal_error(_("Current region cannot be set."));
+
+    set_paper("A4");
+    Palette = NULL;
+    /* initialize default ps_info */
+    PS.level = 3;
+    PS.draft = draft->answer ? 1 : 0;
+    PS.scale = 0;
+    PS.map_top = -1.;
+    PS.map_x = PS.map_y = -1.;
+    PS.map_w = PS.map_h = -1.;
+    unset_color(&(PS.fcolor)); /* no background color in maparea */
+    PS.do_border   = 0;     /* no border */
+    PS.rst.files   = 0;     /* no rast files */
+    PS.need_mask   = 0;     /* select storage in PS_raster_plot */
+    PS.do_rlegend  = 0;     /* no rlegend */
+    PS.vct_files   = 0;     /* no include files */
+    PS.vct = NULL;          /* no vector files */
+    PS.do_vlegend  = 0;     /* no vlegend */
+	PS.grid.sep    = 0;     /* no grid */
+    PS.geogrid.sep = 0;     /* no geogrid */
+    PS.sbar.segments = 0;   /* no scalebar */
+    PS.n_notes     = 0;     /* no notes */
+    PS.n_draws     = 0;     /* no plots */
+
+    /* process options */
+    char buf[1024];
+    double number;
+
+    while (input(1, buf))
+    {
+	    char *key;
+	    char *data;
+
+        if (!key_data(buf, &key, &data)) {
+            continue;
+        }
+        /* General information */
+        if (KEY("paper")) {
+            read_paper(data);
+            continue;
+        }
+        if (KEY("palette")) {
+            read_palette();
+            continue;
+        }
+        if (KEY("maparea")) {
+            read_maparea();
+            continue;
+        }
+        if (KEY("scale")) {
+            if (sscanf(data, "1:%d", &(PS.scale)) != 1) {
+                error(key, data, "illegal scale request");
+            }
+            continue;
+        }
+
+        /* Raster map related information */
+        if (KEY("cell") || KEY("rast") || KEY("raster") || KEY("rgb")) {
+            if (PS.rst.files != 0) {
+                error(key, data, "only one raster command");
+                continue;
+            }
+            read_raster(data);
+            continue;
+        }
+        if (KEY("rlegend")) {
+            if (PS.do_rlegend != 0) {
+                error(key, data, "only one rlegend command");
+            }
+			read_rlegend(data);
+			continue;
+		}
+
+        /* Vector map related information */
+        if (KEY("vlines") || KEY("vline")) {
+            G_strip(data);
+            if (*data == 0) {
+                error(key, data, "vlines need vector map");
+            }
+            read_vlines(data);
+            continue;
+        }
+        if (KEY("vareas") || KEY("varea")) {
+            G_strip(data);
+            if (*data == 0) {
+                error(key, data, "vareas need vector map");
+            }
+            read_vareas(data);
+            continue;
+        }
+        if (KEY("vpoints") || KEY("vpoint")) {
+            G_strip(data);
+            if (*data == 0) {
+                error(key, data, "vpoints need vector map");
+            }
+            read_vpoints(data);
+            continue;
+        }
+        if (KEY("vlegend")) {
+            if (PS.do_vlegend != 0) {
+                error(key, data, "only one vlegend command");
+            }
+            read_vlegend(data);
+			continue;
+        }
+
+        /* Grid and scalebar related */
+        if (KEY("grid")) {
+            read_grid(&(PS.grid), 0);
+            continue;
+        }
+        if (KEY("geogrid")) {
+            if (G_projection() == PROJECTION_XY) {
+                error(key, data, "geogrid is not available for XY projection");
+            }
+            else if (G_projection() == PROJECTION_LL) {
+                error(key, data, "grid just uses LL projection");
+            }
+            read_grid(&(PS.geogrid), 1);
+            continue;
+        }
+        if (KEY("scalebar")) {
+            if (G_projection() == PROJECTION_LL) {
+                error(key, data, "scalebar is not appropriate for this projection");
+            }
+            if (sscanf(data, "%c", &(PS.sbar.type)) != 1)
+                PS.sbar.type = 'I'; /* default new style scalebar */
+            read_scalebar();
+            continue;
+        }
+
+        /* Addons related data */
+        if (KEY("note")) {
+            if (PS.n_notes >= MAX_NOTES) {
+                G_warning("Only %d notes by map", MAX_NOTES);
+                continue;
+            }
+            read_note(data);
+            continue;
+        }
+        if (KEY("draw")) {
+            if (PS.n_draws >= MAX_DRAWS) {
+                G_warning("Only %d draw commands by map", MAX_DRAWS);
+                continue;
+            }
+            read_draw(data);
+            continue;
+        }
+        /* oops, no valid command */
+	    if (*key)
+	        error(key, "", "illegal request");
+    }
+
+    /* last minute adjust */
+    if (PS.grid.format == 2) { /* IHO */
+        PS.brd.width = 2.3 * MM_TO_POINT; /* 12.5 */
+        /* PS.do_border = 0; */
+    }
+
+    /* Well, go on the map */
+    PS3_map();
+    G_message(_("PostScript file '%s' finished!"), output_file->answer);
+    exit(EXIT_SUCCESS);
+}
+
+

Added: grass-addons/ps/ps.output/notes.h
===================================================================
--- grass-addons/ps/ps.output/notes.h	                        (rev 0)
+++ grass-addons/ps/ps.output/notes.h	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,29 @@
+#ifndef _NOTES_H_
+#define _NOTES_H_
+
+/* Header file: notes.h
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <stdio.h>
+#include "fonts.h"
+#include "frames.h"
+
+typedef struct
+{
+	PSFRAME box;
+    PSFONT font;
+
+	char text[1024];
+
+    double angle;
+
+} NOTES;
+
+#endif

Added: grass-addons/ps/ps.output/palettes.c
===================================================================
--- grass-addons/ps/ps.output/palettes.c	                        (rev 0)
+++ grass-addons/ps/ps.output/palettes.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,329 @@
+/* File: palette.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <grass/gis.h>
+#include "colors.h"
+#include "palettes.h"
+
+void RGB_HSV(PSCOLOR *, PALETTE *);
+void HSV_RGB(PALETTE *, PSCOLOR *);
+
+
+int palette_new(int n)
+{
+    int i = ncolors;
+
+    ncolors += n;
+    Palette = (PALETTE *) G_realloc(Palette, ncolors * sizeof(PALETTE));
+
+    return i;
+}
+
+int PS_str_to_color(char *name, PSCOLOR *color)
+{
+    int i;
+
+    for (i = 0; i < ncolors; i++)
+    {
+        if (strcmp(Palette[i].name, name) == 0)
+        {
+            HSV_RGB(&(Palette[i]), color);
+            color->none = 0;
+            return 1;
+        }
+    }
+    color->none = 1;
+    return 0;
+}
+
+/* pure colors: color-wheel */
+int pure_color(char *name, int div)
+{
+    int i, k;
+    double step;
+
+    /* alloc memory */
+    k = palette_new(div);
+
+    step = 360./div;
+
+    for (i = 0; i < div; i++, k++)
+    {
+        Palette[k].h = (double)i * step;
+        Palette[k].s = 1.;
+        Palette[k].v = 1.;
+        sprintf(Palette[k].name, "%s%d", name, i);
+    }
+
+    return 1;
+}
+
+/* monochrome color: white to color */
+int monochrome(char *name, PSCOLOR *rgb, int div)
+{
+    int i, k;
+    double step;
+    PALETTE hsv;
+
+    if (rgb->r == rgb->g && rgb->g == rgb->b)
+    {
+        gray(name, div);
+        return 1;
+    }
+
+    RGB_HSV(rgb, &hsv);
+
+    /* alloc memory */
+    k = palette_new(div);
+
+    if (div > 1) {
+        step = 1./(double)(div-1);
+    }
+    for (i = 0; i < div; i++, k++)
+    {
+        Palette[k].h = hsv.h;
+        Palette[k].s = (double)i * step;
+        Palette[k].v = 1.;
+        sprintf(Palette[k].name, "%s%d", name, i);
+    }
+
+    return 1;
+}
+
+/* gradient */
+int gradient(char *name, PSCOLOR *A, PSCOLOR *B, int div, int pure)
+{
+    int i, k;
+    double hstep, sstep, vstep;
+    PALETTE pal_A, pal_B;
+
+    RGB_HSV(A, &pal_A);
+    RGB_HSV(B, &pal_B);
+
+    if (pal_A.h == pal_B.h)
+        return 0;
+
+    if (pal_B.h < pal_A.h) {
+        i = pal_A.h;
+        pal_A.h = pal_B.h;
+        pal_B.h = i;
+    }
+
+    /* alloc memory */
+    k = palette_new(div);
+
+    hstep = (pal_B.h - pal_A.h)/(div-1.);
+    sstep = (pal_B.s - pal_A.s)/(div-1.);
+    vstep = (pal_B.v - pal_A.v)/(div-1.);
+
+    for (i = 0; i < div; i++, k++)
+    {
+        Palette[k].h = pal_A.h + (double)i * hstep;
+        Palette[k].s = pure ? 1. : pal_A.s + (double)i * sstep;
+        Palette[k].v = pure ? 1. : pal_A.v + (double)i * vstep;
+        sprintf(Palette[k].name, "%s%d", name, i);
+    }
+
+    return 1;
+}
+
+/* analogous or similar color */
+int analogous(char *name, PSCOLOR *rgb, int div)
+{
+    int i, k;
+    double h, step;
+    PALETTE hsv;
+
+    RGB_HSV(rgb, &hsv);
+
+    /* alloc memory */
+    k = palette_new(div);
+
+    if (div > 1) {
+        hsv.h -= 40.;
+        step = 80./(double)(div-1);
+    }
+
+    for (i = 0; i < div; i++, k++)
+    {
+        Palette[k].h = hsv.h + (double)i * step;
+        if (Palette[k].h < 0.)    Palette[k].h += 360.;
+        if (Palette[k].h >= 360.) Palette[k].h -= 360.;
+        Palette[k].s = hsv.s;
+        Palette[k].v = hsv.v;
+        sprintf(Palette[k].name, "%s%d", name, i);
+    }
+
+    return 1;
+}
+
+/* complementary or contrast color */
+int complementary(char *name, PSCOLOR *rgb, int div)
+{
+    int i, k;
+    double step;
+    PALETTE hsv;
+
+    RGB_HSV(rgb, &hsv);
+
+    /* alloc memory */
+    k = palette_new(div);
+
+    if (div > 1) {
+        hsv.h += 140.;
+        step = 80./(double)(div-1);
+    }
+    else {
+        hsv.h += 180.;
+    }
+    for (i = 0; i < div; i++, k++)
+    {
+        Palette[k].h = hsv.h + (double)i * step;
+        if (Palette[k].h < 0.)
+            Palette[k].h += 360.;
+        if (Palette[k].h >= 360.)
+            Palette[k].h -= 360.;
+        Palette[k].s = hsv.s;
+        Palette[k].v = hsv.v;
+        sprintf(Palette[k].name, "%s%d", name, i);
+    }
+
+    return 1;
+}
+
+
+/* gray color */
+int gray(char *name, int div)
+{
+    int i, k;
+    double step;
+
+    /* alloc memory */
+    k = palette_new(div);
+
+    if (div > 1) {
+        step = 1./(double)(div-1);
+    }
+    for (i = 0; i < div; i++, k++)
+    {
+        Palette[k].h = 0.;
+        Palette[k].s = 0.;
+        Palette[k].v = (double)i * step;
+        sprintf(Palette[k].name, "%s%d", name, i);
+    }
+
+    return 1;
+}
+
+
+/*
+ * TRANSFORMATIONS BETWEEN COLORSPACES
+ */
+
+/* r, g, b values are from 0 to 1
+ * h = [0,360], s = [0,1], v = [0,1]
+ */
+void RGB_HSV(PSCOLOR *col, PALETTE *pal)
+{
+    double min, max;
+
+    if (col->r == col->g && col->g == col->b)
+    {
+        pal->h = pal->s = 0.;   /* achromatic, gray */
+        pal->v = col->b;
+        return;
+    }
+    else if (col->r > col->g && col->r > col->b)
+    {
+        max = col->r;
+        min = (col->g < col->b) ? col->g : col->b;
+        pal->h = (col->g - col->b)/(max - min);
+    }
+    else if (col->g > col->b && col->g > col->r)
+    {
+        max = col->g;
+        min = (col->r < col->b) ? col->r : col->b;
+        pal->h = 2. + (col->b - col->r)/(max - min);
+    }
+    else
+    {
+        max = col->b;
+        min = (col->g < col->r) ? col->g : col->r;
+        pal->h = 4. + (col->r - col->g)/(max - min);
+    }
+
+    /* hue */
+    pal->h *= 60.;
+    if (pal->h < 0.) pal->h += 360.;
+    /* saturation */
+    pal->s = (max - min) / max;
+    /* value */
+    pal->v = max;
+
+    return;
+}
+
+/* r, g, b values are from 0 to 1
+ * h = [0,360], s = [0,1], v = [0,1]
+ */
+void HSV_RGB(PALETTE *pal, PSCOLOR *col)
+{
+    /* achromatic, gray */
+    if (pal->s == 0) {
+        col->r = col->g = col->b = pal->v;
+        return;
+    }
+
+    int i;
+    double f, p, q, t;
+    i = floor(pal->h/60.);
+    f = pal->h/60. - (double)i;
+    p = pal->v * ( 1. - pal->s );
+    q = pal->v * ( 1. - pal->s * f );
+    t = pal->v * ( 1. - pal->s * ( 1. - f ) );
+    switch (i)
+    {
+        case 0:
+            col->r = pal->v;
+            col->g = t;
+            col->b = p;
+            break;
+        case 1:
+            col->r = q;
+            col->g = pal->v;
+            col->b = p;
+            break;
+        case 2:
+            col->r = p;
+            col->g = pal->v;
+            col->b = t;
+            break;
+        case 3:
+            col->r = p;
+            col->g = q;
+            col->b = pal->v;
+            break;
+        case 4:
+            col->r = t;
+            col->g = p;
+            col->b = pal->v;
+            break;
+        default: /* 5 */
+            col->r = pal->v;
+            col->g = p;
+            col->b = q;
+            break;
+    }
+}
+

Added: grass-addons/ps/ps.output/palettes.h
===================================================================
--- grass-addons/ps/ps.output/palettes.h	                        (rev 0)
+++ grass-addons/ps/ps.output/palettes.h	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,30 @@
+#ifndef _PALETTE_H_
+#define _PALETTE_H_
+
+/* Header file: palette.h
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+typedef struct
+{
+    char name[50];
+    double h, s, v;
+} PALETTE;
+
+
+#ifdef MAIN
+    PALETTE *Palette;
+    int ncolors;
+#else
+    extern PALETTE *Palette;
+    extern int ncolors;
+#endif
+
+
+#endif

Added: grass-addons/ps/ps.output/papers.c
===================================================================
--- grass-addons/ps/ps.output/papers.c	                        (rev 0)
+++ grass-addons/ps/ps.output/papers.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,61 @@
+/* File: papers.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "papers.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+
+PAPER papers[] = {
+        {"B0",        2920, 4127, 36., 36., 72., 72.},
+        {"B1",        2064, 2920, 36., 36., 72., 72.},
+        {"B2",        1460, 2064, 36., 36., 72., 72.},
+        {"B3",        1032, 1460, 36., 36., 72., 72.},
+        {"B4",         729, 1032, 36., 36., 72., 72.},
+        {"B5",         516,  729, 36., 36., 72., 72.},
+        {"B6",         363,  516, 36., 36., 72., 72.},
+        {"A6",         297,  420, 36., 36., 72., 72.},
+        {"A5",         420,  595, 36., 36., 72., 72.},
+        {"A4",         595,  842, 36., 36., 72., 72.},
+        {"A3",         842, 1191, 36., 36., 72., 72.},
+        {"A2",        1191, 1684, 36., 36., 72., 72.},
+        {"A1",        1684, 2384, 36., 36., 72., 72.},
+        {"A0",        2384, 3370, 36., 36., 72., 72.},
+        {"Legal",      612, 1008, 36., 36., 72., 72.},
+        {"Ledger",    1224,  792, 36., 36., 72., 72.},
+        {"Letter",     612,  792, 36., 36., 72., 72.},
+        {"Tabloid",    792, 1224, 36., 36., 72., 72.},
+        {"Executive",  522,  756, 36., 36., 72., 72.},
+        {"Folio",      595,  935, 36., 36., 72., 72.},
+        {NULL,           0,    0,  0.,  0.,  0.,  0.}
+};
+
+int set_paper(char *name)
+{
+    register int i;
+
+    for (i = 0; papers[i].name != NULL; i++)
+    {
+        if (strcmp(papers[i].name, name) == 0)
+        {
+            PS.page.width  = papers[i].width;
+            PS.page.height = papers[i].height;
+            PS.page.left   = papers[i].left;
+            PS.page.right  = papers[i].right;
+            PS.page.top    = papers[i].top;
+            PS.page.bot    = papers[i].bot;
+            return 1;
+        }
+    }
+
+    return 0;
+}

Added: grass-addons/ps/ps.output/papers.h
===================================================================
--- grass-addons/ps/ps.output/papers.h	                        (rev 0)
+++ grass-addons/ps/ps.output/papers.h	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,21 @@
+#ifndef _PSPAPER_H_
+#define _PSPAPER_H_
+
+/* Header file: papers.h
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+typedef struct
+{
+    char *name;
+    int width, height;
+    double left, right, top, bot;
+} PAPER;
+
+#endif

Added: grass-addons/ps/ps.output/proj_geo.c
===================================================================
--- grass-addons/ps/ps.output/proj_geo.c	                        (rev 0)
+++ grass-addons/ps/ps.output/proj_geo.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,87 @@
+/* File: proj_geo.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <string.h>
+#include <math.h>
+#include <grass/gis.h>
+#include <grass/glocale.h>
+#include <grass/gprojects.h>
+#include "ps_info.h"
+#include "local_proto.h"
+
+
+/* From: r.proj */
+void init_proj(struct pj_info *iproj, struct pj_info *oproj)
+{
+    struct Key_Value *out_proj_info, *out_unit_info;
+
+    /* Get projection info for output mapset */
+    if ((out_proj_info = G_get_projinfo()) == NULL)
+        G_fatal_error(_("Unable to get projection info of output raster map"));
+
+    if ((out_unit_info = G_get_projunits()) == NULL)
+        G_fatal_error(_("Unable to get projection units of output raster map"));
+
+    if (pj_get_kv(oproj, out_proj_info, out_unit_info) < 0)
+        G_fatal_error(_("Unable to get projection key values of output raster map"));
+
+    G_free_key_value(out_proj_info);
+    G_free_key_value(out_unit_info);
+
+    /* In Info */
+    if (GPJ_get_equivalent_latlong(iproj, oproj) < 0)
+        G_fatal_error(_("Unable to set up lat/long projection"));
+
+    return;
+}
+
+/*
+ *
+ */
+int find_limits(double *north, double *south,
+                double *east, double *west,
+                struct pj_info *ll_proj,
+                struct pj_info *xy_proj)
+{
+    int x, y;
+    double d, z;
+
+    /* West */
+    if (PS.map.west < 500000)
+        G_plot_where_en(10.*PS.map_x, 10.*PS.map_top, west, &d);
+    else
+        G_plot_where_en(10.*PS.map_x, 10.*PS.map_y, west, &d);
+    pj_do_proj(west, &d, xy_proj, ll_proj);                            /* UTM > LL */
+
+    /* East */
+    if (PS.map.west < 500000)
+        G_plot_where_en(10.*PS.map_right, 10.*PS.map_top, east, &d);
+    else
+        G_plot_where_en(10.*PS.map_right, 10.*PS.map_y, east, &d);
+    pj_do_proj(east, &d, xy_proj, ll_proj);                            /* UTM > LL */
+
+    /* d previous */
+    z = (6. * PS.map.zone - 183.);
+    pj_do_proj(&z, &d, ll_proj, xy_proj);                              /* LL > UTM */
+    G_plot_where_xy(z, d, &x, &y);                                  /* UTM > XY */
+
+    /* North */
+    G_plot_where_en(x, 10.*PS.map_top, &d, north);                  /* XY > UTM */
+    pj_do_proj(&d, north, xy_proj, ll_proj);                           /* UTM > LL */
+
+    /* South */
+    z = (double)x/10.;
+    if ((z - PS.map_x) > (PS.map_right - z))
+        G_plot_where_en(10.*PS.map_x, 10.*PS.map_y, &d, south);     /* XY > UTM */
+    else
+        G_plot_where_en(10.*PS.map_right, 10.*PS.map_y, &d, south); /* XY > UTM */
+    pj_do_proj(&d, south, xy_proj, ll_proj);                           /* UTM > LL */
+}
+

Added: grass-addons/ps/ps.output/ps.output.tmp.html
===================================================================
--- grass-addons/ps/ps.output/ps.output.tmp.html	                        (rev 0)
+++ grass-addons/ps/ps.output/ps.output.tmp.html	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,682 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<title>GRASS GIS manual: ps.output</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<link rel="stylesheet" href="grassdocs.css" type="text/css">
+</head>
+<body bgcolor="white">
+
+<img src="grass_logo.png" alt="GRASS logo"><hr align=center size=6 noshade>
+
+<h2>NAME</h2>
+<em><b>ps.output</b></em>  - PostScript-3 Output.
+<h2>KEYWORDS</h2>
+postscript, map, printing
+<h2>SYNOPSIS</h2>
+<b>ps.output</b><br>
+<b>ps.output help</b><br>
+<b>ps.output</b> [-<b>d</b>]  [<b>input</b>=<em>string</em>]  <b>output</b>=<em>string</em>  [--<b>verbose</b>]  [--<b>quiet</b>] 
+
+<h3>Flags:</h3>
+<DL>
+<DT><b>-d</b></DT>
+<DD>Create a 1x1cm grid on paper to easy place and drawing</DD>
+
+<DT><b>--verbose</b></DT>
+<DD>Verbose module output</DD>
+<DT><b>--quiet</b></DT>
+<DD>Quiet module output</DD>
+</DL>
+
+<h3>Parameters:</h3>
+<DL>
+<DT><b>input</b>=<em>string</em></DT>
+<DD>File containing mapping instructions</DD>
+
+<DT><b>output</b>=<em>string</em></DT>
+<DD>PostScript output file</DD>
+
+</DL>
+<H2>DESCRIPTION</H2>
+
+<EM>ps.output</EM> is a cartographic mapping program for producing high quality
+hardcopy maps in PostScript-3 format. Output can include a raster map, any
+number of vector overlays, notes, decorations, and other spatial data.
+
+<P>
+A file of mapping instructions that describes the various spatial and textual
+information to be printed must be prepared prior to running <EM>ps.output</EM>.
+
+
+<H2>NOTES</H2>
+
+<P>
+The order of commands is generally unimportant but may affect how some layers
+are drawn. For example to plot <B>vpoints</B> above <B>vareas</B> list the
+<B>vpoints</B> entry first. Raster maps are always drawn first, and only a
+single raster map and an optional background may be used
+(or 3 if part of a RGB group).
+
+<P>
+The hash character ('<tt>#</tt>') may be used at the beginning of a line
+to indicate that the line is a comment. Blank lines will also be ignored.
+
+<P>
+Be aware that some mapping instructions require the <i>end</i> command
+and some do not. Any instruction that allows subcommands will require
+it, any instruction that does not allow subcommands will not.
+
+<P>
+The resolution and extent of raster maps plotted with <EM>ps.output</EM> are controlled by the current region settings via the <a href="g.region.html">g.region</a> module. The output filesize is largely a function of the region resolution, so special care should be taken if working with large raster datasets.
+For example if the desired output is Letter sized paper at 300dpi, with 1" margins and the raster filling the entire page, the usable area on the page will be 6.5" x 9", which at 300 dots/inch is equivalent to a region of 1950 columns x 2700 rows (see "<tt>g.region -p</tt>"). Any higher resolution settings will make the output file larger, but with a consumer printer you probably won't be able to resolve any better detail in the hardcopy.
+
+<P>
+The user can specify negative or greater than 100 percentage values for positioning several map decorations and embedded EPS-files, to move them outside the current map box region (for example to position a caption, barscale, or legend above or below the map box).
+
+<P>
+One "pixel" is 1/72 of an inch or 127/360 (~ 0.35) of a millimetre.
+
+<P>
+For users wanting to use special characters (such as accented characters) it is important to note that <em>ps.output</em> uses <tt>ISO-8859-1</tt> encoding. This means that your instructions file will have to be encoded in this encoding. If you normally work in a different encoding environment (such as <tt>UTF-8</tt>), you have to transform your file to the <tt>ISO-8859-1</tt> encoding, for example by using the <tt>iconv</tt> utility:
+</P>
+<DIV class="code"><PRE>
+iconv -f UTF-8 -t ISO_8859-1 utf_file > iso_file
+</PRE></DIV>
+
+
+<P><P>
+
+<H2>MAPPING INSTRUCTIONS</H2>
+
+The mapping instructions allow the user to specify various spatial data to be plotted. These instructions are normally prepared in a regular text file using a system editor. Except <em>scale</em>, all instructions are multiple line followed by a subsection of one or more additional instructions and are terminated with an <i>end</i> instruction.
+<P>
+
+<h3>Instruction keywords:</h3>
+
+<a href="#draw">draw</a>&nbsp;<BR>
+<a href="#geogrid">geogrid</a>&nbsp; ERROR IN SOUTH HEMISPHERE<BR>
+<a href="#grid">grid</a>&nbsp;<BR>
+<a href="#maparea">maparea</a>&nbsp;<BR>
+<a href="#note">note</a>&nbsp;<BR>
+<a href="#palette">palette</a>&nbsp; CHECK<BR>
+<a href="#paper">paper</a>&nbsp;<BR>
+<a href="#raster">raster</a>&nbsp;<BR>
+<a href="#rlegend">rlegend</a>&nbsp;<BR>
+<a href="#scale">scale</a>&nbsp;<BR>
+<a href="#scalebar">scalebar</a>&nbsp;<BR>
+<a href="#vareas">vareas</a>&nbsp;<BR>
+<a href="#vlines">vlines</a>&nbsp;<BR>
+<a href="#vpoints">vpoints</a>&nbsp;<BR>
+<a href="#vlegend">vlegend</a>&nbsp;<BR>
+
+
+<h3>Convention in description of instructions:</h3>
+
+<DL>
+<DT><B>#</B> <EM>number</EM>
+<P>
+<DT><B>#-</B> <EM>dimension</EM> name (number with units)
+<DD> Acceptable units are <em>mm</em> (millimeters), <em>cm</em> (centimeters), and <em>inch</em> (inches).
+</DD><P>
+<DT><B>CAT</B> <EM>List of categories</EM> e.g. 1,3,5-7
+<P>
+<DT><B>SQL</B> <EM>SQL where statement</EM> like: vlastnik = 'Cimrman'
+<P>
+<DT><b>T</b> <em>Text</em>
+<P>
+<DT><b>R</b> <em>Raster</em> file or group name if first character is ':'
+<P>
+<DT><b>V</b> <em>Vector</em> file
+<P>
+
+<DT><b>color</b> <em>Color</em> name
+<DD>The color may be either a standard <a name="NAMED_COLORS">GRASS color</a>, a <tt>R:G:B</tt> triplet (e.g '<tt>255:0:0</tt>'), or <tt>none</tt>.
+The following colors names are accepted by <EM>ps.output</EM>:
+<tt>aqua, black, blue, brown, cyan, gray, grey, green, indigo, magenta, orange, purple, red, violet, white, yellow</tt>.
+</DD><P>
+
+<DT><B>font</B> command:
+<PRE>
+font
+    name   [T]
+    size   [#-]
+    color  (color)
+    extend [#]
+end
+</PRE>
+
+<DD>
+The name of the PostScript font. Fonts present in all PostScript implementations are:
+<tt>
+Times-Roman,
+Times-Italic,
+Times-Bold,
+Times-BoldItalic,
+Helvetica,
+Helvetica-Oblique,
+Helvetica-Bold,
+Helvetica-BoldOblique,
+Courier,
+Courier-Oblique,
+Courier-Bold,
+and
+Courier-BoldOblique
+</tt>.
+</DD><P>
+
+<DT><B>frame</B> command:
+<PRE>
+frame
+    where  [#- #-]
+    ref    [left|right|center upper|lower|center]
+    offset [# #]
+    border [#-]
+    color  (color)
+    fcolor (color)
+    margin [#-]
+end
+</PRE>
+
+<DT><B>line</B> command:
+<PRE>
+line
+    width [#-]
+    color (color)
+    style [solid|dashed|dotted|dashdotted|#...]
+    cap   [butt|round|extended_butt]
+end
+</PRE>
+
+<DT><b>COOR</b> <em>Coordinates</em> as pair of <b>east north</b>
+<P>
+
+
+
+
+</DL>
+<P>
+
+
+
+
+<H2>COMPOSE THE MAP</H2>
+
+
+<h3>paper</h3>
+<a name="paper"></a>
+Specifies paper size, margins and orientation.
+
+<PRE>
+USAGE
+<B>paper</B> [paper type], default: A4
+    <B>height</B> [#-]
+    <B>width</B>  [#-]
+    <B>left</B>   [#-], default 0.5inch
+    <B>right</B>  [#-], default 0.5inch
+    <B>bottom</B> [#-], default 1.0inch
+    <B>top</B>    [#-], default 1.0inch
+    <B>landscape</B> [y|N], default N
+<B>end</B>
+</PRE>
+
+<P>
+Paper types: A0-6, B0-6, Executive, Folio, Ledger, Legal, Letter, Tabloid.<BR>
+
+<PRE>
+<i>EXAMPLE</i>
+paper A4
+    left 2cm
+    top 4cm
+    landscape y
+end
+</PRE>
+<P>
+
+
+<h3>scale</h3>
+Selects a scale for the output map.
+
+<PRE>
+USAGE
+<B>scale</B> 1:[#]
+</PRE>
+
+The scale is selected as a relative ratio, e.g. 1:25000. Use maparea to select a specific width of map.
+
+<PRE>
+<i>EXAMPLE</i>
+    scale 1:25000
+</PRE>
+<P>
+
+This example would set the scale of the map to 1 unit = 25000 units.
+
+
+<h3>maparea</h3>
+
+Positions the map area on the page.
+
+<PRE>
+USAGE
+<B>maparea</B>
+    <B>left</B>   [#-]
+    <B>top</B>    [#-]
+    <B>width</B>  [#-]
+    <B>height</B> [#-]
+    <B>border</B> [#-]
+    <B>color</B>  [color]
+ <B>end</B>
+</PRE>
+
+The upper left corner of the map will be positioned <EM>left</EM> units from the left edge of the page and <EM>top</EM> units from the top of the page. If <EM>width</EM> and <EM>height</EM> are present, the map will be rescaled, if necessary, to fit.
+<P>
+
+<em>border</em> and <em>color</em> controls the which and color of the line is drawn around the map area.
+<P>
+
+<PRE>
+<i>EXAMPLE</i>
+maparea
+	left 2cm
+	top 3.5cm
+	border 1mm
+	color black
+end
+</PRE>
+
+This example positions the upper left corner of the map 2.0 cm from the left edge and 3.5 cm from the top edge of the map. And draw a black border of 1 mm of width around the map area.
+
+<h3>palette</h3>
+
+
+
+
+<H2>ADDING COMPONENTS</H2>
+
+<h3>grid</h3>
+<a name="grid"></a>
+Overlays a coordinate grid onto the output map.
+
+<PRE>
+USAGE
+<B>grid</B>
+    <B>major</B>  [#] (line)
+    <B>minor</B>  [#] (line)
+    <B>cross</B>  [#]
+    <B>font</B>   [font]
+    <B>fcolor</B> [color]
+    <B>format</B> [#], number (0-2) or 'in', 'out' or 'iho'
+    <B>round</B>  [#]
+ <B>end</B>
+</PRE>
+
+The <B>line separation</B> of the grid is given (in the geographic coordinate system units) on the main instruction line.  The subsection instructions allow the user to specify the properties of the <B>grid line</B>, whether coordinate <B>numbers</B> should appear on the grid lines, and if they should appear every grid line (1), every other grid line (2), etc., and what <B>font</B> the numbers should be.
+The <B>cross</B> argument draws grid intersection crosses instead of grid lines, with cross size given in geographic coordinate system units. The defaults are black grid lines, unnumbered.
+<P>
+
+<PRE>
+<I>EXAMPLE</I>
+grid
+    major 1000
+        width .1mm
+        color gray
+        style 12
+    end
+    minor 200
+        width .05mm
+        color gray
+        style 12
+    end
+    font
+        name Univers
+        size 7
+        color white
+    end
+    fcolor black
+    format 0
+    round 3
+end
+</PRE>
+
+This example would overlay a gray grid with a spacing of 10000 meters (for a metered database, like UTM) onto the output map.  Alternate grid lines would be numbered with white numbers on black boxes.
+
+
+<h3>geogrid</h3>
+<a name="geogrid"></a>
+
+<PRE>
+USAGE
+<B>geogrid</B>
+    <B>major</B>  [#] (line)
+    <B>minor</B>  [#] (line)
+    <B>font</B>   [font]
+    <B>fcolor</B> [color]
+    <B>format</B> [#], number (0-1) or 'in' or 'out'
+ <B>end</B>
+</PRE>
+
+<PRE>
+<I>EXAMPLE</I>
+geogrid
+    format out
+    major 30'
+        width .3
+        color magenta
+    end
+    minor 5'
+        width .1
+        color magenta
+        style 1
+    end
+    font
+        name Univers
+        size 5
+        color black
+        extend 1.2
+    end
+    fcolor none
+end
+</PRE>
+
+
+<H3>scalebar</H3>
+<a name="scalebar"></a>
+
+<PRE>
+<I>USAGE</I>
+<B>scalebar</B>   [scalebar type]
+    <B>length</B> [#]
+    <B>units</B>  [code T]
+    <B>major</B>  [# #], divisions and seperation text label
+    <B>minor</B>  [# #], divisions and seperation text label
+    <B>frame</B>  [frame]
+    <B>font</B>   [font]
+    <B>height</B> [#-]
+    <B>fcolor</B> [color]
+<B>end</B>
+</PRE>
+
+Scalebar types: I F f S s
+
+<PRE>
+<I>EXAMPLE</I>
+scalebar f
+    frame
+        where 50% 0%
+        offset 0 12
+        ref center upper
+        border 0.5mm
+        color black
+        fcolor gray
+    end
+    font
+        name Univers
+        size 8
+        color black
+    end
+    length 20
+    units km Kilometers
+    major 5 2
+    minor 2 2
+    height 2mm
+end
+</PRE>
+
+
+<h3>note</h3>
+<a name="note"></a>
+
+<PRE>
+USAGE
+<B>note</B> [code T]
+    <B>frame</B> [frame]
+    <B>font</B> [font]
+    <B>angle</B> [#] in degrees
+ <B>end</B>
+</PRE>
+
+Note codes: :file (filename),
+    :maplim,
+    :dimen,
+    :scale (pre-text)
+    or simple text use '|' to break lines (max 1024 characters)
+
+
+<PRE>
+<I>EXAMPLE</I>
+note :scale scale
+    frame
+        where 0% 0%
+        offset -12 -4
+        ref left lower
+        border 0
+        fcolor none
+    end
+    angle 90
+    font
+        name Univers
+        size 6
+        extend 1.25
+        color gray
+    end
+end
+</PRE>
+
+
+
+<h2>ADDING RASTER MAPS</h2>
+
+<a name="raster"><H3>raster</H3></a>
+Selects a raster map for output.
+
+<PRE>
+<I>USAGE</I>
+<B>raster</B> [R|R R R], required: one raster, one group name (:name) or three raster (RGB)
+    <B>grey</B>      [y|N]. Output in shades of grey.
+    <B>maskcolor</B> [color]. Color to be used for mask.
+    <B>maskcell</B>  [R (R)]. Raster used as mask and optionally a raster for background.
+    <B>outline</B>   [line]. Specifications of outline.
+    <B>setcolor</B>  [cat color]. Overrides the color of cat
+end
+</PRE>
+
+<PRE>
+<I>EXAMPLE</I>
+raster geology
+    grey n
+    maskcolor none
+    maskcell geo_mask elev_state_500m
+    outline
+        width .01
+        color black
+    end
+    setcolor 28 200:123:200
+end
+</PRE>
+
+
+<h2>ADDING VECTOR MAPS</h2>
+
+<a name="vareas"><H3>vareas</H3></a>
+
+<PRE>
+USAGE
+<B>vareas</B> [V]. Vector map name
+    <b>width</b>  [#-], default 0 (positive or negative, permit draw a line as area).
+    <b>layer</b>  [#], default: 1. Layer number used with cats/where option
+    <b>cats</b>   [CAT]
+    <b>where</b>  [SQL].
+    <b>line</b>   (line)
+    <b>fcolor</b> (color) ([T]). Fill color and, optionally RGB column name (also apply to pattern).
+    <b>pat</b>    [T]. Pattern EPS file.
+    <b>scale</b>  [#]
+    <b>pwidth</b> [#]
+    <b>masked</b> [y|N]. Masked by raster mask
+    <b>label</b>  [T]. For description in vlegend
+    <b>lpos</b>   [#]. Position vector is plotted in legend
+<b>end</b>
+</PRE>
+
+<a name="vlines"><H3>vlines</H3></a>
+
+<PRE>
+USAGE
+<B>vlines</B> [V]. Vector map name
+    <b>type</b>   [line|boundary], default: line
+    <b>layer</b>  [#], default: 1. Layer number used with cats/where option
+    <b>cats</b>   [CAT]
+    <b>where</b>  [SQL]
+    <b>line</b>   (line)
+    <b>rgbcol</b> [T]. Column name with line color data
+    <b>hline</b>  [# (line)], default: 0; and enter line command. Offset dimen from midline
+    <b>masked</b> [y|N]. Masked by raster mask
+    <b>label</b>  [T]. For description in vlegend
+    <b>lpos</b>   [#]. Position vector is plotted in legend
+<b>end</b>
+</PRE>
+
+<PRE>
+<i>EXAMPLE</i>
+vlines railroads
+    type line
+    label Rail roads
+    line
+        width .4mm
+        color green
+    end
+    hline
+        width .1mm
+        color black
+    end
+    masked n
+end
+</PRE>
+
+<a name="vpoints"><H3>vpoints</H3></a>
+
+<PRE>
+USAGE
+<B>vpoints</B> [V]. Vector map name
+    <b>type</b>   [point|centroid], default: point
+    <b>layer</b>  [#], default: 1. Layer number used with cats/where option
+    <b>cats</b>   [CAT]
+    <b>where</b>  [SQL]
+    <b>symbol</b> [T]. Symbol standard or EPS file.
+    <b>line</b>   (line)
+    <b>fcolor</b> (color). Fillcolor
+    <b>size</b>   [# ([T])]. Size and optionally size column.
+    <b>scale</b>  [#]. Scale
+    <b>rotate</b> [# ([T])]. Rotate and optionally rotate column.
+    <b>masked</b> [y|N]. Masked by raster mask
+    <b>label</b>  [T]. For description in vlegend
+    <b>lpos</b>   [#]. Position vector is plotted in legend
+<b>end</b>
+</PRE>
+
+<PRE>
+<i>EXAMPLE</i>
+vpoints precip_30ynormals
+    type centroid
+    symbol basic/circle
+    fcolor red
+    line
+        width .2
+        color black
+    end
+    size 10 ANNUAL
+    scale .01
+end
+</PRE>
+
+<h2>ADDING LEGENDS</h2>
+
+<a name="rlegend"><H3>rlegend</H3></a>
+
+<PRE>
+USAGE
+<B>rlegend</B>
+    <b>raster</b>
+    <b>title</b>
+    <b>frame</b>
+    <b>font</b>
+    <b>cols</b>
+    <b>width</b>
+    <b>height</b>
+    <b>tick</b>
+    <b>whiteframe</b>
+<b>end</b>
+</PRE>
+
+<PRE>
+<i>EXAMPLE</i>
+rlegend
+    title Land Class 1996
+        name Univers Bold
+        size 12
+        extend 0.85
+        color black
+    end
+    raster landclass96
+    cols 1 0
+    frame
+        where 100% 100%
+        ref right upper
+        offset 0 0
+        border 2
+        color  black
+        fcolor white
+        margin 8
+    end
+    font
+        name Univers
+        size 9
+        color black
+    end
+    width 8mm
+    height 7cm
+    tick 3
+    whiteframe 1
+end
+</PRE>
+
+<a name="vlegend"><H3>vlegend</H3></a>
+
+<PRE>
+USAGE
+<B>vlegend</B>
+    <b>title</b> (first char point to center)
+    <b>frame</b>
+    <b>font</b>
+    <b>cols</b>
+    <b>width</b>
+    <b>order</b>
+<b>end</b>
+</PRE>
+
+<PRE>
+<i>EXAMPLE</i>
+vlegend
+    title .Leyenda
+        name Univers-Bold
+        size 10
+        extend 1.1
+    end
+    frame
+        where 100% 100%
+        ref left upper
+        offset 10 0
+        border 1
+    end
+    font
+        name Univers
+        size 9
+    end
+#   cols 1
+#   width 1cm
+end
+</PRE><HR>
+<P><a href="index.html">Main index</a> - <a href="postscript.html">postscript index</a> - <a href="full_index.html">Full index</a></P>
+<P>&copy; 2003-2009 <a href="http://grass.osgeo.org">GRASS Development Team</a></p>
+</body>
+</html>

Added: grass-addons/ps/ps.output/ps3_map.c
===================================================================
--- grass-addons/ps/ps.output/ps3_map.c	                        (rev 0)
+++ grass-addons/ps/ps.output/ps3_map.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,270 @@
+/* File: ps_map3.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include "palettes.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+#define UNMASKED    0
+#define MASKED      1
+
+#define INSIDE      0
+#define OUTSIDE     1
+
+int PS3_map(void)
+{
+    int i;
+    double d;
+
+    /* PostScript header */
+    fprintf(PS.fp, "%%!PS-Adobe-3.0\n");
+    fprintf(PS.fp, "%%%%BoundingBox: 0 0 %d %d\n",
+            (int)(PS.page.width),
+            (int)(PS.page.height));
+    fprintf(PS.fp, "%%%%Title: \n");
+    fprintf(PS.fp, "%%%%Creator: \n");
+    fprintf(PS.fp, "%%%%CreationDate: %s\n", G_date());
+    fprintf(PS.fp, "%%%%Programming: E. Jorge Tizado, Spain 2009\n");
+    fprintf(PS.fp, "%%%%EndComments\n\n");
+    fprintf(PS.fp, "%%%%BeginProlog\n");
+    fprintf(PS.fp, "/D {bind def} bind def\n");
+    fprintf(PS.fp, "/XD {exch def} D\n");
+
+    /* STRING MANIPULATION */
+    fprintf(PS.fp, "/str 20 string def\n");
+    fprintf(PS.fp, "/to_s {str cvs} D\n");
+    /* (a) (b) -> (ab) */
+    fprintf(PS.fp, "/adds { "
+            "exch dup length "
+            "2 index length add string dup dup 4 2 roll copy length "
+            "4 -1 roll putinterval} D\n");
+
+    /* Orden alfabetico */
+    fprintf(PS.fp, "/++ {1 add} D\n");
+    fprintf(PS.fp, "/-- {1 sub} D\n");
+    fprintf(PS.fp, "/mm {360 mul 127 div} D\n");
+    fprintf(PS.fp, "/inch {72 mul} D\n");
+
+    fprintf(PS.fp, "/B {4 1 roll 2 copy 5 index 5 index 8 1 roll newpath moveto lineto lineto lineto closepath} D\n");
+    fprintf(PS.fp, "/C {setrgbcolor} D\n");
+    fprintf(PS.fp, "/cLW {currentlinewidth} D\n");
+    fprintf(PS.fp, "/cP {currentpoint} D\n");
+    fprintf(PS.fp, "/CP {closepath} D\n");
+    fprintf(PS.fp, "/CS {closepath stroke} D\n");
+    fprintf(PS.fp, "/F {gsave fill grestore} D\n");
+    fprintf(PS.fp, "/G {setgray} D\n");
+    fprintf(PS.fp, "/GET {get aload pop} D\n");
+    fprintf(PS.fp, "/CG {0.11 mul exch 0.59 mul add exch 0.30 mul add setgray} D\n");
+    fprintf(PS.fp, "/GS {gsave} D\n");
+    fprintf(PS.fp, "/GR {grestore} D\n");
+    fprintf(PS.fp, "/LC {setlinecap} D\n");
+    fprintf(PS.fp, "/LD {setdash} D\n");
+    fprintf(PS.fp, "/LJ {setlinejoin} D\n");
+    fprintf(PS.fp, "/L {lineto} D\n");
+    fprintf(PS.fp, "/LS {lineto stroke} D\n");
+    fprintf(PS.fp, "/LR {rlineto} D\n");
+    fprintf(PS.fp, "/LRS {rlineto stroke} D\n");
+    fprintf(PS.fp, "/LW {setlinewidth} D\n");
+    fprintf(PS.fp, "/M {moveto} D\n");
+    fprintf(PS.fp, "/ML {moveto lineto stroke} D\n");
+    fprintf(PS.fp, "/MR {rmoveto} D\n");
+    fprintf(PS.fp, "/MS {moveto show} D\n");
+    fprintf(PS.fp, "/NM {newpath moveto} D\n");
+    fprintf(PS.fp, "/NP {newpath} D\n");
+    fprintf(PS.fp, "/RE {rectstroke} D\n");
+    fprintf(PS.fp, "/Re {currentpoint 4 2 roll rectstroke} D\n");   /* stack: w h */
+    fprintf(PS.fp, "/RES {gsave newpath false charpath flattenpath pathbbox grestore} D\n"); /* llx lly urx ury of a string: stack string */
+    fprintf(PS.fp, "/RF {rectfill} D\n");
+    fprintf(PS.fp, "/Rf {currentpoint 4 2 roll rectfill} D\n");   /* stack: w h */
+    fprintf(PS.fp, "/RC {rectclip} D\n");
+    fprintf(PS.fp, "/ROT {rotate} D\n");
+    fprintf(PS.fp, "/S {stroke} D\n");
+    fprintf(PS.fp, "/SC {scale} D\n");
+    fprintf(PS.fp, "/SHL {show} D\n");
+    fprintf(PS.fp, "/SHR {dup stringwidth pop neg 0 rmoveto show} D\n");
+    fprintf(PS.fp, "/SHC {dup stringwidth pop 2 div neg 0 rmoveto show} D\n");
+    fprintf(PS.fp, "/SHCC {dup SWH 2 div neg exch 2 div neg exch rmoveto show} D\n");
+    fprintf(PS.fp, "/SW {stringwidth pop} D\n");
+    /* w h of a string: stack string */
+    fprintf(PS.fp, "/SWH {gsave newpath 0 0 moveto false charpath flattenpath pathbbox "
+                   "4 2 roll pop pop grestore} D\n");
+    /* max string width of an array of string: stack array */
+    fprintf(PS.fp, "/SWx {0 exch {stringwidth pop dup 2 index gt {exch} if pop} forall} def\n");
+    fprintf(PS.fp, "/TR {translate} D\n");
+    fprintf(PS.fp, /* borde exterior del rectangulo: x y w h RO */
+            "/RO {gsave dup cLW exch 0 lt {neg} if add exch cLW add exch "
+            "cLW -2 div dup 2 index 0 lt {neg} if TR RE grestore} D\n");
+    /* stack none */
+    fprintf(PS.fp, "/RESET {/x xo mgx add def /y yo mgy sub def /col 0 def /row 0 def} def\n");
+    /* stack number of col/row 0...n-1 */
+    fprintf(PS.fp, "/COL {/col XD xo mgx add 0 1 col -- {ARw exch get dx add add} for /x XD} def\n");
+    fprintf(PS.fp, "/ROW {/row XD yo mgy sub 0 1 row -- {ARh exch get dy add sub} for /y XD} def\n");
+    /* set fontname with re-encoding */
+    fprintf(PS.fp,
+            "/FN { % (FontName) FN -\n"
+            "    dup (-ISOLatin1) adds dup /F0 exch cvn def exch cvn\n"
+            "    currentdict F0 known {pop pop}\n"
+            "    {findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse } forall\n"
+            "        /Encoding ISOLatin1Encoding def\n"
+            "        /FontName 0 index def\n"
+            "        currentdict end definefont pop} ifelse} D\n");
+    /* set fontsize */
+    fprintf(PS.fp, "/FS {/F0S exch def F0 findfont F0S scalefont setfont} D\n");
+    /* set fontsize */
+    fprintf(PS.fp, "/FE {F0 findfont 3 1 roll 1 index mul 0 0 4 -1 roll 0 0 6 packedarray makefont setfont} D\n");
+    /* trying transparency compatibility */
+    /* fprintf(PS.fp, "/pdfmark where {pop} {userdict /pdfmark /cleartomark load put} ifelse\n"); */
+    /* end */
+    fprintf(PS.fp, "%%%%EndProlog\n");
+
+    /* Page specifications */
+    fprintf(PS.fp, "<< /PageSize [%d %d] >> setpagedevice\n",
+            (int)(PS.page.width), (int)(PS.page.height));
+
+    /* Prepare the map */
+    start_map();
+    if (PS.draft) /* print a reticule as watermark of page */
+    {
+        fprintf(PS.fp, ".5 LW 0.9 G\n");
+        fprintf(PS.fp, "0 28.35 %d {0 M 0 %d LR S} for\n",
+                (int)(PS.page.width), (int)(PS.page.height));
+        fprintf(PS.fp, "%d -28.35 0 {0 exch M %d 0 LR S} for\n",
+                (int)(PS.page.height), (int)(PS.page.width));
+    }
+    /* CLIP the MAP AREA */
+    fprintf(PS.fp, "gsave ");
+    fprintf(PS.fp, "%.4f %.4f %.4f %.4f rectclip\n",
+            PS.map_x, PS.map_y, PS.map_w, PS.map_h);
+    if (!PS.fcolor.none)
+    {
+        set_ps_color(&(PS.fcolor));
+        fprintf(PS.fp, "%.4f %.4f %.4f %.4f RF\n",
+            PS.map_x, PS.map_y, PS.map_w, PS.map_h);
+    }
+    /* needed by uncolored patterns */
+    fprintf(PS.fp, "[/Pattern /DeviceRGB] setcolorspace NP\n");
+
+    /* RASTER */
+    if (PS.rst.files != 0)
+    {
+        set_raster();
+        /* outline, if requested */
+        if (PS.rst.outline.width > 0.)
+        {
+            if (!G_raster_map_is_fp(PS.rst.name[0], PS.rst.mapset[0]))
+                set_outline();
+            else
+                G_warning("Outline is not to float maps!, ignored");
+        }
+    }
+    /* VECTOR (masked) */
+    if (PS.vct_files != 0)
+    {
+        set_vector(MASKED, AREAS);
+        set_vector(MASKED, LINES);
+        set_vector(MASKED, POINTS);
+    }
+    /* LABELS (masked) */
+//     set_labels(MASKED);
+    /* RASTER MASK */
+    if (PS.need_mask && PS.rst.do_mask)
+    {
+    	set_mask();
+    }
+    /* VECTOR-LINES/AREAS under grids (unmasked) */
+    if (PS.vct_files != 0)
+    {
+        set_vector(UNMASKED, AREAS);
+        set_vector(UNMASKED, LINES);
+    }
+    /* CLIPED CUSTOM DRAWS */
+    if (PS.n_draws > 0)
+    {
+        fprintf(PS.fp, "0 0 0 C "); /* default color */
+        for (i = 0; i < PS.n_draws; i++)
+            set_draw(PS.draw.key[i], PS.draw.data[i]);
+    }
+    /* GRIDS LINES INSIDE OF BORDER  */
+    if (PS.grid.sep > 0)
+    {
+        set_lines_grid();
+    }
+    if (PS.geogrid.sep > 0)
+    {
+        set_lines_geogrid();
+    }
+    /* VECTOR-POINTS on grids (unmasked) */
+    if (PS.vct_files != 0)
+    {
+        set_vector(UNMASKED, POINTS);
+    }
+    /* no more work in the map area */
+    fprintf(PS.fp, "grestore\n");
+    /* BORDER */
+    if (PS.do_border && PS.brd.width > 0 && !PS.brd.color.none)
+    {
+        set_ps_line(&(PS.brd));
+        set_ps_rect(PS.map_x, PS.map_y, PS.map_w, PS.map_h);
+    }
+    /* GRID NUMBER, OUTSIDE OF BORDER */
+    if (PS.geogrid.sep > 0)
+    {
+        set_numbers_geogrid();
+    }
+    if (PS.grid.sep > 0)
+    {
+        set_numbers_grid();
+    }
+    /* LEGENDS */
+    if (PS.do_rlegend)
+    {
+        if (G_raster_map_is_fp(PS.rl.name, PS.rl.mapset) ||
+            PS.rl.do_gradient)
+        {
+            set_rlegend_gradient();
+        }
+        else
+        {
+            set_rlegend_cats();
+        }
+    }
+    if (PS.do_vlegend)
+    {
+        set_vlegend();
+    }
+    /* NOTES */
+    for (i = 0; i < PS.n_notes; i++)
+    {
+        set_note(i);
+    }
+    /* SCALEBAR */
+    if (PS.sbar.segments > 0 && PS.sbar.length > 0) {
+        set_scalebar();
+    }
+
+    /* END */
+    fprintf(PS.fp, "showpage\n");
+    fprintf(PS.fp, "%%%%Trailer\n");
+    fprintf(PS.fp, "%%%%EOF\n");
+    fclose(PS.fp);
+
+    /* FREE ALLOCATED POINTERS */
+    for (i = 0; i < PS.vct_files; i++)
+    {
+        G_free(PS.vct[i].data);
+    }
+    G_free(PS.vct);
+    if (Palette != NULL)
+        G_free(Palette);
+
+    return 0;
+}

Added: grass-addons/ps/ps.output/ps_info.h
===================================================================
--- grass-addons/ps/ps.output/ps_info.h	                        (rev 0)
+++ grass-addons/ps/ps.output/ps_info.h	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,89 @@
+#ifndef _PS3_INFO_H_
+#define _PS3_INFO_H_
+
+/* File: ps_info.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+
+#include <grass/gis.h>
+#include "lines.h"
+#include "colors.h"
+#include "notes.h"
+#include "papers.h"
+#include "raster.h"
+#include "rlegend.h"
+#include "vector.h"
+#include "vlegend.h"
+#include "grids.h"
+#include "scalebar.h"
+#include "draws.h"
+#include "conversion.h"
+
+#define MAX_NOTES   10
+
+struct PS3_info
+{
+    FILE *fp;
+    int level;              /* PostScript level */
+    int draft;              /* Grid of 1x1 cm */
+    char *mapset;           /* current mapset */
+    struct Cell_head map;   /* current region */
+
+    int scale;              /* 1 : scale of the map */
+
+    /* rasters */
+    RASTER rst;
+    int need_mask;
+    RLEGEND rl;
+    int do_rlegend;
+
+    /* vectors */
+    VECTOR *vct;
+    int vct_files;
+    VLEGEND vl;
+    int do_vlegend;
+
+    /* border, grids, and scales */
+    PSCOLOR fcolor;
+    PSLINE brd;
+    int do_border;
+    GRID grid;
+    GRID geogrid;
+    SCALEBAR sbar;
+
+    /* notes */
+    NOTES note[MAX_NOTES];      /* notes */
+    int n_notes;                /* number of notes */
+
+    /* draw commands */
+    PSDRAW draw;
+    int n_draws;
+
+    /* dimensions of the page */
+    PAPER page;
+
+    /* dimension and location of the map */
+    double map_x, map_y, map_w, map_h;
+    double map_top, map_right; /* to check outside */
+
+    /* current point to draw */
+    double x, y;
+};
+
+#endif
+
+#ifdef MAIN
+    struct PS3_info PS;
+    int sec_draw;   /* used in PS_plot */
+#else
+    extern struct PS3_info PS;
+    extern int sec_draw;
+#endif
+

Added: grass-addons/ps/ps.output/r_draw.c
===================================================================
--- grass-addons/ps/ps.output/r_draw.c	                        (rev 0)
+++ grass-addons/ps/ps.output/r_draw.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,46 @@
+/* File: r_draw.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+
+
+#include <stdlib.h>
+#include <string.h>
+#include "draws.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+#define KEY(x) (strcmp(key,x)==0)
+
+
+int read_draw(char *name)
+{
+    char buf[1024];
+    char *key, *data;
+
+    G_debug(1, "Reading draw settings ..");
+
+    /* process options */
+    while (input(2, buf))
+	{
+		if (!key_data(buf, &key, &data)) {
+			continue;
+        }
+
+        PS.draw.key[PS.n_draws]  = G_store(key);
+        PS.draw.data[PS.n_draws] = G_store(data);
+        ++PS.n_draws;
+        if (PS.n_draws == MAX_DRAWS)
+            error(key, data, "many draw commands sub-request");
+    }
+
+    return 0;
+}
+
+

Added: grass-addons/ps/ps.output/r_font.c
===================================================================
--- grass-addons/ps/ps.output/r_font.c	                        (rev 0)
+++ grass-addons/ps/ps.output/r_font.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,101 @@
+/* File: r_font.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "fonts.h"
+#include "local_proto.h"
+
+#define KEY(x) (strcmp(key,x)==0)
+
+/* Function: get_font
+ **
+ ** Author: Paul W. Carlson     April 1992
+ */
+int get_font(char *data)
+{
+    char *dp;
+    G_strip(data);
+    /* replace spaces with dashes and make sure each
+    ** word begins with a capital letter.
+    */
+    dp = data;
+    if (*dp >= 'a' && *dp <= 'z')
+        *dp = *dp - 'a' + 'A';
+    while (*dp) {
+        if (*dp == ' ') {
+            *dp++ = '-';
+            if (*dp >= 'a' && *dp <= 'z')
+                *dp = *dp - 'a' + 'A';
+        }
+        else
+            dp++;
+    }
+    return 0;
+}
+
+
+int default_font(PSFONT *font)
+{
+    strcpy(font->name, "Helvetica");
+    font->size = 10.;
+    font->extend = 1.;
+    set_color_rgb(&(font->color), 0, 0, 0);
+}
+
+int read_font(char *arg, PSFONT *font)
+{
+	char buf[1024];
+	char *key, *data;
+
+    G_debug(1, "Reading font settings ..");
+
+	/* init values */
+    default_font(font);
+
+
+    /* process options */
+	while (input(3, buf))
+    {
+	    if (!key_data(buf, &key, &data)) {
+	        continue;
+        }
+        if (KEY("name")) {
+            get_font(data);
+            strcpy(font->name, data);
+            continue;
+        }
+        if (KEY("size")) {
+            if (scan_dimen(data, &(font->size)) != 1) {
+                font->size = 10.;
+                error(key, data, "illegal size request (font)");
+            }
+            continue;
+        }
+        if (KEY("extend")) {
+            if (scan_dimen(data, &(font->extend)) != 1) {
+                font->extend = 1.;
+                error(key, data, "illegal extent request (font)");
+            }
+            continue;
+        }
+        if (KEY("color")) {
+            if (!scan_color(data, &(font->color))) {
+                error(key, data, "illegal color request (font)");
+            }
+            continue;
+        }
+        error(key, data, "illegal font sub-request");
+    }
+
+    return 0;
+}
+
+

Added: grass-addons/ps/ps.output/r_frame.c
===================================================================
--- grass-addons/ps/ps.output/r_frame.c	                        (rev 0)
+++ grass-addons/ps/ps.output/r_frame.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,112 @@
+/* File: r_frame.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "frames.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+#define KEY(x) (strcmp(key,x)==0)
+
+
+int default_frame(PSFRAME *box, int refx, int refy)
+{
+    box->x = (refx == RIGHT ? -100. : 0.0);
+    box->y = 0.0;
+    box->xset = box->yset = 0.;
+    box->xref = refx;
+    box->yref = refy;
+    box->border = 1.;
+    set_color_rgb(&(box->color), 0, 0, 0);
+    set_color_rgb(&(box->fcolor), 255, 255, 255);
+    box->margin = -1.;
+    box->rotate = 0.;
+
+    return 0;
+}
+
+int read_frame(PSFRAME *box)
+{
+    char buf[1024];
+    char *key, *data;
+
+    G_debug(1, "Reading frame settings ..");
+
+    /* init values */
+    default_frame(box, RIGHT, LOWER);
+
+
+    /* process options */
+    while (input(3, buf))
+    {
+	    if (!key_data(buf, &key, &data)) {
+	        continue;
+        }
+        if (KEY("where")) {
+            char xx[50], yy[50];
+            if (sscanf(data, "%s %s", xx, yy) != 2) {
+                error(key, data, "illegal box where request");
+            }
+            else {
+				if (scan_dimen(xx, &(box->x)) == 2)
+					box->x *= -1;
+				if (scan_dimen(yy, &(box->y)) == 2)
+					box->y *= -1;
+                continue;
+            }
+        }
+        if (KEY("offset")) {
+            if (sscanf(data, "%lf %lf", &(box->xset), &(box->yset)) != 2) {
+                error(key, data, "illegal box offset request");
+            }
+            continue;
+        }
+        if (KEY("ref")) {
+			if (!scan_ref(data, &(box->xref), &(box->yref))) {
+                error(key, data, "illegal box ref request");
+            }
+            continue;
+        }
+        if (KEY("border")) {
+			if (scan_dimen(data, &(box->border)) != 1) {
+				box->border = -1;
+			}
+            continue;
+        }
+        if (KEY("color")) {
+            if (!scan_color(data, &(box->color))) {
+                error(key, data, "illegal box color request");
+            }
+            continue;
+        }
+        if (KEY("fcolor")) {
+            if (!scan_color(data, &(box->fcolor))) {
+                error(key, data, "illegal box fcolor request");
+            }
+            continue;
+        }
+        if (KEY("margin")) {
+            if (scan_dimen(data, &(box->margin)) != 1) {
+                error(key, data, "illegal box margin request");
+            }
+            continue;
+        }
+        if (KEY("rotate")) {
+            if (scan_dimen(data, &(box->rotate)) != 1) {
+                error(key, data, "illegal box rotate request");
+            }
+            continue;
+        }
+        error(key, data, "illegal box sub-request");
+    }
+
+    return 0;
+}

Added: grass-addons/ps/ps.output/r_grid.c
===================================================================
--- grass-addons/ps/ps.output/r_grid.c	                        (rev 0)
+++ grass-addons/ps/ps.output/r_grid.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,130 @@
+/* File: r_grid.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "grids.h"
+#include "ps_info.h"
+#include "local_proto.h"
+#include "conversion.h"
+
+#define KEY(x) (strcmp(x,key)==0)
+
+
+int read_grid(GRID * grid, int type)
+{
+    char buf[1024];
+    char *key, *data;
+
+    G_debug(1, "Reading grid settings ..");
+
+    /* default values */
+    grid->sep   = 0;
+    grid->msep  = 0;
+    default_font(&(grid->font));
+    default_psline(&(grid->line));
+    default_psline(&(grid->mline));
+    set_color_rgb(&(grid->fcolor), 255, 255, 255);
+    grid->format = 0;  /* inner labels */
+    grid->round  = -1; /* no round */
+    grid->cross  = 0.;
+
+    /* process options */
+    while (input(2, buf))
+    {
+		if (!key_data(buf, &key, &data)) {
+			continue;
+        }
+        if (KEY("major") || KEY("line")) {
+            char str[50];
+            if (sscanf(data, "%s", str) != 1) {
+                error(key, data, "illegal major request (grid)");
+            }
+            if (G_projection() == PROJECTION_LL || type == 1) {
+                double seconds;
+                scan_second(str, &seconds);
+                grid->sep = (int)seconds;
+            }
+            else {
+                grid->sep = atoi(str); /* units, usually meters */
+            }
+            if (grid->sep <= 0) {
+                error(key, data, "illegal major request (grid)");
+            }
+            read_psline("", &(grid->line));
+            continue;
+        }
+        if (KEY("minor")) {
+            char str[50];
+            if (sscanf(data, "%s", str) != 1) {
+                error(key, data, "illegal minor request (grid)");
+            }
+            if (G_projection() == PROJECTION_LL || type == 1) {
+                double seconds;
+                scan_second(str, &seconds);
+                grid->msep = (int)seconds;
+            }
+            else {
+                grid->msep = atoi(str); /* units, usually meters */
+            }
+            if (grid->msep <= 0) {
+                error(key, data, "illegal minor request (grid)");
+            }
+            read_psline("", &(grid->mline));
+            continue;
+        }
+        if (KEY("format")) {
+            G_strip(data);
+            if (strncmp(data,"in",2)==0) {
+                grid->format = 0;
+            }
+            else if (strncmp(data,"out",3)==0) {
+                grid->format = 1;
+            }
+            else if (strncmp(data,"iho",3)==0) {
+                grid->format = 2;
+            }
+            else
+                grid->format = atoi(data);
+            continue;
+        }
+        if (KEY("round")) {
+            G_strip(data);
+            grid->round = atoi(data);
+            continue;
+        }
+        if (KEY("font")) {
+			read_font(data, &(grid->font));
+			continue;
+		}
+		if (KEY("fcolor")) {
+            if (!scan_color(data, &(grid->fcolor))) {
+                error(key, data, "illegal fcolor request (grid)");
+            }
+			continue;
+		}
+        if (KEY("cross")) {
+            grid->cross = atof(data);
+            continue;
+        }
+        error(key, data, "illegal request (grid)");
+    }
+
+    /* swap major and minor if ... */
+    if (grid->sep < grid->msep)
+    {
+        int tmp;
+        tmp = grid->msep;
+        grid->msep = grid->sep;
+        grid->sep = tmp;
+    }
+
+    return 0;
+}

Added: grass-addons/ps/ps.output/r_line.c
===================================================================
--- grass-addons/ps/ps.output/r_line.c	                        (rev 0)
+++ grass-addons/ps/ps.output/r_line.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,124 @@
+/* File: r_line.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "lines.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+#define KEY(x) (strcmp(key,x)==0)
+
+
+int default_psline(PSLINE *line)
+{
+    line->width = 1.;
+    set_color_rgb(&(line->color), 0, 0, 0);
+    line->dash = G_store("");
+    line->cap = line->join = -1;
+
+    return 0;
+}
+
+int read_psline(char *arg, PSLINE *line)
+{
+    char buf[1024];
+    char *key, *data;
+    char i, dash[21];
+
+    G_debug(1, "Reading line settings ..");
+
+    /* init values */
+    default_psline(line);
+
+    /* inline argument: width */
+    if (arg[0] != 0) {
+        if (scan_dimen(arg, &(line->width)) != 1) {
+            line->width = 1.;
+            error("ERROR:", arg, "illegal line width request");
+        }
+        return 0;
+    }
+
+    /* process options */
+    while (input(3, buf))
+    {
+	    if (!key_data(buf, &key, &data)) {
+	        continue;
+        }
+        if (KEY("width")) {
+			if (scan_dimen(data, &(line->width)) != 1) {
+				line->width = -1.;
+                error(key, data, "illegal line width request");
+			}
+            continue;
+        }
+        if (KEY("color")) {
+            if (!scan_color(data, &(line->color))) {
+                error(key, data, "illegal line color request");
+            }
+            continue;
+        }
+        if (KEY("style")) {
+            G_strip(data);
+            if (strncmp(data, "solid", 5) == 0) {
+                line->dash = G_store("");
+                continue;
+            }
+            else if (strncmp(data, "dashed", 5) == 0) {
+                line->dash = G_store("3 2");
+                continue;
+            }
+            else if (strncmp(data, "dotted", 3) == 0) {
+                line->dash = G_store("1");
+                continue;
+            }
+            else if (strncmp(data, "dashdotted", 5) == 0) {
+                line->dash = G_store("4 2 1 2");
+                continue;
+            }
+            char * dp;
+            for (i = 0, dp = data; *dp && i < 20; dp++) {
+                if (*dp < '0' || *dp > '9')
+                    break;
+                dash[i++] = *dp;
+                dash[i++] = ' ';
+            }
+            if (i == 0) {
+                error(key, data, "illegal line style");
+                continue;
+            }
+            dash[--i] = 0;
+            line->dash = G_store(dash);
+            continue;
+        }
+        if (KEY("cap")) {
+            G_strip(data);
+            if (strncmp(data, "butt", 4) == 0) {
+                line->cap = LINECAP_BUTT;
+                continue;
+            }
+            else if (strncmp(data, "round", 5) == 0) {
+                line->cap = LINECAP_ROUND;
+                continue;
+            }
+            else if (strncmp(data, "extended_butt", 3) == 0) {
+                line->cap = LINECAP_EXTBUTT;
+                continue;
+            }
+            else
+                error(key, data, "illegal line cap");
+            continue;
+        }
+        error(key, data, "illegal line sub-request");
+    }
+
+    return 0;
+}

Added: grass-addons/ps/ps.output/r_maparea.c
===================================================================
--- grass-addons/ps/ps.output/r_maparea.c	                        (rev 0)
+++ grass-addons/ps/ps.output/r_maparea.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,91 @@
+/* File: r_maparea.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "lines.h"
+#include "colors.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+#define KEY(x) (strcmp(key,x)==0)
+
+
+int read_maparea(void)
+{
+    char buf[1024];
+    char *key, *data;
+    double point;
+
+    G_debug(1, "Reading maparea settings ..");
+
+    /* default values */
+    default_psline(&(PS.brd));
+
+    /* process options */
+    while (input(2, buf))
+    {
+        if (!key_data(buf, &key, &data)) {
+            continue;
+        }
+        if (KEY("border")) {
+            if(scan_dimen(data, &(point)) != 1) {
+                error(key, data, "illegal border width request (maparea)");
+            }
+            PS.brd.width = point;
+            PS.do_border = 1;
+            continue;
+        }
+        if (KEY("color")) {
+            if(!scan_color(data, &(PS.brd.color))) {
+                error(key, data, "illegal border color request (maparea)");
+            }
+            continue;
+        }
+        if (KEY("fcolor")) {
+            if(!scan_color(data, &(PS.fcolor))) {
+                error(key, data, "illegal fcolor request (maparea)");
+            }
+            continue;
+        }
+        if (KEY("width")) {
+            if(scan_dimen(data, &(point)) != 1) {
+                error(key, data, "illegal map width request (maparea)");
+            }
+            PS.map_w = point;
+            continue;
+        }
+        if (KEY("height")) {
+            if(scan_dimen(data, &(point)) != 1) {
+                error(key, data, "illegal map height request (maparea)");
+            }
+            PS.map_h = point;
+            continue;
+        }
+        if (KEY("top")) {
+            if (scan_dimen(data, &(point)) != 1) {
+                error(key, data, "illegal map top request (maparea)");
+            }
+            PS.map_top = point;
+            continue;
+            continue;
+        }
+        if (KEY("left")) {
+            if(scan_dimen(data, &(point)) != 1) {
+                error(key, data, "illegal map left request (maparea)");
+            }
+            PS.map_x = point;
+            continue;
+        }
+	    error(key, data, "illegal maparea sub-request");
+    }
+
+    return 0;
+}

Added: grass-addons/ps/ps.output/r_note.c
===================================================================
--- grass-addons/ps/ps.output/r_note.c	                        (rev 0)
+++ grass-addons/ps/ps.output/r_note.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,81 @@
+/* File: r_note.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+
+
+#include <stdlib.h>
+#include <string.h>
+#include "notes.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+#define KEY(x) (strcmp(key,x)==0)
+
+
+int read_note(char *name)
+{
+    char buf[1024];
+    char *key, *data;
+
+    G_debug(1, "Reading note settings ..");
+
+    /* default values */
+    PS.note[PS.n_notes].text[0] = 0;
+    PS.note[PS.n_notes].angle   = 0.;
+    default_font(&(PS.note[PS.n_notes].font));
+    default_frame(&(PS.note[PS.n_notes].box), LEFT, UPPER);
+
+    /* inline argument */
+    if (*name != 0) {
+        strncpy(PS.note[PS.n_notes].text, name, 1024);
+        PS.note[PS.n_notes].text[1023] = 0;
+    }
+
+    /* process options */
+    while (input(2, buf))
+	{
+		if (!key_data(buf, &key, &data)) {
+			continue;
+        }
+		if (KEY("frame")) {
+			read_frame(&(PS.note[PS.n_notes].box));
+			continue;
+		}
+		if (KEY("font")) {
+			read_font(data, &(PS.note[PS.n_notes].font));
+			continue;
+		}
+		if (KEY("text")) {
+			if (sscanf(data, "%s", PS.note[PS.n_notes].text) != 1) {
+				PS.note[PS.n_notes].text[0] = 0;
+				error(key, data, "illegal note sub-request");
+			}
+			else {
+                strncpy(PS.note[PS.n_notes].text, data, 1024);
+                PS.note[PS.n_notes].text[1023] = 0;
+			}
+			continue;
+        }
+        if (KEY("angle")) {
+            if (sscanf(data, "%lf", &(PS.note[PS.n_notes].angle)) != 1) {
+                PS.note[PS.n_notes].angle = 0.;
+                error(key, data, "illegal angle sub-request");
+            }
+            continue;
+        }
+		error(key, data, "illegal note sub-request");
+    }
+
+	++PS.n_notes;
+
+    return 0;
+}
+
+

Added: grass-addons/ps/ps.output/r_palette.c
===================================================================
--- grass-addons/ps/ps.output/r_palette.c	                        (rev 0)
+++ grass-addons/ps/ps.output/r_palette.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,110 @@
+/* File: r_palette.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "colors.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+#define KEY(x,n) (strncmp(key,x,n)==0)
+
+
+// complementary blue 5 <<<< 180 grados
+// afin red 4 <<<< 45 grados
+// gradient red blue 10
+// monochromatic red 10
+// triadic red <<<<< whell 3 con inicio variable
+
+int read_palette(void)
+{
+    char buf[1024];
+    char *key, *data;
+    int i;
+    char name[50];
+    PSCOLOR color, colorb;
+
+    G_debug(1, "Reading palette settings ..");
+
+    /* process options */
+    while (input(2, buf))
+	{
+		if (!key_data(buf, &key, &data)) {
+			continue;
+        }
+        if (KEY("wheel", 2)) {
+            if (sscanf(data, "%d %s", &i, name) != 2 || i < 2) {
+                error(key, data, "illegal wheel sub-request (palette)");
+            }
+            pure_color(name, i);
+            continue;
+        }
+        if (KEY("monochrome", 4)) {
+            char color_name[50];
+            if (sscanf(data, "%s %d %s", color_name, &i, name) != 3) {
+                error(key, data, "illegal monochrome sub-request (palette)");
+            }
+            if (i < 1 || !scan_color(color_name, &color)) {
+                error(key, data, "illegal monochrome sub-request (palette)");
+            }
+            monochrome(name, &color, i);
+            continue;
+        }
+        if (KEY("complementary", 4)) {
+            char color_name[50];
+            if (sscanf(data, "%s %d %s", color_name, &i, name) != 3) {
+                error(key, data, "illegal complementary sub-request (palette)");
+            }
+            if (i < 1 || !scan_color(color_name, &color)) {
+                error(key, data, "illegal complementary sub-request (palette)");
+            }
+            complementary(name, &color, i);
+            continue;
+        }
+        if (KEY("analogous", 3)) {
+            char color_name[50];
+            if (sscanf(data, "%s %d %s", color_name, &i, name) != 3) {
+                error(key, data, "illegal analogous sub-request (palette)");
+            }
+            if (i < 1 || !scan_color(color_name, &color)) {
+                error(key, data, "illegal analogous sub-request (palette)");
+            }
+            analogous(name, &color, i);
+            continue;
+        }
+        if (KEY("pure_gradient", 4)) {
+            char A_name[50], B_name[50];
+            if (sscanf(data, "%s %s %d %s", A_name, B_name, &i, name) != 4) {
+                error(key, data, "illegal gradient sub-request (palette)");
+            }
+            if (i < 3 || !scan_color(A_name, &color) || !scan_color(B_name, &colorb)) {
+                error(key, data, "illegal gradient sub-request (palette)");
+            }
+            gradient(name, &color, &colorb, i, 1);
+            continue;
+        }
+        if (KEY("gradient", 4)) {
+            char A_name[50], B_name[50];
+            if (sscanf(data, "%s %s %d %s", A_name, B_name, &i, name) != 4) {
+                error(key, data, "illegal gradient sub-request (palette)");
+            }
+            if (i < 3 || !scan_color(A_name, &color) || !scan_color(B_name, &colorb)) {
+                error(key, data, "illegal gradient sub-request (palette)");
+            }
+            gradient(name, &color, &colorb, i, 0);
+            continue;
+        }
+        error(key, data, "illegal palette sub-request");
+    }
+
+    return 0;
+}
+
+

Added: grass-addons/ps/ps.output/r_paper.c
===================================================================
--- grass-addons/ps/ps.output/r_paper.c	                        (rev 0)
+++ grass-addons/ps/ps.output/r_paper.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,100 @@
+/* File: r_paper.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "ps_info.h"
+#include "local_proto.h"
+
+#define KEY(x) (strcmp(key,x)==0)
+
+int read_paper(char *arg)
+{
+    char buf[1024];
+    char *key, *data;
+    int do_landscape;
+    double point;
+
+    G_debug(1, "Reading paper settings ..");
+
+    /* default values */
+    if (arg[0] != 0) {
+        set_paper(arg);
+    }
+    do_landscape = 0;
+
+    while (input(2, buf))
+    {
+        if (!key_data(buf, &key, &data)) {
+            continue;
+        }
+        if (KEY("width")) {
+            if(scan_dimen(data, &(point)) != 1) {
+                error(key, data, "illegal paper width request");
+            }
+            PS.page.width = (int)(point);
+            continue;
+        }
+        if (KEY("height")) {
+            if(scan_dimen(data, &(point)) != 1) {
+                error(key, data, "illegal paper width request");
+            }
+            PS.page.height = (int)(point);
+            continue;
+        }
+        if (KEY("left")) {
+            if (scan_dimen(data, &(point)) != 1) {
+                error(key, data, "illegal paper width request");
+            }
+            PS.page.left = point;
+            continue;
+        }
+        if (KEY("right")) {
+            if(scan_dimen(data, &(point)) != 1) {
+                error(key, data, "illegal paper width request");
+            }
+            PS.page.right = point;
+            continue;
+        }
+        if (KEY("top")) {
+            if(scan_dimen(data, &(point)) != 1) {
+                error(key, data, "illegal paper width request");
+            }
+            PS.page.top = point;
+            continue;
+        }
+        if (KEY("bottom")) {
+            if(scan_dimen(data, &(point)) != 1) {
+                error(key, data, "illegal paper width request");
+            }
+            PS.page.bot = point;
+            continue;
+        }
+        if (KEY("landscape")) {
+            do_landscape = scan_yesno(key, data);
+            continue;
+        }
+        error(key, data, "illegal paper sub-request");
+    }
+
+    if (do_landscape != 0)
+    {
+        int tmp;
+        tmp = PS.page.width;
+        PS.page.width = PS.page.height;
+        PS.page.height = tmp;
+    }
+
+    G_debug(1, "Setting paper: %.1f %.1f : %d %d\n",
+            PS.page.left, PS.page.top,
+            PS.page.width, PS.page.height);
+
+    return 0;
+}

Added: grass-addons/ps/ps.output/r_raster.c
===================================================================
--- grass-addons/ps/ps.output/r_raster.c	                        (rev 0)
+++ grass-addons/ps/ps.output/r_raster.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,140 @@
+/* File: raster.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "raster.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+#define KEY(x) (strcmp(key,x)==0)
+
+
+int read_raster(char *arg)
+{
+    char buf[1024];
+    char *key, *data;
+    char name[3][100];
+    int ret;
+
+    G_debug(1, "Reading raster settings ..");
+
+    /* default values */
+    PS.rst.do_rgb  = 0;
+    PS.rst.do_grey = 0;
+    PS.rst.do_mask = 0;
+    default_psline(&(PS.rst.outline));
+    PS.rst.outline.width = 0.;
+    set_color_rgb(&(PS.rst.mask_color), 0, 0, 0);
+
+    /* inline argument */
+    ret = sscanf(arg, "%s %s %s", name[0], name[1], name[2]);
+    if (ret != 1 && ret != 3) {
+        error(key, data, "illegal raster request");
+    }
+    if (ret == 3) {
+        PS.rst.files = load_rgb(name[0], name[1], name[2]);
+        PS.rst.do_rgb = 1;
+    }
+    else {
+        if (name[0][0] == ':') {
+            PS.rst.files = load_group(name[0] + 1);
+            PS.rst.do_rgb = 1;
+        }
+        else {
+            PS.rst.files = load_cell(0, name[0]);
+            PS.rst.fd[1] = PS.rst.fd[2] = -1;
+            PS.rst.do_rgb = 0;
+        }
+    }
+
+    /* process options */
+    while (input(2, buf))
+    {
+		if (!key_data(buf, &key, &data)) {
+			continue;
+        }
+       if (KEY("grey") || KEY("gray")) {
+            PS.rst.do_grey = scan_yesno(key, data);
+            continue;
+        }
+        if (KEY("maskcolor")) {
+            if (!scan_color(data, &(PS.rst.mask_color))) {
+                error(key, data, "illegal raster mask color request");
+            }
+            continue;
+        }
+        if (KEY("maskcell")) {
+            if (PS.rst.do_rgb) {
+                error(key, data, "illegal maskcell with rgb/group raster");
+            }
+            ret = sscanf(data, "%s %s", name[1], name[2]);
+            if (ret != 1 && ret != 2) {
+                error(key, data, "illegal maskcell raster request");
+            }
+            PS.rst.do_mask = 1;
+            load_cell(1, name[1]); /* slot 1: mask */
+            if (ret == 2)
+                load_cell(2, name[2]); /* slot 2: background */
+            continue;
+        }
+        if (KEY("outline")) {
+            if (PS.rst.do_rgb) {
+                error(key, data, "illegal outline with rgb raster");
+            }
+            read_psline(data, &(PS.rst.outline));
+            continue;
+        }
+        if (KEY("setcolor")) {
+            int i, count, R, G, B;
+            PSCOLOR color;
+            DCELL *val_list, dmin, dmax;
+            char colorbuf[100], catsbuf[100];
+            /* set color inline */
+            if (PS.rst.fd[0] < 0 || PS.rst.do_rgb) {
+                error(key, data, "setcolor is not for RGB raster");
+            }
+            if (sscanf(data, "%s %[^\n]", catsbuf, colorbuf) == 2)
+            {
+                if (!scan_color(colorbuf, &color)) {
+                    error(key, data, "illegal setcolor request");
+                    continue;
+                }
+                R = (int)(255.*color.r);
+                G = (int)(255.*color.g);
+                B = (int)(255.*color.b);
+                if (strncmp(catsbuf, "null", 4) == 0) {
+                    G_set_null_value_color(R, G, B, &(PS.rst.colors[0]));
+                    continue;
+                }
+                if (strncmp(catsbuf, "default", 7) == 0) {
+                    G_set_default_color(R, G, B, &(PS.rst.colors[0]));
+                    continue;
+                }
+                if ((count = parse_val_list(catsbuf, &val_list)) < 0) {
+                    error(key, data, "illegal value list");
+                    continue;
+                }
+                for (i = 0; i < count; i += 2)
+                {
+                    dmin = val_list[i];
+                    dmax = val_list[i + 1];
+                    G_add_d_raster_color_rule(&dmin, R, G, B,
+                                              &dmax, R, G, B, &(PS.rst.colors[0]));
+                }
+                G_free(val_list);
+            }
+            continue;
+        }
+		error(key, data, "illegal raster sub-request");
+    }
+
+    return 0;
+}

Added: grass-addons/ps/ps.output/r_rlegend.c
===================================================================
--- grass-addons/ps/ps.output/r_rlegend.c	                        (rev 0)
+++ grass-addons/ps/ps.output/r_rlegend.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,156 @@
+/* File: r_rlegend.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "raster.h"
+// #include "rlegend.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+#define KEY(x) (strcmp(key,x)==0)
+
+int read_rlegend(char *arg)
+{
+    char buf[1024];
+    char *key, *data, *mapset;
+    double dimen;
+
+    G_debug(1, "Reading rlegend settings ..");
+
+    /* default values */
+    PS.rl.name[0]      = 0;
+	PS.rl.height       = 0.;
+    PS.rl.do_gradient  = FALSE;
+    PS.rl.do_nodata    = FALSE;
+	PS.rl.tickbar      = 3;
+	PS.rl.whiteframe   = 1;
+    PS.rl.custom_range = FALSE;
+    PS.rl.cat_order[0] = 0;
+    default_font(&(PS.rl.legend.font));
+    default_frame(&(PS.rl.legend.box), LEFT, LOWER);
+    PS.rl.legend.width = -1.0;
+    PS.rl.legend.cols  = 1;
+    PS.rl.legend.span  = 4.;
+    default_font(&(PS.rl.legend.title_font));
+    PS.rl.legend.title[0] = 0;
+
+    /* process options */
+    while (input(2, buf))
+    {
+	    if (!key_data(buf, &key, &data)) {
+	        continue;
+        }
+        if (KEY("title")) {
+            G_strip(data);
+            strncpy(PS.rl.legend.title, data, 50);
+            read_font("", &(PS.rl.legend.title_font));
+            continue;
+        }
+        if (KEY("font")) {
+            G_strip(data);
+            read_font(data, &(PS.rl.legend.font));
+            continue;
+        }
+        if (KEY("frame")) {
+          read_frame(&(PS.rl.legend.box));
+          continue;
+        }
+        if (KEY("width")) {
+            if(scan_dimen(data, &(PS.rl.legend.width)) != 1) {
+                PS.rl.legend.width = -1.;
+                error(key, data, "illegal width request (rlegend)");
+            }
+            continue;
+        }
+        if (KEY("cols")) {
+            int n;
+            n = sscanf(data, "%d %lf", &(PS.rl.legend.cols), &(PS.rl.legend.span));
+            if (n == 1 || n == 2) {
+                if (PS.rl.legend.cols < 0) PS.rl.legend.cols = 1;
+                if (n == 1) PS.rl.legend.span = -1.;
+            }
+            else
+                error(key, data, "illegal cols/span request (rlegend)");
+            continue;
+        }
+	    if (KEY("height")) {
+	        if (scan_dimen(data, &(PS.rl.height)) != 1) {
+			    error(key, data, "illegal height request (rlegend)");
+	        }
+		    continue;
+	    }
+	    if (KEY("raster")) {
+            G_strip(data);
+            mapset = G_find_file("cell", data, "");
+            if (PS.rl.mapset == NULL) {
+                    PS.rl.name[0] = 0;
+                    error(key, data, "illegal raster request (rlegend)");
+	        }
+            strcpy(PS.rl.name, data);
+            strcpy(PS.rl.mapset, mapset);
+            continue;
+	    }
+	    if (KEY("range")) {
+	        if (sscanf(data, "%lf %lf", &(PS.rl.min), &(PS.rl.max)) != 2) {
+			    PS.rl.custom_range = FALSE;
+                error(key, data, "illegal range request (rlegend)");
+	        }
+	        else {
+                double tmpD;
+			    PS.rl.custom_range = TRUE;
+			    if (PS.rl.min > PS.rl.max) {
+			        tmpD = PS.rl.min;
+			        PS.rl.min = PS.rl.max;
+		            PS.rl.max = tmpD;
+			    }
+			    continue;
+	        }
+	    }
+        if (KEY("nodata")) {
+            PS.rl.do_nodata = scan_yesno(key, data);
+            continue;
+        }
+        if (KEY("gradient")) {
+            PS.rl.do_gradient = scan_yesno(key, data);
+            continue;
+        }
+        if (KEY("tick")) {
+            if (scan_dimen(data, &dimen) != 1) {
+                error(key, data, "illegal tickbar request (rlegend)");
+            }
+		    PS.rl.tickbar = (int)(dimen);
+		    continue;
+	    }
+	    if (KEY("whiteframe")) {
+            if (scan_dimen(data, &dimen) != 1) {
+                error(key, data, "illegal whiteframe request (rlegend)");
+            }
+            PS.rl.whiteframe = (int)(dimen);
+		    continue;
+	    }
+        if (KEY("order")) {
+            G_strip(data);
+            strncpy(PS.rl.cat_order, data, 510);
+            PS.rl.cat_order[510] = 0;
+            continue;
+        }
+        error(key, data, "illegal rlegend sub-request");
+    }
+
+    /* end check */
+    if (!PS.rl.name) {
+        PS.do_rlegend = 0;
+        error(key, data, "rlegend need 'raster' option sub-request");
+    }
+    PS.do_rlegend = 1;
+
+    return 0;
+}

Added: grass-addons/ps/ps.output/r_scalebar.c
===================================================================
--- grass-addons/ps/ps.output/r_scalebar.c	                        (rev 0)
+++ grass-addons/ps/ps.output/r_scalebar.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,161 @@
+/* File: r_scalebar.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "ps_info.h"
+#include "local_proto.h"
+#include "scalebar.h"
+
+#define KEY(x) (strcmp(key,x)==0)
+#ifndef ABS
+    #define ABS(x) (x > 0 ? x : -x)
+#endif
+
+
+int read_scalebar(void)
+{
+    char buf[1024];
+    char *key, *data;
+
+    G_debug(1, "Reading scalebar settings ..");
+
+    /* default values */
+    PS.sbar.ucode    = SB_UNITS_AUTO;
+    PS.sbar.units[0] = 0;
+    PS.sbar.length   = -1.;
+    PS.sbar.height   = 4.;      /* default height in points */
+    PS.sbar.labels   = 1;       /* label each segment */
+    PS.sbar.segments = 4;		/* four segments */
+    PS.sbar.sublabs  = 1;       /* label pre-segment */
+    PS.sbar.subsegs  = 1;       /* division pre-segment */
+    default_font(&(PS.sbar.font));
+    default_frame(&(PS.sbar.box), LEFT, UPPER);
+    set_color_rgb(&(PS.sbar.fcolor), 255, 255, 255);
+
+    /* process options */
+    while (input(2, buf))
+    {
+	    if (!key_data(buf, &key, &data)) {
+	        continue;
+        }
+        if (KEY("frame")) {
+            read_frame(&(PS.sbar.box));
+            continue;
+        }
+        if (KEY("font")) {
+            read_font(data, &(PS.sbar.font));
+            continue;
+        }
+        if (KEY("fcolor")) {
+            if (!scan_color(data, &(PS.sbar.fcolor))) {
+                error(key, data, "illegal fcolor request (scalebar)");
+            }
+            continue;
+        }
+        if (KEY("height")) {
+            if (scan_dimen(data, &(PS.sbar.height)) != 1) {
+                error(key, data, "illegal height request (scalebar)");
+            }
+            continue;
+        }
+	    if (KEY("length")) {
+            if (scan_dimen(data, &(PS.sbar.length)) != 1) {
+                error(key, data, "illegal length request (scalebar)");
+	        }
+            continue;
+	    }
+        if (KEY("major") || KEY("segments")) {
+            int i, j;
+            switch (sscanf(data, "%d %d", &i, &j))
+            {
+                case 1:
+                    PS.sbar.segments = ABS(i);
+                    PS.sbar.labels = 1;
+                    break;
+                case 2:
+                    PS.sbar.segments = ABS(i);
+                    PS.sbar.labels = (j == 0 ? ABS(i)+1 : ABS(j));
+                    break;
+                default:
+                    error(key, data, "illegal segment request (scalebar)");
+                    break;
+            }
+            continue;
+        }
+        if (KEY("minor")) {
+            int i, j;
+            switch (sscanf(data, "%d %d", &i, &j))
+            {
+                case 1:
+                    PS.sbar.subsegs = ABS(i);
+                    PS.sbar.sublabs = 1;
+                    break;
+                case 2:
+                    PS.sbar.subsegs = ABS(i);
+                    PS.sbar.sublabs = (j == 0 ? ABS(i)+1 : ABS(j));
+                    break;
+                default:
+                    error(key, data, "illegal minor request (scalebar)");
+                    break;
+            }
+            continue;
+        }
+        if (KEY("units")) {
+            int ret;
+            char stra[50], strb[50];
+	        G_strip(data);
+            ret = sscanf(data, "%s %s", stra, strb);
+            if (ret != 1 && ret != 2) {
+                error(key, data, "illegal units request (scalebar)");
+            }
+	        if (strcmp(stra, "auto") == 0) {
+                PS.sbar.units[0] = 0;
+                PS.sbar.ucode = SB_UNITS_AUTO;
+    		    continue;
+	        }
+	        else if (G_projection() == PROJECTION_XY) {
+	            error(key, data, "Earth units not available in simple XY location");
+	        }
+	        else if (strcmp(stra, "meters") == 0 || strcmp(stra, "m") == 0) {
+                strcpy(PS.sbar.units, "meters");
+                PS.sbar.ucode = SB_UNITS_METERS;
+	        }
+	        else if (strcmp(stra, "kilometers") == 0 || strcmp(stra, "km") == 0) {
+                strcpy(PS.sbar.units, "kilometers");
+                PS.sbar.ucode = SB_UNITS_KM;
+	        }
+	        else if (strcmp(stra, "feet") == 0 || strcmp(stra, "ft") == 0) {
+                strcpy(PS.sbar.units, "feet");
+                PS.sbar.ucode = SB_UNITS_FEET;
+	        }
+	        else if (strcmp(stra, "miles") == 0 || strcmp(stra, "mil") == 0) {
+                strcpy(PS.sbar.units, "miles");
+		        PS.sbar.ucode = SB_UNITS_MILES;
+	        }
+	        else if (strcmp(stra, "nautmiles") == 0 || strcmp(stra, "nm") == 0) {
+                strcpy(PS.sbar.units, "nautical miles");
+                PS.sbar.ucode = SB_UNITS_NMILES;
+	        }
+	        else {
+                error(key, data, "illegal units request (scalebar)");
+            }
+            if (ret == 2)
+                strcpy(PS.sbar.units, strb);
+            continue;
+	    }
+        error(key, data, "illegal sub-request (scalebar)");
+    }
+
+    if (PS.sbar.type == 'I')
+        PS.sbar.labels = 1;
+
+    return 0;
+}

Added: grass-addons/ps/ps.output/r_vareas.c
===================================================================
--- grass-addons/ps/ps.output/r_vareas.c	                        (rev 0)
+++ grass-addons/ps/ps.output/r_vareas.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,159 @@
+/* File: r_vareas.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <grass/Vect.h>
+#include "vector.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+#define KEY(x) (strcmp(key,x)==0)
+
+
+int read_vareas(char *name)
+{
+    int i;
+    char buf[1024];
+    char *key, *data, *mapset;
+    VAREAS *vector = NULL;
+
+    G_debug(1, "Reading vlines settings ..");
+
+    i = vector_new();   /* G_realloc */
+
+    /* inline argument */
+    mapset = G_find_file("vector", name, "");
+    if (mapset == NULL) {
+        error("ERROR:", name, "Can't find vector map");
+    }
+    PS.vct[i].name   = G_store(name);
+    PS.vct[i].mapset = G_store(mapset);
+    PS.vct[i].data   = G_malloc(sizeof(VAREAS));
+
+    Vect_set_open_level(2);     /* level 2: topology */
+    Vect_set_fatal_error(GV_FATAL_PRINT);
+
+    if (2 > Vect_open_old(&(PS.vct[i].Map), name, mapset))
+    {
+        sprintf(buf, "%s in %s", name, mapset);
+        error("ERROR:", buf, "can't open vector map");
+        return 0;
+    }
+
+    /* generic default values */
+    PS.vct[i].type   = AREAS;
+    PS.vct[i].id     = i;
+    PS.vct[i].layer  = 1;
+    PS.vct[i].cats   = NULL;
+    PS.vct[i].where  = NULL;
+    PS.vct[i].masked = 0;
+    PS.vct[i].label  = G_store(name);
+    PS.vct[i].lpos   = 0;
+
+    /* specific default values */
+    vector = (VAREAS *)PS.vct[i].data;
+    unset_color(&(vector->fcolor));
+    vector->width    = 0.;
+    vector->type_pat = 1;   /* colored pattern */
+    vector->pat      = NULL;
+    vector->pwidth   = 1.;
+    vector->scale    = 1.;
+    vector->rgbcol   = NULL;
+
+    /* process options */
+    while (input(2, buf))
+    {
+        if (!key_data(buf, &key, &data)) {
+            continue;
+        }
+        if (KEY("width")) {
+            G_strip(data);
+            scan_dimen(data, &(vector->width));
+            continue;
+        }
+        if (KEY("line")) {
+            read_psline(data, &(vector->line));
+            continue;
+        }
+        if (KEY("fcolor")) {
+            char stra[50], strb[50];
+            int ret = sscanf(data, "%s %s", stra, strb);
+            if (ret != 1 && ret != 2) {
+                error(key, data, "illegal fcolor (vareas)");
+            }
+            if (!scan_color(stra, &(vector->fcolor))) {
+                error(key, data, "illegal fcolor (vareas)");
+            }
+            if (ret == 2) {
+                vector->rgbcol = G_store(strb);
+                G_warning("Request fcolor from database '%s' (vareas)",
+                          vector->rgbcol);
+                vector->type_pat = 2;   /* uncolored pattern */
+            }
+            continue;
+        }
+        if (KEY("pat")) {
+            G_chop(data);
+            vector->pat = G_store(data);
+            continue;
+        }
+        if (KEY("scale")) {
+            G_chop(data);
+            vector->scale = atof(data);
+            continue;
+        }
+        if (KEY("pwidth")) {
+            if (scan_dimen(data, &(vector->pwidth)) != 1) {
+                error(key, data, "illegal pattern width (vareas)");
+            }
+            continue;
+        }
+        /* common options of all vectors */
+        if (KEY("layer")) {
+            G_strip(data);
+            PS.vct[i].layer = atoi(data);
+            if (PS.vct[i].layer < 1)
+                PS.vct[i].layer = 1;
+            continue;
+        }
+        if (KEY("cats") || KEY("cat")) {
+            G_strip(data);
+            PS.vct[i].cats = G_store(data);
+            continue;
+        }
+        if (KEY("where")) {
+            G_strip(data);
+            PS.vct[i].where = G_store(data);
+            continue;
+        }
+        if (KEY("masked")) {
+            PS.vct[i].masked = scan_yesno(key, data);
+            if (PS.vct[i].masked)
+                PS.need_mask = 1;
+            continue;
+        }
+        if (KEY("label")) {
+            G_strip(data);
+            PS.vct[i].label = G_store(data);
+            if (PS.vct[i].lpos == 0)
+                PS.vct[i].lpos = 1;
+            continue;
+        }
+        if (KEY("lpos")) {
+            G_strip(data);
+            PS.vct[i].lpos = atoi(data);
+            continue;
+        }
+        error(key, "", "illegal request (vareas)");
+    }
+
+    return 1;
+}

Added: grass-addons/ps/ps.output/r_vlegend.c
===================================================================
--- grass-addons/ps/ps.output/r_vlegend.c	                        (rev 0)
+++ grass-addons/ps/ps.output/r_vlegend.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,87 @@
+/* File: r_vlegend.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "vlegend.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+#define KEY(x) (strcmp(key,x)==0)
+
+
+int read_vlegend(char *arg)
+{
+    char buf[1024];
+    char *key, *data;
+
+
+    G_debug(1, "Reading vlegend settings ..");
+
+    /* default values */
+	PS.vl.legend.cols  = 1;
+	PS.vl.legend.span  = 10.;
+	PS.vl.legend.width = -1.;
+    default_font(&(PS.vl.legend.font));
+    default_frame(&(PS.vl.legend.box), LEFT, LOWER);
+    PS.vl.legend.title[0] = 0;
+    default_font(&(PS.vl.legend.title_font));
+    PS.vl.order[0] = 0;
+
+    /* process options */
+    while (input(2, buf))
+    {
+        if (!key_data(buf, &key, &data)) {
+            continue;
+        }
+        if (KEY("title")) {
+            G_strip(data);
+            strncpy(PS.vl.legend.title, data, 50);
+            read_font("", &(PS.vl.legend.title_font));
+            continue;
+        }
+        if (KEY("font")) {
+          read_font(data, &(PS.vl.legend.font));
+          continue;
+        }
+        if (KEY("frame")) {
+          read_frame(&(PS.vl.legend.box));
+          continue;
+        }
+        if (KEY("cols")) {
+            int n;
+            n = sscanf(data, "%d %lf", &(PS.vl.legend.cols), &(PS.vl.legend.span));
+            if (n == 1 || n == 2) {
+                if (PS.vl.legend.cols < 0) PS.vl.legend.cols = 1;
+                if (n == 1) PS.vl.legend.span = -1.;
+            }
+            else
+                error(key, data, "illegal cols/span request (vlegend)");
+            continue;
+        }
+        if (KEY("width")) {
+            if(scan_dimen(data, &(PS.vl.legend.width)) != 1) {
+                PS.vl.legend.width = -1.;
+                error(key, data, "illegal width request (vlegend)");
+            }
+            continue;
+        }
+        if (KEY("order")) {
+            G_strip(data);
+            strncpy(PS.vl.order, data, 510);
+            PS.vl.order[510] = 0;
+            continue;
+        }
+        error(key, data, "illegal vlegend sub-request");
+    }
+
+    PS.do_vlegend = PS.vct_files;
+    return 0;
+}

Added: grass-addons/ps/ps.output/r_vlines.c
===================================================================
--- grass-addons/ps/ps.output/r_vlines.c	                        (rev 0)
+++ grass-addons/ps/ps.output/r_vlines.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,148 @@
+/* File: r_vlines.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <grass/Vect.h>
+#include "vector.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+#define KEY(x) (strcmp(key,x)==0)
+
+
+int read_vlines(char *name)
+{
+    int i;
+    char buf[1024];
+    char *key, *data, *mapset;
+    VLINES *vector;
+
+
+    G_debug(1, "Reading vlines settings ..");
+
+    i = vector_new();   /* G_realloc */
+
+    /* inline argument */
+    mapset = G_find_file("vector", name, "");
+    if (mapset == NULL) {
+        error("ERROR:", name, "Can't find vector map");
+    }
+    PS.vct[i].name   = G_store(name);
+    PS.vct[i].mapset = G_store(mapset);
+    PS.vct[i].data   = G_malloc(sizeof(VLINES));
+
+    Vect_set_open_level(2);     /* level 2: topology */
+    Vect_set_fatal_error(GV_FATAL_PRINT);
+
+    if (2 > Vect_open_old(&(PS.vct[i].Map), name, mapset))
+    {
+        sprintf(buf, "%s in %s", name, mapset);
+        error("ERROR:", buf, "can't open vector map");
+        return 0;
+    }
+
+    /* generic default values */
+    PS.vct[i].type   = LINES;
+    PS.vct[i].id     = i;
+    PS.vct[i].layer  = 1;
+    PS.vct[i].cats   = NULL;
+    PS.vct[i].where  = NULL;
+    PS.vct[i].masked = 0;
+    PS.vct[i].label  = NULL;
+    PS.vct[i].lpos   = 0;
+
+    /* specific default values */
+    vector = (VLINES *)PS.vct[i].data;
+    vector->type        = GV_LINE;
+    default_psline(&(vector->line));
+    default_psline(&(vector->hline));
+    vector->hline.width = 0.;
+    vector->rgbcol      = NULL;
+    vector->offset      = 0.;
+
+
+    /* process options */
+    while (input(2, buf))
+    {
+        if (!key_data(buf, &key, &data)) {
+            continue;
+        }
+        if (KEY("type")) {
+            G_strip(data);
+            if (strcmp(data, "boundary") == 0)
+                vector->type = GV_BOUNDARY;
+            /* else default GV_LINE */
+            continue;
+        }
+        if (KEY("rgbcol")) {
+            G_strip(data);
+            vector->rgbcol = G_store(data);
+            G_warning("Request line color from database '%s' (vlines)",
+                      vector->rgbcol);
+            continue;
+        }
+        if (KEY("line")) {
+            read_psline(data, &(vector->line));
+            continue;
+        }
+        if (KEY("hline")) {
+            if (scan_dimen(data, &(vector->offset)) == 0) {
+                vector->offset = 0.;
+            }
+            read_psline("", &(vector->hline));
+            if (vector->hline.width > 0 && vector->offset == 0.) {
+                vector->hline.width =
+                        vector->line.width +
+                        2. * vector->hline.width;
+            }
+            continue;
+        }
+        /* common options of all vectors */
+        if (KEY("layer")) {
+            G_strip(data);
+            PS.vct[i].layer = atoi(data);
+            if (PS.vct[i].layer < 1)
+                PS.vct[i].layer = 1;
+            continue;
+        }
+        if (KEY("cats") || KEY("cat")) {
+            G_strip(data);
+            PS.vct[i].cats = G_store(data);
+            continue;
+        }
+        if (KEY("where")) {
+            G_strip(data);
+            PS.vct[i].where = G_store(data);
+            continue;
+        }
+        if (KEY("masked")) {
+            PS.vct[i].masked = scan_yesno(key, data);
+            if (PS.vct[i].masked)
+                PS.need_mask = 1;
+            continue;
+        }
+        if (KEY("label")) {
+            G_strip(data);
+            PS.vct[i].label = G_store(data);
+            if (PS.vct[i].lpos == 0)
+                PS.vct[i].lpos = 1;
+            continue;
+        }
+        if (KEY("lpos")) {
+            G_strip(data);
+            PS.vct[i].lpos = atoi(data);
+            continue;
+        }
+        error(key, "", "illegal request (vlines)");
+    }
+
+    return 1;
+}

Added: grass-addons/ps/ps.output/r_vpoints.c
===================================================================
--- grass-addons/ps/ps.output/r_vpoints.c	                        (rev 0)
+++ grass-addons/ps/ps.output/r_vpoints.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,169 @@
+/* File: r_vpoints.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <grass/Vect.h>
+#include "vector.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+#define KEY(x) (strcmp(key,x)==0)
+
+
+int read_vpoints(char *name)
+{
+    int i;
+    char buf[1024];
+    char *key, *data, *mapset;
+    VPOINTS *vector;
+
+
+    G_debug(1, "Reading vlines settings ..");
+
+    i = vector_new();   /* G_realloc */
+
+    /* inline argument */
+    mapset = G_find_file("vector", name, "");
+    if (mapset == NULL) {
+        error("ERROR:", name, "Can't find vector map");
+    }
+    PS.vct[i].name   = G_store(name);
+    PS.vct[i].mapset = G_store(mapset);
+    PS.vct[i].data   = G_malloc(sizeof(VPOINTS));
+
+    Vect_set_open_level(2);     /* level 2: topology */
+    Vect_set_fatal_error(GV_FATAL_PRINT);
+
+    if (2 > Vect_open_old(&(PS.vct[i].Map), name, mapset))
+    {
+        sprintf(buf, "%s in %s", name, mapset);
+        error("ERROR:", buf, "can't open vector map");
+        return 0;
+    }
+
+    /* generic default values */
+    PS.vct[i].type   = POINTS;
+    PS.vct[i].id     = i;
+    PS.vct[i].layer  = 1;
+    PS.vct[i].cats   = NULL;
+    PS.vct[i].where  = NULL;
+    PS.vct[i].masked = 0;
+    PS.vct[i].label  = NULL;
+    PS.vct[i].lpos   = 0;
+
+    /* specific default values */
+    vector            = (VPOINTS *)PS.vct[i].data;
+    vector->type      = GV_POINT;
+    vector->symbol    = G_store("basic/circle");
+    vector->size      = 1.0;
+    vector->sizecol   = NULL;
+    vector->rotate    = 0.0;
+    vector->rotatecol = NULL;
+    vector->scale     = 1.0;
+    unset_color(&(vector->fcolor));
+    default_psline(&(vector->line));
+
+    /* process options */
+    while (input(2, buf))
+    {
+        if (!key_data(buf, &key, &data)) {
+            continue;
+        }
+        if (KEY("type")) {
+            G_strip(data);
+            if (strcmp(data, "centroid"))
+                vector->type = GV_CENTROID;
+            /* else default GV_POINT */
+            continue;
+        }
+        if (KEY("symbol")) {
+            vector->symbol = G_store(data);
+            continue;
+        }
+        if (KEY("line")) {
+            read_psline(data, &(vector->line));
+            continue;
+        }
+        if (KEY("fcolor")) {
+            if (!scan_color(data, &(vector->fcolor))) {
+                error(key, data, "illegal fcolor request (vpoints)");
+            }
+            continue;
+        }
+        if (KEY("size")) {
+            char stra[50], strb[50];
+            int ret = sscanf(data, "%s %s", stra, strb);
+            if (ret != 1 && ret != 2) {
+                error(key, data, "illegal size request (vpoints)");
+            }
+            vector->size = atof(stra);
+            if (ret == 2)
+                vector->sizecol = G_store(strb);
+            continue;
+        }
+        if (KEY("scale")) {
+            if (scan_dimen(data, &(vector->scale)) != 1) {
+                error(key, data, "illegal scale request (vpoints)");
+            }
+            continue;
+        }
+        if (KEY("rotate")) {
+            char stra[50], strb[50];
+            int ret = sscanf(data, "%s %s", stra, strb);
+            if (ret != 1 && ret != 2) {
+                error(key, data, "illegal rotate request (vpoints)");
+            }
+            vector->rotate = atof(stra);
+            if (ret == 2)
+                vector->rotatecol = G_store(strb);
+            continue;
+        }
+        /* common options of all vectors */
+        if (KEY("layer")) {
+            G_strip(data);
+            PS.vct[i].layer = atoi(data);
+            if (PS.vct[i].layer < 1)
+                PS.vct[i].layer = 1;
+            continue;
+        }
+        if (KEY("cats") || KEY("cat")) {
+            G_strip(data);
+            PS.vct[i].cats = G_store(data);
+            continue;
+        }
+        if (KEY("where")) {
+            G_strip(data);
+            PS.vct[i].where = G_store(data);
+            continue;
+        }
+        if (KEY("masked")) {
+            PS.vct[i].masked = scan_yesno(key, data);
+            if (PS.vct[i].masked)
+                PS.need_mask = 1;
+            continue;
+        }
+        if (KEY("label")) {
+            G_strip(data);
+            PS.vct[i].label = G_store(data);
+            if (PS.vct[i].lpos == 0)
+                PS.vct[i].lpos = 1;
+            continue;
+        }
+        if (KEY("lpos")) {
+            G_strip(data);
+            PS.vct[i].lpos = atoi(data);
+            continue;
+        }
+        error(key, "", "illegal request (vpoints)");
+    }
+
+    return 1;
+}

Added: grass-addons/ps/ps.output/raster.c
===================================================================
--- grass-addons/ps/ps.output/raster.c	                        (rev 0)
+++ grass-addons/ps/ps.output/raster.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,32 @@
+/* File: raster.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <string.h>
+#include "raster.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+int raster_close(void)
+{
+    int i;
+
+    for (i = 0; i < 3; i++)
+    {
+        if (PS.rst.fd[i] >= 0) {
+    	    G_close_cell(PS.rst.fd[i]);
+	        G_free(PS.rst.name[i]);
+	        G_free(PS.rst.mapset[i]);
+	        G_free_colors(&(PS.rst.colors[i]));
+	        PS.rst.fd[i] = -1;
+        }
+    }
+
+    return 1;
+}

Added: grass-addons/ps/ps.output/raster.h
===================================================================
--- grass-addons/ps/ps.output/raster.h	                        (rev 0)
+++ grass-addons/ps/ps.output/raster.h	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,39 @@
+#ifndef _RASTER_H_
+#define _RASTER_H_
+
+/* Header file: raster.h
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include "lines.h"
+#include "colors.h"
+#include <grass/imagery.h>
+
+typedef struct
+{
+    int files;
+    char *title;
+
+    struct Categories cats;
+    struct Colors colors[3];
+    CELL min, max;  /* to get color table, in gradient */
+
+    int fd[3];
+    char *name[3], *mapset[3];
+
+    int do_rgb;
+    int do_grey;
+    int do_mask;
+    PSCOLOR mask_color;
+
+    PSLINE outline;
+
+} RASTER;
+
+#endif

Added: grass-addons/ps/ps.output/rlegend.h
===================================================================
--- grass-addons/ps/ps.output/rlegend.h	                        (rev 0)
+++ grass-addons/ps/ps.output/rlegend.h	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,36 @@
+#ifndef _RLEGEND_H_
+#define _RLEGEND_H_
+
+/* Header file: rlegend.h
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <stdio.h>
+#include "legends.h"
+
+typedef struct
+{
+    char name[128];
+    char mapset[128];
+	LEGEND legend;
+
+    /* category rlegend */
+    int do_nodata;          /* show no data categoty */
+    char cat_order[512];    /* category custom order */
+
+    /* gradient rlegend */
+    int do_gradient;        /* forze gradient when no float */
+    double height;          /* Next only for float raster */
+	int custom_range;
+    double min, max;
+    int tickbar;
+	int whiteframe;
+} RLEGEND;
+
+#endif

Added: grass-addons/ps/ps.output/scalebar.h
===================================================================
--- grass-addons/ps/ps.output/scalebar.h	                        (rev 0)
+++ grass-addons/ps/ps.output/scalebar.h	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,44 @@
+#ifndef _SCALEBAR_H_
+#define _SCALEBAR_H_
+
+/* Header file: scalebar.h
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <stdio.h>
+#include "fonts.h"
+#include "frames.h"
+
+
+/* units options */
+#define SB_UNITS_AUTO	0
+#define SB_UNITS_METERS	1
+#define SB_UNITS_KM	    2
+#define SB_UNITS_FEET	3
+#define SB_UNITS_MILES	4
+#define SB_UNITS_NMILES	5
+
+typedef struct
+{
+    char type;
+    double length, height;
+
+    PSFRAME box;
+    PSFONT font;
+    PSCOLOR fcolor;
+
+    int labels, segments;   /* normal segments */
+    int sublabs, subsegs;   /* first segment subdivisions */
+
+    int ucode;
+    char units[50];
+
+} SCALEBAR;
+
+#endif

Added: grass-addons/ps/ps.output/scanners.c
===================================================================
--- grass-addons/ps/ps.output/scanners.c	                        (rev 0)
+++ grass-addons/ps/ps.output/scanners.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,145 @@
+
+#include <string.h>
+#include "colors.h"
+#include "conversion.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+
+/* scan dimensions on the map */
+int scan_easting(char *buf, double *f)
+{
+    if (scan_percent(buf, f, PS.map.west, PS.map.east))
+	    return 1;
+    return G_scan_easting(buf, f, PS.map.proj);
+}
+
+int scan_northing(char *buf, double *f)
+{
+    if (scan_percent(buf, f, PS.map.south, PS.map.north))
+	    return 1;
+    return G_scan_northing(buf, f, PS.map.proj);
+}
+
+int scan_percent(char *buf, double *f, double min, double max)
+{
+    char percent[3];
+
+    *percent = 0;
+    if (sscanf(buf, "%lf%2s", f, percent) != 2)
+	    return 0;
+    if (strcmp(percent, "%") != 0)
+	    return 0;
+    *f = min + (max - min) * (*f / 100.0);
+        return 1;
+}
+
+/* scan references */
+int scan_ref(char *buf, int *xref, int *yref)
+{
+    char refx[10], refy[10];
+
+    *xref = *yref = CENTER;
+    if (sscanf(buf, "%9s %9s", refx, refy) != 2)
+        return 0;
+
+    if(strcmp(refx, "LEFT") == 0 || strcmp(refx, "left") == 0)
+        *xref = LEFT;
+    else if(strcmp(refx, "CENTER") == 0 || strcmp(refx, "center") == 0)
+        *xref = CENTER;
+    else if(strcmp(refx, "RIGHT") == 0 || strcmp(refx, "right") == 0)
+        *xref = RIGHT;
+    else
+        return 0;
+
+    if(strcmp(refy, "UPPER") == 0 || strcmp(refy, "upper") == 0)
+        *yref = UPPER;
+    else if(strcmp(refy, "CENTER") == 0 || strcmp(refy, "center") == 0)
+        *yref = CENTER;
+    else if(strcmp(refy, "LOWER") == 0 || strcmp(refy, "lower") == 0)
+        *yref = LOWER;
+    else
+        return 0;
+
+    return 1;
+}
+
+/* */
+int scan_yesno(char *key, char *data)
+{
+    char buf;
+
+    if (sscanf(data, "%c", &buf) != 1)
+        return 1;
+    if (buf == 'y' || buf == 'Y')
+        return 1;
+    if (buf == 'n' || buf == 'N')
+        return 0;
+
+    error(key, data, "illegal yes/no option");
+    return 0;
+}
+
+int scan_color(char *data, PSCOLOR *color)
+{
+    if (set_color_name(color, data)) {
+        return 1;
+    }
+    return 0;
+}
+
+
+
+int scan_dimen(char *data, double *d)
+{
+    int ret;
+    char unit = ' ';
+
+    ret = sscanf(data, "%lf%c", d, &unit);
+
+    if (ret == 1)
+        unit = ' ';
+    else if (ret != 2) {
+        *d = 0.;
+        return 0;
+    }
+
+    switch (unit)
+    {
+        /* metric to points */
+        case 'i': *d *= INCH_TO_POINT;
+            break;
+        case 'm': *d *= MM_TO_POINT;
+            break;
+        case 'c': *d *= CM_TO_POINT;
+            break;
+        /* special : percent*/
+        case '%':
+            return 2;
+    }
+
+    return (*d < 0 ? -1 : 1);
+}
+
+
+int scan_second(char *data, double *d)
+{
+    int ret;
+    char unit = ' ';
+
+    ret = sscanf(data, "%lf%c", d, &unit);
+
+    if (ret == 1)
+        unit = ' ';
+    else if (ret != 2 || *d < 0.) {
+        *d = 0.;
+        return 0;
+    }
+
+    if (unit == '\'' || unit == 'm')
+        *d *= 60.;
+    else if (unit == 'º' || unit == 'd')
+        *d *= 3600.;
+
+    return 1;
+}

Added: grass-addons/ps/ps.output/set_draw.c
===================================================================
--- grass-addons/ps/ps.output/set_draw.c	                        (rev 0)
+++ grass-addons/ps/ps.output/set_draw.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,227 @@
+/* File: set_draw.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+#include <string.h>
+#include <math.h>
+#include <grass/symbol.h>
+#include <grass/gprojects.h>
+#include "colors.h"
+#include "ps_info.h"
+
+#define PI   3.14159265359
+
+#define KEY(x) (strcmp(x,key)==0)
+
+int set_draw(char * key, char *data)
+{
+    char label[100], buf[256];
+    int i;
+    double d, lw, e1, e2, n1, n2;
+    PSCOLOR color;
+
+    if (KEY("direct"))
+    {
+        fprintf(PS.fp, " %s ", data);
+    }
+    else if (KEY("color"))
+    {
+        set_color_name(&color, data);
+        set_ps_color(&color);
+    }
+    else if (KEY("font"))
+    {
+        i = sscanf(data, "%s %s %lf", label, buf, &d);
+        if (i != 2 && i != 3)
+        {
+            error(key, data, "font need 2 or 3 parameters (name, size, and [extend])");
+        }
+        if (scan_dimen(buf, &lw) != 1) {
+            error(key, data, "size not valid (font)");
+        }
+        fprintf(PS.fp, "(%s) FN %.1f ", label, lw);
+        if (i == 2 )
+            fprintf(PS.fp, "FS ");
+        else
+            fprintf(PS.fp, "%.2f FE ", d);
+    }
+    else if (KEY("text"))
+    {
+        if (sscanf(data, "%lf %lf %[^\n]", &e1, &n1, label) != 3) {
+            error(key, data, "text need 3 parameters (east, north and text)");
+        }
+        set_xy_where("", e1, n1, "M ");
+        fprintf(PS.fp, "(%s) SHCC\n", label);
+    }
+    else if (KEY("moveto"))
+    {
+        if (sscanf(data, "%s %lf %lf", label, &e1, &n1) != 3) {
+            error(key, data, "moveto need 3 parameters");
+        }
+        if (scan_dimen(label, &lw) != 1) {
+            error(key, data, "width not valid (line)");
+        }
+        fprintf(PS.fp, "%.1f LW", lw);
+        set_xy_where("", e1, n1, "M ");
+    }
+    else if (KEY("lineto"))
+    {
+        if (sscanf(data, "%lf %lf", &e1, &n1) != 2) {
+            error(key, data, "lineto need 2 parameters (east and north)");
+        }
+        set_xy_where("", e1, n1, "L ");
+    }
+    else if (KEY("endto"))
+    {
+        if (sscanf(data, "%lf %lf", &e1, &n1) != 2) {
+            error(key, data, "endto need 2 parameters");
+        }
+        set_xy_where("", e1, n1, "LS\n");
+    }
+    else if (KEY("line"))
+    {
+        if (sscanf(data, "%s %lf %lf %lf %lf", label, &e1, &n1, &e2, &n2) != 5) {
+            error(key, data, "line need 5 parameters");
+        }
+        if (scan_dimen(label, &lw) != 1) {
+            error(key, data, "width not valid (line)");
+        }
+        fprintf(PS.fp, "%.1f LW", lw);
+        set_xy_where("", e1, n1, "M");
+        set_xy_where("", e2, n2, "LS\n");
+    }
+    else if (KEY("rect") || KEY("rectangle"))
+    {
+        if (sscanf(data, "%s %lf %lf %lf %lf", label, &e1, &n1, &e2, &n2) != 5) {
+            error(key, data, "rectangle need 5 parameters");
+        }
+        if (scan_dimen(label, &lw) != 1) {
+            error(key, data, "width not valid (rectangle)");
+        }
+        fprintf(PS.fp, "%.1f LW", lw);
+        set_xy_where("", e1, n1, "");
+        set_xy_where("", e2, n2, "B S\n");
+    }
+    else if (KEY("circ") || KEY("circle"))
+    {
+        if (sscanf(data, "%s %lf %lf %lf", label, &e1, &n1, &d) != 4) {
+            error(key, data, "circle need 4 parameters");
+        }
+        if (scan_dimen(label, &lw) != 1) {
+            error(key, data, "width not valid (circle)");
+        }
+        d *= (MT_TO_POINT / (double)PS.scale);
+        fprintf(PS.fp, "%.1f LW", lw);
+        set_xy_where("", e1, n1, "");
+        fprintf(PS.fp, "%.1f 0 360 arc S\n", d);
+    }
+    else if (KEY("arc"))
+    {
+        if (sscanf(data, "%s %lf %lf %lf %lf %lf", label, &e1, &n1, &d, &e2, &n2) != 6) {
+            error(key, data, "arc need 6 parameters");
+        }
+        if (scan_dimen(label, &lw) != 1) {
+            error(key, data, "width not valid (circle)");
+        }
+        d *= (MT_TO_POINT / (double)PS.scale);
+        fprintf(PS.fp, "%.1f LW", lw);
+        set_xy_where("", e1, n1, "");
+        fprintf(PS.fp, "%.1f %.1f %.1f arc S\n", d, e2, n2);
+    }
+    else if (KEY("psfile"))
+    {
+        FILE *fp;
+        if ((fp = fopen(data, "r")) != NULL)
+        {
+            G_message("Reading PostScript include file <%s> ...", data);
+            fprintf(PS.fp, "\n");
+            while (fgets(buf, 256, fp) != NULL)
+                fprintf(PS.fp, "%s", buf);
+            fprintf(PS.fp, "\n");
+            fclose(fp);
+        }
+    }
+    else if (KEY("limit") || KEY("limits"))
+    {
+        fprintf(PS.fp, "%.1f %.1f M ", PS.map_right, PS.map_top);
+        G_format_northing(PS.map.north, label, PS.map.proj);
+        fprintf(PS.fp, "GS (%s) dup SWH ++ neg dup MR pop SHR GR\n", label);
+        G_format_easting(PS.map.east, label, PS.map.proj);
+        fprintf(PS.fp, "GS (%s) dup SWH ++ dup neg 3 1 roll add neg MR 270 ROT SHR GR\n", label);
+        fprintf(PS.fp, "%.1f %.1f M ", PS.map_x, PS.map_y);
+        G_format_easting(PS.map.west, label, PS.map.proj);
+        fprintf(PS.fp, "GS (%s) dup SWH ++ dup MR pop 90 ROT SHL GR\n", label);
+        G_format_northing(PS.map.south, label, PS.map.proj);
+        fprintf(PS.fp, "GS (%s) dup SWH ++ 1 MR pop SHL GR\n", label);
+    }
+    else if (KEY("compass") || KEY("rose"))
+    {
+        char h;
+        int dg, mn;
+        double conv, sec;
+
+        if (sscanf(data, "%lf %lf %lf", &e1, &n1, &d) != 3) {
+            error(key, data, "compass roses need 3 parameters");
+        }
+        d *= (MT_TO_POINT / (double)PS.scale);
+        set_xy_where(".25 LW", e1, n1, "M ");
+        /* exterior */
+        fprintf(PS.fp, "GS 90 ROT ");
+        fprintf(PS.fp, "%.1f 0 90 270 {GS ROT dup 0 LR [1] 0 LD S GR} for ", d);
+        fprintf(PS.fp,
+                " 0 -1 -359 {/i XD GS i ROT dup 0 MR i 10 mod 0 eq "
+                        "{-9 0 LR i neg to_s dup SW 2 div 10 exch MR GS 270 ROT show GR} "
+                        "{i 5 mod 0 eq {-6} {-3} ifelse 0 LR} ifelse S GR} for ");
+        fprintf(PS.fp, " pop GR\n");
+        /* convergence, only for testing the command must have an angle parameter */
+        conv = 0.0;
+        if (PS.map.proj != PROJECTION_LL)
+        {
+            struct pj_info ll_proj, xy_proj;
+
+            init_proj(&ll_proj, &xy_proj);
+            e2 = e1; n2 = n1;
+            pj_do_proj(&e2, &n2, &xy_proj, &ll_proj);
+            n2 = 90.;
+            pj_do_proj(&e2, &n2, &ll_proj, &xy_proj);
+            conv = -1.*atan2(e2-e1, n2-n1)*180./PI;
+        }
+        /* interior */
+        fprintf(PS.fp, "GS %.3f ROT F0S .8 mul FS ", conv+90.);
+        fprintf(PS.fp, "%.1f 0 90 270 {GS ROT dup 0 LR S GR} for ", .60*d);
+        fprintf(PS.fp,
+                " 0 -1 -359 {/i XD GS i ROT dup 0 MR i 10 mod 0 eq "
+                        "{6 0 LR i 30 mod 0 eq "
+                        "{i neg to_s dup SW 2 div 1 exch MR GS 270 ROT show GR} if} "
+                        "{i 5 mod 0 eq {3} {1.5} ifelse 0 LR} ifelse S GR} for ");
+
+        G_lon_parts(conv, &dg, &mn, &sec, &h);
+        fprintf(PS.fp, " 2 div 1 MR F0S 1.25 mul FS (%dº %d' %0.f'' %c) SHC GR\n", dg, mn, sec, h);
+    }
+    else if (KEY("rute"))
+    {
+        if (sscanf(data, "%s %lf %lf %[^\n]", label, &e1, &n1, buf) != 4) {
+            error(key, data, "rute need 4 parameters");
+        }
+        if (scan_dimen(label, &lw) != 1) {
+            error(key, data, "width not valid (rune)");
+        }
+        fprintf(PS.fp, "%.1f LW ", lw);
+        set_xy_where("cP exch 2 copy", e1, n1, "L cP 2 copy 8 2 roll");
+        fprintf(PS.fp,
+                " 4 -1 roll add 2 div 3 1 roll add 2 div exch M"
+                " 4 1 roll sub 3 1 roll exch sub atan GS ROT 0 1 MR (%s) SHC GR S\n", buf);
+    }
+    else
+    {
+        error(key, data, "not found\n");
+    }
+
+    return 1;
+}
+

Added: grass-addons/ps/ps.output/set_geogrid.c
===================================================================
--- grass-addons/ps/ps.output/set_geogrid.c	                        (rev 0)
+++ grass-addons/ps/ps.output/set_geogrid.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,241 @@
+/* File: set_geogrid.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <string.h>
+#include <math.h>
+#include <grass/gis.h>
+#include <grass/glocale.h>
+#include <grass/gprojects.h>
+#include "grids.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+
+/*
+ * LINES OF THE GEOGRID
+ */
+
+int set_lines_geogrid(void)
+{
+    /* make lines */
+    set_geogrid_lines(&(PS.geogrid.mline), PS.geogrid.msep);
+    set_geogrid_lines(&(PS.geogrid.line), PS.geogrid.sep);
+
+    return 1;
+}
+
+int set_geogrid_lines(PSLINE * line, int grid_sep)
+{
+    double sep, n_min, nmin, e_min, emin;
+    double e, n, east, west, north, south;
+    struct pj_info ll_proj, proj;
+
+    if (PS.geogrid.sep <= 0 || PS.geogrid.line.color.none)
+        return 0;
+
+    fprintf(PS.fp, "GS\n");
+    /* set color and set line width */
+    set_ps_line(line);
+
+    sep = (double)grid_sep/3600.;   /* to degrees */
+
+    /* preparing projections */
+    init_proj(&ll_proj, &proj);
+    find_limits(&north, &south, &east, &west, &ll_proj, &proj);
+    n_min = ceil(north / sep) * sep;
+    e_min = ceil(east / sep) * sep;
+
+    /* latitude lines */
+    for (nmin = n_min; nmin >= south; nmin -= sep)
+    {
+        for (emin = e_min; emin >= west; emin -= sep)
+        {
+            e = emin;
+            n = nmin;
+            pj_do_proj(&e, &n, &ll_proj, &proj);    /* LL to PROJ */
+            set_ps_where('M', e, n);                /* PROJ to XY */
+            e = emin - sep;
+            n = nmin;
+            pj_do_proj(&e, &n, &ll_proj, &proj);
+            set_ps_where('L', e, n);
+            fprintf(PS.fp, "S\n");
+        }
+    }
+    /* longitude lines */
+    for (emin = e_min; emin >= west; emin -= sep)
+    {
+        for (nmin = n_min; nmin >= south; nmin -= sep)
+        {
+            e = emin;
+            n = nmin;
+            pj_do_proj(&e, &n, &ll_proj, &proj);
+            set_ps_where('M', e, n);
+            e = emin;
+            n = nmin - sep;
+            pj_do_proj(&e, &n, &ll_proj, &proj);
+            set_ps_where('L', e, n);
+            fprintf(PS.fp, "S\n");
+        }
+    }
+
+    fprintf(PS.fp, "GR\n");
+    return 0;
+}
+
+
+/* select type of number presentation */
+int set_numbers_geogrid(void)
+{
+    char label[50];
+    int i, x, y;
+    double dx, dy;
+    double grid_sep, nmin, emin, dif;
+    double e, n, east, west, north, south;
+    struct pj_info ll_proj, proj;
+
+    if (PS.geogrid.sep <= 0)
+        return 1;
+
+    grid_sep = (double)PS.geogrid.sep/3600.;   /* to degrees */
+
+    /* preparing projections */
+    init_proj(&ll_proj, &proj);
+    find_limits(&north, &south, &east, &west, &ll_proj, &proj);
+
+    /* printf("North %f  South %f\n", north, south); */
+    /* printf("West %f  East %f\n", west, east); */
+
+    /* vertical-right numbers */
+    fprintf(PS.fp, "/GRR [\n");
+    nmin = floor(north / grid_sep) * grid_sep;
+    for (; nmin > south; nmin -= grid_sep)
+    {
+        e = east;
+        n = nmin;
+        pj_do_proj(&e, &n, &ll_proj, &proj);
+        e = PS.map.east;
+        pj_do_proj(&e, &n, &proj, &ll_proj);
+        n = nmin;
+        pj_do_proj(&e, &n, &ll_proj, &proj);
+        if (n > PS.map.north || n < PS.map.south)
+            continue;
+        G_plot_where_xy(PS.map.east, n, &x, &y);
+        dx = ((double)x) / 10.;
+        dy = ((double)y) / 10.;
+        G_format_northing(nmin, label, PROJECTION_LL);
+        fprintf(PS.fp, "[(%s) %.1f %.1f]\n", label, dx, dy);
+    }
+    fprintf(PS.fp, "] def\n");
+
+    /* horizontal-bottom numbers */
+    fprintf(PS.fp, "/GRB [\n");
+    emin = floor(east / grid_sep) * grid_sep;
+    for (; emin > west; emin -= grid_sep)
+    {
+        n = south;
+        e = emin;
+        pj_do_proj(&e, &n, &ll_proj, &proj);
+        n = PS.map.south;
+        pj_do_proj(&e, &n, &proj, &ll_proj);
+        e = emin;
+        pj_do_proj(&e, &n, &ll_proj, &proj);
+        if (e > PS.map.east || e < PS.map.west)
+            continue;
+        G_plot_where_xy(e, PS.map.south, &x, &y);
+        dx = ((double)x) / 10.;
+        dy = ((double)y) / 10.;
+        G_format_easting(emin, label, PROJECTION_LL);
+        fprintf(PS.fp, "[(%s) %.1f %.1f]\n", label, dx, dy);
+    }
+    fprintf(PS.fp, "] def\n");
+
+    /* select format */
+    switch (PS.geogrid.format)
+    {
+        case 0:
+            set_geogrid_inner_numbers();
+            break;
+        case 1:
+            set_geogrid_outer_numbers();
+            break;
+    }
+    return 1;
+}
+
+
+/* geogrid with inner numbers */
+int set_geogrid_inner_numbers(void)
+{
+    set_ps_font(&(PS.geogrid.font));
+    fprintf(PS.fp, "/m %.3f def \n", 0.2 * PS.geogrid.font.size);
+
+    /* vertical numbers */
+    fprintf(PS.fp,
+            "0 1 GRR length -- {GRR exch GET M dup ");
+    set_ps_color(&(PS.geogrid.fcolor));
+    if (PS.geogrid.fcolor.none)
+        fprintf(PS.fp,
+                "SW .5 add neg .5 MR ");
+    else
+        fprintf(PS.fp,
+                "SWH m 2 mul add 1 index m 1 add add neg "
+                "exch dup -2 div 0 exch MR Rf ++ neg m MR ");
+    set_ps_color(&(PS.geogrid.font.color));
+    fprintf(PS.fp,
+            "show} for\n");
+
+    /* horizontal numbers */
+    fprintf(PS.fp,
+            "0 1 GRB length -- {GRB exch GET M dup ");
+    set_ps_color(&(PS.geogrid.fcolor));
+    if (PS.geogrid.fcolor.none)
+        fprintf(PS.fp,
+                "pop -.5 .5 MR ");
+    else
+        fprintf(PS.fp,
+                "SWH m 2 mul add exch m 1 add add 1 index -2 div 0 MR "
+                "1 index exch Rf m sub 1 MR ");
+    set_ps_color(&(PS.geogrid.font.color));
+    fprintf(PS.fp,
+            "GS 90 ROT show GR} for\n");
+
+    return 0;
+}
+
+/* geogrid with outer numbers */
+int set_geogrid_outer_numbers(void)
+{
+    set_ps_font(&(PS.geogrid.font));
+    fprintf(PS.fp, "/m %.3f def \n", 0.2 * PS.geogrid.font.size);
+
+    /* vertical numbers */
+    fprintf(PS.fp,
+            "0 1 GRR length -- {GRR exch get aload pop M dup ");
+    set_ps_color(&(PS.geogrid.fcolor));
+    fprintf(PS.fp,
+            "SW 2 div %.2f exch MR ", PS.brd.width+1.);
+    set_ps_color(&(PS.geogrid.font.color));
+    fprintf(PS.fp,
+            "GS 270 ROT show GR} for\n");
+
+    /* horizontal numbers */
+    fprintf(PS.fp,
+            "0 1 GRB length -- {GRB exch get aload pop M dup ");
+    set_ps_color(&(PS.geogrid.fcolor));
+    fprintf(PS.fp,
+            "SWH %.2f add neg exch -2 div exch MR ", PS.brd.width+1.);
+    set_ps_color(&(PS.geogrid.font.color));
+    fprintf(PS.fp,
+            "show} for\n");
+
+    return 0;
+}
+
+

Added: grass-addons/ps/ps.output/set_grid.c
===================================================================
--- grass-addons/ps/ps.output/set_grid.c	                        (rev 0)
+++ grass-addons/ps/ps.output/set_grid.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,361 @@
+/* File: set_grid.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <string.h>
+#include <math.h>
+#include "grids.h"
+#include "conversion.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+
+/*
+ * LINES OF THE GRATICULE
+ */
+
+int set_lines_grid(void)
+{
+    fprintf(PS.fp, "/XY {get aload pop exch pop} D\n");
+
+    set_grid_lines('m', &(PS.grid.mline), PS.grid.msep);
+    set_grid_lines('M', &(PS.grid.line), PS.grid.sep);
+}
+
+int set_grid_lines(char code, PSLINE * line, int grid_sep)
+{
+    char label[50], h;
+    int i, x, y, zero;
+    double sep, north, west, dx, dy;
+
+    if (grid_sep <= 0)
+        return 0;
+
+    /* detect max trailer zeros if format zero and not LL */
+    zero = 1;
+    if (PS.map.proj == PROJECTION_LL)
+    {
+        sep = (double)grid_sep / 3600.;
+    }
+    else
+    {
+        sep = (double)grid_sep;
+        if (PS.grid.format < 3 && PS.grid.round > 0) {
+            while (PS.grid.sep % zero == 0) zero *= 10;
+            if (zero > 1)
+            {
+                zero /= 10;
+                for (i=0, x=1; i < PS.grid.round; i++)  x *= 10;
+                if (zero > x) zero = x;
+            }
+        }
+    }
+
+    /* vertical numbers */
+    fprintf(PS.fp, "/VGR%c [\n", code);
+    north = floor(PS.map.north / sep) * sep;
+    for (; north >= PS.map.south; north -= sep)
+    {
+        G_plot_where_xy(PS.map.east, north, &x, &y);
+        dy = ((double)y) / 10.;
+        G_format_northing(north/zero, label, PS.map.proj);
+        fprintf(PS.fp, "[(%s) %.1f]\n", label, dy);
+    }
+    fprintf(PS.fp, "] def\n");
+
+    /* horizontal numbers */
+    fprintf(PS.fp, "/HGR%c [\n", code);
+    west = ceil(PS.map.west / sep) * sep;
+    for (; west < PS.map.east; west += sep)
+    {
+        G_plot_where_xy(west, PS.map.south, &x, &y);
+        dx = ((double)x) / 10.;
+        G_format_easting(west/zero, label, PS.map.proj);
+        fprintf(PS.fp, "[(%s) %.1f]\n", label, dx);
+    }
+    fprintf(PS.fp, "] def\n");
+
+
+    if (line->color.none != 1)
+    {
+        set_ps_line(line);
+        if (PS.grid.cross <= 0.) /* draw lines */
+        {
+            fprintf(PS.fp,
+                "VGR%c 0 1 2 index length -- {1 index exch XY "
+                "%.1f exch dup %.1f exch M LS} for pop\n", code, PS.map_x, PS.map_right);
+            fprintf(PS.fp,
+                "HGR%c 0 1 2 index length -- {1 index exch XY "
+                "%.1f 1 index %.1f M LS} for pop\n", code, PS.map_y, PS.map_top);
+        }
+        else /* draw crosses */
+        {
+            G_plot_where_xy(PS.map.east, PS.map.north, &x, &y);
+            dx = ((double)x) / 10.;
+            G_plot_where_xy(PS.map.east - PS.grid.cross, PS.map.north, &x, &y);
+            dy = ((double)x) / 10.;
+
+            fprintf(PS.fp,
+                    "VGR%c 0 1 2 index length -- {1 index exch XY "
+                    "HGR%c 0 1 2 index length -- {1 index exch XY "
+                    "2 index M 0 90 270 {GS ROT 0 %.1f LRS GR} for} "
+                    "for pop pop} for pop\n", code, code, dx-dy);
+        }
+    }
+    /* draw crosses como rotate una longitud desde el punto central*/
+    return 0;
+}
+
+/*
+ * NUMBERS OF THE GRATICULE
+ */
+
+int set_numbers_grid(void)
+{
+    /* make fine border */
+    set_ps_color(&(PS.grid.fcolor));
+    set_ps_brd(.2*MM_TO_POINT, 0.);
+
+    /* make numbers */
+    switch (PS.grid.format)
+    {
+        case 0:
+            set_grid_inner_numbers();
+            break;
+        case 1:
+            set_grid_minor_border(0., PS.brd.width, PS.brd.width);
+            set_grid_outer_numbers();
+            break;
+        case 2:
+            set_grid_fine_border (0.2*MM_TO_POINT, 0.8*MM_TO_POINT);
+            set_grid_minor_border(1.0*MM_TO_POINT, 1.2*MM_TO_POINT, 0.2*MM_TO_POINT);
+            set_grid_major_border(2.2*MM_TO_POINT, 9.5*MM_TO_POINT);
+            set_grid_iho_numbers();
+            break;
+    }
+    return 1;
+}
+
+
+/* FORMAT 0: inner numbers */
+int set_grid_inner_numbers(void)
+{
+    fprintf(PS.fp, "GS\n");
+    fprintf(PS.fp, "/m %.3f def \n", 0.2 * PS.grid.font.size);
+
+    set_ps_font(&(PS.grid.font));
+
+    /* vertical numbers */
+    fprintf(PS.fp, "0 1 VGRM length -- {VGRM exch GET %.1f exch M ", PS.map_x);
+    if (PS.grid.fcolor.none) {
+        fprintf(PS.fp, ".5 .5 MR ");
+    }
+    else  {
+        fprintf(PS.fp,
+                "dup SWH m 2 mul add exch m 1 add add exch "
+                "dup 2 div neg 0 exch MR GS ");
+        set_ps_color(&(PS.grid.fcolor));
+        fprintf(PS.fp, "Rf GR 1 m MR ");
+    }
+    fprintf(PS.fp, "show} for\n");
+
+    /* horizontal numbers */
+    fprintf(PS.fp, "0 1 HGRM length -- {HGRM exch GET %.1f M ", PS.map_top);
+    if (PS.grid.fcolor.none) {
+        fprintf(PS.fp, "dup SW .5 add neg -.5 exch MR ");
+    }
+    else  {
+        fprintf(PS.fp,
+                "dup SWH m 2 mul add exch m 1 add add "
+                "1 index 2 div 1 index neg MR exch neg exch GS ");
+        set_ps_color(&(PS.grid.fcolor));
+        fprintf(PS.fp, "Rf GR m neg m MR ");
+    }
+    fprintf(PS.fp, "GS 90 ROT show GR} for\n");
+
+    fprintf(PS.fp, "GR\n");
+    return 0;
+}
+
+
+/* FORMAT 1: outer numbers */
+int set_grid_outer_numbers(void)
+{
+    fprintf(PS.fp, "GS\n");
+
+    set_ps_font(&(PS.grid.font));
+
+    /* vertical numbers */
+    fprintf(PS.fp, "0 1 VGRM length -- {VGRM exch GET %.1f exch M ", PS.map_x);
+    fprintf(PS.fp, "dup SW -2 div -%.2f exch MR ", PS.brd.width+1.);
+    fprintf(PS.fp, "GS 90 ROT show GR} for\n");
+
+    /* horizontal numbers */
+    fprintf(PS.fp, "0 1 HGRM length -- {HGRM exch GET %.1f M ", PS.map_top);
+    fprintf(PS.fp, "dup SW -2 div %.2f MR ", PS.brd.width+1.);
+    fprintf(PS.fp, "show} for\n");
+
+    fprintf(PS.fp, "GR\n");
+    return 0;
+}
+
+/* FORMAT 2: I.H.O. numbers */
+int set_grid_iho_numbers(void)
+{
+//     fprintf(PS.fp, "GS\n");
+//     fprintf(PS.fp, "/m %.3f def \n", 0.2 * PS.grid.font.size);
+//
+//     set_ps_font(&(PS.grid.font));
+//
+//     /* vertical numbers */
+//     fprintf(PS.fp, "0 1 VGRM length -- {VGRM exch get aload pop %.1f exch M ", PS.map_x);
+//     fprintf(PS.fp, "dup SW -2 div -%.2f exch MR ", PS.brd.width+1.);
+//     fprintf(PS.fp, "GS 90 ROT show GR} for\n");
+//
+//     /* horizontal numbers */
+//     fprintf(PS.fp, "0 1 HGRM length -- {HGRM exch get aload pop %.1f M ", PS.map_top);
+//     fprintf(PS.fp, "dup SW -2 div %.2f MR ", PS.brd.width+1.);
+//     fprintf(PS.fp, "show} for\n");
+//
+//     fprintf(PS.fp, "GR\n");
+    return 0;
+}
+
+/*
+ * BORDER TYPES OF THE GRATICULE
+ */
+
+int set_grid_fine_border(double margin, double width)
+{
+    int div;
+
+    div = (PS.map.proj == PROJECTION_LL) ? 6 : 10;
+
+    set_ps_brd(.2*MM_TO_POINT, margin+width);
+    set_grid_corners(margin, width);
+
+    fprintf(PS.fp,
+            "1 1 VGRm length -- {dup VGRm exch XY exch -- VGRm exch XY "
+            "1 index sub %d div exch "
+            "%d {dup %.1f exch M %.2f 0 LR dup %.1f exch M %.2f 0 LR S "
+            "1 index add} repeat pop pop} for ",
+            div, div, PS.map_x-margin, -width, PS.map_right+margin, width);
+
+    fprintf(PS.fp,
+            "1 1 HGRm length -- {dup HGRm exch XY exch -- HGRm exch XY "
+            "1 index sub %d div exch "
+            "%d {dup %.1f M 0 %.2f LR dup %.1f M 0 %.2f LR S "
+            "1 index add} repeat pop pop} for ",
+            div, div, PS.map_y-margin, -width, PS.map_top+margin, width);
+
+    fprintf(PS.fp,
+            "VGRm 0 XY VGRm 1 XY 1 index sub neg "
+            "%d div exch {dup %.1f gt {exit} "
+            "{dup %.1f exch M %.2f 0 LR dup %.1f exch M %.2f 0 LR S 1 index add} ifelse} loop ",
+            div, PS.map_top, PS.map_x-margin, -width, PS.map_right+margin, width);
+
+    fprintf(PS.fp,
+            "/i VGRm length -- def "
+            "VGRm i XY VGRm i -- XY "
+            "1 index sub neg %d div exch {dup %.1f lt {exit} "
+            "{dup %.1f exch M %.2f 0 LR dup %.1f exch M %.2f 0 LR S 1 index add} ifelse} loop ",
+            div, PS.map_y, PS.map_x-margin, -width, PS.map_right+margin, width);
+
+    fprintf(PS.fp,
+            "HGRm 0 XY HGRm 1 XY 1 index sub neg "
+            "%d div exch {dup %.1f lt {exit} "
+            "{dup %.1f M 0 %.2f LR dup %.1f M 0 %.2f LR S 1 index add} ifelse} loop ",
+            div, PS.map_x, PS.map_y-margin, -width, PS.map_top+margin, width);
+
+    fprintf(PS.fp,
+            "/i HGRm length -- def "
+            "HGRm i XY HGRm i -- XY "
+            "1 index sub neg %d div exch {dup %.1f gt {exit} "
+            "{dup %.1f M 0 %.2f LR dup %.1f M 0 %.2f LR S} ifelse 1 index add} loop\n",
+            div, PS.map_right, PS.map_y-margin, -width, PS.map_top+margin, width);
+}
+
+int set_grid_minor_border(double margin, double width, double midline)
+{
+    double dist;
+
+    dist = margin + width/2. + .1*MM_TO_POINT;
+
+    set_ps_brd(.2*MM_TO_POINT, margin+width);
+
+    fprintf(PS.fp, ".2 mm LW ");
+    set_grid_corners(margin, width);
+
+    fprintf(PS.fp,
+            "0 1 VGRm length -- {VGRm exch XY dup "
+            "%.1f exch M %.2f 0 LR %.1f exch M %.2f 0 LRS} for\n",
+            PS.map_x-margin, -width, PS.map_right+margin, width);
+
+    fprintf(PS.fp,
+            "0 1 HGRm length -- {HGRm exch XY dup "
+            "%.1f M %.2f 0 exch LR %.1f M %.2f 0 exch LRS} for\n",
+            PS.map_y-margin, -width, PS.map_top+margin, width);
+
+
+    fprintf(PS.fp, "%.1f LW ", midline);
+
+    fprintf(PS.fp,
+            "1 2 VGRm length -- {/i XD VGRm i XY VGRm i -- XY 2 copy "
+            "%.1f exch M cP pop exch LS %.1f exch M cP pop exch LS} for\n",
+            PS.map_x-dist, PS.map_right+dist);
+
+    fprintf(PS.fp,
+            "1 2 HGRm length -- {/i XD HGRm i XY HGRm i -- XY 2 copy "
+            "%.1f M cP exch pop LS %.1f M cP exch pop LS} for\n",
+            PS.map_y-dist, PS.map_top+dist);
+
+    fprintf(PS.fp,
+            "VGRm length 2 mod 0 ne {VGRm dup length -- XY %.1f 2 copy "
+                    "%.1f exch M cP pop exch LS %.1f exch M cP pop exch LS} if\n",
+                    PS.map_y, PS.map_x-dist, PS.map_right+dist);
+
+    fprintf(PS.fp,
+            "HGRm length 2 mod 0 ne {HGRm dup length -- XY %.1f 2 copy "
+            "%.1f M cP exch pop LS %.1f M cP exch pop LS} if\n",
+            PS.map_right, PS.map_y-dist, PS.map_top+dist);
+}
+
+int set_grid_major_border(double margin, double width)
+{
+    set_ps_brd(.8*MM_TO_POINT, margin+width);
+
+    fprintf(PS.fp, ".2 mm LW ");
+
+    fprintf(PS.fp,
+            "0 1 VGRM length -- {VGRM exch XY dup "
+            "%.1f exch M %.2f 0 LR %.1f exch M %.2f 0 LR S} for\n",
+            PS.map_x-margin, -width, PS.map_right+margin, width);
+
+    fprintf(PS.fp,
+            "0 1 HGRM length -- {HGRM exch XY dup "
+            "%.1f M %.2f 0 exch LR %.1f M %.2f 0 exch LR S} for\n",
+            PS.map_y-margin, -width, PS.map_top+margin, width);
+}
+
+
+int set_grid_corners(double margin, double width)
+{
+    fprintf(PS.fp, "%.1f %.1f M %.2f 0 LRS ", PS.map_x-margin, PS.map_y, -width);
+    fprintf(PS.fp, "%.1f %.1f M 0 %.2f LRS ", PS.map_x, PS.map_y-margin, -width);
+
+    fprintf(PS.fp, "%.1f %.1f M %.2f 0 LRS ", PS.map_x-margin, PS.map_top, -width);
+    fprintf(PS.fp, "%.1f %.1f M 0 %.2f LRS ", PS.map_x, PS.map_top+margin, width);
+
+    fprintf(PS.fp, "%.1f %.1f M %.2f 0 LRS ", PS.map_right+margin, PS.map_y, width);
+    fprintf(PS.fp, "%.1f %.1f M 0 %.2f LRS ", PS.map_right, PS.map_y-margin, -width);
+
+    fprintf(PS.fp, "%.1f %.1f M %.2f 0 LRS ", PS.map_right+margin, PS.map_top, width);
+    fprintf(PS.fp, "%.1f %.1f M 0 %.2f LRS ", PS.map_right, PS.map_top+margin, width);
+}
+

Added: grass-addons/ps/ps.output/set_mask.c
===================================================================
--- grass-addons/ps/ps.output/set_mask.c	                        (rev 0)
+++ grass-addons/ps/ps.output/set_mask.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,105 @@
+/* File: set_mask.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <stdlib.h>
+#include <grass/gis.h>
+#include <grass/glocale.h>
+#include "raster.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+
+int set_mask(void)
+{
+    int i, byte, row, col, br;
+    void *cbuf, *cptr;
+    RASTER_MAP_TYPE map_type;
+    static int bit[] = { 128, 64, 32, 16, 8, 4, 2, 1 };
+
+
+    if (PS.rst.fd[1] < 0) /* there is no mask */
+    {
+        G_warning(_("Any raster mask to read, don't mask!"));
+        if (PS.need_mask)
+            PS.need_mask = 0;
+        return 0;
+    }
+
+    fprintf(PS.fp, "currentfile /ASCIIHexDecode filter /ReusableStreamDecode filter\n");
+
+    /* storing the bytes of the mask */
+    map_type = G_get_raster_map_type(PS.rst.fd[1]);
+    cbuf     = G_allocate_raster_buf(map_type);
+    for (br = 0, row = 0; row < PS.map.rows; row++)
+    {
+        G_get_raster_row(PS.rst.fd[1], cbuf, row, map_type);
+        cptr = cbuf;
+        i = byte = 0;
+        for (col = 0; col < PS.map.cols; col++)
+        {
+            if (G_is_null_value(cptr, map_type))
+            {
+                byte |= bit[i];
+            }
+            ++i;
+            if (i == 8)
+            {
+                fprintf(PS.fp, "%02x", byte);
+                i = byte = 0;
+            }
+            if (br++ == 45)
+            {
+                br = 0;
+                fprintf(PS.fp, "\n");
+            }
+            cptr = G_incr_void_ptr(cptr, G_raster_size(map_type));
+        }
+        if (i)
+        {
+            while (i < 8)
+                byte |= bit[i++];
+            fprintf(PS.fp, "%02x", byte);
+        }
+    }
+    fprintf(PS.fp, "\n> /maskstream exch def\n");
+
+    /* Mask Dictionary */
+    /*     fprintf(PS.fp, "  /Device%s setcolorspace\n", PS.rst.do_grey ? "Gray" : "RGB"); */
+    fprintf(PS.fp, "/MaskDictionary\n");
+    fprintf(PS.fp, "<< /ImageType 1\n");
+    fprintf(PS.fp, "   /Width %d\n", PS.map.cols);
+    fprintf(PS.fp, "   /Height %d\n", PS.map.rows);
+    fprintf(PS.fp, "   /BitsPerComponent 1\n");
+    /* fprintf(PS.fp, "   /Interpolate true\n"); */
+    fprintf(PS.fp, "   /Decode [1 0]\n");
+    fprintf(PS.fp, "   /ImageMatrix [%d 0 0 %d 0 %d]\n", PS.map.cols, -PS.map.rows, PS.map.rows);
+    fprintf(PS.fp, "   /DataSource maskstream\n");
+    fprintf(PS.fp, ">> store\n");
+
+    /* Now draw the masked image */
+    fprintf(PS.fp, "maskstream resetfile\n");
+    fprintf(PS.fp, "mapstream resetfile\n");
+    fprintf(PS.fp, "gsave\n");
+    fprintf(PS.fp, "  /Device%s setcolorspace\n", PS.rst.do_grey ? "Gray" : "RGB");
+    fprintf(PS.fp, "  %.2f %.2f translate\n", PS.map_x, PS.map_y);
+    fprintf(PS.fp, "  %.1f %.1f scale\n", PS.map_w, PS.map_h);
+    fprintf(PS.fp, "  << /ImageType 3\n");
+    fprintf(PS.fp, "     /InterleaveType 3\n");
+    fprintf(PS.fp, "     /MaskDict MaskDictionary\n");
+    fprintf(PS.fp, "     /DataDict MapDictionary\n");
+    fprintf(PS.fp, "  >> image\n");
+    fprintf(PS.fp, "grestore\n");
+
+    /* no more needed the reusable streams */
+    fprintf(PS.fp, "maskstream closefile\n");
+    fprintf(PS.fp, "mapstream closefile\n");
+
+    return 0;
+}

Added: grass-addons/ps/ps.output/set_note.c
===================================================================
--- grass-addons/ps/ps.output/set_note.c	                        (rev 0)
+++ grass-addons/ps/ps.output/set_note.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,134 @@
+/* File: set_note.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <grass/gis.h>
+#include <grass/glocale.h>
+#include "conversion.h"
+#include "notes.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+
+int note_in_file(char *name);
+
+int set_note(int i)
+{
+	int rows, type;
+    double x, y, dy, fontsize;
+	char *chr, *str, txt[1024];
+
+    rows = 0;
+
+    fontsize = set_ps_font(&(PS.note[i].font));
+
+    if (strncmp(PS.note[i].text, ":file", 5) == 0) {
+        str = PS.note[i].text + 6;
+        rows = note_in_file(str);
+        type = -1;
+    }
+    else if (strncmp(PS.note[i].text, ":maplim", 7) == 0)
+    {
+        char label[50];
+        /* get north, south, east and west strings */
+        fprintf(PS.fp, "/ARo [\n");
+        G_format_northing(PS.map.north, label, PS.map.proj);
+        fprintf(PS.fp, "(North: %s)\n", label);
+        G_format_easting(PS.map.west, label, PS.map.proj);
+        fprintf(PS.fp, "(West: %s)\n", label);
+        G_format_easting(PS.map.east, label, PS.map.proj);
+        fprintf(PS.fp, "(East: %s)\n", label);
+        G_format_northing(PS.map.south, label, PS.map.proj);
+        fprintf(PS.fp, "(South: %s)\n", label);
+        fprintf(PS.fp, "] def\n");
+        rows = 4;
+        type = 0;
+    }
+    else if (strncmp(PS.note[i].text, ":dimen", 6) == 0)
+    {
+            fprintf(PS.fp, "/ARo [\n");
+            fprintf(PS.fp, "(Map Area)");
+            fprintf(PS.fp, "(Position: %.1f mm x %.1f mm)\n",
+                    POINT_TO_MM * PS.map_x,
+                    POINT_TO_MM * PS.map_y);
+            fprintf(PS.fp, "(Dimension: %.1f mm x %.1f mm)\n",
+                    POINT_TO_MM * PS.map_w,
+                    POINT_TO_MM * PS.map_h);
+            fprintf(PS.fp, "] def\n");
+            rows = 3;
+            type = 1;
+    }
+    else if (strncmp(PS.note[i].text, ":scale", 6) == 0)
+    {
+        str = PS.note[i].text + 7;
+        fprintf(PS.fp, "/ARo [(%s 1 : %d)] def\n", str, PS.scale);
+        rows = 1;
+        type = 2;
+    }
+    else { /* free line of text with "|" to cut lines */
+        fprintf(PS.fp, "/ARo [\n");
+        chr = str = PS.note[i].text;
+        while (*chr) {
+            while (*str && *str != '|' ) str++;
+            *str++ = '\0';
+            fprintf(PS.fp, "(%s)\n", chr);
+            chr = str;
+            ++rows;
+        }
+        fprintf(PS.fp, "] def\n");
+        type = 4;
+    }
+
+    if (rows > 0 ) {
+        fprintf(PS.fp, "/ARw 1 array def ARw 0 ARo SWx put\n"); /* cols */
+        fprintf(PS.fp, "/ARh ARo length array def "); /* rows */
+        fprintf(PS.fp, "0 1 ARo length 1 sub {ARh exch %.2f put} for\n", fontsize);
+        set_box_orig(&(PS.note[i].box));
+        set_box_auto(&(PS.note[i].box), &(PS.note[i].font), 0.25);
+        set_box_draw(&(PS.note[i].box));
+        set_ps_color(&(PS.note[i].font.color));
+        fprintf(PS.fp, "/mgx mg def /mgy mg def RESET 0 COL\n");
+        fprintf(PS.fp, "0 1 ARo length 1 sub {dup ROW ARo exch get x y ARh row get sub M ");
+        if (type == 0)
+            fprintf(PS.fp, "GS dup SW ARw 0 get exch sub 0 32 4 -1 roll widthshow GR} for\n");
+        else if (type == 2)
+            fprintf(PS.fp, "GS dup SWH exch pop 0 MR %.2f ROT show GR} for\n", PS.note[i].angle);
+        else
+            fprintf(PS.fp, "show} for\n");
+    }
+
+    return 0;
+}
+
+int note_in_file(char *name)
+{
+	FILE *in = NULL;
+	char buf[1024];
+	int r = 0;
+
+    in = NULL;
+	if (*name) {
+		in = fopen(name, "r");
+		if (in == NULL) {
+			G_message(_("Comment file <%s> can't open"), name);
+			return 0;
+		}
+	}
+
+    fprintf(PS.fp, "/ARo [\n");
+    while (fgets(buf, sizeof(buf), in)) { /* TODO don't read end-of-line */
+		fprintf(PS.fp, "(%s)\n", buf);
+		++r;
+	}
+    fprintf(PS.fp, "] def\n");
+
+	fclose(in);
+
+	return r;
+}

Added: grass-addons/ps/ps.output/set_outline.c
===================================================================
--- grass-addons/ps/ps.output/set_outline.c	                        (rev 0)
+++ grass-addons/ps/ps.output/set_outline.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,75 @@
+/* File: set_outline.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <stdlib.h>
+#include <grass/gis.h>
+#include <grass/glocale.h>
+#include "raster.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+int set_outline(void)
+{
+    int row, col;
+    double nrow, n_rw, erow, e_rw;
+    void *rbuf, *nbuf, *rptr, *nptr, *next;
+    RASTER_MAP_TYPE map_type;
+
+    /* let user know what's happenning */
+    G_message(_("Reading raster map <%s in %s> ..."),
+              PS.rst.name[0], PS.rst.mapset[0]);
+
+    /* set the outline color and width */
+    set_ps_line(&(PS.rst.outline));
+
+    fprintf(PS.fp, "GS 1 setlinejoin\n");  /* lines with linejoin = round */
+
+    /* buffers of the image */
+    map_type = G_get_raster_map_type(PS.rst.fd[0]);
+    rbuf     = G_allocate_raster_buf(map_type);
+    nbuf     = G_allocate_raster_buf(map_type);
+    for (row = 0; row < PS.map.rows-1; row++)
+    {
+        nrow = G_row_to_northing((double)row, &(PS.map));
+        n_rw = G_row_to_northing((double)row+1, &(PS.map));
+        /* load buffers */
+        G_get_raster_row(PS.rst.fd[0], rbuf, row, map_type);
+        G_get_raster_row(PS.rst.fd[0], nbuf, row+1, map_type);
+        /* set pointers */
+        rptr = rbuf;
+        nptr = nbuf;
+        for (col = 0; col < PS.map.cols-1; col++)
+        {
+            erow = G_col_to_easting((double)col+1, &(PS.map));
+            e_rw = G_col_to_easting((double)col, &(PS.map));
+            /* check right outline */
+            next = G_incr_void_ptr(rptr, G_raster_size(map_type));
+            if (G_raster_cmp(rptr, next, map_type) != 0) {
+                set_ps_where('M', erow, nrow);
+                set_ps_where('L', erow, n_rw);
+                fprintf(PS.fp, "S\n");
+            }
+            /* check bottom outline */
+            if (G_raster_cmp(rptr, nptr, map_type) != 0) {
+                set_ps_where('M', e_rw, n_rw);
+                set_ps_where('L', erow, n_rw);
+                fprintf(PS.fp, "S\n");
+            }
+            /* next column */
+            rptr = G_incr_void_ptr(rptr, G_raster_size(map_type));
+            nptr = G_incr_void_ptr(nptr, G_raster_size(map_type));
+        }
+    }
+    G_free(rbuf);
+    G_free(nbuf);
+
+    fprintf(PS.fp, "GR\n");
+    return 0;
+}

Added: grass-addons/ps/ps.output/set_ps.c
===================================================================
--- grass-addons/ps/ps.output/set_ps.c	                        (rev 0)
+++ grass-addons/ps/ps.output/set_ps.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,164 @@
+/* File: set_ps.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+#include <string.h>
+#include <grass/symbol.h>
+#include "vareas.h"
+#include "vpoints.h"
+#include "ps_info.h"
+
+
+
+void set_ps_rect(double x, double y, double w, double h)
+{
+    fprintf(PS.fp, "%.3f %.3f %.3f %.3f RO\n",
+            x, y, w, h);
+}
+
+void set_ps_brd(double width, double margin)
+{
+    fprintf(PS.fp, "%.3f LW %.3f %.3f %.3f %.3f RO\n",
+            width,
+            PS.map_x-margin, PS.map_y-margin,
+            PS.map_w+2.*margin, PS.map_h+2.*margin);
+}
+
+/* GEOGRAPHIC */
+/* geographic coordinates to paper coordinates */
+int set_ps_where(char action, double east, double north)
+{
+    int x, y;
+    double dx, dy;
+
+    G_plot_where_xy(east, north, &x, &y);
+
+    dx = ((double)x) / 10.;
+    dy = ((double)y) / 10.;
+
+    fprintf(PS.fp, "%.1f %.1f %c ", dx, dy, action);
+    return 0;
+}
+
+
+/* GEOGRAPHIC */
+/* geographic coordinates to paper coordinates */
+int set_xy_where(char *pre, double east, double north, char *post)
+{
+    int x, y;
+    double dx, dy;
+
+    G_plot_where_xy(east, north, &x, &y);
+
+    dx = ((double)x) / 10.;
+    dy = ((double)y) / 10.;
+
+    fprintf(PS.fp, "%s %.1f %.1f %s", pre, dx, dy, post);
+    return 0;
+}
+
+int is_xy_outside(double east, double north)
+{
+    int x, y;
+    double dx, dy;
+
+    G_plot_where_xy(east, north, &x, &y);
+
+    dx = ((double)x) / 10.;
+    dy = ((double)y) / 10.;
+
+    if (dx < PS.map_x || dx > PS.map_right ||
+        dy < PS.map_y || dy > PS.map_top)
+        return 1;
+
+    return 0;
+}
+
+
+/* PATTERNS */
+/* store a pattern for posterior reference by number */
+int set_ps_pattern(int code, char *eps, VAREAS *va)
+{
+    FILE *fp;
+    char buf[1024];
+    int ret = 0;
+    double llx, lly, urx, ury;
+
+    if ((fp = fopen(eps, "r")) == NULL) {
+        G_message("File <%s> not found!\n", eps);
+        return 0;
+    }
+
+    /* find the bounding box in EPS */
+    llx = lly = urx = ury = 0.;
+    while (fgets(buf, 128, fp) != NULL && ret != 4)
+    {
+        ret =  sscanf(buf, "%%%%BoundingBox: %lf %lf %lf %lf",
+                      &llx, &lly, &urx, &ury);
+    }
+    if (llx == 0. && lly == 0. && urx == 0. && ury == 0.) {
+        fclose(fp);
+        error("ERROR:", "", "Bounding box in <%s> was not found\n", eps);
+    }
+
+    llx *= va->scale;
+    lly *= va->scale;
+    urx *= va->scale;
+    ury *= va->scale;
+
+    fprintf(PS.fp, "/PATTERN%d\n", code);
+    fprintf(PS.fp, "<< /PatternType 1\n   /PaintType %d\n   /TilingType 1\n", va->type_pat);
+    fprintf(PS.fp, "   /BBox [%.4f %.3f %.4f %.4f]\n", llx, lly, urx, ury);
+    fprintf(PS.fp, "   /XStep %.4f\n   /YStep %.4f\n", (urx - llx), (ury - lly));
+    fprintf(PS.fp, "   /PaintProc\n");
+    fprintf(PS.fp, "   { begin\n");
+    fprintf(PS.fp, "     %.4f %.4f scale\n", va->scale, va->scale);
+    if (va->type_pat == 1)
+        fprintf(PS.fp, "     %.3f %.3f %.3f C\n",
+                va->fcolor.r, va->fcolor.g, va->fcolor.b);
+    fprintf(PS.fp, "     [] 0 LD %.4f LW\n", va->pwidth);
+    while (fgets(buf, 1024, fp) != NULL)
+        fprintf(PS.fp, "     %s", buf);
+    fprintf(PS.fp, "     end }\n");
+    fprintf(PS.fp, ">> matrix makepattern def\n");
+
+    fclose(fp);
+    return 1;
+}
+
+/* SYMBOLS */
+/* store a standard symbol >>>> use symbol_save in symbol.c */
+// int set_ps_symbol_std(int code, VPOINTS *vp, SYMBOL * sym)
+// {
+// }
+
+/* store a eps symbol */
+int set_ps_symbol_eps(int code, VPOINTS *vp, char *eps)
+{
+    FILE *fp;
+    char buf[1024];
+
+    if ((fp = fopen(eps, "r")) == NULL) {
+        G_message("File <%s> not found!\n", eps);
+        return 0;
+    }
+
+    fprintf(PS.fp, "/SYMBOL%d {\n", code);
+    while (fgets(buf, 1024, fp) != NULL)
+    {
+        if (strncmp(buf, "%!PS-Adobe", 10) == 0 ||
+            strncmp(buf, "%%BoundingBox", 13) == 0)
+            continue;
+        fprintf(PS.fp, "     %s", buf);
+    }
+    fprintf(PS.fp, "\n} def\n");
+
+    fclose(fp);
+    return 1;
+}
+

Added: grass-addons/ps/ps.output/set_raster.c
===================================================================
--- grass-addons/ps/ps.output/set_raster.c	                        (rev 0)
+++ grass-addons/ps/ps.output/set_raster.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,347 @@
+/* File: set_raster.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <stdlib.h>
+#include <grass/gis.h>
+#include <grass/glocale.h>
+#include "raster.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+#define NTSC(r,g,b) (.30*(double)r + .59*(double)g + .11*(double)b)
+#define GREY(r,g,b) ((double)(r + g + b)/3.)
+
+
+/* the PS file can be reduced to half if don't use ASCIIHexDecode filter and writing
+directly with %c, not with %02X, but the PS file is less friendly and this is not important
+when after all the PS file is transformed to PDF */
+
+int set_raster(void)
+{
+    int i;
+
+    /* starting */
+    if (PS.need_mask && PS.rst.do_mask)
+    {
+        fprintf(PS.fp, "currentfile /ASCIIHexDecode filter /ReusableStreamDecode filter\n");
+    }
+    else
+    {
+        fprintf(PS.fp, "GS\n");
+        /* Map Dictionary when no mask needed, no reusable stream */
+        fprintf(PS.fp, "/Device%s setcolorspace\n", PS.rst.do_grey ? "Gray" : "RGB");
+        fprintf(PS.fp, "%.2f %.2f translate\n", PS.map_x, PS.map_y);
+        fprintf(PS.fp, "%.1f %.1f scale\n", PS.map_w, PS.map_h);
+        fprintf(PS.fp, "<< /ImageType 1\n");
+        fprintf(PS.fp, "   /Width %d\n", PS.map.cols);
+        fprintf(PS.fp, "   /Height %d\n", PS.map.rows);
+        fprintf(PS.fp, "   /BitsPerComponent 8\n");
+        /* fprintf(PS.fp, "   /Interpolate true\n"); */
+        fprintf(PS.fp, "   /Decode [%s]\n", PS.rst.do_grey ? "0 1" : "0 1 0 1 0 1");
+        fprintf(PS.fp, "   /ImageMatrix [%d 0 0 %d 0 %d]\n", PS.map.cols, -PS.map.rows, PS.map.rows);
+        fprintf(PS.fp, "   /DataSource currentfile /ASCIIHexDecode filter\n");
+        fprintf(PS.fp, ">> ");
+        fprintf(PS.fp, "image\n");
+    }
+    /* split loading stream for some better speed */
+    if (PS.rst.do_rgb)
+    {
+        set_raster_rgb();
+    }
+    else if (PS.rst.do_mask)
+    {
+        if (PS.rst.fd[2] < 0)
+            set_raster_maskcolor();
+        else
+            set_raster_maskcell();
+    }
+    else
+    {
+        set_raster_cell();
+    }
+    /* ending */
+    if (PS.need_mask && PS.rst.do_mask)
+    {
+        fprintf(PS.fp, "\n> ");
+        fprintf(PS.fp, "/mapstream exch def\n");
+        /* Map Dictionary when mask needed, reusable stream */
+        fprintf(PS.fp, "/MapDictionary \n");
+        fprintf(PS.fp, "<< /ImageType 1\n");
+        fprintf(PS.fp, "   /Width %d\n", PS.map.cols);
+        fprintf(PS.fp, "   /Height %d\n", PS.map.rows);
+        fprintf(PS.fp, "   /BitsPerComponent 8\n");
+        /* fprintf(PS.fp, "   /Interpolate true\n"); */
+        fprintf(PS.fp, "   /Decode [%s]\n", PS.rst.do_grey ? "0 1" : "0 1 0 1 0 1");
+        fprintf(PS.fp, "   /ImageMatrix [%d 0 0 %d 0 %d]\n", PS.map.cols, -PS.map.rows, PS.map.rows);
+        fprintf(PS.fp, "   /DataSource mapstream\n");
+        fprintf(PS.fp, ">> store\n");
+        fprintf(PS.fp, "gsave\n");
+        fprintf(PS.fp, "  /Device%s setcolorspace\n", PS.rst.do_grey ? "Gray" : "RGB");
+        fprintf(PS.fp, "  %.2f %.2f translate\n", PS.map_x, PS.map_y);
+        fprintf(PS.fp, "  %.1f %.1f scale\n", PS.map_w, PS.map_h);
+        fprintf(PS.fp, "  mapstream resetfile\n");
+        fprintf(PS.fp, "  MapDictionary image\n");
+    }
+    else
+    {
+        fprintf(PS.fp, ">\n");
+    }
+    fprintf(PS.fp, "GR\n");
+
+    return 0;
+}
+
+/** Process one file with colors */
+int set_raster_cell(void)
+{
+    int row, col, br, R, G, B;
+    void *cbuf, *cptr;
+    RASTER_MAP_TYPE map_type;
+
+
+    /* let user know what's happenning */
+    G_message(_("Reading raster map <%s in %s> ..."),
+              PS.rst.name[0], PS.rst.mapset[0]);
+
+    /* storing the bytes of the image */
+    map_type = G_get_raster_map_type(PS.rst.fd[0]);
+    cbuf     = G_allocate_raster_buf(map_type);
+    for (br = 0, row = 0; row < PS.map.rows; row++)
+    {
+        G_get_raster_row(PS.rst.fd[0], cbuf, row, map_type);
+        cptr = cbuf;
+        for (col = 0; col < PS.map.cols; col++)
+        {
+            /* get the map colors */
+            G_get_raster_color(cptr, &R, &G, &B, &(PS.rst.colors[0]), map_type);
+            cptr = G_incr_void_ptr(cptr, G_raster_size(map_type));
+            /* processing data to the postscript file */
+            if (PS.rst.do_grey) {
+                fprintf(PS.fp, "%02X", (int)NTSC(R,G,B));
+            }
+            else {
+                fprintf(PS.fp, "%02X%02X%02X", R,G,B);
+            }
+            if (br++ == 15) {
+                br = 0;
+                fprintf(PS.fp, "\n");
+            }
+        }
+    }
+    G_free(cbuf);
+
+    return 1;
+}
+
+/** Process three files as RGB color */
+int set_raster_rgb(void)
+{
+    int i, row, col, br;
+    int R[3], G[3], B[3];
+    void *cbuf[3], *cptr[3];
+    RASTER_MAP_TYPE map_type[3];
+
+
+    /* let user know what's happenning */
+    G_message(_("Reading raster maps in group <%s> ..."), PS.rst.title);
+
+    /* storing the bytes of the image */
+    for (i = 0; i < 3; i++) {
+        map_type[i] = G_get_raster_map_type(PS.rst.fd[i]);
+        cbuf[i] = G_allocate_raster_buf(map_type[i]);
+    }
+    for (br = 0, row = 0; row < PS.map.rows; row++)
+    {
+        for (i = 0; i < 3; i++) {
+            G_get_raster_row(PS.rst.fd[i], cbuf[i], row, map_type[i]);
+            cptr[i] = cbuf[i];
+        }
+        for (col = 0; col < PS.map.cols; col++)
+        {
+            /* get the map colors */
+            G_get_raster_color(cptr[0], &(R[0]), &(G[0]), &(B[0]), &(PS.rst.colors[0]), map_type[0]);
+            G_get_raster_color(cptr[1], &(R[1]), &(G[1]), &(B[1]), &(PS.rst.colors[1]), map_type[1]);
+            G_get_raster_color(cptr[2], &(R[2]), &(G[2]), &(B[2]), &(PS.rst.colors[2]), map_type[2]);
+            /* processing data to the postscript file */
+            if (PS.rst.do_grey) {
+                fprintf(PS.fp, "%02X", (int)NTSC(R[0],G[1],B[2]));
+            }
+            else {
+                fprintf(PS.fp, "%02X%02X%02X", R[0], G[1], B[2]);
+            }
+            if (br++ == 15) {
+                br = 0;
+                fprintf(PS.fp, "\n");
+            }
+            /* pointer to next column */
+            cptr[0] = G_incr_void_ptr(cptr[0], G_raster_size(map_type[0]));
+            cptr[1] = G_incr_void_ptr(cptr[1], G_raster_size(map_type[1]));
+            cptr[2] = G_incr_void_ptr(cptr[2], G_raster_size(map_type[2]));
+        }
+    }
+    for (i = 0; i < 3; i++)
+    {
+        G_free(cbuf[i]);
+        G_close_cell(PS.rst.fd[i]);
+        G_free_colors(&(PS.rst.colors[i]));
+        PS.rst.fd[i] = -1;
+    }
+
+    return 3;
+}
+
+
+/** Process three files as raster, mask and background */
+int set_raster_maskcell(void)
+{
+    int i, row, col, br;
+    int r, g, b, R[3], G[3], B[3];
+    double f, red, green, blue;
+    void *cbuf[3], *cptr[3];
+    RASTER_MAP_TYPE map_type[3];
+
+    red   = (1. - PS.rst.mask_color.r);
+    green = (1. - PS.rst.mask_color.g);
+    blue  = (1. - PS.rst.mask_color.b);
+    R[1]  = (int)(255. * PS.rst.mask_color.r);
+    G[1]  = (int)(255. * PS.rst.mask_color.g);
+    B[1]  = (int)(255. * PS.rst.mask_color.b);
+
+    /* let user know what's happenning */
+    G_message(_("Reading raster map <%s in %s> ... %d rows"), PS.rst.name[0], PS.rst.mapset[0], PS.map.rows);
+    G_message(_("... mask raster <%s in %s>"), PS.rst.name[1], PS.rst.mapset[1]);
+    G_message(_("... background raster <%s in %s>"), PS.rst.name[2], PS.rst.mapset[2]);
+
+   /* storing the bytes of the image */
+   for (i = 0; i < 3; i++) {
+       map_type[i] = G_get_raster_map_type(PS.rst.fd[i]);
+       cbuf[i] = G_allocate_raster_buf(map_type[i]);
+   }
+   for (br = 0, row = 0; row < PS.map.rows; row++)
+   {
+       for (i = 0; i < 3; i++) {
+           /* G_get_raster_row(PS.rst.fd[i], cbuf[i], row, map_type[i]); */
+           G_get_raster_row_nomask(PS.rst.fd[i], cbuf[i], row, map_type[i]);
+           cptr[i] = cbuf[i];
+       }
+        for (col = 0; col < PS.map.cols; col++)
+        {
+            /* get the map colors */
+            G_get_raster_color(cptr[0], &(R[0]), &(G[0]), &(B[0]), &(PS.rst.colors[0]), map_type[0]);
+            G_get_raster_color(cptr[2], &(R[2]), &(G[2]), &(B[2]), &(PS.rst.colors[2]), map_type[2]);
+            /* select color by mask */
+            if (G_is_null_value(cptr[1], map_type[1])) {
+                if (PS.rst.mask_color.none) {
+                    r = R[2];
+                    g = G[2];
+                    b = B[2];
+                }
+                else {
+                    f = (double)GREY(R[2],G[2],B[2]);
+                    r = (int)(f*red   + (double)R[1]);
+                    g = (int)(f*green + (double)G[1]);
+                    b = (int)(f*blue  + (double)B[1]);
+                }
+            }
+            else {
+                r = R[0];
+                g = G[0];
+                b = B[0];
+            }
+            /* processing data to the postscript file */
+            if (PS.rst.do_grey) {
+                fprintf(PS.fp, "%02X", (int)NTSC(r,g,b));
+            }
+            else {
+                fprintf(PS.fp, "%02X%02X%02X", r, g, b);
+            }
+            if (br++ == 15) {
+                fprintf(PS.fp, "\n");
+                br = 0;
+            }
+            /* pointer to next column */
+            cptr[0] = G_incr_void_ptr(cptr[0], G_raster_size(map_type[0]));
+            cptr[1] = G_incr_void_ptr(cptr[1], G_raster_size(map_type[1]));
+            cptr[2] = G_incr_void_ptr(cptr[2], G_raster_size(map_type[2]));
+        }
+   }
+   G_free(cbuf[0]);
+   G_free(cbuf[1]);
+   G_free(cbuf[2]);
+
+   return 3;
+}
+
+
+/** Process two files as raster and mask */
+int set_raster_maskcolor(void)
+{
+    int i, row, col, br;
+    int color, r, g, b, R, G, B;
+    void *cbuf[2], *cptr[2];
+    RASTER_MAP_TYPE map_type[2];
+
+    if (PS.rst.mask_color.none)  {
+        r = g = b = 255.;
+    }
+    else {
+        r = (int)(255. * PS.rst.mask_color.r);
+        g = (int)(255. * PS.rst.mask_color.g);
+        b = (int)(255. * PS.rst.mask_color.b);
+    }
+
+    /* let user know what's happenning */
+    G_message(_("Reading raster map <%s in %s> ... %d rows"), PS.rst.name[0], PS.rst.mapset[0], PS.map.rows);
+    G_message(_("... raster to mask <%s in %s>"), PS.rst.name[1], PS.rst.mapset[1]);
+
+    /* storing the bytes of the image */
+    for (i = 0; i < 2; i++) {
+        map_type[i] = G_get_raster_map_type(PS.rst.fd[i]);
+        cbuf[i] = G_allocate_raster_buf(map_type[i]);
+    }
+    for (br = 0, row = 0; row < PS.map.rows; row++)
+    {
+        for (i = 0; i < 2; i++) {
+            G_get_raster_row(PS.rst.fd[i], cbuf[i], row, map_type[i]);
+            cptr[i] = cbuf[i];
+        }
+        for (col = 0; col < PS.map.cols; col++)
+        {
+            /* get the map colors */
+            G_get_raster_color(cptr[0], &R, &G, &B, &(PS.rst.colors[0]), map_type[0]);
+            /* select color by mask */
+            if (G_is_null_value(cptr[1], map_type[1]))
+            {
+                R = r;
+                G = g;
+                B = b;
+            }
+            /* processing data to the postscript file */
+            if (PS.rst.do_grey) {
+                fprintf(PS.fp, "%02X", (int)NTSC(R,G,B));
+            }
+            else {
+                fprintf(PS.fp, "%02X%02X%02X", R, G, B);
+            }
+            if (br++ == 15) {
+                br = 0;
+                fprintf(PS.fp, "\n");
+            }
+            /* pointer to next column */
+            cptr[0] = G_incr_void_ptr(cptr[0], G_raster_size(map_type[0]));
+            cptr[1] = G_incr_void_ptr(cptr[1], G_raster_size(map_type[1]));
+        }
+    }
+    G_free(cbuf[0]);
+    G_free(cbuf[1]);
+
+    return 2;
+}
+

Added: grass-addons/ps/ps.output/set_rlegend.c
===================================================================
--- grass-addons/ps/ps.output/set_rlegend.c	                        (rev 0)
+++ grass-addons/ps/ps.output/set_rlegend.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,344 @@
+/* File: set_rlegend.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <grass/glocale.h>
+#include "ps_info.h"
+#include "raster.h"
+#include "rlegend.h"
+#include "local_proto.h"
+
+static double nice_step(double diff, int cuts);
+
+
+int set_rlegend_cats(void)
+{
+    int i, j, k, n, R, G, B;
+    char *label;
+    int num_cats, rows, cols;
+	double fontsize, fwidth;
+    DCELL dmin, dmax, val;
+
+    /* Let user know what's happenning */
+    G_message(_("Raster legend with category <%s in %s>..."),
+              PS.rl.name, PS.rl.mapset);
+
+    if (G_read_cats(PS.rl.name, PS.rl.mapset, &(PS.rst.cats)) == -1) {
+		G_warning(_("Category file for <%s> not available"), PS.rl.name);
+		return 1;
+    }
+
+    /* Sort categories by user (min value) */
+    CELL * ip = (CELL *) G_malloc(sizeof( CELL) * PS.rst.cats.ncats);
+    for (i = 0; i < PS.rst.cats.ncats; i++)
+    {
+        G_get_ith_d_raster_cat(&(PS.rst.cats), i, &dmin, &dmax);
+        ip[i] = (CELL)dmin;
+    }
+    sort_list(PS.rl.cat_order, PS.rst.cats.ncats, &ip);
+
+    /* How many categories to show */
+    G_debug(3, "colortable: %d categories", num_cats);
+    num_cats = PS.rst.cats.ncats;
+    if (num_cats <= 0) {
+		G_warning(_("Your cats/ file is invalid. A cats/ file with "
+			    "categories and labels is required for 'colortable' when using "
+			    "CELL rasters. No colortable will be assigned to this output "
+		    	"postscript file."));
+		return 1;
+    } else if (num_cats > 100) {
+        G_warning(_("Your cats/ file has %d cats (limit to 100)!"), num_cats);
+    }
+    if (PS.rl.do_nodata)
+        ++num_cats; /* slot for no_data */
+
+	/* define number of rows */
+    if (num_cats < PS.rl.legend.cols) {
+        PS.rl.legend.cols = num_cats;
+        rows = 1;
+    }
+    else {
+        rows = (int)num_cats / PS.rl.legend.cols;
+        if (num_cats % PS.rl.legend.cols) ++rows;
+    }
+    cols = PS.rl.legend.cols;
+
+    if (!PS.rl.do_nodata)
+        ++num_cats; /* slot for no_data */
+
+    /* set font */
+    fontsize = set_ps_font(&(PS.rl.legend.font));
+
+    /* Array of data */
+    fprintf(PS.fp, "/ARh %d array def\n", rows);
+    fprintf(PS.fp, "0 1 %d {ARh exch %.2f put} for\n", rows-1, fontsize);
+
+    fprintf(PS.fp, "/ARw %d array def\n", cols);
+    i = PS.rl.do_nodata ? 0 : 1;
+    for (n = 0; n < cols; n++)
+    {
+        fprintf(PS.fp, "/AR%d [\n", n);
+        for (j = 0; j < rows && i < num_cats; j++, i++)
+        {
+            /* labels */
+			if (i == 0) {
+				fprintf(PS.fp, "(%s) ", "no data");
+                G_get_null_value_color(&R, &G, &B, &(PS.rst.colors[0]));
+				dmin = dmax = 0.;
+			}
+			else {
+				label = G_get_ith_d_raster_cat(&(PS.rst.cats), ip[i-1], &dmin, &dmax);
+				fprintf(PS.fp, "(%s) ", label);
+			}
+			/* colors */
+			fprintf(PS.fp, "[");
+			if (dmin == dmax) {
+                G_get_d_raster_color(&dmin, &R, &G, &B, &(PS.rst.colors[0]));
+                fprintf(PS.fp, "%.3f %.3f %.3f", R/255., G/255., B/255.);
+            }
+			else {
+				for (k = 0; k < 5; k++) {
+					val = dmin + (double)k *(dmax - dmin) / 5;
+                    G_get_d_raster_color(&val, &R, &G, &B, &(PS.rst.colors[0]));
+					fprintf(PS.fp, "%.3f %.3f %.3f ", R/255., G/255., B/255.);
+				}
+			}
+			fprintf(PS.fp, "]\n");
+		}
+        fprintf(PS.fp, "] def\n");
+        fprintf(PS.fp, "/mx 0 def 0 2 AR%d length -- {", n);
+        fprintf(PS.fp, "AR%d exch get SW /t XD t mx gt {/mx t def} if} for\n", n);
+        fprintf(PS.fp, "ARw %d mx put\n", n);
+    }
+
+    G_free(ip);
+
+	/** Adjust - Legend Box */
+    set_box_orig(&(PS.rl.legend.box));
+    set_legend_adjust(&(PS.rl.legend), -1.);
+    if (PS.rl.legend.title[0])
+        set_box_readjust_title(&(PS.rl.legend.box),
+                                 PS.rl.legend.title);
+    set_box_draw(&(PS.rl.legend.box));
+
+	fwidth = .5;
+
+    /* Make the raster legend */
+    fprintf(PS.fp, "RESET %.5f LW\n", fwidth);
+    fprintf(PS.fp, "/xw syw %.2f mul def ", 0.8);    /* symbol-width */
+    fprintf(PS.fp, "/yh %.2f def ", -fontsize);      /* symbol-height */
+    fprintf(PS.fp, "/t yh %d div def\n", 5);   /* gradient symbol-height, if any */
+    for (n = 0; n < cols; n++)
+    {
+        fprintf(PS.fp, "%d COL 0 ROW\n", n);
+        fprintf(PS.fp, "0 2 AR%d length -- {/i XD\n", n);
+        fprintf(PS.fp, "x y -- xw yh\nAR%d i ++ get aload length 3 eq ", n);
+        fprintf(PS.fp, "{%c 4 copy RF} ", PS.rst.do_grey ? 'G' : 'C');
+        fprintf(PS.fp, "{/z y def %d {C /z t add def x z xw t neg RF} repeat} ", 5);
+        fprintf(PS.fp, "ifelse\n0 0 0 C RE\n");
+        set_ps_color(&(PS.rl.legend.font.color));
+        fprintf(PS.fp, "AR%d i get x syw add y ARh row get sub MS row 1 add ROW} for\n", n);
+    }
+
+    /* Make the title of legend */
+    if (PS.rl.legend.title[0] != 0)
+    {
+        set_ps_font(&(PS.rl.legend.title_font));
+        fprintf(PS.fp, "RESET\n");
+        if (PS.vl.legend.title[0] == '.')
+            fprintf(PS.fp, "(%s) x cwd 2 div add yo mgy mg sub sub M SHC\n",
+                    PS.rl.legend.title+1, PS.rl.legend.title_font.size);
+        else
+            fprintf(PS.fp, "(%s) x yo mgy mg sub sub MS\n",
+                    PS.rl.legend.title, PS.rl.legend.title_font.size);
+    }
+
+    return 0;
+}
+
+
+int set_rlegend_gradient(void)
+{
+	int i, k, rows, nlines;
+	int R, G, B;
+	DCELL dmin, dmax, val;
+	double fontsize, step, fwidth;
+	struct Colors colors;
+	struct FPRange range;
+	char *units[GNAME_MAX];
+
+	/* let user know what's happenning */
+	G_message(_("Raster legend with gradient <%s in %s> ..."),
+			  PS.rl.name, PS.rl.mapset);
+
+	/* Get color range */
+	if (G_read_fp_range(PS.rl.name, PS.rl.mapset, &range) == -1) {
+		G_warning(_("Range information not available (run r.support)"));
+		return 1;
+	}
+
+    /* range and check */
+    if (PS.rl.custom_range) {
+		dmin = PS.rl.min;
+		dmax = PS.rl.max;
+	}
+    else {
+        G_get_fp_range_min_max(&range, &dmin, &dmax);
+        PS.rl.min = dmin;
+        PS.rl.max = dmax;
+    }
+
+	if (dmin == dmax) {
+		G_warning(_("It is not a range of values (max = min)"));
+		return 1;
+	}
+
+    /* color table */
+	if (G_read_colors(PS.rl.name, PS.rl.mapset, &colors) == -1) {
+		G_warning(_("Unable to read colors for rlegend"));
+    }
+
+	/* units label */
+	if (G_read_raster_units(PS.rl.name, PS.rl.mapset, (char *)units) != 0) {
+        units[0] = 0;
+    }
+
+	/* initialize */
+    fontsize = set_ps_font(&(PS.rl.legend.font));
+
+    /* set standard height */
+	if (PS.rl.height <= 0.) {
+		PS.rl.height = 15. * fontsize;
+		rows = 10; /* = PS.rl.height / 1.5*fontsize */
+	}
+	else
+		rows = (int)(PS.rl.height/(1.5 * fontsize));
+
+	/* Nice step and first value as ps_fctltbl */
+	step = nice_step(dmax - dmin, rows);
+	val = step * (int)(dmin/step);
+	if (val < dmin) val += step;
+
+    /* Array of strings and widths */
+    fprintf(PS.fp, "/AR0 [\n");
+	while (val <= dmax)
+	{
+		fprintf(PS.fp, "(%.f) %.8f\n", val, (dmax-val)/(dmax-dmin));
+		val += step;
+	}
+	fprintf(PS.fp, "] def\n");
+    fprintf(PS.fp, "/ARh 1 array def ARh 0 %.2f put\n", fontsize);
+    fprintf(PS.fp, "/ARw 1 array def "
+            "/mx 0 def 0 2 AR0 length 1 sub {"
+            "AR0 exch get SW /t XD t mx gt {/mx t def} if } for "
+            "ARw 0 mx put\n");
+
+    PS.rl.legend.span = 0.; /* needed for auto adjust */
+
+	/** Adjust - box legend */
+    set_box_orig(&(PS.rl.legend.box));
+	set_legend_adjust(&(PS.rl.legend), PS.rl.height);
+    if (units[0] != 0)
+        set_box_readjust(&(PS.rl.legend.box), -1., -1., -1., 0.8*fontsize);
+    set_box_draw(&(PS.rl.legend.box));
+
+	fwidth = .5;
+
+	nlines = (int)(PS.rl.height * 2.5); /* = 2.5 * 72 = 180 ppp */
+	step = (dmax - dmin) / nlines;
+
+	/* Draw the labels */
+    set_ps_color(&(PS.rl.legend.font.color));
+    fprintf(PS.fp, "RESET %.4f LW /ch chg %.5f sub def\n", fwidth, fwidth);
+    fprintf(PS.fp, "/x x syw add def /y y %.5f sub def\n", fwidth/2.);
+	fprintf(PS.fp, "0 2 AR0 length -- {/i XD\n");
+	fprintf(PS.fp, "x y ch AR0 i ++ get mul\n");
+	if (PS.rl.tickbar) {
+        fprintf(PS.fp, "GS ");
+        set_ps_color(&(PS.rl.legend.font.color));
+        fprintf(PS.fp, "3 copy sub ");
+		fprintf(PS.fp, "NM -1 0 MR -%d 0 LR CS GR\n", PS.rl.tickbar); /* length of tickbar */
+	}
+    /* Ajusta los extremos que no salgan de la barra */
+	fprintf(PS.fp, "%.5f ", 0.67*fontsize); /* part upper tickbar */
+	fprintf(PS.fp, "2 copy lt {sub neg} {2 div add dup ch gt {pop ch} if} ifelse ");
+	fprintf(PS.fp, "sub M AR0 i get show} for\n");
+
+    /* Prepare the border and stroke area */
+	fprintf(PS.fp, "RESET\n");
+	fprintf(PS.fp, "/dy chg %d div def ", nlines); /* dy: linewidth */
+	fprintf(PS.fp, "/dx syw %d sub def\n", PS.rl.tickbar); /* dx: barwidth, here, here */
+	fprintf(PS.fp, "x y dx chg neg "); /* to rectstroke */
+
+	/* draw the colorbar and frame */
+	fprintf(PS.fp, "dy 1.1 mul LW x y chg sub\n"); /* stack x and y */
+	fprintf(PS.fp, "[\n");
+	for (val = dmin; val <= dmax; val += step)
+	{
+		G_get_d_raster_color(&val, &R, &G, &B, &colors);
+        if (PS.rst.do_grey)
+            fprintf(PS.fp, "[%.3f]\n", (0.30*(double)R+0.59*(double)G+0.11*(double)B)/255.);
+        else
+            fprintf(PS.fp, "[%.3f %.3f %.3f]\n", R/255., G/255., B/255.);
+    }
+	fprintf(PS.fp, "] {aload pop %c 2 copy M dx 0 LR stroke dy add} forall\n",
+            PS.rst.do_grey ? 'G' : 'C');
+    fprintf(PS.fp, "pop pop\n");
+    fprintf(PS.fp, "GS 4 copy RC\n");
+    if (PS.rl.whiteframe > 0.) /* white border: print on colors */
+        fprintf(PS.fp, "4 copy 1 1 1 C %d LW RE\n", PS.rl.whiteframe);
+    fprintf(PS.fp, "GR ");
+    set_ps_color(&(PS.rl.legend.font.color));
+    fprintf(PS.fp, "%.5f LW RO\n", fwidth);
+
+	/* print units label, if present */
+	if (units[0]) {
+		set_ps_color(&(PS.rl.legend.font.color));
+        fprintf(PS.fp, "%.1f FS ", 0.8*fontsize);
+        fprintf(PS.fp, "RESET (%s) dup SW ", units);
+        fprintf(PS.fp, "x cwd add exch sub y chg %.1f add sub MS\n", fontsize);
+	}
+
+	G_free_colors(&colors);
+
+	return 0;
+}
+
+/* Extract from function ps_fcolortable
+ * Author: Radim Blazek, leto 02
+ */
+static double nice_step(double diff, int cuts)
+{
+	int i, cur_step;
+	double nice_steps[4] = { 1.0, 2.0, 2.5, 5.0 };	/* nice steps */
+	double step, ex, cur_d, cur_ex;
+
+	step = diff / cuts;
+
+	for (i = 0; i < 4; i++) {
+		/* smalest n for which nice step >= raw step */
+		if (nice_steps[i] <= step) {
+			ex = 1;
+			while (nice_steps[i] * ex < step)
+				ex *= 10;
+		}
+		else {
+			ex = 0.1;
+			while (nice_steps[i] * ex > step)
+				ex *= 0.1;
+			ex *= 10;
+		}
+		if (i == 0 || (nice_steps[i] * ex - step) < cur_d) {
+			cur_step = i;
+			cur_d = nice_steps[i] * ex - step;
+			cur_ex = ex;
+		}
+	}
+	return nice_steps[cur_step] * cur_ex;
+}

Added: grass-addons/ps/ps.output/set_scalebar.c
===================================================================
--- grass-addons/ps/ps.output/set_scalebar.c	                        (rev 0)
+++ grass-addons/ps/ps.output/set_scalebar.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,223 @@
+
+#include <string.h>
+#include <math.h>
+#include "ps_info.h"
+#include "scalebar.h"
+#include "local_proto.h"
+#include "conversion.h"
+
+char * strnumber(double num);
+
+
+int set_scalebar(void)
+{
+    int i, j;
+    double width, segment;
+
+    if (PS.sbar.length <= 0 || PS.sbar.segments <= 0)
+        return 1;
+
+    /* width of scalebar in points */
+    width = PS.sbar.length;
+    switch (PS.sbar.ucode)
+    {
+        case SB_UNITS_KM:
+            width *= KILOMETERS_TO_METERS;
+            break;
+        case SB_UNITS_FEET:
+            width *= FEET_TO_METERS;
+            break;
+        case SB_UNITS_MILES:
+            width *= MILES_TO_METERS;
+            break;
+        case SB_UNITS_NMILES:
+            width *= NAUT_MILES_TO_METERS;
+            break;
+        default:
+            width *= G_database_units_to_meters_factor();
+            break;
+    }
+    width *= (1000. * MM_TO_POINT / (double)PS.scale);
+
+    if (PS.sbar.subsegs > 0 && PS.sbar.type != 'I') {
+        segment = width/(double)PS.sbar.segments;
+        width += segment;
+    }
+
+    /* adjust to min size */
+    set_ps_font(&(PS.sbar.font));
+
+    set_box_orig(&(PS.sbar.box));
+    set_box_size(&(PS.sbar.box),
+                   width + 2.*PS.sbar.box.margin, /* cwd real width */
+                   PS.sbar.height + 2.*PS.sbar.box.margin);
+
+    /* labels of the scalebar */
+    fprintf(PS.fp, "/AR0 [");
+    segment = (PS.sbar.length / PS.sbar.segments);
+    for (i = 0; i <= PS.sbar.segments; i += PS.sbar.labels )
+    {
+        fprintf(PS.fp, "(%s)", strnumber(i*segment));
+    }
+    fprintf(PS.fp, "] def\n");
+    /* sublabels of the scalebar */
+    if (PS.sbar.type != 'I')
+    {
+        fprintf(PS.fp, "/AR1 [(0)");
+        segment = (PS.sbar.length/PS.sbar.segments)/PS.sbar.subsegs;
+        for (i = PS.sbar.sublabs; i <= PS.sbar.subsegs; i += PS.sbar.sublabs )
+        {
+            fprintf(PS.fp, "(%s)", strnumber(i*segment));
+        }
+        fprintf(PS.fp, "] def\n");
+    }
+
+    /* The text in PS.sbar.units used to calculate size of text */
+    if (PS.sbar.type == 'I') {
+        fprintf(PS.fp,
+                "/mgy mg def (%s) SWH 2 add /chg XD "
+                "chg mg 2 mul add /hg XD 2 add wd add /wd XD\n",
+                PS.sbar.units);
+    }
+    else if (PS.sbar.type == 's' || PS.sbar.type == 'S') {
+        fprintf(PS.fp,
+                "AR0 dup length -- get SWH "
+                "mg add /mgy XD 2 div dup mg add /mgr XD wd add (%s) SW 2 add add /wd XD "
+                "/hg mgy 2 add mg add chg add def\n",
+                PS.sbar.units);
+    }
+    else {
+        fprintf(PS.fp,
+                "AR0 dup length -- get SWH "
+                "mg add /mgy XD 2 div dup mg add /mgr XD wd add /wd XD "
+                "/hg mgy 2 mul ++ chg add def\n");
+    }
+    /* prepare the scalebar */
+    if (PS.sbar.subsegs == 0 || PS.sbar.type == 'I') {
+        fprintf(PS.fp,
+                "/dx cwd %d div def "
+                "/mgx mg def\n", PS.sbar.segments);
+    }
+    else {
+        fprintf(PS.fp,
+                "/dx cwd %d div def\n"
+                "AR1 dup length -- get SW 2 div dup "
+                "mg add dx add /mgx XD wd add /wd XD\n",
+                PS.sbar.segments+1);
+    }
+
+    /* do the scalebar */
+    set_box_draw(&(PS.sbar.box));
+    switch (PS.sbar.type)
+    {
+        case 'I':
+            fprintf(PS.fp, "/RBAR {{x exch dx mul add y dx dy RF} for} D\n");
+            fprintf(PS.fp, "/RTXT {{/i XD x i dx mul add y M AR0 i get SHR} for} D\n");
+            fprintf(PS.fp, "/mgy mg def RESET /dy chg neg def\n");
+            set_ps_color(&(PS.sbar.font.color));
+            fprintf(PS.fp, "1 LW x y cwd dy RE\n");
+            fprintf(PS.fp, "1 2 %d RBAR\n", PS.sbar.segments-1);
+            set_ps_color(&(PS.sbar.fcolor));
+            fprintf(PS.fp, "0 2 %d RBAR\n", PS.sbar.segments-1);
+            fprintf(PS.fp, "/y y dy 1 add add def ");
+            fprintf(PS.fp, "2 2 %d RTXT ", PS.sbar.segments);
+            set_ps_color(&(PS.sbar.font.color));
+            fprintf(PS.fp, "1 2 %d RTXT ", PS.sbar.segments);
+            fprintf(PS.fp, "(%s) x cwd 2 add add y MS\n", PS.sbar.units);
+            break;
+        case 'f':
+        case 'F':
+            fprintf(PS.fp,"/RBAR ");
+            if (PS.sbar.type == 'F')
+                fprintf(PS.fp, "{ {x exch dx mul add y chg 2 div sub dx 3 index RF} for pop} D\n");
+            else
+                fprintf(PS.fp, "{ {x exch dx mul add y dx 3 index RF} for pop} D\n");
+            fprintf(PS.fp,
+                    "/RTXT {1 2 index length -- "
+                    "{dup x exch dx mul i mul add y 1 add M"
+                    " 1 index exch get SHC} for pop} D\n");
+            fprintf(PS.fp, "RESET /dy chg neg def\n");
+            set_ps_color(&(PS.sbar.fcolor));
+            fprintf(PS.fp, "x %s y cwd dy 4 copy RF ", (PS.sbar.subsegs > 0 ? "dx sub" : ""));
+            set_ps_color(&(PS.sbar.font.color));
+            fprintf(PS.fp, ".5 LW RE\n");
+            if (PS.sbar.type == 'F') {
+                fprintf(PS.fp, "dy 2 div neg 0 2 %d RBAR ", PS.sbar.segments-1);
+                fprintf(PS.fp, "dy 2 div 1 2 %d RBAR\n", PS.sbar.segments-1);
+            }
+            else {
+                fprintf(PS.fp, "dy 0 2 %d RBAR ", PS.sbar.segments-1);
+            }
+            fprintf(PS.fp, "/i %d def AR0 0 RTXT ", PS.sbar.labels);
+            if (PS.sbar.subsegs > 0)
+            {
+                fprintf(PS.fp, "/dx dx %d div neg def ", PS.sbar.subsegs);
+                if (PS.sbar.type == 'F') {
+                    fprintf(PS.fp, "dy 2 div 0 2 %d RBAR ", PS.sbar.subsegs-1);
+                    fprintf(PS.fp, "dy 2 neg div 1 2 %d RBAR ", PS.sbar.subsegs-1);
+                }
+                else {
+                    fprintf(PS.fp, "dy 1 2 %d RBAR ", PS.sbar.subsegs-1);
+                }
+                fprintf(PS.fp, "/i %d def AR1 1 RTXT\n", PS.sbar.sublabs);
+            }
+            fprintf(PS.fp,
+                    "xo wd add mgr sub yo hg sub mg add M (%s) SHR\n",
+                    PS.sbar.units);
+            break;
+        case 's':
+        case 'S':
+        default:
+            fprintf(PS.fp,
+                    "/RBAR { {x exch dx mul add y M dup 0 exch LRS} for pop} D\n"
+                    "/RTXT {1 2 index length -- "
+                    "{dup x exch dx mul i mul add y dy add ++ M"
+                    " 1 index exch get SHC} for pop} D\n");
+            fprintf(PS.fp, "RESET /dy chg 2 div def /y y dy sub def .5 LW\n");
+            if (PS.sbar.type == 'S') {
+                set_ps_color(&(PS.sbar.fcolor));
+                fprintf(PS.fp, "x %s y cwd dy neg 4 copy RF ",
+                        (PS.sbar.subsegs > 0 ? "dx sub" : ""));
+                set_ps_color(&(PS.sbar.font.color));
+                fprintf(PS.fp, "RE\n", PS.sbar.segments);
+            }
+            else {
+                set_ps_color(&(PS.sbar.font.color));
+                fprintf(PS.fp, "GS 2 LC x %s y dy sub M cwd 0 LRS GR\n",
+                    (PS.sbar.subsegs > 0 ? "dx sub" : ""));
+            }
+            fprintf(PS.fp, "dy neg 0 1 %d RBAR\n", PS.sbar.segments);
+            fprintf(PS.fp, "/i %d def AR0 0 RTXT ", PS.sbar.labels);
+            fprintf(PS.fp, "dy 0 %d %d RBAR\n", PS.sbar.labels, PS.sbar.segments);
+            if (PS.sbar.subsegs > 0)
+            {
+                fprintf(PS.fp, "/dx dx %d div neg def ", PS.sbar.subsegs);
+                fprintf(PS.fp, "dy neg 1 1 %d RBAR ", PS.sbar.subsegs);
+                fprintf(PS.fp, "/i %d def AR1 1 RTXT\n", PS.sbar.sublabs);
+                fprintf(PS.fp, "dy 0 %d %d RBAR ", PS.sbar.sublabs, PS.sbar.subsegs);
+            }
+            fprintf(PS.fp,
+                    "xo wd add mg sub y dy add ++ M (%s) SHR\n",
+                    PS.sbar.units);
+            break;
+    }
+    return 0;
+}
+
+char * strnumber(double num)
+{
+    static char text[50];
+
+    if (num == 0)
+        sprintf(text, "0");
+    else if (num == (int)num)
+        sprintf(text, "%.0f", num);
+    else if ((num * 10.) == (int)(num * 10))
+        sprintf(text, "%.1f", num);
+    else if ((num * 100.) == (int)(num * 100))
+        sprintf(text, "%.2f", num);
+    else
+        sprintf(text, "%.3f", num);
+
+    return text;
+}

Added: grass-addons/ps/ps.output/set_vector.c
===================================================================
--- grass-addons/ps/ps.output/set_vector.c	                        (rev 0)
+++ grass-addons/ps/ps.output/set_vector.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,489 @@
+/* File: set_vector.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <grass/gis.h>
+#include <grass/glocale.h>
+#include <grass/symbol.h>
+#include <grass/Vect.h>
+#include <grass/dbmi.h>
+#include "vector.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+#define DRAW_LINE   0
+#define DRAW_HLINE  1
+
+int set_vector(int masked, int type)
+{
+    int i;
+    char buf[1024];
+
+    for (i = PS.vct_files -1; i >= 0; i--)
+    {
+        if (masked && !PS.vct[i].masked) {
+            continue;
+        }
+        if (!masked && PS.vct[i].masked) {
+            continue;
+        }
+        if (PS.vct[i].type != type) {
+            continue;
+        }
+        /* select the type of output */
+        if (PS.vct[i].type == LINES)
+        {
+            VLINES * vl = (VLINES *)PS.vct[i].data;
+            if (vl->hline.width > 0 && !(vl->hline.color.none))
+            {
+                set_vlines(PS.vct[i], vl, DRAW_HLINE);
+                Vect_rewind(&(PS.vct[i].Map));
+            }
+            set_vlines(PS.vct[i], vl, DRAW_LINE);
+        }
+        else if (PS.vct[i].type == AREAS)
+        {
+            VAREAS * va = (VAREAS *)PS.vct[i].data;
+            if (va->pat != NULL)
+            {
+                set_ps_pattern(PS.vct[i].id, va->pat, va);
+            }
+            if (va->width != 0.)
+                set_vline_areas(PS.vct[i], va);
+            else
+                set_vareas(PS.vct[i], va);
+        }
+        else if (PS.vct[i].type == POINTS)
+        {
+            SYMBOL *symb;
+            VPOINTS * vp = (VPOINTS *)PS.vct[i].data;
+            symb = S_read(vp->symbol);
+            if (symb != NULL)
+            {
+                symbol_save(PS.vct[i].id, vp, symb);
+            }
+            else
+            {
+                set_ps_symbol_eps(PS.vct[i].id, vp, vp->symbol);
+            }
+            set_vpoints(PS.vct[i], vp);
+        }
+    }
+
+    return 0;
+}
+
+/* TO DRAW LINES */
+int vector_line(struct line_pnts *lpoints)
+{
+    if (lpoints->n_points > 0)
+    {
+        register int i;
+        where_moveto(lpoints->x[0], lpoints->y[0]);
+        for (i = 1; i <= lpoints->n_points - 1; i++)
+        {
+            where_lineto(lpoints->x[i], lpoints->y[i]);
+        }
+    }
+    return 0;
+}
+
+/* TO DRAW AREAS */
+int vector_area(struct line_pnts *lpoints, double sep)
+{
+    if (lpoints->n_points > 0)
+    {
+        struct line_pnts *opoints;
+        opoints = Vect_new_line_struct();
+
+        register int i;
+        where_moveto(lpoints->x[0], lpoints->y[0]);
+        for (i = 1; i < lpoints->n_points; i++)
+        {
+            where_lineto(lpoints->x[i], lpoints->y[i]);
+        }
+        Vect_line_parallel(lpoints, sep, 0.01, 0, opoints);
+        Vect_line_reverse(opoints);
+        for (i = 0; i < opoints->n_points; i++)
+        {
+            where_lineto(opoints->x[i], opoints->y[i]);
+        }
+        where_lineto(lpoints->x[0], lpoints->y[0]);
+    }
+    return 0;
+}
+
+/** Process a vector of lines */
+int set_vlines(VECTOR vec, VLINES *vl, int flag)
+{
+    int ret, cat;
+    int ln, nlines, pt, npoints;
+    struct line_cats *lcats;
+    struct line_pnts *lpoints;
+
+
+    nlines = Vect_get_num_lines(&(vec.Map));
+
+    fprintf(PS.fp, "GS 1 setlinejoin\n");  /* lines with linejoin = round */
+
+    /* Create vector array, if required */
+    if (vec.cats != NULL)
+    {
+        vec.Varray = Vect_new_varray(nlines);
+        ret = Vect_set_varray_from_cat_string(&(vec.Map), vec.layer,
+                        vec.cats, vl->type, 1, vec.Varray);
+    }
+    else if (vec.where != NULL)
+    {
+        vec.Varray = Vect_new_varray(nlines);
+        ret = Vect_set_varray_from_db(&(vec.Map), vec.layer,
+                        vec.where, vl->type, 1, vec.Varray);
+    }
+    else
+        vec.Varray = NULL;
+
+    /* memory for coordinates */
+    lcats   = Vect_new_cats_struct();
+    lpoints = Vect_new_line_struct();
+
+    /* process only vectors in current window */
+    Vect_set_constraint_region(&(vec.Map),
+            PS.map.north, PS.map.south,
+            PS.map.east,  PS.map.west,
+            PORT_DOUBLE_MAX, -PORT_DOUBLE_MAX);
+
+    /* load attributes if fcolor is named */
+    dbCatValArray cv_rgb;
+    if (flag == DRAW_LINE)
+    {
+        if (vl->rgbcol != NULL)
+            load_catval_array(&(vec.Map), vl->rgbcol, &cv_rgb);
+    }
+
+    /* read and plot lines */
+    for (ln = 1; ln <= nlines; ln++)
+    {
+        ret = Vect_read_line(&(vec.Map), lpoints, lcats, ln);
+        if (ret < 0)
+            continue;
+        if (!(ret & GV_LINES) || !(ret & vl->type))
+            continue;
+        if (vec.Varray != NULL && vec.Varray->c[ln] == 0)
+            continue;
+
+        /* Oops the line is correct, I can draw it */
+        /* How I can draw it? */
+        if (flag == DRAW_HLINE)
+        {
+            if (vl->offset != 0.)
+            {
+                double dis;
+                struct line_pnts *opoints = Vect_new_line_struct();
+
+                dis = vl->offset * POINT_TO_MM / 1000. * PS.scale;
+                Vect_line_parallel(lpoints, dis, 0.1, 0, opoints);
+                vector_line(opoints);
+            }
+            else
+                vector_line(lpoints);
+            set_ps_line(&(vl->hline));
+        }
+        else
+        {
+            vector_line(lpoints);
+            Vect_cat_get(lcats, 1, &cat);
+            /* dynamic colors */
+            if (vl->rgbcol != NULL)
+            {
+                PSCOLOR color;
+                set_color_name(&color, get_string(&cv_rgb, cat));
+                set_ps_color(&color);
+            }
+            else
+            {
+                set_ps_color(&(vl->line.color));
+            }
+            set_ps_line_no_color(&(vl->line));
+        }
+        /* paint now */
+        fprintf(PS.fp, "S\n");
+    }
+    fprintf(PS.fp, "GR\n");
+    return 0;
+}
+
+/** Process a vector of areas */
+int set_vareas(VECTOR vec, VAREAS *va)
+{
+    int k, ret, cat;
+    int area, nareas, island, nislands;
+    struct line_cats *lcats;
+    struct line_pnts *lpoints;
+    BOUND_BOX box;
+
+    nareas = Vect_get_num_areas(&(vec.Map));
+
+    fprintf(PS.fp, "GS 1 setlinejoin\n");  /* lines with linejoin = round */
+
+    /* Create vector array, if required */
+    if (vec.cats != NULL)
+    {
+        vec.Varray = Vect_new_varray(nareas);
+        Vect_set_varray_from_cat_string(&(vec.Map),
+                                          vec.layer, vec.cats, GV_AREA, 1, vec.Varray);
+    }
+    else if (vec.where != NULL)
+    {
+        vec.Varray = Vect_new_varray(nareas);
+        Vect_set_varray_from_db(&(vec.Map),
+                                  vec.layer, vec.where, GV_AREA, 1, vec.Varray);
+    }
+    else
+        vec.Varray = NULL;
+
+    /* memory for categories and coordinates */
+    lcats   = Vect_new_cats_struct();
+    lpoints = Vect_new_line_struct();
+
+    /* load attributes if fcolor is named */
+    dbCatValArray rgb;
+    if (va->rgbcol != NULL)
+    {
+        load_catval_array(&(vec.Map), va->rgbcol, &rgb);
+    }
+
+    /* read and plot vectors */
+    for (area = 1; area <= nareas; area++)
+    {
+        if (vec.Varray != NULL && vec.Varray->c[area] == 0) {
+            continue;
+        }
+        /* check if in window */
+        Vect_get_area_box(&(vec.Map), area, &box);
+        if (box.N < PS.map.south || box.S > PS.map.north ||
+            box.E < PS.map.west  || box.W > PS.map.east)
+            continue;
+        /* Oops is a correct area, I can draw it */
+        if (Vect_get_area_points(&(vec.Map), area, lpoints) < 0)
+            break;
+        /* main area */
+        fprintf(PS.fp, "NP ");
+        vector_line(lpoints);
+        fprintf(PS.fp, "CP\n");
+        /* islands */
+        nislands = Vect_get_area_num_isles(&(vec.Map), area);
+        for (island = 0; island < nislands; island++)
+        {
+            k = Vect_get_area_isle(&(vec.Map), area, island);
+            if (Vect_get_isle_points(&(vec.Map), k, lpoints) < 0)
+                return -1;
+
+            vector_line(lpoints);
+            fprintf(PS.fp, "CP\n");
+        }
+        /* set the fill */
+        if (!va->fcolor.none || va->rgbcol != NULL)
+        {
+            double r = va->fcolor.r;
+            double g = va->fcolor.g;
+            double b = va->fcolor.b;
+            /* set the color */
+            if (va->rgbcol != NULL) /* dynamic fcolor */
+            {
+                int R, G, B;
+                cat = Vect_get_area_cat(&(vec.Map), area, vec.layer);
+                if (G_str_to_color(get_string(&rgb, cat), &R, &G, &B) == 1)
+                {
+                    r = (double)R/255.;
+                    g = (double)G/255.;
+                    b = (double)B/255.;
+                }
+            }
+            fprintf(PS.fp, "%.3f %.3f %.3f ", r, g, b);
+            /* set the type of fill */
+            if (va->pat != NULL)
+                fprintf(PS.fp, "PATTERN%d setpattern F ", vec.id);
+            else
+                fprintf(PS.fp, "C F ");
+        }
+        /* set the line style */
+        if (va->line.width > 0 && !va->line.color.none)
+        {
+            set_ps_line(&(va->line));
+            fprintf(PS.fp, "S\n");
+        }
+    }
+
+    fprintf(PS.fp, "GR\n");
+    return 0;
+}
+
+/** Process a vector of lines */
+int set_vpoints(VECTOR vec, VPOINTS * vp)
+{
+    int ret, cat;
+    int  x, y, pt, npoints;
+    double size, rotate;
+    struct line_cats *lcats;
+    struct line_pnts *lpoints;
+
+    npoints = Vect_get_num_lines(&(vec.Map));
+
+    /* Create vector array, if required */
+    if (vec.cats != NULL)
+    {
+        vec.Varray = Vect_new_varray(npoints);
+        Vect_set_varray_from_cat_string(&(vec.Map), vec.layer,
+                    vec.cats, vp->type, 1, vec.Varray);
+    }
+    else if (vec.where != NULL)
+    {
+        vec.Varray = Vect_new_varray(npoints);
+        Vect_set_varray_from_db(&(vec.Map), vec.layer,
+                    vec.where, vp->type, 1, vec.Varray);
+    }
+    else
+        vec.Varray = NULL;
+
+    /* memory for coordinates */
+    lcats   = Vect_new_cats_struct();
+    lpoints = Vect_new_line_struct();
+
+    /* load attributes if any */
+    dbCatValArray cv_size, cv_rot;
+    if (vp->sizecol != NULL)
+        load_catval_array(&(vec.Map), vp->sizecol, &cv_size);
+    if (vp->rotatecol != NULL)
+        load_catval_array(&(vec.Map), vp->rotatecol, &cv_rot);
+
+    /* read and plot lines */
+    for (pt = 1; pt <= npoints; pt++)
+    {
+        ret = Vect_read_line(&(vec.Map), lpoints, lcats, pt);
+        if (ret < 0)
+            continue;
+        if (!(ret & GV_POINTS) || !(ret & vp->type))
+            continue;
+        if (vec.Varray != NULL && vec.Varray->c[pt] == 0)
+            continue;
+        /* Is it inside area? */
+        G_plot_where_xy(lpoints->x[0], lpoints->y[0], &x, &y);
+        PS.x = (double)x / 10.;
+        PS.y = (double)y / 10.;
+        if (PS.x < PS.map_x || PS.x > PS.map_right ||
+            PS.y < PS.map_y || PS.y > PS.map_top)
+            continue;
+        /* Oops the point is correct, I can draw it */
+        Vect_cat_get(lcats, 1, &cat);
+        fprintf(PS.fp, "GS ");
+        fprintf(PS.fp, "%.4f %.4f TR ", PS.x, PS.y);
+        /* symbol size */
+        if (vp->sizecol == NULL) {
+            size = vp->size;
+        }
+        else {
+            get_number(&cv_size, cat, &size);
+            size *= vp->scale;
+        }
+        if (size > 0.)
+            fprintf(PS.fp, "%.3f dup SC ", size);
+        /* symbol rotate */
+        if (vp->rotatecol == NULL) {
+            rotate = vp->rotate;
+        }
+        else {
+            get_number(&cv_rot, cat, &rotate);
+        }
+        if (rotate > 0.)
+            fprintf(PS.fp, "%.3f ROT ", rotate);
+        /* symbol line */
+        if (size == 0.)
+            size = 1.; /* avoid division by zero */
+        fprintf(PS.fp, "%.3f LW SYMBOL%d ", (vp->line.width)/size, vec.id);
+        fprintf(PS.fp, "GR\n");
+    }
+
+    return 0;
+}
+
+/** Process a vector of lines as area */
+int set_vline_areas(VECTOR vec, VAREAS *va)
+{
+    int ret, cat;
+    int ln, nlines, pt, npoints;
+    double width;
+    struct line_cats *lcats;
+    struct line_pnts *lpoints;
+
+
+    nlines = Vect_get_num_lines(&(vec.Map));
+
+    fprintf(PS.fp, "GS 1 setlinejoin\n");  /* lines with linejoin = round */
+
+    /* Create vector array, if required */
+    if (vec.cats != NULL)
+    {
+        vec.Varray = Vect_new_varray(nlines);
+        ret = Vect_set_varray_from_cat_string(&(vec.Map), vec.layer,
+                vec.cats, GV_LINE, 1, vec.Varray);
+    }
+    else if (vec.where != NULL)
+    {
+        vec.Varray = Vect_new_varray(nlines);
+        ret = Vect_set_varray_from_db(&(vec.Map), vec.layer,
+                                        vec.where, GV_LINE, 1, vec.Varray);
+    }
+    else
+        vec.Varray = NULL;
+
+    /* memory for coordinates */
+    lcats   = Vect_new_cats_struct();
+    lpoints = Vect_new_line_struct();
+
+    /* process only vectors in current window */
+    Vect_set_constraint_region(&(vec.Map),
+                                 PS.map.north, PS.map.south,
+                                 PS.map.east,  PS.map.west,
+                                 PORT_DOUBLE_MAX, -PORT_DOUBLE_MAX);
+
+    /* read and plot lines */
+    for (ln = 1; ln <= nlines; ln++)
+    {
+        ret = Vect_read_line(&(vec.Map), lpoints, lcats, ln);
+        if (ret < 0)
+            continue;
+        if (!(ret & GV_LINE))
+            continue;
+        if (vec.Varray != NULL && vec.Varray->c[ln] == 0)
+            continue;
+
+        /* Oops the line is correct, I can draw it */
+        fprintf(PS.fp, "NP ");
+        vector_area(lpoints, va->width * POINT_TO_MM / 1000. * PS.scale);
+        fprintf(PS.fp, "CP\n");
+        /* set the fill */
+        if (!va->fcolor.none)
+        {
+            fprintf(PS.fp, "%.3f %.3f %.3f ",
+                    va->fcolor.r, va->fcolor.g, va->fcolor.b);
+            if (va->pat != NULL)
+                fprintf(PS.fp, "PATTERN%d setpattern F ", vec.id);
+            else
+                fprintf(PS.fp, "C F ");
+        }
+        /* set the line style */
+        if (va->line.width > 0 && !va->line.color.none)
+        {
+            set_ps_line(&(va->line));
+            fprintf(PS.fp, "S\n");
+        }
+    }
+    fprintf(PS.fp, "GR\n");
+    return 0;
+}

Added: grass-addons/ps/ps.output/set_vlegend.c
===================================================================
--- grass-addons/ps/ps.output/set_vlegend.c	                        (rev 0)
+++ grass-addons/ps/ps.output/set_vlegend.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,179 @@
+/* Function: vect_legend
+ **
+ ** Author: Paul W. Carlson April 1992
+ ** Modified by: Radim Blazek Jan 2000 area, label added
+ ** Modified by: Morten Hulden Mar 2004, support for legend in columns added
+ ** Modified by: E. Jorge Tizado Feb 2009, improve postscript code
+ */
+
+#include "vlegend.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+int set_vlegend(void)
+{
+    int n, i, j, k, l, rows, cols, st, items, nopos;
+    double x, y, fontsize, sc;
+
+    /* Sort categories by user (min value) - In preparation */
+    CELL * ip = (CELL *) G_malloc(sizeof( CELL) * PS.vct_files);
+    for (items = 0, i = 0; i < PS.vct_files; i++)
+    {
+        if (PS.vct[i].lpos > 0) {
+            /* ip[items++] = PS.vct[i].id; */
+            ip[items++] = i;
+        }
+    }
+    if (items == 0)
+        return 0;
+
+    if (PS.vl.order[0] != 0)
+        sort_list(PS.vl.order, rows, &ip);
+
+	/* define number of rows */
+    if (items < PS.vl.legend.cols) PS.vl.legend.cols = items;
+    rows = (int)items / PS.vl.legend.cols;	/* lines per column */
+    if (items % PS.vl.legend.cols) ++rows;
+    cols = PS.vl.legend.cols;
+
+    /* set font */
+    fontsize = set_ps_font(&(PS.vl.legend.font));
+
+    /* Array of data */
+    fprintf(PS.fp, "/ARh %d array def\n", rows);
+    fprintf(PS.fp, "0 1 %d {ARh exch %.2f put} for\n", rows-1, fontsize);
+
+    fprintf(PS.fp, "/ARw %d array def\n", cols);
+    for (i = 0, n = 0; n < cols; n++)
+    {
+        fprintf(PS.fp, "/AR%d [\n", n);
+        for (j = 0; j < rows && i < items; j++, i++)
+        {
+            k = ip[i];
+            /* label of de vector file */
+            if (PS.vct[k].label == NULL) {
+                fprintf(PS.fp, "( %s (%s))", PS.vct[k].name, PS.vct[k].mapset);
+            }
+            else {
+                fprintf(PS.fp, "( %s)", PS.vct[k].label);
+            }
+            /* vector data */
+            fprintf(PS.fp, " %d [", PS.vct[k].type);
+            if (PS.vct[k].type == AREAS)
+            {
+                VAREAS * va = (VAREAS *)PS.vct[k].data;
+                if (!va->line.color.none && va->line.width > 0)
+                {
+                    fprintf(PS.fp, "%.3f %.3f %.3f [%s] %.8f 1 ",
+                            va->line.color.r,
+                            va->line.color.g,
+                            va->line.color.b,
+                            va->line.dash,
+                            va->line.width);
+                }
+                else {
+                    fprintf(PS.fp, "0 "); /* no line */
+                }
+                if (!va->fcolor.none || va->pat != NULL)
+                {
+                    if (va->pat != NULL)
+                        fprintf(PS.fp, "PATTERN%d 1 1", PS.vct[k].id);
+                    else
+                        fprintf(PS.fp, "%.3f %.3f %.3f 0 1",
+                            va->fcolor.r,
+                            va->fcolor.g,
+                            va->fcolor.b);
+                }
+                else {
+                    fprintf(PS.fp, "0"); /* no fill area */
+                }
+            }
+            else if (PS.vct[k].type == LINES)
+            {
+                VLINES * vl = (VLINES *)PS.vct[i].data;
+                fprintf(PS.fp, "%.3f %.3f %.3f [%s] %.8f",
+                        vl->line.color.r,
+                        vl->line.color.g,
+                        vl->line.color.b,
+                        vl->line.dash,
+                        vl->line.width);
+                if (vl->hline.width <= 0)
+                    fprintf(PS.fp, " 1");
+                else
+                {
+                    fprintf(PS.fp, " %.3f %.3f %.3f [%s] %.8f",
+                            vl->hline.color.r,
+                            vl->hline.color.g,
+                            vl->hline.color.b,
+                            vl->hline.dash,
+                            vl->hline.width);
+                    fprintf(PS.fp, " 2");
+                }
+            }
+            else if (PS.vct[k].type == POINTS)
+            {
+                VPOINTS * vp = (VPOINTS *)PS.vct[k].data;
+                fprintf(PS.fp, "(SYMBOL%d) ", PS.vct[k].id);
+                /* if vp->size == 0 => no draw? */
+                fprintf(PS.fp, " %.4f", vp->line.width / vp->size);
+                fprintf(PS.fp, " %.3f", vp->rotate);
+                fprintf(PS.fp, " %.3f dup", vp->size);
+                fprintf(PS.fp, " %.3f", .45*fontsize);
+            }
+            fprintf(PS.fp, "]\n");
+        }
+        fprintf(PS.fp, "] def\n");
+        fprintf(PS.fp, "/mx 0 def 0 3 AR%d length -- { ", n);
+        fprintf(PS.fp, "AR%d exch get SW /t XD t mx gt {/mx t def} if } for\n", n);
+        fprintf(PS.fp, "ARw %d mx put\n", n);
+    }
+    G_free(ip);
+
+    /** Adjust - Legend Box */
+    set_box_orig(&(PS.vl.legend.box));
+    set_legend_adjust(&(PS.vl.legend), -1.);
+    if (PS.vl.legend.title[0])
+        set_box_readjust_title(&(PS.vl.legend.box),
+                                 PS.vl.legend.title);
+    set_box_draw(&(PS.vl.legend.box));
+
+    /* Make the vector legend */
+    fprintf(PS.fp, "RESET\n");
+    fprintf(PS.fp, "/xw syw %.2f mul def ", 0.9);    /* symbol-width */
+    for (n = 0; n < cols; n++)
+    {
+        fprintf(PS.fp, "%d COL 0 ROW\n"
+                "0 3 AR%d length 1 sub {/i XD\n"
+                "ARh row get neg /rh XD\n"
+                "AR%d i 1 add get /tipe XD\n"
+                "AR%d i 2 add get aload pop\n", n, n, n, n);
+        fprintf(PS.fp,  "tipe %d eq {", POINTS);
+        fprintf(PS.fp,  "GS rh sub 2 div neg y add x xw 2 div add exch "
+                "TR SC ROT LW cvx cvn exec GR} if\n");
+        fprintf(PS.fp,  "tipe %d eq {", LINES);
+        fprintf(PS.fp,  "{LW 0 LD C x xw add y rh 0.65 mul add dup x exch ML} "
+                "repeat} if\n");
+        fprintf(PS.fp,  "tipe %d eq {[] 0 LD ", AREAS);
+        fprintf(PS.fp,  "x y -- x xw add y rh add -- B "
+                "0 ne {0 eq {C} {setpattern} ifelse F} if "
+                "0 ne {LW 0 LD C} if S} if\n", 0.2, 0.1, 0.6, 0.8);
+        set_ps_color(&(PS.vl.legend.font.color));
+        fprintf(PS.fp, "AR%d i get x syw add y ARh row get sub MS row ++ ROW} for\n", n);
+    }
+	fprintf(PS.fp, "[] 0 setdash\n");
+
+    /* Make the title of legend */
+    if (PS.vl.legend.title[0] != 0)
+    {
+        set_ps_font(&(PS.vl.legend.title_font));
+        fprintf(PS.fp, "RESET\n");
+        if (PS.vl.legend.title[0] == '.')
+            fprintf(PS.fp, "(%s) x cwd 2 div add yo mgy mg sub sub M SHC\n",
+                    PS.vl.legend.title+1, PS.vl.legend.title_font.size);
+        else
+            fprintf(PS.fp, "(%s) x yo mgy mg sub sub MS\n",
+                    PS.vl.legend.title, PS.vl.legend.title_font.size);
+    }
+
+    return 0;
+}

Added: grass-addons/ps/ps.output/start_map.c
===================================================================
--- grass-addons/ps/ps.output/start_map.c	                        (rev 0)
+++ grass-addons/ps/ps.output/start_map.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,117 @@
+/* File: start_map.c
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <grass/gis.h>
+#include <grass/glocale.h>
+#include "ps_info.h"
+#include "local_proto.h"
+
+#include "conversion.h"
+
+int move_local(int x, int y);
+int cont_local(int x, int y);
+
+int start_map(void)
+{
+    double width, height;
+    double fact, d_ns, ns, d_ew, ew;
+
+    /* default position */
+    if (PS.map_x < 0) {
+        PS.map_x = PS.page.left + PS.brd.width;
+    }
+    if (PS.map_top < 0) {
+        PS.map_top = PS.page.top + PS.brd.width;
+    }
+
+    /* maximun space to print from position */
+    width  = PS.page.width - PS.map_x - (PS.page.right + PS.brd.width);
+    height = PS.page.height - PS.map_top - (PS.page.bot + PS.brd.width);
+
+    /* default size */
+    if (PS.map_w < 0 || PS.map_w > width) {
+        PS.map_w = width;
+    }
+    if (PS.map_h < 0 || PS.map_h > height) {
+        PS.map_h = height;
+    }
+
+    /* distance calculation, throught center of map */
+    G_begin_distance_calculations();
+
+    if (PS.map.proj == PROJECTION_LL)
+    {
+        ns = (PS.map.north + PS.map.south)/2.;
+        d_ew = G_distance(PS.map.east, ns, PS.map.west, ns);
+
+        ew = (PS.map.east + PS.map.west)/2.;
+        d_ns = G_distance(ew, PS.map.north, ew, PS.map.south);
+    }
+    else
+    {
+        d_ew = (PS.map.east - PS.map.west);
+        d_ns = (PS.map.north - PS.map.south);
+    }
+
+    /* to define the scale */
+    if (PS.scale > 0)
+    {
+        fact = MT_TO_POINT / (double)PS.scale;
+        ew = fact * d_ew;
+        ns = fact * d_ns;
+        if (ew <= PS.map_w && ns <= PS.map_h)
+        {
+            PS.map_w = ew;
+            PS.map_h = ns;
+        }
+        else
+            PS.scale = 0;   /* forze readjust scale */
+    }
+    /* auto scale */
+    if (PS.scale <= 0)
+    {
+        ew = d_ew / PS.map_w;
+        ns = d_ns / PS.map_h;
+        fact = (ew > ns) ? ew : ns;
+        PS.scale = (int)(MT_TO_POINT * fact);
+
+        fact = 1000. * MM_TO_POINT / (double)PS.scale;
+        PS.map_w = fact * d_ew;
+        PS.map_h = fact * d_ns;
+    }
+
+    G_message(_("Scale set to  1 : %d"), PS.scale);
+
+    /* now I can calculate the 'y' position */
+    PS.map_y = PS.page.height - PS.map_h - PS.map_top;
+
+    /* to complete */
+    PS.map_right = PS.map_x + PS.map_w;
+    PS.map_top   = PS.map_y + PS.map_h;
+
+    G_setup_plot(10. * (PS.map_y + PS.map_h), 10. * PS.map_y,
+                 10. * PS.map_x, 10. * (PS.map_x + PS.map_w),
+                 move_local, cont_local);
+
+    return 0;
+}
+
+/* Needed by G_setup_plot */
+int move_local(int x, int y)
+{
+    fprintf(PS.fp, "%.1f %.1f M\n", (double)x/10., (double)y/10.);
+    return 0;
+}
+int cont_local(int x, int y)
+{
+    fprintf(PS.fp, "%.1f %.1f L ", (double)x/10., (double)y/10.);
+    return 0;
+}
+

Added: grass-addons/ps/ps.output/symbol.c
===================================================================
--- grass-addons/ps/ps.output/symbol.c	                        (rev 0)
+++ grass-addons/ps/ps.output/symbol.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,144 @@
+/* Functions: symbol_save
+ **
+ ** Author: Radim Blazek
+ ** Modified: E. Jorge Tizado
+ */
+
+#include <grass/Vect.h>
+#include <grass/symbol.h>
+#include "vpoints.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+/* draw chain */
+int draw_chain(SYMBCHAIN * chain, double s)
+{
+    int k, l;
+    char *mvcmd;
+    SYMBEL *elem;
+
+    for (k = 0; k < chain->count; k++)
+    {
+        elem = chain->elem[k];
+        switch (elem->type)
+        {
+            case S_LINE:
+                for (l = 0; l < elem->coor.line.count; l++)
+                {
+                    if (k == 0 && l == 0)
+                        mvcmd = "M";
+                    else
+                        mvcmd = "L";
+                    fprintf(PS.fp, "%.4f %.4f %s\n",
+                        s * elem->coor.line.x[l],
+                        s * elem->coor.line.y[l], mvcmd);
+                }
+                break;
+            case S_ARC:
+                if (elem->coor.arc.clock)
+                    mvcmd = "arcn";
+                    else
+                    mvcmd = "arc";
+                fprintf(PS.fp, "%.4f %.4f %.4f %.4f %.4f %s\n",
+                    s * elem->coor.arc.x,
+                    s * elem->coor.arc.y,
+                    s * elem->coor.arc.r,
+                    elem->coor.arc.a1, elem->coor.arc.a2, mvcmd);
+                break;
+        }
+    }
+
+    return 0;
+}
+
+/* store symbol in PS file, scaled to final size and drawn with final colors */
+int symbol_save(int code, VPOINTS *vp, SYMBOL * Symb)
+{
+    SYMBPART *part;
+    SYMBCHAIN *chain;
+    int i,j, points;
+    double s, xo[4], yo[4];
+
+    points = 4;
+    xo[0] = 0.0;
+    yo[0] = 0.5;
+    xo[1] = -0.5;
+    yo[1] = 0.0;
+    xo[2] = 0.0;
+    yo[2] = -0.5;
+    xo[3] = 0.5;
+    yo[3] = 0.0;
+
+    s = 1;
+
+    fprintf(PS.fp, "/SYMBOL%d {\n", code);
+
+    s *= Symb->scale;
+    for (i = 0; i < Symb->count; i++)
+    {
+        part = Symb->part[i];
+        switch (part->type)
+        {
+        case S_POLYGON:
+            fprintf(PS.fp, "NP\n");	/* Start ring */
+            for (j = 0; j < part->count; j++) {	/* RINGS */
+                chain = part->chain[j];
+                draw_chain(chain, s);
+                fprintf(PS.fp, "CP\n");	/* Close one ring */
+            }
+            /* Fill */
+            if (part->fcolor.color == S_COL_DEFAULT && !vp->fcolor.none)
+            {
+                set_ps_color(&(vp->fcolor));
+                fprintf(PS.fp, "F\n");	/* Fill polygon */
+            }
+            else if (part->fcolor.color == S_COL_DEFINED)
+            {
+                fprintf(PS.fp, "%.3f %.3f %.3f C ",
+                        part->fcolor.fr,
+                        part->fcolor.fg,
+                        part->fcolor.fb);
+                fprintf(PS.fp, "F\n");
+            }
+            /* Outline */
+            if (part->color.color == S_COL_DEFAULT && !vp->line.color.none)
+            {
+                set_ps_color(&(vp->line.color));
+                fprintf(PS.fp, "S\n");	/* Draw boundary */
+            }
+            else if (part->color.color == S_COL_DEFINED)
+            {
+                fprintf(PS.fp, "%.3f %.3f %.3f C ",
+                        part->color.fr,
+                        part->color.fg,
+                        part->color.fb);
+                fprintf(PS.fp, "S\n");
+            }
+            break;
+        case S_STRING:	/* string has 1 chain */
+            if (part->color.color != S_COL_NONE)
+            {
+                fprintf(PS.fp, "NP\n");
+                chain = part->chain[0];
+                draw_chain(chain, s);
+                /* Color */
+                if (part->color.color == S_COL_DEFAULT && !vp->line.color.none)
+                {
+                    set_ps_color(&(vp->line.color));
+                    fprintf(PS.fp, "S\n");
+                }
+                else {
+                    fprintf(PS.fp, "%.3f %.3f %.3f C ",
+                            part->color.fr,
+                            part->color.fg,
+                            part->color.fb);
+                fprintf(PS.fp, "S\n");
+                }
+            }
+            break;
+        }
+    }
+    fprintf(PS.fp, "} def\n");
+
+    return 0;
+}

Added: grass-addons/ps/ps.output/val_list.c
===================================================================
--- grass-addons/ps/ps.output/val_list.c	                        (rev 0)
+++ grass-addons/ps/ps.output/val_list.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,117 @@
+/* File: val_list.c
+ *
+ *  COPYRIGHT: (c) 2009 GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include "ps_info.h"
+#include "local_proto.h"
+
+
+/* Sort categories by user */
+int sort_list(char *order, int items, CELL **item)
+{
+    int i, j, k, count, tmp;
+    CELL *ip, val;
+    DCELL *vlist;
+
+    /* initial order */
+    ip = (CELL *)G_malloc(sizeof(CELL) * items);
+    for (i = 0; i < items; i++)
+        ip[i] = i;
+
+    /* if any to order */
+    if (order[0] != 0 &&
+       (count = parse_val_list(order, &vlist)) > 0)
+    {
+        for (i = 0, j = 0; j < count; j += 2)
+        {
+            for (val = vlist[j]; val <= vlist[j+1]; val++)
+            {
+                for (k = i; k < items; k++)
+                {
+                    if ((*item)[k] == val)
+                    {
+                        tmp = ip[k]; ip[k] = ip[i]; ip[i] = tmp;
+                        (*item)[k] = (*item)[i]; i++;
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    G_free(*item);
+    *item = ip;
+    return 0;
+}
+
+
+/***********************************************************
+ * parse_val_list (buf, list)
+ *   char *buf; int **list;
+ *
+ * buf is a comma separated list of values
+ * or value ranges: 1,2,6-10,12
+ *
+ * actual usage is
+ *   char buf[300]; DCELL *list;
+ *
+ *   count = parse_val_list (buf, &list);
+ *
+ *   for (i = 0; i < count; i += 2)
+ *  {
+ *          min = list[i];
+ *      max = list[i+1];
+ *  }
+ *
+ * count will be negative if list is not valid
+ ********************************************************/
+#include <grass/gis.h>
+
+int parse_val_list(char *buf, DCELL **list)
+{
+    int count;
+    DCELL a, b;
+    DCELL *lp;
+
+    count = 0;
+    lp = (DCELL *) G_malloc(sizeof(DCELL));
+    while (*buf)
+    {
+        while (*buf == ' ' || *buf == '\t' ||
+               *buf == ',' || *buf == '\n')
+        {
+            buf++;
+        }
+        if (sscanf(buf, "%lf-%lf", &a, &b) == 2)
+        {
+            if (a > b) {
+                DCELL t;
+                t = a;
+                a = b;
+                b = t;
+            }
+            lp = (DCELL *) G_realloc(lp, (count + 2) * sizeof(DCELL));
+            lp[count++] = a;
+            lp[count++] = b;
+        }
+        else if (sscanf(buf, "%lf", &a) == 1)
+        {
+            lp = (DCELL *) G_realloc(lp, (count + 2) * sizeof(DCELL));
+            lp[count++] = a;
+            lp[count++] = a;
+        }
+        else
+        {
+            G_free(lp);
+            return -1;
+        }
+        while (*buf && (*buf != ','))
+            buf++;
+    }
+    *list = lp;
+    return count;
+}

Added: grass-addons/ps/ps.output/vareas.h
===================================================================
--- grass-addons/ps/ps.output/vareas.h	                        (rev 0)
+++ grass-addons/ps/ps.output/vareas.h	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,34 @@
+#ifndef _VAREAS_H_
+#define _VAREAS_H_
+
+/* Header file: vareas.h
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include "colors.h"
+#include "lines.h"
+
+
+typedef struct
+{
+    PSLINE line;
+
+    PSCOLOR fcolor;
+    char *rgbcol;       /* if set, fcolor for legends */
+
+    int type_pat;       /* private: 1 colored pattern, 2 uncolored pattern */
+    char *pat;          /* name of pattern */
+    double pwidth;      /* pattern width */
+    double scale;       /* pattern scale */
+
+    double width;       /* width of area */
+
+} VAREAS;
+
+#endif

Added: grass-addons/ps/ps.output/vector.c
===================================================================
--- grass-addons/ps/ps.output/vector.c	                        (rev 0)
+++ grass-addons/ps/ps.output/vector.c	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,53 @@
+
+#include <string.h>
+#include <grass/Vect.h>
+#include "vector.h"
+#include "ps_info.h"
+#include "local_proto.h"
+
+
+/* allocate memory space for a new vector */
+int vector_new(void)
+{
+    int i = PS.vct_files;
+
+    ++PS.vct_files;
+    PS.vct = (VECTOR *) G_realloc(PS.vct, PS.vct_files * sizeof(VECTOR));
+
+    PS.vct[i].type = NONE;
+    return i;
+}
+
+/* ****************** */
+
+/* GEOGRAPHIC */
+/* geographic coordinates to paper coordinates */
+/* Siempre lo pone para permitir correcto cerrado de paths */
+int where_moveto(double east, double north)
+{
+    int x, y;
+    double dx, dy;
+
+    G_plot_where_xy(east, north, &x, &y);
+
+    dx = ((double)x) / 10.;
+    dy = ((double)y) / 10.;
+
+    fprintf(PS.fp, "%.1f %.1f M ", dx, dy);
+    return 0;
+}
+
+int where_lineto(double east, double north)
+{
+    int x, y;
+    double dx, dy;
+
+    G_plot_where_xy(east, north, &x, &y);
+
+    dx = (double)x / 10.;
+    dy = (double)y / 10.;
+
+    fprintf(PS.fp, "%.1f %.1f L ", dx, dy);
+
+    return 0;
+}

Added: grass-addons/ps/ps.output/vector.h
===================================================================
--- grass-addons/ps/ps.output/vector.h	                        (rev 0)
+++ grass-addons/ps/ps.output/vector.h	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,45 @@
+#ifndef _VECTOR_H_
+#define _VECTOR_H_
+
+/* Header file: vector.h
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <grass/gis.h>
+#include <grass/Vect.h>
+#include "vareas.h"
+#include "vlines.h"
+#include "vpoints.h"
+
+
+typedef struct
+{
+    struct Map_info Map;
+    VARRAY *Varray;
+
+    char *name;         /* in Map_info also */
+    char *mapset;       /* in Map_info also */
+
+    int layer;          /* category layer */
+
+    char *cats;			/* list of categories */
+    char *where;		/* SQL where condition (without WHERE key word) */
+
+    char masked;
+
+    int id;
+    int type;           /* POINTS, LINES, AREAS */
+    void *data;         /* VPOINTS, VLINES, VAREAS */
+
+    char *label;        /* label in legend */
+    int lpos;           /* position in legend */
+
+} VECTOR;
+
+#endif

Added: grass-addons/ps/ps.output/vlegend.h
===================================================================
--- grass-addons/ps/ps.output/vlegend.h	                        (rev 0)
+++ grass-addons/ps/ps.output/vlegend.h	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,25 @@
+#ifndef _VLEGEND_H_
+#define _VLEGEND_H_
+
+/* Header file: vlegend.h
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+#include <stdio.h>
+#include "legends.h"
+
+typedef struct
+{
+	LEGEND legend;
+
+    char order[512];    /* category custom order */
+
+} VLEGEND;
+
+#endif

Added: grass-addons/ps/ps.output/vlines.h
===================================================================
--- grass-addons/ps/ps.output/vlines.h	                        (rev 0)
+++ grass-addons/ps/ps.output/vlines.h	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,33 @@
+#ifndef _VLINES_H_
+#define _VLINES_H_
+
+/* Header file: vlines.h
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+
+#include "colors.h"
+#include "lines.h"
+#include <grass/gis.h>
+
+
+typedef struct
+{
+    int type;           /* line or boundary */
+
+    PSLINE line;
+    PSLINE hline;
+
+    char *rgbcol;       /* line color from database */
+
+    double offset;      /* offset parallel line */
+
+} VLINES;
+
+#endif

Added: grass-addons/ps/ps.output/vpoints.h
===================================================================
--- grass-addons/ps/ps.output/vpoints.h	                        (rev 0)
+++ grass-addons/ps/ps.output/vpoints.h	2009-05-24 11:11:46 UTC (rev 37413)
@@ -0,0 +1,37 @@
+#ifndef _VPOINTS_H_
+#define _VPOINTS_H_
+
+/* Header file: vpoints.h
+ *
+ *  AUTHOR:    E. Jorge Tizado, Spain 2009
+ *
+ *  COPYRIGHT: (c) 2009 E. Jorge Tizado, and the GRASS Development Team
+ *             This program is free software under the GNU General Public
+ *             License (>=v2). Read the file COPYING that comes with GRASS
+ *             for details.
+ */
+
+
+#include "colors.h"
+#include "lines.h"
+
+
+typedef struct
+{
+    int type;           /* centroid or point */
+    char *symbol;
+
+    double scale;
+
+    PSLINE line;
+    PSCOLOR fcolor;
+
+    double size;
+    char * sizecol;
+
+    double rotate;
+    char * rotatecol;
+
+} VPOINTS;
+
+#endif



More information about the grass-commit mailing list