aboutsummaryrefslogblamecommitdiffstats
path: root/src/mds-kbdc/parse-error.c
blob: 6a3142484d99a29c7b1cbb8164047918f035778c (plain) (tree)
1
2
3

                                 
                                                                         















                                                                        

                  










                                          
                                               
   

                                                                                                    
 



































                                                                                                                 








                                          

                                                                                              
 















































                                                                                       








                                                                 

                                                                   
 




                                                          








                                                                 

                                                                
 

                                           








                                                               

                                                                         
 




                                                                 








                                                                             

                                                                     
 

                                                
 
/**
 * mds — A micro-display server
 * Copyright © 2014, 2015, 2016, 2017  Mattias Andrée (maandree@kth.se)
 * 
 * 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 3 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, see <http://www.gnu.org/licenses/>.
 */
#include "parse-error.h"

#include "paths.h"

#include <stdlib.h>
#include <alloca.h>
#include <string.h>



/**
 * Print information about a parsing error
 * 
 * @param  this    The error structure
 * @param  output  The output file
 * @param  desc    The description of the error
 */
static void
print(const mds_kbdc_parse_error_t *restrict this, FILE *restrict output, const char *restrict desc)
{
	size_t i, n, start = 0, end = 0;
	const char *restrict code = this->code;
	char *restrict path = relpath(this->pathname, NULL);

	/* Convert bytes count to character count for the code position. */
	for (i = 0, n = this->start; i < n; i++)
		if ((code[i] & 0xC0) != 0x80)
			start++;
	for (n = this->end; i < n; i++)
		if ((code[i] & 0xC0) != 0x80)
			end++;
	end += start;

	/* Print error information. */
	fprintf(output, "\033[01m%s\033[21m:", path ? path : this->pathname);
	free(path);
	if (this->error_is_in_file)
		fprintf(output, "%zu:%zu–%zu:", this->line + 1, start, end);
	switch (this->severity) {
	case MDS_KBDC_PARSE_ERROR_NOTE:           fprintf(output, " \033[01;36mnote:\033[00m ");           break;
	case MDS_KBDC_PARSE_ERROR_WARNING:        fprintf(output, " \033[01;35mwarning:\033[00m ");        break;
	case MDS_KBDC_PARSE_ERROR_ERROR:          fprintf(output, " \033[01;31merror:\033[00m ");          break;
	case MDS_KBDC_PARSE_ERROR_INTERNAL_ERROR: fprintf(output, " \033[01;31minternal error:\033[00m "); break;
	default:
		abort();
		break;
	}
	if (this->error_is_in_file) {
		fprintf(output, "%s\n %s\n \033[01;32m", desc, code);
		i = 0;
		for (n = start; i < n; i++) fputc(' ', output);
		for (n = end;   i < n; i++) fputc('^', output);
	} else {
		fprintf(output, "%s\n", desc);
	}
	fprintf(output, "\033[00m\n");
}


/**
 * Print information about a parsing error
 * 
 * @param  this    The error structure
 * @param  output  The output file
 */
void
mds_kbdc_parse_error_print(const mds_kbdc_parse_error_t *restrict this, FILE *restrict output)
{
	size_t n;
	char *desc;
	char *dend = this->description + strlen(this->description);
	char *dstart;
	char *dptr;
	char *p;
	char *q;

	/* Count the number points in the description we should modify to format it. */
	for (p = this->description, n = 0;;) {
		if (!(q = strstr(p, "‘")))
			q = dend;
		if (!(p = strstr(p, "’")))
			p = dend;
		if (q < p)
			p = q;
		if (*p++)
			n++;
		else
			break;
	}

	/* Allocate string for the formatted description. */
	n = 1 + strlen(this->description) + strlen("\033[xxm’") * n;
	dptr = desc = alloca(n * sizeof(char));

	/* Format description. */
	for (p = this->description;;) {
		dstart = p;
		if (!(q = strstr(p, "‘")))
			q = dend;
		if (!(p = strstr(p, "’")))
			p = dend;
		if (q < p)
			p = q;
		if ((n = (size_t)(p - dstart)))
			memcpy(dptr, dstart, n), dptr += n;
		if (p == dend)
			break;
		if (strstr(p, "‘") == p)
			dptr += sprintf(dptr, "\033[01m‘"), p += strlen("‘");
		else
			dptr += sprintf(dptr, "’\033[21m"), p += strlen("’");
	}
	*dptr = '\0';

	/* Print the error. */
	print(this, output, desc);
}



/**
 * Release all resources allocated in a `mds_kbdc_parse_error_t*`
 * 
 * @param  this  The error structure
 */
void
mds_kbdc_parse_error_destroy(mds_kbdc_parse_error_t *restrict this)
{
	if (!this)
		return;
	free(this->pathname),    this->pathname    = NULL;
	free(this->code),        this->code        = NULL;
	free(this->description), this->description = NULL;
}


/**
 * Release all resources allocated in a `mds_kbdc_parse_error_t*`
 * and release the allocation of the structure itself
 * 
 * @param  this  The error structure
 */
void
mds_kbdc_parse_error_free(mds_kbdc_parse_error_t *restrict this)
{
	mds_kbdc_parse_error_destroy(this);
	free(this);
}


/**
 * Release all resources allocated in a `NULL`-terminated group
 * of `mds_kbdc_parse_error_t*`:s
 * 
 * @param  this  The group of error structures
 */
void
mds_kbdc_parse_error_destroy_all(mds_kbdc_parse_error_t **restrict these)
{
	mds_kbdc_parse_error_t *restrict that;
	if (!these)
		return;
	while ((that = *these))
		mds_kbdc_parse_error_free(that), *these++ = NULL;
}


/**
 * Release all resources allocated in a `NULL`-terminated group of
 * `mds_kbdc_parse_error_t*`:s and release the allocation of the group itself
 * 
 * @param  this  The group of error structures
 */
void
mds_kbdc_parse_error_free_all(mds_kbdc_parse_error_t**restrict these)
{
	mds_kbdc_parse_error_destroy_all(these);
	free(these);
}