shithub: riscv

ref: 46cf9d4eb02a3a7c2516be3053994d4fb69eb949
dir: /sys/src/cmd/scat/prose.c/

View raw version
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "sky.h"

extern	Biobuf	bout;

char*
append(char *p, char *s)
{
	while(*s)
		*p++ = *s++;
	return p;
}

int
matchlen(char *a, char *b)
{
	int n;

	for(n=0; *a==*b; a++, b++, n++)
		if(*a == 0)
			return n;
	if(*a == 0)
		return n;
	return 0;
}

char*
prose(char *s, char *desc[][2], short index[])
{
	static char buf[512];
	char *p=buf;
	int i, j, k, max;

	j = 0;
	while(*s){
		if(p >= buf+sizeof buf)
			abort();
		if(*s == ' '){
			if(p>buf && p[-1]!=' ')
				*p++ = ' ';
			s++;
			continue;
		}
		if(*s == ','){
			*p++ = ';', s++;
			continue;
		}
		if(s[0]=='M' && '0'<=s[1] && s[1]<='9'){	/* Messier tag */
			*p++ = *s++;
			continue;	/* below will copy the number */
		}
		if((i=index[*s]) == -1){
	Dup:
			switch(*s){
			default:
				while(*s && *s!=',' && *s!=' ')
					*p++=*s++;
				break;

			case '0': case '1': case '2': case '3': case '4':
			case '5': case '6': case '7': case '8': case '9':
				while('0'<=*s && *s<='9')
					*p++ = *s++;
				if(*s=='\'' || *s=='s')
					*p++ = *s++;
				break;

			case '(': case ')':
			case '\'': case '"':
			case '&': case '-': case '+':
				*p++ = *s++;
				break;

			case '*':
				if('0'<=s[1] && s[1]<='9'){
					int flag=0;
					s++;
				Pnumber:
					while('0'<=*s && *s<='9')
						*p++=*s++;
					if(s[0] == '-'){
						*p++ = *s++;
						flag++;
						goto Pnumber;
					}
					if(s[0]==',' && s[1]==' ' && '0'<=s[2] && s[2]<='9'){
						*p++ = *s++;
						s++;	/* skip blank */
						flag++;
						goto Pnumber;
					}
					if(s[0] == '.'){
						if(s[1]=='.' && s[2]=='.'){
							*p++ = '-';
							s += 3;
							flag++;
							goto Pnumber;
						}
						*p++ = *s++;
						goto Pnumber;
					}
					p = append(p, "m star");
					if(flag)
						*p++ = 's';
					*p++ = ' ';
					break;
				}
				if(s[1] == '*'){
					if(s[2] == '*'){
						p = append(p, "triple star ");
						s += 3;
					}else{
						p = append(p, "double star ");
						s += 2;
					}
					break;
				}
				p = append(p, "star ");
				s++;
				break;
			}
			continue;
		}
		for(max=-1; desc[i][0] && desc[i][0][0]==*s; i++){
			k = matchlen(desc[i][0], s);
			if(k > max)
				max = k, j = i;
		}
		if(max == 0)
			goto Dup;
		s += max;
		for(k=0; desc[j][1][k]; k++)
			*p++=desc[j][1][k];
		if(*s == ' ')
			*p++ = *s++;
		else if(*s == ',')
			*p++ = ';', s++;
		else
			*p++ = ' ';
	}
	*p = 0;
	return buf;
}

void
prdesc(char *s, char *desc[][2], short index[])
{
	int c, j;

	if(index[0] == 0){
		index[0] = 1;
		for(c=1, j=0; c<128; c++)
			if(desc[j][0]==0 || desc[j][0][0]>c)
				index[c] = -1;
			else if(desc[j][0][0] == c){
				index[c] = j;
				while(desc[j][0] && desc[j][0][0] == c)
					j++;
				if(j >= NINDEX){
					fprint(2, "scat: internal error: too many prose entries\n");
					exits("NINDEX");
				}
			}
	}
	Bprint(&bout, "\t%s [%s]\n", prose(s, desc, index), s);
}