/* 
 * mxIndent.c --
 *
 *	Routines in this file provide facilities for querying
 *	and changing the indentation of lines in Mx files.
 *
 * Copyright (C) 1986, 1987, 1988 Regents of the University of California
 * Permission to use, copy, modify, and distribute this
 * software and its documentation for any purpose and without
 * fee is hereby granted, provided that the above copyright
 * notice appear in all copies.  The University of California
 * makes no representations about the suitability of this
 * software for any purpose.  It is provided "as is" without
 * express or implied warranty.
 */

#ifndef lint
static char rcsid[] = "$Header: mxIndent.c,v 1.4 88/07/18 14:45:27 ouster Exp $ SPRITE (Berkeley)";
#endif not lint

#include "mxInt.h"

/*
 *----------------------------------------------------------------------
 *
 * MxGetIndent --
 *
 *	Determine how much a line is indented.
 *
 * Results:
 *	The return value is the amount of leading space in line,
 *	where a space counts as 1 and a tab counts as 8.  An empty
 *	line has 0 indentation.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

int
MxGetIndent(file, line)
    Mx_File file;		/* File in which to check. */
    int line;			/* Line number to check. */
{
    register char *p;
    int indent;

    p = Mx_GetLine(file, line, (int *) NULL);
    if (p == NULL) {
	return 0;
    }

    indent = 0;
    while (1) {
	if (*p == ' ') {
	    indent++;
	} else if (*p == '\t') {
	    indent = (indent + 8) & ~07;
	} else break;
	p++;
    }
    return indent;
}

/*
 *----------------------------------------------------------------------
 *
 * MxSetIndent --
 *
 *	Modify the first few characters of a line to ensure that
 *	it is indented a particular amount.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Line is modified to have enough tabs and spaces at its
 *	beginning to create indent spaces worth of indentation.
 *
 *----------------------------------------------------------------------
 */

void
MxSetIndent(file, line, indent)
    Mx_File file;		/* File whose line is to be indented. */
    int line;			/* Line number to indent. */
    int indent;			/* Amount that line should be indented. */
{
#define MAXINSERT 100
    char insertChars[MAXINSERT];/* Characters to insert to create proper
				 * indentation. */
    int i;
    Mx_Position first, last;
    register char *p;
    char *string;

    p = Mx_GetLine(file, line, (int *) NULL);
    if (p == NULL) {
	return;
    }

    /*
     * Compute how much leading space to delete.
     */
    
    first.lineIndex = line;
    first.charIndex = 0;
    last.lineIndex = line;
    last.charIndex = 0;
    while ((*p == ' ') || (*p == '\t')) {
	last.charIndex++;
	p++;
    }
    
    /*
     * Compute how much leading space to insert to make the
     * proper indentation, then make the replacement.
     */
    
    if (indent == 0) {
	string = NULL;
    } else {
	for (i = 0; (indent >= 8) && (i < MAXINSERT-1); i++, indent -= 8) {
	    insertChars[i] = '\t';
	}
	for ( ; (indent > 0) && (i < MAXINSERT-1); i++, indent--) {
	    insertChars[i] = ' ';
	}
	insertChars[i] = 0;
	string = insertChars;
    }
    Mx_ReplaceBytes(file, first, last, string);
}

/*
 *----------------------------------------------------------------------
 *
 * MxCleanIndent --
 *
 *	This procedure is generally called just before the caret is
 *	moved from one line to another.  It checks the indentation
 *	on a line and cleans it up (if, for example, there are spaces
 *	before a tab) and also removes the indentation completely if
 *	there are no non-blank characters on the line.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The leading characters on the given line may be modified or
 *	deleted.
 *
 *----------------------------------------------------------------------
 */

void
MxCleanIndent(file, line)
    Mx_File file;		/* File whose line is to be cleaned up. */
    int line;			/* Line number to clean up. */
{
    register char *p;
    int length;
    int space, spaceBeforeTab;

    space = spaceBeforeTab = 0;
    p = Mx_GetLine(file, line, &length);
    if ((p == NULL) || (length == 1)) {
	return;
    }
    while (1) {
	if (*p == ' ') {
	    space = 1;
	} else if (*p == '\t') {
	    if (space) {
		spaceBeforeTab = 1;
	    }
	} else if (*p == '\n') {
	    Mx_Position first, last;
	    first.lineIndex = line;
	    first.charIndex = 0;
	    last.lineIndex = first.lineIndex;
	    last.charIndex = length-1;
	    Mx_ReplaceBytes(file, first, last, (char *) NULL);
	    return;
	} else {
	    break;
	}
	p++;
    }

    if (spaceBeforeTab) {
	MxSetIndent(file, line, MxGetIndent(file, line));
    }
}
