/* parse user command line */ static void parseargs(char *argstr, int *argc_p, char **argv, char** resid) { char c; argc = 0; /* tokenize the argstr */ last_state = PS_WHITESPACE; while ((c = *argstr) != 0) { if (c == ';' && last_state != PS_STRING && last_state != PS_ESCAPE) break; if (last_state == PS_ESCAPE) { new_state = stacked_state; } else if (last_state == PS_STRING) { if (c == '"') { new_state = PS_WHITESPACE; *argstr = 0; } else { new_state = PS_STRING; } } else if ((c == ' ') || (c == '\t')) { /* whitespace character */ *argstr = 0; new_state = PS_WHITESPACE; } else if (c == '"') { new_state = PS_STRING; *argstr++ = 0; argv[argc++] = argstr; } else if (c == '\\') { stacked_state = last_state; new_state = PS_ESCAPE; } else { /* token */ if (last_state == PS_WHITESPACE) { argv[argc++] = argstr; } new_state = PS_TOKEN; } last_state = new_state; argstr++; } #if 0 /* for debugging */ { int i; putLabeledWord("parseargs: argc=", argc); for (i = 0; i < argc; i++) { puts(" "); puts(argv[i]); puts("\r\n"); } } #endif argv[argc] = NULL; if (argc_p != NULL) *argc_p = argc; if (*argstr == ';') { *argstr++ = '\0'; } *resid = argstr; }
/* Returns the length of the file received, or 0 on error: */ int ymodem_receive(char *buf, unsigned int length) { unsigned char packet_data[PACKET_1K_SIZE + PACKET_OVERHEAD]; int packet_length, i, file_done, session_done, crc_tries, crc_nak, use_crc; unsigned int packets_received, errors, timeout, first_try = 1; char file_name[FILE_NAME_LENGTH], file_size[FILE_SIZE_LENGTH], *file_ptr; char *buf_ptr; unsigned long size = 0; #ifdef CONFIG_MD5 unsigned int sum[MD5_SUM_WORDS]; #endif if(crc16_init() < 0){ putstr("Unable to generate CRC16 lookup table\r\n"); return 0; } putstr("ready for YMODEM transfer...\r\n"); /* Give the user time to frantically type in the file name: */ timeout = INITIAL_TIMEOUT; for(session_done = 0, errors = 0; ; ){ crc_tries = crc_nak = use_crc = 1; if(!first_try) putc(CRC); first_try = 0; for(packets_received = 0, file_done = 0, buf_ptr = buf; ; ){ switch(receive_packet(packet_data, &packet_length, use_crc, timeout)){ case 0: errors = 0; switch(packet_length){ case -1: /* abort */ putc(ACK); return 0; case 0: /* end of transmission */ putc(ACK); /* Should add some sort of sanity check on the number of * packets received and the advertised file length. */ file_done = 1; break; default: /* normal packet */ if((packet_data[PACKET_SEQNO_INDEX] & 0xff) != (packets_received & 0xff)){ putc(NAK); } else { if(packets_received == 0){ /* The spec suggests that the whole data section should * be zeroed, but I don't think all senders do this. If * we have a NULL filename and the first few digits of * the file length are zero, we'll call it empty. */ for(i = PACKET_HEADER; i < PACKET_HEADER + 4; ++i) if(packet_data[i] != 0) break; if(i < PACKET_HEADER + 4){ /* filename packet has data */ for(file_ptr = packet_data + PACKET_HEADER, i = 0; *file_ptr && i < FILE_NAME_LENGTH;) file_name[i++] = *file_ptr++; file_name[i++] = '\0'; for(++file_ptr, i = 0; *file_ptr != ' ' && i < FILE_SIZE_LENGTH;) file_size[i++] = *file_ptr++; file_size[i++] = '\0'; size = strtoul(file_size, NULL, 0); if(size > length){ putc(CAN); putc(CAN); delay_seconds(3); putstr("Receive buffer too small ("); putHexInt32(length); putLabeledWord(") to accept file size ", size); return 0; } putc(ACK); putc(crc_nak ? CRC : NAK); crc_nak = 0; } else { /* filename packet is empty; end session */ putc(ACK); file_done = 1; session_done = 1; break; } } else { /* This shouldn't happen, but we check anyway in case the * sender lied in its filename packet: */ if((buf_ptr + packet_length) - buf > length){ putc(CAN); putc(CAN); delay_seconds(3); putLabeledWord("Sender exceeded size of receive buffer: ", length); return 0; } memcpy(buf_ptr, packet_data + PACKET_HEADER, packet_length); buf_ptr += packet_length; putc(ACK); } ++packets_received; } /* sequence number ok */ } break; default: if(++errors >= ((packets_received == 0 ? MAX_CRC_TRIES : 0) + MAX_ERRORS)){ putc(CAN); putc(CAN); delay_seconds(1); putstr("Too many errors during receive; giving up.\r\n"); return 0; } if(packets_received == 0){ if(crc_tries < MAX_CRC_TRIES) { ++crc_tries; timeout = CRC_TIMEOUT; } else { crc_nak = use_crc = 0; timeout = NAK_TIMEOUT; } } putc(crc_nak ? CRC : NAK); } if(file_done) break; } /* receive packets */ if(session_done) break; } /* receive files */ #ifdef CONFIG_MD5 /* Give sender time to exit so that the subsequent MD5 display will be * visible on the user's terminal: */ delay_seconds(1); md5_sum(buf, size, sum); md5_display(sum); putstr(" "); putstr(file_name); putstr("\r\n"); #endif return size; }