fmt.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 643 行 · 第 1/2 页
C
643 行
/****************************************************************************
*
* Open Watcom Project
*
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
* ========================================================================
*
* This file contains Original Code and/or Modifications of Original
* Code as defined in and that are subject to the Sybase Open Watcom
* Public License version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
* provided with the Original Code and Modifications, and is also
* available at www.sybase.com/developer/opensource.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
* NON-INFRINGEMENT. Please see the License for the specific language
* governing rights and limitations under the License.
*
* ========================================================================
*
* Description: WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
* DESCRIBE IT HERE!
*
****************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include <limits.h>
#include "misc.h"
#include "getopt.h"
#include "argvrx.h"
#include "argvenv.h"
#define DEF_PARA_LEN 128
#define MIN_PARA_LEN 1
#define DEF_LINE_LEN 72
#define DEF_LIST_LEN 512
#define MIN_WORD_LEN 8
#define FMT_CENTRE 0x01
#define FMT_JUSTIFY 0x02
#define FMT_NOSPACE 0x04
#define END_LINE 0x01
#define END_PARA 0x02
#define END_FILE 0x04
#define OUT_OF_MEM 0x08
char *OptEnvVar="fmt";
static const char *usageMsg[] = {
"Usage: fmt [-?Xcnj] [-l length] [-p offset] [@env] [files...]",
"\tenv : environment variable to expand",
"\tfiles : files to format",
"\tOptions: -? : display this message",
"\t\t -c : centre",
"\t\t -j : right justify",
"\t\t -n : do not preserve word spacing",
"\t\t -l length : set output line length",
"\t\t -p offset : set output page offset",
"\t\t -X : match files by regular expressions",
NULL
};
typedef struct wordlist {
unsigned size; // Structure for some word text.
unsigned len;
struct wordlist *next;
char buf[ 1 ];
} wordlist;
typedef struct word { // Structure for a single Word.
char *text;
unsigned len;
unsigned spc;
} word;
typedef struct para { // Structure for a single Paragraph.
word *words;
unsigned len;
unsigned indent;
unsigned offset;
unsigned size;
} para;
typedef struct range { // Structure for a particular Range
long cost; // of words that might form a line.
unsigned start;
unsigned left;
} range;
/*
* Global data.
*/
static char *w_buff = NULL; // word buffer
static unsigned w_size = 0; // size of word buffer
static int f_mode = 0; // formatting mode
/*
* Local functions.
*/
static void fputspc( int num )
{
for( ; num > 0; num-- ) { // simply output a given number of
fputchar( ' ' ); // spacees
}
}
static void justifyParagraph( para *p, range *r, int lines, int err )
{
int i, j, upper, blanks;
div_t s;
for( i = 0; i < lines; i++ ) {
if( i < lines - 1 ) {
upper = r[i+1].start - 1;
} else if( err ) { // If para. break was due to out
upper = p->len - 1; // of mem error, then justify last
} else { // line of paragraph. If not, then
break; // don't justify last line.
}
blanks = upper - r[i].start;
if( blanks == 0 ) { // Only one word on the line.
continue;
}
s = div( r[i].left, blanks ); // Divide spaces among the
for( j = r[i].start; j < upper; j++ ) { // inter-word blanks.
p->words[ j ].spc += s.quot;
}
if( s.rem != 0 ) { // Distribute remaining spaces
blanks /= s.rem; // somewhat equally.
if( i % 2 == 0 ) {
for( j = r[i].start; s.rem > 0; j += blanks ) {
p->words[j].spc += 1;
s.rem--;
}
} else {
for( j = upper - 1; s.rem > 0; j -= blanks ) {
p->words[j].spc += 1;
s.rem--;
}
}
}
}
}
static void outputParagraph( para *p, range *r, int lines )
{
int i, j;
fputspc( p->indent );
for( i = 0; i < lines - 1; i++ ) {
if( f_mode & FMT_CENTRE ) {
fputspc( r[i].left / 2 );
}
for( j = r[ i ].start; j < r[ i + 1 ].start - 1; j++ ) {
fputs( p->words[ j ].text, stdout );
fputspc( p->words[ j ].spc );
}
fputs( p->words[ j ].text, stdout );
fputchar( '\n' );
fputspc( p->offset );
}
if( f_mode & FMT_CENTRE ) {
fputspc( r[lines - 1].left / 2 );
}
for( j = r[lines - 1].start; j < p->len - 1; j++ ) {
fputs( p->words[ j ].text, stdout );
fputspc( p->words[ j ].spc );
}
fputs( p->words[ j ].text, stdout );
fputchar( '\n' );
}
static void formatParagraph( para *p, int width, int offset, int err )
{
range *r;
int i, j;
long cost, tempcost;
unsigned spcleft = 0;
unsigned comp = p->len - 1;
unsigned start = 0;
long inicost = width;
long length = p->offset;
r = (range *) malloc( p->len * sizeof( range ) );
if( err ) {
comp++;
}
p->words[ 0 ].len += p->indent - p->offset;
for( j = 0; j < p->len; j++ ) {
r[j].cost = LONG_MAX;
length += p->words[ j ].len;
tempcost = inicost - length;
p->words[j].len += p->words[j].spc;
for( i = start; i <= j; i++ ) {
cost = tempcost;
tempcost += p->words[i].len;
if( cost >= 0 ) {
spcleft = cost; // spaces left on line
if( j < comp ) {
cost *= cost; // calculate cost of range
} else {
cost = 0; // so you can ignore last line
}
if( i != 0 ) {
cost += r[i-1].cost;
}
if( cost < r[j].cost ) {
r[j].left = spcleft;
r[j].cost = cost;
r[j].start = i;
}
} else {
if( i == j ) {
r[j].cost = 0;
r[j].start = i;
}
length -= p->words[ start ].len;
start++;
}
}
length += p->words[j].spc;
}
j = p->len - 1;
for( i = j; i >= 0; i-- ) { // Walk back through table to find
r[i].start = r[j].start; // optimal path. Store path in the
r[i].left = r[j].left; // upper part of the range array.
if( r[j].start == 0 ) {
break;
}
j = r[i].start - 1;
}
// Note: Centring takes priority over justification. The output function
// actually handles most of the centring - here we only split the
// paragraph offsets/indents. To add right-justification, simply
// don't split the offsets/indents (here) and don't split the
// spaces left on lines. (in the output fcn.)
if( f_mode & FMT_CENTRE ) {
p->offset /= 2;
p->indent /= 2;
} else if( f_mode & FMT_JUSTIFY ) {
justifyParagraph( p, r + i, p->len - i, err );
}
p->offset += offset;
p->indent += offset;
outputParagraph( p, r + i, p->len - i );
free( r );
}
static void freeWordlist( wordlist *list )
{
wordlist *temp;
while( list != NULL ) {
temp = list->next; // free up all the text memory
free( list );
list = temp;
}
}
static void resetParagraph( para *p )
{
int i;
for( i = 0; i < p->len; i++ ) { // Reset word lengths and
p->words[ i ].len = 0; // space counts
p->words[ i ].spc = 0;
}
p->offset = 0;
p->indent = 0;
p->len = 0; // Reset paragraph settings
}
static void resetWordlist( wordlist *list )
{
for( ; list != NULL; list = list->next ) { // Reset wordlist settings
list->len = 0;
}
}
static void trimParagraph( para *p )
{
if( p->size > p->len ) {
p->size = p->len + 1;
p->words = (word *) realloc( p->words, p->size * sizeof( word ) );
}
}
static int expandParagraph( para *p, unsigned inc )
{
word *tmp;
if( p->len >= p->size ) {
p->size += inc;
tmp = (word *) realloc( p->words, p->size * sizeof( word ) );
if( tmp != NULL ) {
p->words = tmp;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?