fmt.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 643 行 · 第 1/2 页

C
643
字号
            for( tmp += p->len; tmp < p->words + p->size; tmp++ ) {
                memset( tmp, 0, sizeof( word ) );
            }
            return( 0 );
        } else {
            p->size -= inc;
            return( 1 );
        }
    }
    return( 0 );
}

static int getIndentation( FILE *fp, unsigned *os )
{
    int         ch = 0;

    while( 1 ) {
        ch = fgetc( fp );
        if( ch == ' ' ) {
            *os += 1;
        } else if( ch == '\t' ) {
            *os += 8 - *os % 8;
        } else {
            break;
        }
    }
    if( ch == '\n' ) {
        *os = 0;
        return( END_LINE );
    } else if( ch == EOF ) {
        *os = 0;
        return( END_FILE );
    } else {
        ungetc( ch, fp );
        return( 0 );
    }
}

static char *insertWord( wordlist **list, char *wtext, unsigned wlen )
{
    wordlist    *temp;
    char        *text;
    unsigned     size;

    for( temp = *list; temp != NULL; temp = temp->next ) {
        if( wlen < temp->size - temp->len ) {
            text = temp->buf + temp->len;
            strcpy( text, wtext );
            temp->len += wlen + 1;
            return( text );
        }
    }
    size = max( wlen + 1, DEF_LIST_LEN );
    while( size > wlen ) {
        temp = (wordlist *) realloc( temp, sizeof( wordlist ) + size - sizeof( char ) );
        if( temp != NULL ) {
            break;
        } else {
            size /= 2;
        }
    }
    if( temp == NULL ) {
        return( NULL );
    } else {
        temp->size = size;
        temp->next = *list;
        temp->len  = wlen + 1;
        strcpy( temp->buf, wtext );
        *list = temp;
        return( temp->buf );
    }
}

static int getWord( FILE *fp, wordlist **list, word *w, unsigned *os )
{
    static int           ret  = 0;

    char                *tmp  = NULL;
    int                  ch   = 0;
    int                  pv   = 0;
    int                  ppv  = 0;

    ret &= ~OUT_OF_MEM;
    if( w->len == 0  ||  w->len >= w_size ) {
        ret = 0;
        while( 1 ) {
            if( w->len >= w_size ) {
                w_size += MIN_WORD_LEN;
                tmp  = (char *) realloc( w_buff, w_size );
                if( tmp == NULL ) {
                    w_size -= MIN_WORD_LEN;
                    return( OUT_OF_MEM );
                }
                w_buff = tmp;
            }
            ppv = pv;
            pv  = ch;
            ch  = fgetc( fp );
            if( ch == '\n'  ||  ch == '\t'  ||  ch == ' '  ||  ch == EOF ) {
                break;
            } else {
                *os += 1;
                w_buff[ w->len ] = ch;
                w->len++;
            }
        }
        while( 1 ) {
            if( ch == ' ' ) {
                w->spc++;
                *os += 1;
            } else if( ch == '\t' ) {
                w->spc += 8 - *os % 8;
                *os += 8 - *os % 8;
            } else {
                break;
            }
            ch = fgetc( fp );
        }

        if( w->len > 0 ) {
            w_buff[ w->len ] = '\0';
        }
        if( ch == EOF ) {
            *os = 0;
            w->spc = 1;
            ret |= END_FILE;
        } else if( ch == '\n' ) {
            *os = 0;
            w->spc = 1;
            ret |= END_LINE;
        } else {
            ungetc( ch, fp );
        }

        if( w->spc == 0 ) {
            w->spc = 1;
        } else if( f_mode & FMT_NOSPACE ) {
            if( pv == '.'  ||  pv == '?'  ||  pv == '!' ) {
                if( isupper( ppv ) ) {
                    w->spc = 1;
                } else {
                    w->spc = 2;
                }
            } else {
                w->spc = 1;
            }
        }
    }
    w->text = insertWord( list, w_buff, w->len );
    if( w->text == NULL ) {
        ret |= OUT_OF_MEM;
    }
    return( ret );
}

