home *** CD-ROM | disk | FTP | other *** search
/ Da Capo / da_capo_vol1.bin / programs / amiga / midi / midi_playground / sourcecode / text.c < prev    next >
C/C++ Source or Header  |  1993-01-23  |  10KB  |  391 lines

  1. /**************************************************************************
  2. * text.c:    Functions for text input/output.
  3. *        Part of MP, the MIDI Playground.
  4. *
  5. * Author:    Daniel Barrett
  6. * Version:    See the file "version.h".
  7. * Copyright:    None!  This program is in the Public Domain.
  8. *        Please share it with others.
  9. ***************************************************************************/
  10.  
  11.     
  12. #include "mp.h"
  13.  
  14.  
  15. /* Given the currently read character and the current state, compute
  16.  * the new state and the MIDI value. */
  17.     
  18. STATE_T NewState(int c, STATE_T state, MIDI_VALUE *answer)
  19. {
  20.     static BOOL inString = FALSE;
  21.  
  22.     if (inString)
  23.         return(DoInString(c, state, answer, &inString));
  24.     else if (c == HELP_SYMBOL)
  25.     {
  26.         InputHelp();
  27.         return(state);
  28.     }
  29.     else if (state == STATE_NORMAL && c == '\"')
  30.     {
  31.         inString = TRUE;
  32.         return(STATE_NORMAL);    /* Doesn't matter. */
  33.     }
  34.     else
  35.         return(NonStringState(c, state, answer));
  36. }
  37.  
  38. /****************************************************************************
  39. * Our finite automaton for non-strings.  Process the character and return
  40. * the new state.
  41. ****************************************************************************/
  42.     
  43. STATE_T NonStringState(int c, STATE_T state, MIDI_VALUE *answer)
  44. {
  45.     switch (state)
  46.     {
  47.         case STATE_NORMAL:    return(DoNormal(c, answer));
  48.         case STATE_INCOMMENT:    return(DoComment(c));
  49.         case STATE_INDECIMAL:    return(DoDecimal(c, answer));
  50.         case STATE_INOCTAL:    return(DoOctal(c, answer));
  51.         case STATE_STARTHEX:    return(DoHex(c, answer));
  52.         case STATE_INHEX:    return(DoInHex(c, answer));
  53.         case STATE_LEADZERO:    return(DoLeadZero(c, answer));
  54.         case STATE_INCHAR:    return(DoInChar(c, answer));
  55.         case STATE_STARTBINARY:    return(DoBinary(c, answer));
  56.         case STATE_INBINARY:    return(DoInBinary(c, answer));
  57.         case STATE_EXPECTQUOTE:    return(DoExpectQuote(c, answer));
  58.         case STATE_BACKSLASHINCHAR:
  59.             return(DoBackslash(c, answer, STATE_EXPECTQUOTE));
  60.         case STATE_SUCCESS:    
  61.         case STATE_OVERFLOW:    
  62.         case STATE_ERROR:    return(state);
  63.     }
  64. }
  65.  
  66.  
  67. /****************************************************************************
  68. * We are not currently in a number.  A character is read; decide what to
  69. * do with it.
  70. ****************************************************************************/
  71.     
  72. STATE_T DoNormal(int c, MIDI_VALUE *answer)
  73. {
  74.     if (isspace(c))
  75.         return(STATE_NORMAL);
  76.     else if (c == START_COMMENT)
  77.         return(STATE_INCOMMENT);
  78.     else if (c == START_BINARY)
  79.         return(STATE_STARTBINARY);
  80.     else if (c == '\'')
  81.         return(STATE_INCHAR);
  82.     else if (c == '0')
  83.         return(STATE_LEADZERO);
  84.     else if (toupper(c) == 'H')
  85.         return(STATE_STARTHEX);
  86.     else if (isdigit(c))
  87.     {
  88.         *answer = D_TO_INT(c);
  89.         return(STATE_INDECIMAL);
  90.     }
  91.     else if (isxdigit(c))
  92.     {
  93.         *answer = H_TO_INT(c);
  94.         return(STATE_INHEX);
  95.     }
  96.     else
  97.         return(STATE_ERROR);
  98. }
  99.  
  100.     
  101. /****************************************************************************
  102. * Base 10 (decimal) numbers.
  103. ****************************************************************************/
  104.     
  105. STATE_T DoDecimal(int c, MIDI_VALUE *answer)
  106. {
  107.     if (isdigit(c))
  108.         return(IncreaseIfPossible(answer, D_TO_INT(c), 10, 
  109.             STATE_INDECIMAL));
  110.     else if (isspace(c))
  111.         return(STATE_SUCCESS);
  112.     else
  113.         return(STATE_ERROR);
  114. }
  115.  
  116.     
  117. /****************************************************************************
  118. * Octal numbers.
  119. ****************************************************************************/
  120.     
  121. STATE_T DoOctal(int c, MIDI_VALUE *answer)
  122. {
  123.     if (isoctal(c))
  124.         return(IncreaseIfPossible(answer, D_TO_INT(c), 8, 
  125.             STATE_INOCTAL));
  126.     else if (isspace(c))
  127.         return(STATE_SUCCESS);
  128.     else
  129.         return(STATE_ERROR);
  130. }
  131.  
  132.  
  133. /****************************************************************************
  134. * Hexadecimal numbers.
  135. ****************************************************************************/
  136.     
  137. STATE_T DoHex(int c, MIDI_VALUE *answer)
  138. {
  139.     if (isxdigit(c))
  140.     {
  141.         *answer = H_TO_INT(c);
  142.         return(STATE_INHEX);
  143.     }
  144.     else
  145.         return(STATE_ERROR);
  146. }
  147.  
  148.  
  149. STATE_T DoInHex(int c, MIDI_VALUE *answer)
  150. {
  151.     if (isxdigit(c))
  152.         return(IncreaseIfPossible(answer, H_TO_INT(c), 16, 
  153.             STATE_INHEX));
  154.     else if (isspace(c))
  155.         return(STATE_SUCCESS);
  156.     else
  157.         return(STATE_ERROR);
  158. }
  159.  
  160.  
  161. /****************************************************************************
  162. * Binary numbers.
  163. ****************************************************************************/
  164.     
  165. STATE_T DoBinary(int c, MIDI_VALUE *answer)
  166. {
  167.     if ((c == '0') || (c == '1'))
  168.     {
  169.             *answer = D_TO_INT(c);
  170.         return(STATE_INBINARY);
  171.     }
  172.     else
  173.         return(STATE_ERROR);
  174. }
  175.  
  176.     
  177. STATE_T DoInBinary(int c, MIDI_VALUE *answer)
  178. {
  179.     if ((c == '0') || (c == '1'))
  180.         return(IncreaseIfPossible(answer, D_TO_INT(c), 2, 
  181.             STATE_INBINARY));
  182.     else if (isspace(c))
  183.         return(STATE_SUCCESS);
  184.     else
  185.         return(STATE_ERROR);
  186. }
  187.  
  188.     
  189. /****************************************************************************
  190. * Hook for negative numbers.  Commented out right now.
  191. ****************************************************************************/
  192.     
  193. #ifdef ALLOW_NEGATIVE
  194. STATE_T DoNegative(int c, MIDI_VALUE *answer)
  195. {
  196.     if (c == '0')
  197.         return(STATE_LEADZERO);
  198.     else if (isdigit(c))
  199.     {
  200.         return(STATE_INDECIMAL);
  201.     }
  202.     else
  203.         return(STATE_ERROR);
  204. }
  205. #endif /* ALLOW_NEGATIVE */
  206.  
  207.     
  208. /****************************************************************************
  209. * Leading zero was found:  Do octal or hexadecimal as required.
  210. ****************************************************************************/
  211.     
  212. STATE_T DoLeadZero(int c, MIDI_VALUE *answer)
  213. {
  214.     if (toupper(c) == 'X')
  215.         return(STATE_STARTHEX);
  216.     else if (isoctal(c))
  217.     {
  218.         *answer = D_TO_INT(c);
  219.         return(STATE_INOCTAL);
  220.     }
  221.     else if (isspace(c))
  222.         return(STATE_SUCCESS);
  223.     else
  224.         return(STATE_ERROR);
  225. }
  226.  
  227.     
  228. /****************************************************************************
  229. * Append the digit "newNum" onto the right of the number *answer.
  230. * Don't allow overflow.  Works for any base.  Return newState on success.
  231. ****************************************************************************/
  232.     
  233. STATE_T IncreaseIfPossible(MIDI_VALUE *answer, int newNum, int base,
  234.                STATE_T newState)
  235. {
  236.     if ((*answer) > (LARGEST_VALUE / base))
  237.         return(STATE_OVERFLOW);
  238.     else
  239.     {
  240.         *answer *= base;
  241.  
  242.         if ((*answer) > (LARGEST_VALUE - newNum))
  243.             return(STATE_OVERFLOW);
  244.         else
  245.         {
  246.             *answer += newNum;
  247.             return(newState);
  248.         }
  249.     }
  250. }
  251.  
  252.  
  253. /****************************************************************************
  254. * Character-oriented routines.
  255. ****************************************************************************/
  256.     
  257. STATE_T DoInChar(int c, MIDI_VALUE *answer)
  258. {
  259.     if (c == '\\')
  260.         return(STATE_BACKSLASHINCHAR);
  261.     else
  262.     {
  263.         *answer = c;
  264.         return(STATE_EXPECTQUOTE);
  265.     }
  266. }
  267.  
  268.     
  269. STATE_T DoExpectQuote(int c, MIDI_VALUE *answer)
  270. {
  271.     return((c == '\'') ? STATE_SUCCESS : STATE_ERROR);
  272. }
  273.  
  274.  
  275. STATE_T DoBackslash(int c, MIDI_VALUE *answer, STATE_T newState)
  276. {
  277.     switch (c)
  278.     {
  279.         case '0':    *answer = '\0';        break;
  280.         case 'a':    *answer = '\a';        break;
  281.         case 'b':    *answer = '\b';        break;
  282.             case 'f':    *answer = '\f';        break;
  283.         case 'n':    *answer = '\n';        break;
  284.         case 'r':    *answer = '\r';        break;
  285.         case 't':    *answer = '\t';        break;
  286.         case 'v':    *answer = '\v';        break;
  287.         case '\\':
  288.         case '\'':
  289.         case '\"':    *answer = c;        break;
  290.         default:    return(STATE_ERROR);
  291.     }
  292.     return(newState);
  293. }
  294.  
  295.  
  296. /****************************************************************************
  297. * String-oriented routines.
  298. ****************************************************************************/
  299.     
  300. STATE_T DoInString(int c, STATE_T state, MIDI_VALUE *answer, BOOL *inString)
  301. {
  302.     switch (state)
  303.     {
  304.         case STATE_NORMAL:
  305.             if (c == '\"')
  306.             {
  307.                 *inString = FALSE;
  308.                     return(STATE_NORMAL);
  309.             }
  310.             else if (c == '\\')
  311.                 return(STATE_BACKSLASHINSTRING);
  312.             else
  313.             {
  314.                 *answer = isspace(c) ? ' ' : c;
  315.                 return(STATE_SUCCESS);
  316.             }
  317.             break;
  318.         case STATE_BACKSLASHINSTRING:
  319.             return(DoBackslash(c, answer, STATE_SUCCESS));
  320.     }
  321. }
  322.  
  323.  
  324. /****************************************************************************
  325. * Handling comments.  Everything from comment symbol to the end of the
  326. * line is a comment.
  327. ****************************************************************************/
  328.  
  329. STATE_T DoComment(int c)
  330. {
  331.     return( (c == '\n') ? STATE_NORMAL : STATE_INCOMMENT );
  332. }
  333.     
  334. /****************************************