parse.c 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "../port/error.h"
  7. /*
  8. * Generous estimate of number of fields, including terminal nil pointer
  9. */
  10. static int
  11. ncmdfield(char *p, int n)
  12. {
  13. int white, nwhite;
  14. char *ep;
  15. int nf;
  16. if(p == nil)
  17. return 1;
  18. nf = 0;
  19. ep = p+n;
  20. white = 1; /* first text will start field */
  21. while(p < ep){
  22. nwhite = (strchr(" \t\r\n", *p++ & 0xFF) != 0); /* UTF is irrelevant */
  23. if(white && !nwhite) /* beginning of field */
  24. nf++;
  25. white = nwhite;
  26. }
  27. return nf+1; /* +1 for nil */
  28. }
  29. /*
  30. * parse a command written to a device
  31. */
  32. Cmdbuf*
  33. parsecmd(char *p, int n)
  34. {
  35. Cmdbuf *volatile cb;
  36. int nf;
  37. char *sp;
  38. nf = ncmdfield(p, n);
  39. /* allocate Cmdbuf plus string pointers plus copy of string including \0 */
  40. sp = smalloc(sizeof(*cb) + nf * sizeof(char*) + n + 1);
  41. cb = (Cmdbuf*)sp;
  42. cb->f = (char**)(&cb[1]);
  43. cb->buf = (char*)(&cb->f[nf]);
  44. if(up!=nil && waserror()){
  45. free(cb);
  46. nexterror();
  47. }
  48. memmove(cb->buf, p, n);
  49. if(up != nil)
  50. poperror();
  51. /* dump new line and null terminate */
  52. if(n > 0 && cb->buf[n-1] == '\n')
  53. n--;
  54. cb->buf[n] = '\0';
  55. cb->nf = tokenize(cb->buf, cb->f, nf-1);
  56. cb->f[cb->nf] = nil;
  57. return cb;
  58. }
  59. /*
  60. * Reconstruct original message, for error diagnostic
  61. */
  62. void
  63. cmderror(Cmdbuf *cb, char *s)
  64. {
  65. int i;
  66. char *p, *e;
  67. p = up->genbuf;
  68. e = p+ERRMAX-10;
  69. p = seprint(p, e, "%s \"", s);
  70. for(i=0; i<cb->nf; i++){
  71. if(i > 0)
  72. p = seprint(p, e, " ");
  73. p = seprint(p, e, "%q", cb->f[i]);
  74. }
  75. strcpy(p, "\"");
  76. error(up->genbuf);
  77. }
  78. /*
  79. * Look up entry in table
  80. */
  81. Cmdtab*
  82. lookupcmd(Cmdbuf *cb, Cmdtab *ctab, int nctab)
  83. {
  84. int i;
  85. Cmdtab *ct;
  86. if(cb->nf == 0)
  87. error("empty control message");
  88. for(ct = ctab, i=0; i<nctab; i++, ct++){
  89. if(strcmp(ct->cmd, "*") !=0) /* wildcard always matches */
  90. if(strcmp(ct->cmd, cb->f[0]) != 0)
  91. continue;
  92. if(ct->narg != 0 && ct->narg != cb->nf)
  93. cmderror(cb, Ecmdargs);
  94. return ct;
  95. }
  96. cmderror(cb, "unknown control message");
  97. return nil;
  98. }