예제 #1
0
/*
 * Get the next line.
 * A "current" position is passed and a "new" position is returned.
 * The current position is the position of the first character of
 * a line.  The new position is the position of the first character
 * of the NEXT line.  The line obtained is the line starting at curr_pos.
 */
off_t
forw_line(off_t curr_pos)
{
	off_t new_pos;
	int c;

	if (curr_pos == NULL_POSITION || ch_seek(curr_pos))
		return (NULL_POSITION);

	c = ch_forw_get();
	if (c == EOI)
		return (NULL_POSITION);

	prewind();
	for (;;) {
		if (sigs)
			return (NULL_POSITION);
		if (c == '\n' || c == EOI) {
			/*
			 * End of the line.
			 */
			new_pos = ch_tell();
			break;
		}

		/*
		 * Append the char to the line and get the next char.
		 */
		if (pappend(c)) {
			/*
			 * The char won't fit in the line; the line
			 * is too long to print in the screen width.
			 * End the line here.
			 */
			new_pos = ch_tell() - 1;
			break;
		}
		c = ch_forw_get();
	}
	(void) pappend('\0');

	if (squeeze && *line == '\0') {
		/*
		 * This line is blank.
		 * Skip down to the last contiguous blank line
		 * and pretend it is the one which we are returning.
		 */
		while ((c = ch_forw_get()) == '\n')
			if (sigs)
				return (NULL_POSITION);
		if (c != EOI)
			(void) ch_back_get();
		new_pos = ch_tell();
	}

	return (new_pos);
}
예제 #2
0
/*
 * Get the previous line.
 * A "current" position is passed and a "new" position is returned.
 * The current position is the position of the first character of
 * a line.  The new position is the position of the first character
 * of the PREVIOUS line.  The line obtained is the one starting at new_pos.
 */
