/* ** ydom_new() ** Create a new XML DOM object. */ ydom_t *ydom_new() { ydom_t *dom; ydom_node_t *node; YLOG_MOD("ydom", YLOG_DEBUG, "Entering"); if (!(dom = malloc0(sizeof(ydom_t)))) { YLOG_ADD(YLOG_ERR, "Unable to allocate memory"); return (NULL); } if (!(node = malloc0(sizeof(ydom_node_t)))) { free0(dom); YLOG_ADD(YLOG_ERR, "Unable to allocate memory"); return (NULL); } node->node_type = DOCUMENT_NODE; node->complete = YTRUE; node->name = NULL; dom->error = YENOERR; dom->document_element = dom->current_parsed_node = node; YLOG_MOD("ydom", YLOG_DEBUG, "Exiting"); return (dom); }
// send one element of list static yerr_t _command_list_loop(void *ptr, ybin_t key, ybin_t data) { tcp_thread_t *thread = (tcp_thread_t*)ptr; uint16_t length16; struct iovec iov[2]; struct msghdr mh; ssize_t expected, rc; YLOG_ADD(YLOG_DEBUG, "list element: '%s'.", (char*)key.data); mh.msg_name = NULL; mh.msg_namelen = 0; mh.msg_iov = iov; mh.msg_iovlen = 2; mh.msg_control = NULL; mh.msg_controllen = 0; mh.msg_flags = 0; length16 = htons((uint16_t)key.len); iov[0].iov_base = (caddr_t)&length16; iov[0].iov_len = sizeof(uint16_t); iov[1].iov_base = (caddr_t)key.data; iov[1].iov_len = key.len; expected = iov[0].iov_len + iov[1].iov_len; rc = sendmsg(thread->fd, &mh, 0); if (rc < 0) { YLOG_ADD(YLOG_WARN, "Unable to send response."); return (YEIO); } else if (rc < expected) { YLOG_ADD(YLOG_WARN, "Unable to send the complete response (%d / %d).", rc, expected); return (YEIO); } return (YENOERR); }
/* ** ydom_read_file() ** Parse an existing XML file. */ yerr_t ydom_read_file(ydom_t *dom, const char *filename) { ysax_t *sax; YLOG_MOD("ydom", YLOG_DEBUG, "Entering"); if (!dom) { YLOG_ADD(YLOG_WARN, "NULL dom pointer"); return (YENOERR); } if ((sax = ysax_new(dom)) == NULL) { YLOG_ADD(YLOG_ERR, "Bad SAX creation"); return (YENOENT); } ysax_set_tag_hdlr(sax, _ydom_open_hdlr, _ydom_close_hdlr); ysax_set_inside_text_hdlr(sax, _ydom_inside_hdlr); ysax_set_comment_hdlr(sax, _ydom_comment_hdlr); ysax_set_process_instr_hdlr(sax, _ydom_process_instr_hdlr); ysax_set_cdata_hdlr(sax, _ydom_cdata_hdlr); dom->error = ysax_read_file(sax, filename); ysax_del(sax); YLOG_MOD("ydom", YLOG_DEBUG, "Exiting"); return (dom->error); }
/* Process a SETDB command. */ yerr_t command_setdb(tcp_thread_t *thread, ydynabin_t *buff) { unsigned char *pdbname_len, dbname_len; char *dbname = NULL; void *ptr; yerr_t result = YENOERR; YLOG_ADD(YLOG_DEBUG, "SETDB command"); // read dbname length if (connection_read_data(thread, buff, sizeof(dbname_len)) != YENOERR) goto error; pdbname_len = ydynabin_forward(buff, sizeof(dbname_len)); dbname_len = *pdbname_len; YFREE(thread->dbname); if (dbname_len > 0) { // read dbname if (connection_read_data(thread, buff, (size_t)dbname_len) != YENOERR) goto error; ptr = ydynabin_forward(buff, (size_t)dbname_len); if ((dbname = YMALLOC((size_t)dbname_len + 1)) == NULL) goto error; memcpy(dbname, ptr, (size_t)dbname_len); thread->dbname = dbname; } // send the response to the client YLOG_ADD(YLOG_DEBUG, "SETDB command OK"); CONNECTION_SEND_OK(thread); return (result); error: YLOG_ADD(YLOG_WARN, "SETDB error"); CONNECTION_SEND_ERROR(thread, RESP_ERR_SERVER); return (YEIO); }
/* ** add_inc_paths() ** Add path directories from string. */ void add_inc_paths(cg_t *carta, const char *paths) { const char *pt; ystr_t ys; if (!carta) { YLOG_ADD(YLOG_WARN, "No main structure."); return ; } if (!(ys = ys_new(""))) { YLOG_ADD(YLOG_WARN, "Memory error"); return ; } for (pt = paths; pt && *pt; ++pt) { ys_trunc(ys); while (*pt == SEMICOLON || *pt == COMMA) pt++; for (; *pt && *pt != SEMICOLON && *pt != COMMA; ++pt) ys_addc(&ys, *pt); yv_add(&carta->inc_paths, ys_string(ys)); } ys_del(&ys); }
/* ** import_font() ** Try to import a given font. */ void import_font(cg_t *carta, ydom_node_t *node) { struct stat st; cg_font_t *font; if (!(font = malloc0(sizeof(cg_font_t)))) return ; font->id = ydom_node_get_attr_value(node, "id"); font->outline = ydom_node_get_attr_value(node, "outline"); font->metrics = ydom_node_get_attr_value(node, "metrics"); if (!font->id || !font->outline || !font->metrics) { YLOG_ADD(YLOG_WARN, "Empty font declaration [line %d].", node->line_nbr); free0(font->outline); free0(font->id); free0(font); return ; } font->f = -1; if (!stat(font->outline, &st) && !stat(font->metrics, &st)) { yv_add(&carta->fonts, font); return ; } else { ystr_t ys1 = ys_new(""), ys2 = ys_new(""); int i; for (i = 0; i < yv_len(carta->font_paths); ++i) { ys_printf(&ys1, "%s%c%s", carta->font_paths[i], CARTA_SEP, font->outline); ys_printf(&ys2, "%s%c%s", carta->font_paths[i], CARTA_SEP, font->metrics); if (!stat(ys1, &st) && !stat(ys2, &st)) { free0(font->outline); free0(font->metrics); font->outline = ys_string(ys1); font->metrics = ys_string(ys2); yv_add(&carta->fonts, font); ys_del(&ys1); ys_del(&ys2); return ; } } ys_del(&ys1); ys_del(&ys2); } YLOG_ADD(YLOG_WARN, "Unable to find files '%s' and '%s' in font paths.", font->outline, font->metrics); free_font(font, NULL); }
/* Process a STOP command. */ yerr_t command_stop(tcp_thread_t *thread, ybool_t sync, ybool_t compress, ybool_t serialized, ydynabin_t *buff) { YLOG_ADD(YLOG_DEBUG, "STOP command"); // check running transaction if (thread->transaction == NULL) goto error; // rollback transaction database_transaction_rollback(thread->transaction); thread->transaction = NULL; CONNECTION_SEND_OK(thread); return (YENOERR); error: YLOG_ADD(YLOG_WARN, "STOP error"); CONNECTION_SEND_ERROR(thread, RESP_ERR_TRANSACTION); return (YEACCESS); }
/* ** include_file() ** Try to include a given file. */ void include_file(cg_t *carta, const char *file) { struct stat st; if (!stat(file, &st)) { cg_read_conf(carta, file, YFALSE); return ; } else { ystr_t ys = ys_new(""); int i; for (i = 0; i < yv_len(carta->inc_paths); ++i) { ys_printf(&ys, "%s%c%s", carta->inc_paths[i], CARTA_SEP, file); if (!stat(ys, &st)) { cg_read_conf(carta, ys, YFALSE); ys_del(&ys); return ; } } ys_del(&ys); } YLOG_ADD(YLOG_WARN, "Unable to find file '%s' in include paths.", file); }
/* ** ytcp_server_delete() ** Delete a yTCP server and all its threads. */ ytcp_server_t *ytcp_server_delete(ytcp_server_t *server, unsigned short wait_threads) { ytcp_thread_t *thread; YLOG_MOD("ytcp", YLOG_DEBUG, "Entering"); if (!server || !server->vect_threads) { YLOG_ADD(YLOG_NOTE, "Server doesn't exist."); return (NULL); } while ((thread = (ytcp_thread_t*)yv_get(server->vect_threads))) { if (wait_threads && thread->state == YTCP_RUN) { while (thread->state == YTCP_RUN) usleep(500); } thread->state = YTCP_CLOSE; pthread_mutex_unlock(&(thread->mut_do)); pthread_join(thread->tid, NULL); pthread_mutex_destroy(&(thread->mut_do)); free0(thread); server->nbr_threads--; } yv_del(&(server->vect_threads), NULL, NULL); free0(server); YLOG_MOD("ytcp", YLOG_DEBUG, "Exiting"); return (NULL); }
/* ** cg_process_deck() ** Process a deck of cards and write PDF data. */ yerr_t cg_process_deck(cg_t *carta, cg_deck_t *deck) { int nbr_cards, cards_per_page, nbr_pages, i; /* check paper size */ if (!deck->cols || !deck->rows) { YLOG_ADD(YLOG_WARN, "Cards bigger than paper size [line %d]. Deck skipped.", deck->line_nbr); return (YE2BIG); } /* compute the number of pages and cards per page */ cards_per_page = deck->cols * deck->rows; nbr_cards = cg_deck_get_nb_cards(carta,deck); nbr_pages = nbr_cards / cards_per_page; nbr_pages = (nbr_cards % cards_per_page) ? (nbr_pages + 1) : nbr_pages; /* process every pages */ for (i = 0; i < nbr_pages; ++i) { if (!carta->reverse) { cg_process_deck_fronts(carta, deck, i, cards_per_page); cg_process_deck_backs(carta, deck, i, cards_per_page); } else { cg_process_deck_backs(carta, deck, i, cards_per_page); cg_process_deck_fronts(carta, deck, i, cards_per_page); } } return (YENOERR); }
/* ** _ydom_inside_hdlr() ** DOM handler for SAX parsing */ static void _ydom_inside_hdlr(ysax_t *sax, char *str) { ydom_t *dom; ydom_node_t *text; char *tmp; YLOG_MOD("ydom", YLOG_DEBUG, "Entering"); dom = (ydom_t*)YSAX_DATA(sax); if (dom->current_parsed_node->node_type == TEXT_NODE) { tmp = malloc0(strlen(dom->current_parsed_node->value) + strlen(str) + 1); strcpy(tmp, dom->current_parsed_node->value); strcat(tmp, str); free0(str); free0(dom->current_parsed_node->value); dom->current_parsed_node->value = tmp; } else { if (!(text = malloc0(sizeof(ydom_node_t)))) { YLOG_ADD(YLOG_ERR, "Unable to allocate memory"); return ; } text->node_type = TEXT_NODE; text->value = str; text->line_nbr = sax->line_nbr; _ydom_add_child_to_node(dom->current_parsed_node, text); dom->current_parsed_node = text; } YLOG_MOD("ydom", YLOG_DEBUG, "Exiting"); }
/* ** _ydom_open_hdlr() ** DOM handler for SAX parsing */ static void _ydom_open_hdlr(ysax_t *sax, char *tag_name, yvect_t attrs) { ydom_t *dom; ydom_node_t *node; ysax_attr_t *pt; YLOG_MOD("ydom", YLOG_DEBUG, "Entering"); dom = (ydom_t*)YSAX_DATA(sax); if (!(node = malloc0(sizeof(ydom_node_t)))) { YLOG_ADD(YLOG_ERR, "Memory alloc error"); return ; } node->node_type = ELEMENT_NODE; node->name = tag_name; node->line_nbr = sax->line_nbr; while ((pt = yv_pop(attrs))) { _ydom_add_attr_to_node(node, pt->name, pt->value); free0(pt); } yv_del(&attrs, NULL, NULL); if (dom->current_parsed_node->node_type == TEXT_NODE) { dom->current_parsed_node->complete = YTRUE; _ydom_add_next_to_node(dom->current_parsed_node, node); } else _ydom_add_child_to_node(dom->current_parsed_node, node); dom->current_parsed_node = node; YLOG_MOD("ydom", YLOG_DEBUG, "Exiting"); }
/* Process a START command. */ yerr_t command_start(tcp_thread_t *thread, ybool_t sync, ybool_t compress, ybool_t serialized, ydynabin_t *buff) { YLOG_ADD(YLOG_DEBUG, "START command"); // rollback previous transaction if (thread->transaction != NULL) database_transaction_rollback(thread->transaction); // open transaction thread->transaction = database_transaction_start(thread->finedb->database, YTRUE); if (thread->transaction == NULL) goto error; CONNECTION_SEND_OK(thread); return (YENOERR); error: YLOG_ADD(YLOG_WARN, "START error"); CONNECTION_SEND_ERROR(thread, RESP_ERR_TRANSACTION); return (YEACCESS); }
/* ** _ydom_comment_hdlr() ** DOM handler for SAX parsing */ static void _ydom_comment_hdlr(ysax_t *sax, char *s) { ydom_t *dom; ydom_node_t *node; YLOG_MOD("ydom", YLOG_DEBUG, "Entering"); dom = (ydom_t*)YSAX_DATA(sax); if (!(node = malloc0(sizeof(ydom_node_t)))) { YLOG_ADD(YLOG_ERR, "Unable to allocate memory"); return ; } node->node_type = COMMENT_NODE; node->value = s; node->line_nbr = sax->line_nbr; node->complete = YTRUE; if (dom->current_parsed_node->node_type == TEXT_NODE) { dom->current_parsed_node->complete = YTRUE; _ydom_add_next_to_node(dom->current_parsed_node, node); dom->current_parsed_node = dom->current_parsed_node->parent; } else _ydom_add_child_to_node(dom->current_parsed_node, node); YLOG_MOD("ydom", YLOG_DEBUG, "Exiting"); }
/* Process a LIST command. */ yerr_t command_list(tcp_thread_t *thread, ybool_t sync, ybool_t compress, ybool_t serialized, ydynabin_t *buff) { char last_byte = 0; yerr_t result; YLOG_ADD(YLOG_DEBUG, "LIST command"); // send the response to the client result = CONNECTION_SEND_OK(thread); if (result != YENOERR) goto error; // send data if (database_list(thread->finedb->database, thread->transaction, thread->dbname, _command_list_loop, thread) != YENOERR) goto error; // send last byte if (write(thread->fd, &last_byte, 1) != 1) goto error; YLOG_ADD(YLOG_DEBUG, "LIST command OK"); return (result); error: YLOG_ADD(YLOG_WARN, "LIST error"); CONNECTION_SEND_ERROR(thread, RESP_ERR_SERVER); return (YEIO); }
/* ** ydaemon() ** Daemonize the program. */ void ydaemon(char *serv_name, yproto_t serv_proto, char *env_serv_port, int *port) { int fd, nbr_fd; struct servent *serv; char *serv_env; char *proto_code[] = {"tcp", "udp"}; YLOG_ADD(YLOG_DEBUG, "Entering"); /* detach process */ if (fork() != 0) exit(0); setsid(); /* close all file descriptors */ nbr_fd = getdtablesize(); for (fd = 0; nbr_fd > 0 && fd < nbr_fd; ++fd) close(fd); chdir("/tmp"); /* set umask */ umask(0); /* get port number */ if (port) { if (env_serv_port && (serv_env = getenv(env_serv_port))) *port = atoi(serv_env); else if (serv_name && (serv = getservbyname(serv_name, proto_code[serv_proto]))) *port = serv->s_port; else *port = -1; } YLOG_ADD(YLOG_DEBUG, "Exiting"); }
/* ** ydom_write() ** Write the content of an XML tree to a stream. */ void ydom_write(ydom_t *dom, FILE *stream) { YLOG_MOD("ydom", YLOG_DEBUG, "Entering"); if (!dom) { YLOG_ADD(YLOG_WARN, "NULL dom pointer"); return ; } if (dom->error != YENOERR) { YLOG_ADD(YLOG_ERR, "Previous error"); return ; } fprintf(stream, "<?xml"); if (dom->xml_version) fprintf(stream, " version=\"%s\"", dom->xml_version); if (dom->encoding) fprintf(stream, " encoding=\"%s\"", dom->encoding); if (dom->standalone) fprintf(stream, " standalone=\"%s\"", dom->standalone); fprintf(stream, "?>\n"); _ydom_write_node(dom->document_element, 0, stream); YLOG_MOD("ydom", YLOG_DEBUG, "Exiting"); }
/* ** ytcp_server_set_nbr_threads() ** Set the number of threads to a given number. If there is more running ** threads than wanted number, only the waiting threads are ended. If there ** is less threads than desired, new ones are created. */ yerr_t ytcp_server_set_nbr_threads(ytcp_server_t *server, int nbr) { ytcp_thread_t *thread; int i; YLOG_MOD("ytcp", YLOG_DEBUG, "Entering"); if (nbr == server->nbr_threads) return (YENOERR); if (server->nbr_threads > nbr) { for (i = server->nbr_threads; i; --i) { thread = (ytcp_thread_t*)(server->vect_threads[i - 1]); if (thread->state != YTCP_RUN) { thread = yv_ext(server->vect_threads, i); thread->state = YTCP_CLOSE; pthread_mutex_unlock(&(thread->mut_do)); pthread_join(thread->tid, NULL); pthread_mutex_destroy(&(thread->mut_do)); free0(thread); server->nbr_threads--; } } } while (server->nbr_threads < nbr) { thread = malloc0(sizeof(ytcp_thread_t)); pthread_mutex_init(&(thread->mut_do), NULL); pthread_mutex_lock(&(thread->mut_do)); thread->server = server; thread->data = ((ytcp_thread_t*)(server->vect_threads[0]))->data; if (pthread_create(&(thread->tid), 0, _ytcp_server_thread_handle, thread)) { YLOG_ADD(YLOG_ERR, "Problem during thread creation"); thread->state = YTCP_CLOSE; thread->fd = -1; return (YEAGAIN); } yv_add(&(server->vect_threads), thread); server->nbr_threads++; thread->fd = -1; thread->state = YTCP_WAIT; } YLOG_MOD("ytcp", YLOG_DEBUG, "Exiting"); return (YENOERR); }
/* ** ytcp_server_init() ** Initialize a yTCP server. */ ytcp_server_t *ytcp_server_init(unsigned int nbr_threads, void *(*f)(void*), void *data) { ytcp_thread_t *thread; yvect_t threads; ytcp_server_t *server; unsigned int i; YLOG_MOD("ytcp", YLOG_DEBUG, "Entering"); nbr_threads = (nbr_threads == 0) ? _YTCP_NBR_THREADS : nbr_threads; threads = yv_new(); server = malloc0(sizeof(ytcp_server_t)); server->threads_func = f; server->nbr_threads = nbr_threads; server->first_waiting = 0; server->vect_threads = threads; server->sd = -1; server->run_loop = 1; server->purge_cnt = _YTCP_PURGE_COUNTER; for (i = 0; i < nbr_threads && i < 1024; ++i) { thread = malloc0(sizeof(ytcp_thread_t)); pthread_mutex_init(&(thread->mut_do), NULL); pthread_mutex_lock(&(thread->mut_do)); if (pthread_create(&(thread->tid), 0, _ytcp_server_thread_handle, thread)) { YLOG_ADD(YLOG_WARN, "Problem during thread creation"); thread->state = YTCP_CLOSE; } thread->fd = -1; thread->state = YTCP_WAIT; thread->data = data; thread->server = server; yv_add(&threads, thread); } YLOG_MOD("ytcp", YLOG_DEBUG, "Exiting"); return (server); }
/* ** ytcp_server_start() ** Start a yTCP server. */ yerr_t ytcp_server_start(ytcp_server_t *server, int port) { struct sockaddr_in addr; unsigned int addr_size; int fd; const int on = 1; YLOG_MOD("ytcp", YLOG_DEBUG, "Entering"); if ((server->sd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { YLOG_ADD(YLOG_ERR, "Socket error"); return (YEIO); } if (setsockopt(server->sd, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0) YLOG_ADD(YLOG_WARN, "setsockopt(SO_REUSEADDR) failed"); if (setsockopt(server->sd, SOL_SOCKET, SO_KEEPALIVE, (void*)&on, sizeof(on)) < 0) YLOG_ADD(YLOG_WARN, "setsockopt(SO_KEEPALIVE) failed"); addr_size = sizeof(addr); memset(&addr, 0, addr_size); addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_family = AF_INET; addr.sin_port = htons(port); if (bind(server->sd, (struct sockaddr*)&addr, addr_size) < 0) { YLOG_ADD(YLOG_CRIT, "Bind error"); return (YEBADF); } if (listen(server->sd, SOMAXCONN)) { YLOG_ADD(YLOG_CRIT, "Listen error"); return (YEBADF); } while (server->run_loop) { if ((fd = accept(server->sd, (struct sockaddr*)&addr, &addr_size)) < 0) continue ; if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&on, sizeof(on)) < 0) YLOG_ADD(YLOG_WARN, "setsockopt(KEEPALIVE) failed"); if (_ytcp_server_thread_launch(server, fd) != YENOERR) close(fd); } close(server->sd); YLOG_MOD("ytcp", YLOG_DEBUG, "Exiting"); return (YENOERR); }
/* ** cg_read_conf() ** Read the configuration file. */ yerr_t cg_read_conf(cg_t *carta, const char *input, ybool_t initial) { ydom_t *dom; ydom_node_t *root_node; yvect_t array; int i; char *pt = NULL, *pt2 = NULL; if (!(dom = ydom_new())) { YLOG_ADD(YLOG_ERR, "Memory error"); return (YENOMEM); } if (ydom_read_file(dom, input) != YENOERR) { YLOG_ADD(YLOG_ERR, "Problem with file '%s'", input); ydom_del(dom); return (YEINVAL); } if (!(array = ydom_xpath(dom, "/pandocreon:carta-genius")) || !yv_len(array) || !array[0]) { YLOG_ADD(YLOG_ERR, "No configuration"); yv_del(&array, NULL, NULL); ydom_del(dom); return (YEINVAL); } root_node = array[0]; yv_del(&array, NULL, NULL); yv_add(&carta->xml_doms, dom); /* get document info */ if ((array = ydom_node_xpath(root_node, "info")) && yv_len(array) && array[0]) { carta->author = ydom_node_get_attr_value(array[0], "author"); carta->title = ydom_node_get_attr_value(array[0], "title"); carta->subject = ydom_node_get_attr_value(array[0], "subject"); carta->keywords = ydom_node_get_attr_value(array[0], "keywords"); carta->copyright = ydom_node_get_attr_value(array[0], "copyright"); carta->version = ydom_node_get_attr_value(array[0], "version"); carta->language = ydom_node_get_attr_value(array[0], "lang"); carta->note = ydom_node_get_attr_value(array[0], "note"); } yv_del(&array, NULL, NULL); /* get PDF version */ if ((array = ydom_node_xpath(root_node, "pdf")) && yv_len(array) && array[0]) { char *passwd1 = NULL, *passwd2 = NULL; pt = ydom_node_get_attr_value(array[0], "version"); passwd1 = ydom_node_get_attr_value(array[0], "master-password"); passwd2 = ydom_node_get_attr_value(array[0], "user-password"); if (!passwd1 || !passwd2 || !strcmp(passwd1, passwd2)) { free0(passwd1); free0(passwd2); } carta->master_password = passwd1; carta->user_password = passwd2; } if (pt && !strcmp(pt, "1.3")) carta->pdf_version = PDF_13; else if (pt && !strcmp(pt, "1.5")) carta->pdf_version = PDF_15; else carta->pdf_version = PDF_14; free0(pt); yv_del(&array, NULL, NULL); /* get general configuration */ if (initial) { /* get default unit */ if ((array = ydom_node_xpath(root_node, "unit")) && yv_len(array) && array[0] && (pt = ydom_node_get_attr_value(array[0], "base"))) { if (!strcasecmp(pt, "mm") || !strcasecmp(pt, "millimeter")) carta->default_unit = YUNIT_MM; else if (!strcasecmp(pt, "cm") || !strcasecmp(pt, "centimeter")) carta->default_unit = YUNIT_CM; else if (!strcasecmp(pt, "in") || !strcasecmp(pt, "inch")) carta->default_unit = YUNIT_IN; else if (!strcasecmp(pt, "pt") || !strcasecmp(pt, "point")) carta->default_unit = YUNIT_PT; else { YLOG_ADD(YLOG_ERR, "Bad default unit [line %d]", ((ydom_node_t*)array[0])->line_nbr); free0(pt); yv_del(&array, NULL, NULL); ydom_del(dom); return (YEINVAL); } free0(pt); } else { YLOG_ADD(YLOG_INFO, "No default unit. Set to mm."); carta->default_unit = YUNIT_MM; } yv_del(&array, NULL, NULL); /* get cards' back configuration */ if ((array = ydom_node_xpath(root_node, "back")) && yv_len(array) && array[0]) { if ((pt = ydom_node_get_attr_value(array[0], "side"))) { if (!strcasecmp(pt, "width")) carta->do_back = BACK_WIDTH; else if (!strcasecmp(pt, "height")) carta->do_back = BACK_HEIGHT; free0(pt); } else carta->do_back = BACK_NO; if ((pt = ydom_node_get_attr_value(array[0], "reverse")) && (!strcasecmp(pt, "yes") || !strcasecmp(pt, "true"))) carta->reverse = YTRUE; free0(pt); } else carta->do_back = BACK_NO; yv_del(&array, NULL, NULL); } /* get templates */ if ((array = ydom_node_xpath(root_node, "templates/template")) && yv_len(array)) { int i; for (i = 0; i < yv_len(array); ++i) yv_add(&carta->templates, array[i]); } yv_del(&array, NULL, NULL); /* get init variables */ if ((array = ydom_node_xpath(root_node, "variables/var")) && yv_len(array)) { int i; for (i = 0; i < yv_len(array); ++i) yv_add(&carta->variables, array[i]); } yv_del(&array, NULL, NULL); /* get default font */ if ((array = ydom_node_xpath(root_node, "fonts")) && yv_len(array) && array[0]) { char *default_font; if ((default_font = ydom_node_get_attr_value(array[0], "default"))) { free0(carta->default_font); carta->default_font = default_font; } } yv_del(&array, NULL, NULL); /* get fonts */ if ((array = ydom_node_xpath(root_node, "fonts/*")) && yv_len(array) && array[0]) { int i; for (i = 0; i < yv_len(array); ++i) { char *tag_name = ydom_node_get_name(array[i]); if (tag_name && !strcmp(tag_name, "font")) import_font(carta, array[i]); else if (tag_name && !strcmp(tag_name, "path")) { char *dir = ydom_node_get_attr_value(array[i], "dir"); if (dir && strlen(dir)) add_font_paths(carta, dir); else YLOG_ADD(YLOG_WARN, "Path without 'dir' argument [line %d].", ((ydom_node_t*)array[i])->line_nbr); free0(dir); } free0(tag_name); } } yv_del(&array, NULL, NULL); /* get images */ if ((array = ydom_node_xpath(root_node, "images/*")) && yv_len(array) && array[0]) { int i; for (i = 0; i < yv_len(array); ++i) { char *tag_name = ydom_node_get_name(array[i]); if (tag_name && !strcmp(tag_name, "image")) import_image(carta, array[i], YFALSE); else if (tag_name && !strcmp(tag_name, "mask")) import_image(carta, array[i], YTRUE); else if (tag_name && !strcmp(tag_name, "path")) { /* add a directory for path searching */ char *dir = ydom_node_get_attr_value(array[i], "dir"); if (dir && strlen(dir)) add_img_paths(carta, dir); else YLOG_ADD(YLOG_WARN, "Path without 'dir' argument [line %d].", ((ydom_node_t*)array[i])->line_nbr); free0(dir); } free0(tag_name); } } yv_del(&array, NULL, NULL); /* get all decks */ array = ydom_node_xpath(root_node, "deck"); for (i = 0; i < yv_len(array); ++i) { cg_deck_t *deck; ydom_node_t *deck_node = array[i]; yvect_t array2; deck = malloc0(sizeof(cg_deck_t)); deck->line_nbr = deck_node->line_nbr; /* get paper size */ if ((array2 = ydom_node_xpath(deck_node, "paper")) && yv_len(array2) && array2[0]) { cg_expr_var_t e_w = {0}, e_h = {0}; yvalue_t width, height, margin_w, margin_h; /* get width and height */ if ((pt = ydom_node_get_attr_value(array2[0], "type"))) { cg_paper_t paper_type = cg_get_paper(pt); width = cg_get_paper_width(paper_type); height = cg_get_paper_height(paper_type); if ((pt2 = ydom_node_get_attr_value(array2[0], "landscape")) && (!strcasecmp(pt2, "yes") || !strcasecmp(pt2, "true"))) { yvalue_t tmp_val = width; width = height; height = tmp_val; } } else if ((pt = ydom_node_get_attr_value(array2[0], "width")) && cg_expr(carta, pt, &e_w, carta->default_unit) == YENOERR && e_w.type == CG_EXPR_VALUE && (pt2 = ydom_node_get_attr_value(array2[0], "height")) && cg_expr(carta, pt2, &e_h, carta->default_unit) == YENOERR && e_h.type == CG_EXPR_VALUE) { width = e_w.value.value; height = e_h.value.value; } else { YLOG_ADD(YLOG_WARN, "No valid paper size. Set to a4."); width = cg_get_paper_width(A4); height = cg_get_paper_height(A4); } free0(pt); free0(pt2); free_var(&e_w, &e_w); free_var(&e_h, &e_h); /* get margin */ if ((pt = ydom_node_get_attr_value(array2[0], "margin"))) margin_w = margin_h = yvalue_read(pt, carta->default_unit); else margin_w = margin_h = yvalue_read(DEFAULT_MARGIN, carta->default_unit); free0(pt); if ((pt = ydom_node_get_attr_value(array2[0], "margin-width")) && cg_expr(carta, pt, &e_w, carta->default_unit) == YENOERR && e_w.type == CG_EXPR_VALUE) margin_w = e_w.value.value; free0(pt); if ((pt = ydom_node_get_attr_value(array2[0], "margin-height")) && cg_expr(carta, pt, &e_h, carta->default_unit) == YENOERR && e_h.type == CG_EXPR_VALUE) margin_h = e_h.value.value; free0(pt); free_var(&e_w, &e_w); free_var(&e_h, &e_h); deck->paper_width = width; deck->paper_height = height; deck->paper_margin_w = margin_w; deck->paper_margin_h = margin_h; } else { YLOG_ADD(YLOG_INFO, "No paper size, set to default (A4)."); deck->paper_width = cg_get_paper_width(A4); deck->paper_height = cg_get_paper_height(A4); deck->paper_margin_w = deck->paper_margin_h = yvalue_read(DEFAULT_MARGIN, carta->default_unit); } yv_del(&array2, NULL, NULL); /* get hidden ditch config */ if ((array2 = ydom_node_xpath(deck_node, "hidden-ditch")) && yv_len(array2) && array2[0]) { /* get margin */ deck->ditch_even = ydom_node_get_attr_value(array2[0], "even"); deck->ditch_odd = ydom_node_get_attr_value(array2[0], "odd"); } yv_del(&array2, NULL, NULL); /* get card size */ if ((array2 = ydom_node_xpath(deck_node, "cardsize")) && yv_len(array2) && array2[0]) { yvalue_t width, height, space_w, space_h; if ((pt = ydom_node_get_attr_value(array2[0], "type"))) { cg_paper_t paper_type = cg_get_paper(pt); width = cg_get_paper_width(paper_type); height = cg_get_paper_height(paper_type); if ((pt2 = ydom_node_get_attr_value(array2[0], "landscape")) && (!strcasecmp(pt2, "yes") || !strcasecmp(pt2, "true"))) { yvalue_t tmp_val = width; width = height; height = tmp_val; } } else if ((pt = ydom_node_get_attr_value(array2[0], "width")) && (pt2 = ydom_node_get_attr_value(array2[0], "height"))) { width = yvalue_read(pt, carta->default_unit); height = yvalue_read(pt2, carta->default_unit); } else { YLOG_ADD(YLOG_WARN, "No valid card size. Set to a6."); width = cg_get_paper_width(A6); height = cg_get_paper_height(A6); } free0(pt); free0(pt2); deck->card_width = width; deck->card_height = height; if ((pt = ydom_node_get_attr_value(array2[0], "space"))) space_w = space_h = yvalue_read(pt, carta->default_unit); else if ((pt = ydom_node_get_attr_value(array2[0], "space-width")) && (pt2 = ydom_node_get_attr_value(array2[0], "space-height"))) { space_w = yvalue_read(pt, carta->default_unit); space_h = yvalue_read(pt2, carta->default_unit); } else { space_w.unit = space_h.unit = YUNIT_PT; space_w.value = space_h.value = 0.0; } deck->space_width = space_w; deck->space_height = space_h; free0(pt); free0(pt2); } else { YLOG_ADD(YLOG_INFO, "No card size. Set to a6."); deck->card_width = cg_get_paper_width(A6); deck->card_height = cg_get_paper_height(A6); } yv_del(&array2, NULL, NULL); /* get cards */ deck->cards = ydom_node_xpath(deck_node, "card"); yv_add(&carta->decks, deck); } /* get included files */ if ((array = ydom_node_xpath(root_node, "includes/*")) && yv_len(array) && array[0]) { int i; for (i = 0; i < yv_len(array); ++i) { char *tag_name = ydom_node_get_name(array[i]); if (tag_name && !strcmp(tag_name, "include")) { /* include a file */ char *file = ydom_node_get_attr_value(array[i], "file"); if (file && strlen(file)) include_file(carta, file); else YLOG_ADD(YLOG_WARN, "Include without 'file' argument [line %d].", ((ydom_node_t*)array[i])->line_nbr); free0(file); } else if (tag_name && !strcmp(tag_name, "path")) { /* add an include dir */ char *dir = ydom_node_get_attr_value(array[i], "dir"); if (dir && strlen(dir)) add_inc_paths(carta, dir); else YLOG_ADD(YLOG_WARN, "Path without 'dir' argument [line %d].", ((ydom_node_t*)array[i])->line_nbr); free0(dir); } free0(tag_name); } } yv_del(&array, NULL, NULL); return (YENOERR); }
/* ** _ydom_process_instr_hdlr() ** DOM handler for SAX parsing */ static void _ydom_process_instr_hdlr(ysax_t *sax, char *target, char *content) { ydom_t *dom; ydom_node_t *node; char *pt; char *pt2; YLOG_MOD("ydom", YLOG_DEBUG, "Entering"); dom = (ydom_t*)YSAX_DATA(sax); if (!strcmp(target, XML)) { if (content && (pt = strstr(content, XML_VERSION))) { if ((pt = strchr(pt, EQ)) && ((pt = strchr(pt, DQUOTE)) || (pt = strchr(pt, QUOTE))) && ((pt2 = strchr(pt + 1, DQUOTE)) || (pt2 = strchr(pt + 1, QUOTE)))) { if ((dom->xml_version = malloc0(pt2 - pt))) { memcpy(dom->xml_version, pt + 1, pt2 - pt - 1); dom->xml_version[pt2 - pt - 1] = '\0'; } } } if (content && (pt = strstr(content, ENCODING))) { if ((pt = strchr(pt, EQ)) && ((pt = strchr(pt, DQUOTE)) || (pt = strchr(pt, QUOTE))) && ((pt2 = strchr(pt + 1, DQUOTE)) || (pt2 = strchr(pt + 1, QUOTE)))) { if ((dom->encoding = malloc0(pt2 - pt))) { memcpy(dom->encoding, pt + 1, pt2 - pt - 1); dom->encoding[pt2 - pt - 1] = '\0'; } } } if (content && (pt = strstr(content, STANDALONE))) { if ((pt = strchr(pt, EQ)) && ((pt = strchr(pt, DQUOTE)) || (pt = strchr(pt, QUOTE))) && ((pt2 = strchr(pt + 1, DQUOTE)) || (pt2 = strchr(pt + 1, QUOTE)))) { if ((dom->standalone = malloc0(pt2 - pt))) { memcpy(dom->standalone, pt + 1, pt2 - pt - 1); dom->standalone[pt2 - pt - 1] = '\0'; } } } } else { if (!(node = malloc0(sizeof(ydom_node_t)))) { YLOG_ADD(YLOG_DEBUG, "Unable to allocate memory"); return ; } node->node_type = PROCESSING_INSTRUCTION_NODE; node->name = target; node->value = content; node->line_nbr = sax->line_nbr; node->complete = YTRUE; if (dom->current_parsed_node->node_type == TEXT_NODE) { dom->current_parsed_node->complete = YTRUE; _ydom_add_next_to_node(dom->current_parsed_node, node); dom->current_parsed_node = dom->current_parsed_node->parent; } else _ydom_add_child_to_node(dom->current_parsed_node, node); } YLOG_MOD("ydom", YLOG_DEBUG, "Exiting"); }
/* ** _ytcp_server_thread_launch() -- PRIVATE FUNCTION ** Use a waiting thread to handle an incoming connection. */ static yerr_t _ytcp_server_thread_launch(ytcp_server_t *server, int fd) { ytcp_thread_t *thread; int i; YLOG_MOD("ytcp", YLOG_DEBUG, "Entering"); if (!server->purge_cnt) { ytcp_server_purge_threads(server); server->purge_cnt = _YTCP_PURGE_COUNTER; } /* search a waiting thread */ if (server->first_waiting >= 0) { thread = (ytcp_thread_t*)(server->vect_threads[server->first_waiting]); thread->fd = fd; thread->stream = fdopen(fd, "rb+"); setvbuf(thread->stream, NULL, _IONBF, 0); thread->state = YTCP_RUN; pthread_mutex_unlock(&(thread->mut_do)); for (i = 0; i < server->nbr_threads; ++i) { thread = (ytcp_thread_t*)(server->vect_threads[i]); if (thread->state == YTCP_WAIT) { server->first_waiting = i; break; } } if (i == server->nbr_threads) server->first_waiting = -1; YLOG_MOD("ytcp", YLOG_DEBUG, "Exiting"); return (YENOERR); } /* update 'first_waiting' */ for (i = 0; i < server->nbr_threads; ++i) { thread = (ytcp_thread_t*)(server->vect_threads[i]); if (thread->state == YTCP_WAIT) { server->first_waiting = i; break; } } if (i != server->nbr_threads) { YLOG_MOD("ytcp", YLOG_DEBUG, "Recall the function"); return (_ytcp_server_thread_launch(server, fd)); } /* no one waiting thread - create a new one */ thread = malloc0(sizeof(ytcp_thread_t)); pthread_mutex_init(&(thread->mut_do), NULL); pthread_mutex_lock(&(thread->mut_do)); thread->server = server; thread->data = ((ytcp_thread_t*)(server->vect_threads[0]))->data; if (pthread_create(&(thread->tid), 0, _ytcp_server_thread_handle, thread)) { YLOG_ADD(YLOG_ERR, "Problem during thread creation"); thread->state = YTCP_CLOSE; thread->fd = -1; pthread_mutex_unlock(&(thread->mut_do)); pthread_mutex_destroy(&(thread->mut_do)); return (YEAGAIN); } yv_add(&(server->vect_threads), thread); server->nbr_threads++; thread->fd = fd; thread->state = YTCP_RUN; pthread_mutex_unlock(&(thread->mut_do)); YLOG_MOD("ytcp", YLOG_DEBUG, "New thread created - Exiting"); return (YENOERR); }
/* ** import_image() ** Try to import a given image. */ void import_image(cg_t *carta, ydom_node_t *node, ybool_t is_mask) { char *width = NULL, *height = NULL; struct stat st; cg_image_t *image; if (!(image = malloc0(sizeof(cg_image_t)))) return ; image->id = ydom_node_get_attr_value(node, "id"); image->file = ydom_node_get_attr_value(node, "file"); if (!image->id || !image->file) { if (is_mask) YLOG_ADD(YLOG_WARN, "Empty image mask declaration [line %d].", node->line_nbr); else YLOG_ADD(YLOG_WARN, "Empty image declaration [line %d].", node->line_nbr); free0(image->id); free0(image); return ; } if (!is_mask) { image->mask = ydom_node_get_attr_value(node, "mask"); image->mask_id = ydom_node_get_attr_value(node, "mask-id"); width = ydom_node_get_attr_value(node, "width"); height = ydom_node_get_attr_value(node, "height"); image->width = yvalue_read(width, carta->default_unit); image->height = yvalue_read(height, carta->default_unit); free0(width); free0(height); } image->i = image->m = -1; if (!stat(image->file, &st)) { if (is_mask) yv_add(&carta->masks, image); else yv_add(&carta->images, image); return ; } else { ystr_t ys = ys_new(""); int i; for (i = 0; i < yv_len(carta->img_paths); ++i) { ys_printf(&ys, "%s%c%s", carta->img_paths[i], CARTA_SEP, image->file); if (!stat(ys, &st)) { free0(image->file); image->file = ys_string(ys); if (is_mask) yv_add(&carta->masks, image); else yv_add(&carta->images, image); ys_del(&ys); return ; } } ys_del(&ys); } YLOG_ADD(YLOG_WARN, "Unable to find file '%s' in image paths.", image->file); free_image(image, NULL); }
/* ** cg_compute_cols_rows() ** Compute number of colons and rows of every decks' pages. */ yerr_t cg_compute_cols_rows(cg_t *carta) { double useable_w, useable_h; cg_deck_t *deck; int i; for (i = 0; i < yv_len(carta->decks); ++i) { deck = carta->decks[i]; useable_w = yvalue_get(deck->paper_width, carta->default_unit) - (2 * yvalue_get(deck->paper_margin_w, carta->default_unit)); useable_h = yvalue_get(deck->paper_height, carta->default_unit) - (2 * yvalue_get(deck->paper_margin_h, carta->default_unit)); deck->cols = (int)(useable_w / yvalue_get(deck->card_width, carta->default_unit)); deck->rows = (int)(useable_h / yvalue_get(deck->card_height, carta->default_unit)); /* adjust depending from space between cards */ while (deck->cols > 0) { double total_width; total_width = deck->cols * yvalue_get(deck->card_width, carta->default_unit); total_width += (deck->cols - 1) * yvalue_get(deck->space_width, carta->default_unit); if (total_width <= useable_w) break ; deck->cols--; } while (deck->rows > 0) { double total_height; total_height = deck->rows * yvalue_get(deck->card_height, carta->default_unit); total_height += (deck->rows - 1) * yvalue_get(deck->space_height, carta->default_unit); if (total_height <= useable_h) break ; deck->rows--; } /* check cards */ if (!yv_len(deck->cards)) { YLOG_ADD(YLOG_WARN, "No card in deck [line %d]. Deck skipped.", deck->line_nbr); deck = yv_ext(carta->decks, i); free_deck(deck, NULL); i--; } /* check paper size */ if (!deck->cols || !deck->rows) { YLOG_ADD(YLOG_WARN, "Cards bigger than paper size [line %d]. Deck skipped.", deck->line_nbr); deck = yv_ext(carta->decks, i); free_deck(deck, NULL); i--; } } /* check decks */ if (!yv_len(carta->decks)) { YLOG_ADD(YLOG_ERR, "No usable deck. Abort."); return (YENOENT); } return (YENOERR); }
/* ** cg_init() ** Initialize the Carta object and launch the configuration file parsing. */ cg_t *cg_init(char *input, const char *inc_paths, const char *font_paths, const char *img_paths) { cg_t *carta; ystr_t ys; /* init */ if (!(carta = malloc0(sizeof(cg_t)))) { YLOG_ADD(YLOG_ERR, "Memory error"); return (NULL); } if (!(ys = ys_new("")) || !(carta->xml_doms = yv_new()) || !(carta->fonts = yv_new()) || !(carta->images = yv_new()) || !(carta->masks = yv_new()) || !(carta->templates = yv_new()) || !(carta->variables = yv_new()) || !(carta->decks = yv_new()) || !(carta->inc_paths = yv_new()) || !(carta->img_paths = yv_new()) || !(carta->font_paths = yv_new()) || !(carta->text_defines = yv_new())) { YLOG_ADD(YLOG_ERR, "Memory error"); ys_del(&ys); yv_del(&carta->xml_doms, NULL, NULL); yv_del(&carta->fonts, NULL, NULL); yv_del(&carta->images, NULL, NULL); yv_del(&carta->masks, NULL, NULL); yv_del(&carta->templates, NULL, NULL); yv_del(&carta->variables, NULL, NULL); yv_del(&carta->decks, NULL, NULL); yv_del(&carta->inc_paths, NULL, NULL); yv_del(&carta->img_paths, NULL, NULL); yv_del(&carta->font_paths, NULL, NULL); free0(carta); return (NULL); } /* extract path directories */ add_inc_paths(carta, inc_paths); add_font_paths(carta, font_paths); add_img_paths(carta, img_paths); /* initialize expression evaluation engine */ if (cg_expr_init(carta) != YENOERR) YLOG_ADD(YLOG_WARN, "Parser init error."); /* read input file */ if (cg_read_conf(carta, input, YTRUE) != YENOERR) { YLOG_ADD(YLOG_ERR, "Problem during input file processing."); yv_del(&carta->xml_doms, NULL, NULL); yv_del(&carta->fonts, NULL, NULL); yv_del(&carta->images, NULL, NULL); yv_del(&carta->masks, NULL, NULL); yv_del(&carta->templates, NULL, NULL); yv_del(&carta->variables, NULL, NULL); yv_del(&carta->decks, NULL, NULL); yv_del(&carta->inc_paths, NULL, NULL); yv_del(&carta->img_paths, NULL, NULL); yv_del(&carta->font_paths, NULL, NULL); yv_del(&carta->text_defines, NULL, NULL); if (carta->expr) { yv_del(&carta->expr->vars, free_var, NULL); yv_del(&carta->expr->funcs, free_func, NULL); free0(carta->expr); } free0(carta); } return (carta); }
/* Process a DEL command. */ yerr_t command_del(tcp_thread_t *thread, ybool_t sync, ybool_t compress, ybool_t serialized, ydynabin_t *buff) { uint16_t *pkey_len, key_len; void *ptr, *key = NULL; writer_msg_t *msg = NULL; char answer; YLOG_ADD(YLOG_DEBUG, "DEL command"); // read key length if (connection_read_data(thread, buff, sizeof(key_len)) != YENOERR) goto error; pkey_len = ydynabin_forward(buff, sizeof(key_len)); key_len = ntohs(*pkey_len); // read key if (connection_read_data(thread, buff, (size_t)key_len) != YENOERR) goto error; ptr = ydynabin_forward(buff, (size_t)key_len); if ((key = YMALLOC((size_t)key_len)) == NULL) goto error; memcpy(key, ptr, (size_t)key_len); if (!sync) { // send the response connection_send_response(thread, RESP_OK, YFALSE, YFALSE, NULL, 0); } // creation of the message if ((msg = YMALLOC(sizeof(writer_msg_t))) == NULL) goto error; msg->type = WRITE_DEL; ybin_set(&msg->name, key, key_len); if (!sync) { msg->dbname = thread->dbname ? strdup(thread->dbname) : NULL; // send the message to the writer thread if (nn_send(thread->write_sock, &msg, sizeof(msg), 0) < 0) { YLOG_ADD(YLOG_WARN, "Unable to send message to writer thread."); goto error; } return (YENOERR); } // synchronized if (database_del(thread->finedb->database, thread->transaction, thread->dbname, msg->name) == YENOERR) { YLOG_ADD(YLOG_DEBUG, "Deletion done on database."); answer = 1; } else { YLOG_ADD(YLOG_WARN, "Unable to delete data on database."); answer = 0; } YFREE(key); YFREE(msg); YLOG_ADD(YLOG_DEBUG, "DEL command %s", (answer ? "OK" : "failed")); if (!sync) return (YENOERR); return (connection_send_response(thread, (answer ? RESP_OK : RESP_ERR_BAD_NAME), YFALSE, YFALSE, NULL, 0)); error: YLOG_ADD(YLOG_WARN, "PUT error"); YFREE(key); YFREE(msg); CONNECTION_SEND_ERROR(thread, RESP_ERR_SERVER); return (YEIO); }
int main(int argc, char **argv) { int optch, return_value = 0; char *input = NULL, *output = NULL, *inc_paths = NULL; char *font_paths = NULL, *img_paths = NULL; cg_back_t do_back = BACK_NO; cg_paper_t do_paper = A4; yvalue_t do_width, do_height, do_margin_width, do_margin_height; ybool_t set_back = YFALSE, set_paper = YFALSE, set_pdf = YFALSE; ybool_t set_width = YFALSE, set_height = YFALSE, set_margin = YFALSE; ybool_t set_margin_width = YFALSE, set_margin_height = YFALSE; ybool_t do_reverse = YFALSE, set_reverse = YFALSE; ybool_t set_landscape = YFALSE, set_quiet = YFALSE; cg_pdf_version_t pdf_version = PDF_14; char *author = NULL, *title = NULL, *log_file = NULL;; cg_t *carta; /* parse the command line */ while ((optch = getopt(argc, argv, "p:w:h:l:m:x:y:b:v:r:i:o:d:e:t:L:q")) != -1) switch (optch) { case 'p': /* paper type */ set_paper = YTRUE; do_paper = cg_get_paper(optarg); do_width = cg_get_paper_width(do_paper); do_height = cg_get_paper_height(do_paper); break ; case 'w': /* paper width */ set_width = YTRUE; do_width = yvalue_read(optarg, YUNIT_MM); break ; case 'h': /* paper height */ set_height = YTRUE; do_height = yvalue_read(optarg, YUNIT_MM); break ; case 'l': /* landscape mode */ if (!strcasecmp(optarg, "yes") || !strcasecmp(optarg, "true")) set_landscape = YTRUE; break ; case 'm': /* margin size */ set_margin = YTRUE; do_margin_width = yvalue_read(optarg, YUNIT_MM); do_margin_height = do_margin_width; break ; case 'x': /* margin width */ set_margin_width = YTRUE; do_margin_width = yvalue_read(optarg, YUNIT_MM); break ; case 'y': /* margin height */ set_margin_height = YTRUE; do_margin_height = yvalue_read(optarg, YUNIT_MM); break ; case 'b': /* cards' back configuration */ set_back = YTRUE; if (!strcasecmp(optarg, "width")) do_back = BACK_WIDTH; else if (!strcasecmp(optarg, "height")) do_back = BACK_HEIGHT; else if (!strcasecmp(optarg, "no")) do_back = BACK_NO; else set_back = YFALSE; break ; case 'v': /* PDF version */ set_pdf = YTRUE; if (!strcmp(optarg, "1.3")) pdf_version = PDF_13; else if (!strcmp(optarg, "1.4")) pdf_version = PDF_14; else if (!strcmp(optarg, "1.5")) pdf_version = PDF_15; else set_pdf = YFALSE; break ; case 'r': /* inverse page order */ if (!strcasecmp(optarg, "yes") || !strcasecmp(optarg, "true")) { set_reverse = YTRUE; do_reverse = YTRUE; } else if (!strcasecmp(optarg, "no") || !strcasecmp(optarg, "false")) { set_reverse = YTRUE; do_reverse = YFALSE; } break ; case 'd': /* include path directories */ inc_paths = strdup(optarg); break ; case 'f': /* font path directories */ font_paths = strdup(optarg); break ; case 'g': /* image path directories */ img_paths = strdup(optarg); break ; case 'i': /* input file */ input = strdup(optarg); break ; case 'o': /* output file */ output = strdup(optarg); break ; case 'e': /* author */ author = strdup(optarg); break ; case 't': /* title */ title = strdup(optarg); break ; case 'L': /* log file */ log_file = strdup(optarg); break ; case 'q': /* quiet mode */ set_quiet = YTRUE; break ; default: _usage(); exit(1); } if (!input || !output) { _usage(); exit(1); } /* logging init */ if (set_quiet && log_file) YLOG_INIT_FILE(log_file); else if (set_quiet && !log_file) YLOG_INIT_SYSLOG(); else if (!set_quiet && log_file) YLOG_INIT_STDERR_FILE(log_file); else YLOG_INIT_STDERR(); /* read input file */ if (!(carta = cg_init(input, inc_paths, font_paths, img_paths))) { YLOG_ADD(YLOG_ERR, "Unable to read input file '%s'", input); exit(1); } /* update with command line options */ if (set_back) carta->do_back = do_back; if (set_paper || set_width || set_height || set_landscape || set_margin || set_margin_width || set_margin_height) { cg_deck_t *deck; int i; for (i = 0; i < yv_len(carta->decks); ++i) { deck = carta->decks[i]; if (set_paper || set_width) deck->paper_width = do_width; if (set_paper || set_height) deck->paper_height = do_height; if (set_landscape) { yvalue_t tmp_val = deck->paper_width; deck->paper_width = deck->paper_height; deck->paper_height = tmp_val; } if (set_margin || set_margin_width) deck->paper_margin_w = do_margin_width; if (set_margin || set_margin_height) deck->paper_margin_h = do_margin_height; } } if (set_pdf) carta->pdf_version = pdf_version; if (set_reverse) carta->reverse = do_reverse; if (author) { free0(carta->author); carta->author = author; } if (title) { free0(carta->title); carta->title = title; } /* compute cols and rows */ if (cg_compute_cols_rows(carta) == YENOERR) { /* create the PDF file */ if (cg_create_document(output, carta) != YENOERR) return_value = 2; } else return_value = 3; /* free memory */ yv_del(&carta->xml_doms, free_dom, NULL); yv_del(&carta->decks, free_deck, NULL); yv_del(&carta->fonts, free_font, NULL); yv_del(&carta->images, free_image, NULL); yv_del(&carta->masks, free_image, NULL); yv_del(&carta->templates, NULL, NULL); yv_del(&carta->variables, NULL, NULL); yv_del(&carta->inc_paths, free_path, NULL); yv_del(&carta->img_paths, free_path, NULL); yv_del(&carta->text_defines, free_text_define, NULL); if (carta->expr) { yv_del(&carta->expr->vars, free_var, NULL); yv_del(&carta->expr->funcs, free_func, NULL); free0(carta->expr); } free0(carta->author); free0(carta->title); free0(carta->subject); free0(carta->keywords); free0(carta->copyright); free0(carta->version); free0(carta->language); free0(carta->note); free0(carta->master_password); free0(carta->user_password); free0(carta); return (return_value); }
/* ** cg_create_document() ** Create the ouput PDF file. */ yerr_t cg_create_document(char *output, cg_t *carta) { PDF *p; int i; yerr_t return_value = YENOERR; if (!(carta->p = p = PDF_new())) { YLOG_ADD(YLOG_ERR, "PDF allocation error."); return (YEUNDEF); } PDF_TRY(p) { ystr_t ys = ys_new(""); /* document's initialization */ ys_printf(&ys, "compatibility %s", (carta->pdf_version == PDF_13) ? "1.3" : (carta->pdf_version == PDF_15) ? "1.5" : "1.4"); if (carta->master_password && carta->user_password) { ys_cat(&ys, " masterpassword "); ys_cat(&ys, carta->master_password); ys_cat(&ys, " userpassword "); ys_cat(&ys, carta->user_password); } if (PDF_begin_document(p, output, 0, ys) == -1) { YLOG_ADD(YLOG_ERR, "Unable to create file '%s'", output); PDF_delete(p); ys_del(&ys); return (YEUNDEF); } ys_del(&ys); PDF_set_info(p, "Creator", DEFAULT_CREATOR); if (carta->author) PDF_set_info(p, "Author", carta->author); if (carta->title) PDF_set_info(p, "Title", carta->title); if (carta->subject) PDF_set_info(p, "Subject", carta->subject); if (carta->keywords) PDF_set_info(p, "Keywords", carta->keywords); if (carta->copyright) PDF_set_info(p, "Copyright", carta->copyright); if (carta->version) PDF_set_info(p, "Version", carta->version); if (carta->language) PDF_set_info(p, "Language", carta->language); if (carta->note) PDF_set_info(p, "Note", carta->note); /* load variables, fonts and images */ cg_load_variables(carta); cg_load_fonts(carta); cg_load_images(carta); /* process every decks */ for (i = 0; i < yv_len(carta->decks); ++i) { cg_deck_t *deck = carta->decks[i]; /* update variables */ cg_expr_set_scalar(carta, "DECK_INDEX", (double)i + 1); cg_expr_set_element(carta, "PAGE", deck->paper_width, deck->paper_height); cg_expr_set_element(carta, "PAGE_DIM", deck->paper_width, deck->paper_height); cg_expr_set_element(carta, "PAGE_DIMENSION", deck->paper_width, deck->paper_height); cg_expr_set_element(carta, "CARD", deck->card_width, deck->card_height); cg_expr_set_element(carta, "CARD_DIM", deck->card_width, deck->card_height); cg_expr_set_element(carta, "CARD_DIMENSION", deck->card_width, deck->card_height); cg_expr_set_element(carta, "MARGIN", deck->paper_margin_w, deck->paper_margin_h); cg_expr_set_element(carta, "MARGIN_DIM", deck->paper_margin_w, deck->paper_margin_h); cg_expr_set_element(carta, "MARGIN_DIMENSION", deck->paper_margin_w, deck->paper_margin_h); cg_expr_set_element(carta, "SPACE", deck->space_width, deck->space_height); cg_expr_set_element(carta, "SPACE_DIM", deck->space_width, deck->space_height); cg_expr_set_element(carta, "SPACE_DIMENSION", deck->space_width, deck->space_height); cg_expr_set_scalar(carta, "CARD_DECK", (double)cg_deck_get_nb_cards(carta, deck)); cg_expr_set_scalar(carta, "CARDS_IN_DECK", (double)cg_deck_get_nb_cards(carta,deck)); cg_expr_set_scalar(carta, "NBR_CARDS_IN_DECK", (double)cg_deck_get_nb_cards(carta,deck)); /* process deck */ cg_process_deck(carta, deck); } cg_unload_images(carta); PDF_end_document(p, ""); } PDF_CATCH(p) { YLOG_ADD(YLOG_ERR, "PDFlib exception:\n[%d] %s: %s\n", PDF_get_errnum(p), PDF_get_apiname(p), PDF_get_errmsg(p)); return_value = YEUNDEF; } PDF_delete(p); return (return_value); }
/* ** cg_load_image() ** Load one specified image. */ yerr_t cg_load_image(cg_t *carta, cg_image_t *image, ybool_t is_mask) { char *type; ystr_t optlist = NULL; yerr_t res = YENOERR; if (!image) return (YENOERR); /* check image type */ if (!strcasecmp(image->file + strlen(image->file) - strlen(".jpg"), ".jpg") || !strcasecmp(image->file + strlen(image->file) - strlen(".jpeg"), ".jpeg")) type = "jpeg"; else if (!strcasecmp(image->file + strlen(image->file) - strlen(".gif"), ".gif")) type = "gif"; else if (!strcasecmp(image->file + strlen(image->file) - strlen(".png"), ".png")) type = "png"; else { YLOG_ADD(YLOG_WARN, "Unknown image type (%s).", image->file); return (YEUNDEF); } if (is_mask) { if (strcmp(type, "png")) { YLOG_ADD(YLOG_WARN, "Image masks must be PNG (%s).", image->file); return (YEINVAL); } if ((image->i = PDF_load_image(carta->p, type, image->file, 0, "mask")) == -1) { YLOG_ADD(YLOG_WARN, "Unable to open image mask '%s'.", image->file); return (YEUNDEF); } } else { optlist = ys_new(""); if (image->mask && (image->m = PDF_load_image(carta->p, "png", image->mask, 0, "mask")) != -1) ys_printf(&optlist, "masked %d", image->m); else if (image->mask_id) { int i; cg_image_t *img_mask = NULL; for (i = 0; i < yv_len(carta->masks); ++i) { img_mask = carta->masks[i]; if (!strcasecmp(image->mask_id, img_mask->id) && img_mask->i != -1) break ; img_mask = NULL; } if (!img_mask) YLOG_ADD(YLOG_WARN, "Unable to find image mask '%s'.", image->mask_id); else ys_printf(&optlist, "masked %d", img_mask->i); } else image->m = -1; if ((image->i = PDF_load_image(carta->p, type, image->file, 0, optlist)) == -1) { YLOG_ADD(YLOG_WARN, "Unable to open image '%s'.", image->file); res = YEUNDEF; } ys_del(&optlist); } return (res); }