boxes-1.1.1/0040755000175000001440000000000012040315627012406 5ustar tsjensenusersboxes-1.1.1/doc/0040755000175000001440000000000012040315720013145 5ustar tsjensenusersboxes-1.1.1/doc/boxes.el0100644000175000001440000001073510455113533014620 0ustar tsjensenusers;;; boxes.el --- use boxes to comment regions ;; Copyright (C) 1999, 2001, 2006 Jason L. Shiffer ;; Author: Jason L. Shiffer ;; Maintainer: jshiffer@zerotao.com ;; Keywords: extensions ;; Created: 1999-10-30 ;; Others: ;; Vijay Lakshminarayanan: support for choosing boxes comment by current buffer mode. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program; if not, you can either send email to this ;; program's maintainer or write to: The Free Software Foundation, ;; Inc.; 675 Massachusetts Avenue; Cambridge, MA 02139, USA. ;;; Commentary: ;; This program provides an interface to the boxes application which can be found at ;; http://boxes.thomasjensen.com/ ;; To use this, put it somewhere in your load path and add the following ;; lines to your .emacs: ;; ;; (autoload 'boxes-command-on-region "boxes" nil t) ;; (autoload 'boxes-remove "boxes" nil t) ;; (autoload 'boxes-create "boxes" nil t) ;; (global-set-key "\C-cq" 'boxes-create) ;; (global-set-key "\C-cr" 'boxes-remove) ;;; Code: (eval-when-compile (require 'cl)) ;;;###autoload (defvar boxes-command "boxes" "The boxes command.") (defvar boxes-types-alist (ignore-errors (with-temp-buffer (call-process "boxes" nil t nil "-l") (goto-char (point-min)) (let ((retval nil)) (while (re-search-forward "^\\([a-zA-Z][a-zA-Z0-9-]+\\) (.*):" nil t) (add-to-list 'retval (cons (match-string 1) (match-string 1)))) retval))) "Association of types available to the current boxes implementation." ) (make-variable-buffer-local 'boxes-types-alist) (defvar boxes-history (list nil)) ;;;###autoload (defvar boxes-known-modes '((c-mode . "c-cmt2") (c++-mode . "c-cmt2") (java-mode . "java-cmt") (html-mode . "html-cmt") (sh-mode . "pound-cmt") (perl-mode . "pound-cmt") (python-mode . "pound-cmt") (ruby-mode . "pound-cmt") (emacs-lisp-mode . "lisp-cmt") (lisp-mode . "lisp-cmt")) "The default comment type based on file names.") (make-variable-buffer-local 'boxes-known-modes) ;;;###autoload (defun boxes-set-default-type (mode) "Set the default box mode according to the buffer's major mode." (setq boxes-default-type (or (cdr (assoc mode boxes-known-modes)) "c-cmt2"))) ;;;###autoload (defvar boxes-default-type nil "The default type of comment.") (make-variable-buffer-local 'boxes-default-type) ;;;###autoload (defvar boxes-args "" "Arguments to the boxes command.") (make-variable-buffer-local 'boxes-args) ;;;###autoload (defun boxes-create () "Automagicly create a new box around the region based on the default type." (interactive "*") (boxes-command-on-region (region-beginning) (region-end) boxes-default-type)) ;;;###autoload (defun boxes-remove () "Automagicly remove a new box around the region based on the default type." (interactive "*") (boxes-command-on-region (region-beginning) (region-end) boxes-default-type 1)) ;;;###autoload (defun boxes-command-on-region (start end type &optional remove) "Create/Remove boxes from a region. To create just select a region and M-x boxes-command-on-region then you will be prompted to enter a box type. The type selection can use tab completion on the types available. To remove a box simply prefix a 1 to the callL M-1 M-x boxes-command-on-region will remove a box from a region." (interactive (let ((string (completing-read (format "Box type (%s): " boxes-default-type) boxes-types-alist nil t nil 'boxes-history boxes-default-type))) (list (region-beginning) (region-end) string current-prefix-arg))) (if type (setq boxes-default-type type) (setq boxes-default-type (boxes-set-default-type major-mode) type boxes-default-type)) (let ((command-string (concat boxes-command (if remove (concat boxes-args " -r ")) (if type (concat boxes-args " -d " type))))) (shell-command-on-region start end command-string nil 1 nil))) (provide 'boxes) ;;; boxes.el ends here boxes-1.1.1/doc/boxes.1.in0100644000175000001440000002614512040266157014772 0ustar tsjensenusers.\" @(#)boxes.1 1.1.1 10/19/12 .\" .\" $Id: boxes.1.in,v 1.10 2012/10/19 15:05:17 tsjensen Exp $ .\" .TH boxes 1 "October 19 2012" .UC 4 .SH NAME boxes \- text mode box and comment drawing filter .SH SYNOPSIS .B boxes [\-hlmrv] [\-a\ format] [\-d\ design] [\-f\ file] [\-i\ indent] [\-k\ bool] [\-p\ pad] [\-s\ size] [\-t\ tabopts] [infile [outfile]] .SH DESCRIPTION .I Boxes is a text filter which can draw any kind of box around its input text. Box design choices range from simple boxes to complex ASCII art. A box can also be removed and repaired, even if it has been badly damaged by editing of the text inside. Since boxes may be open on any side, .I boxes can also be used to create regional comments in any programming language. New box designs of all sorts can easily be added and shared by appending to a free format configuration file. .br .I boxes was originally intended to be used with the .I vim(1) text editor, but it can be tied to any text editor which supports filters, as well as called from the command line as a standalone tool. .\" ======================================================================= .SH OPTIONS Options offered by .I boxes are the following: .TP 0.6i .B \-a \fIstring\fP Alignment/positioning of text inside box. This option takes a format string argument which is read from left to right. The format string may not contain whitespace and must consist of one or more of the following components: .br .B h\fPx \- horizontal alignment of the input text block inside a potentially larger box. Possible values for .I x are .B l (ell, for left alignment), .B c (center), or .B r (right). This does not affect the justification of text lines within the input text block (use the .B j argument instead). .br .B v\fPx \- vertical alignment of the input text block inside a potentially larger box. Possible values for .I x are .B t (for top alignment), .B c (center), or .B b (bottom). .br .B j\fPx \- justification of lines within the input text block. Possible values for .I x are .B l (ell, for left justification), .B c (center), or .B r (right). This does not affect the alignment of the input text block itself within the box. Use the .B h and .B v arguments for input text block positioning. .br Short hand notations (can be combined with the above arguments): .br .B l (ell) \- short for .B h\fPl\fBv\fPc\fBj\fPl .br .B c \- short for .B h\fPc\fBv\fPc\fBj\fPc .br .B r \- short for .B h\fPr\fBv\fPc\fBj\fPr .br The factory default setting for .B \-a is .B h\fPl\fBv\fPt. .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .TP 0.6i .B \-c \fIstring\fP Command line design definition for simple cases. The argument of this option is the definition for the "west" (W) shape. The defined shape must consist of exactly one line, i.e. no multi\-line shapes are allowed. The .B \-c option is intended as a shortcut for those cases where simple regional comments are to be created, which only need a certain character or sequence of characters to be placed in front of every line. In such cases, it is much more convenient to simply specify .B \-c than to do a complete design definition in one's config file, where the only shape defined is the west shape. .br This option implies a .B \-d and does not access the config file. .B \-c may of course be used in conjunction with any of the other options. By default, .B \-c is not specified. .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .TP 0.6i .B \-d \fIstring\fP Design selection. The one argument of this option is the name of the design to use. .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .TP 0.6i .B \-f \fIstring\fP Use alternate config file. The one argument of this option is the name of a valid .I boxes config file, containing new and exciting designs! .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .TP 0.6i .B \-h Print usage information. .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .TP 0.6i .B \-i \fIstring\fP Indentation mode. Possible arguments are "text" (indent text inside of box), "box" (indent box, not text inside of box), or "none" (throw away indentation). Arguments may be abbreviated. The default is to indent the box, but not the text. .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .TP 0.6i .B \-k \fIbool\fP Kill leading/trailing blank lines on removal. The value of .I bool can be specified as on, yes, true, 1, or t, all meaning yes, or off, no, false, 0, or f, which mean no. This is case\-insensitive. This option only takes effect in connection with .B \-r\fP. If set to yes, leading and trailing blank lines will be removed from the output. If set to no, the entire content of the former box is returned. The default is no, if both the top and the bottom part of the box are open, as is the case with most regional comments. If the box's design defines a top part or a bottom part, the default is yes. .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .TP 0.6i .B \-l (ell) List designs. Produces a listing of all available box designs in the config file, along with a sample box and information about it's creator. Also checks syntax of the entire config file. If used in connection with .B \-d\fP, displays detailed information about the specified design. .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .TP 0.6i .B \-m Mend box. This removes a (potentially broken) box as with .B \-r\fP, and redraws it afterwards. The mended box is drawn according to the options given. This may be important to know when it comes to restoring padding, identation, etc. for the mended box. Implies .B \-k false. .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .TP 0.6i .B \-p \fIstring\fP Padding. Specify padding in spaces around the input text block for all sides of the box. The argument string may not contain whitespace and must consist of a combination of the following characters, each followed by a number indicating the padding in spaces: .br .B a \- (all) give padding for all sides at once .br .B h \- (horiz) give padding for both horizontal sides .br .B v \- (vertical) give padding for both vertical sides .br .B b \- (bottom) give padding for bottom (south) side .br .B l \- (left) give padding for left (west) side .br .B t \- (top) give padding for top (north) side .br .B r \- (right) give padding for right (east) side .br Example: .B \-p a\fP4\fBt\fP2 would define the padding to be 4 characters on all sides, except for the top of the box, where the input text block will be only 2 lines away from the box. .br By default, unless specified otherwise in the config file, no padding is used. .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .TP 0.6i .B \-r Remove box. Removes an existing box instead of drawing it. Which design to use is detected automatically. In order to save time or in case the detection does not decide correctly, combine with .B \-d to specify the design. The default is to draw a new box. .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .TP 0.6i .B \-s \fIwidth\fBx\fPheight\fP Box size. This option specifies the desired box size in units of columns (for width) and lines (for height). If only a single number is given as argument, this number specifies the desired box width. A single number prefixed by 'x' specifies only the box height. The actual resulting box size may vary depending on the individual shape sizes of the chosen design. Also, other command line options may influence the box size (such as .B \-p\fP). .br By default, the smallest possible box is created around the text. .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .TP 0.6i .B \-t \fIstring\fP Tab handling. This option controls how tab characters in the input text are handled. The option string must always begin with a .I uint number indicating the distance between tab stops. It is important that this value be set correctly, or tabulator characters will upset your input text. The correct tab distance value depends on the settings used for the text you are processing. A common value is 8. .br Immediately following the tab distance, an optional character can be appended, telling .I boxes how to treat the leading tabs. The following options are available: .br .B e \- expand tabs into spaces .br .B k \- keep tabs as close to what they were as possible .br .B u \- unexpand tabs. This makes .I boxes turn as many spaces as possible into tabs. .br In order to maintain backwards compatibility, the .B \-t .I string can be just a number. In that case, .B e is assumed for tab handling, which removes all tabs and replaces them with spaces. The factory default for the .B \-t option is simply 8, which is just such a case. .br For example, you could specify .B \-t \fP4u in order to have your leading tabs unexpanded. In the box content, tabs are always converted into spaces. The tab distance in this example is 4. .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .TP 0.6i .B \-v Print out current version number. .\" ======================================================================= .SH CONFIGURATION FILES .I Boxes will use the configuration file specified on the command line (using .B \-f\fP). If no config file is specified on the command line, .I boxes will check for the BOXES environment variable, which may contain a filename to use. If BOXES is not set, .I boxes will try to read $HOME/.boxes and use it as a config file. Failing that, .I boxes will try to read the system\-wide config file (see FILES). .PP The syntax of .I boxes config files is described on the website (see below). They are quite self\-explanatory, though. .\" ======================================================================= .SH AVAILABILITY .I Boxes is available from its website at . The website also features a number of examples illustrating this manual page as well as more in\-depth documentation. .PP Check out .I vim(1) at ! .\" ======================================================================= .SH AUTHOR .I Boxes was made by Thomas Jensen . .br Please see the .I boxes website for a current email address. .\" ======================================================================= .SH VERSION This is .I boxes version --BVERSION--. .\" ======================================================================= .SH BUGS Although it is doing fine in most cases, imho the design autodetector needs some more work. .br Should you notice any other unspecified behavior, please tell the author! .\" ======================================================================= .SH ENVIRONMENT .I Boxes recognizes the following environment variables: .TP 1.0i HOME The user's home directory. .TP 1.0i BOXES Name of .I boxes configuration file, if different from ~/.boxes. .\" ======================================================================= .SH FILES .TP 1.0i $HOME/.boxes .I boxes configuration file .TP 1.0i --GLOBALCONF-- system\-wide configuration file .\" ======================================================================= .SH "SEE ALSO" .I tal(1) , .I vim(1) boxes-1.1.1/doc/boxes.10100644000175000001440000002614012040302150014340 0ustar tsjensenusers.\" @(#)boxes.1 1.1.1 10/19/12 .\" .\" $Id: boxes.1.in,v 1.10 2012/10/19 15:05:17 tsjensen Exp $ .\" .TH boxes 1 "October 19 2012" .UC 4 .SH NAME boxes \- text mode box and comment drawing filter .SH SYNOPSIS .B boxes [\-hlmrv] [\-a\ format] [\-d\ design] [\-f\ file] [\-i\ indent] [\-k\ bool] [\-p\ pad] [\-s\ size] [\-t\ tabopts] [infile [outfile]] .SH DESCRIPTION .I Boxes is a text filter which can draw any kind of box around its input text. Box design choices range from simple boxes to complex ASCII art. A box can also be removed and repaired, even if it has been badly damaged by editing of the text inside. Since boxes may be open on any side, .I boxes can also be used to create regional comments in any programming language. New box designs of all sorts can easily be added and shared by appending to a free format configuration file. .br .I boxes was originally intended to be used with the .I vim(1) text editor, but it can be tied to any text editor which supports filters, as well as called from the command line as a standalone tool. .\" ======================================================================= .SH OPTIONS Options offered by .I boxes are the following: .TP 0.6i .B \-a \fIstring\fP Alignment/positioning of text inside box. This option takes a format string argument which is read from left to right. The format string may not contain whitespace and must consist of one or more of the following components: .br .B h\fPx \- horizontal alignment of the input text block inside a potentially larger box. Possible values for .I x are .B l (ell, for left alignment), .B c (center), or .B r (right). This does not affect the justification of text lines within the input text block (use the .B j argument instead). .br .B v\fPx \- vertical alignment of the input text block inside a potentially larger box. Possible values for .I x are .B t (for top alignment), .B c (center), or .B b (bottom). .br .B j\fPx \- justification of lines within the input text block. Possible values for .I x are .B l (ell, for left justification), .B c (center), or .B r (right). This does not affect the alignment of the input text block itself within the box. Use the .B h and .B v arguments for input text block positioning. .br Short hand notations (can be combined with the above arguments): .br .B l (ell) \- short for .B h\fPl\fBv\fPc\fBj\fPl .br .B c \- short for .B h\fPc\fBv\fPc\fBj\fPc .br .B r \- short for .B h\fPr\fBv\fPc\fBj\fPr .br The factory default setting for .B \-a is .B h\fPl\fBv\fPt. .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .TP 0.6i .B \-c \fIstring\fP Command line design definition for simple cases. The argument of this option is the definition for the "west" (W) shape. The defined shape must consist of exactly one line, i.e. no multi\-line shapes are allowed. The .B \-c option is intended as a shortcut for those cases where simple regional comments are to be created, which only need a certain character or sequence of characters to be placed in front of every line. In such cases, it is much more convenient to simply specify .B \-c than to do a complete design definition in one's config file, where the only shape defined is the west shape. .br This option implies a .B \-d and does not access the config file. .B \-c may of course be used in conjunction with any of the other options. By default, .B \-c is not specified. .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .TP 0.6i .B \-d \fIstring\fP Design selection. The one argument of this option is the name of the design to use. .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .TP 0.6i .B \-f \fIstring\fP Use alternate config file. The one argument of this option is the name of a valid .I boxes config file, containing new and exciting designs! .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .TP 0.6i .B \-h Print usage information. .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .TP 0.6i .B \-i \fIstring\fP Indentation mode. Possible arguments are "text" (indent text inside of box), "box" (indent box, not text inside of box), or "none" (throw away indentation). Arguments may be abbreviated. The default is to indent the box, but not the text. .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .TP 0.6i .B \-k \fIbool\fP Kill leading/trailing blank lines on removal. The value of .I bool can be specified as on, yes, true, 1, or t, all meaning yes, or off, no, false, 0, or f, which mean no. This is case\-insensitive. This option only takes effect in connection with .B \-r\fP. If set to yes, leading and trailing blank lines will be removed from the output. If set to no, the entire content of the former box is returned. The default is no, if both the top and the bottom part of the box are open, as is the case with most regional comments. If the box's design defines a top part or a bottom part, the default is yes. .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .TP 0.6i .B \-l (ell) List designs. Produces a listing of all available box designs in the config file, along with a sample box and information about it's creator. Also checks syntax of the entire config file. If used in connection with .B \-d\fP, displays detailed information about the specified design. .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .TP 0.6i .B \-m Mend box. This removes a (potentially broken) box as with .B \-r\fP, and redraws it afterwards. The mended box is drawn according to the options given. This may be important to know when it comes to restoring padding, identation, etc. for the mended box. Implies .B \-k false. .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .TP 0.6i .B \-p \fIstring\fP Padding. Specify padding in spaces around the input text block for all sides of the box. The argument string may not contain whitespace and must consist of a combination of the following characters, each followed by a number indicating the padding in spaces: .br .B a \- (all) give padding for all sides at once .br .B h \- (horiz) give padding for both horizontal sides .br .B v \- (vertical) give padding for both vertical sides .br .B b \- (bottom) give padding for bottom (south) side .br .B l \- (left) give padding for left (west) side .br .B t \- (top) give padding for top (north) side .br .B r \- (right) give padding for right (east) side .br Example: .B \-p a\fP4\fBt\fP2 would define the padding to be 4 characters on all sides, except for the top of the box, where the input text block will be only 2 lines away from the box. .br By default, unless specified otherwise in the config file, no padding is used. .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .TP 0.6i .B \-r Remove box. Removes an existing box instead of drawing it. Which design to use is detected automatically. In order to save time or in case the detection does not decide correctly, combine with .B \-d to specify the design. The default is to draw a new box. .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .TP 0.6i .B \-s \fIwidth\fBx\fPheight\fP Box size. This option specifies the desired box size in units of columns (for width) and lines (for height). If only a single number is given as argument, this number specifies the desired box width. A single number prefixed by 'x' specifies only the box height. The actual resulting box size may vary depending on the individual shape sizes of the chosen design. Also, other command line options may influence the box size (such as .B \-p\fP). .br By default, the smallest possible box is created around the text. .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .TP 0.6i .B \-t \fIstring\fP Tab handling. This option controls how tab characters in the input text are handled. The option string must always begin with a .I uint number indicating the distance between tab stops. It is important that this value be set correctly, or tabulator characters will upset your input text. The correct tab distance value depends on the settings used for the text you are processing. A common value is 8. .br Immediately following the tab distance, an optional character can be appended, telling .I boxes how to treat the leading tabs. The following options are available: .br .B e \- expand tabs into spaces .br .B k \- keep tabs as close to what they were as possible .br .B u \- unexpand tabs. This makes .I boxes turn as many spaces as possible into tabs. .br In order to maintain backwards compatibility, the .B \-t .I string can be just a number. In that case, .B e is assumed for tab handling, which removes all tabs and replaces them with spaces. The factory default for the .B \-t option is simply 8, which is just such a case. .br For example, you could specify .B \-t \fP4u in order to have your leading tabs unexpanded. In the box content, tabs are always converted into spaces. The tab distance in this example is 4. .\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .TP 0.6i .B \-v Print out current version number. .\" ======================================================================= .SH CONFIGURATION FILES .I Boxes will use the configuration file specified on the command line (using .B \-f\fP). If no config file is specified on the command line, .I boxes will check for the BOXES environment variable, which may contain a filename to use. If BOXES is not set, .I boxes will try to read $HOME/.boxes and use it as a config file. Failing that, .I boxes will try to read the system\-wide config file (see FILES). .PP The syntax of .I boxes config files is described on the website (see below). They are quite self\-explanatory, though. .\" ======================================================================= .SH AVAILABILITY .I Boxes is available from its website at . The website also features a number of examples illustrating this manual page as well as more in\-depth documentation. .PP Check out .I vim(1) at ! .\" ======================================================================= .SH AUTHOR .I Boxes was made by Thomas Jensen . .br Please see the .I boxes website for a current email address. .\" ======================================================================= .SH VERSION This is .I boxes version 1.1.1. .\" ======================================================================= .SH BUGS Although it is doing fine in most cases, imho the design autodetector needs some more work. .br Should you notice any other unspecified behavior, please tell the author! .\" ======================================================================= .SH ENVIRONMENT .I Boxes recognizes the following environment variables: .TP 1.0i HOME The user's home directory. .TP 1.0i BOXES Name of .I boxes configuration file, if different from ~/.boxes. .\" ======================================================================= .SH FILES .TP 1.0i $HOME/.boxes .I boxes configuration file .TP 1.0i /usr/share/boxes system\-wide configuration file .\" ======================================================================= .SH "SEE ALSO" .I tal(1) , .I vim(1) boxes-1.1.1/src/0040755000175000001440000000000012040315762013175 5ustar tsjensenusersboxes-1.1.1/src/misc/0040755000175000001440000000000010454257120014130 5ustar tsjensenusersboxes-1.1.1/src/misc/getopt.c0100644000175000001440000007465607064260172015621 0ustar tsjensenusers/* Getopt for GNU. NOTE: getopt is now part of the C library, so if you don't know what "Keep this file name-space clean" means, talk to drepper@gnu.org before changing it! Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98 Free Software Foundation, Inc. NOTE: The canonical source of this file is maintained with the GNU C Library. Bugs can be reported to bug-glibc@gnu.org. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* This tells Alpha OSF/1 not to define a getopt prototype in . Ditto for AIX 3.2 and . */ #ifndef _NO_PROTO # define _NO_PROTO #endif #ifdef HAVE_CONFIG_H # include #endif #if !defined __STDC__ || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ # ifndef const # define const # endif #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 # include # if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION # define ELIDE_CODE # endif #endif #ifndef ELIDE_CODE /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ /* Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting prototypes for getopt. */ # include # include #endif /* GNU C library. */ #ifdef VMS # include # if HAVE_STRING_H - 0 # include # endif #endif #ifndef _ /* This is for other GNU distributions with internationalized messages. When compiling libc, the _ macro is predefined. */ # ifdef HAVE_LIBINTL_H # include # define _(msgid) gettext (msgid) # else # define _(msgid) (msgid) # endif #endif /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user to intersperse the options with the other arguments. As `getopt' works, it permutes the elements of ARGV so that, when it is done, all the options precede everything else. Thus all application programs are extended to handle flexible argument order. Setting the environment variable POSIXLY_CORRECT disables permutation. Then the behavior is completely standard. GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ #include "getopt.h" /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ char * optarg = NULL; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ /* 1003.2 says this must be 1 before any call. */ int optind = 1; /* Formerly, initialization of getopt depended on optind==0, which causes problems with re-calling getopt as programs generally don't know that. */ int __getopt_initialized = 0; /* The next char to be scanned in the option-element in which the last option character we returned was found. This allows us to pick up the scan where we left off. If this is zero, or a null string, it means resume the scan by advancing to the next ARGV-element. */ static char *nextchar; /* Callers store zero here to inhibit the error message for unrecognized options. */ int opterr = 1; /* Set to an option character which was unrecognized. This must be initialized on some systems to avoid linking in the system's own getopt implementation. */ int optopt = '?'; /* Describe how to deal with options that follow non-option ARGV-elements. If the caller did not specify anything, the default is REQUIRE_ORDER if the environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise. REQUIRE_ORDER means don't recognize them as options; stop option processing when the first non-option is seen. This is what Unix does. This mode of operation is selected by either setting the environment variable POSIXLY_CORRECT, or using `+' as the first character of the list of option characters. PERMUTE is the default. We permute the contents of ARGV as we scan, so that eventually all the non-options are at the end. This allows options to be given in any order, even with programs that were not written to expect this. RETURN_IN_ORDER is an option available to programs that were written to expect options and other ARGV-elements in any order and that care about the ordering of the two. We describe each non-option ARGV-element as if it were the argument of an option with character code 1. Using `-' as the first character of the list of option characters selects this mode of operation. The special argument `--' forces an end of option-scanning regardless of the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return -1 with `optind' != ARGC. */ static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; /* Value of POSIXLY_CORRECT environment variable. */ static char *posixly_correct; #ifdef __GNU_LIBRARY__ /* We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can cause trouble. On some systems, it contains special magic macros that don't work in GCC. */ # include # define my_index strchr #else /* Avoid depending on library functions or files whose names are inconsistent. */ #ifndef getenv extern char *getenv (); #endif #ifndef strncmp extern int strncmp (); #endif static char * my_index (str, chr) const char *str; int chr; { while (*str) { if (*str == chr) return (char *) str; str++; } return 0; } /* If using GCC, we can safely declare strlen this way. If not using GCC, it is ok not to declare it. */ #ifdef __GNUC__ /* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. That was relevant to code that was here before. */ # if (!defined __STDC__ || !__STDC__) && !defined strlen /* gcc with -traditional declares the built-in strlen to return int, and has done so at least since version 2.4.5. -- rms. */ extern int strlen (const char *); # endif /* not __STDC__ */ #endif /* __GNUC__ */ #endif /* not __GNU_LIBRARY__ */ /* Handle permutation of arguments. */ /* Describe the part of ARGV that contains non-options that have been skipped. `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is the index after the last of them. */ static int first_nonopt; static int last_nonopt; #ifdef _LIBC /* Bash 2.0 gives us an environment variable containing flags indicating ARGV elements that should not be considered arguments. */ /* Defined in getopt_init.c */ extern char *__getopt_nonoption_flags; static int nonoption_flags_max_len; static int nonoption_flags_len; static int original_argc; static char *const *original_argv; /* Make sure the environment variable bash 2.0 puts in the environment is valid for the getopt call we must make sure that the ARGV passed to getopt is that one passed to the process. */ static void __attribute__ ((unused)) store_args_and_env (int argc, char *const *argv) { /* XXX This is no good solution. We should rather copy the args so that we can compare them later. But we must not use malloc(3). */ original_argc = argc; original_argv = argv; } # ifdef text_set_element text_set_element (__libc_subinit, store_args_and_env); # endif /* text_set_element */ # define SWAP_FLAGS(ch1, ch2) \ if (nonoption_flags_len > 0) \ { \ char __tmp = __getopt_nonoption_flags[ch1]; \ __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ __getopt_nonoption_flags[ch2] = __tmp; \ } #else /* !_LIBC */ # define SWAP_FLAGS(ch1, ch2) #endif /* _LIBC */ /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) which contains all the non-options that have been skipped so far. The other is elements [last_nonopt,optind), which contains all the options processed since those non-options were skipped. `first_nonopt' and `last_nonopt' are relocated so that they describe the new indices of the non-options in ARGV after they are moved. */ #if defined __STDC__ && __STDC__ static void exchange (char **); #endif static void exchange (argv) char **argv; { int bottom = first_nonopt; int middle = last_nonopt; int top = optind; char *tem; /* Exchange the shorter segment with the far end of the longer segment. That puts the shorter segment into the right place. It leaves the longer segment in the right place overall, but it consists of two parts that need to be swapped next. */ #ifdef _LIBC /* First make sure the handling of the `__getopt_nonoption_flags' string can work normally. Our top argument must be in the range of the string. */ if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) { /* We must extend the array. The user plays games with us and presents new arguments. */ char *new_str = malloc (top + 1); if (new_str == NULL) nonoption_flags_len = nonoption_flags_max_len = 0; else { memset (__mempcpy (new_str, __getopt_nonoption_flags, nonoption_flags_max_len), '\0', top + 1 - nonoption_flags_max_len); nonoption_flags_max_len = top + 1; __getopt_nonoption_flags = new_str; } } #endif while (top > middle && middle > bottom) { if (top - middle > middle - bottom) { /* Bottom segment is the short one. */ int len = middle - bottom; register int i; /* Swap it with the top part of the top segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[top - (middle - bottom) + i]; argv[top - (middle - bottom) + i] = tem; SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); } /* Exclude the moved bottom segment from further swapping. */ top -= len; } else { /* Top segment is the short one. */ int len = top - middle; register int i; /* Swap it with the bottom part of the bottom segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[middle + i]; argv[middle + i] = tem; SWAP_FLAGS (bottom + i, middle + i); } /* Exclude the moved top segment from further swapping. */ bottom += len; } } /* Update records for the slots the non-options now occupy. */ first_nonopt += (optind - last_nonopt); last_nonopt = optind; } /* Initialize the internal data when the first call is made. */ #if defined __STDC__ && __STDC__ static const char *_getopt_initialize (int, char *const *, const char *); #endif static const char * _getopt_initialize (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { /* Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped non-option ARGV-elements is empty. */ first_nonopt = last_nonopt = optind; nextchar = NULL; posixly_correct = getenv ("POSIXLY_CORRECT"); /* Determine how to handle the ordering of options and nonoptions. */ if (optstring[0] == '-') { ordering = RETURN_IN_ORDER; ++optstring; } else if (optstring[0] == '+') { ordering = REQUIRE_ORDER; ++optstring; } else if (posixly_correct != NULL) ordering = REQUIRE_ORDER; else ordering = PERMUTE; #ifdef _LIBC if (posixly_correct == NULL && argc == original_argc && argv == original_argv) { if (nonoption_flags_max_len == 0) { if (__getopt_nonoption_flags == NULL || __getopt_nonoption_flags[0] == '\0') nonoption_flags_max_len = -1; else { const char *orig_str = __getopt_nonoption_flags; int len = nonoption_flags_max_len = strlen (orig_str); if (nonoption_flags_max_len < argc) nonoption_flags_max_len = argc; __getopt_nonoption_flags = (char *) malloc (nonoption_flags_max_len); if (__getopt_nonoption_flags == NULL) nonoption_flags_max_len = -1; else memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), '\0', nonoption_flags_max_len - len); } } nonoption_flags_len = nonoption_flags_max_len; } else nonoption_flags_len = 0; #endif return optstring; } /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option element. The characters of this element (aside from the initial '-') are option characters. If `getopt' is called repeatedly, it returns successively each of the option characters from each of the option elements. If `getopt' finds another option character, it returns that character, updating `optind' and `nextchar' so that the next call to `getopt' can resume the scan with the following option character or ARGV-element. If there are no more option characters, `getopt' returns -1. Then `optind' is the index in ARGV of the first ARGV-element that is not an option. (The ARGV-elements have been permuted so that those that are not options now come last.) OPTSTRING is a string containing the legitimate option characters. If an option character is seen that is not listed in OPTSTRING, return '?' after printing an error message. If you set `opterr' to zero, the error message is suppressed but we still return '?'. If a char in OPTSTRING is followed by a colon, that means it wants an arg, so the following text in the same ARGV-element, or the text of the following ARGV-element, is returned in `optarg'. Two colons mean an option that wants an optional arg; if there is text in the current ARGV-element, it is returned in `optarg', otherwise `optarg' is set to zero. If OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. Long-named options begin with `--' instead of `-'. Their names may be abbreviated as long as the abbreviation is unique or is an exact match for some defined option. If they have an argument, it follows the option name in the same ARGV-element, separated from the option name by a `=', or else the in next ARGV-element. When `getopt' finds a long-named option, it returns 0 if that option's `flag' field is nonzero, the value of the option's `val' field if the `flag' field is zero. The elements of ARGV aren't really const, because we permute them. But we pretend they're const in the prototype to be compatible with other systems. LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero. LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a long-named option has been found by the most recent call. If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. */ int _getopt_internal (argc, argv, optstring, longopts, longind, long_only) int argc; char *const *argv; const char *optstring; const struct option *longopts; int *longind; int long_only; { optarg = NULL; if (optind == 0 || !__getopt_initialized) { if (optind == 0) optind = 1; /* Don't scan ARGV[0], the program name. */ optstring = _getopt_initialize (argc, argv, optstring); __getopt_initialized = 1; } /* Test whether ARGV[optind] points to a non-option argument. Either it does not have option syntax, or there is an environment flag from the shell indicating it is not an option. The later information is only used when the used in the GNU libc. */ #ifdef _LIBC # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ || (optind < nonoption_flags_len \ && __getopt_nonoption_flags[optind] == '1')) #else # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') #endif if (nextchar == NULL || *nextchar == '\0') { /* Advance to the next ARGV-element. */ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been moved back by the user (who may also have changed the arguments). */ if (last_nonopt > optind) last_nonopt = optind; if (first_nonopt > optind) first_nonopt = optind; if (ordering == PERMUTE) { /* If we have just processed some options following some non-options, exchange them so that the options come first. */ if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (last_nonopt != optind) first_nonopt = optind; /* Skip any additional non-options and extend the range of non-options previously skipped. */ while (optind < argc && NONOPTION_P) optind++; last_nonopt = optind; } /* The special ARGV-element `--' means premature end of options. Skip it like a null option, then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ if (optind != argc && !strcmp (argv[optind], "--")) { optind++; if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (first_nonopt == last_nonopt) first_nonopt = optind; last_nonopt = argc; optind = argc; } /* If we have done all the ARGV-elements, stop the scan and back over any non-options that we skipped and permuted. */ if (optind == argc) { /* Set the next-arg-index to point at the non-options that we previously skipped, so the caller will digest them. */ if (first_nonopt != last_nonopt) optind = first_nonopt; return -1; } /* If we have come to a non-option and did not permute it, either stop the scan or describe it to the caller and pass it by. */ if (NONOPTION_P) { if (ordering == REQUIRE_ORDER) return -1; optarg = argv[optind++]; return 1; } /* We have found another option-ARGV-element. Skip the initial punctuation. */ nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-')); } /* Decode the current option-ARGV-element. */ /* Check whether the ARGV-element is a long option. If long_only and the ARGV-element has the form "-f", where f is a valid short option, don't consider it an abbreviated form of a long option that starts with f. Otherwise there would be no way to give the -f short option. On the other hand, if there's a long option "fubar" and the ARGV-element is "-fu", do consider that an abbreviation of the long option, just like "--fu", and not "-f" with arg "u". This distinction seems to be the most useful approach. */ if (longopts != NULL && (argv[optind][1] == '-' || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = -1; int option_index; for (nameend = nextchar; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == (unsigned int) strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (opterr) fprintf (stderr, _("%s: option `%s' is ambiguous\n"), argv[0], argv[optind]); nextchar += strlen (nextchar); optind++; optopt = 0; return '?'; } if (pfound != NULL) { option_index = indfound; optind++; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) { optarg = nameend + 1; } else { if (opterr) if (argv[optind - 1][1] == '-') /* --option */ fprintf (stderr, _("%s: option `--%s' doesn't allow an argument\n"), argv[0], pfound->name); else /* +option or -option */ fprintf (stderr, _("%s: option `%c%s' doesn't allow an argument\n"), argv[0], argv[optind - 1][0], pfound->name); nextchar += strlen (nextchar); optopt = pfound->val; return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (opterr) fprintf (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); nextchar += strlen (nextchar); optopt = pfound->val; return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } /* Can't find it as a long option. If this is not getopt_long_only, or the option starts with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a short option. */ if (!long_only || argv[optind][1] == '-' || my_index (optstring, *nextchar) == NULL) { if (opterr) { if (argv[optind][1] == '-') /* --option */ fprintf (stderr, _("%s: unrecognized option `--%s'\n"), argv[0], nextchar); else /* +option or -option */ fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), argv[0], argv[optind][0], nextchar); } nextchar = (char *) ""; optind++; optopt = 0; return '?'; } } /* Look at and handle the next short option-character. */ { char c = *nextchar++; char *temp = my_index (optstring, c); /* Increment `optind' when we start to process its last character. */ if (*nextchar == '\0') ++optind; if (temp == NULL || c == ':') { if (opterr) { if (posixly_correct) /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], c); else fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c); } optopt = c; return '?'; } /* Convenience. Treat POSIX -W foo same as long option --foo */ if (temp[0] == 'W' && temp[1] == ';') { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = 0; int option_index; /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (opterr) { /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; return c; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; /* optarg is now the argument, see if it's in the table of longopts. */ for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (opterr) fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), argv[0], argv[optind]); nextchar += strlen (nextchar); optind++; return '?'; } if (pfound != NULL) { option_index = indfound; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (opterr) fprintf (stderr, _("\ %s: option `-W %s' doesn't allow an argument\n"), argv[0], pfound->name); nextchar += strlen (nextchar); return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (opterr) fprintf (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); nextchar += strlen (nextchar); return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } nextchar = NULL; return 'W'; /* Let the application handle it. */ } if (temp[1] == ':') { if (temp[2] == ':') { /* This is an option that accepts an argument optionally. */ if (*nextchar != '\0') { optarg = nextchar; optind++; } else optarg = NULL; nextchar = NULL; } else { /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (opterr) { /* 1003.2 specifies the format of this message. */ fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; nextchar = NULL; } } return c; } } int getopt (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { return _getopt_internal (argc, argv, optstring, (const struct option *) 0, (int *) 0, 0); } #endif /* Not ELIDE_CODE. */ #ifdef TEST /* Compile with -DTEST to make an executable for use in testing the above definition of `getopt'. */ int main (argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; c = getopt (argc, argv, "abc:d:0123456789"); if (c == -1) break; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ boxes-1.1.1/src/misc/getopt.h0100644000175000001440000000770607064260124015613 0ustar tsjensenusers/* Declarations for getopt. Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc. NOTE: The canonical source of this file is maintained with the GNU C Library. Bugs can be reported to bug-glibc@gnu.org. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _GETOPT_H #define _GETOPT_H 1 /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ char * optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ int optind; /* Callers store zero here to inhibit the error message `getopt' prints for unrecognized options. */ int opterr; /* Set to an option character which was unrecognized. */ int optopt; /* Describe the long-named options requested by the application. The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector of `struct option' terminated by an element containing a name which is zero. The field `has_arg' is: no_argument (or 0) if the option does not take an argument, required_argument (or 1) if the option requires an argument, optional_argument (or 2) if the option takes an optional argument. If the field `flag' is not NULL, it points to a variable that is set to the value given in the field `val' when the option is found, but left unchanged if the option is not found. To have a long-named option do something other than set an `int' to a compiled-in constant, such as set a value from `optarg', set the option's `flag' field to zero and its `val' field to a nonzero value (the equivalent single-letter option character, if there is one). For long options that have a zero `flag' field, `getopt' returns the contents of the `val' field. */ struct option { #if defined (__STDC__) && __STDC__ const char *name; #else char *name; #endif /* has_arg can't be an enum because some compilers complain about type mismatches in all the code that assumes it is an int. */ int has_arg; int *flag; int val; }; /* Names for the values of the `has_arg' field of `struct option'. */ #define no_argument 0 #define required_argument 1 #define optional_argument 2 extern int getopt_long (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind); extern int getopt_long_only (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind); /* Internal only. Users should not call this directly. */ extern int _getopt_internal (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind, int long_only); #endif /* getopt.h */ boxes-1.1.1/src/Makefile0100644000175000001440000001433310460473631014642 0ustar tsjensenusers# # File: Makefile # Creation: March 18, 1999 (Thursday, 15:10h) # Author: Copyright (C) 1999 Thomas Jensen # Version: $Id: Makefile,v 1.19 2006/07/22 19:07:21 tsjensen Exp $ # Format: GNU make # Web Site: http://boxes.thomasjensen.com/ # Platforms: sparc/Solaris 2.6 and others # Purpose: Makefile for boxes, the box drawing program # # Remarks: o This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # o This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # o You should have received a copy of the GNU General Public # License along with this program; if not, write to the Free # Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, # MA 02111-1307 USA # # Revision History: # # $Log: Makefile,v $ # Revision 1.19 2006/07/22 19:07:21 tsjensen # The file boxes.h is now managed by the top level Makefile only # Added rcslocks target to check lock status # Small usability enhancements # # Revision 1.18 2006/07/12 05:32:10 tsjensen # Updated email and web addresses in comment header # # Revision 1.17 2000-03-17 15:51:43-08 tsjensen # Added Makefile.Win32 and misc/* to snap generation commands # # Revision 1.16 1999/11/08 10:55:13 tsjensen # Moved config.h into ORIG_HDRCL group, so it appears in the change log Web # page # # Revision 1.15 1999/08/21 23:35:44 tsjensen # boxes.h is now generated from boxes.h.in by top level Makefile # Added -Wall -W to CFLAGS and removed .c.o rule # # Revision 1.14 1999/08/21 16:10:41 tsjensen # Removed case insensitivity option (-i) from flex call (-> lexer.l) # # Revision 1.13 1999/08/13 23:55:03 tsjensen # Given regexp stuff its own Makefile in regexp. # Major Makefile overhaul, maily implementation of new directory structure # and consolidation of file macros # Use more GNU make features # # Revision 1.12 1999/07/20 18:49:58 tsjensen # Added GNU GPL disclaimer # Now evaluating date command from SNAPFILE only once # Changed order of files in snapshot archive (who cares) # # Revision 1.11 1999/07/12 18:28:53 tsjensen # Removed --yacc option from bison call # Added logpage target to generate the chronologically sorted global change # log in HTML format. This requires a Perl script (create_changelog.pl). # Added config.h to dependencies and stuff # Removed special targets for yacc and lex files. Thanks to Andreas Heiduk, # it is now possible to compile all files with -W -Wall and no extra # defines. # Moved regexp library to a subdirectory regexp # Some modifications on the source file macros which now differentiate # between files which are listed in the HTML change log and files which # aren't. # # Revision 1.10 1999/07/02 11:50:35 tsjensen # Added parser.h header file for lexer-parser communication # Moved from yacc to GNU "bison --yacc" # No longer linking with flex library # Activated -Wall -W for parser.y # Removed -DYY_NO_UNPUT from lexer compilation (now done via file option) # # Revision 1.1 1999/03/18 15:10:41 tsjensen # Initial revision #____________________________________________________________________________ #============================================================================ LEX = flex YACC = bison CC = gcc CFLAGS = -ansi -I. -Iregexp -Wall -W $(CFLAGS_ADDTL) LDFLAGS = -Lregexp GEN_HDR = parser.h GEN_SRC = parser.c lex.yy.c GEN_FILES = $(GEN_SRC) $(GEN_HDR) ORIG_HDRCL = boxes.h.in config.h ORIG_HDR = $(ORIG_HDRCL) lexer.h tools.h shape.h generate.h remove.h ORIG_GEN = lexer.l parser.y ORIG_NORM = boxes.c tools.c shape.c generate.c remove.c ORIG_SRC = $(ORIG_GEN) $(ORIG_NORM) ORIG_FILES = $(ORIG_SRC) $(ORIG_HDR) OTH_FILES = Makefile ALL_CL = $(ORIG_SRC) $(ORIG_HDRCL) $(OTH_FILES) ALL_FILES = $(ORIG_FILES) $(GEN_FILES) $(OTH_FILES) boxes.h ALL_OBJ = $(GEN_SRC:.c=.o) $(ORIG_NORM:.c=.o) build: $(MAKE) CFLAGS_ADDTL=-O boxes strip boxes debug: $(MAKE) CFLAGS_ADDTL=-g boxes boxes: $(ALL_OBJ) $(MAKE) -C regexp CC=$(CC) libregexp.a $(CC) $(LDFLAGS) $(ALL_OBJ) -o boxes -lregexp boxes.h: @echo File boxes.h not found or not current. Please run make in the parent directory. @exit 1 parser.c parser.h: parser.y boxes.h regexp/regexp.h $(YACC) -o parser.c -d parser.y lex.yy.c: lexer.l boxes.h $(LEX) -t lexer.l > lexer.tmp.c echo '#include "config.h"' > lex.yy.c cat lexer.tmp.c >> lex.yy.c rm lexer.tmp.c boxes.o: boxes.c boxes.h regexp/regexp.h shape.h tools.h generate.h remove.h config.h tools.o: tools.c tools.h boxes.h shape.h config.h shape.o: shape.c shape.h boxes.h config.h tools.h generate.o: generate.c generate.h boxes.h shape.h tools.h config.h remove.o: remove.c remove.h boxes.h shape.h tools.h config.h lex.yy.o: lex.yy.c parser.h tools.h shape.h lexer.h config.h parser.o: parser.c parser.h tools.h shape.h lexer.h config.h snap: $(ALL_FILES) @if [ -z "$(SNAPFILE)" ] ; then echo "make snap must be run from the parent directory" ; exit 1 ; fi mkdir $(SNAPFILE)/src cp $(ALL_FILES) $(SNAPFILE)/src cp Makefile.Win32 $(SNAPFILE)/src mkdir $(SNAPFILE)/src/misc cp misc/getopt.c misc/getopt.h $(SNAPFILE)/src/misc touch $(patsubst %,$(SNAPFILE)/src/%,$(GEN_FILES)) $(MAKE) -C regexp SNAPFILE=../$(SNAPFILE) snap rcstest: -for i in $(ORIG_FILES) $(OTH_FILES) ; do rcsdiff $$i ; done $(MAKE) -C regexp rcstest rcslocks: @rlog -L -R $(ORIG_FILES) $(OTH_FILES) | sed -e 's/^/ - src\//' @$(MAKE) -C regexp rcslocks logpage: $(ALL_CL) @echo $(ALL_CL) $(shell $(MAKE) -C regexp -s logpage) clean: rm -f $(ALL_OBJ) rm -f $(GEN_FILES) rm -f core boxes $(MAKE) -C regexp clean love: @echo "Not in front of the kids, honey!" #EOF boxes-1.1.1/src/remove.c0100644000175000001440000011555410460475145014654 0ustar tsjensenusers/* * File: remove.c * Project Main: boxes.c * Date created: June 23, 1999 (Wednesday, 20:59h) * Author: Copyright (C) 1999 Thomas Jensen * Version: $Id: remove.c,v 1.8 2006/07/22 19:19:26 tsjensen Exp $ * Language: ANSI C * World Wide Web: http://boxes.thomasjensen.com/ * Purpose: Box removal, i.e. the deletion of boxes * * Remarks: o This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * o This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * o You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * Revision History: * * $Log: remove.c,v $ * Revision 1.8 2006/07/22 19:19:26 tsjensen * Applied patch by Christoph Dreyer to support unexpansion of leading tabs * Added ability to retain existing tabs * * Revision 1.7 2006/07/12 05:28:58 tsjensen * Updated email and web addresses in comment header * Added trim_only flag to output_input() function, used for box mending * * Revision 1.6 1999-11-08 02:51:41-08 tsjensen * Bugfix: For non-empty left box sides, spaces belonging to "empty" shape * lines were not properly removed in some cases * * Revision 1.5 1999/11/07 17:46:26 tsjensen * Bugfix: Horizontal box parts were not correctly detected if the west box * side was empty (reported: Tobias Buchal) * Bugfix: boxes could hang in detect_horiz() due to goeast/west confusion * * Revision 1.4 1999/08/21 16:03:31 tsjensen * Bugfix: When matching vertical side shape lines, ignore empty shape lines * * Revision 1.3 1999/07/20 18:57:16 tsjensen * Added GNU GPL disclaimer * Does not kill leading/trailing blank lines anymore when !opt.killblank * Added include config.h * * Revision 1.2 1999/06/25 18:45:33 tsjensen * Added initialization of mmok to please compiler * Changed parameters of empty_side() calls to comply with new signature * * Revision 1.1 1999/06/23 19:14:53 tsjensen * Initial revision * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "config.h" #include #include #include #include "shape.h" #include "boxes.h" #include "tools.h" #include "remove.h" static const char rcsid_remove_c[] = "$Id: remove.c,v 1.8 2006/07/22 19:19:26 tsjensen Exp $"; static int best_match (const line_t *line, char **ws, char **we, char **es, char **ee) /* * Find positions of west and east box parts in line. * * line line to examine * ws etc. result parameters (west start, west end, east start, east end) * * RETURNS: > 0 a match was found (ws etc are set to indicate positions) * == 0 no match was found * < 0 internal error (out of memory) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { size_t numw = 0; /* number of shape lines on west side */ size_t nume = 0; /* number of shape lines on east side */ size_t j; /* counts number of lines of all shapes tested */ size_t k; /* line counter within shape */ int w; /* shape counter */ sentry_t *cs; /* current shape */ char *s; /* duplicate of current shape part */ char *p; /* position found by strstr */ size_t cq; /* current quality */ char *q; /* space check rover */ line_t chkline; /* for calls to empty_line() */ size_t quality; *ws = *we = *es = *ee = NULL; numw = opt.design->shape[WNW].height; numw += opt.design->shape[ W ].height; numw += opt.design->shape[WSW].height; nume = opt.design->shape[ENE].height; nume += opt.design->shape[ E ].height; nume += opt.design->shape[ESE].height; #ifdef DEBUG fprintf (stderr, "Number of WEST side shape lines: %d\n", numw); fprintf (stderr, "Number of EAST side shape lines: %d\n", nume); #endif /* * Find match for WEST side */ if (!empty_side (opt.design->shape, BLEF)) { quality = 0; cs = opt.design->shape + WNW; for (j=0,k=0,w=3; jheight) { k = 0; cs = opt.design->shape + west_side[--w]; } chkline.text = cs->chars[k]; chkline.len = cs->width; if (empty_line (&chkline) && !(quality==0 && j==numw-1)) continue; s = (char *) strdup (cs->chars[k]); if (s == NULL) { perror (PROJECT); return -1; } cq = cs->width; do { p = strstr (line->text, s); if (p) { q = p-1; while (q >= line->text) { if (*q-- != ' ') { p = NULL; break; } } if (p) break; } if (!p && cq) { if (*s == ' ') memmove (s, s+1, cq--); else if (s[cq-1] == ' ') s[--cq] = '\0'; else { cq = 0; break; } } } while (cq && !p); if (cq == 0) { BFREE (s); continue; } /* * If the current match is the best yet, adjust result values */ if (cq > quality) { quality = cq; *ws = p; *we = p + cq; } BFREE (s); } } /* * Find match for EAST side */ if (!empty_side (opt.design->shape, BRIG)) { quality = 0; cs = opt.design->shape + ENE; for (j=0,k=0,w=1; jheight) { k = 0; cs = opt.design->shape + east_side[++w]; } #ifdef DEBUG fprintf (stderr, "\nj %d, k %d, w %d, cs->chars[k] = \"%s\"\n", j, k, w, cs->chars[k]?cs->chars[k]:"(null)"); #endif chkline.text = cs->chars[k]; chkline.len = cs->width; if (empty_line (&chkline)) continue; s = (char *) strdup (cs->chars[k]); if (s == NULL) { perror (PROJECT); return -1; } cq = cs->width; do { p = my_strnrstr (line->text, s, cq, 0); if (p) { q = p + cq; while (*q) { if (*q++ != ' ') { p = NULL; break; } } if (p) break; } if (!p && cq) { if (*s == ' ') memmove (s, s+1, cq--); else if (s[cq-1] == ' ') s[--cq] = '\0'; else { cq = 0; break; } } } while (cq && !p); if (cq == 0) { BFREE (s); continue; } /* * If the current match is the best yet, adjust result values */ if (cq > quality) { quality = cq; *es = p; *ee = p + cq; } BFREE (s); } } return *ws || *es ? 1:0; } static int hmm (const int aside, const size_t follow, const char *p, const char *ecs, const int cnt) /* * (horizontal middle match) * * aside box part to check (BTOP or BBOT) * follow index of line number in shape spec to check * p current check position * ecs pointer to first char of east corner shape * cnt current shape to check (0 == leftmost middle shape) * * Recursive helper function for detect_horiz(), uses backtracking * * RETURNS: == 0 success * != 0 error * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { int cmp; sentry_t *cs; shape_t sh; int rc; #ifdef DEBUG fprintf (stderr, "hmm (%s, %d, \'%c\', \'%c\', %d)\n", aside==BTOP?"BTOP":"BBOT", follow, p[0], *ecs, cnt); #endif if (p > ecs) /* last shape tried was too long */ return 2; sh = leftmost (aside, cnt); if (sh == ANZ_SHAPES) return 1; cs = opt.design->shape + sh; cmp = strncmp (p, cs->chars[follow], cs->width); if (cmp == 0) { if (p+cs->width == ecs) { if (leftmost (aside, cnt+1) == ANZ_SHAPES) return 0; /* good! all clear, it matched */ else return 3; /* didn't use all shapes to do it */ } if (cs->elastic) { rc = hmm (aside, follow, p+cs->width, ecs, cnt); #ifdef DEBUG fprintf (stderr, "hmm returned %d\n", rc); #endif if (rc) { rc = hmm (aside, follow, p+cs->width, ecs, cnt+1); #ifdef DEBUG fprintf (stderr, "hmm returned %d\n", rc); #endif } } else { rc = hmm (aside, follow, p+cs->width, ecs, cnt+1); #ifdef DEBUG fprintf (stderr, "hmm returned %d\n", rc); #endif } if (rc == 0) return 0; /* we're on the way back */ else return 4; /* can't continue on this path */ } else { return 5; /* no match */ } } static int detect_horiz (const int aside, size_t *hstart, size_t *hend) /* * Detect which part of the input belongs to the top/bottom of the box * * aside part of box to detect (BTOP or BBOT) * hstart index of first line of detected box part (result) * hend index of first line following detected box part (result) * * We assume the horizontal parts of the box to be in one piece, i.e. no * blank lines inserted. Lines may be missing, though. Lines may not be * duplicated. They may be shifted left and right by inserting whitespace, * but whitespace which is part of the box must not have been deleted * (unless it's because an entire box side is empty). Box part lines may * even differ in length as long as each line is in itself a valid * horizontal box line. * * RETURNS: == 0 success (hstart & hend are set) * != 0 error * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { size_t follow; /* possible box line */ sentry_t *cs; /* current shape */ line_t *line; /* currently processed input line */ size_t lcnt; /* line counter */ char *p = NULL; /* middle line part scanner */ char *q; /* space check rover */ char *wcs = NULL; /* west corner shape position */ char *ecs = NULL; /* east corner shape position */ int mmok = 0; /* true if middle match was ok */ size_t mheight; /* regular height of box part */ int result_init = 0; /* true if hstart etc. was init. */ int nowside; /* true if west side is empty */ int goeast; /* no. of finds to ignore on right */ int gowest; /* set to request search start incr. */ *hstart = *hend = 0; nowside = empty_side (opt.design->shape, BLEF); mheight = opt.design->shape[sides[aside][0]].height; if (aside == BTOP) { follow = 0; line=input.lines; } else { follow = mheight - 1; line = input.lines + input.anz_lines - 1; } for (lcnt=0; lcnt= input.lines; ++lcnt) { goeast = gowest = 0; #ifdef DEBUG fprintf (stderr, "----- Processing line index %2d ----------" "-------------------------------------\n", aside == BTOP? lcnt: input.anz_lines - lcnt - 1); #endif do { /* * Look for west corner shape */ if (!goeast) { if (nowside) { wcs = NULL; if (gowest) { gowest = 0; if (*p == ' ' || *p == '\t') ++p; else break; } else { p = line->text; } } else { cs = opt.design->shape + sides[aside][aside==BTOP?0:SHAPES_PER_SIDE-1]; if (gowest) { gowest = 0; wcs = strstr (wcs+1, cs->chars[follow]); } else { wcs = strstr (line->text, cs->chars[follow]); } if (wcs) { for (q=wcs-1; q>=line->text; --q) { if (*q != ' ' && *q != '\t') break; } if (q >= line->text) wcs = NULL; } if (!wcs) break; p = wcs + cs->width; } } /* Now, wcs is either NULL (if west side is empty) */ /* or not NULL (if west side is not empty). In any case, p */ /* points to where we start searching for the east corner. */ #ifdef DEBUG if (wcs) fprintf (stderr, "West corner shape matched at " "position %d.\n", wcs - line->text); else fprintf (stderr, "West box side is empty.\n"); #endif /* * Look for east corner shape */ cs = opt.design->shape + sides[aside][aside==BTOP?SHAPES_PER_SIDE-1:0]; ecs = my_strnrstr (p, cs->chars[follow], cs->width, goeast); if (ecs) { for (q=ecs+cs->width; *q; ++q) { if (*q != ' ' && *q != '\t') break; } if (*q) ecs = NULL; } if (!ecs) { if (goeast == 0) break; else { goeast = 0; gowest = 1; continue; } } #ifdef DEBUG fprintf (stderr, "East corner shape matched at position %d.\n", ecs-line->text); #endif /* * Check if text between corner shapes is valid */ mmok = !hmm (aside, follow, p, ecs, 0); if (!mmok) ++goeast; #ifdef DEBUG fprintf (stderr, "Text between corner shapes is %s.\n", mmok? "VALID": "NOT valid"); #endif } while (!mmok); /* * Proceed to next line */ if (mmok) { /* match found */ if (!result_init) { result_init = 1; if (aside == BTOP) *hstart = lcnt; else *hend = (input.anz_lines - lcnt - 1) + 1; } if (aside == BTOP) *hend = lcnt + 1; else *hstart = input.anz_lines - lcnt - 1; } else { if (result_init) break; } wcs = NULL; ecs = NULL; p = NULL; mmok = 0; if (aside == BTOP) { ++follow; ++line; } else { --follow; --line; } } return result_init? 0: 1; } static design_t *detect_design() /* * Autodetect design used by box in input. * * This requires knowledge about ALL designs, so the entire config file had * to be parsed at some earlier time. * * RETURNS: != NULL success, pointer to detected design * == NULL on error * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { design_t *d = designs; /* ptr to currently tested design */ long hits; /* hit points of the current design */ long maxhits = 0; /* maximum no. of hits so far */ design_t *res = NULL; /* ptr to design with the most hits */ int dcnt; /* design loop counter */ shape_t scnt; /* shape loop counter */ size_t j, k; char *p; char *s; line_t shpln; /* a line which is part of a shape */ size_t a; int empty[ANZ_SIDES]; for (dcnt=0; dcntname); #endif hits = 0; for (j=0; jshape, j); #ifdef DEBUG fprintf (stderr, "Empty sides: TOP %d, LEFT %d, BOTTOM %d, RIGHT %d\n", empty[BTOP], empty[BLEF], empty[BBOT], empty[BRIG]); #endif for (scnt=0; scntshape[scnt].height; ++j) { shpln.text = d->shape[scnt].chars[j]; shpln.len = d->shape[scnt].width; if (empty_line (&shpln)) continue; for (s=shpln.text; *s==' ' || *s=='\t'; ++s); for (k=0; kshape[scnt].height; ++k) { a = k; if (scnt == SW) a += input.anz_lines - d->shape[scnt].height; if (a >= input.anz_lines) break; for (p=input.lines[a].text; *p==' '||*p=='\t'; ++p); if (strncmp (p, s, shpln.len-(s-shpln.text)) == 0) ++hits; } } #ifdef DEBUG fprintf (stderr, "After %s corner check:\t%ld hits.\n", shape_name[scnt], hits); #endif break; case NE: case SE: /* * Try and find east corner shapes. Every non-empty shape * line is searched for on every input line. A hit is * generated whenever a match is found. */ if (empty[BRIG] || (empty[BTOP] && scnt == NE) || (empty[BBOT] && scnt == SE)) break; for (j=0; jshape[scnt].height; ++j) { shpln.text = d->shape[scnt].chars[j]; shpln.len = d->shape[scnt].width; if (empty_line (&shpln)) continue; for (s = shpln.text + shpln.len -1; (*s==' ' || *s=='\t') && shpln.len; --s, --(shpln.len)); for (k=0; kshape[scnt].height; ++k) { a = k; if (scnt == SE) a += input.anz_lines - d->shape[scnt].height; if (a >= input.anz_lines) break; for (p=input.lines[a].text + input.lines[a].len -1; p>=input.lines[a].text && (*p==' ' || *p=='\t'); --p); p = p - shpln.len + 1; if (p < input.lines[a].text) continue; if (strncmp (p, shpln.text, shpln.len) == 0) ++hits; } } #ifdef DEBUG fprintf (stderr, "After %s corner check:\t%ld hits.\n", shape_name[scnt], hits); #endif break; default: if (isempty (d->shape+scnt)) continue; if ((scnt >= NNW && scnt <= NNE) || (scnt >= SSE && scnt <= SSW)) { /* * Try and find horizontal shapes between the box * corners. Every non-empty shape line is searched for * on every input line. Elastic shapes must occur * twice in an uninterrupted row to generate a hit. */ if ((scnt >= NNW && scnt <= NNE && empty[BTOP]) || (scnt >= SSE && scnt <= SSW && empty[BBOT])) { ++hits; break; /* horizontal box part is empty */ } for (j=0; jshape[scnt].height; ++j) { shpln.text = d->shape[scnt].chars[j]; shpln.len = d->shape[scnt].width; if (empty_line (&shpln)) continue; for (k=0; kshape[scnt].height; ++k) { a = k; if (scnt >= SSE && scnt <= SSW) a += input.anz_lines-d->shape[scnt].height; if (a >= input.anz_lines) break; for (p=input.lines[a].text; *p == ' ' || *p == '\t'; ++p); p += d->shape[NW].width; if (p-input.lines[a].text >= (long) input.lines[a].len) continue; p = strstr (p, shpln.text); if (p) { if (d->shape[scnt].elastic) { p += shpln.len; if (p-input.lines[a].text >= (long) input.lines[a].len) continue; if (!strncmp (p, shpln.text, shpln.len)) ++hits; } else { ++hits; } } } } } else if ((scnt >= ENE && scnt <= ESE) || (scnt >= WSW && scnt <= WNW)) { /* handle later */ break; } else { fprintf (stderr, "%s: internal error\n", PROJECT); return NULL; } #ifdef DEBUG fprintf (stderr, "After %s shape check:\t%ld hits.\n", shape_name[scnt], hits); #endif } } /* * Now iterate over all input lines except for potential top and * bottom box parts. Check if east and west line ends match a * non-empty shape line. If so, generate a hit. */ if (((empty[BTOP]? 0: d->shape[NW].height) + (empty[BBOT]? 0: d->shape[SW].height)) < input.anz_lines) { for (k = empty[BTOP]? 0: d->shape[NW].height; k < input.anz_lines -(empty[BBOT]? 0: d->shape[SW].height); ++k) { for (p=input.lines[k].text; *p==' ' || *p=='\t'; ++p); for (scnt=WSW; scnt<=WNW; ++scnt) { a = 0; if (isempty (d->shape + scnt)) continue; for (j=0; jshape[scnt].height; ++j) { shpln.text = d->shape[scnt].chars[j]; shpln.len = d->shape[scnt].width; if (empty_line (&shpln)) continue; for (s=shpln.text; *s==' ' || *s=='\t'; ++s); if (strncmp (p, s, shpln.len-(s-shpln.text)) == 0) { ++hits; a = 1; break; } } if (a) break; } for (scnt=ENE; scnt<=ESE; ++scnt) { a = 0; if (isempty (d->shape + scnt)) continue; for (j=0; jshape[scnt].height; ++j) { shpln.text = d->shape[scnt].chars[j]; shpln.len = d->shape[scnt].width; if (empty_line (&shpln)) continue; for (p=input.lines[k].text + input.lines[k].len -1; p>=input.lines[a].text && (*p==' ' || *p=='\t'); --p); for (s = shpln.text + shpln.len -1; (*s==' ' || *s=='\t') && shpln.len; --s, --(shpln.len)); p = p - shpln.len + 1; if (strncmp (p, shpln.text, shpln.len) == 0) { ++hits; a = 1; break; } } if (a) break; } } } #ifdef DEBUG fprintf (stderr, "After side checks:\t%ld hits.\n", hits); #endif if (hits > maxhits) { maxhits = hits; res = d; } } #ifdef DEBUG if (res) fprintf (stderr, "CHOOSING \"%s\" design (%ld hits).\n", res->name, maxhits); else fprintf (stderr, "NO DESIGN FOUND WITH EVEN ONE HIT!\n"); #endif return res; } int remove_box() /* * Remove box from input. * * RETURNS: == 0 success * != 0 error * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { size_t textstart = 0; /* index of 1st line of box body */ size_t textend = 0; /* index of 1st line of south side */ size_t boxstart = 0; /* index of 1st line of box */ size_t boxend = 0; /* index of 1st line trailing the box */ int m; /* true if a match was found */ size_t j; /* loop counter */ int did_something = 0; /* true if there was something to remove */ /* * If the user didn't specify a design to remove, autodetect it. * Since this requires knowledge of all available designs, the entire * config file had to be parsed (earlier). */ if (opt.design_choice_by_user == 0) { design_t *tmp = detect_design(); if (tmp) { opt.design = tmp; #ifdef DEBUG fprintf (stderr, "Design autodetection: Removing box of " "design \"%s\".\n", opt.design->name); #endif } else { fprintf (stderr, "%s: Box design autodetection failed. Use -d " "option.\n", PROJECT); return 1; } } /* * Make all lines the same length by adding trailing spaces (needed * for recognition). * Also append a number of spaces to ALL input lines. A greater number * takes more space and time, but enables the correct removal of boxes * whose east sides consist of lots of spaces (the given value). So we * add a number of spaces equal to the east side width. */ input.maxline += opt.design->shape[NE].width; for (j=0; jshape, BTOP)) { #ifdef DEBUG fprintf (stderr, "----> Top box side is empty: boxstart == textstart == 0.\n"); #endif } else { detect_horiz (BTOP, &boxstart, &textstart); #ifdef DEBUG fprintf (stderr, "----> First line of box is %d, ", boxstart); fprintf (stderr, "first line of box body (text) is %d.\n", textstart); #endif } /* * Phase 2: Find out how many lines belong to the bottom of the box */ if (empty_side (opt.design->shape, BBOT)) { textend = input.anz_lines; boxend = input.anz_lines; #ifdef DEBUG fprintf (stderr, "----> Bottom box side is empty: boxend == textend == %d.\n", input.anz_lines); #endif } else { textend = 0; boxend = 0; detect_horiz (BBOT, &textend, &boxend); if (textend == 0 && boxend == 0) { textend = input.anz_lines; boxend = input.anz_lines; } #ifdef DEBUG fprintf (stderr, "----> Last line of box body (text) is %d, ", textend-1); fprintf (stderr, "last line of box is %d.\n", boxend-1); #endif } /* * Phase 3: Iterate over body lines, removing box sides where applicable */ for (j=textstart; jshape[NW].width + opt.design->padding[BLEF]; for (c=0; c textstart) { #ifdef DEBUG fprintf (stderr, "Killing trailing blank line in box body.\n"); #endif --textend; } } if (textstart > boxstart) { for (j=boxstart; j textend) { for (j=textend; j input.maxline) input.maxline = input.lines[j].len; } memset (input.lines + input.anz_lines, 0, (BMAX (textstart - boxstart, 0) + BMAX (boxend - textend, 0)) * sizeof(line_t)); #ifdef DEBUG #if 0 for (j=0; j * Version: $Id: remove.h,v 1.3 2006/07/12 05:28:31 tsjensen Exp $ * Language: ANSI C * World Wide Web: http://boxes.thomasjensen.com/ * Purpose: Box removal, i.e. the deletion of boxes * * Remarks: o This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * o This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * o You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * Revision History: * * $Log: remove.h,v $ * Revision 1.3 2006/07/12 05:28:31 tsjensen * Updated email and web addresses in comment header * * Revision 1.2 1999-07-23 09:16:40-07 tsjensen * Added GNU GPL disclaimer * * Revision 1.1 1999/06/23 19:15:00 tsjensen * Initial revision * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef REMOVE_H #define REMOVE_H int remove_box(); void output_input(); #endif /*REMOVE_H*/ /*EOF*/ /* vim: set cindent sw=4: */ boxes-1.1.1/src/boxes.h.in0100644000175000001440000002260312040267214015071 0ustar tsjensenusers/* * File: boxes.h * Date created: March 18, 1999 (Thursday, 15:09h) * Author: Copyright (C) 1999 Thomas Jensen * Version: $Id: boxes.h.in,v 1.22 2006/07/22 19:15:52 tsjensen Exp $ * Language: ANSI C * World Wide Web: http://boxes.thomasjensen.com/ * Purpose: Project-wide globals and data structures * * Remarks: o This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * o This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * o You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * Revision History: * * $Log: boxes.h.in,v $ * Revision 1.22 2006/07/22 19:15:52 tsjensen * Fix: Renamed yylineno to tjlineno to enable compilation on certain * flexes (reported by Andreas Heiduk) * Added tabexp to opt_t * Added tabpos and tabpos_len to line_t for advanced tab handling * * Revision 1.21 2006/07/12 05:44:12 tsjensen * Updated email and web addresses in comment header * Added new member 'mend' to opt_t (for option -m, mend box) * * Revision 1.20 2000-04-01 10:28:18-08 tsjensen * Added cld member to command line option struct (-c option) * * Revision 1.19 2000/03/17 23:43:13 tsjensen * Added vim autocommand to set syntax highlighting to C * * Revision 1.18 1999/08/21 23:37:23 tsjensen * Renamed file from boxes.h to boxes.h.in * VERSION and GLOBALCONF values are now put in by top level Makefile * * Revision 1.17 1999/08/14 19:31:23 tsjensen * Incremented beta version number to 5 * Added maxshapeheight member to design_t struct * * Revision 1.16 1999/07/20 18:48:46 tsjensen * Added GNU GPL disclaimer * Updated beta version number :-) * Added killblank member to global options * * Revision 1.15 1999/06/30 12:19:12 tsjensen * Removed DEF_DESIGN macro, because it now defaults to first design * Removed some porting code, hoping for autoconf future * Added PARSER_DEBUG and LEXER_DEBUG macros * * Revision 1.14 1999/06/25 18:51:04 tsjensen * Removed empty_side() prototype (now in shape.h) * Added indentmode and justify members to command line options struct * * Revision 1.13 1999/06/23 19:21:15 tsjensen * Now exporting anz_designs, input, and empty_side() * Added #include regexp.h back * * Revision 1.12 1999/06/23 12:33:49 tsjensen * Moved some data structures and macros related to shapes to shape.h * Added #ifdef DEBUG around __TJ() macro for convenience * * Revision 1.11 1999/06/22 12:01:24 tsjensen * Added DEF_DESIGN (default design name) * Added opt_t and opt global variable from boxes.c * Moved BFREE macro and yyerror() and empty_line() prototypes to tools.h * Added LINE_MAX and MAX_TABSTOP macros from boxes.c * Added #define DEBUG and REGEXP_DEBUG. This will centrally activate * debugging. * * Revision 1.10 1999/06/20 14:19:31 tsjensen * Added padding member to design struct * * Revision 1.9 1999/06/17 19:08:50 tsjensen * Removed #pragma ident "string" * Changed VERSION to 1.0 beta * Added line_t and empty_line() prototype * * Revision 1.8 1999/06/14 12:11:54 tsjensen * Added struct members for regexp reversion code * Renamed current_reprule to current_rule, now used for both directions * * Revision 1.6 1999/04/09 13:32:55 tsjensen * Removed code related to OFFSET blocks (obsolete) * * Revision 1.5 1999/04/04 16:10:51 tsjensen * Added some flags to design structure * Move default settings here from boxes.c * * Revision 1.4 1999/03/31 17:34:43 tsjensen * ... still programming ... * Added minwidth and minheight to design structure * * Revision 1.3 1999/03/30 09:36:58 tsjensen * ... still programming ... * It drew a correct box for the first time! * * Revision 1.1 1999/03/18 15:09:34 tsjensen * Initial revision * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef BOXES_H #define BOXES_H /* #define DEBUG */ /* #define REGEXP_DEBUG */ /* #define PARSER_DEBUG */ /* #define LEXER_DEBUG */ #include "regexp.h" #define PROJECT "boxes" /* name of program */ #define VERSION "--BVERSION--" /* current release of project */ #define GLOBALCONF "--GLOBALCONF--" /* name of system-wide config file */ /* * default settings of all kinds (THIS PARAGRAPH MAY BE EDITED) */ #define DEF_TABSTOP 8 /* default tab stop distance (part of -t) */ #define DEF_INDENTMODE 'b' /* indent box, not text by default */ /* * max. allowed tab stop distance */ #define MAX_TABSTOP 16 /* * max. supported line length * This is how many characters of a line will be read. Anything beyond * will be discarded. The line feed character at the end does not count. * (This should have been done via sysconf(), but I didn't do it in order * to ease porting to non-unix platforms.) */ #if defined(LINE_MAX) && (LINE_MAX < 1024) #undef LINE_MAX #endif #ifndef LINE_MAX #define LINE_MAX 2048 #endif #ifdef DEBUG #define __TJ(s) fprintf (stderr, s); #else #define __TJ(s) /**/ #endif #define BTOP 0 /* for use with sides */ #define BRIG 1 #define BBOT 2 #define BLEF 3 typedef struct { char *search; char *repstr; regexp *prog; /* compiled search pattern */ int line; /* line of definition in config file */ char mode; /* 'g' or 'o' */ } reprule_t; typedef struct { char *name; char *author; char *created; /* date created, free format */ char *revision; /* revision number of design */ char *revdate; /* date of current revision */ char *sample; char indentmode; /* 'b', 't', or 'n' */ sentry_t shape[ANZ_SHAPES]; size_t maxshapeheight; /* height of highest shape in design */ size_t minwidth; size_t minheight; int padding[ANZ_SIDES]; reprule_t *current_rule; reprule_t *reprules; /* applied when drawing a box */ size_t anz_reprules; reprule_t *revrules; /* applied upon removal of a box */ size_t anz_revrules; } design_t; extern design_t *designs; extern int anz_designs; extern int design_idx; extern int tjlineno; /* config file line counter */ extern char *yyfilename; /* name of config file */ typedef struct { /* Command line options: */ int l; /* list available designs */ int mend; /* 1 if -m is given, 2 in 2nd loop */ int r; /* remove box from input */ int tabstop; /* tab stop distance */ char tabexp; /* tab expansion mode (for leading tabs) */ int padding[ANZ_SIDES]; /* in spaces or lines resp. */ design_t *design; /* currently used box design */ int design_choice_by_user; /* true if design was chosen by user */ char *cld; /* commandline design definition, -c */ long reqwidth; /* requested box width (-s) */ long reqheight; /* requested box height (-s) */ char valign; /* text position inside box */ char halign; /* ( h[lcr]v[tcb] ) */ char indentmode; /* 'b', 't', 'n', or '\0' */ char justify; /* 'l', 'c', 'r', or '\0' */ int killblank; /* -1 if not set */ FILE *infile; /* where we get our input */ FILE *outfile; /* where we put our output */ } opt_t; extern opt_t opt; typedef struct { size_t len; /* length of text in characters */ char *text; /* line content, tabs expanded */ size_t *tabpos; /* tab positions in expanded work strings */ size_t tabpos_len; /* number of tabs in a line */ } line_t; #ifndef FILE_LEXER_L typedef struct { line_t *lines; size_t anz_lines; /* number of entries in input */ size_t maxline; /* length of longest input line */ size_t indent; /* number of leading spaces found */ } input_t; #define INPUT_INITIALIZER {NULL, 0, 0, LINE_MAX} extern input_t input; #endif /*!FILE_LEXER_L*/ #endif /* BOXES_H */ /*EOF*/ /* vim: set cindent sw=4 syntax=c: */ boxes-1.1.1/src/lexer.h0100644000175000001440000000467110456216307014476 0ustar tsjensenusers/* * File: lexer.h * Project Main: boxes.c * Date created: July 01, 1999 (Thursday, 13:43h) * Author: Copyright (C) 1999 Thomas Jensen * Version: $Id: lexer.h,v 1.5 2006/07/12 05:33:12 tsjensen Exp $ * Language: ANSI C * World Wide Web: http://boxes.thomasjensen.com/ * Purpose: Export symbols used by the parser files only * * Remarks: o This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * o This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * o You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * Revision History: * * $Log: lexer.h,v $ * Revision 1.5 2006/07/12 05:33:12 tsjensen * Updated email and web addresses in comment header * * Revision 1.4 1999-08-18 08:42:46-07 tsjensen * Added LEX_SDELIM macro (valid string delimiter characters) * Added prototype for chg_strdelims() * * Revision 1.3 1999/08/14 19:06:26 tsjensen * Added GNU GPL disclaimer * Added yylex() declaration to please compiler * * Revision 1.2 1999/07/03 16:12:19 tsjensen * Renamed file from parser.h to lexer.h * * Revision 1.1 1999/07/02 11:47:11 tsjensen * Initial revision * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef LEXER_H #define LEXER_H /* * Valid characters to be used as string delimiters. Note that the * following list must correspond to the DELIM definition in lexer.l. */ #define LEX_SDELIM "\"~'`!@%&*=:;<>?/|.\\" int yylex(); /* defined in lex.yy.c */ void begin_speedmode(); void chg_strdelims (const char asdel, const char asesc); extern int speeding; #endif /*LEXER_H*/ /*EOF*/ /* vim: set sw=4: */ boxes-1.1.1/src/lexer.l0100644000175000001440000003232110460476427014501 0ustar tsjensenusers%{ /* * File: lexer.l * Date created: March 15, 1999 (Monday, 17:16h) * Author: Copyright (C) 1999 Thomas Jensen * Version: $Id: lexer.l,v 1.19 2006/07/22 19:31:25 tsjensen Exp $ * Language: lex (ANSI C) * Purpose: flex lexical analyzer for boxes configuration files * * Remarks: o This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * o This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * o You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * - We don't use the yylineno %option. It is not only inefficient, * but also doesn't work. :-| *doh* * * Revision History: * * $Log: lexer.l,v $ * Revision 1.19 2006/07/22 19:31:25 tsjensen * Fix: Renamed yylineno to tjlineno to enable compilation on certain * flexes (reported by Andreas Heiduk) * * Revision 1.18 2006/07/07 07:24:17 tsjensen * Applied patch by Andreas Heiduk to facilitate compilation with * present-day flexes * * Revision 1.17 1999/08/20 19:51:12 tsjensen * Moved contents of YY_USER_INIT definition into a separate function which * is now called by YY_USER_INIT (better readability) * * Revision 1.16 1999/08/18 18:23:41 tsjensen * Declared yyerrcnt to be static * Added YY_USER_INIT macro to set the input buffer size to the config file * size (plus a bit). This is supposed to be a workaround for the REJECT * problem. * * Revision 1.15 1999/08/18 15:40:10 tsjensen * Added %options never-interactive and caseless * Added code for DELIMITER statements * Rewrote string rules to deal with delimiter statements * * Revision 1.14 1999/08/16 16:28:03 tsjensen * Implemented new SAMPLE block syntax * Replaced states SAMPLE1 and SAMPLE2 with new state SAMPLE - this is now * much simpler code * * Revision 1.13 1999/07/22 12:21:14 tsjensen * Added GNU GPL disclaimer * Renamed y.tab.h include to parser.h (same file) * Renamed parser.h include to lexer.h (same file) * Added config.h include * * Revision 1.12 1999/07/02 11:58:15 tsjensen * Added begin_speedmode() which is called by parser.y * Added state SPEEDMODE for fast skipping of designs * Introduced definitions for PWORD, PBOX, and PWHITE (whitespace) * Added %options nounput and noyywrap for easier compilation/linking * * Revision 1.11 1999/06/28 18:37:38 tsjensen * Replaced DEBUG macro with LEXER_DEBUG, which is now activated in boxes.h * New tokens to, with, global, once * Added LEX_MAX_WARN macro to limit number of lex errors printed per design * Replaced exit()s with return YUNREC where errors are not fatal * * Revision 1.10 1999/06/28 12:17:46 tsjensen * Added tokens YBOX and YEND (thus, BOX and END are no longer YKEYWORDs) * Added #define FILE_LEXER_L around #include boxes.h to please compiler * * Revision 1.9 1999/06/22 12:00:05 tsjensen * Added #undef DEBUG, because DEBUGging is now activated in boxes.h * Added #include tools.h * * Revision 1.8 1999/06/20 14:17:58 tsjensen * Added "padding" keyword and recognition of numbers (YNUMBER) * * Revision 1.7 1999/06/17 19:05:46 tsjensen * Bugfix: Sample block analysis didn't handle empty blocks * * Revision 1.6 1999/06/14 12:13:41 tsjensen * Added Reverse pattern * * Revision 1.4 1999/04/09 13:31:13 tsjensen * Removed all code related to OFFSET blocks (obsolete) * * Revision 1.3 1999/04/04 16:11:39 tsjensen * Added indent keyword * Added Replace token * Some fiddling which will hopefully fix a line counting bug * * Revision 1.1 1999/03/18 15:09:48 tsjensen * Initial revision * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "config.h" #include #include #include #include "shape.h" #define FILE_LEXER_L #include "boxes.h" #undef FILE_LEXER_L #include "tools.h" #include "parser.h" #include "lexer.h" #define LEX_MAX_WARN 3 /* number of lex errors per design */ static const char rcsid_lexer_l[] = "$Id: lexer.l,v 1.19 2006/07/22 19:31:25 tsjensen Exp $"; int tjlineno = 1; static int yyerrcnt = 0; static char sdel = '\"'; static char sesc = '\\'; /* * User-defined initializations for the lexer */ static void inflate_inbuf(); #define YY_USER_INIT inflate_inbuf() %} %option nounput %option noyywrap %option never-interactive %option caseless %option noyylineno %x SAMPLE %x SPEEDMODE %x DELWORD %s SHAPES %s ELASTIC PWORD [a-zA-ZäöüÄÖÜ][a-zA-Z0-9\-_üäöÜÄÖß]* PWHITE [\n \r\t] PBOX Box SDELIM [\"~\'`!@\%\&\*=:;<>\?/|\.\\] %% [ \r\t] /* ignore whitespace */ \n ++tjlineno; [^ \t\r\n]+ { /* * String delimiter spec - like WORD, but allow any character */ #ifdef LEXER_DEBUG fprintf (stderr, "\nYDELWOR: %s -- STATE INITIAL", yytext); #endif yylval.s = (char *) strdup (yytext); if (yylval.s == NULL) { perror (PROJECT); exit (EXIT_FAILURE); } BEGIN INITIAL; return YDELWORD; } {SDELIM}.*$ { /* * Strings -- first match everything starting from a potential * string delimiter until the end of the line. We will give back what * we don't need and also detect unterminated strings. */ char *p; int rest_len = yyleng - 1; /* length of string pointed to by p */ int qcnt = 0; /* esc char count in current string */ if (yytext[0] != sdel) { REJECT; /* that was not our delimiter */ } yylval.s = (char *) strdup (yytext + 1); if (yylval.s == NULL) { perror (PROJECT); exit (EXIT_FAILURE); } p = yylval.s; while (*p) { if (*p == sesc) { memmove (p, p+1, rest_len); /* incl. '\0' */ ++qcnt; --rest_len; if (*p == '\0') break; } else if (*p == sdel) { *p = '\0'; yyless ((p-yylval.s)+2+qcnt); /* string plus quotes */ #ifdef LEXER_DEBUG fprintf (stderr, "\n STRING: \"%s\"", yylval.s); #endif return STRING; } --rest_len; ++p; } if (yyerrcnt++ < 5) yyerror ("Unterminated String -- %s", yytext); return YUNREC; } Sample { #ifdef LEXER_DEBUG fprintf (stderr, "\nYSAMPLE: %s -- STATE SAMPLE", yytext); #endif BEGIN SAMPLE; return YSAMPLE; } \n { ++tjlineno; if (yyleng > 1) yymore(); } ^[ \t]*ends[ \t\r]*$ { char *p = yytext + yyleng -1; size_t len; /* length of sample */ while (*p == ' ' || *p == '\t' || *p == '\r') --p; /* skip trailing whitespace */ p -= 2; /* almost skip "ends" statement */ *p = '\0'; /* p now points to 'n' */ yylval.s = (char *) strdup (yytext); if (yylval.s == NULL) { perror (PROJECT); exit (EXIT_FAILURE); } *p-- = 'n'; len = p - yytext; /* yyless(n): push back all but the first n */ yyless (len); /* allow him to return YENDSAMPLE */ yylval.s[len] = '\n'; /* replace 'e' with newline */ btrim (yylval.s, &len); if (len > 0) { strcat (yylval.s, "\n"); /* memory was allocated with strdup */ #ifdef LEXER_DEBUG fprintf (stderr, "\n STRING: \"%s\" -- STATE INITIAL", yylval.s); #endif BEGIN INITIAL; return STRING; } else { if (yyerrcnt++ < 5) yyerror ("SAMPLE block must not be empty"); BFREE (yylval.s); return YUNREC; } } . yymore(); ends[ \t\r]*$ { #ifdef LEXER_DEBUG fprintf (stderr, "\nYENDSAM: %s", yytext); #endif return YENDSAMPLE; } Elastic { #ifdef LEXER_DEBUG fprintf (stderr, "\nYELASTC: %s -- STATE ELASTIC", yytext); #endif BEGIN ELASTIC; return YELASTIC; } Shapes { #ifdef LEXER_DEBUG fprintf (stderr, "\nYSHAPES: %s -- STATE SHAPES", yytext); #endif BEGIN SHAPES; return YSHAPES; } {PBOX} { #ifdef LEXER_DEBUG fprintf (stderr, "\n YBOX: %s", yytext); #endif yyerrcnt = 0; return YBOX; } Replace { return YREPLACE; } Reverse { return YREVERSE; } Padding { return YPADDING; } End { return YEND; } To { return YTO; } With { return YWITH; } Global { yylval.c = 'g'; return YRXPFLAG; } Once { yylval.c = 'o'; return YRXPFLAG; } nw { yylval.shape = NW; return SHAPE; } nnw { yylval.shape = NNW; return SHAPE; } n { yylval.shape = N; return SHAPE; } nne { yylval.shape = NNE; return SHAPE; } ne { yylval.shape = NE; return SHAPE; } ene { yylval.shape = ENE; return SHAPE; } e { yylval.shape = E; return SHAPE; } ese { yylval.shape = ESE; return SHAPE; } se { yylval.shape = SE; return SHAPE; } sse { yylval.shape = SSE; return SHAPE; } s { yylval.shape = S; return SHAPE; } ssw { yylval.shape = SSW; return SHAPE; } sw { yylval.shape = SW; return SHAPE; } wsw { yylval.shape = WSW; return SHAPE; } w { yylval.shape = W; return SHAPE; } wnw { yylval.shape = WNW; return SHAPE; } \) { #ifdef LEXER_DEBUG fprintf (stderr, "\n SYMBOL: \'%c\' -- STATE INITIAL", yytext[0]); #endif BEGIN INITIAL; return yytext[0]; } \} { #ifdef LEXER_DEBUG fprintf (stderr, "\n SYMBOL: \'%c\' -- STATE INITIAL", yytext[0]); #endif BEGIN INITIAL; return yytext[0]; } author|created|revision|revdate|indent { /* * general key words */ #ifdef LEXER_DEBUG fprintf (stderr, "\nKEYWORD: %s", yytext); #endif yylval.s = (char *) strdup (yytext); if (yylval.s == NULL) { perror (PROJECT); exit (EXIT_FAILURE); } return KEYWORD; } Delimiter|Delim { /* * Change string delimiting characters */ #ifdef LEXER_DEBUG fprintf (stderr, "\nYCHGDEL: %s -- STATE DELWORD", yytext); #endif BEGIN DELWORD; return YCHGDEL; } {PWORD} { #ifdef LEXER_DEBUG fprintf (stderr, "\n WORD: %s", yytext); #endif yylval.s = (char *) strdup (yytext); if (yylval.s == NULL) { perror (PROJECT); exit (EXIT_FAILURE); } return WORD; } [\+-]?[0-9]+ { #ifdef LEXER_DEBUG fprintf (stderr, "\nYNUMBER: %s", yytext); #endif yylval.num = atoi (yytext); return YNUMBER; } [,(){}] { #ifdef LEXER_DEBUG fprintf (stderr, "\n SYMBOL: \'%c\'", yytext[0]); #endif return yytext[0]; } #.*$ { /* ignore comments */ #ifdef LEXER_DEBUG fprintf (stderr, "\nCOMMENT: %s", yytext+1); #endif } . { if (yyerrcnt++ < LEX_MAX_WARN) yyerror ("Unrecognized input char \'%s\'", yytext); return YUNREC; } {PBOX}{PWHITE}+{PWORD} { #ifdef LEXER_DEBUG fprintf (stderr, "\n STATUS: %s -- STATE INITIAL", yytext); #endif yyless (0); speeding = 0; BEGIN INITIAL; } \n ++tjlineno; . /* ignore anything else */ %% static void inflate_inbuf() /* * User-defined initializations for the lexer. * * Since this scanner must use REJECT in order to be able to process the * string delimiter commands, it cannot dynamically enlarge its input * buffer to accomodate larger tokens. Thus, we simply set the buffer size * to the input file size plus 10 bytes margin-of-error. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { struct stat sinf; if (stat(yyfilename, &sinf)) { perror (PROJECT); exit (EXIT_FAILURE); } yy_delete_buffer (YY_CURRENT_BUFFER); yy_switch_to_buffer (yy_create_buffer (yyin, sinf.st_size+10)); } void begin_speedmode() { #ifdef LEXER_DEBUG fprintf (stderr, "\n STATUS: begin_speedmode() -- STATE SPEEDMODE"); #endif BEGIN SPEEDMODE; } void chg_strdelims (const char asesc, const char asdel) { #ifdef LEXER_DEBUG fprintf (stderr, "\n STATUS: chg_strdelims ('%c', '%c')", asesc, asdel); #endif sesc = asesc; sdel = asdel; } /*EOF*/ /* vim: set cindent sw=4: */ boxes-1.1.1/src/shape.c0100644000175000001440000002421510460475451014450 0ustar tsjensenusers/* * File: shape.c * Project Main: boxes.c * Date created: June 23, 1999 (Wednesday, 13:39h) * Author: Copyright (C) 1999 Thomas Jensen * Version: $Id: shape.c,v 1.6 2006/07/12 05:27:29 tsjensen Exp $ * Language: ANSI C * World Wide Web: http://boxes.thomasjensen.com/ * Purpose: Shape handling and information functions * * Remarks: o This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * o This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * o You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * Revision History: * * $Log: shape.c,v $ * Revision 1.6 2006/07/12 05:27:29 tsjensen * Updated email and web addresses in comment header * * Revision 1.5 1999-08-14 12:11:53-07 tsjensen * Added findshape(), genshape(), freeshape(), and isdeepempty() functions * Added on_side() back in with a few changes * Changed empty_side() to use isdeepempty() -> much simpler code * * Revision 1.4 1999/07/23 16:38:02 tsjensen * Removed functions iscorner(), on_side(), shapecmp(), both_on_side(), and * shape_distance() - nobody was using them anyway. * * Revision 1.3 1999/07/22 12:28:25 tsjensen * Added GNU GPL disclaimer * Added include config.h * * Revision 1.2 1999/06/25 18:52:28 tsjensen * Added empty_side() function from boxes.c * Removed #include regexp.h * * Revision 1.1 1999/06/23 12:26:59 tsjensen * Initial revision * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "config.h" #include #include #include #include #include "shape.h" #include "boxes.h" #include "tools.h" static const char rcsid_shape_c[] = "$Id: shape.c,v 1.6 2006/07/12 05:27:29 tsjensen Exp $"; char *shape_name[] = { "NW", "NNW", "N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW" }; shape_t north_side[SHAPES_PER_SIDE] = { NW, NNW, N, NNE, NE }; /* clockwise */ shape_t east_side[SHAPES_PER_SIDE] = { NE, ENE, E, ESE, SE }; shape_t south_side[SHAPES_PER_SIDE] = { SE, SSE, S, SSW, SW }; shape_t west_side[SHAPES_PER_SIDE] = { SW, WSW, W, WNW, NW }; shape_t corners[ANZ_CORNERS] = { NW, NE, SE, SW }; shape_t *sides[] = { north_side, east_side, south_side, west_side }; shape_t findshape (const sentry_t *sarr, const int num) /* * Find a non-empty shape and return its name * * sarr the shape array to check * num number of entries in sarr to be checked * * RETURNS: a shape_name on success * num on error (e.g. empty shape array) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { int i; for (i=0; i LINE_MAX) { fprintf (stderr, "%s: internal error\n", PROJECT); return 1; } *chars = (char **) calloc (height, sizeof(char *)); if (*chars == NULL) { perror (PROJECT); return 2; } for (j=0; j0; --j) BFREE ((*chars)[j-1]); BFREE (*chars); return 3; } memset ((*chars)[j], ' ', width); } return 0; } void freeshape (sentry_t *shape) /* * Free all memory allocated by the shape and set the struct to * SENTRY_INITIALIZER. Do not free memory of the struct. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { size_t j; for (j=0; jheight; ++j) BFREE (shape->chars[j]); BFREE (shape->chars); *shape = SENTRY_INITIALIZER; } int isempty (const sentry_t *shape) /* * Return true if shape is empty. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { if (shape == NULL) return 1; else if (shape->chars == NULL) return 1; else if (shape->width == 0 || shape->height == 0) return 1; else return 0; } int isdeepempty (const sentry_t *shape) /* * Return true if shape is empty, also checking if lines consist of spaces * only. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { size_t j; if (isempty (shape)) return 1; for (j=0; jheight; ++j) { if (shape->chars[j]) { if (strspn (shape->chars[j], " ") != shape->width) return 0; } } return 1; } size_t highest (const sentry_t *sarr, const int n, ...) /* * Return height (vert.) of highest shape in given list. * * sarr array of shapes to examine * n number of shapes following * ... the shapes to consider * * RETURNS: height in lines (may be zero) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { va_list ap; int i; size_t max = 0; /* current maximum height */ #if defined(DEBUG) && 0 fprintf (stderr, "highest (%d, ...)\n", n); #endif va_start (ap, n); for (i=0; i max) max = sarr[r].height; } } va_end (ap); return max; } size_t widest (const sentry_t *sarr, const int n, ...) /* * Return width (horiz.) of widest shape in given list. * * sarr array of shapes to examine * n number of shapes following * ... the shapes to consider * * RETURNS: width in chars (may be zero) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { va_list ap; int i; size_t max = 0; /* current maximum width */ #if defined(DEBUG) && 0 fprintf (stderr, "widest (%d, ...)\n", n); #endif va_start (ap, n); for (i=0; i max) max = sarr[r].width; } } va_end (ap); return max; } shape_t leftmost (const int aside, const int cnt) /* * Return leftmost existing shape in specification for side aside * (BTOP or BBOT), skipping cnt shapes. Corners are not considered. * * RETURNS: shape if shape was found * ANZ_SHAPES on error (e.g. cnt too high) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { int c = 0; int s; if (cnt < 0) return ANZ_SHAPES; if (aside == BTOP) { s = 0; do { ++s; while (s < SHAPES_PER_SIDE-1 && isempty(opt.design->shape + north_side[s])) ++s; if (s == SHAPES_PER_SIDE-1) return ANZ_SHAPES; } while (c++ < cnt); return north_side[s]; } else if (aside == BBOT) { s = SHAPES_PER_SIDE - 1; do { --s; while (s && isempty(opt.design->shape + south_side[s])) --s; if (!s) return ANZ_SHAPES; } while (c++ < cnt); return south_side[s]; } return ANZ_SHAPES; } int empty_side (sentry_t *sarr, const int aside) /* * Return true if the shapes on the given side consist entirely out of * spaces - and spaces only, tabs are considered non-empty. * * sarr pointer to shape list of design to check * aside the box side (one of BTOP etc.) * * RETURNS: == 0 side is not empty * != 0 side is empty * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { int i; for (i=0; i * Version: $Id: shape.h,v 1.5 2006/07/12 05:27:59 tsjensen Exp $ * Language: ANSI C * World Wide Web: http://boxes.thomasjensen.com/ * Purpose: Shape handling and information functions * * Remarks: o This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * o This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * o You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * Revision History: * * $Log: shape.h,v $ * Revision 1.5 2006/07/12 05:27:59 tsjensen * Updated email and web addresses in comment header * * Revision 1.4 1999-08-14 12:08:34-07 tsjensen * Added genshape(), freeshape(), and findshape() prototypes * Added on_side() prototype back again * Added isdeepempty() prototype * Changed first parameter of empty_side() prototype * * Revision 1.3 1999/07/23 16:36:33 tsjensen * Added GNU GPL disclaimer * Removed prototypes of iscorner(), on_side(), shapecmp(), both_on_side(), * and shape_distance() - nobody was using those anyway. * * Revision 1.2 1999/06/25 18:52:59 tsjensen * Added empty_side() prototype * * Revision 1.1 1999/06/23 12:27:06 tsjensen * Initial revision * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef SHAPE_H #define SHAPE_H typedef enum { NW, NNW, N, NNE, NE, ENE, E, ESE, SE, SSE, S, SSW, SW, WSW, W, WNW } shape_t; extern char *shape_name[]; #define ANZ_SHAPES 16 #define SHAPES_PER_SIDE 5 #define ANZ_SIDES 4 #define ANZ_CORNERS 4 extern shape_t north_side[SHAPES_PER_SIDE]; /* groups of shapes, clockwise */ extern shape_t east_side[SHAPES_PER_SIDE]; extern shape_t south_side[SHAPES_PER_SIDE]; extern shape_t west_side[SHAPES_PER_SIDE]; extern shape_t corners[ANZ_CORNERS]; extern shape_t *sides[ANZ_SIDES]; typedef struct { char **chars; size_t height; size_t width; int elastic; /* elastic is used only in orginial definition */ } sentry_t; #define SENTRY_INITIALIZER (sentry_t) {NULL, 0, 0, 0} int genshape (const size_t width, const size_t height, char ***chars); void freeshape (sentry_t *shape); shape_t findshape (const sentry_t *sarr, const int num); int on_side (const shape_t s, const int idx); int isempty (const sentry_t *shape); int isdeepempty (const sentry_t *shape); size_t highest (const sentry_t *sarr, const int n, ...); size_t widest (const sentry_t *sarr, const int n, ...); shape_t leftmost (const int aside, const int cnt); int empty_side (sentry_t *sarr, const int aside); #endif /*SHAPE_H*/ /*EOF*/ /* vim: set cindent sw=4: */ boxes-1.1.1/src/parser.c0100644000175000001440000020671312040302150014626 0ustar tsjensenusers/* A Bison parser, made by GNU Bison 1.875. */ /* Skeleton parser for Yacc-like parsing with Bison, Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* As a special exception, when this file is copied by Bison into a Bison output file, you may use that output file without restriction. This special exception was added by the Free Software Foundation in version 1.24 of Bison. */ /* Written by Richard Stallman by simplifying the original so called ``semantic'' parser. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output. */ #define YYBISON 1 /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 0 /* Using locations. */ #define YYLSP_NEEDED 0 /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE /* Put the tokens into the symbol table, so that GDB and other debuggers know about them. */ enum yytokentype { YSHAPES = 258, YELASTIC = 259, YPADDING = 260, YSAMPLE = 261, YENDSAMPLE = 262, YBOX = 263, YEND = 264, YUNREC = 265, YREPLACE = 266, YREVERSE = 267, YTO = 268, YWITH = 269, YCHGDEL = 270, KEYWORD = 271, WORD = 272, STRING = 273, SHAPE = 274, YNUMBER = 275, YRXPFLAG = 276, YDELWORD = 277 }; #endif #define YSHAPES 258 #define YELASTIC 259 #define YPADDING 260 #define YSAMPLE 261 #define YENDSAMPLE 262 #define YBOX 263 #define YEND 264 #define YUNREC 265 #define YREPLACE 266 #define YREVERSE 267 #define YTO 268 #define YWITH 269 #define YCHGDEL 270 #define KEYWORD 271 #define WORD 272 #define STRING 273 #define SHAPE 274 #define YNUMBER 275 #define YRXPFLAG 276 #define YDELWORD 277 /* Copy the first part of user declarations. */ #line 1 "parser.y" /* * File: parser.y * Date created: March 16, 1999 (Tuesday, 17:17h) * Author: Copyright (C) 1999 Thomas Jensen * Version: $Id: parser.y,v 1.25 2006/07/23 16:11:39 tsjensen Exp $ * Language: GNU bison (ANSI C) * World Wide Web: http://boxes.thomasjensen.com/ * Purpose: Yacc parser for boxes configuration files * * Remarks: o This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * o This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * o You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * Revision History: * * $Log: parser.y,v $ * Revision 1.25 2006/07/23 16:11:39 tsjensen * Removed unsigned modifier from a pointer declaration in order to clear a warning * which appeared on some Linuxes (reported by Andreas Heiduk) * * Revision 1.24 2006/07/22 19:30:55 tsjensen * Fix: Renamed yylineno to tjlineno to enable compilation on certain * flexes (reported by Andreas Heiduk) * * Revision 1.23 2006/07/12 05:31:25 tsjensen * Updated email and web addresses in comment header * * Revision 1.22 1999-08-21 08:53:58-07 tsjensen * Removed check for empty sample block, which is also done in lexer.l * * Revision 1.21 1999/08/18 15:38:44 tsjensen * Added new tokens YCHGDEL and YDELWORD * Added code for DELIMITER statements * * Revision 1.20 1999/08/16 16:29:25 tsjensen * Changed SAMPLE block syntax to get rid of all the quoting sh*t in SAMPLE * blocks. Samples now look authentic even in the config file. Very simple now. * Added new token YENDSAMPLE in the process. * * Revision 1.19 1999/08/14 19:19:25 tsjensen * Added anz_shapespec variable to count non-deepempty user-specified shapes * (must at least be 1) * Moved yylex declaration to lexer.h, where it belongs * Bugfix: bison and yacc seem to differ in the way action code is treated * which is associated with an error token. Since bison calls the action * routine whenever a token is skipped while recovering, added skipping * variable to ensure that only one "skipping to next design" message is * printed. That was not necessary before. %-/ * Removed existence check from corner_check() routine (obsolete). * Added code to generate required shapes which were not specified by the user * Clean-up in shape_def rule (use freeshape() and some more) * * Revision 1.18 1999/07/23 16:14:17 tsjensen * Added computation of height of highest shape in design (maxshapeheight) * Options -l and -d together now call quickinfo mode -> parse only 1 design * * Revision 1.17 1999/07/22 12:27:16 tsjensen * Added GNU GPL disclaimer * Renamed parser.h include to lexer.h (same file) * Added include config.h * * Revision 1.16 1999/07/02 11:54:52 tsjensen * Some minor changes to please compiler * Communication of speed mode to lexer * Bugfix: Forgot to check for opt.l before calling YYACCEPT * * Revision 1.15 1999/06/30 12:13:47 tsjensen * Now parsing only those designs which will be needed later on * Checks formerly done in boxes.c now done here (no valid designs etc.) * * Revision 1.14 1999/06/28 18:32:51 tsjensen * Unified appearance of error messages, which are now all based on yyerror() * Eliminated duplicate code by introducing intermediate rules * New tokens YTO, YWITH, and YRXPFLAG to reduce strcasecmp() usage * New token YUNREC for integration of lexer into error handling * Some code restructuring and rule renaming for better consistency * Added out-of-memory-checks to many strdup()s and such * * Revision 1.13 1999/06/28 12:15:47 tsjensen * Added error handling. Now skips to next design on error. * Replaced DEBUG macro with PARSER_DEBUG, which is now activated in boxes.h * Added rule first_rule, which performs init and cleanup formerly done in main() * Introduced symbols YBOX and YEND * * Revision 1.12 1999/06/22 12:01:01 tsjensen * Added #undef DEBUG, because DEBUGging is now activated in boxes.h * Added #include tools.h * * Revision 1.11 1999/06/20 14:18:51 tsjensen * Adden YPADDING and YNUMBER tokens plus code for padding blocks * * Revision 1.10 1999/06/17 19:04:45 tsjensen * Added detection of empty sample blocks (we don't want that) * Added detection of duplicate sample blocks * * Revision 1.9 1999/06/14 12:13:01 tsjensen * Added YREVERSE token * Added code for regexp reversion * * Revision 1.7 1999/04/09 13:31:54 tsjensen * Added checks for duplicate design names * Added checks for valid design names (no extended ASCII or ctrl chars) * Removed all code related to OFFSET blocks (obsolete) * * Revision 1.6 1999/04/04 16:07:53 tsjensen * Enforced use of PROJECT macro * Added "indent" directive to grammar * Added "replace" directive to grammar * * Revision 1.5 1999/03/30 13:29:50 tsjensen * Added computation of minimum width/height of each design. * * Revision 1.4 1999/03/30 09:37:51 tsjensen * It drew a correct box for the first time! * * Revision 1.3 1999/03/24 17:29:12 tsjensen * Added detection of empty shapes ("") which are now cleared (+warning) * Changed rcs string to #ident directive * * Revision 1.1 1999/03/18 15:10:06 tsjensen * Initial revision * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "config.h" #include #include #include #include "shape.h" #include "boxes.h" #include "tools.h" #include "lexer.h" const char rcsid_parser_y[] = "$Id: parser.y,v 1.25 2006/07/23 16:11:39 tsjensen Exp $"; static int pflicht = 0; static int time_for_se_check = 0; static int anz_shapespec = 0; /* number of user-specified shapes */ int speeding = 0; /* true if we're skipping designs, */ /* but no error */ static int skipping = 0; /* used to limit "skipping" msgs */ static int check_sizes() /* * For the author's convenience, it is required that shapes on one side * have equal width (vertical sides) and height (horizontal sides). * * RETURNS: == 0 no problem detected * != 0 on error (prints error message, too) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { int i, j, k; #ifdef PARSER_DEBUG fprintf (stderr, "check_sizes()\n"); #endif for (i=0; i /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # endif # define YYSTACK_ALLOC malloc # define YYSTACK_FREE free # endif #endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */ #if (! defined (yyoverflow) \ && (! defined (__cplusplus) \ || (YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { short yyss; YYSTYPE yyvs; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (sizeof (short) + sizeof (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) /* Copy COUNT objects from FROM to TO. The source and destination do not overlap. */ # ifndef YYCOPY # if 1 < __GNUC__ # define YYCOPY(To, From, Count) \ __builtin_memcpy (To, From, (Count) * sizeof (*(From))) # else # define YYCOPY(To, From, Count) \ do \ { \ register YYSIZE_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (To)[yyi] = (From)[yyi]; \ } \ while (0) # endif # endif /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack) \ do \ { \ YYSIZE_T yynewbytes; \ YYCOPY (&yyptr->Stack, Stack, yysize); \ Stack = &yyptr->Stack; \ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / sizeof (*yyptr); \ } \ while (0) #endif #if defined (__STDC__) || defined (__cplusplus) typedef signed char yysigned_char; #else typedef short yysigned_char; #endif /* YYFINAL -- State number of the termination state. */ #define YYFINAL 3 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 64 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 28 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 19 /* YYNRULES -- Number of rules. */ #define YYNRULES 37 /* YYNRULES -- Number of states. */ #define YYNSTATES 70 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 #define YYMAXUTOK 277 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) /* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ static const unsigned char yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 25, 26, 2, 2, 27, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 23, 2, 24, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 }; #if YYDEBUG /* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in YYRHS. */ static const unsigned char yyprhs[] = { 0, 0, 3, 4, 7, 10, 12, 14, 16, 17, 24, 27, 30, 32, 34, 37, 40, 43, 47, 52, 57, 63, 69, 74, 76, 77, 81, 83, 85, 88, 90, 93, 97, 100, 104, 106, 109, 111 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yysigned_char yyrhs[] = { 29, 0, -1, -1, 30, 31, -1, 31, 32, -1, 32, -1, 33, -1, 1, -1, -1, 8, 17, 34, 35, 9, 17, -1, 35, 36, -1, 35, 37, -1, 36, -1, 37, -1, 16, 18, -1, 15, 22, -1, 17, 18, -1, 6, 18, 7, -1, 3, 23, 41, 24, -1, 4, 25, 39, 26, -1, 11, 38, 18, 14, 18, -1, 12, 38, 18, 13, 18, -1, 5, 23, 45, 24, -1, 21, -1, -1, 39, 27, 40, -1, 40, -1, 19, -1, 41, 42, -1, 42, -1, 19, 43, -1, 25, 44, 26, -1, 25, 26, -1, 44, 27, 18, -1, 18, -1, 45, 46, -1, 46, -1, 17, 20, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const unsigned short yyrline[] = { 0, 445, 445, 445, 488, 488, 491, 491, 503, 502, 582, 582, 582, 582, 585, 637, 655, 664, 689, 831, 840, 871, 902, 915, 920, 926, 926, 929, 940, 940, 943, 963, 972, 979, 1009, 1034, 1034, 1037 }; #endif #if YYDEBUG || YYERROR_VERBOSE /* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "$end", "error", "$undefined", "YSHAPES", "YELASTIC", "YPADDING", "YSAMPLE", "YENDSAMPLE", "YBOX", "YEND", "YUNREC", "YREPLACE", "YREVERSE", "YTO", "YWITH", "YCHGDEL", "KEYWORD", "WORD", "STRING", "SHAPE", "YNUMBER", "YRXPFLAG", "YDELWORD", "'{'", "'}'", "'('", "')'", "','", "$accept", "first_rule", "@1", "config_file", "design_or_error", "design", "@2", "layout", "entry", "block", "rflag", "elist", "elist_entry", "slist", "slist_entry", "shape_def", "shape_lines", "wlist", "wlist_entry", 0 }; #endif # ifdef YYPRINT /* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to token YYLEX-NUM. */ static const unsigned short yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 123, 125, 40, 41, 44 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const unsigned char yyr1[] = { 0, 28, 30, 29, 31, 31, 32, 32, 34, 33, 35, 35, 35, 35, 36, 36, 36, 37, 37, 37, 37, 37, 37, 38, 38, 39, 39, 40, 41, 41, 42, 43, 43, 44, 44, 45, 45, 46 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ static const unsigned char yyr2[] = { 0, 2, 0, 2, 2, 1, 1, 1, 0, 6, 2, 2, 1, 1, 2, 2, 2, 3, 4, 4, 5, 5, 4, 1, 0, 3, 1, 1, 2, 1, 2, 3, 2, 3, 1, 2, 1, 2 }; /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state STATE-NUM when YYTABLE doesn't specify something else to do. Zero means the default is an error. */ static const unsigned char yydefact[] = { 2, 0, 0, 1, 7, 0, 0, 5, 6, 8, 4, 0, 0, 0, 0, 0, 24, 24, 0, 0, 0, 0, 12, 13, 0, 0, 0, 0, 23, 0, 0, 15, 14, 16, 0, 10, 11, 0, 0, 29, 27, 0, 26, 0, 0, 36, 17, 0, 0, 9, 0, 30, 18, 28, 19, 0, 37, 22, 35, 0, 0, 34, 32, 0, 25, 20, 21, 31, 0, 33 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yysigned_char yydefgoto[] = { -1, 1, 2, 6, 7, 8, 11, 21, 22, 23, 29, 41, 42, 38, 39, 51, 63, 44, 45 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ #define YYPACT_NINF -15 static const yysigned_char yypact[] = { -15, 4, 29, -15, -15, -10, 25, -15, -15, -15, -15, 12, -1, 7, 13, 21, 19, 19, 20, 23, 26, -3, -15, -15, 24, 27, 28, 40, -15, 30, 31, -15, -15, -15, 33, -15, -15, 32, -14, -15, -15, -6, -15, 34, 14, -15, -15, 37, 39, -15, -7, -15, -15, -15, -15, 27, -15, -15, -15, 35, 38, -15, -15, 8, -15, -15, -15, -15, 41, -15 }; /* YYPGOTO[NTERM-NUM]. */ static const yysigned_char yypgoto[] = { -15, -15, -15, -15, 49, -15, -15, -15, 42, 43, 44, -15, 3, -15, 22, -15, -15, -15, 18 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which number is the opposite. If zero, do what YYDEFACT says. If YYTABLE_NINF, syntax error. */ #define YYTABLE_NINF -4 static const yysigned_char yytable[] = { 12, 13, 14, 15, 3, 37, 34, 9, 16, 17, 52, 61, 18, 19, 20, 12, 13, 14, 15, 62, 54, 55, 24, 16, 17, -3, 4, 18, 19, 20, 4, 43, 25, 5, 67, 68, 26, 5, 57, 27, 28, 32, 31, 37, 33, 43, 40, 46, 47, 48, 49, 59, 60, 65, 56, 10, 66, 50, 64, 69, 53, 30, 58, 35, 36 }; static const unsigned char yycheck[] = { 3, 4, 5, 6, 0, 19, 9, 17, 11, 12, 24, 18, 15, 16, 17, 3, 4, 5, 6, 26, 26, 27, 23, 11, 12, 0, 1, 15, 16, 17, 1, 17, 25, 8, 26, 27, 23, 8, 24, 18, 21, 18, 22, 19, 18, 17, 19, 7, 18, 18, 17, 14, 13, 18, 20, 6, 18, 25, 55, 18, 38, 17, 44, 21, 21 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const unsigned char yystos[] = { 0, 29, 30, 0, 1, 8, 31, 32, 33, 17, 32, 34, 3, 4, 5, 6, 11, 12, 15, 16, 17, 35, 36, 37, 23, 25, 23, 18, 21, 38, 38, 22, 18, 18, 9, 36, 37, 19, 41, 42, 19, 39, 40, 17, 45, 46, 7, 18, 18, 17, 25, 43, 24, 42, 26, 27, 20, 24, 46, 14, 13, 18, 26, 44, 40, 18, 18, 26, 27, 18 }; #if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) # define YYSIZE_T __SIZE_TYPE__ #endif #if ! defined (YYSIZE_T) && defined (size_t) # define YYSIZE_T size_t #endif #if ! defined (YYSIZE_T) # if defined (__STDC__) || defined (__cplusplus) # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # endif #endif #if ! defined (YYSIZE_T) # define YYSIZE_T unsigned int #endif #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYEMPTY (-2) #define YYEOF 0 #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrlab1 /* Like YYERROR except do call yyerror. This remains here temporarily to ease the transition to the new meaning of YYERROR, for GCC. Once GCC version 2 has supplanted version 1, this can go. */ #define YYFAIL goto yyerrlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY && yylen == 1) \ { \ yychar = (Token); \ yylval = (Value); \ yytoken = YYTRANSLATE (yychar); \ YYPOPSTACK; \ goto yybackup; \ } \ else \ { \ yyerror ("syntax error: cannot back up");\ YYERROR; \ } \ while (0) #define YYTERROR 1 #define YYERRCODE 256 /* YYLLOC_DEFAULT -- Compute the default location (before the actions are run). */ #ifndef YYLLOC_DEFAULT # define YYLLOC_DEFAULT(Current, Rhs, N) \ Current.first_line = Rhs[1].first_line; \ Current.first_column = Rhs[1].first_column; \ Current.last_line = Rhs[N].last_line; \ Current.last_column = Rhs[N].last_column; #endif /* YYLEX -- calling `yylex' with the right arguments. */ #ifdef YYLEX_PARAM # define YYLEX yylex (YYLEX_PARAM) #else # define YYLEX yylex () #endif /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (0) # define YYDSYMPRINT(Args) \ do { \ if (yydebug) \ yysymprint Args; \ } while (0) # define YYDSYMPRINTF(Title, Token, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yysymprint (stderr, \ Token, Value); \ YYFPRINTF (stderr, "\n"); \ } \ } while (0) /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (cinluded). | `------------------------------------------------------------------*/ #if defined (__STDC__) || defined (__cplusplus) static void yy_stack_print (short *bottom, short *top) #else static void yy_stack_print (bottom, top) short *bottom; short *top; #endif { YYFPRINTF (stderr, "Stack now"); for (/* Nothing. */; bottom <= top; ++bottom) YYFPRINTF (stderr, " %d", *bottom); YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (0) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ #if defined (__STDC__) || defined (__cplusplus) static void yy_reduce_print (int yyrule) #else static void yy_reduce_print (yyrule) int yyrule; #endif { int yyi; unsigned int yylineno = yyrline[yyrule]; YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ", yyrule - 1, yylineno); /* Print the symbols being reduced, and their result. */ for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++) YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]); YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]); } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (Rule); \ } while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) # define YYDSYMPRINT(Args) # define YYDSYMPRINTF(Title, Token, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #if YYMAXDEPTH == 0 # undef YYMAXDEPTH #endif #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif #if YYERROR_VERBOSE # ifndef yystrlen # if defined (__GLIBC__) && defined (_STRING_H) # define yystrlen strlen # else /* Return the length of YYSTR. */ static YYSIZE_T # if defined (__STDC__) || defined (__cplusplus) yystrlen (const char *yystr) # else yystrlen (yystr) const char *yystr; # endif { register const char *yys = yystr; while (*yys++ != '\0') continue; return yys - yystr - 1; } # endif # endif # ifndef yystpcpy # if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) # define yystpcpy stpcpy # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ static char * # if defined (__STDC__) || defined (__cplusplus) yystpcpy (char *yydest, const char *yysrc) # else yystpcpy (yydest, yysrc) char *yydest; const char *yysrc; # endif { register char *yyd = yydest; register const char *yys = yysrc; while ((*yyd++ = *yys++) != '\0') continue; return yyd - 1; } # endif # endif #endif /* !YYERROR_VERBOSE */ #if YYDEBUG /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ #if defined (__STDC__) || defined (__cplusplus) static void yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep) #else static void yysymprint (yyoutput, yytype, yyvaluep) FILE *yyoutput; int yytype; YYSTYPE *yyvaluep; #endif { /* Pacify ``unused variable'' warnings. */ (void) yyvaluep; if (yytype < YYNTOKENS) { YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); # ifdef YYPRINT YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); # endif } else YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); switch (yytype) { default: break; } YYFPRINTF (yyoutput, ")"); } #endif /* ! YYDEBUG */ /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ #if defined (__STDC__) || defined (__cplusplus) static void yydestruct (int yytype, YYSTYPE *yyvaluep) #else static void yydestruct (yytype, yyvaluep) int yytype; YYSTYPE *yyvaluep; #endif { /* Pacify ``unused variable'' warnings. */ (void) yyvaluep; switch (yytype) { default: break; } } /* Prevent warnings from -Wmissing-prototypes. */ #ifdef YYPARSE_PARAM # if defined (__STDC__) || defined (__cplusplus) int yyparse (void *YYPARSE_PARAM); # else int yyparse (); # endif #else /* ! YYPARSE_PARAM */ #if defined (__STDC__) || defined (__cplusplus) int yyparse (void); #else int yyparse (); #endif #endif /* ! YYPARSE_PARAM */ /* The lookahead symbol. */ int yychar; /* The semantic value of the lookahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; /*----------. | yyparse. | `----------*/ #ifdef YYPARSE_PARAM # if defined (__STDC__) || defined (__cplusplus) int yyparse (void *YYPARSE_PARAM) # else int yyparse (YYPARSE_PARAM) void *YYPARSE_PARAM; # endif #else /* ! YYPARSE_PARAM */ #if defined (__STDC__) || defined (__cplusplus) int yyparse (void) #else int yyparse () #endif #endif { register int yystate; register int yyn; int yyresult; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; /* Lookahead token as an internal (translated) token number. */ int yytoken = 0; /* Three stacks and their tools: `yyss': related to states, `yyvs': related to semantic values, `yyls': related to locations. Refer to the stacks thru separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* The state stack. */ short yyssa[YYINITDEPTH]; short *yyss = yyssa; register short *yyssp; /* The semantic value stack. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs = yyvsa; register YYSTYPE *yyvsp; #define YYPOPSTACK (yyvsp--, yyssp--) YYSIZE_T yystacksize = YYINITDEPTH; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; /* When reducing, the number of symbols on the RHS of the reduced rule. */ int yylen; YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ /* Initialize stack pointers. Waste one element of value and location stack so that they stay on the same level as the state stack. The wasted elements are never initialized. */ yyssp = yyss; yyvsp = yyvs; goto yysetstate; /*------------------------------------------------------------. | yynewstate -- Push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. so pushing a state here evens the stacks. */ yyssp++; yysetstate: *yyssp = yystate; if (yyss + yystacksize - 1 <= yyssp) { /* Get the current used size of the three stacks, in elements. */ YYSIZE_T yysize = yyssp - yyss + 1; #ifdef yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ YYSTYPE *yyvs1 = yyvs; short *yyss1 = yyss; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow ("parser stack overflow", &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; } #else /* no yyoverflow */ # ifndef YYSTACK_RELOCATE goto yyoverflowlab; # else /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) goto yyoverflowlab; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { short *yyss1 = yyss; union yyalloc *yyptr = (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyoverflowlab; YYSTACK_RELOCATE (yyss); YYSTACK_RELOCATE (yyvs); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif #endif /* no yyoverflow */ yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long int) yystacksize)); if (yyss + yystacksize - 1 <= yyssp) YYABORT; } YYDPRINTF ((stderr, "Entering state %d\n", yystate)); goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. */ /* Read a lookahead token if we need one and don't already have one. */ /* yyresume: */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yyn == YYPACT_NINF) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); yychar = YYLEX; } if (yychar <= YYEOF) { yychar = yytoken = YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else { yytoken = YYTRANSLATE (yychar); YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yyn == 0 || yyn == YYTABLE_NINF) goto yyerrlab; yyn = -yyn; goto yyreduce; } if (yyn == YYFINAL) YYACCEPT; /* Shift the lookahead token. */ YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken])); /* Discard the token being shifted unless it is eof. */ if (yychar != YYEOF) yychar = YYEMPTY; *++yyvsp = yylval; /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; yystate = yyn; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- Do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: `$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; YY_REDUCE_PRINT (yyn); switch (yyn) { case 2: #line 445 "parser.y" { /* * Initialize parser data structures */ designs = (design_t *) calloc (1, sizeof(design_t)); if (designs == NULL) { perror (PROJECT); YYABORT; } designs->indentmode = DEF_INDENTMODE; ;} break; case 3: #line 457 "parser.y" { /* * Clean up parser data structures */ design_t *tmp; if (design_idx == 0) { BFREE (designs); anz_designs = 0; if (opt.design_choice_by_user) { fprintf (stderr, "%s: unknown box design -- %s\n", PROJECT, (char *) opt.design); } else { yyerror ("no valid designs found"); } YYABORT; } --design_idx; anz_designs = design_idx + 1; tmp = (design_t *) realloc (designs, anz_designs*sizeof(design_t)); if (!tmp) { perror (PROJECT); YYABORT; } designs = tmp; ;} break; case 7: #line 492 "parser.y" { if (!speeding && !skipping) { recover(); yyerror ("skipping to next design"); skipping = 1; } ;} break; case 8: #line 503 "parser.y" { chg_strdelims ('\\', '\"'); skipping = 0; if (!design_needed (yyvsp[0].s, design_idx)) { speeding = 1; begin_speedmode(); YYERROR; } ;} break; case 9: #line 513 "parser.y" { design_t *tmp; int i; char *p; #ifdef PARSER_DEBUG fprintf (stderr, "--------- ADDING DESIGN \"%s\".\n", yyvsp[-4].s); #endif if (strcasecmp (yyvsp[-4].s, yyvsp[0].s)) { yyerror ("box design name differs at BOX and END"); YYERROR; } if (pflicht < 3) { yyerror ("entries SAMPLE, SHAPES, and ELASTIC are mandatory"); YYERROR; } for (i=0; i 126) { yyerror ("box design name must consist of printable standard " "ASCII characters."); YYERROR; } ++p; } designs[design_idx].name = (char *) strdup (yyvsp[-4].s); if (designs[design_idx].name == NULL) { perror (PROJECT); YYABORT; } pflicht = 0; time_for_se_check = 0; anz_shapespec = 0; /* * Check if we need to continue parsing. If not, return. * The condition here must correspond to design_needed(). */ if (opt.design_choice_by_user || (!opt.r && !opt.l)) { anz_designs = design_idx + 1; YYACCEPT; } /* * Allocate space for next design */ ++design_idx; tmp = (design_t *) realloc (designs, (design_idx+1)*sizeof(design_t)); if (tmp == NULL) { perror (PROJECT); YYABORT; } designs = tmp; memset (&(designs[design_idx]), 0, sizeof(design_t)); designs[design_idx].indentmode = DEF_INDENTMODE; ;} break; case 14: #line 586 "parser.y" { #ifdef PARSER_DEBUG fprintf (stderr, "entry rule fulfilled [%s = %s]\n", yyvsp[-1].s, yyvsp[0].s); #endif if (strcasecmp (yyvsp[-1].s, "author") == 0) { designs[design_idx].author = (char *) strdup (yyvsp[0].s); if (designs[design_idx].author == NULL) { perror (PROJECT); YYABORT; } } else if (strcasecmp (yyvsp[-1].s, "revision") == 0) { designs[design_idx].revision = (char *) strdup (yyvsp[0].s); if (designs[design_idx].revision == NULL) { perror (PROJECT); YYABORT; } } else if (strcasecmp (yyvsp[-1].s, "created") == 0) { designs[design_idx].created = (char *) strdup (yyvsp[0].s); if (designs[design_idx].created == NULL) { perror (PROJECT); YYABORT; } } else if (strcasecmp (yyvsp[-1].s, "revdate") == 0) { designs[design_idx].revdate = (char *) strdup (yyvsp[0].s); if (designs[design_idx].revdate == NULL) { perror (PROJECT); YYABORT; } } else if (strcasecmp (yyvsp[-1].s, "indent") == 0) { if (strcasecmp (yyvsp[0].s, "text") == 0 || strcasecmp (yyvsp[0].s, "box") == 0 || strcasecmp (yyvsp[0].s, "none") == 0) { designs[design_idx].indentmode = yyvsp[0].s[0]; } else { yyerror ("indent keyword must be followed by \"text\", " "\"box\", or \"none\""); YYERROR; } } else { yyerror ("internal parser error (unrecognized: %s) in line %d " "of %s.", yyvsp[-1].s, __LINE__, __FILE__); YYERROR; } ;} break; case 15: #line 638 "parser.y" { if (strlen(yyvsp[0].s) != 2) { yyerror ("invalid string delimiter specification -- %s", yyvsp[0].s); YYERROR; } if ((yyvsp[0].s)[0] == (yyvsp[0].s)[1]) { yyerror ("string delimiter and escape char may not be the same"); YYERROR; } if (strchr (LEX_SDELIM, (yyvsp[0].s)[1]) == NULL) { yyerror ("invalid string delimiter -- %c (try one of %s)", (yyvsp[0].s)[1], LEX_SDELIM); YYERROR; } chg_strdelims (yyvsp[0].s[0], yyvsp[0].s[1]); ;} break; case 16: #line 656 "parser.y" { #ifdef PARSER_DEBUG fprintf (stderr, "%s: Discarding entry [%s = %s].\n", PROJECT, yyvsp[-1].s, yyvsp[0].s); #endif ;} break; case 17: #line 665 "parser.y" { /* * SAMPLE block (STRING is non-empty if we get here) */ char *line; #ifdef PARSER_DEBUG fprintf (stderr, "SAMPLE block rule satisfied\n"); #endif if (designs[design_idx].sample) { yyerror ("duplicate SAMPLE block"); YYERROR; } line = (char *) strdup (yyvsp[-1].s); if (line == NULL) { perror (PROJECT); YYABORT; } designs[design_idx].sample = line; ++pflicht; ;} break; case 18: #line 690 "parser.y" { int i,j; shape_t fshape; /* found shape */ int fside; /* first side */ int sc; /* side counter */ int side; /* effective side */ int rc; /* received return code */ /* * At least one shape must be specified */ if (anz_shapespec < 1) { yyerror ("must specify at least one non-empty shape per design"); YYERROR; } /* * Ensure that all corners have been specified. Generate corners * as necessary, starting at any side which already includes at * least one shape in order to ensure correct measurements. */ fshape = findshape (designs[design_idx].shape, ANZ_SHAPES); if (fshape == ANZ_SHAPES) { yyerror ("internal error"); YYABORT; /* never happens ;-) */ } fside = on_side (fshape, 0); if (fside == ANZ_SIDES) { yyerror ("internal error"); YYABORT; /* never happens ;-) */ } for (sc=0,side=fside; scheight = 1; else c->height = c[nshape].height; c->width = designs[design_idx].shape[fshape].width; } else { if (nshape == SHAPES_PER_SIDE) c->width = 1; else c->width = c[nshape].width; c->height = designs[design_idx].shape[fshape].height; } c->elastic = 0; rc = genshape (c->width, c->height, &(c->chars)); if (rc) YYABORT; } fshape = sides[side][SHAPES_PER_SIDE-1]; } /* * For all sides whose side shapes have not been defined, generate * an elastic middle side shape. */ for (side=0; sidewidth = designs[design_idx].shape[sides[side][0]].width; c->height = 1; } else { c->width = 1; c->height = designs[design_idx].shape[sides[side][0]].height; } c->elastic = 1; rc = genshape (c->width, c->height, &(c->chars)); if (rc) YYABORT; } } if (check_sizes()) YYERROR; ++pflicht; if (++time_for_se_check > 1) { if (perform_se_check() != 0) YYERROR; } /* * Compute minimum height/width of a box of current design */ for (i=0; i designs[design_idx].minheight) designs[design_idx].minheight = c; } else { /* horizontal sides */ for (j=0; j designs[design_idx].minwidth) designs[design_idx].minwidth = c; } } /* * Compute height of highest shape in design */ for (i=0; i designs[design_idx].maxshapeheight) designs[design_idx].maxshapeheight = designs[design_idx].shape[i].height; } #ifdef PARSER_DEBUG fprintf (stderr, "Minimum box dimensions: width %d height %d\n", designs[design_idx].minwidth, designs[design_idx].minheight); fprintf (stderr, "Maximum shape height: %d\n", designs[design_idx].maxshapeheight); #endif ;} break; case 19: #line 832 "parser.y" { ++pflicht; if (++time_for_se_check > 1) { if (perform_se_check() != 0) YYERROR; } ;} break; case 20: #line 841 "parser.y" { int a = designs[design_idx].anz_reprules; #ifdef PARSER_DEBUG fprintf (stderr, "Adding replacement rule: \"%s\" with \"%s\" (%c)\n", yyvsp[-2].s, yyvsp[0].s, yyvsp[-3].c); #endif designs[design_idx].reprules = (reprule_t *) realloc (designs[design_idx].reprules, (a+1) * sizeof(reprule_t)); if (designs[design_idx].reprules == NULL) { perror (PROJECT); YYABORT; } memset (&(designs[design_idx].reprules[a]), 0, sizeof(reprule_t)); designs[design_idx].reprules[a].search = (char *) strdup (yyvsp[-2].s); designs[design_idx].reprules[a].repstr = (char *) strdup (yyvsp[0].s); if (designs[design_idx].reprules[a].search == NULL || designs[design_idx].reprules[a].repstr == NULL) { perror (PROJECT); YYABORT; } designs[design_idx].reprules[a].line = tjlineno; designs[design_idx].reprules[a].mode = yyvsp[-3].c; designs[design_idx].anz_reprules = a + 1; ;} break; case 21: #line 872 "parser.y" { int a = designs[design_idx].anz_revrules; #ifdef PARSER_DEBUG fprintf (stderr, "Adding reversion rule: \"%s\" to \"%s\" (%c)\n", yyvsp[-2].s, yyvsp[0].s, yyvsp[-3].c); #endif designs[design_idx].revrules = (reprule_t *) realloc (designs[design_idx].revrules, (a+1) * sizeof(reprule_t)); if (designs[design_idx].revrules == NULL) { perror (PROJECT); YYABORT; } memset (&(designs[design_idx].revrules[a]), 0, sizeof(reprule_t)); designs[design_idx].revrules[a].search = (char *) strdup (yyvsp[-2].s); designs[design_idx].revrules[a].repstr = (char *) strdup (yyvsp[0].s); if (designs[design_idx].revrules[a].search == NULL || designs[design_idx].revrules[a].repstr == NULL) { perror (PROJECT); YYABORT; } designs[design_idx].revrules[a].line = tjlineno; designs[design_idx].revrules[a].mode = yyvsp[-3].c; designs[design_idx].anz_revrules = a + 1; ;} break; case 22: #line 903 "parser.y" { #ifdef PARSER_DEBUG fprintf (stderr, "Padding set to (l%d o%d r%d u%d)\n", designs[design_idx].padding[BLEF], designs[design_idx].padding[BTOP], designs[design_idx].padding[BRIG], designs[design_idx].padding[BBOT]); #endif ;} break; case 23: #line 916 "parser.y" { yyval.c = yyvsp[0].c; ;} break; case 24: #line 920 "parser.y" { yyval.c = 'g'; ;} break; case 27: #line 930 "parser.y" { #ifdef PARSER_DEBUG fprintf (stderr, "Marked \'%s\' shape as elastic\n", shape_name[(int)yyvsp[0].shape]); #endif designs[design_idx].shape[yyvsp[0].shape].elastic = 1; ;} break; case 30: #line 944 "parser.y" { #ifdef PARSER_DEBUG fprintf (stderr, "Adding shape spec for \'%s\' (width %d " "height %d)\n", shape_name[yyvsp[-1].shape], yyvsp[0].sentry.width, yyvsp[0].sentry.height); #endif if (isempty (designs[design_idx].shape + yyvsp[-1].shape)) { designs[design_idx].shape[yyvsp[-1].shape] = yyvsp[0].sentry; if (!isdeepempty(&(yyvsp[0].sentry))) ++anz_shapespec; } else { yyerror ("duplicate specification for %s shape", shape_name[yyvsp[-1].shape]); YYERROR; } ;} break; case 31: #line 964 "parser.y" { if (yyvsp[-1].sentry.width == 0 || yyvsp[-1].sentry.height == 0) { yyerror ("minimum shape dimension is 1x1 - clearing"); freeshape (&(yyvsp[-1].sentry)); } yyval.sentry = yyvsp[-1].sentry; ;} break; case 32: #line 973 "parser.y" { yyval.sentry = SENTRY_INITIALIZER; ;} break; case 33: #line 980 "parser.y" { sentry_t rval = yyvsp[-2].sentry; size_t slen = strlen (yyvsp[0].s); char **tmp; #ifdef PARSER_DEBUG fprintf (stderr, "Extending a shape entry\n"); #endif if (slen != rval.width) { yyerror ("all elements of a shape spec must be of equal length"); YYERROR; } rval.height++; tmp = (char **) realloc (rval.chars, rval.height*sizeof(char*)); if (tmp == NULL) { perror (PROJECT": shape_lines11"); YYABORT; } rval.chars = tmp; rval.chars[rval.height-1] = (char *) strdup (yyvsp[0].s); if (rval.chars[rval.height-1] == NULL) { perror (PROJECT": shape_lines12"); YYABORT; } yyval.sentry = rval; ;} break; case 34: #line 1010 "parser.y" { sentry_t rval = SENTRY_INITIALIZER; #ifdef PARSER_DEBUG fprintf (stderr, "Initializing a shape entry with first line\n"); #endif rval.width = strlen (yyvsp[0].s); rval.height = 1; rval.chars = (char **) malloc (sizeof(char*)); if (rval.chars == NULL) { perror (PROJECT": shape_lines21"); YYABORT; } rval.chars[0] = (char *) strdup (yyvsp[0].s); if (rval.chars[0] == NULL) { perror (PROJECT": shape_lines22"); YYABORT; } yyval.sentry = rval; ;} break; case 37: #line 1038 "parser.y" { if (yyvsp[0].num < 0) { yyerror ("padding must be a positive integer (%s %d) (ignored)", yyvsp[-1].s, yyvsp[0].num); } else { size_t len1 = strlen (yyvsp[-1].s); if (len1 <= 3 && !strncasecmp ("all", yyvsp[-1].s, len1)) { designs[design_idx].padding[BTOP] = yyvsp[0].num; designs[design_idx].padding[BBOT] = yyvsp[0].num; designs[design_idx].padding[BLEF] = yyvsp[0].num; designs[design_idx].padding[BRIG] = yyvsp[0].num; } else if (len1 <= 10 && !strncasecmp ("horizontal", yyvsp[-1].s, len1)) { designs[design_idx].padding[BRIG] = yyvsp[0].num; designs[design_idx].padding[BLEF] = yyvsp[0].num; } else if (len1 <= 8 && !strncasecmp ("vertical", yyvsp[-1].s, len1)) { designs[design_idx].padding[BTOP] = yyvsp[0].num; designs[design_idx].padding[BBOT] = yyvsp[0].num; } else if (len1 <= 3 && !strncasecmp ("top", yyvsp[-1].s, len1)) { designs[design_idx].padding[BTOP] = yyvsp[0].num; } else if (len1 <= 5 && !strncasecmp ("right", yyvsp[-1].s, len1)) { designs[design_idx].padding[BRIG] = yyvsp[0].num; } else if (len1 <= 4 && !strncasecmp ("left", yyvsp[-1].s, len1)) { designs[design_idx].padding[BLEF] = yyvsp[0].num; } else if (len1 <= 6 && !strncasecmp ("bottom", yyvsp[-1].s, len1)) { designs[design_idx].padding[BBOT] = yyvsp[0].num; } else { yyerror ("invalid padding area %s (ignored)", yyvsp[-1].s); } } ;} break; } /* Line 991 of yacc.c. */ #line 2125 "parser.c" yyvsp -= yylen; yyssp -= yylen; YY_STACK_PRINT (yyss, yyssp); *++yyvsp = yyval; /* Now `shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ yyn = yyr1[yyn]; yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) yystate = yytable[yystate]; else yystate = yydefgoto[yyn - YYNTOKENS]; goto yynewstate; /*------------------------------------. | yyerrlab -- here on detecting error | `------------------------------------*/ yyerrlab: /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; #if YYERROR_VERBOSE yyn = yypact[yystate]; if (YYPACT_NINF < yyn && yyn < YYLAST) { YYSIZE_T yysize = 0; int yytype = YYTRANSLATE (yychar); char *yymsg; int yyx, yycount; yycount = 0; /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. */ for (yyx = yyn < 0 ? -yyn : 0; yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++) if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) yysize += yystrlen (yytname[yyx]) + 15, yycount++; yysize += yystrlen ("syntax error, unexpected ") + 1; yysize += yystrlen (yytname[yytype]); yymsg = (char *) YYSTACK_ALLOC (yysize); if (yymsg != 0) { char *yyp = yystpcpy (yymsg, "syntax error, unexpected "); yyp = yystpcpy (yyp, yytname[yytype]); if (yycount < 5) { yycount = 0; for (yyx = yyn < 0 ? -yyn : 0; yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++) if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) { const char *yyq = ! yycount ? ", expecting " : " or "; yyp = yystpcpy (yyp, yyq); yyp = yystpcpy (yyp, yytname[yyx]); yycount++; } } yyerror (yymsg); YYSTACK_FREE (yymsg); } else yyerror ("syntax error; also virtual memory exhausted"); } else #endif /* YYERROR_VERBOSE */ yyerror ("syntax error"); } if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ /* Return failure if at end of input. */ if (yychar == YYEOF) { /* Pop the error token. */ YYPOPSTACK; /* Pop the rest of the stack. */ while (yyss < yyssp) { YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp); yydestruct (yystos[*yyssp], yyvsp); YYPOPSTACK; } YYABORT; } YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc); yydestruct (yytoken, &yylval); yychar = YYEMPTY; } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab2; /*----------------------------------------------------. | yyerrlab1 -- error raised explicitly by an action. | `----------------------------------------------------*/ yyerrlab1: /* Suppress GCC warning that yyerrlab1 is unused when no action invokes YYERROR. */ #if defined (__GNUC_MINOR__) && 2093 <= (__GNUC__ * 1000 + __GNUC_MINOR__) \ && !defined __cplusplus __attribute__ ((__unused__)) #endif goto yyerrlab2; /*---------------------------------------------------------------. | yyerrlab2 -- pop states until the error token can be shifted. | `---------------------------------------------------------------*/ yyerrlab2: yyerrstatus = 3; /* Each real token shifted decrements this. */ for (;;) { yyn = yypact[yystate]; if (yyn != YYPACT_NINF) { yyn += YYTERROR; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp); yydestruct (yystos[yystate], yyvsp); yyvsp--; yystate = *--yyssp; YY_STACK_PRINT (yyss, yyssp); } if (yyn == YYFINAL) YYACCEPT; YYDPRINTF ((stderr, "Shifting error token, ")); *++yyvsp = yylval; yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturn; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturn; #ifndef yyoverflow /*----------------------------------------------. | yyoverflowlab -- parser overflow comes here. | `----------------------------------------------*/ yyoverflowlab: yyerror ("parser stack overflow"); yyresult = 2; /* Fall through. */ #endif yyreturn: #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif return yyresult; } #line 1079 "parser.y" /*EOF*/ /* vim: set sw=4 cindent: */ boxes-1.1.1/src/parser.h0100644000175000001440000000471212040302150014626 0ustar tsjensenusers/* A Bison parser, made by GNU Bison 1.875. */ /* Skeleton parser for Yacc-like parsing with Bison, Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* As a special exception, when this file is copied by Bison into a Bison output file, you may use that output file without restriction. This special exception was added by the Free Software Foundation in version 1.24 of Bison. */ /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE /* Put the tokens into the symbol table, so that GDB and other debuggers know about them. */ enum yytokentype { YSHAPES = 258, YELASTIC = 259, YPADDING = 260, YSAMPLE = 261, YENDSAMPLE = 262, YBOX = 263, YEND = 264, YUNREC = 265, YREPLACE = 266, YREVERSE = 267, YTO = 268, YWITH = 269, YCHGDEL = 270, KEYWORD = 271, WORD = 272, STRING = 273, SHAPE = 274, YNUMBER = 275, YRXPFLAG = 276, YDELWORD = 277 }; #endif #define YSHAPES 258 #define YELASTIC 259 #define YPADDING 260 #define YSAMPLE 261 #define YENDSAMPLE 262 #define YBOX 263 #define YEND 264 #define YUNREC 265 #define YREPLACE 266 #define YREVERSE 267 #define YTO 268 #define YWITH 269 #define YCHGDEL 270 #define KEYWORD 271 #define WORD 272 #define STRING 273 #define SHAPE 274 #define YNUMBER 275 #define YRXPFLAG 276 #define YDELWORD 277 #if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) #line 416 "parser.y" typedef union YYSTYPE { char *s; char c; shape_t shape; sentry_t sentry; int num; } YYSTYPE; /* Line 1249 of yacc.c. */ #line 88 "parser.h" # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 # define YYSTYPE_IS_TRIVIAL 1 #endif extern YYSTYPE yylval; boxes-1.1.1/src/parser.y0100644000175000001440000010032010460717755014670 0ustar tsjensenusers%{ /* * File: parser.y * Date created: March 16, 1999 (Tuesday, 17:17h) * Author: Copyright (C) 1999 Thomas Jensen * Version: $Id: parser.y,v 1.25 2006/07/23 16:11:39 tsjensen Exp $ * Language: GNU bison (ANSI C) * World Wide Web: http://boxes.thomasjensen.com/ * Purpose: Yacc parser for boxes configuration files * * Remarks: o This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * o This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * o You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * Revision History: * * $Log: parser.y,v $ * Revision 1.25 2006/07/23 16:11:39 tsjensen * Removed unsigned modifier from a pointer declaration in order to clear a warning * which appeared on some Linuxes (reported by Andreas Heiduk) * * Revision 1.24 2006/07/22 19:30:55 tsjensen * Fix: Renamed yylineno to tjlineno to enable compilation on certain * flexes (reported by Andreas Heiduk) * * Revision 1.23 2006/07/12 05:31:25 tsjensen * Updated email and web addresses in comment header * * Revision 1.22 1999-08-21 08:53:58-07 tsjensen * Removed check for empty sample block, which is also done in lexer.l * * Revision 1.21 1999/08/18 15:38:44 tsjensen * Added new tokens YCHGDEL and YDELWORD * Added code for DELIMITER statements * * Revision 1.20 1999/08/16 16:29:25 tsjensen * Changed SAMPLE block syntax to get rid of all the quoting sh*t in SAMPLE * blocks. Samples now look authentic even in the config file. Very simple now. * Added new token YENDSAMPLE in the process. * * Revision 1.19 1999/08/14 19:19:25 tsjensen * Added anz_shapespec variable to count non-deepempty user-specified shapes * (must at least be 1) * Moved yylex declaration to lexer.h, where it belongs * Bugfix: bison and yacc seem to differ in the way action code is treated * which is associated with an error token. Since bison calls the action * routine whenever a token is skipped while recovering, added skipping * variable to ensure that only one "skipping to next design" message is * printed. That was not necessary before. %-/ * Removed existence check from corner_check() routine (obsolete). * Added code to generate required shapes which were not specified by the user * Clean-up in shape_def rule (use freeshape() and some more) * * Revision 1.18 1999/07/23 16:14:17 tsjensen * Added computation of height of highest shape in design (maxshapeheight) * Options -l and -d together now call quickinfo mode -> parse only 1 design * * Revision 1.17 1999/07/22 12:27:16 tsjensen * Added GNU GPL disclaimer * Renamed parser.h include to lexer.h (same file) * Added include config.h * * Revision 1.16 1999/07/02 11:54:52 tsjensen * Some minor changes to please compiler * Communication of speed mode to lexer * Bugfix: Forgot to check for opt.l before calling YYACCEPT * * Revision 1.15 1999/06/30 12:13:47 tsjensen * Now parsing only those designs which will be needed later on * Checks formerly done in boxes.c now done here (no valid designs etc.) * * Revision 1.14 1999/06/28 18:32:51 tsjensen * Unified appearance of error messages, which are now all based on yyerror() * Eliminated duplicate code by introducing intermediate rules * New tokens YTO, YWITH, and YRXPFLAG to reduce strcasecmp() usage * New token YUNREC for integration of lexer into error handling * Some code restructuring and rule renaming for better consistency * Added out-of-memory-checks to many strdup()s and such * * Revision 1.13 1999/06/28 12:15:47 tsjensen * Added error handling. Now skips to next design on error. * Replaced DEBUG macro with PARSER_DEBUG, which is now activated in boxes.h * Added rule first_rule, which performs init and cleanup formerly done in main() * Introduced symbols YBOX and YEND * * Revision 1.12 1999/06/22 12:01:01 tsjensen * Added #undef DEBUG, because DEBUGging is now activated in boxes.h * Added #include tools.h * * Revision 1.11 1999/06/20 14:18:51 tsjensen * Adden YPADDING and YNUMBER tokens plus code for padding blocks * * Revision 1.10 1999/06/17 19:04:45 tsjensen * Added detection of empty sample blocks (we don't want that) * Added detection of duplicate sample blocks * * Revision 1.9 1999/06/14 12:13:01 tsjensen * Added YREVERSE token * Added code for regexp reversion * * Revision 1.7 1999/04/09 13:31:54 tsjensen * Added checks for duplicate design names * Added checks for valid design names (no extended ASCII or ctrl chars) * Removed all code related to OFFSET blocks (obsolete) * * Revision 1.6 1999/04/04 16:07:53 tsjensen * Enforced use of PROJECT macro * Added "indent" directive to grammar * Added "replace" directive to grammar * * Revision 1.5 1999/03/30 13:29:50 tsjensen * Added computation of minimum width/height of each design. * * Revision 1.4 1999/03/30 09:37:51 tsjensen * It drew a correct box for the first time! * * Revision 1.3 1999/03/24 17:29:12 tsjensen * Added detection of empty shapes ("") which are now cleared (+warning) * Changed rcs string to #ident directive * * Revision 1.1 1999/03/18 15:10:06 tsjensen * Initial revision * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "config.h" #include #include #include #include "shape.h" #include "boxes.h" #include "tools.h" #include "lexer.h" const char rcsid_parser_y[] = "$Id: parser.y,v 1.25 2006/07/23 16:11:39 tsjensen Exp $"; static int pflicht = 0; static int time_for_se_check = 0; static int anz_shapespec = 0; /* number of user-specified shapes */ int speeding = 0; /* true if we're skipping designs, */ /* but no error */ static int skipping = 0; /* used to limit "skipping" msgs */ static int check_sizes() /* * For the author's convenience, it is required that shapes on one side * have equal width (vertical sides) and height (horizontal sides). * * RETURNS: == 0 no problem detected * != 0 on error (prints error message, too) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { int i, j, k; #ifdef PARSER_DEBUG fprintf (stderr, "check_sizes()\n"); #endif for (i=0; i KEYWORD %token WORD %token STRING %token SHAPE %token YNUMBER %token YRXPFLAG %token YDELWORD %type shape_def %type shape_lines %type rflag %start first_rule %% first_rule: { /* * Initialize parser data structures */ designs = (design_t *) calloc (1, sizeof(design_t)); if (designs == NULL) { perror (PROJECT); YYABORT; } designs->indentmode = DEF_INDENTMODE; } config_file { /* * Clean up parser data structures */ design_t *tmp; if (design_idx == 0) { BFREE (designs); anz_designs = 0; if (opt.design_choice_by_user) { fprintf (stderr, "%s: unknown box design -- %s\n", PROJECT, (char *) opt.design); } else { yyerror ("no valid designs found"); } YYABORT; } --design_idx; anz_designs = design_idx + 1; tmp = (design_t *) realloc (designs, anz_designs*sizeof(design_t)); if (!tmp) { perror (PROJECT); YYABORT; } designs = tmp; } ; config_file: config_file design_or_error | design_or_error ; design_or_error: design | error { if (!speeding && !skipping) { recover(); yyerror ("skipping to next design"); skipping = 1; } } ; design: YBOX WORD { chg_strdelims ('\\', '\"'); skipping = 0; if (!design_needed ($2, design_idx)) { speeding = 1; begin_speedmode(); YYERROR; } } layout YEND WORD { design_t *tmp; int i; char *p; #ifdef PARSER_DEBUG fprintf (stderr, "--------- ADDING DESIGN \"%s\".\n", $2); #endif if (strcasecmp ($2, $6)) { yyerror ("box design name differs at BOX and END"); YYERROR; } if (pflicht < 3) { yyerror ("entries SAMPLE, SHAPES, and ELASTIC are mandatory"); YYERROR; } for (i=0; i 126) { yyerror ("box design name must consist of printable standard " "ASCII characters."); YYERROR; } ++p; } designs[design_idx].name = (char *) strdup ($2); if (designs[design_idx].name == NULL) { perror (PROJECT); YYABORT; } pflicht = 0; time_for_se_check = 0; anz_shapespec = 0; /* * Check if we need to continue parsing. If not, return. * The condition here must correspond to design_needed(). */ if (opt.design_choice_by_user || (!opt.r && !opt.l)) { anz_designs = design_idx + 1; YYACCEPT; } /* * Allocate space for next design */ ++design_idx; tmp = (design_t *) realloc (designs, (design_idx+1)*sizeof(design_t)); if (tmp == NULL) { perror (PROJECT); YYABORT; } designs = tmp; memset (&(designs[design_idx]), 0, sizeof(design_t)); designs[design_idx].indentmode = DEF_INDENTMODE; } ; layout: layout entry | layout block | entry | block ; entry: KEYWORD STRING { #ifdef PARSER_DEBUG fprintf (stderr, "entry rule fulfilled [%s = %s]\n", $1, $2); #endif if (strcasecmp ($1, "author") == 0) { designs[design_idx].author = (char *) strdup ($2); if (designs[design_idx].author == NULL) { perror (PROJECT); YYABORT; } } else if (strcasecmp ($1, "revision") == 0) { designs[design_idx].revision = (char *) strdup ($2); if (designs[design_idx].revision == NULL) { perror (PROJECT); YYABORT; } } else if (strcasecmp ($1, "created") == 0) { designs[design_idx].created = (char *) strdup ($2); if (designs[design_idx].created == NULL) { perror (PROJECT); YYABORT; } } else if (strcasecmp ($1, "revdate") == 0) { designs[design_idx].revdate = (char *) strdup ($2); if (designs[design_idx].revdate == NULL) { perror (PROJECT); YYABORT; } } else if (strcasecmp ($1, "indent") == 0) { if (strcasecmp ($2, "text") == 0 || strcasecmp ($2, "box") == 0 || strcasecmp ($2, "none") == 0) { designs[design_idx].indentmode = $2[0]; } else { yyerror ("indent keyword must be followed by \"text\", " "\"box\", or \"none\""); YYERROR; } } else { yyerror ("internal parser error (unrecognized: %s) in line %d " "of %s.", $1, __LINE__, __FILE__); YYERROR; } } | YCHGDEL YDELWORD { if (strlen($2) != 2) { yyerror ("invalid string delimiter specification -- %s", $2); YYERROR; } if (($2)[0] == ($2)[1]) { yyerror ("string delimiter and escape char may not be the same"); YYERROR; } if (strchr (LEX_SDELIM, ($2)[1]) == NULL) { yyerror ("invalid string delimiter -- %c (try one of %s)", ($2)[1], LEX_SDELIM); YYERROR; } chg_strdelims ($2[0], $2[1]); } | WORD STRING { #ifdef PARSER_DEBUG fprintf (stderr, "%s: Discarding entry [%s = %s].\n", PROJECT, $1, $2); #endif } ; block: YSAMPLE STRING YENDSAMPLE { /* * SAMPLE block (STRING is non-empty if we get here) */ char *line; #ifdef PARSER_DEBUG fprintf (stderr, "SAMPLE block rule satisfied\n"); #endif if (designs[design_idx].sample) { yyerror ("duplicate SAMPLE block"); YYERROR; } line = (char *) strdup ($2); if (line == NULL) { perror (PROJECT); YYABORT; } designs[design_idx].sample = line; ++pflicht; } | YSHAPES '{' slist '}' { int i,j; shape_t fshape; /* found shape */ int fside; /* first side */ int sc; /* side counter */ int side; /* effective side */ int rc; /* received return code */ /* * At least one shape must be specified */ if (anz_shapespec < 1) { yyerror ("must specify at least one non-empty shape per design"); YYERROR; } /* * Ensure that all corners have been specified. Generate corners * as necessary, starting at any side which already includes at * least one shape in order to ensure correct measurements. */ fshape = findshape (designs[design_idx].shape, ANZ_SHAPES); if (fshape == ANZ_SHAPES) { yyerror ("internal error"); YYABORT; /* never happens ;-) */ } fside = on_side (fshape, 0); if (fside == ANZ_SIDES) { yyerror ("internal error"); YYABORT; /* never happens ;-) */ } for (sc=0,side=fside; scheight = 1; else c->height = c[nshape].height; c->width = designs[design_idx].shape[fshape].width; } else { if (nshape == SHAPES_PER_SIDE) c->width = 1; else c->width = c[nshape].width; c->height = designs[design_idx].shape[fshape].height; } c->elastic = 0; rc = genshape (c->width, c->height, &(c->chars)); if (rc) YYABORT; } fshape = sides[side][SHAPES_PER_SIDE-1]; } /* * For all sides whose side shapes have not been defined, generate * an elastic middle side shape. */ for (side=0; sidewidth = designs[design_idx].shape[sides[side][0]].width; c->height = 1; } else { c->width = 1; c->height = designs[design_idx].shape[sides[side][0]].height; } c->elastic = 1; rc = genshape (c->width, c->height, &(c->chars)); if (rc) YYABORT; } } if (check_sizes()) YYERROR; ++pflicht; if (++time_for_se_check > 1) { if (perform_se_check() != 0) YYERROR; } /* * Compute minimum height/width of a box of current design */ for (i=0; i designs[design_idx].minheight) designs[design_idx].minheight = c; } else { /* horizontal sides */ for (j=0; j designs[design_idx].minwidth) designs[design_idx].minwidth = c; } } /* * Compute height of highest shape in design */ for (i=0; i designs[design_idx].maxshapeheight) designs[design_idx].maxshapeheight = designs[design_idx].shape[i].height; } #ifdef PARSER_DEBUG fprintf (stderr, "Minimum box dimensions: width %d height %d\n", designs[design_idx].minwidth, designs[design_idx].minheight); fprintf (stderr, "Maximum shape height: %d\n", designs[design_idx].maxshapeheight); #endif } | YELASTIC '(' elist ')' { ++pflicht; if (++time_for_se_check > 1) { if (perform_se_check() != 0) YYERROR; } } | YREPLACE rflag STRING YWITH STRING { int a = designs[design_idx].anz_reprules; #ifdef PARSER_DEBUG fprintf (stderr, "Adding replacement rule: \"%s\" with \"%s\" (%c)\n", $3, $5, $2); #endif designs[design_idx].reprules = (reprule_t *) realloc (designs[design_idx].reprules, (a+1) * sizeof(reprule_t)); if (designs[design_idx].reprules == NULL) { perror (PROJECT); YYABORT; } memset (&(designs[design_idx].reprules[a]), 0, sizeof(reprule_t)); designs[design_idx].reprules[a].search = (char *) strdup ($3); designs[design_idx].reprules[a].repstr = (char *) strdup ($5); if (designs[design_idx].reprules[a].search == NULL || designs[design_idx].reprules[a].repstr == NULL) { perror (PROJECT); YYABORT; } designs[design_idx].reprules[a].line = tjlineno; designs[design_idx].reprules[a].mode = $2; designs[design_idx].anz_reprules = a + 1; } | YREVERSE rflag STRING YTO STRING { int a = designs[design_idx].anz_revrules; #ifdef PARSER_DEBUG fprintf (stderr, "Adding reversion rule: \"%s\" to \"%s\" (%c)\n", $3, $5, $2); #endif designs[design_idx].revrules = (reprule_t *) realloc (designs[design_idx].revrules, (a+1) * sizeof(reprule_t)); if (designs[design_idx].revrules == NULL) { perror (PROJECT); YYABORT; } memset (&(designs[design_idx].revrules[a]), 0, sizeof(reprule_t)); designs[design_idx].revrules[a].search = (char *) strdup ($3); designs[design_idx].revrules[a].repstr = (char *) strdup ($5); if (designs[design_idx].revrules[a].search == NULL || designs[design_idx].revrules[a].repstr == NULL) { perror (PROJECT); YYABORT; } designs[design_idx].revrules[a].line = tjlineno; designs[design_idx].revrules[a].mode = $2; designs[design_idx].anz_revrules = a + 1; } | YPADDING '{' wlist '}' { #ifdef PARSER_DEBUG fprintf (stderr, "Padding set to (l%d o%d r%d u%d)\n", designs[design_idx].padding[BLEF], designs[design_idx].padding[BTOP], designs[design_idx].padding[BRIG], designs[design_idx].padding[BBOT]); #endif } ; rflag: YRXPFLAG { $$ = $1; } | { $$ = 'g'; } ; elist: elist ',' elist_entry | elist_entry; elist_entry: SHAPE { #ifdef PARSER_DEBUG fprintf (stderr, "Marked \'%s\' shape as elastic\n", shape_name[(int)$1]); #endif designs[design_idx].shape[$1].elastic = 1; } ; slist: slist slist_entry | slist_entry ; slist_entry: SHAPE shape_def { #ifdef PARSER_DEBUG fprintf (stderr, "Adding shape spec for \'%s\' (width %d " "height %d)\n", shape_name[$1], $2.width, $2.height); #endif if (isempty (designs[design_idx].shape + $1)) { designs[design_idx].shape[$1] = $2; if (!isdeepempty(&($2))) ++anz_shapespec; } else { yyerror ("duplicate specification for %s shape", shape_name[$1]); YYERROR; } } ; shape_def: '(' shape_lines ')' { if ($2.width == 0 || $2.height == 0) { yyerror ("minimum shape dimension is 1x1 - clearing"); freeshape (&($2)); } $$ = $2; } | '(' ')' { $$ = SENTRY_INITIALIZER; } ; shape_lines: shape_lines ',' STRING { sentry_t rval = $1; size_t slen = strlen ($3); char **tmp; #ifdef PARSER_DEBUG fprintf (stderr, "Extending a shape entry\n"); #endif if (slen != rval.width) { yyerror ("all elements of a shape spec must be of equal length"); YYERROR; } rval.height++; tmp = (char **) realloc (rval.chars, rval.height*sizeof(char*)); if (tmp == NULL) { perror (PROJECT": shape_lines11"); YYABORT; } rval.chars = tmp; rval.chars[rval.height-1] = (char *) strdup ($3); if (rval.chars[rval.height-1] == NULL) { perror (PROJECT": shape_lines12"); YYABORT; } $$ = rval; } | STRING { sentry_t rval = SENTRY_INITIALIZER; #ifdef PARSER_DEBUG fprintf (stderr, "Initializing a shape entry with first line\n"); #endif rval.width = strlen ($1); rval.height = 1; rval.chars = (char **) malloc (sizeof(char*)); if (rval.chars == NULL) { perror (PROJECT": shape_lines21"); YYABORT; } rval.chars[0] = (char *) strdup ($1); if (rval.chars[0] == NULL) { perror (PROJECT": shape_lines22"); YYABORT; } $$ = rval; } ; wlist: wlist wlist_entry | wlist_entry; wlist_entry: WORD YNUMBER { if ($2 < 0) { yyerror ("padding must be a positive integer (%s %d) (ignored)", $1, $2); } else { size_t len1 = strlen ($1); if (len1 <= 3 && !strncasecmp ("all", $1, len1)) { designs[design_idx].padding[BTOP] = $2; designs[design_idx].padding[BBOT] = $2; designs[design_idx].padding[BLEF] = $2; designs[design_idx].padding[BRIG] = $2; } else if (len1 <= 10 && !strncasecmp ("horizontal", $1, len1)) { designs[design_idx].padding[BRIG] = $2; designs[design_idx].padding[BLEF] = $2; } else if (len1 <= 8 && !strncasecmp ("vertical", $1, len1)) { designs[design_idx].padding[BTOP] = $2; designs[design_idx].padding[BBOT] = $2; } else if (len1 <= 3 && !strncasecmp ("top", $1, len1)) { designs[design_idx].padding[BTOP] = $2; } else if (len1 <= 5 && !strncasecmp ("right", $1, len1)) { designs[design_idx].padding[BRIG] = $2; } else if (len1 <= 4 && !strncasecmp ("left", $1, len1)) { designs[design_idx].padding[BLEF] = $2; } else if (len1 <= 6 && !strncasecmp ("bottom", $1, len1)) { designs[design_idx].padding[BBOT] = $2; } else { yyerror ("invalid padding area %s (ignored)", $1); } } } ; %% /*EOF*/ /* vim: set sw=4 cindent: */ boxes-1.1.1/src/lex.yy.c0100644000175000001440000016562212040302150014565 0ustar tsjensenusers#include "config.h" /* A lexical scanner generated by flex */ /* Scanner skeleton version: * $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $ */ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 5 #include /* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ #ifdef c_plusplus #ifndef __cplusplus #define __cplusplus #endif #endif #ifdef __cplusplus #include #include /* Use prototypes in function declarations. */ #define YY_USE_PROTOS /* The "const" storage-class-modifier is valid. */ #define YY_USE_CONST #else /* ! __cplusplus */ #if __STDC__ #define YY_USE_PROTOS #define YY_USE_CONST #endif /* __STDC__ */ #endif /* ! __cplusplus */ #ifdef __TURBOC__ #pragma warn -rch #pragma warn -use #include #include #define YY_USE_CONST #define YY_USE_PROTOS #endif #ifdef YY_USE_CONST #define yyconst const #else #define yyconst #endif #ifdef YY_USE_PROTOS #define YY_PROTO(proto) proto #else #define YY_PROTO(proto) () #endif /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an unsigned * integer for use as an array index. If the signed char is negative, * we want to instead treat it as an 8-bit unsigned char, hence the * double cast. */ #define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN yy_start = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START ((yy_start - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE yyrestart( yyin ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #define YY_BUF_SIZE 16384 typedef struct yy_buffer_state *YY_BUFFER_STATE; extern int yyleng; extern FILE *yyin, *yyout; #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 /* The funky do-while in the following #define is used to turn the definition * int a single C statement (which needs a semi-colon terminator). This * avoids problems with code like: * * if ( condition_holds ) * yyless( 5 ); * else * do_something_else(); * * Prior to using the do-while the compiler would get upset at the * "else" because it interpreted the "if" statement as being all * done when it reached the ';' after the yyless() call. */ /* Return all but the first 'n' matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ *yy_cp = yy_hold_char; \ YY_RESTORE_YY_MORE_OFFSET \ yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, yytext_ptr ) /* The following is because we cannot portably get our hands on size_t * (without autoconf's help, which isn't available because we want * flex-generated scanners to compile on their own). */ typedef unsigned int yy_size_t; struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ yy_size_t yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via yyrestart()), so that the user can continue scanning by * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; static YY_BUFFER_STATE yy_current_buffer = 0; /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". */ #define YY_CURRENT_BUFFER yy_current_buffer /* yy_hold_char holds the character lost when yytext is formed. */ static char yy_hold_char; static int yy_n_chars; /* number of characters read into yy_ch_buf */ int yyleng; /* Points to current character in buffer. */ static char *yy_c_buf_p = (char *) 0; static int yy_init = 1; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ /* Flag which is used to allow yywrap()'s to do buffer switches * instead of setting up a fresh yyin. A bit of a hack ... */ static int yy_did_buffer_switch_on_eof; void yyrestart YY_PROTO(( FILE *input_file )); void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); void yy_load_buffer_state YY_PROTO(( void )); YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); #define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size )); YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); static void *yy_flex_alloc YY_PROTO(( yy_size_t )); static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )); static void yy_flex_free YY_PROTO(( void * )); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! yy_current_buffer ) \ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ yy_current_buffer->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! yy_current_buffer ) \ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ yy_current_buffer->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (yy_current_buffer->yy_at_bol) #define YY_USES_REJECT #define yywrap() 1 #define YY_SKIP_YYWRAP typedef unsigned char YY_CHAR; FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; typedef int yy_state_type; extern char *yytext; #define yytext_ptr yytext static yy_state_type yy_get_previous_state YY_PROTO(( void )); static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); static int yy_get_next_buffer YY_PROTO(( void )); static void yy_fatal_error YY_PROTO(( yyconst char msg[] )); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ yytext_ptr = yy_bp; \ yytext_ptr -= yy_more_len; \ yyleng = (int) (yy_cp - yytext_ptr); \ yy_hold_char = *yy_cp; \ *yy_cp = '\0'; \ yy_c_buf_p = yy_cp; #define YY_NUM_RULES 49 #define YY_END_OF_BUFFER 50 static yyconst short int yy_acclist[238] = { 0, 50, 45, 49, 1, 45, 49, 2, 49, 45, 49, 45, 49, 43, 45, 49, 45, 49, 42, 45, 49, 41, 45, 49, 41, 45, 49, 41, 45, 49, 41, 45, 49, 41, 45, 49, 41, 45, 49, 41, 45, 49, 41, 45, 49, 41, 45, 49, 41, 45, 49, 41, 45, 49, 41, 45, 49, 41, 45, 49, 41, 45, 49, 8, 49, 6, 49, 8, 49, 8, 49, 48, 49, 47, 49, 48, 49, 3, 49, 1, 49, 27, 41, 45, 49, 23, 41, 45, 49, 31, 41, 45, 49, 35, 41, 45, 49, 38, 43, 45, 49, 37, 43, 45, 49, 4, 44, 42, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 17, 41, 41, 3, 41, 41, 25, 41, 41, 21, 41, 29, 41, 41, 33, 41, 41, 41, 41, 12, 41, 41, 41, 41, 16, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 26, 41, 28, 41, 24, 41, 22, 41, 30, 41, 32, 41, 36, 41, 34, 41, 41, 41, 41, 41, 41, 41, 41, 20, 41, 41, 41, 41, 41, 41, 41, 41, 18, 41, 41, 41, 40, 41, 41, 9, 41, 41, 41, 41, 41, 41, 41, 41, 41, 7, 46, 39, 41, 41, 41, 41, 19, 41, 41, 41, 41, 41, 41, 5, 41, 11, 41, 46, 41, 10, 41, 15, 41, 13, 41, 14, 41, 41, 41, 40, 41 } ; static yyconst short int yy_accept[171] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 7, 9, 11, 13, 16, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 85, 89, 93, 97, 101, 105, 105, 106, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 124, 125, 125, 125, 125, 125, 126, 127, 128, 130, 131, 133, 135, 136, 138, 139, 140, 141, 143, 144, 145, 146, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 157, 157, 159, 161, 163, 165, 167, 169, 171, 173, 174, 175, 176, 177, 178, 179, 180, 182, 183, 184, 185, 186, 187, 188, 189, 191, 191, 191, 192, 193, 195, 196, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 206, 207, 208, 210, 211, 212, 213, 215, 216, 217, 218, 219, 220, 222, 224, 225, 226, 228, 230, 232, 234, 235, 236, 238, 238 } ; static yyconst int yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 5, 5, 6, 1, 5, 5, 5, 7, 8, 5, 9, 7, 10, 5, 5, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 5, 5, 5, 5, 5, 5, 5, 13, 14, 15, 16, 17, 18, 19, 20, 21, 18, 18, 22, 23, 24, 25, 26, 18, 27, 28, 29, 30, 31, 32, 33, 18, 18, 1, 5, 1, 1, 12, 5, 13, 14, 15, 16, 17, 18, 19, 20, 21, 18, 18, 22, 23, 24, 25, 26, 18, 27, 28, 29, 30, 31, 32, 33, 18, 18, 7, 5, 34, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 1, 1, 1, 1, 1, 18, 1, 1, 12, 1, 1, 1, 1, 18, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 1, 1, 1, 1, 1, 18, 1, 1, 1 } ; static yyconst int yy_meta[35] = { 0, 1, 2, 2, 2, 1, 1, 1, 1, 1, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1 } ; static yyconst short int yy_base[179] = { 0, 0, 0, 236, 33, 34, 35, 37, 40, 28, 29, 47, 50, 238, 240, 240, 240, 234, 233, 240, 224, 223, 203, 207, 204, 213, 44, 0, 207, 204, 203, 213, 208, 34, 199, 202, 240, 240, 63, 198, 240, 240, 196, 0, 240, 48, 60, 68, 62, 240, 240, 217, 240, 216, 240, 207, 0, 188, 183, 198, 192, 200, 196, 186, 194, 194, 192, 63, 184, 193, 0, 176, 85, 180, 187, 169, 0, 81, 184, 0, 74, 0, 0, 76, 0, 168, 167, 178, 0, 184, 175, 167, 166, 179, 175, 174, 174, 167, 88, 162, 161, 166, 157, 108, 0, 0, 0, 0, 0, 0, 0, 0, 159, 154, 159, 152, 111, 167, 155, 0, 157, 164, 163, 148, 146, 151, 155, 0, 114, 117, 144, 153, 148, 147, 120, 240, 145, 137, 141, 149, 134, 134, 140, 143, 131, 123, 240, 0, 0, 139, 122, 92, 0, 84, 84, 82, 78, 48, 0, 0, 0, 52, 0, 0, 0, 0, 35, 24, 0, 240, 127, 131, 135, 139, 143, 145, 149, 152, 154 } ; static yyconst short int yy_def[179] = { 0, 169, 1, 170, 170, 171, 171, 172, 172, 1, 1, 1, 1, 169, 169, 169, 169, 173, 174, 169, 169, 169, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 169, 169, 169, 169, 169, 169, 169, 176, 169, 175, 175, 175, 175, 169, 169, 173, 169, 174, 169, 169, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 169, 169, 169, 169, 176, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 169, 169, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 169, 177, 175, 175, 175, 175, 169, 169, 175, 175, 175, 175, 175, 175, 175, 175, 175, 169, 169, 178, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 178, 175, 175, 175, 175, 175, 175, 175, 175, 0, 169, 169, 169, 169, 169, 169, 169, 169, 169 } ; static yyconst short int yy_nxt[275] = { 0, 14, 15, 16, 15, 17, 18, 19, 19, 20, 20, 21, 14, 22, 23, 24, 25, 26, 27, 28, 27, 29, 27, 27, 27, 30, 31, 32, 33, 34, 27, 27, 35, 27, 19, 38, 37, 41, 41, 44, 16, 44, 44, 16, 44, 45, 45, 68, 42, 42, 39, 168, 46, 46, 69, 50, 47, 47, 50, 148, 48, 48, 49, 49, 45, 72, 61, 45, 62, 167, 61, 46, 77, 166, 46, 47, 78, 79, 47, 48, 73, 68, 48, 71, 80, 82, 85, 72, 69, 97, 86, 106, 81, 108, 98, 165, 83, 92, 104, 148, 84, 164, 73, 163, 122, 123, 107, 162, 109, 124, 129, 129, 129, 134, 135, 134, 145, 146, 145, 129, 129, 129, 134, 135, 134, 145, 146, 145, 36, 36, 36, 36, 40, 40, 40, 40, 43, 43, 43, 43, 51, 51, 51, 51, 53, 53, 53, 53, 56, 56, 76, 161, 76, 76, 147, 148, 147, 160, 160, 159, 158, 157, 156, 155, 154, 153, 148, 152, 151, 150, 149, 148, 144, 143, 142, 141, 140, 139, 138, 137, 136, 133, 132, 131, 130, 128, 127, 126, 125, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112, 111, 110, 105, 103, 102, 74, 101, 100, 99, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 55, 54, 52, 75, 74, 71, 70, 67, 66, 65, 64, 63, 60, 59, 58, 57, 55, 55, 54, 52, 169, 37, 13, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169 } ; static yyconst short int yy_chk[275] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 5, 6, 7, 7, 7, 8, 8, 8, 9, 10, 33, 5, 6, 4, 167, 9, 10, 33, 11, 9, 10, 12, 166, 9, 10, 9, 10, 11, 38, 26, 12, 26, 161, 45, 11, 45, 157, 12, 11, 45, 46, 12, 11, 38, 47, 12, 48, 46, 47, 48, 72, 47, 67, 48, 80, 46, 83, 67, 156, 47, 77, 77, 155, 47, 154, 72, 153, 98, 98, 80, 151, 83, 98, 103, 103, 103, 116, 116, 116, 128, 128, 128, 129, 129, 129, 134, 134, 134, 145, 145, 145, 170, 170, 170, 170, 171, 171, 171, 171, 172, 172, 172, 172, 173, 173, 173, 173, 174, 174, 174, 174, 175, 175, 176, 150, 176, 176, 177, 149, 177, 178, 178, 144, 143, 142, 141, 140, 139, 138, 137, 136, 133, 132, 131, 130, 126, 125, 124, 123, 122, 121, 120, 118, 117, 115, 114, 113, 112, 102, 101, 100, 99, 97, 96, 95, 94, 93, 92, 91, 90, 89, 87, 86, 85, 78, 75, 74, 73, 71, 69, 68, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 55, 53, 51, 42, 39, 35, 34, 32, 31, 30, 29, 28, 25, 24, 23, 22, 21, 20, 18, 17, 13, 3, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169 } ; static yy_state_type yy_state_buf[YY_BUF_SIZE + 2], *yy_state_ptr; static char *yy_full_match; static int yy_lp; #define REJECT \ { \ *yy_cp = yy_hold_char; /* undo effects of setting up yytext */ \ yy_cp = yy_full_match; /* restore poss. backed-over text */ \ ++yy_lp; \ goto find_rule; \ } static int yy_more_flag = 0; static int yy_more_len = 0; #define yymore() (yy_more_flag = 1) #define YY_MORE_ADJ yy_more_len #define YY_RESTORE_YY_MORE_OFFSET char *yytext; #line 1 "lexer.l" #define INITIAL 0 #line 2 "lexer.l" /* * File: lexer.l * Date created: March 15, 1999 (Monday, 17:16h) * Author: Copyright (C) 1999 Thomas Jensen * Version: $Id: lexer.l,v 1.19 2006/07/22 19:31:25 tsjensen Exp $ * Language: lex (ANSI C) * Purpose: flex lexical analyzer for boxes configuration files * * Remarks: o This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * o This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * o You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * - We don't use the yylineno %option. It is not only inefficient, * but also doesn't work. :-| *doh* * * Revision History: * * $Log: lexer.l,v $ * Revision 1.19 2006/07/22 19:31:25 tsjensen * Fix: Renamed yylineno to tjlineno to enable compilation on certain * flexes (reported by Andreas Heiduk) * * Revision 1.18 2006/07/07 07:24:17 tsjensen * Applied patch by Andreas Heiduk to facilitate compilation with * present-day flexes * * Revision 1.17 1999/08/20 19:51:12 tsjensen * Moved contents of YY_USER_INIT definition into a separate function which * is now called by YY_USER_INIT (better readability) * * Revision 1.16 1999/08/18 18:23:41 tsjensen * Declared yyerrcnt to be static * Added YY_USER_INIT macro to set the input buffer size to the config file * size (plus a bit). This is supposed to be a workaround for the REJECT * problem. * * Revision 1.15 1999/08/18 15:40:10 tsjensen * Added %options never-interactive and caseless * Added code for DELIMITER statements * Rewrote string rules to deal with delimiter statements * * Revision 1.14 1999/08/16 16:28:03 tsjensen * Implemented new SAMPLE block syntax * Replaced states SAMPLE1 and SAMPLE2 with new state SAMPLE - this is now * much simpler code * * Revision 1.13 1999/07/22 12:21:14 tsjensen * Added GNU GPL disclaimer * Renamed y.tab.h include to parser.h (same file) * Renamed parser.h include to lexer.h (same file) * Added config.h include * * Revision 1.12 1999/07/02 11:58:15 tsjensen * Added begin_speedmode() which is called by parser.y * Added state SPEEDMODE for fast skipping of designs * Introduced definitions for PWORD, PBOX, and PWHITE (whitespace) * Added %options nounput and noyywrap for easier compilation/linking * * Revision 1.11 1999/06/28 18:37:38 tsjensen * Replaced DEBUG macro with LEXER_DEBUG, which is now activated in boxes.h * New tokens to, with, global, once * Added LEX_MAX_WARN macro to limit number of lex errors printed per design * Replaced exit()s with return YUNREC where errors are not fatal * * Revision 1.10 1999/06/28 12:17:46 tsjensen * Added tokens YBOX and YEND (thus, BOX and END are no longer YKEYWORDs) * Added #define FILE_LEXER_L around #include boxes.h to please compiler * * Revision 1.9 1999/06/22 12:00:05 tsjensen * Added #undef DEBUG, because DEBUGging is now activated in boxes.h * Added #include tools.h * * Revision 1.8 1999/06/20 14:17:58 tsjensen * Added "padding" keyword and recognition of numbers (YNUMBER) * * Revision 1.7 1999/06/17 19:05:46 tsjensen * Bugfix: Sample block analysis didn't handle empty blocks * * Revision 1.6 1999/06/14 12:13:41 tsjensen * Added Reverse pattern * * Revision 1.4 1999/04/09 13:31:13 tsjensen * Removed all code related to OFFSET blocks (obsolete) * * Revision 1.3 1999/04/04 16:11:39 tsjensen * Added indent keyword * Added Replace token * Some fiddling which will hopefully fix a line counting bug * * Revision 1.1 1999/03/18 15:09:48 tsjensen * Initial revision * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "config.h" #include #include #include #include "shape.h" #define FILE_LEXER_L #include "boxes.h" #undef FILE_LEXER_L #include "tools.h" #include "parser.h" #include "lexer.h" #define LEX_MAX_WARN 3 /* number of lex errors per design */ static const char rcsid_lexer_l[] = "$Id: lexer.l,v 1.19 2006/07/22 19:31:25 tsjensen Exp $"; int tjlineno = 1; static int yyerrcnt = 0; static char sdel = '\"'; static char sesc = '\\'; /* * User-defined initializations for the lexer */ static void inflate_inbuf(); #define YY_USER_INIT inflate_inbuf() #define YY_NO_UNPUT 1 #define YY_NEVER_INTERACTIVE 1 #define SAMPLE 1 #define SPEEDMODE 2 #define DELWORD 3 #define SHAPES 4 #define ELASTIC 5 /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int yywrap YY_PROTO(( void )); #else extern int yywrap YY_PROTO(( void )); #endif #endif #ifndef YY_NO_UNPUT static void yyunput YY_PROTO(( int c, char *buf_ptr )); #endif #ifndef yytext_ptr static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen YY_PROTO(( yyconst char * )); #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput YY_PROTO(( void )); #else static int input YY_PROTO(( void )); #endif #endif #if YY_STACK_USED static int yy_start_stack_ptr = 0; static int yy_start_stack_depth = 0; static int *yy_start_stack = 0; #ifndef YY_NO_PUSH_STATE static void yy_push_state YY_PROTO(( int new_state )); #endif #ifndef YY_NO_POP_STATE static void yy_pop_state YY_PROTO(( void )); #endif #ifndef YY_NO_TOP_STATE static int yy_top_state YY_PROTO(( void )); #endif #else #define YY_NO_PUSH_STATE 1 #define YY_NO_POP_STATE 1 #define YY_NO_TOP_STATE 1 #endif #ifdef YY_MALLOC_DECL YY_MALLOC_DECL #else #if __STDC__ #ifndef __cplusplus #include #endif #else /* Just try to get by without declaring the routines. This will fail * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) * or sizeof(void*) != sizeof(int). */ #endif #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #define YY_READ_BUF_SIZE 8192 #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( yy_current_buffer->yy_is_interactive ) \ { \ int c = '*', n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \ && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) #endif /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL int yylex YY_PROTO(( void )) #endif /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK break; #endif #define YY_RULE_SETUP \ if ( yyleng > 0 ) \ yy_current_buffer->yy_at_bol = \ (yytext[yyleng - 1] == '\n'); \ YY_USER_ACTION YY_DECL { register yy_state_type yy_current_state; register char *yy_cp, *yy_bp; register int yy_act; #line 161 "lexer.l" if ( yy_init ) { yy_init = 0; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! yy_start ) yy_start = 1; /* first start state */ if ( ! yyin ) yyin = stdin; if ( ! yyout ) yyout = stdout; if ( ! yy_current_buffer ) yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); yy_load_buffer_state(); } while ( 1 ) /* loops until end-of-file is reached */ { yy_more_len = 0; if ( yy_more_flag ) { yy_more_len = yy_c_buf_p - yytext_ptr; yy_more_flag = 0; } yy_cp = yy_c_buf_p; /* Support of yytext. */ *yy_cp = yy_hold_char; /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = yy_start; yy_current_state += YY_AT_BOL(); yy_state_ptr = yy_state_buf; *yy_state_ptr++ = yy_current_state; yy_match: do { register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 170 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; *yy_state_ptr++ = yy_current_state; ++yy_cp; } while ( yy_base[yy_current_state] != 240 ); yy_find_action: yy_current_state = *--yy_state_ptr; yy_lp = yy_accept[yy_current_state]; find_rule: /* we branch to this label when backing up */ for ( ; ; ) /* until we find what rule we matched */ { if ( yy_lp && yy_lp < yy_accept[yy_current_state + 1] ) { yy_act = yy_acclist[yy_lp]; { yy_full_match = yy_cp; break; } } --yy_cp; yy_current_state = *--yy_state_ptr; yy_lp = yy_accept[yy_current_state]; } YY_DO_BEFORE_ACTION; do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 1: YY_RULE_SETUP #line 165 "lexer.l" /* ignore whitespace */ YY_BREAK case 2: YY_RULE_SETUP #line 167 "lexer.l" ++tjlineno; YY_BREAK case 3: YY_RULE_SETUP #line 170 "lexer.l" { /* * String delimiter spec - like WORD, but allow any character */ #ifdef LEXER_DEBUG fprintf (stderr, "\nYDELWOR: %s -- STATE INITIAL", yytext); #endif yylval.s = (char *) strdup (yytext); if (yylval.s == NULL) { perror (PROJECT); exit (EXIT_FAILURE); } BEGIN INITIAL; return YDELWORD; } YY_BREAK case 4: *yy_cp = yy_hold_char; /* undo effects of setting up yytext */ yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP #line 187 "lexer.l" { /* * Strings -- first match everything starting from a potential * string delimiter until the end of the line. We will give back what * we don't need and also detect unterminated strings. */ char *p; int rest_len = yyleng - 1; /* length of string pointed to by p */ int qcnt = 0; /* esc char count in current string */ if (yytext[0] != sdel) { REJECT; /* that was not our delimiter */ } yylval.s = (char *) strdup (yytext + 1); if (yylval.s == NULL) { perror (PROJECT); exit (EXIT_FAILURE); } p = yylval.s; while (*p) { if (*p == sesc) { memmove (p, p+1, rest_len); /* incl. '\0' */ ++qcnt; --rest_len; if (*p == '\0') break; } else if (*p == sdel) { *p = '\0'; yyless ((p-yylval.s)+2+qcnt); /* string plus quotes */ #ifdef LEXER_DEBUG fprintf (stderr, "\n STRING: \"%s\"", yylval.s); #endif return STRING; } --rest_len; ++p; } if (yyerrcnt++ < 5) yyerror ("Unterminated String -- %s", yytext); return YUNREC; } YY_BREAK case 5: YY_RULE_SETUP #line 234 "lexer.l" { #ifdef LEXER_DEBUG fprintf (stderr, "\nYSAMPLE: %s -- STATE SAMPLE", yytext); #endif BEGIN SAMPLE; return YSAMPLE; } YY_BREAK case 6: YY_RULE_SETUP #line 243 "lexer.l" { ++tjlineno; if (yyleng > 1) yymore(); } YY_BREAK case 7: *yy_cp = yy_hold_char; /* undo effects of setting up yytext */ yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP #line 250 "lexer.l" { char *p = yytext + yyleng -1; size_t len; /* length of sample */ while (*p == ' ' || *p == '\t' || *p == '\r') --p; /* skip trailing whitespace */ p -= 2; /* almost skip "ends" statement */ *p = '\0'; /* p now points to 'n' */ yylval.s = (char *) strdup (yytext); if (yylval.s == NULL) { perror (PROJECT); exit (EXIT_FAILURE); } *p-- = 'n'; len = p - yytext; /* yyless(n): push back all but the first n */ yyless (len); /* allow him to return YENDSAMPLE */ yylval.s[len] = '\n'; /* replace 'e' with newline */ btrim (yylval.s, &len); if (len > 0) { strcat (yylval.s, "\n"); /* memory was allocated with strdup */ #ifdef LEXER_DEBUG fprintf (stderr, "\n STRING: \"%s\" -- STATE INITIAL", yylval.s); #endif BEGIN INITIAL; return STRING; } else { if (yyerrcnt++ < 5) yyerror ("SAMPLE block must not be empty"); BFREE (yylval.s); return YUNREC; } } YY_BREAK case 8: YY_RULE_SETUP #line 287 "lexer.l" yymore(); YY_BREAK case 9: *yy_cp = yy_hold_char; /* undo effects of setting up yytext */ yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP #line 290 "lexer.l" { #ifdef LEXER_DEBUG fprintf (stderr, "\nYENDSAM: %s", yytext); #endif return YENDSAMPLE; } YY_BREAK case 10: YY_RULE_SETUP #line 299 "lexer.l" { #ifdef LEXER_DEBUG fprintf (stderr, "\nYELASTC: %s -- STATE ELASTIC", yytext); #endif BEGIN ELASTIC; return YELASTIC; } YY_BREAK case 11: YY_RULE_SETUP #line 307 "lexer.l" { #ifdef LEXER_DEBUG fprintf (stderr, "\nYSHAPES: %s -- STATE SHAPES", yytext); #endif BEGIN SHAPES; return YSHAPES; } YY_BREAK case 12: YY_RULE_SETUP #line 315 "lexer.l" { #ifdef LEXER_DEBUG fprintf (stderr, "\n YBOX: %s", yytext); #endif yyerrcnt = 0; return YBOX; } YY_BREAK case 13: YY_RULE_SETUP #line 323 "lexer.l" { return YREPLACE; } YY_BREAK case 14: YY_RULE_SETUP #line 324 "lexer.l" { return YREVERSE; } YY_BREAK case 15: YY_RULE_SETUP #line 325 "lexer.l" { return YPADDING; } YY_BREAK case 16: YY_RULE_SETUP #line 326 "lexer.l" { return YEND; } YY_BREAK case 17: YY_RULE_SETUP #line 327 "lexer.l" { return YTO; } YY_BREAK case 18: YY_RULE_SETUP #line 328 "lexer.l" { return YWITH; } YY_BREAK case 19: YY_RULE_SETUP #line 329 "lexer.l" { yylval.c = 'g'; return YRXPFLAG; } YY_BREAK case 20: YY_RULE_SETUP #line 330 "lexer.l" { yylval.c = 'o'; return YRXPFLAG; } YY_BREAK case 21: YY_RULE_SETUP #line 333 "lexer.l" { yylval.shape = NW; return SHAPE; } YY_BREAK case 22: YY_RULE_SETUP #line 334 "lexer.l" { yylval.shape = NNW; return SHAPE; } YY_BREAK case 23: YY_RULE_SETUP #line 335 "lexer.l" { yylval.shape = N; return SHAPE; } YY_BREAK case 24: YY_RULE_SETUP #line 336 "lexer.l" { yylval.shape = NNE; return SHAPE; } YY_BREAK case 25: YY_RULE_SETUP #line 337 "lexer.l" { yylval.shape = NE; return SHAPE; } YY_BREAK case 26: YY_RULE_SETUP #line 338 "lexer.l" { yylval.shape = ENE; return SHAPE; } YY_BREAK case 27: YY_RULE_SETUP #line 339 "lexer.l" { yylval.shape = E; return SHAPE; } YY_BREAK case 28: YY_RULE_SETUP #line 340 "lexer.l" { yylval.shape = ESE; return SHAPE; } YY_BREAK case 29: YY_RULE_SETUP #line 341 "lexer.l" { yylval.shape = SE; return SHAPE; } YY_BREAK case 30: YY_RULE_SETUP #line 342 "lexer.l" { yylval.shape = SSE; return SHAPE; } YY_BREAK case 31: YY_RULE_SETUP #line 343 "lexer.l" { yylval.shape = S; return SHAPE; } YY_BREAK case 32: YY_RULE_SETUP #line 344 "lexer.l" { yylval.shape = SSW; return SHAPE; } YY_BREAK case 33: YY_RULE_SETUP #line 345 "lexer.l" { yylval.shape = SW; return SHAPE; } YY_BREAK case 34: YY_RULE_SETUP #line 346 "lexer.l" { yylval.shape = WSW; return SHAPE; } YY_BREAK case 35: YY_RULE_SETUP #line 347 "lexer.l" { yylval.shape = W; return SHAPE; } YY_BREAK case 36: YY_RULE_SETUP #line 348 "lexer.l" { yylval.shape = WNW; return SHAPE; } YY_BREAK case 37: YY_RULE_SETUP #line 350 "lexer.l" { #ifdef LEXER_DEBUG fprintf (stderr, "\n SYMBOL: \'%c\' -- STATE INITIAL", yytext[0]); #endif BEGIN INITIAL; return yytext[0]; } YY_BREAK case 38: YY_RULE_SETUP #line 358 "lexer.l" { #ifdef LEXER_DEBUG fprintf (stderr, "\n SYMBOL: \'%c\' -- STATE INITIAL", yytext[0]); #endif BEGIN INITIAL; return yytext[0]; } YY_BREAK case 39: YY_RULE_SETUP #line 367 "lexer.l" { /* * general key words */ #ifdef LEXER_DEBUG fprintf (stderr, "\nKEYWORD: %s", yytext); #endif yylval.s = (char *) strdup (yytext); if (yylval.s == NULL) { perror (PROJECT); exit (EXIT_FAILURE); } return KEYWORD; } YY_BREAK case 40: YY_RULE_SETUP #line 383 "lexer.l" { /* * Change string delimiting characters */ #ifdef LEXER_DEBUG fprintf (stderr, "\nYCHGDEL: %s -- STATE DELWORD", yytext); #endif BEGIN DELWORD; return YCHGDEL; } YY_BREAK case 41: YY_RULE_SETUP #line 395 "lexer.l" { #ifdef LEXER_DEBUG fprintf (stderr, "\n WORD: %s", yytext); #endif yylval.s = (char *) strdup (yytext); if (yylval.s == NULL) { perror (PROJECT); exit (EXIT_FAILURE); } return WORD; } YY_BREAK case 42: YY_RULE_SETUP #line 408 "lexer.l" { #ifdef LEXER_DEBUG fprintf (stderr, "\nYNUMBER: %s", yytext); #endif yylval.num = atoi (yytext); return YNUMBER; } YY_BREAK case 43: YY_RULE_SETUP #line 417 "lexer.l" { #ifdef LEXER_DEBUG fprintf (stderr, "\n SYMBOL: \'%c\'", yytext[0]); #endif return yytext[0]; } YY_BREAK case 44: *yy_cp = yy_hold_char; /* undo effects of setting up yytext */ yy_c_buf_p = yy_cp -= 1; YY_DO_BEFORE_ACTION; /* set up yytext again */ YY_RULE_SETUP #line 425 "lexer.l" { /* ignore comments */ #ifdef LEXER_DEBUG fprintf (stderr, "\nCOMMENT: %s", yytext+1); #endif } YY_BREAK case 45: YY_RULE_SETUP #line 433 "lexer.l" { if (yyerrcnt++ < LEX_MAX_WARN) yyerror ("Unrecognized input char \'%s\'", yytext); return YUNREC; } YY_BREAK case 46: YY_RULE_SETUP #line 440 "lexer.l" { #ifdef LEXER_DEBUG fprintf (stderr, "\n STATUS: %s -- STATE INITIAL", yytext); #endif yyless (0); speeding = 0; BEGIN INITIAL; } YY_BREAK case 47: YY_RULE_SETUP #line 449 "lexer.l" ++tjlineno; YY_BREAK case 48: YY_RULE_SETUP #line 451 "lexer.l" /* ignore anything else */ YY_BREAK case 49: YY_RULE_SETUP #line 454 "lexer.l" ECHO; YY_BREAK case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(SAMPLE): case YY_STATE_EOF(SPEEDMODE): case YY_STATE_EOF(DELWORD): case YY_STATE_EOF(SHAPES): case YY_STATE_EOF(ELASTIC): yyterminate(); case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = yy_hold_char; YY_RESTORE_YY_MORE_OFFSET if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure * consistency between yy_current_buffer and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ yy_n_chars = yy_current_buffer->yy_n_chars; yy_current_buffer->yy_input_file = yyin; yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) { /* This was really a NUL. */ yy_state_type yy_next_state; yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state(); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state ); yy_bp = yytext_ptr + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++yy_c_buf_p; yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = yy_c_buf_p; goto yy_find_action; } } else switch ( yy_get_next_buffer() ) { case EOB_ACT_END_OF_FILE: { yy_did_buffer_switch_on_eof = 0; if ( yywrap() ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * yytext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! yy_did_buffer_switch_on_eof ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state(); yy_cp = yy_c_buf_p; yy_bp = yytext_ptr + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: yy_c_buf_p = &yy_current_buffer->yy_ch_buf[yy_n_chars]; yy_current_state = yy_get_previous_state(); yy_cp = yy_c_buf_p; yy_bp = yytext_ptr + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer() { register char *dest = yy_current_buffer->yy_ch_buf; register char *source = yytext_ptr; register int number_to_move, i; int ret_val; if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( yy_current_buffer->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ yy_current_buffer->yy_n_chars = yy_n_chars = 0; else { int num_to_read = yy_current_buffer->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ #ifdef YY_USES_REJECT YY_FATAL_ERROR( "input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); #else /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = yy_current_buffer; int yy_c_buf_p_offset = (int) (yy_c_buf_p - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ yy_flex_realloc( (void *) b->yy_ch_buf, b->yy_buf_size + 2 ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = 0; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = yy_current_buffer->yy_buf_size - number_to_move - 1; #endif } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), yy_n_chars, num_to_read ); yy_current_buffer->yy_n_chars = yy_n_chars; } if ( yy_n_chars == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; yyrestart( yyin ); } else { ret_val = EOB_ACT_LAST_MATCH; yy_current_buffer->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; yy_n_chars += number_to_move; yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; yytext_ptr = &yy_current_buffer->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ static yy_state_type yy_get_previous_state() { register yy_state_type yy_current_state; register char *yy_cp; yy_current_state = yy_start; yy_current_state += YY_AT_BOL(); yy_state_ptr = yy_state_buf; *yy_state_ptr++ = yy_current_state; for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) { register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 170 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; *yy_state_ptr++ = yy_current_state; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ #ifdef YY_USE_PROTOS static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state ) #else static yy_state_type yy_try_NUL_trans( yy_current_state ) yy_state_type yy_current_state; #endif { register int yy_is_jam; register YY_CHAR yy_c = 1; while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 170 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; yy_is_jam = (yy_current_state == 169); if ( ! yy_is_jam ) *yy_state_ptr++ = yy_current_state; return yy_is_jam ? 0 : yy_current_state; } #ifndef YY_NO_UNPUT #ifdef YY_USE_PROTOS static void yyunput( int c, register char *yy_bp ) #else static void yyunput( c, yy_bp ) int c; register char *yy_bp; #endif { register char *yy_cp = yy_c_buf_p; /* undo effects of setting up yytext */ *yy_cp = yy_hold_char; if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) { /* need to shift things up to make room */ /* +2 for EOB chars. */ register int number_to_move = yy_n_chars + 2; register char *dest = &yy_current_buffer->yy_ch_buf[ yy_current_buffer->yy_buf_size + 2]; register char *source = &yy_current_buffer->yy_ch_buf[number_to_move]; while ( source > yy_current_buffer->yy_ch_buf ) *--dest = *--source; yy_cp += (int) (dest - source); yy_bp += (int) (dest - source); yy_current_buffer->yy_n_chars = yy_n_chars = yy_current_buffer->yy_buf_size; if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) YY_FATAL_ERROR( "flex scanner push-back overflow" ); } *--yy_cp = (char) c; yytext_ptr = yy_bp; yy_hold_char = *yy_cp; yy_c_buf_p = yy_cp; } #endif /* ifndef YY_NO_UNPUT */ #ifdef __cplusplus static int yyinput() #else static int input() #endif { int c; *yy_c_buf_p = yy_hold_char; if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) /* This was really a NUL. */ *yy_c_buf_p = '\0'; else { /* need more input */ int offset = yy_c_buf_p - yytext_ptr; ++yy_c_buf_p; switch ( yy_get_next_buffer() ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ yyrestart( yyin ); /* fall through */ case EOB_ACT_END_OF_FILE: { if ( yywrap() ) return EOF; if ( ! yy_did_buffer_switch_on_eof ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(); #else return input(); #endif } case EOB_ACT_CONTINUE_SCAN: yy_c_buf_p = yytext_ptr + offset; break; } } } c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ *yy_c_buf_p = '\0'; /* preserve yytext */ yy_hold_char = *++yy_c_buf_p; yy_current_buffer->yy_at_bol = (c == '\n'); return c; } #ifdef YY_USE_PROTOS void yyrestart( FILE *input_file ) #else void yyrestart( input_file ) FILE *input_file; #endif { if ( ! yy_current_buffer ) yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); yy_init_buffer( yy_current_buffer, input_file ); yy_load_buffer_state(); } #ifdef YY_USE_PROTOS void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) #else void yy_switch_to_buffer( new_buffer ) YY_BUFFER_STATE new_buffer; #endif { if ( yy_current_buffer == new_buffer ) return; if ( yy_current_buffer ) { /* Flush out information for old buffer. */ *yy_c_buf_p = yy_hold_char; yy_current_buffer->yy_buf_pos = yy_c_buf_p; yy_current_buffer->yy_n_chars = yy_n_chars; } yy_current_buffer = new_buffer; yy_load_buffer_state(); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ yy_did_buffer_switch_on_eof = 1; } #ifdef YY_USE_PROTOS void yy_load_buffer_state( void ) #else void yy_load_buffer_state() #endif { yy_n_chars = yy_current_buffer->yy_n_chars; yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; yyin = yy_current_buffer->yy_input_file; yy_hold_char = *yy_c_buf_p; } #ifdef YY_USE_PROTOS YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) #else YY_BUFFER_STATE yy_create_buffer( file, size ) FILE *file; int size; #endif { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; yy_init_buffer( b, file ); return b; } #ifdef YY_USE_PROTOS void yy_delete_buffer( YY_BUFFER_STATE b ) #else void yy_delete_buffer( b ) YY_BUFFER_STATE b; #endif { if ( ! b ) return; if ( b == yy_current_buffer ) yy_current_buffer = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) yy_flex_free( (void *) b->yy_ch_buf ); yy_flex_free( (void *) b ); } #ifndef YY_ALWAYS_INTERACTIVE #ifndef YY_NEVER_INTERACTIVE extern int isatty YY_PROTO(( int )); #endif #endif #ifdef YY_USE_PROTOS void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) #else void yy_init_buffer( b, file ) YY_BUFFER_STATE b; FILE *file; #endif { yy_flush_buffer( b ); b->yy_input_file = file; b->yy_fill_buffer = 1; #if YY_ALWAYS_INTERACTIVE b->yy_is_interactive = 1; #else #if YY_NEVER_INTERACTIVE b->yy_is_interactive = 0; #else b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; #endif #endif } #ifdef YY_USE_PROTOS void yy_flush_buffer( YY_BUFFER_STATE b ) #else void yy_flush_buffer( b ) YY_BUFFER_STATE b; #endif { if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == yy_current_buffer ) yy_load_buffer_state(); } #ifndef YY_NO_SCAN_BUFFER #ifdef YY_USE_PROTOS YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size ) #else YY_BUFFER_STATE yy_scan_buffer( base, size ) char *base; yy_size_t size; #endif { YY_BUFFER_STATE b; if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return 0; b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; b->yy_input_file = 0; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; yy_switch_to_buffer( b ); return b; } #endif #ifndef YY_NO_SCAN_STRING #ifdef YY_USE_PROTOS YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str ) #else YY_BUFFER_STATE yy_scan_string( yy_str ) yyconst char *yy_str; #endif { int len; for ( len = 0; yy_str[len]; ++len ) ; return yy_scan_bytes( yy_str, len ); } #endif #ifndef YY_NO_SCAN_BYTES #ifdef YY_USE_PROTOS YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len ) #else YY_BUFFER_STATE yy_scan_bytes( bytes, len ) yyconst char *bytes; int len; #endif { YY_BUFFER_STATE b; char *buf; yy_size_t n; int i; /* Get memory for full buffer, including space for trailing EOB's. */ n = len + 2; buf = (char *) yy_flex_alloc( n ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); for ( i = 0; i < len; ++i ) buf[i] = bytes[i]; buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; b = yy_scan_buffer( buf, n ); if ( ! b ) YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->yy_is_our_buffer = 1; return b; } #endif #ifndef YY_NO_PUSH_STATE #ifdef YY_USE_PROTOS static void yy_push_state( int new_state ) #else static void yy_push_state( new_state ) int new_state; #endif { if ( yy_start_stack_ptr >= yy_start_stack_depth ) { yy_size_t new_size; yy_start_stack_depth += YY_START_STACK_INCR; new_size = yy_start_stack_depth * sizeof( int ); if ( ! yy_start_stack ) yy_start_stack = (int *) yy_flex_alloc( new_size ); else yy_start_stack = (int *) yy_flex_realloc( (void *) yy_start_stack, new_size ); if ( ! yy_start_stack ) YY_FATAL_ERROR( "out of memory expanding start-condition stack" ); } yy_start_stack[yy_start_stack_ptr++] = YY_START; BEGIN(new_state); } #endif #ifndef YY_NO_POP_STATE static void yy_pop_state() { if ( --yy_start_stack_ptr < 0 ) YY_FATAL_ERROR( "start-condition stack underflow" ); BEGIN(yy_start_stack[yy_start_stack_ptr]); } #endif #ifndef YY_NO_TOP_STATE static int yy_top_state() { return yy_start_stack[yy_start_stack_ptr - 1]; } #endif #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif #ifdef YY_USE_PROTOS static void yy_fatal_error( yyconst char msg[] ) #else static void yy_fatal_error( msg ) char msg[]; #endif { (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ yytext[yyleng] = yy_hold_char; \ yy_c_buf_p = yytext + n; \ yy_hold_char = *yy_c_buf_p; \ *yy_c_buf_p = '\0'; \ yyleng = n; \ } \ while ( 0 ) /* Internal utility routines. */ #ifndef yytext_ptr #ifdef YY_USE_PROTOS static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) #else static void yy_flex_strncpy( s1, s2, n ) char *s1; yyconst char *s2; int n; #endif { register int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN #ifdef YY_USE_PROTOS static int yy_flex_strlen( yyconst char *s ) #else static int yy_flex_strlen( s ) yyconst char *s; #endif { register int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif #ifdef YY_USE_PROTOS static void *yy_flex_alloc( yy_size_t size ) #else static void *yy_flex_alloc( size ) yy_size_t size; #endif { return (void *) malloc( size ); } #ifdef YY_USE_PROTOS static void *yy_flex_realloc( void *ptr, yy_size_t size ) #else static void *yy_flex_realloc( ptr, size ) void *ptr; yy_size_t size; #endif { /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter * because both ANSI C and C++ allow castless assignment from * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ return (void *) realloc( (char *) ptr, size ); } #ifdef YY_USE_PROTOS static void yy_flex_free( void *ptr ) #else static void yy_flex_free( ptr ) void *ptr; #endif { free( ptr ); } #if YY_MAIN int main() { yylex(); return 0; } #endif #line 454 "lexer.l" static void inflate_inbuf() /* * User-defined initializations for the lexer. * * Since this scanner must use REJECT in order to be able to process the * string delimiter commands, it cannot dynamically enlarge its input * buffer to accomodate larger tokens. Thus, we simply set the buffer size * to the input file size plus 10 bytes margin-of-error. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { struct stat sinf; if (stat(yyfilename, &sinf)) { perror (PROJECT); exit (EXIT_FAILURE); } yy_delete_buffer (YY_CURRENT_BUFFER); yy_switch_to_buffer (yy_create_buffer (yyin, sinf.st_size+10)); } void begin_speedmode() { #ifdef LEXER_DEBUG fprintf (stderr, "\n STATUS: begin_speedmode() -- STATE SPEEDMODE"); #endif BEGIN SPEEDMODE; } void chg_strdelims (const char asesc, const char asdel) { #ifdef LEXER_DEBUG fprintf (stderr, "\n STATUS: chg_strdelims ('%c', '%c')", asesc, asdel); #endif sesc = asesc; sdel = asdel; } /*EOF*/ /* vim: set cindent sw=4: */ boxes-1.1.1/src/config.h0100644000175000001440000000412710460474365014625 0ustar tsjensenusers/* * File: config.h * Project Main: boxes.c * Date created: July 4, 1999 (Sunday, 21:04h) * Author: Copyright (C) 1999 Thomas Jensen * Version: $Id: config.h,v 1.4 2006/07/12 05:42:48 tsjensen Exp $ * Language: ANSI C * World Wide Web: http://boxes.thomasjensen.com/ * Purpose: Please compiler and ease porting * * Remarks: o This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * o This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * o You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * Revision History: * * $Log: config.h,v $ * Revision 1.4 2006/07/12 05:42:48 tsjensen * Updated email and web addresses in comment header * * Revision 1.3 1999-08-25 06:38:37-07 tsjensen * Bugfix: Changed empty #elif to #else (thanks Tommy Williams) * Port to i386/FreeBSD by Tommy Williams * * Revision 1.2 1999/08/18 18:23:06 tsjensen * Added Linux defines. Now compiles nicely on (my) Linux. * * Revision 1.1 1999/07/22 12:26:10 tsjensen * Initial revision * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef CONFIG_H #define CONFIG_H #if defined(__linux__) #define _GNU_SOURCE #elif defined(__sun__) #define _POSIX_SOURCE #define __EXTENSIONS__ #elif defined(__FreeBSD__) /* do nothing */ #else #define _POSIX_SOURCE #endif #endif /*CONFIG_H*/ /*EOF*/ boxes-1.1.1/src/tools.c0100644000175000001440000002775310460476130014515 0ustar tsjensenusers/* * File: tools.c * Project Main: boxes.c * Date created: June 20, 1999 (Sunday, 16:51h) * Author: Copyright (C) 1999 Thomas Jensen * Version: $Id: tools.c,v 1.7 2006/07/22 19:27:15 tsjensen Exp $ * Language: ANSI C * World Wide Web: http://boxes.thomasjensen.com/ * Purpose: Provide tool functions for error reporting and some * string handling * * Remarks: o This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * o This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * o You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * Revision History: * * $Log: tools.c,v $ * Revision 1.7 2006/07/22 19:27:15 tsjensen * Changed expand_tabs_into() so that it records the original tab positions in a line * Added tabbify_indent() to restore original leading tabs after box processing * * Revision 1.6 2006/07/12 05:25:47 tsjensen * Updated email and web addresses in comment header * * Revision 1.5 1999-08-31 08:35:13-07 tsjensen * Applied Joe Zbiciak's patches to remove all snprintf()s and variants * Added concat_strings() function and changed yyerror() in the process * * Revision 1.4 1999/08/21 16:09:33 tsjensen * Removed newline check from empty_line() function * * Revision 1.3 1999/08/13 23:54:24 tsjensen * Bugfix: cut&paste error in in strisyes() and strisno(). Thanks Warren Seltzer * * Revision 1.2 1999/07/20 18:55:20 tsjensen * Added GNU GPL disclaimer * Added functions strisyes() and strisno() * Added config.h and shape.h include statements * * Revision 1.1 1999/06/23 11:19:30 tsjensen * Initial revision * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "config.h" #include #include #include #include #include "shape.h" #include "boxes.h" #include "tools.h" static const char rcsid_tools_c[] = "$Id: tools.c,v 1.7 2006/07/22 19:27:15 tsjensen Exp $"; int yyerror (const char *fmt, ...) /* * Print configuration file parser errors. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { va_list ap; va_start (ap, fmt); fprintf (stderr, "%s: %s: line %d: ", PROJECT, yyfilename? yyfilename: "(null)", tjlineno); vfprintf (stderr, fmt, ap); fputc ('\n', stderr); va_end (ap); return 0; } void regerror (char *msg) /* * Print regular expression andling error messages * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { fprintf (stderr, "%s: %s: line %d: %s\n", PROJECT, yyfilename? yyfilename: "(null)", opt.design->current_rule? opt.design->current_rule->line: 0, msg); errno = EINVAL; } int strisyes (const char *s) /* * Determine if the string s has a contents indicating "yes". * * s string to examine * * RETURNS: == 0 string does NOT indicate yes (including errors) * != 0 string indicates yes * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { if (s == NULL) return 0; if (!strncasecmp ("on", s, 3)) return 1; else if (!strncasecmp ("yes", s, 4)) return 1; else if (!strncasecmp ("true", s, 5)) return 1; else if (!strncmp ("1", s, 2)) return 1; else if (!strncasecmp ("t", s, 2)) return 1; else return 0; } int strisno (const char *s) /* * Determine if the string s has a contents indicating "no". * * s string to examine * * RETURNS: == 0 string does NOT indicate no (including errors) * != 0 string indicates no * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { if (s == NULL) return 0; if (!strncasecmp ("off", s, 4)) return 1; else if (!strncasecmp ("no", s, 3)) return 1; else if (!strncasecmp ("false", s, 6)) return 1; else if (!strncmp ("0", s, 2)) return 1; else if (!strncasecmp ("f", s, 2)) return 1; else return 0; } void concat_strings (char *dst, int max_len, int count, ...) /* * Concatenate a variable number of strings into a fixed-length buffer. * * dst Destination array * max_len Maximum resulting string length (including terminating NULL). * count Number of source strings. * * The concatenation process terminates when either the destination * buffer is full or all 'count' strings are processed. Null string * pointers are treated as empty strings. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { va_list va; const char *src; va_start (va, count); /* * Sanity check. */ if (max_len < 1) return; if (max_len == 1 || count < 1) { *dst = '\0'; return; } /* * Loop over all input strings. */ while (count-->0 && max_len > 1) { /* * Grab an input string pointer. If it's NULL, skip it (eg. treat * it as empty. */ src = va_arg (va, const char *); if (src == NULL) continue; /* * Concatenate 'src' onto 'dst', as long as we have room. */ while (*src && max_len > 1) { *dst++ = *src++; max_len--; } } va_end (va); /* * Terminate the string with an ASCII NUL. */ *dst = '\0'; } int empty_line (const line_t *line) /* * Return true if line is empty. * * Empty lines either consist entirely of whitespace or don't exist. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { char *p; size_t j; if (!line) return 1; if (line->text == NULL || line->len <= 0) return 1; for (p=line->text, j=0; *p && jlen; ++j, ++p) { if (*p != ' ' && *p != '\t' && *p != '\r') return 0; } return 1; } size_t expand_tabs_into (const char *input_buffer, const size_t in_len, const int tabstop, char **text, size_t **tabpos, size_t *tabpos_len) /* * Expand tab chars in input_buffer and store result in text. * * input_buffer Line of text with tab chars * in_len length of the string in input_buffer * tabstop tab stop distance * text address of the pointer that will take the result * tabpos array of ints giving the positions of the first * space of an expanded tab in the text result buffer * tabpos_len number of tabs recorded in tabpos * * Memory will be allocated for text and tabpos. * Should only be called for lines of length > 0; * * RETURNS: Success: Length of the result line in characters (> 0) * Error: 0 (e.g. out of memory) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { static char temp [LINE_MAX*MAX_TABSTOP+1]; /* work string */ size_t ii; /* position in input string */ size_t io; /* position in work string */ size_t jp; /* tab expansion jump point */ size_t tabnum; /* number of tabs in input */ *text = NULL; for (ii=0, *tabpos_len=0; ii 0) { *tabpos = (size_t *) calloc ((*tabpos_len) + 1, sizeof(size_t)); if (*tabpos == NULL) { return 0; /* out of memory */ } } for (ii=0, io=0, tabnum=0; ii < in_len && ((int) io) < (LINE_MAX*tabstop-1); ++ii) { if (input_buffer[ii] == '\t') { if (*tabpos_len > 0) { (*tabpos)[tabnum++] = io; } for (jp=io+tabstop-(io%tabstop); io= 0 && (text[idx] == '\n' || text[idx] == '\r' || text[idx] == '\t' || text[idx] == ' ')) { text[idx--] = '\0'; } *len = idx + 1; } char *my_strnrstr (const char *s1, const char *s2, const size_t s2_len, int skip) /* * Return pointer to last occurrence of string s2 in string s1. * * s1 string to search * s2 string to search for in s1 * s2_len length in characters of s2 * skip number of finds to ignore before returning anything * * RETURNS: pointer to last occurrence of string s2 in string s1 * NULL if not found or error * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { char *p; int comp; if (!s2 || *s2 == '\0') return (char *) s1; if (!s1 || *s1 == '\0') return NULL; if (skip < 0) skip = 0; p = strrchr (s1, s2[0]); if (!p) return NULL; while (p >= s1) { comp = strncmp (p, s2, s2_len); if (comp == 0) { if (skip--) --p; else return p; } else { --p; } } return NULL; } char *tabbify_indent (const size_t lineno, char *indentspc, const size_t indentspc_len) /* * Checks if tab expansion mode is "keep", and if so, calculates a new * indentation string based on the one given. The new string contains * tabs in their original positions. * * lineno index of the input line we are referring to * indentspc previously calculated "space-only" indentation string * (may be NULL). This is only used when opt.tabexp != 'k', * in which case it will be used as the function result. * indentspc_len desired result length, measured in spaces only * * RETURNS: if successful and opt.tabexp == 'k': new string * on error (invalid input or out of memory): NULL * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { size_t i; char *result; size_t result_len; if (opt.tabexp != 'k') { return indentspc; } if (lineno >= input.anz_lines) { return NULL; } if (indentspc_len == 0) { return (char *) strdup (""); } result = (char *) malloc (indentspc_len + 1); if (result == NULL) { perror (PROJECT); return NULL; } memset (result, (int)' ', indentspc_len); result[indentspc_len] = '\0'; result_len = indentspc_len; for (i=0; i < input.lines[lineno].tabpos_len && input.lines[lineno].tabpos[i] < indentspc_len; ++i) { size_t tpos = input.lines[lineno].tabpos[i]; size_t nspc = opt.tabstop - (tpos % opt.tabstop); /* no of spcs covered by tab */ if (tpos + nspc > input.indent) { break; } result[tpos] = '\t'; result_len -= nspc - 1; result[result_len] = '\0'; } return result; } /*EOF*/ /* vim: set sw=4: */ boxes-1.1.1/src/tools.h0100644000175000001440000000606610460474216014517 0ustar tsjensenusers/* * File: tools.h * Project Main: boxes.c * Date created: June 20, 1999 (Sunday, 16:57h) * Author: Copyright (C) 1999 Thomas Jensen * Version: $Id: tools.h,v 1.5 2006/07/22 19:11:07 tsjensen Exp $ * Language: ANSI C * World Wide Web: http://boxes.thomasjensen.com/ * Purpose: Tool functions for error reporting and some string * handling and other needful things * * Remarks: o This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * o This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * o You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * Revision History: * * $Log: tools.h,v $ * Revision 1.5 2006/07/22 19:11:07 tsjensen * Changed expand_tabs_into() signature in order to support advanced tab handling * Added tabbify_indent() * * Revision 1.4 2006/07/12 05:25:27 tsjensen * Updated email and web addresses in comment header * * Revision 1.3 1999-08-31 08:38:42-07 tsjensen * Added concat_strings() function prototype from Joe Zbiciak's patches * * Revision 1.2 1999/07/20 18:56:15 tsjensen * Added GNU GPL disclaimer * Removed include boxes.h * Added prototypes for strisyes() and strisno() * * Revision 1.1 1999/06/23 11:19:59 tsjensen * Initial revision * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef TOOLS_H #define TOOLS_H #define BMAX(a,b) ((a)>(b)? (a):(b)) /* return the larger value */ #define BFREE(p) { /* free memory and clear pointer */ \ if (p) { \ free (p); \ (p) = NULL; \ } \ } int yyerror (const char *fmt, ...); void regerror (char *msg); int empty_line (const line_t *line); size_t expand_tabs_into (const char *input_buffer, const size_t in_len, const int tabstop, char **text, size_t **tabpos, size_t *tabpos_len); void btrim (char *text, size_t *len); char* my_strnrstr (const char *s1, const char *s2, const size_t s2_len, int skip); int strisyes (const char *s); int strisno (const char *s); void concat_strings (char *dst, int max_len, int count, ...); char *tabbify_indent (const size_t lineno, char *indentspc, const size_t indentspc_len); #endif /*EOF*/ /* vim: set cindent sw=4: */ boxes-1.1.1/src/regexp/0040755000175000001440000000000012040315414014461 5ustar tsjensenusersboxes-1.1.1/src/regexp/regsub.c0100644000175000001440000001604510460720336016126 0ustar tsjensenusers/* * File: regsub.c * Date created: Copyright (c) 1986 by University of Toronto. * Author: Henry Spencer. * Extensions and modifications by Thomas Jensen * Version: $Id: regsub.c,v 1.7 2006/07/23 16:15:55 tsjensen Exp $ * Language: K&R C (traditional) * World Wide Web: http://boxes.thomasjensen.com/ * Purpose: Perform substitutions after a regexp match * Remarks: - Not derived from licensed software. * - Permission is granted to anyone to use this * software for any purpose on any computer system, * and to redistribute it freely, subject to the * following restrictions: * 1. The author is not responsible for the * consequences of use of this software, no matter * how awful, even if they arise from defects in it. * 2. The origin of this software must not be * misrepresented, either by explicit claim or by * omission. * 3. Altered versions must be plainly marked as such, * and must not be misrepresented as being the * original software. * Revision History: * * $Log: regsub.c,v $ * Revision 1.7 2006/07/23 16:15:55 tsjensen * Undo of previous version * Added include string.h and removed manual extern declarations for strncpy() * * Revision 1.6 2006/07/22 19:01:10 tsjensen * Added extern declaration of strncpy() to myregsub(), hoping this will clear some warnings on Debian * * Revision 1.5 2006/07/12 05:20:26 tsjensen * Updated world wide web link in comment header * * Revision 1.4 1999-07-20 11:51:41-07 tsjensen * Bugfix: REPLACE "^" with "a" caused a hangup. Now automatically declaring * matches which have a length of zero to be of scope "once". * * Revision 1.3 1999/04/12 18:13:57 tsjensen * Added missing '$' to rcs id string, changed from #ident to char * * Revision 1.2 1999/04/05 19:39:27 tsjensen * Hopefully fixed a potential buffer overrun problem in regsub() * * Revision 1.1 1999/04/04 16:14:46 tsjensen * Initial revision * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include #include #include #include "regmagic.h" char rcsid_regsub_c[] = "$Id: regsub.c,v 1.7 2006/07/23 16:15:55 tsjensen Exp $"; #ifndef CHARBITS #define UCHARAT(p) ((int)*(unsigned char *)(p)) #else #define UCHARAT(p) ((int)*(p)&CHARBITS) #endif /* - regsub - perform substitutions after a regexp match */ size_t /* RETURNS length of dest str */ regsub (prog, source, dest, dest_size) regexp *prog; char *source; char *dest; size_t dest_size; /* size of destination buffer */ { register char *src; register char *dst; register char c; register int no; register int len; size_t fill; /* current number of chars in dest */ if (prog == NULL || source == NULL || dest == NULL) { regerror("NULL parm to regsub"); return 0; } if (UCHARAT(prog->program) != MAGIC) { regerror("damaged regexp fed to regsub"); return 0; } src = source; dst = dest; fill = 0; while ((c = *src++) != '\0') { if (c == '&') no = 0; else if (c == '\\' && '0' <= *src && *src <= '9') no = *src++ - '0'; else no = -1; if (no < 0) { /* Ordinary character. */ if (c == '\\' && (*src == '\\' || *src == '&')) c = *src++; *dst++ = c; ++fill; } else if (prog->startp[no] != NULL && prog->endp[no] != NULL) { len = prog->endp[no] - prog->startp[no]; if (len < dest_size-fill) { (void) strncpy(dst, prog->startp[no], len); dst += len; fill += len; if (len != 0 && *(dst-1) == '\0') { /* strncpy hit NUL. */ regerror("damaged match string"); return fill; } } else { (void) strncpy (dst, prog->startp[no], dest_size-fill); dest[dest_size-1] = '\0'; return dest_size-1; } } if (fill >= dest_size) { dest[dest_size-1] = '\0'; return dest_size-1; } } *dst++ = '\0'; return fill; } size_t /* RETURNS length of str in destination buffer */ myregsub (prog, orig, orig_len, repstr, dest, dest_size, mode) regexp *prog; /* pointers for matched regexp to original text */ char *orig; /* original input line */ size_t orig_len; /* length of original input line */ char *repstr; /* source buffer for replaced parts */ char *dest; /* destination buffer */ size_t dest_size; /* size of destination buffer */ char mode; /* 'g' or 'o' */ { size_t fill; /* current number of chars in dest */ char *sp, *dp; /* source rover, destination rover */ int rc; /* received return codes */ size_t rest_size; /* remaining space in dest */ size_t partlen; /* temp length of a piece handled */ fill = 0; sp = orig; dp = dest; rest_size = dest_size; do { rc = regexec (prog, sp); if (!rc) break; partlen = prog->startp[0] - sp; if (partlen < rest_size) { strncpy (dp, sp, partlen); fill += partlen; sp = prog->startp[0]; dp += partlen; rest_size -= partlen; } else { strncpy (dp, sp, rest_size); dest[dest_size-1] = '\0'; return dest_size - 1; } /* fprintf (stderr, "regsub (%p, \"%s\", \"%s\", %d);\n", */ /* prog, repstr, dp, rest_size); */ fill += regsub (prog, repstr, dp, rest_size); dp = dest + fill; sp = prog->endp[0]; rest_size = dest_size - fill; if (fill >= dest_size) { dest[dest_size-1] = '\0'; return dest_size - 1; } /* fprintf (stderr, "dest = \"%s\";\n", dest); */ if (prog->startp[0] == prog->endp[0]) break; /* match "^" or "$" only once */ } while (mode == 'g'); partlen = orig + orig_len - sp; if (partlen < rest_size) { strncpy (dp, sp, partlen); fill += partlen; dp[partlen] = '\0'; } else { strncpy (dp, sp, rest_size); dest[dest_size-1] = '\0'; fill = dest_size - 1; } return fill; } /*EOF*/ /* vim: set sw=4: */ boxes-1.1.1/src/regexp/Makefile0100644000175000001440000000533110460473305016130 0ustar tsjensenusers# # File: Makefile # Creation: August 13, 1999 (Friday, 22:13h) # Author: Copyright (C) 1999 Thomas Jensen # Version: $Id: Makefile,v 1.4 2006/07/22 19:04:30 tsjensen Exp $ # Format: GNU make # Web Site: http://boxes.thomasjensen.com/ # Platforms: sparc/Solaris 2.6 and others # Purpose: Makefile for boxes, the box drawing program # generation of regexp handling library # # Remarks: o This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # o This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # o You should have received a copy of the GNU General Public # License along with this program; if not, write to the Free # Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, # MA 02111-1307 USA # # Revision History: # # $Log: Makefile,v $ # Revision 1.4 2006/07/22 19:04:30 tsjensen # Small usability enhancements # # Revision 1.3 2006/07/12 21:28:38 tsjensen # Added target rcslocks # # Revision 1.2 2006/07/08 08:47:58 tsjensen # Removed -traditional flag from CFLAGS definition # Updated email and web addresses # # Revision 1.1 1999/08/13 20:56:09 tsjensen # Initial revision # #____________________________________________________________________________ #============================================================================ CFLAGS = -O -I. $(CFLAGS_ADDTL) ALL_CL = regexp/regexp.c regexp/regsub.c C_SRC = $(notdir $(ALL_CL)) ALLFILES = Makefile $(C_SRC) regexp.h regmagic.h ALLOBJ = $(C_SRC:.c=.o) build: libregexp.a debug: libregexp.a libregexp.a: $(ALLOBJ) ar cr libregexp.a $(ALLOBJ) regexp.o: regexp.c regmagic.h regexp.h ../config.h regsub.o: regsub.c regmagic.h regexp.h ../config.h .c.o: $(CC) $(CFLAGS) -c $< snap: $(ALLFILES) @if [ -z "$(SNAPFILE)" ] ; then echo "make snap must be run from the main directory" ; exit 1 ; fi mkdir $(SNAPFILE)/src/regexp cp $(ALLFILES) $(SNAPFILE)/src/regexp rcstest: -for i in $(ALLFILES) ; do rcsdiff $$i ; done rcslocks: @rlog -L -R $(ALLFILES) | sed -e 's/^/ - src\/regexp\//' logpage: $(C_SRC) @echo $(ALL_CL) clean: rm -f $(ALLOBJ) libregexp.a core love: @echo "Not in front of the kids, honey!" #EOF boxes-1.1.1/src/regexp/regmagic.h0100644000175000001440000000023106701422344016411 0ustar tsjensenusers/* * The first byte of the regexp internal "program" is actually this magic * number; the start node begins in the second byte. */ #define MAGIC 0234 boxes-1.1.1/src/regexp/regexp.c0100644000175000001440000006577710460721702016147 0ustar tsjensenusers/* * regcomp and regexec -- regsub and regerror are elsewhere * * Copyright (c) 1986 by University of Toronto. * Written by Henry Spencer. Not derived from licensed software. * * Permission is granted to anyone to use this software for any * purpose on any computer system, and to redistribute it freely, * subject to the following restrictions: * * 1. The author is not responsible for the consequences of use of * this software, no matter how awful, even if they arise * from defects in it. * * 2. The origin of this software must not be misrepresented, either * by explicit claim or by omission. * * 3. Altered versions must be plainly marked as such, and must not * be misrepresented as being the original software. * * Beware that some of this code is subtly aware of the way operator * precedence is structured in regular expressions. Serious changes in * regular-expression syntax might require a total rethink. */ #include #include #include #include #include "regmagic.h" char rcsid_regexp_c[] = "$Id: regexp.c,v 1.5 2006/07/23 16:28:13 tsjensen Exp $"; /* * The "internal use only" fields in regexp.h are present to pass info from * compile to execute that permits the execute phase to run lots faster on * simple cases. They are: * * regstart char that must begin a match; '\0' if none obvious * reganch is the match anchored (at beginning-of-line only)? * regmust string (pointer into program) that match must include, or NULL * regmlen length of regmust string * * Regstart and reganch permit very fast decisions on suitable starting points * for a match, cutting down the work a lot. Regmust permits fast rejection * of lines that cannot possibly match. The regmust tests are costly enough * that regcomp() supplies a regmust only if the r.e. contains something * potentially expensive (at present, the only such thing detected is * or + * at the start of the r.e., which can involve a lot of backup). Regmlen is * supplied because the test in regexec() needs it and regcomp() is computing * it anyway. */ /* * Structure for regexp "program". This is essentially a linear encoding * of a nondeterministic finite-state machine (aka syntax charts or * "railroad normal form" in parsing technology). Each node is an opcode * plus a "next" pointer, possibly plus an operand. "Next" pointers of * all nodes except BRANCH implement concatenation; a "next" pointer with * a BRANCH on both ends of it is connecting two alternatives. (Here we * have one of the subtle syntax dependencies: an individual BRANCH (as * opposed to a collection of them) is never concatenated with anything * because of operator precedence.) The operand of some types of node is * a literal string; for others, it is a node leading into a sub-FSM. In * particular, the operand of a BRANCH node is the first node of the branch. * (NB this is *not* a tree structure: the tail of the branch connects * to the thing following the set of BRANCHes.) The opcodes are: */ /* definition number opnd? meaning */ #define END 0 /* no End of program. */ #define BOL 1 /* no Match "" at beginning of line. */ #define EOL 2 /* no Match "" at end of line. */ #define ANY 3 /* no Match any one character. */ #define ANYOF 4 /* str Match any character in this string. */ #define ANYBUT 5 /* str Match any character not in this string. */ #define BRANCH 6 /* node Match this alternative, or the next... */ #define BACK 7 /* no Match "", "next" ptr points backward. */ #define EXACTLY 8 /* str Match this string. */ #define NOTHING 9 /* no Match empty string. */ #define STAR 10 /* node Match this (simple) thing 0 or more times. */ #define PLUS 11 /* node Match this (simple) thing 1 or more times. */ #define OPEN 20 /* no Mark this point in input as start of #n. */ /* OPEN+1 is number 1, etc. */ #define CLOSE 30 /* no Analogous to OPEN. */ /* * Opcode notes: * * BRANCH The set of branches constituting a single choice are hooked * together with their "next" pointers, since precedence prevents * anything being concatenated to any individual branch. The * "next" pointer of the last BRANCH in a choice points to the * thing following the whole choice. This is also where the * final "next" pointer of each individual branch points; each * branch starts with the operand node of a BRANCH node. * * BACK Normal "next" pointers all implicitly point forward; BACK * exists to make loop structures possible. * * STAR,PLUS '?', and complex '*' and '+', are implemented as circular * BRANCH structures using BACK. Simple cases (one character * per match) are implemented with STAR and PLUS for speed * and to minimize recursive plunges. * * OPEN,CLOSE ...are numbered at compile time. */ /* * A node is one char of opcode followed by two chars of "next" pointer. * "Next" pointers are stored as two 8-bit pieces, high order first. The * value is a positive offset from the opcode of the node containing it. * An operand, if any, simply follows the node. (Note that much of the * code generation knows about this implicit relationship.) * * Using two bytes for the "next" pointer is vast overkill for most things, * but allows patterns to get big without disasters. */ #define OP(p) (*(p)) #define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377)) #define OPERAND(p) ((p) + 3) /* * See regmagic.h for one further detail of program structure. */ /* * Utility definitions. */ #ifndef CHARBITS #define UCHARAT(p) ((int)*(unsigned char *)(p)) #else #define UCHARAT(p) ((int)*(p)&CHARBITS) #endif #define FAIL(m) { regerror(m); return(NULL); } #define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?') #define META "^$.[()|?+*\\" /* * Flags to be passed up and down. */ #define HASWIDTH 01 /* Known never to match null string. */ #define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */ #define SPSTART 04 /* Starts with * or +. */ #define WORST 0 /* Worst case. */ /* * Global work variables for regcomp(). */ static char *regparse; /* Input-scan pointer. */ static int regnpar; /* () count. */ static char regdummy; static char *regcode; /* Code-emit pointer; ®dummy = don't. */ static long regsize; /* Code size. */ /* * Forward declarations for regcomp()'s friends. */ #ifndef STATIC #define STATIC static #endif STATIC char *reg(); STATIC char *regbranch(); STATIC char *regpiece(); STATIC char *regatom(); STATIC char *regnode(); STATIC char *regnext(); STATIC void regc(); STATIC void reginsert(); STATIC void regtail(); STATIC void regoptail(); #ifdef STRCSPN STATIC int strcspn(); #endif /* - regcomp - compile a regular expression into internal code * * We can't allocate space until we know how big the compiled form will be, * but we can't compile it (and thus know how big it is) until we've got a * place to put the code. So we cheat: we compile it twice, once with code * generation turned off and size counting turned on, and once "for real". * This also means that we don't allocate space until we are sure that the * thing really will compile successfully, and we never have to move the * code and thus invalidate pointers into it. (Note that it has to be in * one piece because free() must be able to free it all.) * * Beware that the optimization-preparation code in here knows about some * of the structure of the compiled regexp. */ regexp * regcomp(exp) char *exp; { register regexp *r; register char *scan; register char *longest; register int len; int flags; if (exp == NULL) FAIL("NULL argument"); /* First pass: determine size, legality. */ regparse = exp; regnpar = 1; regsize = 0L; regcode = ®dummy; regc(MAGIC); if (reg(0, &flags) == NULL) return(NULL); /* Small enough for pointer-storage convention? */ if (regsize >= 32767L) /* Probably could be 65535L. */ FAIL("regexp too big"); /* Allocate space. */ r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize); if (r == NULL) FAIL("out of space"); /* Second pass: emit code. */ regparse = exp; regnpar = 1; regcode = r->program; regc(MAGIC); if (reg(0, &flags) == NULL) return(NULL); /* Dig out information for optimizations. */ r->regstart = '\0'; /* Worst-case defaults. */ r->reganch = 0; r->regmust = NULL; r->regmlen = 0; scan = r->program+1; /* First BRANCH. */ if (OP(regnext(scan)) == END) { /* Only one top-level choice. */ scan = OPERAND(scan); /* Starting-point info. */ if (OP(scan) == EXACTLY) r->regstart = *OPERAND(scan); else if (OP(scan) == BOL) r->reganch++; /* * If there's something expensive in the r.e., find the * longest literal string that must appear and make it the * regmust. Resolve ties in favor of later strings, since * the regstart check works with the beginning of the r.e. * and avoiding duplication strengthens checking. Not a * strong reason, but sufficient in the absence of others. */ if (flags&SPSTART) { longest = NULL; len = 0; for (; scan != NULL; scan = regnext(scan)) if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) { longest = OPERAND(scan); len = strlen(OPERAND(scan)); } r->regmust = longest; r->regmlen = len; } } return(r); } /* - reg - regular expression, i.e. main body or parenthesized thing * * Caller must absorb opening parenthesis. * * Combining parenthesis handling with the base level of regular expression * is a trifle forced, but the need to tie the tails of the branches to what * follows makes it hard to avoid. */ static char * reg(paren, flagp) int paren; /* Parenthesized? */ int *flagp; { register char *ret; register char *br; register char *ender; register int parno; int flags; *flagp = HASWIDTH; /* Tentatively. */ /* Make an OPEN node, if parenthesized. */ if (paren) { if (regnpar >= NSUBEXP) FAIL("too many ()"); parno = regnpar; regnpar++; ret = regnode(OPEN+parno); } else ret = NULL; /* Pick up the branches, linking them together. */ br = regbranch(&flags); if (br == NULL) return(NULL); if (ret != NULL) regtail(ret, br); /* OPEN -> first. */ else ret = br; if (!(flags&HASWIDTH)) *flagp &= ~HASWIDTH; *flagp |= flags&SPSTART; while (*regparse == '|') { regparse++; br = regbranch(&flags); if (br == NULL) return(NULL); regtail(ret, br); /* BRANCH -> BRANCH. */ if (!(flags&HASWIDTH)) *flagp &= ~HASWIDTH; *flagp |= flags&SPSTART; } /* Make a closing node, and hook it on the end. */ ender = regnode((paren) ? CLOSE+parno : END); regtail(ret, ender); /* Hook the tails of the branches to the closing node. */ for (br = ret; br != NULL; br = regnext(br)) regoptail(br, ender); /* Check for proper termination. */ if (paren && *regparse++ != ')') { FAIL("unmatched ()"); } else if (!paren && *regparse != '\0') { if (*regparse == ')') { FAIL("unmatched ()"); } else FAIL("junk on end"); /* "Can't happen". */ /* NOTREACHED */ } return(ret); } /* - regbranch - one alternative of an | operator * * Implements the concatenation operator. */ static char * regbranch(flagp) int *flagp; { register char *ret; register char *chain; register char *latest; int flags; *flagp = WORST; /* Tentatively. */ ret = regnode(BRANCH); chain = NULL; while (*regparse != '\0' && *regparse != '|' && *regparse != ')') { latest = regpiece(&flags); if (latest == NULL) return(NULL); *flagp |= flags&HASWIDTH; if (chain == NULL) /* First piece. */ *flagp |= flags&SPSTART; else regtail(chain, latest); chain = latest; } if (chain == NULL) /* Loop ran zero times. */ (void) regnode(NOTHING); return(ret); } /* - regpiece - something followed by possible [*+?] * * Note that the branching code sequences used for ? and the general cases * of * and + are somewhat optimized: they use the same NOTHING node as * both the endmarker for their branch list and the body of the last branch. * It might seem that this node could be dispensed with entirely, but the * endmarker role is not redundant. */ static char * regpiece(flagp) int *flagp; { register char *ret; register char op; register char *next; int flags; ret = regatom(&flags); if (ret == NULL) return(NULL); op = *regparse; if (!ISMULT(op)) { *flagp = flags; return(ret); } if (!(flags&HASWIDTH) && op != '?') FAIL("*+ operand could be empty"); *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH); if (op == '*' && (flags&SIMPLE)) reginsert(STAR, ret); else if (op == '*') { /* Emit x* as (x&|), where & means "self". */ reginsert(BRANCH, ret); /* Either x */ regoptail(ret, regnode(BACK)); /* and loop */ regoptail(ret, ret); /* back */ regtail(ret, regnode(BRANCH)); /* or */ regtail(ret, regnode(NOTHING)); /* null. */ } else if (op == '+' && (flags&SIMPLE)) reginsert(PLUS, ret); else if (op == '+') { /* Emit x+ as x(&|), where & means "self". */ next = regnode(BRANCH); /* Either */ regtail(ret, next); regtail(regnode(BACK), ret); /* loop back */ regtail(next, regnode(BRANCH)); /* or */ regtail(ret, regnode(NOTHING)); /* null. */ } else if (op == '?') { /* Emit x? as (x|) */ reginsert(BRANCH, ret); /* Either x */ regtail(ret, regnode(BRANCH)); /* or */ next = regnode(NOTHING); /* null. */ regtail(ret, next); regoptail(ret, next); } regparse++; if (ISMULT(*regparse)) FAIL("nested *?+"); return(ret); } /* - regatom - the lowest level * * Optimization: gobbles an entire sequence of ordinary characters so that * it can turn them into a single node, which is smaller to store and * faster to run. Backslashed characters are exceptions, each becoming a * separate node; the code is simpler that way and it's not worth fixing. */ static char * regatom(flagp) int *flagp; { register char *ret; int flags; *flagp = WORST; /* Tentatively. */ switch (*regparse++) { case '^': ret = regnode(BOL); break; case '$': ret = regnode(EOL); break; case '.': ret = regnode(ANY); *flagp |= HASWIDTH|SIMPLE; break; case '[': { register int class; register int classend; if (*regparse == '^') { /* Complement of range. */ ret = regnode(ANYBUT); regparse++; } else ret = regnode(ANYOF); if (*regparse == ']' || *regparse == '-') regc(*regparse++); while (*regparse != '\0' && *regparse != ']') { if (*regparse == '-') { regparse++; if (*regparse == ']' || *regparse == '\0') regc('-'); else { class = UCHARAT(regparse-2)+1; classend = UCHARAT(regparse); if (class > classend+1) FAIL("invalid [] range"); for (; class <= classend; class++) regc(class); regparse++; } } else regc(*regparse++); } regc('\0'); if (*regparse != ']') FAIL("unmatched []"); regparse++; *flagp |= HASWIDTH|SIMPLE; } break; case '(': ret = reg(1, &flags); if (ret == NULL) return(NULL); *flagp |= flags&(HASWIDTH|SPSTART); break; case '\0': case '|': case ')': FAIL("internal urp"); /* Supposed to be caught earlier. */ break; case '?': case '+': case '*': FAIL("?+* follows nothing"); break; case '\\': if (*regparse == '\0') FAIL("trailing \\"); ret = regnode(EXACTLY); regc(*regparse++); regc('\0'); *flagp |= HASWIDTH|SIMPLE; break; default: { register int len; register char ender; regparse--; len = strcspn(regparse, META); if (len <= 0) FAIL("internal disaster"); ender = *(regparse+len); if (len > 1 && ISMULT(ender)) len--; /* Back off clear of ?+* operand. */ *flagp |= HASWIDTH; if (len == 1) *flagp |= SIMPLE; ret = regnode(EXACTLY); while (len > 0) { regc(*regparse++); len--; } regc('\0'); } break; } return(ret); } /* - regnode - emit a node */ static char * /* Location. */ regnode(op) char op; { register char *ret; register char *ptr; ret = regcode; if (ret == ®dummy) { regsize += 3; return(ret); } ptr = ret; *ptr++ = op; *ptr++ = '\0'; /* Null "next" pointer. */ *ptr++ = '\0'; regcode = ptr; return(ret); } /* - regc - emit (if appropriate) a byte of code */ static void regc(b) char b; { if (regcode != ®dummy) *regcode++ = b; else regsize++; } /* - reginsert - insert an operator in front of already-emitted operand * * Means relocating the operand. */ static void reginsert(op, opnd) char op; char *opnd; { register char *src; register char *dst; register char *place; if (regcode == ®dummy) { regsize += 3; return; } src = regcode; regcode += 3; dst = regcode; while (src > opnd) *--dst = *--src; place = opnd; /* Op node, where operand used to be. */ *place++ = op; *place++ = '\0'; *place++ = '\0'; } /* - regtail - set the next-pointer at the end of a node chain */ static void regtail(p, val) char *p; char *val; { register char *scan; register char *temp; register int offset; if (p == ®dummy) return; /* Find last node. */ scan = p; for (;;) { temp = regnext(scan); if (temp == NULL) break; scan = temp; } if (OP(scan) == BACK) offset = scan - val; else offset = val - scan; *(scan+1) = (offset>>8)&0377; *(scan+2) = offset&0377; } /* - regoptail - regtail on operand of first argument; nop if operandless */ static void regoptail(p, val) char *p; char *val; { /* "Operandless" and "op != BRANCH" are synonymous in practice. */ if (p == NULL || p == ®dummy || OP(p) != BRANCH) return; regtail(OPERAND(p), val); } /* * regexec and friends */ /* * Global work variables for regexec(). */ static char *reginput; /* String-input pointer. */ static char *regbol; /* Beginning of input, for ^ check. */ static char **regstartp; /* Pointer to startp array. */ static char **regendp; /* Ditto for endp. */ /* * Forwards. */ STATIC int regtry(); STATIC int regmatch(); STATIC int regrepeat(); #ifdef DEBUG int regnarrate = 0; void regdump(); STATIC char *regprop(); #endif /* - regexec - match a regexp against a string */ int regexec(prog, string) register regexp *prog; register char *string; { register char *s; /* Be paranoid... */ if (prog == NULL || string == NULL) { regerror("NULL parameter"); return(0); } /* Check validity of program. */ if (UCHARAT(prog->program) != MAGIC) { regerror("corrupted program"); return(0); } /* If there is a "must appear" string, look for it. */ if (prog->regmust != NULL) { s = string; while ((s = strchr(s, prog->regmust[0])) != NULL) { if (strncmp(s, prog->regmust, prog->regmlen) == 0) break; /* Found it. */ s++; } if (s == NULL) /* Not present. */ return(0); } /* Mark beginning of line for ^ . */ regbol = string; /* Simplest case: anchored match need be tried only once. */ if (prog->reganch) return(regtry(prog, string)); /* Messy cases: unanchored match. */ s = string; if (prog->regstart != '\0') /* We know what char it must start with. */ while ((s = strchr(s, prog->regstart)) != NULL) { if (regtry(prog, s)) return(1); s++; } else /* We don't -- general case. */ do { if (regtry(prog, s)) return(1); } while (*s++ != '\0'); /* Failure. */ return(0); } /* - regtry - try match at specific point */ static int /* 0 failure, 1 success */ regtry(prog, string) regexp *prog; char *string; { register int i; register char **sp; register char **ep; reginput = string; regstartp = prog->startp; regendp = prog->endp; sp = prog->startp; ep = prog->endp; for (i = NSUBEXP; i > 0; i--) { *sp++ = NULL; *ep++ = NULL; } if (regmatch(prog->program + 1)) { prog->startp[0] = string; prog->endp[0] = reginput; return(1); } else return(0); } /* - regmatch - main matching routine * * Conceptually the strategy is simple: check to see whether the current * node matches, call self recursively to see whether the rest matches, * and then act accordingly. In practice we make some effort to avoid * recursion, in particular by going through "ordinary" nodes (that don't * need to know whether the rest of the match failed) by a loop instead of * by recursion. */ static int /* 0 failure, 1 success */ regmatch(prog) char *prog; { register char *scan; /* Current node. */ char *next; /* Next node. */ scan = prog; #ifdef DEBUG if (scan != NULL && regnarrate) fprintf(stderr, "%s(\n", regprop(scan)); #endif while (scan != NULL) { #ifdef DEBUG if (regnarrate) fprintf(stderr, "%s...\n", regprop(scan)); #endif next = regnext(scan); switch (OP(scan)) { case BOL: if (reginput != regbol) return(0); break; case EOL: if (*reginput != '\0') return(0); break; case ANY: if (*reginput == '\0') return(0); reginput++; break; case EXACTLY: { register int len; register char *opnd; opnd = OPERAND(scan); /* Inline the first character, for speed. */ if (*opnd != *reginput) return(0); len = strlen(opnd); if (len > 1 && strncmp(opnd, reginput, len) != 0) return(0); reginput += len; } break; case ANYOF: if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL) return(0); reginput++; break; case ANYBUT: if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL) return(0); reginput++; break; case NOTHING: break; case BACK: break; case OPEN+1: case OPEN+2: case OPEN+3: case OPEN+4: case OPEN+5: case OPEN+6: case OPEN+7: case OPEN+8: case OPEN+9: { register int no; register char *save; no = OP(scan) - OPEN; save = reginput; if (regmatch(next)) { /* * Don't set startp if some later * invocation of the same parentheses * already has. */ if (regstartp[no] == NULL) regstartp[no] = save; return(1); } else return(0); } break; case CLOSE+1: case CLOSE+2: case CLOSE+3: case CLOSE+4: case CLOSE+5: case CLOSE+6: case CLOSE+7: case CLOSE+8: case CLOSE+9: { register int no; register char *save; no = OP(scan) - CLOSE; save = reginput; if (regmatch(next)) { /* * Don't set endp if some later * invocation of the same parentheses * already has. */ if (regendp[no] == NULL) regendp[no] = save; return(1); } else return(0); } break; case BRANCH: { register char *save; if (OP(next) != BRANCH) /* No choice. */ next = OPERAND(scan); /* Avoid recursion. */ else { do { save = reginput; if (regmatch(OPERAND(scan))) return(1); reginput = save; scan = regnext(scan); } while (scan != NULL && OP(scan) == BRANCH); return(0); /* NOTREACHED */ } } break; case STAR: case PLUS: { register char nextch; register int no; register char *save; register int min; /* * Lookahead to avoid useless match attempts * when we know what character comes next. */ nextch = '\0'; if (OP(next) == EXACTLY) nextch = *OPERAND(next); min = (OP(scan) == STAR) ? 0 : 1; save = reginput; no = regrepeat(OPERAND(scan)); while (no >= min) { /* If it could work, try it. */ if (nextch == '\0' || *reginput == nextch) if (regmatch(next)) return(1); /* Couldn't or didn't -- back up. */ no--; reginput = save + no; } return(0); } break; case END: return(1); /* Success! */ break; default: regerror("memory corruption"); return(0); break; } scan = next; } /* * We get here only if there's trouble -- normally "case END" is * the terminating point. */ regerror("corrupted pointers"); return(0); } /* - regrepeat - repeatedly match something simple, report how many */ static int regrepeat(p) char *p; { register int count = 0; register char *scan; register char *opnd; scan = reginput; opnd = OPERAND(p); switch (OP(p)) { case ANY: count = strlen(scan); scan += count; break; case EXACTLY: while (*opnd == *scan) { count++; scan++; } break; case ANYOF: while (*scan != '\0' && strchr(opnd, *scan) != NULL) { count++; scan++; } break; case ANYBUT: while (*scan != '\0' && strchr(opnd, *scan) == NULL) { count++; scan++; } break; default: /* Oh dear. Called inappropriately. */ regerror("internal foulup"); count = 0; /* Best compromise. */ break; } reginput = scan; return(count); } /* - regnext - dig the "next" pointer out of a node */ static char * regnext(p) register char *p; { register int offset; if (p == ®dummy) return(NULL); offset = NEXT(p); if (offset == 0) return(NULL); if (OP(p) == BACK) return(p-offset); else return(p+offset); } #ifdef DEBUG STATIC char *regprop(); /* - regdump - dump a regexp onto stdout in vaguely comprehensible form */ void regdump(r) regexp *r; { register char *s; register char op = EXACTLY; /* Arbitrary non-END op. */ register char *next; s = r->program + 1; while (op != END) { /* While that wasn't END last time... */ op = OP(s); printf("%2d%s", s-r->program, regprop(s)); /* Where, what. */ next = regnext(s); if (next == NULL) /* Next ptr. */ printf("(0)"); else printf("(%d)", (s-r->program)+(next-s)); s += 3; if (op == ANYOF || op == ANYBUT || op == EXACTLY) { /* Literal string, where present. */ while (*s != '\0') { putchar(*s); s++; } s++; } putchar('\n'); } /* Header fields of interest. */ if (r->regstart != '\0') printf("start `%c' ", r->regstart); if (r->reganch) printf("anchored "); if (r->regmust != NULL) printf("must have \"%s\"", r->regmust); printf("\n"); } /* - regprop - printable representation of opcode */ static char * regprop(op) char *op; { register char *p; static char buf[50]; (void) strcpy(buf, ":"); switch (OP(op)) { case BOL: p = "BOL"; break; case EOL: p = "EOL"; break; case ANY: p = "ANY"; break; case ANYOF: p = "ANYOF"; break; case ANYBUT: p = "ANYBUT"; break; case BRANCH: p = "BRANCH"; break; case EXACTLY: p = "EXACTLY"; break; case NOTHING: p = "NOTHING"; break; case BACK: p = "BACK"; break; case END: p = "END"; break; case OPEN+1: case OPEN+2: case OPEN+3: case OPEN+4: case OPEN+5: case OPEN+6: case OPEN+7: case OPEN+8: case OPEN+9: sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN); p = NULL; break; case CLOSE+1: case CLOSE+2: case CLOSE+3: case CLOSE+4: case CLOSE+5: case CLOSE+6: case CLOSE+7: case CLOSE+8: case CLOSE+9: sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE); p = NULL; break; case STAR: p = "STAR"; break; case PLUS: p = "PLUS"; break; default: regerror("corrupted opcode"); break; } if (p != NULL) (void) strcat(buf, p); return(buf); } #endif /* * The following is provided for those people who do not have strcspn() in * their C libraries. They should get off their butts and do something * about it; at least one public-domain implementation of those (highly * useful) string routines has been published on Usenet. */ #ifdef STRCSPN /* * strcspn - find length of initial segment of s1 consisting entirely * of characters not from s2 */ static int strcspn(s1, s2) char *s1; char *s2; { register char *scan1; register char *scan2; register int count; count = 0; for (scan1 = s1; *scan1 != '\0'; scan1++) { for (scan2 = s2; *scan2 != '\0';) /* ++ moved down. */ if (*scan1 == *scan2++) return(count); count++; } return(count); } #endif boxes-1.1.1/src/regexp/regexp.h0100644000175000001440000000136110460473344016135 0ustar tsjensenusers/* * Definitions etc. for regexp(3) routines. * * Version: $Id: regexp.h,v 1.5 1999/06/25 18:53:51 tsjensen Exp $ * * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof], * not the System V one. */ #ifndef REGEXP_H #define REGEXP_H #define NSUBEXP 10 typedef struct regexp { char *startp[NSUBEXP]; char *endp[NSUBEXP]; char regstart; /* Internal use only. */ char reganch; /* Internal use only. */ char *regmust; /* Internal use only. */ int regmlen; /* Internal use only. */ char program[1]; /* Unwarranted chumminess with compiler. */ } regexp; extern regexp *regcomp(); /* extern int regexec(); */ /* extern size_t regsub(); */ extern size_t myregsub(); /* extern void regerror(); */ #endif /* REGEXP_H */ boxes-1.1.1/src/generate.c0100644000175000001440000011374410460475356015154 0ustar tsjensenusers/* * File: generate.c * Project Main: boxes.c * Date created: June 23, 1999 (Wednesday, 20:10h) * Author: Copyright (C) 1999 Thomas Jensen * Version: $Id: generate.c,v 1.11 2006/07/22 19:21:13 tsjensen Exp $ * Language: ANSI C * World Wide Web: http://boxes.thomasjensen.com/ * Purpose: Box generation, i.e. the drawing of boxes * * Remarks: o This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * o This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * o You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * Revision History: * * $Log: generate.c,v $ * Revision 1.11 2006/07/22 19:21:13 tsjensen * Applied patch by Christoph Dreyer to support unexpansion of leading tabs * Added ability to retain existing tabs * * Revision 1.10 2006/07/12 05:42:28 tsjensen * Updated email and web addresses in comment header * * Revision 1.9 1999-08-31 08:37:01-07 tsjensen * Applied Joe Zbiciak's patches to remove all snprintf()s and variants * Replaced snprintf() calls with calls to concat_strings() in the process * * Revision 1.8 1999/08/22 11:36:45 tsjensen * Removed const from 2nd parameter of justify_line() function * * Revision 1.7 1999/08/21 16:04:24 tsjensen * Bugfix: justify_line() still didn't work right. It should now. (This time I * discovered that indentmode=="text" was confusing it. Arghh!) * * Revision 1.6 1999/08/18 15:37:09 tsjensen * Bugfix: justify_line() still didn't work right. It should now. (Man, I got * a strong sense of déja vu! Weird ...) * * Revision 1.5 1999/08/16 18:30:32 tsjensen * Bugfix: justify_line() still didn't work right. It should now. * * Revision 1.4 1999/07/21 16:50:48 tsjensen * Added GNU GPL disclaimer * Bugfix: When doing the line justification in output_box(), the padding * was counted as part of the modifyable inner part of the box instead of * the fixed box itself, which resulted in strange bugs (tricky one). * * Revision 1.3 1999/06/25 18:42:50 tsjensen * Added justify_line() function for alignment of lines inside the text block * Cleaned up hfill calculation in output_box() * Changed parameters of empty_side() calls to comply with new signature * * Revision 1.2 1999/06/23 19:23:55 tsjensen * Added output_box() from boxes.c * * Revision 1.1 1999/06/23 18:52:54 tsjensen * Initial revision * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "config.h" #include #include #include #include "shape.h" #include "boxes.h" #include "tools.h" #include "generate.h" static const char rcsid_generate_c[] = "$Id: generate.c,v 1.11 2006/07/22 19:21:13 tsjensen Exp $"; static int horiz_precalc (const sentry_t *sarr, size_t *topiltf, size_t *botiltf, size_t *hspace) /* * Calculate data for horizontal box side generation. * * sarr Array of shapes from the current design * * topiltf RESULT: individual lines (columns) to fill by shapes 1, 2, and 3 * botiltf in top part of box (topiltf) and bottom part of box * hspace RESULT: number of columns excluding corners (sum over iltf) * * RETURNS: == 0 on success (result values are set) * != 0 on error * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { int tnumsh; /* number of existent shapes in top part */ int bnumsh; size_t twidth; /* current hspace for top side */ size_t bwidth; /* current hspace for bottom side */ int i; size_t target_width; /* assumed text width for minimum box size */ int btoggle, ttoggle; /* for case 3 w/ 2 elastics */ /* * Initialize future result values */ memset (topiltf, 0, (SHAPES_PER_SIDE-2) * sizeof(size_t)); memset (botiltf, 0, (SHAPES_PER_SIDE-2) * sizeof(size_t)); *hspace = 0; /* * Ensure minimum width for the insides of a box in order to ensure * minimum box size required by current design */ if (input.maxline >= (opt.design->minwidth - sarr[north_side[0]].width - sarr[north_side[SHAPES_PER_SIDE-1]].width)) { target_width = input.maxline; } else { target_width = opt.design->minwidth - sarr[north_side[0]].width - sarr[north_side[SHAPES_PER_SIDE-1]].width; } /* * Compute number of existent shapes in top and in bottom part */ tnumsh = 0; bnumsh = 0; for (i=1; iminwidth %d, input.maxline %d, target_width" " %d, tnumsh %d, bnumsh %d\n", opt.design->minwidth, input.maxline, target_width, tnumsh, bnumsh); #endif twidth = 0; bwidth = 0; btoggle = 1; /* can be 1 or 3 */ ttoggle = 1; do { shape_t *seite; /* ptr to north_side or south_side */ size_t *iltf; /* ptr to botiltf or topiltf */ size_t *res_hspace; /* ptr to bwidth or twidth */ int *stoggle; /* ptr to btoggle or ttoggle */ int numsh; /* either bnumsh or tnumsh */ /* * Set pointers to the side which is currently shorter, * so it will be advanced in this step. */ if (twidth > bwidth) { /* south (bottom) is behind */ seite = south_side; iltf = botiltf; res_hspace = &bwidth; numsh = bnumsh; stoggle = &btoggle; } else { /* north (top) is behind */ seite = north_side; iltf = topiltf; res_hspace = &twidth; numsh = tnumsh; stoggle = &ttoggle; } switch (numsh) { case 1: /* * only one shape -> it must be elastic */ for (i=1; i one must be elastic, the other must not */ for (i=1; i one or two of them must be elastic * If two are elastic, they are the two outer ones. */ for (i=1; i= (opt.design->minheight - sarr[west_side[0]].height - sarr[west_side[SHAPES_PER_SIDE-1]].height)) { target_height = input.anz_lines; } else { target_height = opt.design->minheight - sarr[west_side[0]].height - sarr[west_side[SHAPES_PER_SIDE-1]].height; } /* * Compute number of existent shapes in left and right part (1..3) */ lnumsh = 0; rnumsh = 0; for (i=1; i rheight) { /* east (right) is behind */ seite = east_side; iltf = rightiltf; res_vspace = &rheight; numsh = rnumsh; stoggle = &rtoggle; } else { /* west (left) is behind */ seite = west_side; iltf = leftiltf; res_vspace = &lheight; numsh = lnumsh; stoggle = <oggle; } switch (numsh) { case 1: /* * only one shape -> it must be elastic */ for (i=1; i one must be elastic, the other must not */ for (i=1; i one or two of them must be elastic * If two are elastic, they are the two outer ones. */ for (i=1; iheight; ++line) { result->chars[line] = (char *) calloc (1, result->width+1); if (result->chars[line] == NULL) { perror (PROJECT); if ((long)--line >= 0) do { BFREE (result->chars[line--]); } while ((long)line >= 0); return 1; /* out of memory */ } } cshape = (seite == north_side)? 0 : 2; for (j=0; jwidth; j+=sarr[seite[cshape+1]].width) { while (iltf[cshape] == 0) cshape += (seite == north_side)? 1 : -1; for (line=0; lineheight; ++line) strcat (result->chars[line], sarr[seite[cshape+1]].chars[line]); iltf[cshape] -= sarr[seite[cshape+1]].width; } return 0; /* all clear */ } static void horiz_assemble (const sentry_t *sarr, const shape_t *seite, size_t *iltf, sentry_t *result) { size_t j; size_t sc; /* index to shape chars (lines) */ int cshape; /* current shape (idx to iltf) */ shape_t ctop, cbottom; if (seite == east_side) { ctop = seite[0]; cbottom = seite[SHAPES_PER_SIDE-1]; cshape = 0; } else { ctop = seite[SHAPES_PER_SIDE-1]; cbottom = seite[0]; cshape = 2; } for (j=0; jchars[j] = sarr[ctop].chars[j]; for (j=0; jchars[result->height-sarr[cbottom].height+j] = sarr[cbottom].chars[j]; sc = 0; for (j=sarr[ctop].height; j < result->height-sarr[cbottom].height; ++j) { while (iltf[cshape] == 0) { if (seite == east_side) ++cshape; else --cshape; sc = 0; } if (sc == sarr[seite[cshape+1]].height) sc = 0; result->chars[j] = sarr[seite[cshape+1]].chars[sc]; ++sc; iltf[cshape] -= 1; } } static int horiz_generate (sentry_t *tresult, sentry_t *bresult) /* * Generate top and bottom parts of box (excluding corners). * * RETURNS: == 0 if successful (resulting char array is stored in [bt]result) * != 0 on error * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { size_t biltf[SHAPES_PER_SIDE-2]; /* individual lines to fill (bottom) */ size_t tiltf[SHAPES_PER_SIDE-2]; /* individual lines to fill (top) */ int rc; /* received return code */ tresult->height = highest (opt.design->shape, SHAPES_PER_SIDE, NW, NNW, N, NNE, NE); bresult->height = highest (opt.design->shape, SHAPES_PER_SIDE, SW, SSW, S, SSE, SE); rc = horiz_precalc (opt.design->shape, tiltf, biltf, &(tresult->width)); if (rc) return rc; bresult->width = tresult->width; #ifdef DEBUG fprintf (stderr, "Top side box rect width %d, height %d.\n", tresult->width, tresult->height); fprintf (stderr, "Top columns to fill: %s %d, %s %d, %s %d.\n", shape_name[north_side[1]], tiltf[0], shape_name[north_side[2]], tiltf[1], shape_name[north_side[3]], tiltf[2]); fprintf (stderr, "Bottom side box rect width %d, height %d.\n", bresult->width, bresult->height); fprintf (stderr, "Bottom columns to fill: %s %d, %s %d, %s %d.\n", shape_name[south_side[1]], biltf[0], shape_name[south_side[2]], biltf[1], shape_name[south_side[3]], biltf[2]); #endif tresult->chars = (char **) calloc (tresult->height, sizeof(char *)); bresult->chars = (char **) calloc (bresult->height, sizeof(char *)); if (tresult->chars == NULL || bresult->chars == NULL) return 1; rc = vert_assemble (opt.design->shape, north_side, tiltf, tresult); if (rc) return rc; rc = vert_assemble (opt.design->shape, south_side, biltf, bresult); if (rc) return rc; #if defined(DEBUG) && 1 { /* * Debugging code - Output horizontal sides of box */ size_t j; fprintf (stderr, "TOP SIDE:\n"); for (j=0; jheight; ++j) { fprintf (stderr, " %2d: \'%s\'\n", j, tresult->chars[j]? tresult->chars[j] : "(null)"); } fprintf (stderr, "BOTTOM SIDE:\n"); for (j=0; jheight; ++j) { fprintf (stderr, " %2d: \'%s\'\n", j, bresult->chars[j]? bresult->chars[j] : "(null)"); } } #endif return 0; /* all clear */ } static int vert_generate (sentry_t *lresult, sentry_t *rresult) /* * Generate vertical sides of box. * * RETURNS: == 0 on success (resulting char array is stored in [rl]result) * != 0 on error * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { size_t vspace = 0; size_t leftiltf[SHAPES_PER_SIDE-2]; /* individual lines to fill */ size_t rightiltf[SHAPES_PER_SIDE-2]; /* individual lines to fill */ int rc; /* received return code */ lresult->width = widest (opt.design->shape, SHAPES_PER_SIDE, SW, WSW, W, WNW, NW); rresult->width = widest (opt.design->shape, SHAPES_PER_SIDE, SE, ESE, E, ENE, NE); rc = vert_precalc (opt.design->shape, leftiltf, rightiltf, &vspace); if (rc) return rc; lresult->height = vspace + opt.design->shape[NW].height + opt.design->shape[SW].height; rresult->height = vspace + opt.design->shape[NE].height + opt.design->shape[SE].height; #ifdef DEBUG fprintf (stderr, "Left side box rect width %d, height %d, vspace %d.\n", lresult->width, lresult->height, vspace); fprintf (stderr, "Left lines to fill: %s %d, %s %d, %s %d.\n", shape_name[west_side[1]], leftiltf[0], shape_name[west_side[2]], leftiltf[1], shape_name[west_side[3]], leftiltf[2]); fprintf (stderr, "Right side box rect width %d, height %d, vspace %d.\n", rresult->width, rresult->height, vspace); fprintf (stderr, "Right lines to fill: %s %d, %s %d, %s %d.\n", shape_name[east_side[1]], rightiltf[0], shape_name[east_side[2]], rightiltf[1], shape_name[east_side[3]], rightiltf[2]); #endif lresult->chars = (char **) calloc (lresult->height, sizeof(char *)); if (lresult->chars == NULL) return 1; rresult->chars = (char **) calloc (rresult->height, sizeof(char *)); if (rresult->chars == NULL) return 1; horiz_assemble (opt.design->shape, west_side, leftiltf, lresult); horiz_assemble (opt.design->shape, east_side, rightiltf, rresult); #if defined(DEBUG) && 1 { /* * Debugging code - Output left and right side of box */ size_t j; fprintf (stderr, "LEFT SIDE:\n"); for (j=0; jheight; ++j) { fprintf (stderr, " %2d: \'%s\'\n", j, lresult->chars[j]? lresult->chars[j] : "(null)"); } fprintf (stderr, "RIGHT SIDE:\n"); for (j=0; jheight; ++j) { fprintf (stderr, " %2d: \'%s\'\n", j, rresult->chars[j]? rresult->chars[j] : "(null)"); } } #endif return 0; /* all clear */ } int generate_box (sentry_t *thebox) /* * * RETURNS: == 0 if successful (thebox is set) * != 0 on error * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { int rc; int i; rc = horiz_generate (&(thebox[0]), &(thebox[2])); if (rc) goto err; rc = vert_generate (&(thebox[3]), &(thebox[1])); if (rc) goto err; return 0; /* all clear */ err: for (i=0; ilen; if (opt.justify == '\0') return 0; if (empty_line(line)) return 0; for (p=line->text; *p==' ' || *p=='\t'; ++p); newlen = line->len - (p-line->text); switch (opt.justify) { case 'l': if (opt.design->indentmode == 't') { memmove (line->text+input.indent, p, newlen+1); line->len = newlen + input.indent; } else { memmove (line->text, p, newlen+1); line->len = newlen; } break; case 'c': if (opt.design->indentmode == 't') { shift = (input.maxline-input.indent-newlen) / 2 + input.indent; skew -= input.indent; if ((input.maxline-input.indent-newlen) % 2 && skew == 1) ++shift; } else { shift = (input.maxline - newlen) / 2; if ((input.maxline - newlen) % 2 && skew == 1) ++shift; } newtext = (char *) calloc (shift + newlen + 1, sizeof(char)); if (newtext == NULL) { perror (PROJECT); return 2; } spaces = (char *) malloc (shift+1); if (spaces == NULL) { perror (PROJECT); BFREE (newtext); return 3; } memset (spaces, ' ', shift); spaces[shift] = '\0'; #if defined(DEBUG) && 0 fprintf (stderr, "j(c): newlen=%d, shift=%d, spaces=\"%s\"\n", newlen, shift, spaces); #endif strncpy (newtext, spaces, shift); strncat (newtext, p, newlen); newtext[shift+newlen] = '\0'; BFREE (spaces); BFREE (line->text); line->text = newtext; line->len = shift + newlen; break; case 'r': shift = input.maxline - newlen; newtext = (char *) calloc (input.maxline+1, sizeof(char)); if (newtext == NULL) { perror (PROJECT); return 2; } spaces = (char *) malloc (shift+1); if (spaces == NULL) { perror (PROJECT); BFREE (newtext); return 3; } memset (spaces, ' ', shift); spaces[shift] = '\0'; strncpy (newtext, spaces, shift); strncat (newtext, p, newlen); newtext[input.maxline] = '\0'; BFREE (spaces); BFREE (line->text); line->text = newtext; line->len = input.maxline; break; default: fprintf (stderr, "%s: internal error\n", PROJECT); return 1; } /* * If we might have broken the maxline value, recalculate it. */ if (opt.justify != 'r' && oldlen == input.maxline) { size_t k; input.maxline = 0; for (k=0; k input.maxline) input.maxline = input.lines[k].len; } } return 0; } int output_box (const sentry_t *thebox) /* * Generate final output using the previously generated box parts. * * thebox Array of four shapes which contain the previously generated * box parts in the following order: BTOP, BRIG, BBOT, BLEF * * RETURNS: == 0 if successful * != 0 on error * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { size_t j; size_t nol = thebox[BRIG].height; /* number of output lines */ char trailspc[LINE_MAX+1]; char *indentspc; int indentspclen; size_t vfill, vfill1, vfill2; /* empty lines/columns in box */ size_t hfill; char *hfill1, *hfill2; /* space before/after text */ size_t hpl, hpr; size_t r; int rc; char obuf[LINE_MAX+1]; /* final output buffer */ size_t obuf_len; /* length of content of obuf */ size_t skip_start; /* lines to skip for box top */ size_t skip_end; /* lines to skip for box bottom */ size_t skip_left; /* true if left box part is to be skipped */ int ntabs, nspcs; /* needed for unexpand of tabs */ char *restored_indent; #ifdef DEBUG fprintf (stderr, "Padding used: left %d, top %d, right %d, bottom %d\n", opt.design->padding[BLEF], opt.design->padding[BTOP], opt.design->padding[BRIG], opt.design->padding[BBOT]); #endif /* * Create string of spaces for indentation */ indentspc = NULL; ntabs = nspcs = indentspclen = 0; if (opt.design->indentmode == 'b') { if (opt.tabexp == 'u') { ntabs = input.indent / opt.tabstop; nspcs = input.indent % opt.tabstop; indentspclen = ntabs + nspcs; } else { indentspclen = input.indent; } indentspc = (char *) malloc (indentspclen + 1); if (indentspc == NULL) { perror (PROJECT); return 1; } if (opt.tabexp == 'u') { memset (indentspc, (int)'\t', ntabs); memset (indentspc + ntabs, (int)' ', nspcs); } else { memset (indentspc, (int)' ', indentspclen); } indentspc[indentspclen] = '\0'; } else { indentspc = (char *) strdup (""); if (indentspc == NULL) { perror (PROJECT); return 1; } } /* * Provide string of spaces for filling of space between text and * right side of box */ memset (trailspc, (int)' ', LINE_MAX); trailspc[LINE_MAX] = '\0'; /* * Compute number of empty lines in box (vfill). */ vfill = nol - thebox[BTOP].height - thebox[BBOT].height - input.anz_lines; vfill -= opt.design->padding[BTOP] + opt.design->padding[BBOT]; if (opt.valign == 'c') { vfill1 = vfill / 2; vfill2 = vfill1 + (vfill % 2); } else if (opt.valign == 'b') { vfill1 = vfill; vfill2 = 0; } else { vfill1 = 0; vfill2 = vfill; } vfill1 += opt.design->padding[BTOP]; vfill2 += opt.design->padding[BBOT]; vfill += opt.design->padding[BTOP] + opt.design->padding[BBOT]; /* * Provide strings for horizontal text alignment. */ hfill = thebox[BTOP].width - input.maxline; hfill1 = (char *) malloc (hfill+1); hfill2 = (char *) malloc (hfill+1); if (!hfill1 || !hfill2) { perror (PROJECT); return 1; } memset (hfill1, (int)' ', hfill+1); memset (hfill2, (int)' ', hfill+1); hfill1[hfill] = '\0'; hfill2[hfill] = '\0'; hpl = 0; hpr = 0; if (hfill == 1) { if (opt.halign == 'r' || opt.design->padding[BLEF] > opt.design->padding[BRIG]) { hpl = 1; hpr = 0; } else { hpl = 0; hpr = 1; } } else { hfill -= opt.design->padding[BLEF] + opt.design->padding[BRIG]; if (opt.halign == 'c') { hpl = hfill/2 + opt.design->padding[BLEF]; hpr = hfill/2 + opt.design->padding[BRIG] + (hfill%2); } else if (opt.halign == 'r') { hpl = hfill + opt.design->padding[BLEF]; hpr = opt.design->padding[BRIG]; } else { hpl = opt.design->padding[BLEF]; hpr = hfill + opt.design->padding[BRIG]; } hfill += opt.design->padding[BLEF] + opt.design->padding[BRIG]; } hfill1[hpl] = '\0'; hfill2[hpr] = '\0'; #if defined(DEBUG) fprintf (stderr, "Alignment: hfill %d hpl %d hpr %d, vfill %d " "vfill1 %d vfill2 %d.\n", hfill, hpl, hpr, vfill, vfill1, vfill2); fprintf (stderr, " hfill1 = \"%s\"; hfill2 = \"%s\"; " "indentspc = \"%s\";\n", hfill1, hfill2, indentspc); #endif /* * Find out if and how many leading or trailing blank lines must be * skipped because the corresponding box side was defined empty. */ skip_start = 0; skip_end = 0; skip_left = 0; if (empty_side (opt.design->shape, BTOP)) skip_start = opt.design->shape[NW].height; if (empty_side (opt.design->shape, BBOT)) skip_end = opt.design->shape[SW].height; if (empty_side (opt.design->shape, BLEF)) skip_left = opt.design->shape[NW].width; /* could simply be 1, though */ #if defined(DEBUG) fprintf (stderr, "skip_start = %d; skip_end = %d; skip_left = %d; " "nol = %d;\n", skip_start, skip_end, skip_left, nol); #endif /* * Generate actual output */ for (j=skip_start; j= 0? input.lines[ti].text : "", hfill2, trailspc, thebox[BRIG].chars[j]); } else { /* bottom vfill */ r = thebox[BTOP].width; trailspc[r] = '\0'; restored_indent = tabbify_indent (input.anz_lines - 1, indentspc, indentspclen); concat_strings (obuf, LINE_MAX+1, 4, restored_indent, skip_left?"":thebox[BLEF].chars[j], trailspc, thebox[BRIG].chars[j]); } trailspc[r] = ' '; } else { /* box bottom */ restored_indent = tabbify_indent (input.anz_lines - 1, indentspc, indentspclen); concat_strings (obuf, LINE_MAX+1, 4, restored_indent, skip_left?"":thebox[BLEF].chars[j], thebox[BBOT].chars[j-(nol-thebox[BBOT].height)], thebox[BRIG].chars[j]); } obuf_len = strlen (obuf); if (obuf_len > LINE_MAX) { size_t newlen = LINE_MAX; btrim (obuf, &newlen); } else { btrim (obuf, &obuf_len); } if (opt.tabexp == 'k') { BFREE (restored_indent); } fprintf (opt.outfile, "%s\n", obuf); } BFREE (indentspc); BFREE (hfill1); BFREE (hfill2); return 0; /* all clear */ } /*EOF*/ /* vim: set sw=4: */ boxes-1.1.1/src/generate.h0100644000175000001440000000371610460473717015155 0ustar tsjensenusers/* * File: generate.h * Project Main: boxes.c * Date created: June 23, 1999 (Wednesday, 20:12h) * Author: Copyright (C) 1999 Thomas Jensen * Version: $Id: generate.h,v 1.4 2006/07/12 05:41:52 tsjensen Exp $ * Language: ANSI C * World Wide Web: http://boxes.thomasjensen.com/ * Purpose: Box generation, i.e. the drawing of boxes * * Remarks: o This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * o This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * o You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * Revision History: * * $Log: generate.h,v $ * Revision 1.4 2006/07/12 05:41:52 tsjensen * Updated email and web addresses in comment header * * Revision 1.3 1999-08-14 12:30:01-07 tsjensen * Added GNU GPL disclaimer * * Revision 1.2 1999/06/25 18:45:12 tsjensen * Added output_box() function * * Revision 1.1 1999/06/23 18:53:03 tsjensen * Initial revision * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef GENERATE_H #define GENERATE_H int generate_box (sentry_t *thebox); int output_box (const sentry_t *thebox); #endif /*GENERATE_H*/ /*EOF*/ /* vim: set cindent sw=4: */ boxes-1.1.1/src/boxes.c0100644000175000001440000017553610474610761014505 0ustar tsjensenusers/* * File: boxes.c * Date created: March 18, 1999 (Thursday, 15:09h) * Author: Copyright (C) 1999 Thomas Jensen * Version: $Id: boxes.c,v 1.39 2006/08/28 15:53:46 tsjensen Exp $ * Language: ANSI C * Platforms: sunos5/sparc, for now * World Wide Web: http://boxes.thomasjensen.com/ * Purpose: Filter to draw boxes around input text (and remove it). * * Remarks: o This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later * version. * o This program is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * o You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA * * - This version is leaking small bits of memory. Since boxes * runs as a filter in its own process, the leaks are irrelevant. * - The decision to number box shapes in clockwise order was a * major design mistake. Treatment of box parts of the same * alignment (N-S and E-W) is usually combined in one function, * which must now deal with the numbering being reversed all the * time. This is nasty, but changing the shape order would * pretty much mean a total rewrite of the code, so we'll have * to live with it. * - All shapes defined in a box design must be used in any box of * that design at least once. In other words, there must not be * a shape which is defined in the config file but cannot be * found in an actual box of that design. This sort of limits * how small your boxes can get. However, in practice it is not * a problem, because boxes which must be small usually consist * of small shapes which can be packed pretty tightly anyway. * And again, changing this would pretty much mean a total * rewrite. * * Revision History: * * $Log: boxes.c,v $ * Revision 1.39 2006/08/28 15:53:46 tsjensen * Added support for --help and -? options, which do the same as -h * (This feature was requested by Raphael Wimmer). * * Revision 1.38 2006/07/22 19:40:40 tsjensen * Applied patch by Christoph Dreyer to support unexpansion of leading tabs * Added ability to retain leading tabs in their original positions * Mending a box with -m now implies -k false * * Revision 1.37 2006/07/12 05:49:50 tsjensen * Updated email and web addresses in comment header etc. * Applied patch by Elmar Loos that adds -m option for mending a box * Changed a few more things to make the box mending patch work in * connection with all the other boxes options * * Revision 1.36 2000-04-01 10:27:17-08 tsjensen * Added -c option (simple comment definition) * * Revision 1.35 2000/03/21 14:26:31 tsjensen * Minor change to make boxes compile on DEC/OSF, too (S_ISDIR) * * Revision 1.34 2000/03/17 23:44:26 tsjensen * Port to Win32 platform based on patches by Ron Aaron * Changes only affect Win32 version. Win32 behavior differs from the UNIX * platforms in the way the config file is searched and the config file * name (boxes.cfg). * * Revision 1.33 1999/09/10 19:21:05 tsjensen * Eliminated use of PATH_MAX in order to ease porting * Restructured infile/outfile code to eliminate need for access() function * and improve readability * Added file type check before reading config file. boxes used to generate * a weird error message if the config file is a directory * * Revision 1.32 1999/08/22 11:34:46 tsjensen * Bugfix: no-input-check must take place before indentation computation * * Revision 1.31 1999/08/21 23:33:03 tsjensen * Added usage of system-wide config file (GLOBALCONF from boxes.h) * Moved config file selection code into it own function (get_config_file()) * * Revision 1.30 1999/08/21 15:55:42 tsjensen * Updated usage information * Updated quickinfo (-l -d) with killblank default value * Made indentation computation into a function of its own (get_indent()) * Bugfix: REVERSION code may change indentation -> recompute if necessary * * Revision 1.29 1999/08/16 18:29:39 tsjensen * Added output of total number of designs for -l * * Revision 1.28 1999/07/23 16:15:48 tsjensen * Added quickinfo mode to list_styles(). Called with -l and -d together. * * Revision 1.27 1999/07/21 16:53:17 tsjensen * Bugfix: Empty box sides were still counted when -s was specified (so * -s x5 would get you only three lines). * * Revision 1.26 1999/07/20 18:45:29 tsjensen * Added GNU GPL disclaimer * Added -k option (kill leading/trailing blank lines on removal yes/no) * Bugfix: REPLACE and indentation conflict. Now applying regexp substitutions * only after indentation was already handled. * * Revision 1.25 1999/07/12 18:16:36 tsjensen * Added include "config.h" to top of file * * Revision 1.24 1999/06/30 12:37:25 tsjensen * Added [lcr] "shorthand" to -a option * * Revision 1.23 1999/06/30 12:16:38 tsjensen * Removed entire select_design stuff, because the parser now returns much * smaller data structures. The first design pointed to by designs is always * the one we need (except for ops on *all* designs). * The first design in config file is now default design (no DEF_DESIGN anymore). * * Revision 1.22 1999/06/28 12:19:29 tsjensen * Moved parser init and cleanup from main() to parser.y * Some further cleanup in main() * * Revision 1.21 1999/06/25 18:46:39 tsjensen * Bugfix: Mixed up SW and NE in padding calculation (tricky, that one) * Added indent mode command line option for grammar overrides * Moved empty_side() to shape.c after small change in signature * Added text-in-block justification (j) to alignment option (-a) * * Revision 1.20 1999/06/23 19:17:27 tsjensen * Removed snprintf() and vsnprintf() prototypes (why were they in anyway?) * along with stdarg.h include * Exported input global data and empty_side() function * Declared non-exported functions static * Moved horiz_precalc(), vert_precalc(), horiz_assemble(), vert_assemble(), * horiz_generate(), vert_generate(), generate_box() and output_box() to a * new file generate.c * Moved best_match(), hmm(), detect_horiz(), detect_design(), remove_box() * and output_input() to a new file remove.c * * Revision 1.19 1999/06/23 12:31:26 tsjensen * Improvements on design detection (could still be better though) * Moved iscorner(), on_side(), isempty(), shapecmp(), both_on_side(), * shape_distance(), empty_side(), highest(), and widest() as well as * some data structures and macros related to shapes to new file shape.c * * Revision 1.18 1999/06/22 12:03:33 tsjensen * DEBUGging is now activated in boxes.h * Moved MAX_TABSTOP, LINE_MAX macros and struct opt_t to boxes.h * Moved BMAX, strrstr(), btrim(), yyerror(), expand_tabs_into(), * regerror(), empty_line() to a new file tools.c, added #include tools.h * Some cleanup in main() * Declared style_sort() helper function static * Renamed strrstr() to my_strnrstr() (now defined in tools.c) * Default design is now defined by DEF_DESIGN macro * Changed select_design(), because default design value now set in process_commandline() * Bugfix: segfaulted if shape was bigger than input when detecting design * Bugfix: Padding was not removed when box was removed * Bugfix: Forgot null byte when removing west box side * * Revision 1.17 1999/06/20 14:20:29 tsjensen * Added code for padding handling (-p) * Added BMAX macro (returns maximum of two values) * * Revision 1.16 1999/06/17 19:07:06 tsjensen * Moved line_t to boxes.h * empty_line() now also considers \r and \n whitespace * Added empty_side() function * Added handling of empty box sides in output_box() * * Revision 1.15 1999/06/15 12:07:39 tsjensen * Removed a stray debug message * Move apply_substitutions() regexp handling function up in file * Use apply_substitutions() in read_input() routine also * Moved "extern int yyparse()" prototype to start of file * * Revision 1.14 1999/06/14 12:08:49 tsjensen * Bugfix: best_match() box side detection used numw instead of nume * Added apply_substitutions() routine for central regexp handling * Added regexp reversion code for box removal * Unified use of current_re[pv]rule * Added a few comments and debugging code * * Revision 1.13 1999/06/13 15:28:31 tsjensen * Some error message clean-up * Regular expression substitutions on input text only if *drawing* a box, * not if the box is to be removed (requires other substitutions, todo). * Added code for box design auto-detection when removing a box. * * Revision 1.12 1999/06/04 18:13:26 tsjensen * Don't adjust indentation after removing a box unless something was * removed on the west side * East Padding made dynamic, i.e. dependant on the east side size * * Revision 1.11 1999/06/03 19:24:14 tsjensen * A few fixes related to box removal (as expected) * * Revision 1.10 1999/06/03 18:54:05 tsjensen * Lots of fixes * Added remove box functionality (-r), which remains to be tested * * Revision 1.9 1999/04/09 13:33:24 tsjensen * Removed code related to OFFSET blocks (obsolete) * * Revision 1.8 1999/04/04 16:09:01 tsjensen * Added code for specification of indentation handling of input * Added regular expression substitutions * Some minor fixes * * Revision 1.7 1999/04/02 18:42:44 tsjensen * Added infile/outfile parameter code (pasted from tal, more or less) * Added code to remove trailing spaces from output lines * * Revision 1.6 1999/04/01 17:26:18 tsjensen * Some bug fixes * Added size option (-s) * Added Alignment Option (-a) * It seems actually usable for drawing boxes :-) * * Revision 1.4 1999/03/30 13:30:19 tsjensen * Added minimum width/height for a design. Fixed screwed tiny boxes. * Bugfix: Did not handle zero input. * * Revision 1.1 1999/03/18 15:09:17 tsjensen * Initial revision * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "config.h" #include #include #include #include #include #include #include #include #include "shape.h" #include "boxes.h" #include "tools.h" #include "regexp.h" #include "generate.h" #include "remove.h" #ifdef __MINGW32__ #include #endif extern char *optarg; /* for getopt() */ extern int optind, opterr, optopt; /* for getopt() */ #ifdef __MINGW32__ #define BOXES_CONFIG "boxes.cfg" /* filename of config file in $HOME */ #else #define BOXES_CONFIG ".boxes" #endif static const char rcsid_boxes_c[] = "$Id: boxes.c,v 1.39 2006/08/28 15:53:46 tsjensen Exp $"; /* _\|/_ (o o) +----oOO-{_}-OOo------------------------------------------------------------+ | G l o b a l V a r i a b l e s | +--------------------------------------------------------------------------*/ extern int yyparse(); extern FILE *yyin; /* lex input file */ char *yyfilename = NULL; /* file name of config file used */ design_t *designs = NULL; /* available box designs */ int design_idx = 0; /* anz_designs-1 */ int anz_designs = 0; /* no of designs after parsing */ opt_t opt; /* command line options */ input_t input = INPUT_INITIALIZER; /* input lines */ /* _\|/_ (o o) +----oOO-{_}-OOo------------------------------------------------------------+ | F u n c t i o n s | +--------------------------------------------------------------------------*/ static void usage (FILE *st) /* * Print usage information on stream st. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { fprintf (st, "Usage: %s [options] [infile [outfile]]\n", PROJECT); fprintf (st, " -a fmt alignment/positioning of text inside box [default: hlvt]\n"); fprintf (st, " -c str use single shape box design where str is the W shape\n"); fprintf (st, " -d name box design [default: first one in file]\n"); fprintf (st, " -f file configuration file\n"); fprintf (st, " -h print usage information\n"); fprintf (st, " -i mode indentation mode [default: box]\n"); fprintf (st, " -k bool leading/trailing blank line retention on removal\n"); fprintf (st, " -l list available box designs w/ samples\n"); fprintf (st, " -m mend box, i.e. remove it and redraw it afterwards\n"); fprintf (st, " -p fmt padding [default: none]\n"); fprintf (st, " -r remove box\n"); fprintf (st, " -s wxh box size (width w and/or height h)\n"); fprintf (st, " -t str tab stop distance and expansion [default: %de]\n", DEF_TABSTOP); fprintf (st, " -v print version information\n"); } static void usage_short (FILE *st) /* * Print abbreviated usage information on stream st. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { fprintf (st, "Usage: %s [options] [infile [outfile]]\n", PROJECT); fprintf (st, "Try `%s -h' for more information.\n", PROJECT); } static void usage_long (FILE *st) /* * Print usage information on stream st, including a header text. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { fprintf (st, "%s - draws any kind of box around your text (and removes it)\n", PROJECT); fprintf (st, " (c) Thomas Jensen \n"); fprintf (st, " Web page: http://boxes.thomasjensen.com/\n"); usage (st); } static int is_dir (const char *path) /* * Return true if file specified by path is a directory * * path file name to check * * On Windows, this check seems unnecessary, because fopen() seems to fail * when applied to a directory. * * RETURNS: == 0 path is not a directory * > 0 path is a directory * == -1 error in stat() call * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { struct stat sinf; int rc; rc = stat (path, &sinf); if (rc) { perror (PROJECT); return -1; } return S_ISDIR(sinf.st_mode); } static int get_config_file() /* * Set yyin and yyfilename to the config file to be used. * * If no config file was specified on the command line (yyin == stdin), * try getting it from other locations: * (1) contents of BOXES environment variable * (2) file ~/.boxes * (3) system-wide config file from GLOBALCONF macro. * If neither file exists, return complainingly. * * May change current working directory to $HOME. * * RETURNS: == 0 success (yyin and yyfilename are set) * != 0 error (yyin is unmodified) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { FILE *new_yyin = NULL; char *s; /* points to data from environment */ int rc; #ifdef __MINGW32__ char exepath[256]; /* for constructing config file path */ #endif if (yyin != stdin) return 0; /* we're already ok */ /* * Try getting it from the BOXES environment variable */ s = getenv ("BOXES"); if (s) { new_yyin = fopen (s, "r"); if (new_yyin == NULL) { fprintf (stderr, "%s: Couldn't open config file '%s' " "for input (taken from $BOXES).\n", PROJECT, s); return 1; } rc = is_dir (s); if (rc == -1) return 1; else if (rc) { fprintf (stderr, "%s: Alleged config file '%s' is a directory " "(taken from $BOXES)\n", PROJECT, s); return 1; } yyfilename = (char *) strdup (s); if (yyfilename == NULL) { perror (PROJECT); return 1; } yyin = new_yyin; return 0; } /* * Try getting it from ~/.boxes */ s = getenv ("HOME"); if (s) { rc = chdir (s); if (rc) { perror (PROJECT); return 1; } new_yyin = fopen (BOXES_CONFIG, "r"); if (new_yyin) { rc = is_dir (BOXES_CONFIG); if (rc == -1) return 1; else { if (rc == 0) { yyfilename = (char *) strdup (BOXES_CONFIG); if (yyfilename == NULL) { perror (PROJECT); return 1; } yyin = new_yyin; return 0; } else { fclose (new_yyin); new_yyin = NULL; } } } } else { #ifndef __MINGW32__ /* Do not print this warning on windows. */ fprintf (stderr, "%s: warning: Environment variable HOME not set!\n", PROJECT); #endif } /* * Try reading the system-wide config file * On UNIX, the global config file must be given by the GLOBALCONF macro. * On Win32, it is expected to reside in the same directory as the binary * used, and its name is assumed to be execfilename+".cfg". */ #ifdef __MINGW32__ if (GetModuleFileName (NULL, exepath, 255) != 0) { char *p = strrchr (exepath, '.') + 1; if (p) { /* p is always != NULL, because we get the full path */ *p = '\0'; if (strlen(exepath) < 253) { strcat (exepath, "cfg"); /* c:\blah\boxes.cfg */ } else { fprintf (stderr, "%s: path too long. Using C:\\boxes.cfg.\n", PROJECT); strcpy (exepath, "C:\\boxes.cfg"); } } } else { strcpy (exepath, "C:\\boxes.cfg"); } new_yyin = fopen (exepath, "r"); #else new_yyin = fopen (GLOBALCONF, "r"); #endif if (new_yyin) { #ifdef __MINGW32__ yyfilename = (char *) strdup (exepath); #else rc = is_dir (GLOBALCONF); if (rc == -1) return 1; else if (rc) { fprintf (stderr, "%s: Alleged system-wide config file '%s' " "is a directory\n", PROJECT, GLOBALCONF); return 1; } yyfilename = (char *) strdup (GLOBALCONF); #endif if (yyfilename == NULL) { perror (PROJECT); return 1; } yyin = new_yyin; return 0; } /* * Darn. No luck today. */ fprintf (stderr, "%s: Can't find config file.\n", PROJECT); return 2; } static int process_commandline (int argc, char *argv[]) /* * Process command line options. * * argc, argv command line as passed to main() * * RETURNS: == 0 success, continue * == 42 success, but terminate anyway (e.g. help/version) * != 0/42 error * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { int oc; /* option character */ FILE *f; /* potential input file */ int idummy; char *pdummy; char c; int errfl = 0; /* true on error */ size_t optlen; int rc; /* * Set default values */ memset (&opt, 0, sizeof(opt_t)); opt.tabstop = DEF_TABSTOP; opt.tabexp = 'e'; opt.killblank = -1; for (idummy=0; idummy= 2 && argv[1] != NULL && (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)) { usage_long (stdout); return 42; } /* * Parse Command Line */ do { oc = getopt (argc, argv, "a:c:d:f:hi:k:lmp:rs:t:v"); switch (oc) { case 'a': /* * Alignment/positioning of text inside box */ errfl = 0; pdummy = optarg; while (*pdummy) { if (pdummy[1] == '\0' && !strchr ("lLcCrR", *pdummy)) { errfl = 1; break; } switch (*pdummy) { case 'h': case 'H': switch (pdummy[1]) { case 'c': case 'C': opt.halign = 'c'; break; case 'l': case 'L': opt.halign = 'l'; break; case 'r': case 'R': opt.halign = 'r'; break; default: errfl = 1; break; } ++pdummy; break; case 'v': case 'V': switch (pdummy[1]) { case 'c': case 'C': opt.valign = 'c'; break; case 't': case 'T': opt.valign = 't'; break; case 'b': case 'B': opt.valign = 'b'; break; default: errfl = 1; break; } ++pdummy; break; case 'j': case 'J': switch (pdummy[1]) { case 'l': case 'L': opt.justify = 'l'; break; case 'c': case 'C': opt.justify = 'c'; break; case 'r': case 'R': opt.justify = 'r'; break; default: errfl = 1; break; } ++pdummy; break; case 'l': case 'L': opt.justify = 'l'; opt.halign = 'l'; opt.valign = 'c'; break; case 'r': case 'R': opt.justify = 'r'; opt.halign = 'r'; opt.valign = 'c'; break; case 'c': case 'C': opt.justify = 'c'; opt.halign = 'c'; opt.valign = 'c'; break; default: errfl = 1; break; } if (errfl) break; else ++pdummy; } if (errfl) { fprintf (stderr, "%s: Illegal text format -- %s\n", PROJECT, optarg); return 1; } break; case 'c': /* * Command line design definition */ opt.cld = (char *) strdup (optarg); if (opt.cld == NULL) { perror (PROJECT); return 1; } else { line_t templine; templine.len = strlen (opt.cld); templine.text = opt.cld; if (empty_line(&templine)) { fprintf (stderr, "%s: boxes may not consist entirely " "of whitespace\n", PROJECT); return 1; } } opt.design_choice_by_user = 1; break; case 'd': /* * Box design selection */ BFREE (opt.design); opt.design = (design_t *) ((char *) strdup (optarg)); if (opt.design == NULL) { perror (PROJECT); return 1; } opt.design_choice_by_user = 1; break; case 'f': /* * Input File */ f = fopen (optarg, "r"); if (f == NULL) { fprintf (stderr, "%s: Couldn\'t open config file \'%s\' " "for input.\n", PROJECT, optarg); return 1; } rc = is_dir (optarg); if (rc == -1) return 1; else if (rc) { fprintf (stderr, "%s: Alleged config file '%s' is a " "directory\n", PROJECT, optarg); return 1; } yyfilename = (char *) strdup (optarg); if (yyfilename == NULL) { perror (PROJECT); return 1; } yyin = f; break; case 'h': /* * Display usage information and terminate */ usage_long (stdout); return 42; case 'i': /* * Indentation mode */ optlen = strlen (optarg); if (optlen <= 3 && !strncasecmp ("box", optarg, optlen)) opt.indentmode = 'b'; else if (optlen <= 4 && !strncasecmp ("text", optarg, optlen)) opt.indentmode = 't'; else if (optlen <= 4 && !strncasecmp ("none", optarg, optlen)) opt.indentmode = 'n'; else { fprintf (stderr, "%s: invalid indentation mode\n", PROJECT); return 1; } break; /* * Kill blank lines or not [default: design-dependent] */ case 'k': if (opt.killblank == -1) { if (strisyes (optarg)) opt.killblank = 1; else if (strisno (optarg)) opt.killblank = 0; else { fprintf (stderr, "%s: -k: invalid parameter\n", PROJECT); return 1; } } break; case 'l': /* * List available box styles */ opt.l = 1; break; case 'm': /* * Mend box: remove, then redraw */ opt.mend = 2; opt.r = 1; opt.killblank = 0; break; case 'p': /* * Padding. format is ([ahvtrbl]n)+ */ errfl = 0; pdummy = optarg; while (*pdummy) { if (pdummy[1] == '\0') { errfl = 1; break; } c = *pdummy; errno = 0; idummy = (int) strtol (pdummy+1, &pdummy, 10); if (errno || idummy < 0) { errfl = 1; break; } switch (c) { case 'a': case 'A': opt.padding[BTOP] = idummy; opt.padding[BBOT] = idummy; opt.padding[BLEF] = idummy; opt.padding[BRIG] = idummy; break; case 'h': case 'H': opt.padding[BLEF] = idummy; opt.padding[BRIG] = idummy; break; case 'v': case 'V': opt.padding[BTOP] = idummy; opt.padding[BBOT] = idummy; break; case 't': case 'T': opt.padding[BTOP] = idummy; break; case 'l': case 'L': opt.padding[BLEF] = idummy; break; case 'b': case 'B': opt.padding[BBOT] = idummy; break; case 'r': case 'R': opt.padding[BRIG] = idummy; break; default: errfl = 1; break; } if (errfl) break; } if (errfl) { fprintf (stderr, "%s: invalid padding specification - " "%s\n", PROJECT, optarg); return 1; } break; case 'r': /* * Remove box from input */ opt.r = 1; break; case 's': /* * Specify desired box target size */ pdummy = strchr (optarg, 'x'); if (!pdummy) pdummy = strchr (optarg, 'X'); errno = 0; opt.reqwidth = strtol (optarg, NULL, 10); idummy = errno; if (idummy) { fprintf (stderr, "%s: invalid box size specification: %s\n", PROJECT, strerror(idummy)); return 1; } if (pdummy) { errno = 0; opt.reqheight = strtol (pdummy+1, NULL, 10); idummy = errno; if (idummy) { fprintf (stderr, "%s: invalid box size specification: %s\n", PROJECT, strerror(idummy)); return 1; } } if ((opt.reqwidth == 0 && opt.reqheight == 0) || opt.reqwidth < 0 || opt.reqheight < 0) { fprintf (stderr, "%s: invalid box size specification -- %s\n", PROJECT, optarg); return 1; } break; case 't': /* * Tab handling. Format is n[eku] */ idummy = (int) strtol (optarg, &pdummy, 10); if (idummy < 1 || idummy > MAX_TABSTOP) { fprintf (stderr, "%s: invalid tab stop distance -- %d\n", PROJECT, idummy); return 1; } opt.tabstop = idummy; errfl = 0; if (*pdummy != '\0') { if (pdummy[1] != '\0') { errfl = 1; } else { switch (*pdummy) { case 'e': case 'E': opt.tabexp = 'e'; break; case 'k': case 'K': opt.tabexp = 'k'; break; case 'u': case 'U': opt.tabexp = 'u'; break; default: errfl = 1; break; } } } if (errfl) { fprintf (stderr, "%s: invalid tab handling specification - " "%s\n", PROJECT, optarg); return 1; } break; case 'v': /* * Print version number */ printf ("%s version %s\n", PROJECT, VERSION); return 42; case ':': case '?': /* * Missing argument or illegal option - do nothing else */ usage_short (stderr); return 1; case EOF: /* * End of list, do nothing more */ break; default: /* This case must never be */ fprintf (stderr, "%s: internal error\n", PROJECT); return 1; } } while (oc != EOF); /* * Input and Output Files * * After any command line options, an input file and an output file may * be specified (in that order). "-" may be substituted for standard * input or output. A third file name would be invalid. */ if (argv[optind] == NULL) { /* neither infile nor outfile given */ opt.infile = stdin; opt.outfile = stdout; } else if (argv[optind+1] && argv[optind+2]) { /* illegal third file */ fprintf (stderr, "%s: illegal parameter -- %s\n", PROJECT, argv[optind+2]); usage_short (stderr); return 1; } else { if (strcmp (argv[optind], "-") == 0) { opt.infile = stdin; /* use stdin for input */ } else { opt.infile = fopen (argv[optind], "r"); if (opt.infile == NULL) { fprintf (stderr, "%s: Can\'t open input file -- %s\n", PROJECT, argv[optind]); return 9; /* can't read infile */ } } if (argv[optind+1] == NULL) { opt.outfile = stdout; /* no outfile given */ } else if (strcmp (argv[optind+1], "-") == 0) { opt.outfile = stdout; /* use stdout for output */ } else { opt.outfile = fopen (argv[optind+1], "w"); if (opt.outfile == NULL) { perror (PROJECT); if (opt.infile != stdin) fclose (opt.infile); return 10; } } } /* * If no config file has been specified yet, try getting it elsewhere. */ if (opt.cld == NULL) { rc = get_config_file(); /* sets yyin and yyfilename */ if (rc) /* may change working directory */ return rc; } #if defined(DEBUG) || 0 fprintf (stderr, "Command line option settings (excerpt):\n"); fprintf (stderr, "- Padding: l:%d t:%d r:%d b:%d\n", opt.padding[BLEF], opt.padding[BTOP], opt.padding[BRIG], opt.padding[BBOT]); fprintf (stderr, "- Requested box size: %ldx%ld\n", opt.reqwidth, opt.reqheight); fprintf (stderr, "- Tabstop distance: %d\n", opt.tabstop); fprintf (stderr, "- Tab handling: \'%c\'\n", opt.tabexp); fprintf (stderr, "- Alignment: horiz %c, vert %c\n", opt.halign?opt.halign:'?', opt.valign?opt.valign:'?'); fprintf (stderr, "- Indentmode: \'%c\'\n", opt.indentmode? opt.indentmode: '?'); fprintf (stderr, "- Line justification: \'%c\'\n", opt.justify? opt.justify: '?'); fprintf (stderr, "- Kill blank lines: %d\n", opt.killblank); fprintf (stderr, "- Remove box: %d\n", opt.r); fprintf (stderr, "- Mend box: %d\n", opt.mend); fprintf (stderr, "- Design Definition W shape: %s\n", opt.cld? opt.cld: "n/a"); #endif return 0; } static int build_design (design_t **adesigns, const char *cld) /* * Build a box design. * * adesigns Pointer to global designs list * cld the W shape as specified on the command line * * Builds the global design list containing only one design which was * built from the -c command line definition. * * RETURNS: != 0 on error (out of memory) * == 0 on success * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { design_t *dp; /* pointer to design to be created */ sentry_t *c; /* pointer to current shape */ int i; int rc; *adesigns = (design_t *) calloc (1, sizeof(design_t)); if (*adesigns == NULL) { perror (PROJECT); return 1; } dp = *adesigns; /* for readability */ dp->name = ""; dp->created = "now"; dp->revision = "1.0"; dp->sample = "n/a"; dp->indentmode = DEF_INDENTMODE; dp->padding[BLEF] = 1; dp->shape[W].height = 1; dp->shape[W].width = strlen(cld); dp->shape[W].elastic = 1; rc = genshape (dp->shape[W].width, dp->shape[W].height, &(dp->shape[W].chars)); if (rc) return rc; strcpy (dp->shape[W].chars[0], cld); for (i=0; ishape + i; if (i == NNW || i == NNE || i == WNW || i == ENE || i == W || i == WSW || i == ESE || i == SSW || i == SSE) continue; switch (i) { case NW: case SW: c->width = dp->shape[W].width; c->height = 1; c->elastic = 0; break; case NE: case SE: c->width = 1; c->height = 1; c->elastic = 0; break; case N: case S: case E: c->width = 1; c->height = 1; c->elastic = 1; break; default: fprintf (stderr, "%s: internal error\n", PROJECT); return 1; /* never happens ;-) */ } rc = genshape (c->width, c->height, &(c->chars)); if (rc) return rc; } dp->maxshapeheight = 1; dp->minwidth = dp->shape[W].width + 2; dp->minheight = 3; return 0; } static int style_sort (const void *p1, const void *p2) { return strcasecmp ((const char *) ((*((design_t **) p1))->name), (const char *) ((*((design_t **) p2))->name)); } static int list_styles() /* * Generate sorted listing of available box styles. * Uses design name from BOX spec and sample picture plus author. * * RETURNS: != 0 on error (out of memory) * == 0 on success * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { int i; if (opt.design_choice_by_user) { design_t *d = opt.design; int until = -1; int sstart = 0; size_t w = 0; size_t j; char space[LINE_MAX+1]; memset (&space, ' ', LINE_MAX); space[LINE_MAX] = '\0'; fprintf (opt.outfile, "Complete Design Information for \"%s\":\n", d->name); fprintf (opt.outfile, "-----------------------------------"); for (i=strlen(d->name); i>0; --i) fprintf (opt.outfile, "-"); fprintf (opt.outfile, "\n"); fprintf (opt.outfile, "Author: %s\n", d->author? d->author: "(unknown artist)"); fprintf (opt.outfile, "Creation Date: %s\n", d->created? d->created: "(unknown)"); fprintf (opt.outfile, "Current Revision: %s%s%s\n", d->revision? d->revision: "", d->revision && d->revdate? " as of ": "", d->revdate? d->revdate: (d->revision? "": "(unknown)")); fprintf (opt.outfile, "Indentation Mode: "); switch (d->indentmode) { case 'b': fprintf (opt.outfile, "box (indent box)\n"); break; case 't': fprintf (opt.outfile, "text (retain indentation inside of box)\n"); break; default: fprintf (opt.outfile, "none (discard indentation)\n"); break; } fprintf (opt.outfile, "Replacement Rules: "); if (d->anz_reprules > 0) { for (i=0; i<(int)d->anz_reprules; ++i) { fprintf (opt.outfile, "%d. (%s) \"%s\" WITH \"%s\"\n", i+1, d->reprules[i].mode == 'g'? "glob": "once", d->reprules[i].search, d->reprules[i].repstr); if (i < (int) d->anz_reprules - 1) fprintf (opt.outfile, " "); } } else { fprintf (opt.outfile, "none\n"); } fprintf (opt.outfile, "Reversion Rules: "); if (d->anz_revrules > 0) { for (i=0; i<(int)d->anz_revrules; ++i) { fprintf (opt.outfile, "%d. (%s) \"%s\" TO \"%s\"\n", i+1, d->revrules[i].mode == 'g'? "glob": "once", d->revrules[i].search, d->revrules[i].repstr); if (i < (int) d->anz_revrules - 1) fprintf (opt.outfile, " "); } } else { fprintf (opt.outfile, "none\n"); } fprintf (opt.outfile, "Minimum Box Dimensions: %d x %d (width x height)\n", d->minwidth, d->minheight); fprintf (opt.outfile, "Default Padding: "); if (d->padding[BTOP] || d->padding[BRIG] || d->padding[BBOT] || d->padding[BLEF]) { if (d->padding[BLEF]) { fprintf (opt.outfile, "left %d", d->padding[BLEF]); if (d->padding[BTOP] || d->padding[BRIG] || d->padding[BBOT]) fprintf (opt.outfile, ", "); } if (d->padding[BTOP]) { fprintf (opt.outfile, "top %d", d->padding[BTOP]); if (d->padding[BRIG] || d->padding[BBOT]) fprintf (opt.outfile, ", "); } if (d->padding[BRIG]) { fprintf (opt.outfile, "right %d", d->padding[BRIG]); if (d->padding[BBOT]) fprintf (opt.outfile, ", "); } if (d->padding[BBOT]) fprintf (opt.outfile, "bottom %d", d->padding[BBOT]); fprintf (opt.outfile, "\n"); } else { fprintf (opt.outfile, "none\n"); } fprintf (opt.outfile, "Default Killblank: %s\n", empty_side (opt.design->shape, BTOP) && empty_side (opt.design->shape, BBOT)? "no": "yes"); fprintf (opt.outfile, "Elastic Shapes: "); sstart = 0; for (i=0; ishape+i)) continue; if (d->shape[i].elastic) { fprintf (opt.outfile, "%s%s", sstart? ", ": "", shape_name[i]); sstart = 1; } } fprintf (opt.outfile, "\n"); /* * Display all shapes */ fprintf (opt.outfile, "Defined Shapes: "); until = -1; sstart = 0; do { sstart = until + 1; for (w=0, i=sstart; ishape+i)) continue; w += 6; w += d->shape[i].width; w += strlen(shape_name[i]); if (i == 0) w -= 2; else if (w > 56) { /* assuming an 80 character screen */ until = i - 1; break; } } if (i == ANZ_SHAPES) until = ANZ_SHAPES - 1; for (w=0, i=sstart; i<=until; ++i) { if (d->shape[i].height > w) w = d->shape[i].height; } for (j=0; j 0 || sstart > 0) fprintf (opt.outfile, " "); for (i=sstart; i<=until; ++i) { if (isempty(d->shape+i)) continue; fprintf (opt.outfile, " "); if (j == 0) fprintf (opt.outfile, "%s: ", shape_name[i]); else { space[strlen(shape_name[i])+2] = '\0'; fprintf (opt.outfile, space); space[strlen(shape_name[i])+2] = ' '; } if (j < d->shape[i].height) { fprintf (opt.outfile, "\"%s\"", d->shape[i].chars[j]); } else { space[d->shape[i].width+2] = '\0'; fprintf (opt.outfile, space); space[d->shape[i].width+2] = ' '; } } fprintf (opt.outfile, "\n"); } if (until < ANZ_SHAPES-1 && d->maxshapeheight > 2) fprintf (opt.outfile, "\n"); } while (until < ANZ_SHAPES-1); } else { design_t **list; /* temp list for sorting */ char buf[42]; list = (design_t **) calloc (design_idx+1, sizeof(design_t *)); if (list == NULL) { perror (PROJECT); return 1; } for (i=0; i0; --i) fprintf (opt.outfile, "-"); fprintf (opt.outfile, "\n\n"); for (i=0; iname, list[i]->author? list[i]->author: "unknown artist", list[i]->sample); BFREE (list); } return 0; } static int get_indent (const line_t *lines, const size_t lanz) /* * Determine indentation of given lines in spaces. * * lines the lines to examine * lanz number of lines to examine * * Lines are assumed to be free of trailing whitespace. * * RETURNS: >= 0 indentation in spaces * < 0 error * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { size_t j; int res = LINE_MAX; /* result */ int nonblank = 0; /* true if one non-blank line found */ if (lines == NULL) { fprintf (stderr, "%s: internal error\n", PROJECT); return -1; } if (lanz == 0) return 0; for (j=0; j 0) { size_t ispc; nonblank = 1; ispc = strspn (lines[j].text, " "); if ((int) ispc < res) res = ispc; } } if (nonblank) return res; /* success */ else return 0; /* success, but only blank lines */ } static int apply_substitutions (const int mode) /* * Apply regular expression substitutions to input text. * * mode == 0 use replacement rules (box is being *drawn*) * == 1 use reversion rules (box is being *removed*) * * Attn: This modifies the actual input array! * * RETURNS: == 0 success * != 0 error * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { size_t anz_rules; reprule_t *rules; size_t j, k; char buf[LINE_MAX*2]; size_t buf_len; /* length of string in buf */ if (opt.design == NULL) return 1; if (mode == 0) { anz_rules = opt.design->anz_reprules; rules = opt.design->reprules; } else if (mode == 1) { anz_rules = opt.design->anz_revrules; rules = opt.design->revrules; } else { fprintf (stderr, "%s: internal error\n", PROJECT); return 2; } /* * Compile regular expressions */ errno = 0; opt.design->current_rule = rules; for (j=0; jcurrent_rule)) { rules[j].prog = regcomp (rules[j].search); } opt.design->current_rule = NULL; if (errno) return 3; /* * Apply regular expression substitutions to input lines */ for (k=0; kcurrent_rule = rules; for (j=0; jcurrent_rule)) { #ifdef REGEXP_DEBUG fprintf (stderr, "myregsub (0x%p, \"%s\", %d, \"%s\", buf, %d, \'%c\') == ", rules[j].prog, input.lines[k].text, input.lines[k].len, rules[j].repstr, LINE_MAX*2, rules[j].mode); #endif errno = 0; buf_len = myregsub (rules[j].prog, input.lines[k].text, input.lines[k].len, rules[j].repstr, buf, LINE_MAX*2, rules[j].mode); #ifdef REGEXP_DEBUG fprintf (stderr, "%d\n", buf_len); #endif if (errno) return 1; BFREE (input.lines[k].text); input.lines[k].text = (char *) strdup (buf); if (input.lines[k].text == NULL) { perror (PROJECT); return 1; } input.lines[k].len = buf_len; if (input.lines[k].len > input.maxline) input.maxline = input.lines[k].len; #ifdef REGEXP_DEBUG fprintf (stderr, "input.lines[%d] == {%d, \"%s\"}\n", k, input.lines[k].len, input.lines[k].text); #endif } opt.design->current_rule = NULL; } /* * If text indentation was part of the lines processed, indentation * may now be different -> recalculate input.indent. */ if (opt.design->indentmode == 't') { int rc; rc = get_indent (input.lines, input.anz_lines); if (rc >= 0) input.indent = (size_t) rc; else return 4; } return 0; } static int read_all_input (const int use_stdin) /* * Read entire input (possibly from stdin) and store it in 'input' array. * * Tabs are expanded. * Might allocate slightly more memory than it needs. Trade-off for speed. * * use_stdin: flag indicating whether to read from stdin (use_stdin != 0) * or use the data currently present in input (use_stdin == 0). * * RETURNS: != 0 on error (out of memory) * == 0 on success * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { char buf[LINE_MAX+2]; /* input buffer */ size_t input_size = 0; /* number of elements allocated */ line_t *tmp = NULL; char *temp = NULL; /* string resulting from tab exp. */ size_t newlen; /* line length after tab expansion */ size_t i; int rc; input.indent = LINE_MAX; input.maxline = 0; if (use_stdin) { input.anz_lines = 0; /* * Start reading */ while (fgets (buf, LINE_MAX+1, opt.infile)) { if (input_size % 100 == 0) { input_size += 100; tmp = (line_t *) realloc (input.lines, input_size*sizeof(line_t)); if (tmp == NULL) { perror (PROJECT); BFREE (input.lines); return 1; } input.lines = tmp; } input.lines[input.anz_lines].len = strlen (buf); if (opt.r) { input.lines[input.anz_lines].len -= 1; if (buf[input.lines[input.anz_lines].len] == '\n') buf[input.lines[input.anz_lines].len] = '\0'; } else { btrim (buf, &(input.lines[input.anz_lines].len)); } if (input.lines[input.anz_lines].len > 0) { newlen = expand_tabs_into (buf, input.lines[input.anz_lines].len, opt.tabstop, &temp, &(input.lines[input.anz_lines].tabpos), &(input.lines[input.anz_lines].tabpos_len)); if (newlen == 0) { perror (PROJECT); BFREE (input.lines); return 1; } input.lines[input.anz_lines].text = temp; input.lines[input.anz_lines].len = newlen; temp = NULL; } else { input.lines[input.anz_lines].text = (char *) strdup (buf); } /* * Update length of longest line */ if (input.lines[input.anz_lines].len > input.maxline) input.maxline = input.lines[input.anz_lines].len; /* * next please */ ++input.anz_lines; } if (ferror (stdin)) { perror (PROJECT); BFREE (input.lines); return 1; } } else { /* recalculate input statistics for redrawing the mended box */ for (i=0; i input.maxline) input.maxline = input.lines[i].len; } } /* * Exit if there was no input at all */ if (input.lines == NULL || input.lines[0].text == NULL) return 0; /* * Compute indentation */ rc = get_indent (input.lines, input.anz_lines); if (rc >= 0) input.indent = (size_t) rc; else return 1; /* * Remove indentation, unless we want to preserve it (when removing * a box or if the user wants to retain it inside the box) */ if (opt.design->indentmode != 't' && opt.r == 0) { for (i=0; i= input.indent) { memmove (input.lines[i].text, input.lines[i].text+input.indent, input.lines[i].len-input.indent+1); input.lines[i].len -= input.indent; } } input.maxline -= input.indent; } /* * Apply regular expression substitutions */ if (opt.r == 0) { if (apply_substitutions(0) != 0) return 1; } #if 0 /* * Debugging Code: Display contents of input structure */ for (i=0; iminwith backup, used for mending */ int saved_designheight; /* opt.design->minheight backup, used for mending */ #ifdef DEBUG fprintf (stderr, "BOXES STARTING ...\n"); #endif /* * Process command line options */ #ifdef DEBUG fprintf (stderr, "Processing Command Line ...\n"); #endif rc = process_commandline (argc, argv); if (rc == 42) exit (EXIT_SUCCESS); if (rc) exit (EXIT_FAILURE); /* * Parse config file, then reset design pointer */ #ifdef DEBUG fprintf (stderr, "Parsing Config File ...\n"); #endif if (opt.cld == NULL) { rc = yyparse(); if (rc) exit (EXIT_FAILURE); } else { rc = build_design (&designs, opt.cld); if (rc) exit (EXIT_FAILURE); anz_designs = 1; } BFREE (opt.design); opt.design = designs; /* * If "-l" option was given, list styles and exit. */ if (opt.l) { rc = list_styles(); exit (rc); } /* * Adjust box size and indentmode to command line specification * Increase box width/height by width/height of empty sides in order * to match appearance of box with the user's expectations (if -s). */ if (opt.reqheight > (long) opt.design->minheight) opt.design->minheight = opt.reqheight; if (opt.reqwidth > (long) opt.design->minwidth) opt.design->minwidth = opt.reqwidth; if (opt.reqwidth) { if (empty_side (opt.design->shape, BRIG)) opt.design->minwidth += opt.design->shape[SE].width; if (empty_side (opt.design->shape, BLEF)) opt.design->minwidth += opt.design->shape[NW].width; } if (opt.reqheight) { if (empty_side (opt.design->shape, BTOP)) opt.design->minheight += opt.design->shape[NW].height; if (empty_side (opt.design->shape, BBOT)) opt.design->minheight += opt.design->shape[SE].height; } if (opt.indentmode) opt.design->indentmode = opt.indentmode; saved_designwidth = opt.design->minwidth; saved_designheight = opt.design->minheight; do { if (opt.mend == 1) /* Mending a box works in two phases: */ opt.r = 0; /* opt.mend == 2: remove box */ --opt.mend; /* opt.mend == 1: add it back */ opt.design->minwidth = saved_designwidth; opt.design->minheight = saved_designheight; /* * Read input lines */ #ifdef DEBUG fprintf (stderr, "Reading all input ...\n"); #endif rc = read_all_input (opt.mend); if (rc) exit (EXIT_FAILURE); if (input.anz_lines == 0) exit (EXIT_SUCCESS); /* * Adjust box size to fit requested padding value * Command line-specified box size takes precedence over padding. */ for (i=0; i -1) opt.design->padding[i] = opt.padding[i]; } pad = opt.design->padding[BTOP] + opt.design->padding[BBOT]; if (pad > 0) { pad += input.anz_lines; pad += opt.design->shape[NW].height + opt.design->shape[SW].height; if (pad > opt.design->minheight) { if (opt.reqheight) { for (i=0; i<(int)(pad-opt.design->minheight); ++i) { if (opt.design->padding[i%2?BBOT:BTOP]) opt.design->padding[i%2?BBOT:BTOP] -= 1; else if (opt.design->padding[i%2?BTOP:BBOT]) opt.design->padding[i%2?BTOP:BBOT] -= 1; else break; } } else { opt.design->minheight = pad; } } } pad = opt.design->padding[BLEF] + opt.design->padding[BRIG]; if (pad > 0) { pad += input.maxline; pad += opt.design->shape[NW].width + opt.design->shape[NE].width; if (pad > opt.design->minwidth) { if (opt.reqwidth) { for (i=0; i<(int)(pad-opt.design->minwidth); ++i) { if (opt.design->padding[i%2?BRIG:BLEF]) opt.design->padding[i%2?BRIG:BLEF] -= 1; else if (opt.design->padding[i%2?BLEF:BRIG]) opt.design->padding[i%2?BLEF:BRIG] -= 1; else break; } } else { opt.design->minwidth = pad; } } } if (opt.r) { /* * Remove box */ #ifdef DEBUG fprintf (stderr, "Removing Box ...\n"); #endif if (opt.killblank == -1) { if (empty_side (opt.design->shape, BTOP) && empty_side (opt.design->shape, BBOT)) opt.killblank = 0; else opt.killblank = 1; } rc = remove_box(); if (rc) exit (EXIT_FAILURE); rc = apply_substitutions (1); if (rc) exit (EXIT_FAILURE); output_input (opt.mend > 0); } else { /* * Generate box */ sentry_t *thebox; #ifdef DEBUG fprintf (stderr, "Generating Box ...\n"); #endif thebox = (sentry_t *) calloc (ANZ_SIDES, sizeof(sentry_t)); if (thebox == NULL) { perror (PROJECT); exit (EXIT_FAILURE); } rc = generate_box (thebox); if (rc) exit (EXIT_FAILURE); output_box (thebox); } } while (opt.mend > 0); return EXIT_SUCCESS; } /*EOF*/ /* vim: set sw=4: */ boxes-1.1.1/src/boxes.h0100644000175000001440000002257612040302150014462 0ustar tsjensenusers/* * File: boxes.h * Date created: March 18, 1999 (Thursday, 15:09h) * Author: Copyright (C) 1999 Thomas Jensen * Version: $Id: boxes.h.in,v 1.22 2006/07/22 19:15:52 tsjensen Exp $ * Language: ANSI C * World Wide Web: http://boxes.thomasjensen.com/ * Purpose: Project-wide globals and data structures * * Remarks: o This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * o This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * o You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * Revision History: * * $Log: boxes.h.in,v $ * Revision 1.22 2006/07/22 19:15:52 tsjensen * Fix: Renamed yylineno to tjlineno to enable compilation on certain * flexes (reported by Andreas Heiduk) * Added tabexp to opt_t * Added tabpos and tabpos_len to line_t for advanced tab handling * * Revision 1.21 2006/07/12 05:44:12 tsjensen * Updated email and web addresses in comment header * Added new member 'mend' to opt_t (for option -m, mend box) * * Revision 1.20 2000-04-01 10:28:18-08 tsjensen * Added cld member to command line option struct (-c option) * * Revision 1.19 2000/03/17 23:43:13 tsjensen * Added vim autocommand to set syntax highlighting to C * * Revision 1.18 1999/08/21 23:37:23 tsjensen * Renamed file from boxes.h to boxes.h.in * VERSION and GLOBALCONF values are now put in by top level Makefile * * Revision 1.17 1999/08/14 19:31:23 tsjensen * Incremented beta version number to 5 * Added maxshapeheight member to design_t struct * * Revision 1.16 1999/07/20 18:48:46 tsjensen * Added GNU GPL disclaimer * Updated beta version number :-) * Added killblank member to global options * * Revision 1.15 1999/06/30 12:19:12 tsjensen * Removed DEF_DESIGN macro, because it now defaults to first design * Removed some porting code, hoping for autoconf future * Added PARSER_DEBUG and LEXER_DEBUG macros * * Revision 1.14 1999/06/25 18:51:04 tsjensen * Removed empty_side() prototype (now in shape.h) * Added indentmode and justify members to command line options struct * * Revision 1.13 1999/06/23 19:21:15 tsjensen * Now exporting anz_designs, input, and empty_side() * Added #include regexp.h back * * Revision 1.12 1999/06/23 12:33:49 tsjensen * Moved some data structures and macros related to shapes to shape.h * Added #ifdef DEBUG around __TJ() macro for convenience * * Revision 1.11 1999/06/22 12:01:24 tsjensen * Added DEF_DESIGN (default design name) * Added opt_t and opt global variable from boxes.c * Moved BFREE macro and yyerror() and empty_line() prototypes to tools.h * Added LINE_MAX and MAX_TABSTOP macros from boxes.c * Added #define DEBUG and REGEXP_DEBUG. This will centrally activate * debugging. * * Revision 1.10 1999/06/20 14:19:31 tsjensen * Added padding member to design struct * * Revision 1.9 1999/06/17 19:08:50 tsjensen * Removed #pragma ident "string" * Changed VERSION to 1.0 beta * Added line_t and empty_line() prototype * * Revision 1.8 1999/06/14 12:11:54 tsjensen * Added struct members for regexp reversion code * Renamed current_reprule to current_rule, now used for both directions * * Revision 1.6 1999/04/09 13:32:55 tsjensen * Removed code related to OFFSET blocks (obsolete) * * Revision 1.5 1999/04/04 16:10:51 tsjensen * Added some flags to design structure * Move default settings here from boxes.c * * Revision 1.4 1999/03/31 17:34:43 tsjensen * ... still programming ... * Added minwidth and minheight to design structure * * Revision 1.3 1999/03/30 09:36:58 tsjensen * ... still programming ... * It drew a correct box for the first time! * * Revision 1.1 1999/03/18 15:09:34 tsjensen * Initial revision * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef BOXES_H #define BOXES_H /* #define DEBUG */ /* #define REGEXP_DEBUG */ /* #define PARSER_DEBUG */ /* #define LEXER_DEBUG */ #include "regexp.h" #define PROJECT "boxes" /* name of program */ #define VERSION "1.1.1" /* current release of project */ #define GLOBALCONF "/usr/share/boxes" /* name of system-wide config file */ /* * default settings of all kinds (THIS PARAGRAPH MAY BE EDITED) */ #define DEF_TABSTOP 8 /* default tab stop distance (part of -t) */ #define DEF_INDENTMODE 'b' /* indent box, not text by default */ /* * max. allowed tab stop distance */ #define MAX_TABSTOP 16 /* * max. supported line length * This is how many characters of a line will be read. Anything beyond * will be discarded. The line feed character at the end does not count. * (This should have been done via sysconf(), but I didn't do it in order * to ease porting to non-unix platforms.) */ #if defined(LINE_MAX) && (LINE_MAX < 1024) #undef LINE_MAX #endif #ifndef LINE_MAX #define LINE_MAX 2048 #endif #ifdef DEBUG #define __TJ(s) fprintf (stderr, s); #else #define __TJ(s) /**/ #endif #define BTOP 0 /* for use with sides */ #define BRIG 1 #define BBOT 2 #define BLEF 3 typedef struct { char *search; char *repstr; regexp *prog; /* compiled search pattern */ int line; /* line of definition in config file */ char mode; /* 'g' or 'o' */ } reprule_t; typedef struct { char *name; char *author; char *created; /* date created, free format */ char *revision; /* revision number of design */ char *revdate; /* date of current revision */ char *sample; char indentmode; /* 'b', 't', or 'n' */ sentry_t shape[ANZ_SHAPES]; size_t maxshapeheight; /* height of highest shape in design */ size_t minwidth; size_t minheight; int padding[ANZ_SIDES]; reprule_t *current_rule; reprule_t *reprules; /* applied when drawing a box */ size_t anz_reprules; reprule_t *revrules; /* applied upon removal of a box */ size_t anz_revrules; } design_t; extern design_t *designs; extern int anz_designs; extern int design_idx; extern int tjlineno; /* config file line counter */ extern char *yyfilename; /* name of config file */ typedef struct { /* Command line options: */ int l; /* list available designs */ int mend; /* 1 if -m is given, 2 in 2nd loop */ int r; /* remove box from input */ int tabstop; /* tab stop distance */ char tabexp; /* tab expansion mode (for leading tabs) */ int padding[ANZ_SIDES]; /* in spaces or lines resp. */ design_t *design; /* currently used box design */ int design_choice_by_user; /* true if design was chosen by user */ char *cld; /* commandline design definition, -c */ long reqwidth; /* requested box width (-s) */ long reqheight; /* requested box height (-s) */ char valign; /* text position inside box */ char halign; /* ( h[lcr]v[tcb] ) */ char indentmode; /* 'b', 't', 'n', or '\0' */ char justify; /* 'l', 'c', 'r', or '\0' */ int killblank; /* -1 if not set */ FILE *infile; /* where we get our input */ FILE *outfile; /* where we put our output */ } opt_t; extern opt_t opt; typedef struct { size_t len; /* length of text in characters */ char *text; /* line content, tabs expanded */ size_t *tabpos; /* tab positions in expanded work strings */ size_t tabpos_len; /* number of tabs in a line */ } line_t; #ifndef FILE_LEXER_L typedef struct { line_t *lines; size_t anz_lines; /* number of entries in input */ size_t maxline; /* length of longest input line */ size_t indent; /* number of leading spaces found */ } input_t; #define INPUT_INITIALIZER {NULL, 0, 0, LINE_MAX} extern input_t input; #endif /*!FILE_LEXER_L*/ #endif /* BOXES_H */ /*EOF*/ /* vim: set cindent sw=4 syntax=c: */ boxes-1.1.1/src/Makefile.Win320100644000175000001440000001352510454256312015543 0ustar tsjensenusers# # File: Makefile.Win32 # Creation: March 18, 1999 (Thursday, 15:10h) # Author: Copyright (C) 1999 Thomas Jensen # Win32 Modifications by Ron Aaron # Version: $Id: Makefile,v 1.16 1999/11/08 10:55:13 tsjensen Exp tsjensen $ # Format: GNU make # Web Site: http://boxes.thomasjensen.com/ # Platforms: win32 # Purpose: Makefile for boxes, the box drawing program # # Remarks: o This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # o This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # o You should have received a copy of the GNU General Public # License along with this program; if not, write to the Free # Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, # MA 02111-1307 USA # # Revision History: # # $Log: Makefile,v $ # Revision 1.17 2000/03/16 10:55:13 ronaaron # Win32 port # # Revision 1.16 1999/11/08 10:55:13 tsjensen # Moved config.h into ORIG_HDRCL group, so it appears in the change log Web # page # # Revision 1.15 1999/08/21 23:35:44 tsjensen # boxes.h is now generated from boxes.h.in by top level Makefile # Added -Wall -W to CFLAGS and removed .c.o rule # # Revision 1.14 1999/08/21 16:10:41 tsjensen # Removed case insensitivity option (-i) from flex call (-> lexer.l) # # Revision 1.13 1999/08/13 23:55:03 tsjensen # Given regexp stuff its own Makefile in regexp. # Major Makefile overhaul, maily implementation of new directory structure # and consolidation of file macros # Use more GNU make features # # Revision 1.12 1999/07/20 18:49:58 tsjensen # Added GNU GPL disclaimer # Now evaluating date command from SNAPFILE only once # Changed order of files in snapshot archive (who cares) # # Revision 1.11 1999/07/12 18:28:53 tsjensen # Removed --yacc option from bison call # Added logpage target to generate the chronologically sorted global change # log in HTML format. This requires a Perl script (create_changelog.pl). # Added config.h to dependencies and stuff # Removed special targets for yacc and lex files. Thanks to Andreas Heiduk, # it is now possible to compile all files with -W -Wall and no extra # defines. # Moved regexp library to a subdirectory regexp # Some modifications on the source file macros which now differentiate # between files which are listed in the HTML change log and files which # aren't. # # Revision 1.10 1999/07/02 11:50:35 tsjensen # Added parser.h header file for lexer-parser communication # Moved from yacc to GNU "bison --yacc" # No longer linking with flex library # Activated -Wall -W for parser.y # Removed -DYY_NO_UNPUT from lexer compilation (now done via file option) # # Revision 1.1 1999/03/18 15:10:41 tsjensen # Initial revision #____________________________________________________________________________ #============================================================================ LEX = flex YACC = bison CC = gcc CFLAGS = -Os -s -I. -Iregexp -Wall -W $(CFLAGS_ADDTL) LDFLAGS = -s GEN_HDR = parser.h boxes.h GEN_SRC = parser.c lex.yy.c GEN_FILES = $(GEN_SRC) $(GEN_HDR) ORIG_HDRCL = boxes.h.in config.h ORIG_HDR = $(ORIG_HDRCL) lexer.h tools.h shape.h generate.h remove.h ORIG_GEN = lexer.l parser.y ORIG_NORM = boxes.c tools.c shape.c generate.c remove.c ORIG_SRC = $(ORIG_GEN) $(ORIG_NORM) ORIG_FILES = $(ORIG_SRC) $(ORIG_HDR) OTH_FILES = Makefile ALL_CL = $(ORIG_SRC) $(ORIG_HDRCL) $(OTH_FILES) ALL_FILES = $(ORIG_FILES) $(GEN_FILES) $(OTH_FILES) ALL_OBJ = $(GEN_SRC:.c=.o) $(ORIG_NORM:.c=.o) regexp/regexp.o \ regexp/regsub.o misc/getopt.o boxes: $(ALL_OBJ) $(CC) $(LDFLAGS) $(ALL_OBJ) -o boxes -lkernel32 parser.c parser.h: parser.y boxes.h regexp/regexp.h $(YACC) -o parser.c -d parser.y lex.yy.c: lexer.l boxes.h $(LEX) -t lexer.l > lexer.tmp.c echo #include "config.h" > lex.yy.c cat lexer.tmp.c >> lex.yy.c rm lexer.tmp.c boxes.o: boxes.c boxes.h regexp/regexp.h shape.h tools.h generate.h remove.h config.h tools.o: tools.c tools.h boxes.h shape.h config.h shape.o: shape.c shape.h boxes.h config.h tools.h generate.o: generate.c generate.h boxes.h shape.h tools.h config.h remove.o: remove.c remove.h boxes.h shape.h tools.h config.h lex.yy.o: lex.yy.c parser.h tools.h shape.h lexer.h config.h parser.o: parser.c parser.h tools.h shape.h lexer.h config.h regexp/regexp.o: regexp/regexp.c regexp/regsub.o: regexp/regsub.c misc/getopt.o: misc/getopt.c snap: $(ALL_FILES) if [ -z "$(SNAPFILE)" ] ; then exit 1 ; fi mkdir $(SNAPFILE)/src cp $(ALL_FILES) $(SNAPFILE)/src touch $(patsubst %,$(SNAPFILE)/src/%,$(GEN_FILES)) $(MAKE) -C regexp SNAPFILE=../$(SNAPFILE) snap rcstest: -for i in $(ORIG_FILES) $(OTH_FILES) ; do rcsdiff $$i ; done $(MAKE) -C regexp rcstest logpage: $(ALL_CL) @echo $(ALL_CL) $(shell $(MAKE) -C regexp -s logpage) clean: rm -f $(ALL_OBJ) rm -f $(GEN_FILES) rm -f core boxes $(MAKE) -C regexp clean love: @echo "Not in front of the kids, honey!" boxes.h: boxes.h.in cp boxes.h.in boxes.h build: $(MAKE) CFLAGS_ADDTL=-O boxes strip boxes debug: $(MAKE) CFLAGS_ADDTL=-g boxes #EOF boxes-1.1.1/Makefile0100644000175000001440000001272412040302003014031 0ustar tsjensenusers# # File: Makefile # Creation: August 14, 1999 (Saturday, 01:08h) # Author: Copyright (C) 1999 Thomas Jensen # Version: $Id: Makefile,v 1.13 2012/10/19 16:46:32 tsjensen Exp $ # Format: GNU make # Web Site: http://boxes.thomasjensen.com/ # Platforms: sparc/Solaris 2.6, Linux, and others # Purpose: Makefile for boxes, the box drawing program # # Remarks: o This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # o This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # o You should have received a copy of the GNU General Public # License along with this program; if not, write to the Free # Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, # MA 02111-1307 USA # # Revision History: # # $Log: Makefile,v $ # Revision 1.13 2012/10/19 16:46:32 tsjensen # Incremented version number to 1.1.1 # Include boxes.1.in in the changelog # # Revision 1.12 2006/08/04 20:44:00 tsjensen # Changed the latest snap creation target to adjust to VM build environment # # Revision 1.11 2006/07/23 16:50:09 tsjensen # Updated version number to 1.1 # Changed default value of GLOBALCONF to comply with current Linux standards # # Revision 1.10 2006/07/22 19:51:08 tsjensen # Added boxes.h management # Added rcslocks target # Updated some of the administrative paths (not relevant for builders) # # Revision 1.9 2006-07-11 23:43:00-07 tsjensen # Added a missing tab character # # Revision 1.8 2006-07-08 01:58:08-07 tsjensen # Updated email and web addresses # # Revision 1.7 2006/07/08 08:56:38 tsjensen # Added reminder of compilation faq # Changed BVERSION to 1.0.2 # # Revision 1.6 2000/04/01 18:29:17 tsjensen # Added code to add snapshot info to version number for snapshots. This # affects the author only. # # Revision 1.5 2000/03/17 23:52:29 tsjensen # Incremented version number to 1.0.1 # Renamed snapshot file name to boxes-SNAP-latest # Added README.Win32.txt to snapshot generation commands # # Revision 1.4 1999/08/22 11:43:55 tsjensen # Added comment to guide user to GLOBALCONF definition line # # Revision 1.3 1999/08/21 23:39:01 tsjensen # Added GLOBALCONF and BVERSION macros whose values are put into boxes.h and # boxes.1 # Added locsnap target for generation of archives without posting to the Web # page # Added README file # Added rules to generate boxes.h and boxes.1 from boxes.1.in and boxes.h.in # # Revision 1.2 1999/08/14 19:01:31 tsjensen # After taking a snapshot, put it in the author's archives, too. # # Revision 1.1 1999/08/13 23:45:34 tsjensen # Initial revision #____________________________________________________________________________ #============================================================================ # The following line (GLOBALCONF) is the only line you should need to edit! GLOBALCONF = /usr/share/boxes BVERSION = 1.1.1 SNAPFILE = boxes-SNAP-$(shell date +%Y%m%d) WEBHOME = $(HOME)/boxes/website CLOGFILE = $(WEBHOME)/changelogs.shtml CL_FILES = boxes-config doc/boxes.1.in RCS_FILES = $(CL_FILES) Makefile doc/boxes.el doc/create_changelog.pl ALL_FILES = COPYING README README.Win32.txt boxes-config Makefile DOC_FILES = doc/boxes.1 doc/boxes.1.in doc/boxes.el build debug boxes: src/boxes.h doc/boxes.1 @echo For compilation info see the boxes website at http://boxes.thomasjensen.com/ $(MAKE) -C src $@ src/boxes.h: src/boxes.h.in src/regexp/regexp.h Makefile sed -e 's/--BVERSION--/$(BVERSION)/; s/--GLOBALCONF--/$(subst /,\/,$(GLOBALCONF))/' src/boxes.h.in > src/boxes.h doc/boxes.1: doc/boxes.1.in Makefile sed -e 's/--BVERSION--/$(BVERSION)/; s/--GLOBALCONF--/$(subst /,\/,$(GLOBALCONF))/' doc/boxes.1.in > doc/boxes.1 clean: rm -f doc/boxes.1 src/boxes.h $(MAKE) -C src clean locsnap: $(ALL_FILES) $(DOC_FILES) mkdir -p $(SNAPFILE)/doc cp $(ALL_FILES) $(SNAPFILE) cp $(DOC_FILES) $(SNAPFILE)/doc $(MAKE) -C src SNAPFILE=../$(SNAPFILE) snap mv $(SNAPFILE)/Makefile $(SNAPFILE)/Makefile.vin cat $(SNAPFILE)/Makefile.vin | perl -ne 'if (/^(BVERSION\s*=\s*)(.*)$$/) { print "BVERSION = above $$2 (SNAP of '`date +%d-%b-%Y`')\n"; } else { print $$_; }' > $(SNAPFILE)/Makefile rm -f $(SNAPFILE)/Makefile.vin find $(SNAPFILE) -type f -print | xargs chmod 644 gtar cfvz $(SNAPFILE).tar.gz $(SNAPFILE)/* rm -rf $(SNAPFILE)/ snap: locsnap mv -i $(SNAPFILE).tar.gz archive/ chmod 444 archive/$(SNAPFILE).tar.gz rm -f archive/boxes-SNAP-latest.tar.gz (cd archive; ln -s $(SNAPFILE).tar.gz boxes-SNAP-latest.tar.gz) rcstest: -for i in $(RCS_FILES) ; do rcsdiff $$i ; done $(MAKE) -C src rcstest rcslocks: @echo Locked files: @rlog -L -R $(RCS_FILES) | sed -e 's/^/ - /' @$(MAKE) -C src rcslocks logpage: $(CL_FILES) cd src; ../doc/create_changelog.pl $(patsubst %,../%,$(CL_FILES)) $(shell $(MAKE) -C src -s logpage) > $(CLOGFILE) love: @echo "Not in front of the kids, honey!" #EOF boxes-1.1.1/README.Win32.txt0100644000175000001440000000274610464466416015026 0ustar tsjensenusersboxes 1.1 Win32 port Information Date: 03-Aug-2006 This is the Win32 Version of boxes 1.1, built from the official source tarball. It was built using gcc 3.4.2 (mingw-special) with MinGW 3.9. Many thanks to Ron Aaron for originally helping me with the Win32 port of boxes! I could use his information for the version 1.0.1 port to build this one, too. General information may be found in the generic README file provided with this archive and at http://boxes.thomasjensen.com/, the boxes home page. Note that the generic README file is intended for UNIX users, so some things don't translate literally (e.g., you would have to type Ctrl-Z instead of Ctrl-D to signal end of file, etc.). The system-wide config file is assumed to reside in the same directory as the boxes executable. (This is the case when you unpack the archive.) The name of the config file is assumed to be the same as the name of the executable, only with a .cfg extension instead of .exe. As with the UNIX version, boxes still looks for a file boxes.cfg in the directory pointed to by the environment variable HOME, and for a file pointed to by the environment variable BOXES. The standard troff format manual page is part of the package (boxes.1), but knowing that in the Windows world there may be some people who don't have troff installed on their systems, an HTML version of the page is provided. Enjoy! Thomas Jensen EOT boxes-1.1.1/README0100644000175000001440000001314612040272241013262 0ustar tsjensenusers _. | | ____ ____ | |__ ____ ___ ___ ____ ______ ___ __ /_ | /_ | | __ \ / _ \ \ \/ / _/ __ \ / ___/ \ \/ / | | | | | \_\ \ ( <_> ) > < \ ___/ \___ \ \ / | | | | |___ / \____/ /__/\_ \ \___ > /____ > \_/ |___| /\ |___| \/ \/ \/ \/ \/ draws all kinds of boxes around your text (in ASCII art) [stable release 1.1.1] GETTING IT http://boxes.thomasjensen.com/ Boxes is free software under the GNU General Public License (GNU GPL), version 2. See COPYING file or http://www.gnu.org/copyleft/gpl.html. COMPILING IT Skip this section if you got yourself a binary distribution. NOTE, however, that the location of the system-wide config file can only be changed using the source distribution, because its path is compiled in. 1. Unpack the archive 2. Edit the top level Makefile and change the value of GLOBALCONF to whereever you want the system-wide config file to reside. Note that each user may have his/her own config file in $HOME/.boxes. Also note that the value of GLOBALCONF is a full file name. It does NOT specify a directory into which to copy the config file. 3. If you are on DEC/OSF, edit src/regexp/Makefile, and add -D_ANSI_C_SOURCE to the CFLAGS definition. 4. Type 'make' in the top level directory. This should leave you with a binary in the src directory. The boxes development platform is intel/linux (SLES). If you are on a different platform and somehow manage to materialize a binary, please send it to the author (boxes@thomasjensen.com), so it can be posted on the boxes home page. Boxes is generally very easy to port, because it uses only a small set of instructions and is comformant to the ANSI C standard. For a small collection of frequently asked questions, visit the compilation FAQ on the boxes website. INSTALLING IT 1. If you are installing a BINARY distribution: - Copy boxes.1 to an appropriate manual page directory - Copy boxes-config to /usr/share/boxes Note that /usr/share/boxes is the name of the file, and NOT the name of a directory into which to copy the file. So, the name of the config file is changed from boxes-config to just boxes. - Copy the executable to a location which is in your path Example (as root): cp boxes.1 /usr/share/man/man1 cp boxes-config /usr/share/boxes cp boxes /usr/bin If you are installing a SOURCE distribution: - Copy doc/boxes.1 to an appropriate manual page directory - Copy boxes-config to the location specified in the Makefile as being the name of the system-wide boxes config file. Note that the value of GLOBALCONF is the name of the file, and NOT the name of a directory into which to copy the file. So, the name of the config file is changed from boxes-config to just boxes. - Copy src/boxes (the binary) to a location which is in your path Example (as root): cp doc/boxes.1 /usr/share/man/man1 cp boxes-config /usr/share/boxes cp src/boxes /usr/bin 2. If you want to make your own changes to the config file, copy the system-wide config file into your home as $HOME/.boxes, then modify it. Boxes will use $HOME/.boxes if it exists. 3. Installation into your text editor: Please see the installation page on the Web at http://boxes.thomasjensen.com/docs/install.shtml It currently describes installation with vim, emacs, and jed, but this list may grow as time goes by and people send me how-tos. RUNNING IT Try if boxes works by typing "boxes" on the command line, then enter "foo", press return and hit Ctrl-D. It should give you something like that: /*******/ /* foo */ /*******/ Detailed usage information is in the manual page and a lot more can be found on the Web page (see above). It is especially interesting to tie boxes to your editor, so that it can be invoked by a simple keypress. DEFINING YOUR OWN BOXES Any user may define his own box designs by creating a file called .boxes in his home directory. The syntax of the config file is explained on the boxes home page, along with several examples: http://boxes.thomasjensen.com/docs/ CONTACT * For questions which the online documentation could not answer, requests for more features, praise and bug reports please feel free to email the author at boxes@thomasjensen.com. Bug reports are especially appreciated. * For questions particular to the binary you downloaded contact the supplier of the binary listed on the download page. * Send your cool new box designs to boxes@thomasjensen.com! If I like them, they may be added to the official config file. _________________________ /\ \ \_| Enjoy! | 10/19/2012 | -- Thomas Jensen | | ____________________|_ EOF \_/______________________/ boxes-1.1.1/boxes-config0100644000175000001440000013127012040271365014715 0ustar tsjensenusers# # File: boxes-config # Date created: March 17, 1999 (Wednesday, 17:02h) # Author: Thomas Jensen # Version: $Id: boxes-config,v 1.19 2012/10/19 15:33:21 tsjensen Exp $ # Format: ASCII Text # World Wide Web: http://boxes.thomasjensen.com/ # Purpose: Example configuration file for the boxes program # # Remarks: Extensive documentation may be found on the Web at # http://boxes.thomasjensen.com/docs/ # The config file syntax in particular is described in # http://boxes.thomasjensen.com/docs/config-syntax.shtml #____________________________________________________________________________ #============================================================================ BOX c author "Thomas Jensen " revision "1.0" revdate "March 18, 1999 (Thursday, 15:25h)" created "March 18, 1999 (Thursday, 15:25h)" sample /*************/ /* */ /* */ /*************/ ends shapes { nw ("/*") n ("*") ne ("*/") w ("/*") e ("*/") sw ("/*") s ("*") se ("*/") } delim ?" replace "\*/" with "*\/" # quote closing comment tags reverse "\*\\/" to "*/" padding { horiz 1 # alternatives: all, vert, lef, rig, bottom, top } # can be combined, e.g. all 3 top 1 elastic (n,e,s,w) END c # ============================================================================ BOX parchment created "March 12, 1999 (Friday, 17:05h)" revision "1.0" revdate "March 12, 1999 (Friday, 17:05h)" escaped "aaa\"bbb\\\"ccc#" # the string aaa"bbb\"ccc# #escaped2 "aaa\\"bbb" # unterminated sample ________________________ /\ \ \_| | | | | | | ____________________|_ \_/_____________________/ ends shapes { nw (" __") nnw () wnw ("/\\ ", "\\_|") w (" |") n ("_") ne (" ") ene ("\\ ") e ("| ") se ("|_ ","__/") s ("_","_") ssw (" ", "\\_/") sw (" |"," ") ese () } padding { top 1 h 1 } elastic (n,e,s,w) END parchment # ============================================================================ BOX columns revision "1.1" revdate "July 20, 1999 (Tuesday, 21:06h)" created "March 17, 1999 (Wednesday, 15:27h)" sample __^__ __^__ ( ___ )---------------( ___ ) | / | | \ | | / | | \ | | / | | \ | |___| |___| (_____)---------------(_____) ends shapes { nw (" __^__", "( ___ ") nnw (" ",")") n (" ","-") nne (" ","(") ne ("__^__ ", " ___ )") w (" | / |") wsw (" |___|") e ("| \\ | ") ese ("|___| ") sw ("(_____") ssw (")") s ("-") sse ("(") se ("_____)") } elastic (n, e, w, s) padding { horiz 1 } END columns # ============================================================================ BOX whirly created "March 17, 1999 (Wednesday, 15:40h)" revdate "March 17, 1999 (Wednesday, 15:40h)" revision "1.0" sample .+"+.+"+.+"+.+"+.+"+.+"+.+"+.+"+.+"+.+"+.+"+.+"+.+"+.+"+.+"+. ( ) ) ( ( ) "+.+"+.+"+.+"+.+"+.+"+.+"+.+"+.+"+.+"+.+"+.+"+.+"+.+"+.+"+.+" ends shapes { nw (" .") wnw ("( ") w (" )", "( ") sw (" \"") n ("+\"+.") ne (". ") ene (" )") e ("( ", " )") s ("+.+\"") nne ("+\"+") sse ("+.+") se ("\" ") } elastic (n, w, s, e) END whirly # ============================================================================ BOX scroll revision "1.2" revdate "August 18, 1999 (Wednesday, 17:00h)" created "March 17, 1999 (Wednesday, 17:04h)" SAMPLE / ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \ | /~~\ /~~\ | |\ \ | | / /| | \ /| |\ / | | ~~ | | ~~ | | | | | | | | | | | | | | | | | | | | | \ |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| / \ / \ / ~~~ ~~~ ENDS delimiter ?" shapes { ne ("~~~~~ \ ") ene (" /~~\ |", "| / /|", "|\ / |", "| ~~ |") e ("| |") se ("| / ", " \ / ", " ~~~ ") nw (" / ~~~~~") wnw ("| /~~\ ", "|\ \ |", "| \ /|", "| ~~ |") w ("| |") sw (" \ |", " \ / ", " ~~~ ") n ("~") s ("~"," "," ") } eLAStic (n, s, e, w) padding { h 2 v 1 } END scroll # ============================================================================ BOX simple author "Thomas Jensen " revision "1.1" revdate "August 22, 1999 (Sunday, 12:44h)" created "March 18, 1999 (Thursday, 15:24h)" sample ************* * * * * ************* ends shapes { nw ("*") ne ("*") sw ("*") se ("*") n ("*") e ("*") s ("*") w ("*") } padding { horiz 1 } elastic (n,e,s,W) END simple # ============================================================================ BOX c-cmt author "Thomas Jensen " revision "1.0" revdate "June 17, 1999 (Thursday, 19:59h)" created "June 17, 1999 (Thursday, 19:59h)" sample /* */ /* regular C language */ /* comments */ /* */ ends shapes { w ("/*") e ("*/") } replace "\\*/" with "*\\/" # quote closing comment tags reverse "\\*\\\\/" to "*/" Padding { h 1 } elastic (e, w) END c-cmt # ============================================================================ BOX c-cmt2 author "Thomas Jensen " revision "1.1" revdate "August 18, 1999 (Wednesday, 17:01h)" created "June 17, 1999 (Thursday, 19:59h)" sample /* * regular C language * comments */ ends shapes { nw ("/*") w (" *") sw (" *") ssw ("/") s (" ") # note that S must be defined! } padding { left 2 } delimiter ?" replace "\*/" with "*\/" # quote closing comment tags reverse "\*\\/" to "*/" elastic (s, w) END c-cmt2 # ============================================================================ BOX c-cmt3 author "AlpT (@freaknet.org)" revision "1.0" revdate "Fri Jun 9 11:04:42 CEST 2006" created "Fri Jun 9 11:04:42 CEST 2006" sample /** * */ code(here); a++; /**/ ends shapes { nnw ("/** ", " * ", " */ ") n (" ", " ", " ") ssw ("/**/") s (" ") } delimiter ?" replace "\*/" with "*\/" # quote closing comment tags reverse "\*\\/" to "*/" elastic (n,s) END c-cmt3 # ============================================================================ BOX javadoc author "Ted Berg " revision "1.0" revdate "October 25, 1999 (Monday 10:16h)" created "October 25, 1999 (Monday 10:16h)" sample /** * Javadoc Comments * */ ends shapes { nw ("/*") nnw ("*") n (" ") w (" *") sw (" *") ssw ("/") s (" ") } padding { left 2 } delimiter ?" replace "\*/" with "*\/" # quote closing comment tags reverse "\*\\/" to "*/" elastic (s, w, n) END javadoc # ============================================================================ BOX html author "Thomas Jensen " revision "1.2" revdate "October 19, 2012 (Friday, 17:32h)" created "March 18, 1999 (Thursday, 15:26h)" sample ends shapes { nw ("") w ("") sw ("") } padding { h 1 } delim ?" replace "-->" with "-\-\>" reverse "-\\-\\>" to "-->" elastic (n,e,s,w) END html # ============================================================================ BOX shell author "Thomas Jensen " revision "1.0" revdate "March 18, 1999 (Thursday, 15:27h)" created "March 18, 1999 (Thursday, 15:27h)" sample ############# # # # # ############# ends shapes { nw ("#") n ("#") se ("#") e ("#") sw ("#") s ("#") ne ("#") w ("#") } padding { h 1 } elastic (n,s,e, w) END shell # ============================================================================ BOX nuke author "Joan G. Stark " revision "1.1" revdate "August 22, 1999 (Sunday, 12:51h)" created "March 30, 1999 (Tuesday, 15:55h)" sample _ ._ _ , _ ._ (_ ' ( ` )_ .__) ( ( ( ) `) ) _) (__ (_ (_ . _) _) ,__) `~~`\ ' . /`~~` ,::: ; ; :::, ':::::::::::::::' _________________jgs______/_ __ \________________________ | | | BAD, BAD, BUG HERE :-) | |_________________________________________________________| ends shapes { nw (" "," "," "," "," "," "," "," ") ne (" "," "," "," "," "," "," "," ") nnw (" "," "," "," "," "," "," ","_") nne (" "," "," "," "," "," "," ","_") n (" _ ._ _ , _ ._ ", " (_ ' ( ` )_ .__) ", " ( ( ( ) `) ) _) ", " (__ (_ (_ . _) _) ,__)", " `~~`\\ ' . /`~~` ", " ,::: ; ; :::, ", " ':::::::::::::::' ", "jgs______/_ __ \\_________") w ("|") e ("|") sw ("|") s ("_") se ("|") } padding { all 1 bottom 0 } elastic (nne,nnw, s, e, w) END nuke # ============================================================================ BOX diamonds author "Joan G. Stark " revision "1.1" revdate "August 18, 1999 (Wednesday, 17:02h)" created "March 30, 1999 (Tuesday, 15:59h)" Sample /\ /\ /\ /\ /\//\\/\ /\//\\/\ /\//\\/\ /\//\\/\ /\//\\\///\\/\//\\\///\\/\//\\\///\\/\//\\\///\\/\ //\\\//\/\\///\\\//\/\\///\\\//\/\\///\\\//\/\\///\\ \\//\/ \/\\// \/ \/ /\ /\ //\\ joan stark spunk1111@juno.com //\\ \\// http://www.geocities.com/SoHo/7373/ \\// \/ \/ /\ /\ //\\/\ /\//\\ \\///\\/\//\\\///\\/\//\\\///\\/\//\\\///\\/\//\\\// \/\\///\\\//\/\\///\\\//\/\\///\\\//\/\\///\\\//\/ \/\\//\/ \/\\//\/ \/\\//\/ \/\\//\/ \/ \/ \/ \/ Ends delimiter ?" shapes { nw (" ", " /\", " /\//\", "//\\\/") nnw (" /\ ", "//\\/\ ", "\\///\\/", "/\/\\///") n (" /\ ", " /\//\\/\ ", "\//\\\///\\/", "\\\//\/\\///") nne (" /\ ", " /\//\\", "\//\\\//", "\\\//\/\") ne (" ", "/\ ", "/\\/\ ", "\///\\") ene ("\/\\//", " \/ ") e (" /\ ", " //\\", " \\//", " \/ ") ese (" /\ ", "/\//\\") wnw ("\\//\/", " \/ ") w (" /\ ", "//\\ ", "\\// ", " \/ ") wsw (" /\ ", "//\\/\") sw ("\\///\", " \/\\/", " \/", " ") ssw ("\/\//\\\", "//\\\//\", "\\//\/ ", " \/ ") s ("///\\/\//\\\", "/\\///\\\//\", " \/\\//\/ ", " \/ ") sse ("///\\/\/", "/\\///\\", " \/\\//", " \/ ") se ("/\\\//", "\//\/ ", "\/ ", " ") } elastic (n,s,e, w) END diamonds # ============================================================================ BOX mouse author "Joan G. Stark " revision "1.1" revdate "August 22, 1999 (Sunday, 12:57h)" created "March 18, 1999 (Thursday, 15:27h)" sample .--, .--, ( ( \.---./ ) ) '.__/o o\__.' {= ^ =} > - < ___________.""`-------`"".____________ / \ \ o joan stark O / / spunk1111@juno.com \ \ ascii art gallery / / http://www.geocities.com/SoHo/7373/ \ \______________________________________/ ___)( )(___ (((__) (__))) ends shapes { nnw (" ", " ", " ", " ", " ", "_") nne (" ", " ", " ", " ", " ", "_") ne (" ", " ", " ", " ", " ", " ") nw (" ", " ", " ", " ", " ", " ") sw ("\\", " ", " ") se ("/", " ", " ") ene ("\\") wnw ("/") e ("/","\\") w ("\\","/") n (" .--, .--, ", "( ( \\.---./ ) )", " '.__/o o\\__.' ", " {= ^ =} ", " > - < ", "_.\"\"`-------`\"\"._") s ("_____________", " ___)( )(___ ", "(((__) (__)))") ssw ("_"," "," ") sse ("_"," "," ") } elastic (nne,nnw, sse,ssw, e, w) padding { top 1 horiz 1 } END mouse # ============================================================================ BOX sunset author "Joan G. Stark " revision "1.0" revdate "March 30, 1999 (Tuesday, 17:10h)" created "March 30, 1999 (Tuesday, 17:10h)" sample . . | . \ | / '. \ ' / .' '. .'```'. .' <>.............:::::::`.......`:::::::................<> <>: ., .., . . . . . . . . . . joan stark :<> <>: :, :.' : : :`.: :.' `: `: `: `: spunk1111 :<> <>: ,.; : `.' : `: : `. : : : : @juno.com :<> <>:..................................................:<> <><><><><><><><><><><><><><><><><><><><><><><><><><><><> ~you can't hurt your eyesight by looking on the bright side~ ~but you can hurt them by looking at bad ascii art!~ ends shapes { e (":<>") w ("<>:") sw ("<>:", "<><") se (":<>", "><>") s ("..", "><") nw (" ", " ", " ", " ", " ", "<>.") ne (" ", " ", " ", " ", " ", ".<>") nnw (" ", " ", " ", " ", " ", ".") nne (" ", " ", " ", " ", " ", ".") n (" . ", " . | . ", " \\ | / ", " '. \\ ' / .' ", " '. .'```'. .' ", ":::::::`.......`:::::::") } elastic (nne,nnw, s, e, w) END sunset # ============================================================================ BOX boy author "Joan G. Stark " revision "1.1" revdate "August 22, 1999 (Sunday, 13:02h)" created "April 02, 1999 (Friday, 15:02h)" sample .-"""-. / .===. \ \/ 6 6 \/ ( \___/ ) _________ooo__\_____/______________ / \ | joan stark spunk1111@juno.com | | VISIT MY ASCII ART GALLERY: | | http://www.geocities.com/SoHo/7373/ | \_______________________ooo_________/ jgs | | | |_ | _| | | | |__|__| /-'Y'-\ (__/ \__) ends shapes { e (" |") w ("| ") sw (" \\", " ", " ", " ", " ", " ", " ") se ("/ ", " ", " ", " ", " ", " ", " ") ssw ("_", " ", " ", " ", " ", " ", " ") sse ("_", " ", " ", " ", " ", " ", " ") nw (" ", " ", " ", " ", " ") nnw (" ", " ", " ", " ", "_") nne (" ", " ", " ", " ", "_") ne (" ", " ", " ", " ", " ") ene ("\\ ") wnw (" /") n (" .-\"\"\"-. ", " / .===. \\ ", " \\/ 6 6 \\/ ", " ( \\___/ ) ", "ooo__\\_____/_____") s ("______________ooo", " | | | ", " |_ | _| ", " | | | ", " |__|__| ", " /-'Y'-\\ ", " (__/ \\__) ") } padding { top 1 } #elastic (n,s,e, w) # then I'd have to call this "boys" elastic (nne,nnw, sse,ssw, e, w) END boy # ============================================================================ BOX girl author "Joan G. Stark " revision "1.0" revdate "April 02, 1999 (Friday, 19:13h)" created "April 02, 1999 (Friday, 19:13h)" sample .-"""-. / .===. \ / / a a \ \ / ( \___/ ) \ ________ooo\__\_____/__/___________ / \ | joan stark spunk1111@juno.com | | VISIT MY ASCII ART GALLERY: | | http://www.geocities.com/SoHo/7373/ | \________________________ooo________/ jgs / \ /:.:.:.:.:.:.:\ | | | \==|==/ /-'Y'-\ (__/ \__) ends shapes { n (" .-\"\"\"-. ", " / .===. \\ ", " / / a a \\ \\ ", " / ( \\___/ ) \\ ", "ooo\\__\\_____/__/___", " ") s ("________________ooo", " / \\ ", " /:.:.:.:.:.:.:\\ ", " | | | ", " \\==|==/ ", " /-'Y'-\\ ", " (__/ \\__) ") e (" |") w ("| ") sw (" \\", " ", " ", " ", " ", " ", " ") se ("/ ", " ", " ", " ", " ", " ", " ") ssw ("_", " ", " ", " ", " ", " ", " ") sse ("_", " ", " ", " ", " ", " ", " ") nw (" ", " ", " ", " ", " ", " /") nnw (" ", " ", " ", " ", "_", " ") nne (" ", " ", " ", " ", "_", " ") ne (" ", " ", " ", " ", " ", "\\ ") } elastic (nne,nnw, sse,ssw, e, w) END girl # ============================================================================ BOX tjc author "Thomas Jensen " revision "1.1" revdate "July 16, 1999 (Friday, 18:55h)" created "April 02, 1999 (Friday, 19:26h)" SAmple static char *foo (const int a, const int b) /* * Do the foo on the bar and around again. * * a number of doodlefrobs * b barfoo mode (0 == off) * * Memory will be allocated for the result. * * RETURNS: Success: Pointer to result line * Error: 0 (e.g. out of memory) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ { static char temp .... int ii; .... ends indent "none" # alternatives: "box", "text" replace "\\*/" with "*\\/" # quote closing comment tags reverse "\\*\\\\/" to "*/" shapes { wnw ("/*") w (" *") sw ("* ", " *") ssw ("*", "/") s (" *", " ") } elastic (n, s, w) padding { left 2 vertical 1 } END tjc # ============================================================================ BOX netdata author "Thomas Jensen " revision "1.0" revdate "April 09, 1999 (Friday, 19:06h)" created "April 09, 1999 (Friday, 19:06h)" sample %{-----------------------------------------------------------------+ | IBM Net.Data Macro Sample - Perl and SQL Backends | | Thomas Jensen, February 17, 1998 (Tuesday, 16:40h) | +-----------------------------------------------------------------%} ends shapes { nw ("%{") ne ("+ ") sw (" +") se ("%}") e ("| ") w (" |") n ("-") s ("-") } replace "%}" with "%\\}" reverse "%\\\\}" to "%}" padding { horizontal 1 } elastic (n, e, s, w) END netdata # ============================================================================ BOX xes author "Joan G. Stark " revision "1.1" revdate "August 18, 1999 (Wednesday, 17:04h)" created "April 09, 1999 (Friday, 20:05h)" sample <\/><\/><\/> <\/><\/> <\/> <\/> <\/> <\/> <\/> <\/> <\/> <\/> <\/><\/><\/> jgs ends delim ?" shapes { nw (" ", " <", " <") nnw (" ", "\/>", "/\>") n ("<\/>", "", " ") nne (" ", "<\/", " ", "> ") wnw (" <\/>", " ") w ("<\/> ", " ") wsw (" <\/>", " ") sw (" <", " <", " ") ssw ("\/>", "/\>", " ") s (" ", "<\/>", "") sse ("<\/", " ", "> ", " ") ese ("<\/> ", " ") e (" <\/>", " ") ene ("<\/> ", " ") } elastic (n, e, s, w) END xes # ============================================================================ BOX dog author "Joan G. Stark " revision "1.0" revdate "April 09, 1999 (Friday, 19:45h)" created "April 09, 1999 (Friday, 19:45h)" sample __ _,--="=--,_ __ / \." .-. "./ \ / ,/ _ : : _ \/` \ \ `| /o\ :_: /o\ |\__/ `-'| :="~` _ `~"=: | \` (_) `/ jgs .-"-. \ | / .-"-. .-----{ }--| /,.-'-.,\ |--{ }-----. ) (_)_)_) \_/`~-===-~`\_/ (_(_(_) ( ( joan stark ) ) < spunk1111@juno.com > ( ( ASCII ART GALLERY: ) ) < http://www.geocities.com/SoHo/7373/ > ( '-------------------------------------------' ends shapes { nnw (" ", " ", " ", " ", " ", " ", " ", "-", " ") nne (" ", " ", " ", " ", " ", " ", " ", "-", " ") nw (" ", " ", " ", " ", " ", " ", " ", ".--", " ) ") ne (" ", " ", " ", " ", " ", " ", " ", "--.", " ( ") w ("( ", " ) ") e (" )", " ( ") sw ("'--") se ("--'") s ("-") n (" __ _,--=\"=--,_ __ ", " / \\.\" .-. \"./ \\ ", " / ,/ _ : : _ \\/` \\ ", " \\ `| /o\\ :_: /o\\ |\\__/ ", " `-'| :=\"~` _ `~\"=: | ", " \\` (_) `/ ", " .-\"-. \\ | / .-\"-. ", "{ }--| /,.-'-.,\\ |--{ }", "(_)_)_) \\_/`~-===-~`\\_/ (_(_(_)") } elastic (nnw, nne,e,s,w) END dog # ============================================================================ BOX cat author "Joan G. Stark " revision "1.0" revdate "April 09, 1999 (Friday, 19:45h)" created "April 09, 1999 (Friday, 19:45h)" sample /\ /\ |`\\_,--="=--,_//`| \ ." :'. .': ". / ==) _ : ' : _ (== |>/O\ _ /O\<| | \-"~` _ `~"-/ | >|`===. \_/ .===`|< jgs .-"-. \===' | '===/ .-"-. .-----{'. '`}---\, .-'-. ,/---{.'. '}-----. ) `"---"` `~-===-~` `"---"` ( ( joan stark ) ) < spunk1111@juno.com > ( ( ASCII ART GALLERY: ) ) < http://www.geocities.com/SoHo/7373/ > ( '-------------------------------------------' ends shapes { nnw (" ", " ", " ", " ", " ", " ", " ", " ", "-", " ") nne (" ", " ", " ", " ", " ", " ", " ", " ", "-", " ") nw (" ", " ", " ", " ", " ", " ", " ", " ", ".--", " ) ") ne (" ", " ", " ", " ", " ", " ", " ", " ", "--.", " ( ") w ("( ", " ) ") e (" )", " ( ") sw ("'--") se ("--'") s ("-") n (" /\\ /\\ ", " |`\\\\_,--=\"=--,_//`| ", " \\ .\" :'. .': \". / ", " ==) _ : ' : _ (== ", " |>/O\\ _ /O\\<| ", " | \\-\"~` _ `~\"-/ | ", " >|`===. \\_/ .===`|< ", " .-\"-. \\===' | '===/ .-\"-. ", "{'. '`}---\\, .-'-. ,/---{.'. '}", "`\"---\"` `~-===-~` `\"---\"`") } elastic (nnw, nne,e,s,w) END cat # ============================================================================ BOX capgirl author "Joan G. Stark " revision "1.0" revdate "April 09, 1999 (Friday, 19:24h)" created "April 09, 1999 (Friday, 19:24h)" sample .-"```"-. /_______; \ (_________)\| / / a a \ \(_) / ( \___/ ) \ ________ooo\__\_____/__/___________ / \ | joan stark spunk1111@juno.com | | VISIT MY ASCII ART GALLERY: | | http://www.ascii-art.com | \________________________ooo________/ / \ jgs /:.:.:.:.:.:.:\ | | | \==|==/ /-'Y'-\ (__/ \__) ends shapes { n (" .-\"```\"-. ", " /_______; \\ ", " (_________)\\| ", " / / a a \\ \\(_) ", " / ( \\___/ ) \\ ", "ooo\\__\\_____/__/___", " ") s ("________________ooo", " / \\ ", " /:.:.:.:.:.:.:\\ ", " | | | ", " \\==|==/ ", " /-'Y'-\\ ", " (__/ \\__) ") e (" |") w ("| ") sw (" \\", " ", " ", " ", " ", " ", " ") se ("/ ", " ", " ", " ", " ", " ", " ") ssw ("_", " ", " ", " ", " ", " ", " ") sse ("_", " ", " ", " ", " ", " ", " ") nw (" ", " ", " ", " ", " ", " ", " /") nnw (" ", " ", " ", " ", " ", "_", " ") nne (" ", " ", " ", " ", " ", "_", " ") ne (" ", " ", " ", " ", " ", " ", "\\ ") } elastic (nne,nnw, sse,ssw, e, w) END capgirl # ============================================================================ BOX santa author "Joan G. Stark " revision "1.0" revdate "April 09, 1999 (Friday, 19:24h)" created "April 09, 1999 (Friday, 19:24h)" sample .-"``"-. /______; \ {_______}\| (/ a a \)(_) (.-.).-.) _______ooo__( ^ )____________ / '-.___.-' \ | joan stark | | spunk1111@juno.com | | ASCII ART GALLERY: | | http://www.ascii-art.com | \________________________ooo________/ |_ | _| jgs \___|___/ {___|___} |_ | _| /-'Y'-\ (__/ \__) ends shapes { n (" .-\"``\"-. ", " /______; \\ ", " {_______}\\| ", " (/ a a \\)(_) ", " (.-.).-.) ", "ooo__( ^ )____", " '-.___.-' ") s ("_________________ooo", " |_ | _| jgs", " \\___|___/ ", " {___|___} ", " |_ | _| ", " /-'Y'-\\ ", " (__/ \\__) ") e (" |") w ("| ") sw (" \\", " ", " ", " ", " ", " ", " ") se ("/ ", " ", " ", " ", " ", " ", " ") ssw ("_", " ", " ", " ", " ", " ", " ") sse ("_", " ", " ", " ", " ", " ", " ") nw (" ", " ", " ", " ", " ", " ", " /") nnw (" ", " ", " ", " ", " ", "_", " ") nne (" ", " ", " ", " ", " ", "_", " ") ne (" ", " ", " ", " ", " ", " ", "\\ ") } elastic (nne,nnw, sse,ssw, e, w) END santa # ============================================================================ BOX spring author "Joan G. Stark " revision "1.1" revdate "August 18, 1999 (Wednesday, 17:05h)" created "April 09, 1999 (Friday, 15:53h)" sample , /\^/`\ | \/ | | | | SPRING IS IN THE AIR! jgs \ \ / _ _ '\\//' _{ ' }_ || joan stark { `.!.` } || ',_/Y\_,' || , {_,_} |\ || |\ | | | || | | ASCII ART GALLERY: (\| /) | | || / / \| // \ \||/ / |// `\\//` \\ \./ \\ / // \\./ \\ // \\ |/ / ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ends delim ?" shapes { nw (" , ") wnw (" /\^/`\ ", " | \/ | ", " | | | ", " \ \ / ", " '\\//' ") w (" || ") wsw (" || , ", "|\ || |\ ", "| | || | |", "| | || / / ", " \ \||/ / ") sw (" `\\//` ", " ^^^^^^^^^^") ene (" ", " ", " jgs ", " _ _ ", " _{ ' }_ ", "{ `.!.` }", "',_/Y\_,'", " {_,_} ") e (" | ") ese (" (\| /)", " \| // ", " |// ") se (" \\ |/ / ", "^^^^^^^^^") s ("\ \./ \", "^^^^^^^^^^^^") } elastic (s,e,w) END spring # ============================================================================ BOX stark2 author "Joan G. Stark " revision "1.0" revdate "April 05, 1999 (Monday, 21:55h)" created "April 05, 1999 (Monday, 21:55h)" sample .:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@-:. .:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@-:. .:-@ ____ (_, _, _, _, _, @-:. .:-@ (-(__`,_ ,_ |_, | | | | Spunk1111@juno.com @-:. .:-@ ____)|_)|_|| || \__, _|_ _|_ _|_ _|_ @-:. .:-@ ( _| |_, @-:. .:-@ ( ____, ____ (_, @-:. .:-@ (-| _ _ ,_ (-(__`_|_ _ ,_ |_, @-:. .:-@ _ |(_)(_|| | ____) | (_|| | \_, @-:. .:-@ (__/ ( |_, @-:. .:-@ @-:. .:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@-:. .:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@.:-@-:. ends shapes { nw (".:-@", ".:-@") n (".:-@", ".:-@") nne (".:-", ".:-") ne ("@-:.", "@-:.") e ("@-:.") w (".:-@") sw (".:-@", ".:-@") s (".:-@", ".:-@") sse (".:-", ".:-") se ("@-:.", "@-:.") } elastic (n,s,e, w) END stark2 # ============================================================================ BOX stark1 author "Joan G. Stark " revision "1.0" revdate "April 05, 1999 (Monday, 21:55h)" created "April 05, 1999 (Monday, 21:55h)" sample =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= ^ -, ,-. . . ^ ^ | ,-. ,-. ;-. `-, |- ,-. ;-. | ' ^ ^ , | | | ,-| | | , ; | ,-| | |`. ^ ^ `-' `-' `-^ ' ^ `-' `- `-^ ' ` ` ^ ^ Spunk1111@juno.com ^ ^ ,-. . . . . . ^ ^ `-, ;-. . . ;-. | ' | | | | ^ ^ , ; | | | | | | |`. | | | | ^ ^ `-' |-' `-^ ' ^ ` ` ` ` ` ` ^ ^ ` ^ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= ends shapes { nw ("=") ne ("=") nne ("-") N ("-=") e ("^") w ("^") sw ("=") ssw ("-") s ("=-") se ("=") } padding {h 1} elastic (n,s,e, w) END stark1 # ============================================================================ BOX peek revision "1.0" revdate "April 12, 1999 (Monday, 12:52h)" created "April 12, 1999 (Monday, 12:52h)" sample /* _\|/_ (o o) +----oOO-{_}-OOo---------------------+ | | | C function headers? | | | | | +-----------------------------------*/ ends shapes { nw ("/*", " ", " +") nnw (" _\\|/_ ", " (o o) ", "----oOO-{_}-OOo") n (" ", " ", "-") ne (" ", " ", "+") e ("|") w (" |") sw (" +") s ("-") sse ("*") se ("/") } replace "\\*/" with "*\\/" # quote closing comment tags reverse "\\*\\\\/" to "*/" elastic (n,e,s,w) END peek # ============================================================================ BOX java-cmt author "Thomas Jensen " revision "1.0" revdate "June 17, 1999 (Thursday, 19:59h)" created "June 17, 1999 (Thursday, 19:59h)" sample // // regular Java // comments // ends shapes { w ("//") } padding {lef 1} elastic (w) END java-cmt # ============================================================================ BOX pound-cmt author "Thomas Jensen " revision "1.0" revdate "June 17, 1999 (Thursday, 19:59h)" created "June 17, 1999 (Thursday, 19:59h)" sample # # regular comments used in Perl, Shell scripts, etc. # ends shapes { w ("#") } padding { left 1} elastic (w) END pound-cmt # ============================================================================ BOX html-cmt author "Thomas Jensen " revision "1.0" revdate "June 17, 1999 (Thursday, 19:59h)" created "June 17, 1999 (Thursday, 19:59h)" sample ends shapes { w ("") } elastic (e,w) END html-cmt # ============================================================================ BOX vim-cmt author "Thomas Jensen " revision "1.0" revdate "June 17, 1999 (Thursday, 19:59h)" created "June 17, 1999 (Thursday, 19:59h)" sample " " comments used in the vim editor's config file (.vimrc) " ends shapes { w ("\"") } padding { left 1 } elastic ( w ) END vim-cmt # ============================================================================ BOX right author "Thomas Jensen " revision "1.0" revdate "June 17, 1999 (Thursday, 19:59h)" created "June 17, 1999 (Thursday, 19:59h)" sample This can be used for marking code changes with your initials (I don't like it, but some people work this way): for (j=0; j" revision "1.0" revdate "March 15, 2000 (Wednesday 12:17h)" created "March 15, 2000 (Wednesday 12:17h)" sample -- -- regular Ada -- comments -- ends shapes { w ("--") } padding {lef 1} elastic (w) END ada-cmt # ============================================================================ BOX ada-box author "Neil Bird " revision "1.0" revdate "March 15, 2000 (Wednesday 12:24h)" created "March 15, 2000 (Wednesday 12:24h)" sample --------------- -- -- -- -- --------------- ends shapes { nw ("--") n ("-") ne ("--") w ("--") e ("--") sw ("--") s ("-") se ("--") } padding { horiz 1 } elastic (n,e,s,w) END ada-box # ============================================================================ BOX boxquote author "Christian Molls " revdate "Die Aug 15 23:02:02 CEST 2000" created "Die Aug 15 23:01:50 CEST 2000" revision "1.0" sample ,----[ mp3-wav ] | #!/bin/sh | # konvertiert im aktuellen Verzeichnis .mp3 in .wav | for i in *.mp3; do | mpg123 -v --stereo --rate 44100 -w "`basename "$i" .mp3`".wav "$i" | done `---- ends shapes { nw (",") nnw ("---- [ ]") n (" ") w ("|") sw ("`") ssw ("---- ") s (" ") } padding { horiz 1 } elastic (w,n,s) END boxquote # ============================================================================ BOX cc author "Bas van Gils " revision "1.0" revdate "Tue Sep 19 12:06:51 CEST 2000" created "Tue Sep 19 12:06:51 CEST 2000" sample /**************** * * * * ****************/ ends shapes { nw ("/*") n ("*") ne ("* ") w (" *") e ("* ") sw (" *") s ("*") se ("*/") } delim ?" replace "\*/" with "*\/" # quote closing comment tags reverse "\*\\/" to "*/" padding { horiz 1 } elastic (n,e,s,w) END cc # ============================================================================ BOX stone author "Fredrik Steen " revision "1.0" created "April 25, 2001 (Wed 11:00)" sample +-------------+ | stone | +-------------+ ends shapes { nw ("+") n ("-") ne ("+") w ("|") e ("|") sw ("+") s ("-") se ("+") } padding { horiz 1 } elastic (n,e,s,w) END stone # ============================================================================ BOX test1 author "Thomas Jensen " sample test1 ends shapes { nw ("#") n ("123") s ("12345") se ("#") e ("#") sw ("#") ne ("#") w ("#") } elastic (n,s,e, w) END test1 # ============================================================================ BOX test2 author "Thomas Jensen " sample test2 ends shapes { nw ("#") nnw ("--") sse ("---") n ("123") s ("12345") se ("#") e ("#") sw ("#") ne ("#") w ("#") } elastic (n,s,e, w) END test2 # ============================================================================ BOX test3 author "Thomas Jensen " sample test3 ends shapes { nnw ("123") nne ("456") n ("---") s ("<>") ssw ("12345") sse ("67890") nw ("#") se ("#") e ("#") sw ("#") ne ("#") w ("#") } elastic (nne,nnw,ssw,sse,e, w) END test3 # ============================================================================ BOX test4 author "Thomas Jensen " sample test4 ends shapes { e ("1","2","3") w ("1","2","3","4","5") s ("#") n ("#") nw ("#") se ("#") sw ("#") ne ("#") } elastic (n,s,e, w) END test4 # ============================================================================ BOX test5 author "Thomas Jensen " sample test5 ends shapes { e ("1","2","3") w ("1","2","3","4","5") ene ("|","|") wsw ("|","|","|") s ("#") n ("#") nw ("#") se ("#") sw ("#") ne ("#") } elastic (n,s,e, w) END test5 # ============================================================================ BOX test6 author "Thomas Jensen " sample test6 ends shapes { ene ("1","2","3") ese ("4","5","6") wnw ("1","2","3","4","5") wsw ("6","7","8","9","0") e ("|","|") w ("|","|","|") s ("#") n ("#-") nw ("#") se ("#") sw ("#") ne ("#") } elastic (ene,ese,wnw,wsw,n,s) END test6 # ============================================================================ BOX retest author "Thomas Jensen " revision "1.1" revdate "August 18, 1999 (Wednesday, 17:07h)" created "April 04, 1999 (Sunday, 18:00h)" sample regular expression test use "foo", "bar", and "--" repeatedly in input ends delimiter ?" shapes { nw ("*") ne ("*") sw ("*") se ("*") n ("*") e ("*") s ("*") w ("*") } elastic (n,e,s,W) replace once "bar" with "raba-raba" replace global "f(o)o" with "fu\1\1\1\1\1\1" replace "--" with "++++" END retest # ============================================================================ BOX headline author "Thomas Jensen " revision "1.2" revdate "August 22, 1999 (Sunday, 13:22h)" created "March 18, 1999 (Thursday, 15:25h)" sample /*************/ /* */ /* */ /*************/ ends shapes { nw ("/*") n ("*") ne ("*/") w ("/*") e ("*/") sw ("/*") s ("*") se ("*/") } replace "^( *)([^ ])" with "\\1\\2 " replace "([^ ]) ([^ ])" with "\\1 \\2" reverse "^( *)([^ ]*) " to "\\1\\2" # \1 to leave indentation untouched reverse "([^ ]) ([^ ])" to "\\1 \\2" padding { left 2 right 1 } elastic (n,e,s,w) END headline # ============================================================================ BOX lisp-cmt author "Vijay Lakshminarayanan " revision "1.0" revdate "February 20, 2006 (Monday, 20:36h)" created "February 20, 2006 (Monday, 20:36h)" sample ;; ;; regular comments used in Lisp ;; ends shapes { w (";;") } padding { left 1 } elastic (w) END lisp-cmt #============================================================================ BOX ccel author "Elmar Loos " revision "1.0" sample /////////////// text // here // /////////////// ends shapes { nnw ("/") n ("/") ne ("//") e ("//") ssw ("//") s ("/") se ("//") } padding { right 1 } elastic (n,e,s) END ccel #============================================================================ BOX underline author "Elmar Loos " revision "1.0" sample // Bla, foo bar! // ~~~~~~~~~~~~~ ends shapes { w ("// ") sw ("// ") s ("~") } elastic (s,w) END underline #============================================================================ BOX ian_jones author "Karl E. Jorgensen " created "Fri Jul 20 16:52:39 BST 2001" revision "0.1" sample \\\/// / _ _ \ (| (.)(.) |) .----------------------.OOOo--()--oOOO.-----------------. | | | Your Text Here Your Text Here Your Text Here Your Tex | | Your Text Here Your Text Here Your Text Here Your Tex | | Your Text Here Your Text Here Your Text Here Your Tex | | Your Text Here Your Text Here Your Text Here Your Tex | | | '--------------------.oooO------------------------------' ( ) Oooo. \ ( ( ) \_) ) / (_/ ends shapes { nw(" ", " ", " ", ".") w ("|") sw("'", " ", " ", " ", " ") nnw(" ", " ", " ", "-") n (" \\\\\\/// ", " / _ _ \\ ", " (| (.)(.) |) ", ".OOOo--()--oOOO.") nne(" ", " ", " ", "-") ne (" ", " ", " ", ".") e ("|") se ("'", " ", " ", " ", " ") ssw("-", " ", " ", " ", " ") s (".oooO-----------", " ( ) Oooo. ", " \\ ( ( ) ", " \\_) ) / ", " (_/ ") sse("-", " ", " ", " ", " ") } elastic (w,e,nnw,nne,ssw,sse) padding { all 1 } END ian_jones #EOF vim: set ai sw=4: boxes-1.1.1/COPYING0100644000175000001440000004312706737703360013460 0ustar tsjensenusers GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.