off_t
back_line(off_t curr_pos)
{
	off_t new_pos, begin_new_pos;
	int c;

	if (curr_pos == NULL_POSITION || curr_pos <= (off_t)0 ||
		ch_seek(curr_pos-1))
		return (NULL_POSITION);

	if (squeeze) {
		/*
		 * Find out if the "current" line was blank.
		 */
		(void) ch_forw_get();	/* Skip the newline */
		c = ch_forw_get();	/* First char of "current" line */
		(void) ch_back_get();	/* Restore our position */
		(void) ch_back_get();

		if (c == '\n') {
			/*
			 * The "current" line was blank.
			 * Skip over any preceeding blank lines,
			 * since we skipped them in forw_line().
			 */
			while ((c = ch_back_get()) == '\n')
				if (sigs)
					return (NULL_POSITION);
			if (c == EOI)
				return (NULL_POSITION);
			(void) ch_forw_get();
		}
	}

	/*
	 * Scan backwards until we hit the beginning of the line.
	 */
	for (;;) {
		if (sigs)
			return (NULL_POSITION);
		c = ch_back_get();
		if (c == '\n') {
			/*
			 * This is the newline ending the previous line.
			 * We have hit the beginning of the line.
			 */
			new_pos = ch_tell() + 1;
			break;
		}

		if (c == EOI) {
			/*
			 * We have hit the beginning of the file.
			 * This must be the first line in the file.
			 * This must, of course, be the beginning of the line.
			 */
			new_pos = ch_tell();
			break;
		}
	}

	/*
	 * Now scan forwards from the beginning of this line.
	 * We keep discarding "printable lines" (based on screen width)
	 * until we reach the curr_pos.
	 *
	 * {{ This algorithm is pretty inefficient if the lines
	 *    are much longer than the screen width, 
	 *    but I don't know of any better way. }}
	 */
	if (ch_seek(new_pos))
		return (NULL_POSITION);
    loop:
	begin_new_pos = new_pos;
	prewind();

	do {
		c = ch_forw_get();
		if (c == EOI || sigs)
			return (NULL_POSITION);
		new_pos++;
		if (c == '\n')
			break;
		if (pappend(c)) {
			/*
			 * Got a full printable line, but we haven't
			 * reached our curr_pos yet.  Discard the line
			 * and start a new one.
			 */
			(void) pappend('\0');
			(void) ch_back_get();
			new_pos--;
			goto loop;
		}
	} while (new_pos < curr_pos);

	(void) pappend('\0');

	return (begin_new_pos);
}
예제 #3
0
swexp_list_node *parse_block(parser *p) {
  // parses a block of lines with the same indentation into a chain
  // (not a list)
  char c;

  swexp_list_node fakehead, *tail;
  fakehead.next = NULL;
  fakehead.content = NULL;
  fakehead.type = UNDEFINED;
  tail = &fakehead;

  // get initial indentation by consuming characters until we find some
  unsigned int current_indentation;
  for (current_indentation = p->indentation; is_space(pgetc(p));
       current_indentation++) {
  }
  prewind(p, '\0');

  while ((c = pgetc(p)) != EOF) {
    // if we encounter a comment in any state, strip it out
    IGNORE_COMMENTS()

    switch (p->state) {
    case COUNTING_INDENTATION:
      if (is_space(c)) {
        p->indentation++;
      } else if (is_newline(c)) {
        p->indentation = 0;
      } else {
        // this is a start of an atom.
        // parse as appropriate based on indent
        prewind(p, c);
        if (p->indentation > current_indentation) {
          if (tail->type == ATOM) {
            // make the tail a list before appending
            swexp_list_node *tailcont = malloc(sizeof(swexp_list_node));
            tailcont->type = ATOM;
            tailcont->next = NULL;
            tailcont->content = tail->content;
            tailcont->location = NULL;

            tail->type = LIST;
            tail->content = tailcont;
            if (tail->location != NULL) {
              free(tail->location);
              tail->location = NULL;
            }
          }
          // append it to the list that is the last
          // element
          list_tail(tail)->next = parse_block(p);
        } else if (p->indentation == current_indentation) {
          tail->next = parse_line(p);
          p->state = COUNTING_INDENTATION;
          tail = tail->next;
        } else {
          goto clean_and_return;
        }
      }
      break;
    default:
      printf("unexpected state in parse_line\n");
      exit(1);
    }
  }

clean_and_return:
  return fakehead.next;
}
예제 #4
0
swexp_list_node *parse_s_expr(parser *p, char opening_brace) {
  char c;

  swexp_list_node fakehead, *tail = &fakehead;
  fakehead.next = NULL;
  fakehead.content = NULL;
  fakehead.type = UNDEFINED;

  char closing_brace = brace_pair(opening_brace);

  while ((c = pgetc(p)) != EOF && !is_closing_brace(c)) {
    // if we encounter a comment in any state, strip it out
    IGNORE_COMMENTS()

    switch (p->state) {
    case SKIP_SPACE:
      if (is_space(c) || is_newline(c)) {
        // do nothing if it is space or newline
      } else if (is_opening_brace(c)) {
        // parse the parenthesized s expression into a list
        // and append it to the thing
        swexp_list_node *list = malloc(sizeof(swexp_list_node));
        list->type = LIST;
        list->next = NULL;
        list->location = NULL;
        list->content = parse_s_expr(p, c);

        tail->next = list;
        tail = list;
      } else {
        // step back and start collecting the atom
        prewind(p, c);
        begin_atom(p);
      }
      break;
    case COLLECTING_ATOM:
      if (is_space(c) || is_newline(c)) {
        prewind(p, c);
        tail->next = close_atom(p);
        tail = tail->next;
      } else if (is_opening_brace(c)) {
        swexp_list_node *node = close_atom(p);
        node->next = parse_s_expr(p, c);
        tail->next = listof(node);
        tail = chain_tail(tail);
      } else {
        build_atom(p, c);
      }
      break;
    default:
      printf("unexpected state %d in parse_s_expr", p->state);
      exit(1);
    }
  }

  if (is_closing_brace(c) && c != closing_brace) {
    printf("mismatched braces in s expression\n");
    exit(1);
  }

  if (p->state == COLLECTING_ATOM) {
    tail->next = close_atom(p);
  }

  if (c == EOF) {
    printf("unexpected EOF while parsing s expression\n");
    exit(1);
  }

  p->state = SKIP_SPACE;

  return fakehead.next;
}
예제 #5
0
swexp_list_node *parse_line(parser *p) {
  // parses a line of text, starting at a non-whitespace char
  char c;

  // build a list of expressions started by this
  // list head on the stack.
  swexp_list_node head, *tail;
  head.next = NULL;
  head.content = NULL;
  head.type = UNDEFINED;
  tail = &head;

  p->state = SKIP_SPACE;

  while ((c = pgetc(p)) != EOF && !is_newline(c) && !is_closing_brace(c)) {
    // if we encounter a comment in any state, strip it out
    IGNORE_COMMENTS()

    switch (p->state) {
    case COLLECTING_ATOM:
      if (is_space(c)) {
        // end atom
        tail->next = close_atom(p);
        tail = tail->next;
        prewind(p, c);
      } else if (is_opening_brace(c)) {
        swexp_list_node *bracehead = close_atom(p);
        swexp_list_node *bracecontent = parse_s_expr(p, c);
        bracehead->next = bracecontent;
        tail->next = listof(bracehead);
        tail = chain_tail(tail);
      } else {
        // continue to build item
        build_atom(p, c);
      }
      break;
    case SKIP_SPACE:
      if (is_opening_brace(c)) {
        swexp_list_node *brace = parse_s_expr(p, c);
        tail->next = brace;
        tail = chain_tail(tail);
      } else if (!is_space(c)) {
        begin_atom(p);
        prewind(p, c);
      }
      break;
    default:
      printf("unexpected state %d in parse_line\n", p->state);
      exit(1);
    }
  }

  if (is_newline(c)) {
    p->indentation = 0;
  }
  if (is_closing_brace(c)) {
    printf("encountered unmatched closing brace\n");
    exit(1);
  }

  // close ongoing capture
  if (p->state == COLLECTING_ATOM) {
    tail->next = close_atom(p);
  }

  // if the number of collected atoms is more than one,
  // make it a list and return it
  if (chain_len(head.next) > 1) {
    swexp_list_node *listhead = malloc(sizeof(swexp_list_node));
    listhead->type = LIST;
    listhead->next = NULL;
    listhead->content = head.next;
    listhead->location = NULL;
    return listhead;
  } else {
    return head.next;
  }
}