/* roff.c general register handling code */ #include "nroff.h" char *getnreg(); getrname(name, ival) char *name; int *ival; { int c; c = getm(); if(c == EOF) return(0); if(ival){ if(c == '+' || c == '-'){ *ival = c; if((c = getm()) == EOF) return(0); } } if(c == '('){ if((c = getm()) == EOF) return(0); name[0] = c; if( (c = getm()) == EOF) return(0); name[1] = c; } else { name[0] = c; name[1] = '\0'; } return(1); } /* numeric registers */ defreg(buf) char *buf; { char *p; char name[2]; struct nregs *np; int sign = 0; int val; if( (p = getnreg(buf, name)) == 0) return; if(*p == '\0') return; if(numregs == 0) initsvals(); for(np = numregs ; np ; np = np->n_next) if(np->n_name[0] == name[0] && np->n_name[1] == name[1]) break; if(np == 0){ np = (struct nregs *)mymalloc(sizeof(struct nregs), TRUE); np->n_name[0] = name[0]; np->n_name[1] = name[1]; np->n_next = numregs; numregs = np; } if(np->n_status & NRO) return; if(*p == '+' || *p == '-') sign = *p++; val = eval(&p); if(sign == '+') np->n_value += val; else if(sign == '-') np->n_value -= val; else np->n_value = val; np->n_incr = 1; if(np->n_status & NSYS) return; while(*p == ' ') p++; if(*p != '\0') np->n_incr = eval(&p); } setnform(buf) char *buf; { char *p; char name[2]; struct nregs *np; if( (p = getnreg(buf, name)) == 0) return; if(*p == '\0') return; for(np = numregs ; np ; np = np->n_next) if(np->n_name[0] == name[0] && np->n_name[1] == name[1]) break; if(np == 0) return; if(np->n_status & (NRO|NSYS)) return; if(isdigit(*p)){ for(np->n_digits = 0 ; isdigit(*p) ; p++) np->n_digits++; np->n_form = '1'; return; } switch(*p){ case 'a': case 'A': case 'i': case 'I': np->n_form = *p; return; } } char * getnreg(buf, name) char *buf, *name; { char *p = buf; char *ttl = name; if(*p == '\0') return( (char *) 0); for(ttl = name; *p && *p != ' ' ; p++) if(ttl < name + 2) *ttl++ = *p; if(ttl == name + 1) *ttl = '\0'; while(*p == ' ') p++; return(p); } numread() { struct nregs *np; char name[2]; int sign = 0; char tbuf[20]; char *p; int val; int i; struct source *mp; char *setroman(); if(getrname(name, &sign) == 0) return; if(numregs == 0) /* if not used yet, set up system regs */ initsvals(); for(np = numregs ; np ; np = np->n_next) if(np->n_name[0] == name[0] && np->n_name[1] == name[1]) break; if(np == 0) /* register not found */ return; if(np->n_status & NSYS) getsvals(np); if( (np->n_status & NRO) == 0 && sign){ if(sign == '+') np->n_value += np->n_incr; else np->n_value -= np->n_incr; } val = np->n_value; switch(np->n_form){ default: np->n_digits = 1; np->n_form = '1'; /* fall through */ case '1': /* arabic */ i = np->n_digits; if(i == 0) i = 1; else if(i > 15) i = 15; p = &tbuf[15]; sprintf(p, "%d", val); i -= strlen(p); while(i-- > 0) *--p = '0'; break; case 'i': case 'I': p = setroman(tbuf, val, np->n_form == 'I'); break; case 'a': case 'A': p = &tbuf[19]; *p-- = '\0'; if(val <= 0) *p = '0'; else { i = val-1; do { *p-- = i % 26 + np->n_form; } while(i /= 26); p++; } break; } /* wow !! got number in p - put into output queue */ mp = (struct source *)mymalloc(sizeof(struct source), TRUE); mp->m_val = mymalloc(strlen(p) + 1, FALSE); strcpy(mp->m_val, p); mp->m_curp = mp->m_val; mp->m_last = curmacro; curmacro = mp; if(sign && (np->n_status & (NRO|NSYS)) == NSYS) rsetsvals(np); } /* convert val to a string in roman numerals */ char * setroman(tbuf, val, ucase) char *tbuf; { char *tlets; char *p; p = tbuf + 15; *p-- = '\0'; if(val > 3999) val = 3999; else if(val <= 0){ *p = '0'; return(p); } if(ucase) tlets = "IVXLCDM"; else tlets = "ivxlcdm"; for(; val ; val /= 10, tlets += 2){ switch(val % 10){ case 0: continue; case 3: *p-- = *tlets; case 2: *p-- = *tlets; case 1: *p-- = *tlets; continue; case 4: *p-- = tlets[1]; *p-- = *tlets; continue; case 8: *p-- = *tlets; case 7: *p-- = *tlets; case 6: *p-- = *tlets; case 5: *p-- = tlets[1]; continue; case 9: *p-- = tlets[2]; *p-- = *tlets; continue; } } return(++p); } /* regread, called from ngets to set redirection */ regread() { struct source *findreg(); char name[2]; struct source *mp; int c; if(getrname(name, (int *)0) == 0) return; mp = findreg(name, FALSE); if(mp == 0) return; if( (mp->m_type & ASTR) == 0) return; if(mp->m_last != 0) /* already in use */ return; mp->m_last = curmacro; /* invoke the macro */ curmacro = mp; curmacro->m_curp = mp->m_val; } struct source * findreg(str, tocreat) char *str; { char c = str[1]; struct source *mp; if(c == ' ') c = '\0'; for(mp = regstrs ; mp ; mp = mp->m_next) if(mp->m_name[0] == *str && mp->m_name[1] == c) return(mp); if(!tocreat) return(mp); mp = (struct source *)mymalloc(sizeof(struct source), TRUE); mp->m_next = regstrs; regstrs = mp; mp->m_name[0] = *str; mp->m_name[1] = c; return(mp); } /* define a string */ defstr(buf, cmd) char *buf; { char name[2]; char *ttl = name; struct source *mp; int len; int c; int olen; if(*buf == '\0') return; for(;*buf && *buf != ' '; buf++) if(ttl < name + 2) *ttl++ = *buf; if(ttl == name + 1) *ttl = '\0'; while(*buf == ' ') buf++; if(*buf == '"') c = *buf++; else c = ' '; ttl = buf; while(*buf && *buf != c) buf++; *buf = '\0'; mp = findreg(name, TRUE); if(mp->m_type == 0) mp->m_type = AREG|ASTR; else if((mp->m_type & (ASTR|AREG|ARO)) != (ASTR|AREG)) return; /* * shame about the current string !! can't do */ if(mp->m_last || mp == curmacro || mp == curdiv) return; if(cmd != AS){ /* must junk original str */ if(mp->m_val) myfree(mp->m_val); mp->m_val = 0; } len = buf - ttl + 1; if(mp->m_val == 0){ mp->m_val = mymalloc(len, FALSE); strcpy(mp->m_val, ttl); } else { olen = strlen(mp->m_val); buf = mymalloc(olen + len, FALSE); strcpy(buf, mp->m_val); myfree(mp->m_val); mp->m_val = buf; strcpy(mp->m_val + olen, ttl); } }