/* drops the last component of the path, leaving only the directory */ char * directory_path (char *s) { char *t, *tail = NULL; char path[MAXPATHLEN]; for (t = s; *t; t++) { if (*t == '/') tail = t; } if (tail == NULL) { return NULL; } else { return substring_copy (s, 0, tail-s); } }
static void _doc_process_tag(doc_ptr doc, doc_tag_ptr tag) { if ( tag->type == DOC_TAG_CLOSE_COLOR || tag->type == DOC_TAG_CLOSE_STYLE || tag->type == DOC_TAG_CLOSE_INDENT ) { doc_pop_style(doc); } else if (tag->type == DOC_TAG_COLOR) { assert(tag->arg); if (tag->arg_size == 1) { if (tag->arg[0] == '*') doc_pop_style(doc); else { doc_style_t style = *doc_current_style(doc); /* copy */ switch (tag->arg[0]) { case 'd': style.color = TERM_DARK; break; case 'w': style.color = TERM_WHITE; break; case 's': style.color = TERM_SLATE; break; case 'o': style.color = TERM_ORANGE; break; case 'r': style.color = TERM_RED; break; case 'g': style.color = TERM_GREEN; break; case 'b': style.color = TERM_BLUE; break; case 'u': style.color = TERM_UMBER; break; case 'D': style.color = TERM_L_DARK; break; case 'W': style.color = TERM_L_WHITE; break; case 'v': style.color = TERM_VIOLET; break; case 'y': style.color = TERM_YELLOW; break; case 'R': style.color = TERM_L_RED; break; case 'G': style.color = TERM_L_GREEN; break; case 'B': style.color = TERM_L_BLUE; break; case 'U': style.color = TERM_L_UMBER; break; } doc_push_style(doc, &style); } } else { string_ptr arg = string_copy_sn(tag->arg, tag->arg_size); doc_style_t style = *doc_current_style(doc); /* copy */ doc_style_f f = _get_doc_style_f(doc, string_buffer(arg)); if (f) f(&style); {/* We don't copy the named style, just its color. */ /* Also, we damn well better push a style or we'll be upset when the good little user pops! */ doc_style_t copy = *doc_current_style(doc); copy.color = style.color; doc_push_style(doc, ©); } string_free(arg); } } else if (tag->type == DOC_TAG_INDENT) { doc_style_t style = *doc_current_style(doc); style.left = doc->cursor.x; doc_push_style(doc, &style); } else { string_ptr arg = string_copy_sn(tag->arg, tag->arg_size); switch (tag->type) { case DOC_TAG_STYLE: if (tag->arg_size == 1 && tag->arg[0] == '*') doc_pop_style(doc); else {/* Better silently add one if name doesn't exist ... */ doc_style_t copy = *doc_current_style(doc); doc_style_f f = _get_doc_style_f(doc, string_buffer(arg)); if (f) f(©); doc_push_style(doc, ©); } break; case DOC_TAG_VAR: _doc_process_var(doc, string_buffer(arg)); break; case DOC_TAG_TAB: { int pos = atoi(string_buffer(arg)) + doc_current_style(doc)->left; if (pos > doc->cursor.x) doc_insert_space(doc, pos - doc->cursor.x); else doc_rollback(doc, doc_pos_create(pos, doc->cursor.y)); break; } case DOC_TAG_TOPIC: { doc_bookmark_ptr mark = malloc(sizeof(doc_bookmark_t)); mark->name = arg; /* steal ownership */ arg = NULL; mark->pos = doc->cursor; vec_add(doc->bookmarks, mark); break; } case DOC_TAG_LINK: { doc_link_ptr link = malloc(sizeof(doc_link_t)); int split = string_chr(arg, 0, '#'); int ch = 'a' + int_map_count(doc->links); if (split >= 0) { substring_t left = string_left(arg, split); substring_t right = string_right(arg, string_length(arg) - split - 1); link->file = substring_copy(&left); link->topic = substring_copy(&right); } else { link->file = arg; /* steal ownership */ arg = NULL; link->topic = NULL; } link->location.start = doc->cursor; int_map_add(doc->links, ch, link); { /* TODO: This is flawed. Here's a real world example: "(see below <link:birth.txt#PrimaryStats>)." Can you see the problem? We might line break after "[a]" right before ").". Instead, "[a])." should be treated as the current word. To fix this, we'll need a parser with a token queue that we can push onto, but this raises storage issues. */ string_ptr s = string_alloc_format("<style:link>[%c]</style>", ch); doc_insert(doc, string_buffer(s)); string_free(s); link->location.stop = doc->cursor; } break; } } string_free(arg); } }