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 + -
显示快捷键?