/* * Is this a horizontal whitespace character (i.e., any whitespace * character other than a newline character of some kind)? */ static int is_hspace(wchar_t ch) { /* * it's a horizontal whitespace character if it's a whitespace * character and it's not a vertical whitespace character */ return is_space(ch) && !is_vspace(ch); }
/* * Skip to the start of the next line */ static void skip_to_next_line(utf8_ptr *p, size_t *rem) { /* find the next line-ending sequence */ for ( ; *rem != 0 ; p->inc(rem)) { /* get the current character */ wchar_t ch = p->getch(); /* check to see if we've reached a newline yet */ if (is_vspace(ch)) { /* skip the entire newline sequence */ skip_newline(p, rem); /* we're done looking for the end of the line */ break; } } }
/* The stored comment includes the comment start and any terminator. */ static void save_comment (cpp_reader *pfile, cpp_token *token, const unsigned char *from, cppchar_t type) { unsigned char *buffer; unsigned int len, clen; len = pfile->buffer->cur - from + 1; /* + 1 for the initial '/'. */ /* C++ comments probably (not definitely) have moved past a new line, which we don't want to save in the comment. */ if (is_vspace (pfile->buffer->cur[-1])) len--; /* If we are currently in a directive, then we need to store all C++ comments as C comments internally, and so we need to allocate a little extra space in that case. Note that the only time we encounter a directive here is when we are saving comments in a "#define". */ clen = (pfile->state.in_directive && type == '/') ? len + 2 : len; buffer = _cpp_unaligned_alloc (pfile, clen); token->type = CPP_COMMENT; token->val.str.len = clen; token->val.str.text = buffer; buffer[0] = '/'; memcpy (buffer + 1, from, len - 1); /* Finish conversion to a C comment, if necessary. */ if (pfile->state.in_directive && type == '/') { buffer[1] = '*'; buffer[clen - 2] = '*'; buffer[clen - 1] = '/'; } }
/* * Parse a file */ int CTadsGameInfo::parse_file(osfildef *fp, unsigned long res_seek_pos, unsigned long res_size) { /* find the tail of the existing list */ tads_valinfo *last_val; for (last_val = first_val_ ; last_val != 0 && last_val->nxt != 0 ; last_val = last_val->nxt) ; /* we found the resource - seek to it in the file */ if (osfseek(fp, res_seek_pos, OSFSK_SET)) return FALSE; /* * Allocate a block of memory for loading the game information. The * game information resource is typically fairly small, so for * simplicity we'll just allocate a single block of memory and load * the whole resource into the block. Allocate space for one extra * byte, so that we can ensure we have a newline at the end of the * buffer. */ buf_ = (char *)osmalloc(res_size + 1); if (buf_ == 0) return FALSE; /* read the data */ if (osfrb(fp, buf_, res_size)) return FALSE; /* * store an extra newline at the end of the buffer, so that we can be * certain that the last line ends in a newline - at worst, this will * add an extra blank line to the end, but since we ignore blank lines * this will do no harm */ buf_[res_size++] = '\n'; /* parse the data */ utf8_ptr p(buf_); for (size_t rem = res_size ; rem != 0 ; ) { /* skip any leading whitespace */ while (rem != 0 && is_space(p.getch())) p.inc(&rem); /* if the line starts with '#', it's a comment, so skip it */ if (rem != 0 && p.getch() == '#') { /* skip the entire line, and go back for the next one */ skip_to_next_line(&p, &rem); continue; } /* we must have the start of a name - note it */ utf8_ptr name_start = p; /* skip ahead to a space or colon */ while (rem != 0 && p.getch() != ':' && !is_hspace(p.getch())) p.inc(&rem); /* note the length of the name */ size_t name_len = p.getptr() - name_start.getptr(); /* skip any whitespace before the presumed colon */ while (rem != 0 && is_hspace(p.getch())) p.inc(&rem); /* if we're not at a colon, the line is ill-formed, so skip it */ if (rem == 0 || p.getch() != ':') { /* skip the entire line, and go back for the next one */ skip_to_next_line(&p, &rem); continue; } /* skip the colon and any whitespace immediately after it */ for (p.inc(&rem) ; rem != 0 && is_hspace(p.getch()) ; p.inc(&rem)) ; /* * Whatever terminated the name, replace it with a null character * - this is safe, since we at least have a colon character to * replace, and we've already skipped it so we can overwrite it * now. A null character in utf-8 is simply a single zero byte, * so we can store our byte directly without worrying about any * utf-8 multi-byte strangeness. */ *(name_start.getptr() + name_len) = '\0'; /* note where the value starts */ utf8_ptr val_start = p; /* set up to write to the buffer at the current point */ utf8_ptr dst = p; /* * Now find the end of the value. The value can span multiple * lines; if we find a newline followed by a space, it means that * the next line is a continuation of the current value, and that * the entire sequence of newlines and immediately following * whitespace should be converted to a single space in the value. * * Note that we copy the transformed value directly over the old * version of the value in the buffer. This is safe because the * transformation can only remove characters - we merely collapse * each newline-whitespace sequence into a single space. */ while (rem != 0) { /* get this character */ wchar_t ch = p.getch(); /* check for a newline */ if (is_vspace(ch)) { /* * it's a newline - skip it (and any other characters in * the newline sequence) */ skip_newline(&p, &rem); /* * if there's no leading whitespace on the next line, * we've reached the end of this value */ if (rem == 0 || !is_hspace(p.getch())) { /* * no whitespace -> end of the value - stop scanning * the value */ break; } /* skip leading whitespace on the line */ while (rem != 0 && is_hspace(p.getch())) p.inc(&rem); /* * add a single whitespace character to the output for the * entire sequence of the newline plus the leading * whitespace on the line */ dst.setch(' '); } else if (ch == 0) { /* change null bytes to spaces */ dst.setch(' '); /* skip this character */ p.inc(&rem); } else { /* it's not a newline - simply copy it out and keep going */ dst.setch(ch); /* skip this character */ p.inc(&rem); } } /* * Store a null terminator at the end of the value (it's safe to * write this to the buffer because at worst it'll overwrite the * newline at the end of the last line, which we've already * skipped in the source). Note that we obtain the length of the * value string before storing the null terminator, because we * don't want to count the null byte in the value's length. */ dst.setch('\0'); /* * Create a new value list entry. Point the entry directly into * our buffer, since we're keeping the buffer around as long as * the value list is around. */ tads_valinfo *val_info = (tads_valinfo *)osmalloc(sizeof(tads_valinfo)); val_info->name = name_start.getptr(); val_info->name_len = name_len; val_info->val = store_value(val_start.getptr(), dst.getptr() - val_start.getptr()); val_info->nxt = 0; /* link the new value at the end of our list */ if (last_val != 0) last_val->nxt = val_info; else first_val_ = val_info; last_val = val_info; } /* success */ return TRUE; }