chiark / gitweb /
only autoflush if the message ends with \n
[trains.git] / hostside / parseutils.c
1 /*
2  * common
3  * utilities for helping parsing
4  */
5
6 #include <stdarg.h>
7 #include <errno.h>
8 #include <stdlib.h>
9 #include <string.h>
10
11 #include "common.h"
12
13 void badcmd(ParseState *ps, const char *fmt, ...) {
14   va_list al;
15   va_start(al,fmt);
16   vbadcmd(ps,fmt,al);
17   va_end(al);
18 }
19
20 int ps_word(ParseState *ps) {
21   const char *space;
22   if (!ps->remain) return 0;
23   space= strchr(ps->remain, ' ');
24   ps->thisword= ps->remain;
25   if (space) {
26     ps->lthisword= space - ps->thisword;
27     ps->remain= space + 1;
28   } else {
29     ps->lthisword= strlen(ps->remain);
30     ps->remain= 0;
31   }
32   return 1;
33 }
34
35 int ps_needword(ParseState *ps) {
36   if (!ps_word(ps)) { badcmd(ps,"too few args"); return 0; }
37   return 1;
38 }
39
40 int ps_neednumber(ParseState *ps, long *r, long mi, long mx, const char *wh) {
41   char *ep;
42   long v;
43   
44   if (!ps_needword(ps)) return 0;
45   errno= 0; v= strtol(ps->thisword,&ep,0);
46   if (errno || ep != ps->thisword + ps->lthisword) {
47     badcmd(ps,"invalid number for %s",wh);
48     return 0;
49   }
50   if (v < mi || v > mx) {
51     badcmd(ps,"%s %ld out of range %ld..%ld",wh,v,mi,mx);
52     return 0;
53   }
54   *r= v;
55   return 1;
56 }
57
58 int ps_neednoargs(ParseState *ps) {
59   if (ps->remain) {
60     badcmd(ps,"too many arguments");
61     return 0;
62   }
63   return 1;
64 }
65  
66 int ps_needhextoend(ParseState *ps, Byte *d, int *len_io) {
67   Byte *d_begin, *d_end;
68   char buf[3], *ep;
69
70   d_begin= d;
71   d_end= d + *len_io;
72   buf[2]= 0;
73   
74   if (!ps->remain) { badcmd(ps,"need hex data block"); return 0; }
75   for (;;) {
76     if (!ps_word(ps)) break;
77     while (ps->lthisword > 0) {
78       if (ps->lthisword & 1) {
79         badcmd(ps,"hex data block with odd number of digits in part");
80         return 0;
81       }
82       buf[0]= ps->thisword[0];
83       buf[1]= ps->thisword[1];
84       if (d >= d_end) { badcmd(ps,"hex data block too long"); return 0; }
85       *d++= strtoul(buf,&ep,16);
86       if (*ep) { badcmd(ps,"invalid digit in hex data block"); return 0; }
87       ps->lthisword -= 2;
88       ps->thisword += 2;
89     }
90   }
91
92   *len_io= d - d_begin;
93   return 1;
94 }
95
96 const void *any_lookup(ParseState *ps, const void *inf, int ninfsmax,
97                        size_t sz) {
98   const char *tname;
99   int i;
100   
101   for (i=0;
102        i<ninfsmax && (tname= *(const char *const*)inf);
103        i++, inf= (const char*)inf + sz)
104     if (!thiswordstrcmp(ps,tname))
105       return inf;
106   return 0;
107 }
108
109 const void *any_needword_lookup(ParseState *ps, const void *infs, int ninfsmax,
110                                 size_t sz, const char *what) {
111   const void *r;
112   if (!ps_needword(ps)) return 0;
113   r= any_lookup(ps,infs,ninfsmax,sz);
114   if (!r) {
115     badcmd(ps,"unknown %s %.*s",what, ps->lthisword,ps->thisword);
116     return 0;
117   }
118   return r;
119 }
120
121 int lstrstrcmp(const char *a, int la, const char *b) {
122   int lb, minl, r;
123
124   lb= strlen(b);
125   minl= la < lb ? la : lb;
126   r= memcmp(a,b,minl);
127   if (r) return r;
128
129   return (la < lb ? -1 :
130           la > lb ? 1 : 0);
131 }
132
133 int thiswordstrcmp(ParseState *ps, const char *b) {
134   return lstrstrcmp(ps->thisword, ps->lthisword, b);
135 }
136