static int getParagraph( FILE *fp, para *p, wordlist **list )
{
    static  unsigned    lastos = 0;
    static  unsigned    lineos = 0;
    static  unsigned    curros = 0;
    static  int         start  = -1;

    int                 status = 0;
    int                 retval = 0;

    while( 1 ) {
        if( expandParagraph( p, MIN_PARA_LEN ) ) {
            return( OUT_OF_MEM );
        }
        if( lineos == 0 ) {
            lastos = curros;
            status = getIndentation( fp, &lineos );
            curros = lineos;
            start++;
        }
        if( (status & END_FILE)  ||  (status & END_LINE) ) {
            curros = 0;
            start  = 0;
            return( status );
        } else if( curros > lastos  &&  start ) {
            lastos = curros;
            return( status );
        }
        if( curros > p->indent ) {
            p->indent = curros;
            p->offset = curros;
        }
        if( curros < p->offset ) {
            p->offset = curros;
        }

        retval = getWord( fp, list, &p->words[ p->len ], &lineos );

        if( retval & OUT_OF_MEM ) {
            return( OUT_OF_MEM );
        }
        p->len++;
        if( retval & END_FILE ) {
            return( END_FILE );
        }
    }
}

static void formatFile( FILE *fp, int width, int offset )
{
    int         ret;

    para        p     = { NULL, 0, 0, 0, 0 };
    int         oldos = 0;
    int         erros = -1;
    wordlist   *list  = NULL;

    expandParagraph( &p, DEF_PARA_LEN );

    for( ; ; ) {
        ret = getParagraph( fp, &p, &list );

        if( ret & OUT_OF_MEM ) {
            if( erros != p.len ) {
                trimParagraph( &p );
                erros = p.len;
                continue;
            } else if( p.len == 0 ) {
                Die( "fmt: out of memory error\n" );
            }
        }

        if( p.len != 0 ) {
            if( p.indent <= oldos ) {       // keep track of offsets & indents
                p.indent = oldos;           // in case of out of mem. errors
                p.offset = oldos;
            }
            oldos = p.offset;
            formatParagraph( &p, width, offset, ret & OUT_OF_MEM );
        }
        if( ret & END_LINE ) {              // no need to format blank line
            fputchar( '\n' );
            oldos = 0;
        }

        resetParagraph( &p );
        resetWordlist( list );

        if( ret & END_FILE ) {
            break;
        }
        erros = -1;
    }
    free( p.words );                    // free the paragraph space
    freeWordlist( list );               // free the text space
}

void main( int argc, char **argv )
{
    FILE       *fp;
    int         ch;

    int         width  = DEF_LINE_LEN;
    int         offset = 0;
    int         regexp = 0;

    argv = ExpandEnv( &argc, argv );

    while( 1 ) {
        ch = GetOpt( &argc, argv, "Xcjnl:p:", usageMsg );
        if( ch == -1 ) {
            break;
        }
        switch( ch ) {
            case 'c':
                f_mode |= FMT_CENTRE;
                break;
            case 'j':
                f_mode |= FMT_JUSTIFY;
                break;
            case 'n':
                f_mode |= FMT_NOSPACE;
                break;
            case 'l':
                width = atoi( OptArg );
                break;
            case 'p':
                offset = atoi( OptArg );
                break;
            case 'X':
                regexp = 1;
                break;
        }
    }

    if( width <= 0 ) {
        Die( "fmt: invalid line length\n" );
    }
    if( offset < 0 ) {
        Die( "fmt: invalid page offset\n" );
    }

    argv = ExpandArgv( &argc, argv, regexp );
    argv++;

    if( *argv == NULL ) {
        formatFile( stdin, width, offset );
    } else {
        while( *argv != NULL ) {
            fp = fopen( *argv, "r" );
            if( fp == NULL ) {
                fprintf( stderr, "fmt: cannot open input file \"%s\"\n", *argv );
            } else {
                if( argc > 2 ) {
                    fprintf( stdout, "%s:\n", *argv );
                }
                formatFile( fp, width, offset );
                fclose( fp );
            }
            argv++;
        }
    }
    free( w_buff );                     // free the word space
    exit( EXIT_SUCCESS );
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?