diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aeb592a --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +.build/ +*.hex +*.elf +*.dfu +*.o +*.obj +*.exe +*.bin +*.pyc +inc/romfiles.h +*.swp +.sconf_temp/ +.sconsign.dblite +config.log +.DS_Store +mux* +rfs_server* +doc/dist +doc/cache +inc/git_version.h +*~ +*.*~ +luac.cross* +boards/*.h +sdcard.img +core +luarpc* +*.map diff --git a/SConstruct b/SConstruct index 90b0afa..25922c7 100644 --- a/SConstruct +++ b/SConstruct @@ -60,7 +60,7 @@ toolchain_list['devkitarm'] = toolchain_list['arm-eabi-gcc'] platform_list = { 'lm3s' : { 'cpus' : [ 'LM3S1968', 'LM3S8962', 'LM3S6965', 'LM3S6918', 'LM3S9B92' ], 'toolchains' : [ 'arm-gcc', 'codesourcery', 'devkitarm', 'arm-eabi-gcc' ] }, 'i386' : { 'cpus' : [ 'I386' ], 'toolchains' : [ 'i686-gcc' ] }, - 'stm32' : { 'cpus' : [ 'STM32F103ZE', 'STM32F103RE' ], 'toolchains' : [ 'arm-gcc', 'codesourcery', 'devkitarm', 'arm-eabi-gcc' ] } + 'stm32' : { 'cpus' : [ 'STM32F103ZE', 'STM32F103RE', 'STM32F103VCT6' ], 'toolchains' : [ 'arm-gcc', 'codesourcery', 'devkitarm', 'arm-eabi-gcc' ] } } # List of board/CPU combinations @@ -72,6 +72,7 @@ board_list = { 'EK-LM3S8962' : [ 'LM3S8962' ], 'ET-STM32' : [ 'STM32F103RE' ], 'EAGLE-100' : [ 'LM3S6918' ], 'STM3210E-EVAL' : [ 'STM32F103ZE' ], + 'ZEISIG-GEMACHT' : [ 'STM32F103VCT6' ], } cpu_list = sum([board_list[i] for i in board_list],[]) @@ -111,6 +112,7 @@ file_list = { 'EK-LM3S8962' : [ ], 'EK-LM3S9B92' : [ ], 'PC' : [ 'hello', 'info' ], 'ET-STM32' : [ ], + 'ZEISIG-GEMACHT' : [ ], 'EAGLE-100' : [ ], 'STM3210E-EVAL' : [ ], } @@ -303,8 +305,12 @@ if not GetOption( 'help' ): cstdlib/stdbool.c platform/platform_unix.c platform/library_unix.c rotable.c""" picoc_full_files = " " + " ".join( [ "src/picoc/%s" % name for name in picoc_files.split() ] ) + + # The iv text editor + iv_files = """ iv.c """ + iv_full_files = " " + " ".join( [ "src/iv/%s" % name for name in iv_files.split() ] ) - comp.Append(CPPPATH = ['inc', 'inc/newlib', 'src/platform', 'src/picoc']) + comp.Append(CPPPATH = ['inc', 'inc/newlib', 'src/platform', 'src/picoc', 'src/iv']) if comp['target'] == 'nofp': conf.env.Append(CPPDEFINES = ['NO_FP']) @@ -344,7 +350,7 @@ if not GetOption( 'help' ): execfile( "src/platform/%s/conf.py" % platform ) # Complete file list - source_files = Split( app_files + specific_files + newlib_files + picoc_full_files + module_files ) + source_files = Split( app_files + specific_files + newlib_files + picoc_full_files + module_files + iv_full_files ) comp = conf.Finish() diff --git a/inc/shell.h b/inc/shell.h index ab93a8f..f1c2c5e 100644 --- a/inc/shell.h +++ b/inc/shell.h @@ -8,6 +8,7 @@ #define SHELL_ERRMSG "Invalid command, type 'help' for help\n" #define SHELL_MAXSIZE 50 #define SHELL_MAX_PICOC_ARGS 3 +#define SHELL_MAX_IV_ARGS 1 #define REMIX_VERSION "v0.1" int shell_init(); diff --git a/src/iv/COPYING b/src/iv/COPYING new file mode 100644 index 0000000..960fe74 --- /dev/null +++ b/src/iv/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/src/iv/README b/src/iv/README new file mode 100644 index 0000000..d5ed25b --- /dev/null +++ b/src/iv/README @@ -0,0 +1,103 @@ +iv - embedded editor May 2, 2010 +------------------------------------------------------------------------------- +(C) 2003-2010 Christopher Cole, Cole Design and Development, LLC + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +------------------------------------------------------------------------------- +AUTHOR / MAINTAINER + +Christopher Cole, Cole Design and Development, LLC +email: cole@coledd.com +http://www.coledd.com + +------------------------------------------------------------------------------- +ABOUT + +This program is a tiny editor aimed at embedded applications. It was designed +to have an extremely small footprint - at just over 15KB, it is perfect for any +embedded Linux distribution. Most embedded editors currently available are over +100KB in size! Flash memory is not cheap, hence the creation of this program. +It has most of the features of Bill Joy's vi editor, yet remains lightweight. +This code is released under the terms of the GPL (see COPYING). Please send +any bug reports or patches that you would like to contribute to this open- +source project to the maintainer. + +------------------------------------------------------------------------------- +INSTALLING + +To build, issue the following commands: + + make + make install + +If cross compiling, specify which cross compiler to use. For example: + + make CROSS=arm-linux- + make install + +The binary, iv, will be placed in /bin. + +------------------------------------------------------------------------------- +KNOWN BUGS / TODO: + +This is a work in progress! Please understand that there may exist bugs in +the current version of this program. Please also note that many features of +comparable editors might not be found in this program. This is either +because that feature has not been added yet but will be; or it may be a +feature deliberately left out in the interest of maintaining a lightweight +executable. + +Please send any bug reports or patches that you would like to contribute +to this open-source project to the maintainer. + +The following is the current TODO list for iv (bugs marked with *): + +* need to handle line wrap +* catch SIGINT and exit nicely +* some esc chars not mapping properly ( PGUP= ^[[3~ or ^[[5~ ) in teraTerm +* line length (end) realization problem when cursor up/down on various lines +- make use of prev ptr in each structure for tracing back through lines +- undo capability ('u') (necessitates cmd history audit trail) +- Implement: !, yy +- capability to edit multiple files / paging b/t file buffers +- don't corrupt binary files when saving them after an edit attempt +- get rid of all the global variables that needn't be + +------------------------------------------------------------------------------- +DEVELOPMENT / DEBUGGING + +Whilst in development, should the urge strike you to contribute to this +project, there are a couple of things to be aware of. First, debugging may be +enabled by uncommenting the "-DDEBUG" flag in the Makefile. This will do a +couple of helpful things: + +* DEBUG uses a wrapped version of malloc() and free() that will log the +function calls, as well as make a note when a null pointer is attempted +to be freed. + +* DEBUG also creates a file in the current directory called ".debug" that +contains the malloc() and free() activity, as well as anything else that the +developer wants to place in this file to aid in tracking down a bug. This +facility was originally used to debug the linked-list functions within this +application. + +The '-g' flag may be included in the CFLAGS in the Makefile to produce a +binary that is stuffed with debugging symbols that can be utilized by gdb. +Note that the '-s' flag must be left out of the LDFLAGS in this case, as +stripping the binary leaves it devoid of its symbols. + +------------------------------------------------------------------------------- + diff --git a/src/iv/iv.c b/src/iv/iv.c new file mode 100644 index 0000000..f3dbbef --- /dev/null +++ b/src/iv/iv.c @@ -0,0 +1,1430 @@ +/* + * iv - embedded editor + * (C) 2001-2010 Christopher Cole, Cole Design and Development, LLC + * cole@coledd.com + * + * Modified by Raman Gopalan Dec, 2012 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "platform_conf.h" + +#ifdef BUILD_EDITOR_IV + +#include +#include +#include +#include +#include +#include +#include +#include +#include "term.h" +#include "iv.h" +#include "ioctl.h" +#include + +#ifdef DEBUG +#include +FILE *fp_debug; +struct timeval tv_new; +struct timeval tv_old; +#endif + +struct alcor_iv_winsize win_size; +int pos_x_line = 0; +int pos_y = 0; +long current_line = 0; +char *line_buffer = NULL; +long line_buffer_end = 0; +long line_buffer_size = 0; +char *filename = NULL; +int file_exists = 0; +int stdin_saved; +char editor_mode = EDITOR_MODE_CMD; +char cursor_mode = 0; +char search_string[MAX_SEARCH] = {0}; +char cmd_queue[MAX_CMD_QUEUE] = {CMD_NONE}; +int cmd_queue_head = 0; +int cmd_queue_tail = 0; +int env_tabstop = TABSTOP; +extern int errno; + +struct ll_struct file_buffer_begin; + +static void iv_reset_globals(void); +static void get_winsize(void); +static void redraw_screen(struct ll_struct *file_buffer); +static void sig_winch(int signo); + +static jmp_buf ebuf; + +#if DEBUG > 1 +#define DEBUG_CALL \ + tv_old = tv_new; \ + gettimeofday(&tv_new, 0); \ + fprintf(fp_debug, "%lu:\t", tv_new.tv_usec - tv_old.tv_usec); \ + fprintf(fp_debug, "DEBUG: %s()\n", __FUNCTION__); +#else +#define DEBUG_CALL +#endif + +int iv_main(int argc, char **argv) +{ + struct ll_struct *file_buffer = &file_buffer_begin; + char input; + char *cmd_line = NULL; + int cmd_line_index = 0; + int exit_program = 0; + int file_flags = 0; + + int f = setjmp(ebuf); + + if (f == 0) { + if (argc > 1) { + // keep it simple + if (argv[1][0] == '-') { + printf("iv version %s\n%s\n%s\n", VERSION, INFO, AUTHOR); + return 0; + } + } +#ifdef DEBUG + fp_debug = fopen("/mmc/.debug", "wa"); + if (NULL == fp_debug) + show_error(ERROR_TYPE_FILE, "Cannot open debug output"); +#endif + line_buffer = MALLOC((LINE_BUFFER_CHUNK_SIZE)*sizeof(char)); + if (NULL == line_buffer) + show_error(ERROR_TYPE_MEMORY, "line buffer"); + line_buffer_size += LINE_BUFFER_CHUNK_SIZE; + cmd_line = MALLOC((MAX_CMD_LINE_SIZE)*sizeof(char)); + if (NULL == cmd_line) + show_error(ERROR_TYPE_MEMORY, "cmd line"); + if (NULL == argv[1]) { + filename = MALLOC(strlen(TEMP_FILE)*sizeof(char) + 1); + if (NULL == filename) + show_error(ERROR_TYPE_MEMORY, "temp filename"); + strcpy(filename, TEMP_FILE); + if (read_file(file_buffer) == 0) { + file_flags |= FILE_FLAGS_NEW; + // ll_insert(file_buffer, 0, NULL, 0); + } + } else { + filename = MALLOC(strlen(argv[1])*sizeof(char) + 1); + if (NULL == filename) + show_error(ERROR_TYPE_MEMORY, "filename"); + strcpy(filename, argv[1]); + read_file(file_buffer); + } + current_line = 0; + get_winsize(); + if (signal(SIGWINCH, sig_winch) == SIG_ERR) + show_error(ERROR_TYPE_UNKNOWN, "Signal error"); + redraw_screen(file_buffer); + printf("%c[%d;%dr", ESC, 0, win_size.ws_row - 1); + printf("%c[%d;%dH", ESC, win_size.ws_row, 0); + printf("\"%s\"", filename); + if (!file_exists) + printf(" [new file]"); + // else if (file_flags & FILE_FLAGS_READONLY) + // printf(" [read only]"); + printf(" %ldL, %ldC%c[H", ll_count(file_buffer), ll_size(file_buffer), ESC); + fflush(0); + // update contents of line buffer + fill_line_buffer(file_buffer, current_line); + while (!(exit_program |= process_command(file_buffer))) { + process_output(file_buffer, cmd_line); + while ((input = term_getch_nt(TERM_INPUT_WAIT))) { + exit_program |= process_command(file_buffer); // handle pending activity + if (input == ESC) + break; + break; + } + cmd_line[cmd_line_index++] = (char)input; + if (cmd_line_index > MAX_CMD_LINE_SIZE) + clear_cmd_line(cmd_line, &cmd_line_index); + if (ESC == input) { + clear_cmd_line(cmd_line, &cmd_line_index); + cmd_line[cmd_line_index++] = input; + while ((cmd_line[cmd_line_index] = term_getch_nt(TERM_INPUT_DONT_WAIT))) { + cmd_line_index++; + if (cmd_line_index > MAX_CMD_LINE_SIZE) + clear_cmd_line(cmd_line, &cmd_line_index); + break; + } + } + if (editor_mode & EDITOR_MODE_CMD) + parse_input_cmds(file_buffer, cmd_line, &cmd_line_index); + else + do_insert(file_buffer, cmd_line, &cmd_line_index); + } + + printf("%c[2J%c[H", ESC, ESC); + + ll_free(file_buffer); + FREE(filename); + FREE(cmd_line); + FREE(line_buffer); +#ifdef DEBUG + fclose(fp_debug); +#endif + + /* + * raman: reset globals before exit. + */ + iv_reset_globals(); + + restore_input_mode(); + + } /* longjmp */ + return 0; +} + +/* + * cmd_add() - appends a new command to the end of the current command queue. + */ +int cmd_add(int cmd) +{ + DEBUG_CALL + if (CMD_NONE != cmd) + cmd_queue[cmd_queue_head++] = cmd; + if (cmd_queue_head >= MAX_CMD_QUEUE) { + cmd_queue_head = 0; +#ifdef DEBUG + fprintf(fp_debug, "ERROR: %s()[%d]: cmd_queue grew too large!\n", __FUNCTION__, __LINE__); +#endif + } + return 0; +} + +/* + * cmd_get() - returns next command from the queue. + */ +int cmd_get(void) +{ + int cmd = CMD_NONE; + + DEBUG_CALL + if (cmd_queue_head != cmd_queue_tail) + cmd = cmd_queue[cmd_queue_tail++]; + if (cmd_queue_tail >= MAX_CMD_QUEUE) + cmd_queue_tail = 0; + return cmd; +} + +/* + * clear_cmd_line() - erases current input line, possibly because a command has been recognized. + */ +void clear_cmd_line(char *cmd_line, int *cmd_line_index) +{ + DEBUG_CALL + bzero(cmd_line, MAX_CMD_LINE_SIZE); + *cmd_line_index = 0; +} + +/* + * parse_input_cmds() - gets terminal input for command mode + * TODO: move remaining command execution routines in here out to process_cmd function. + */ +void parse_input_cmds(struct ll_struct *file_buffer, char *cmd_line, int *cmd_line_index) +{ + DEBUG_CALL + switch (cmd_line[0]) { + case ESC: + cmd_add(parse_esc_cmd(cmd_line)); + clear_cmd_line(cmd_line, cmd_line_index); + break; + case 0x0c: + // repaint screen (^L) + cmd_add(CMD_REDRAW); + clear_cmd_line(cmd_line, cmd_line_index); + break; + case 'h': + case BKSP: + case 0x44: + cmd_add(CMD_CURSOR_LEFT); + clear_cmd_line(cmd_line, cmd_line_index); + break; + case 'l': + case 0x43: + cmd_add(CMD_CURSOR_RIGHT); + clear_cmd_line(cmd_line, cmd_line_index); + break; + case 'j': + case 0x42: + cmd_add(CMD_CURSOR_DOWN); + clear_cmd_line(cmd_line, cmd_line_index); + break; + case 'k': + case 0x41: + cmd_add(CMD_CURSOR_UP); + clear_cmd_line(cmd_line, cmd_line_index); + break; + case 0x05: + // scroll up + if (current_line < ll_count(file_buffer) - 1) + current_line++; + else if (pos_y > 0) + pos_y--; + cmd_add(CMD_REDRAW); + clear_cmd_line(cmd_line, cmd_line_index); + break; + case 0x19: + // scroll down + if ((current_line - pos_y) > 0) + current_line--; + cmd_add(CMD_REDRAW); + clear_cmd_line(cmd_line, cmd_line_index); + break; + case 'r': + editor_mode |= EDITOR_MODE_REPLACE; + cmd_add(CMD_DEL_CHAR); + cmd_add(CMD_INSERT_MODE); + clear_cmd_line(cmd_line, cmd_line_index); + break; + case 'x': + cmd_add(CMD_DEL_CHAR); + clear_cmd_line(cmd_line, cmd_line_index); + break; + case 'a': + cmd_add(CMD_APPEND_AFTER_CURSOR); + clear_cmd_line(cmd_line, cmd_line_index); + break; + case 's': + cmd_add(CMD_DEL_CHAR); + if (pos_x_line == (ll_get_data_size(file_buffer, current_line) - 1)) { + cmd_add(CMD_APPEND_AFTER_CURSOR); + clear_cmd_line(cmd_line, cmd_line_index); + break; + } + case 'i': // insert + case 'I': // append at end of current line + if ('I' == cmd_line[0]) { + pos_x_line = ll_get_data_size(file_buffer, current_line); + if (pos_x_line < 0) + pos_x_line = 0; + } + cmd_add(CMD_INSERT_MODE); + clear_cmd_line(cmd_line, cmd_line_index); + break; + case 'o': + case 'O': + // open new line + if ('o' == cmd_line[0]) { + current_line++; + pos_y++; + } + line_buffer_end = 0; + ll_insert(file_buffer, current_line, line_buffer, line_buffer_end); + pos_x_line = 0; + cmd_add(CMD_INSERT_MODE); + cmd_add(CMD_REDRAW); + clear_cmd_line(cmd_line, cmd_line_index); + break; + case 0x0d: + cmd_add(CMD_CURSOR_DOWN); + clear_cmd_line(cmd_line, cmd_line_index); + break; + case ':': + switch (cmd_line[1]) { + case 'q': + switch (cmd_line[2]) { + case 0x0d: + case '!': + cmd_add(CMD_EXIT); + clear_cmd_line(cmd_line, cmd_line_index); + break; + case 0x0: + break; + default: + clear_cmd_line(cmd_line, cmd_line_index); + } + break; + case 'w': + switch (cmd_line[2]) { + // for :w /mmc/foofile + // TODO: Saves the file in /mmc but :wq/:q + // crashes Alcor. + case ' ': + if (0x0d == cmd_line[*cmd_line_index - 1]) { + cmd_line[*cmd_line_index - 1] = '\0'; + if (*cmd_line_index > 2) { + free(filename); + filename = MALLOC(strlen(cmd_line) + 1); + strcpy(filename, cmd_line + 1); + filename = filename + 2; + } + printf("%c[%d;%dH%c[K\"%s\"", ESC, win_size.ws_row, 0,\ + ESC, (write_file(file_buffer) == 0 ? filename: "")); + printf(" [new file]"); + printf(" written"); + clear_cmd_line(cmd_line, cmd_line_index); + } + break; + case 'q': + switch (cmd_line[3]) + { + case 0x0d: + cmd_add(CMD_WRITE); + cmd_add(CMD_EXIT); + clear_cmd_line(cmd_line, cmd_line_index); + break; + case 0x0: + break; + default: + clear_cmd_line(cmd_line, cmd_line_index); + break; + } + break; + case 0x0d: + cmd_add(CMD_WRITE); + clear_cmd_line(cmd_line, cmd_line_index); + break; + case 0x0: + break; + default: + clear_cmd_line(cmd_line, cmd_line_index); + } + break; + case 0x0: + break; + default: + clear_cmd_line(cmd_line, cmd_line_index); + break; + } + break; + case 'Z': + switch (cmd_line[1]) { + case 'Z': + cmd_add(CMD_WRITE); + cmd_add(CMD_EXIT); + clear_cmd_line(cmd_line, cmd_line_index); + break; + case 0x0: + break; + default: + clear_cmd_line(cmd_line, cmd_line_index); + break; + } + break; + case 'd': + switch (cmd_line[1]) { + case 'd': + cmd_add(CMD_DELETE_LINE); + clear_cmd_line(cmd_line, cmd_line_index); + break; + case 0x0: + break; + default: + clear_cmd_line(cmd_line, cmd_line_index); + break; + } + break; + case '/': + if (0x0d == cmd_line[*cmd_line_index - 1]) { + cmd_line[*cmd_line_index - 1] = '\0'; + if (*cmd_line_index > 2) + strcpy(search_string, cmd_line + 1); + printf("%c[%d;%dH%c[K%s", ESC, win_size.ws_row, 0, ESC, (strlen(search_string) > 0)?((do_search_string(file_buffer, search_string) < 0)?"pattern not found":""):"null search pattern"); + clear_cmd_line(cmd_line, cmd_line_index); + } + break; + case 'n': + printf("%c[%d;%dH%c[K%s", ESC, win_size.ws_row, 0, ESC, (strlen(search_string) > 0)?((do_search_string(file_buffer, search_string) < 0)?"pattern not found":""):"null search pattern"); + clear_cmd_line(cmd_line, cmd_line_index); + break; + default: + clear_cmd_line(cmd_line, cmd_line_index); + break; + } +} + +/* + * do_search_string() - locates a substring henceforth in the file. + * returns: line number containing the match. + */ +int do_search_string(struct ll_struct *file_buffer, char *string) +{ + long index = current_line; + long num_lines; + long length = 0; + char *line = NULL; + char *match = NULL; + int retval = -1; + + DEBUG_CALL + num_lines = ll_count(file_buffer); + while ((NULL == match) && (index < num_lines)) { + line = ll_get(file_buffer, index, &length); + if (index == current_line) + match = strstr(line + pos_x_line + 1, string); + else + match = strstr(line, string); + index++; + } + if (NULL != match) { + current_line = index - 1; + pos_x_line = match - line; + cmd_add(CMD_REDRAW); + retval = index - 1; + cursor_mode &= ~CURSOR_MODE_END; + } + return retval; +} + +/* + * parse_esc_cmd() - evaluates escape sequence passed in cmd_line in search of commands. + * returns: command. + */ +int parse_esc_cmd(char *cmd_line) +{ + int cmd = CMD_NONE; + + DEBUG_CALL + switch (cmd_line[1]) { + case 0x0: + // escape key was hit + printf("%c[%d;%dH%c[K", ESC, win_size.ws_row, 0, ESC); + break; + case '[': + // escape sequence initiated + switch (cmd_line[2]) { + case 0x31: + cmd = CMD_CURSOR_HOME; + break; + case 0x33: + cmd = CMD_DEL_CHAR; + break; + case 0x34: + cmd = CMD_CURSOR_END; + break; + case 0x35: + cmd = CMD_CURSOR_PGUP; + break; + case 0x36: + cmd = CMD_CURSOR_PGDN; + break; + case 0x41: + cmd = CMD_CURSOR_UP; + break; + case 0x42: + cmd = CMD_CURSOR_DOWN; + break; + case 0x43: + cmd = CMD_CURSOR_RIGHT; + break; + case 0x44: + cmd = CMD_CURSOR_LEFT; + break; + default: + break; + } + break; + case 'O': + // escape sequence initiated + switch (cmd_line[2]) { + case 0x46: + cmd = CMD_CURSOR_END; + break; + case 0x48: + cmd = CMD_CURSOR_HOME; + break; + break; + } + break; + } + return cmd; +} + +/* + * do_insert() - gets terminal input for command mode + */ +void do_insert(struct ll_struct *file_buffer, char *cmd_line, int *cmd_line_index) +{ + int cmd; + + DEBUG_CALL + switch(cmd_line[0]) { + case ESC: + cmd_add(CMD_COMMAND_MODE); + cmd = parse_esc_cmd(cmd_line); + if (CMD_NONE == cmd) { + // escape key was hit + cmd_add(CMD_CURSOR_LEFT); + } else { + // cursor movement + cmd_add(cmd); + cmd_add(CMD_INSERT_MODE); + } + clear_cmd_line(cmd_line, cmd_line_index); + break; + case BKSP: + cmd_add(CMD_COMMAND_MODE); + if (pos_x_line > 0) { + cmd_add(CMD_CURSOR_LEFT); + cmd_add(CMD_DEL_CHAR); + cmd_add(CMD_APPEND_AFTER_CURSOR); + } + clear_cmd_line(cmd_line, cmd_line_index); + break; + case '\n': + case 0x0d: + ll_delete(file_buffer, current_line); + ll_insert(file_buffer, current_line, line_buffer, pos_x_line); + ll_insert(file_buffer, current_line + 1, line_buffer + pos_x_line, line_buffer_end - pos_x_line); + fill_line_buffer(file_buffer, current_line + 1); + printf("%c[%d;%dH%c[2K", ESC, win_size.ws_row, 0, ESC); + pos_x_line = 0; + current_line++; + pos_y++; + cmd_add(CMD_REDRAW); + clear_cmd_line(cmd_line, cmd_line_index); + break; + default: + printf("%c", cmd_line[0]); + insert_into_line_buffer(pos_x_line, cmd_line[0]); + pos_x_line++; + display_line(file_buffer, -1); + clear_cmd_line(cmd_line, cmd_line_index); + break; + } + if (editor_mode & EDITOR_MODE_REPLACE) { + cmd_add(CMD_COMMAND_MODE); + clear_cmd_line(cmd_line, cmd_line_index); + } +} + +/* + * process_command() - perform any actions that may be waiting in cmd. + */ +int process_command(struct ll_struct *file_buffer) +{ + int retval = 0; + int cmd; + int pos_x_temp; + + DEBUG_CALL + while(CMD_NONE != (cmd = cmd_get())) { + switch(cmd) { + case CMD_WRITE: + write_file(file_buffer); + printf("%c[%d;%dH%c[2K", ESC, win_size.ws_row, 0, ESC); + printf("\"%s\" %ldL, %ldC written", filename, ll_count(file_buffer), ll_size(file_buffer)); + break; + case CMD_REDRAW: + redraw_screen(file_buffer); + break; + case CMD_CURSOR_LEFT: + do_cursor_left(file_buffer); + break; + case CMD_CURSOR_RIGHT: + do_cursor_right(file_buffer); + break; + case CMD_CURSOR_DOWN: + do_cursor_down(file_buffer); + break; + case CMD_CURSOR_UP: + do_cursor_up(file_buffer); + break; + case CMD_CURSOR_HOME: + cursor_mode &= ~CURSOR_MODE_END; + pos_x_line = 0; + break; + case CMD_CURSOR_END: + cursor_mode |= CURSOR_MODE_END; + break; + case CMD_CURSOR_PGUP: + if (current_line > 0) { + pos_x_temp = get_print_pos(line_buffer, pos_x_line); + current_line -= (win_size.ws_row - 1); + if (current_line < 0) + current_line = 0; + pos_y -= (win_size.ws_row - 1); + if (pos_y < 0) + pos_y = 0; + cmd_add(CMD_REDRAW); + fill_line_buffer(file_buffer, current_line); + pos_x_line = set_print_pos(line_buffer, pos_x_temp); + } + break; + case CMD_CURSOR_PGDN: + pos_x_temp = get_print_pos(line_buffer, pos_x_line); + current_line += (win_size.ws_row - 1); + if (current_line >= ll_count(file_buffer)) { + current_line = (ll_count(file_buffer) - 1); + pos_y = 0; + } + // TODO: only refresh if needed + cmd_add(CMD_REDRAW); + fill_line_buffer(file_buffer, current_line); + pos_x_line = set_print_pos(line_buffer, pos_x_temp); + break; + case CMD_DELETE_LINE: + ll_delete(file_buffer, current_line); + if (current_line > ll_count(file_buffer) - 1) + cmd_add(CMD_CURSOR_UP); + cmd_add(CMD_REDRAW); + break; + case CMD_APPEND_AFTER_CURSOR: + if (ll_get_data_size(file_buffer, current_line) > pos_x_line) + pos_x_line++; + cmd_add(CMD_INSERT_MODE); + break; + case CMD_INSERT_MODE: + editor_mode &= ~EDITOR_MODE_CMD; + fill_line_buffer(file_buffer, current_line); + printf("%c[%d;%dH%c[K-- %s --", ESC, win_size.ws_row, 0, ESC, (editor_mode & EDITOR_MODE_REPLACE) ? "REPLACE" : "INSERT"); + break; + case CMD_COMMAND_MODE: + editor_mode |= EDITOR_MODE_CMD; + editor_mode &= ~EDITOR_MODE_REPLACE; + printf("%c[%d;%dH%c[K", ESC, win_size.ws_row, 0, ESC); + // copy the line buffer back into the file buffer + ll_delete(file_buffer, current_line); + ll_insert(file_buffer, current_line, line_buffer, line_buffer_end); + break; + case CMD_DEL_CHAR: + fill_line_buffer(file_buffer, current_line); + if (ll_get_data_size(file_buffer, current_line) > 0) { + delete_from_line_buffer(pos_x_line); + ll_delete(file_buffer, current_line); + ll_insert(file_buffer, current_line, line_buffer, line_buffer_end); + display_line(file_buffer, current_line); + if (pos_x_line > (ll_get_data_size(file_buffer, current_line) - 1)) { + pos_x_line = ll_get_data_size(file_buffer, current_line) - 1; + if (pos_x_line < 0) + pos_x_line = 0; + } + } + break; + case CMD_EXIT: + retval = 1; + break; + default: +#ifdef DEBUG + show_error(ERROR_TYPE_UNKNOWN, "Unknown command"); +#endif + break; + } + if (pos_y > (win_size.ws_row - 2)) { + pos_y = win_size.ws_row - 2; + printf("%cD", ESC); + display_line(file_buffer, current_line); + } + else if (pos_y < 0) { + pos_y = 0; + printf("%cM", ESC); + display_line(file_buffer, current_line); + } + } + return retval; +} + +/* + * get_print_pos() - returns the x location the cursor should be at for any given index into the line_buffer. + */ +int get_print_pos(char *line_buffer, int pos_x_line) +{ + int x = 0; + int index; + + DEBUG_CALL + if ((line_buffer_end > 0) && ('\t' == line_buffer[0])) + x = env_tabstop - 1; + for (index = 0; index < pos_x_line; index++) { + // TODO: combine some code with set_print_pos() + if ('\t' == line_buffer[index+1]) { + x += env_tabstop + 1; + x /= env_tabstop; + x *= env_tabstop; + x--; + } + else if (iscntrl(line_buffer[index+1])) + x+=2; + else + x++; + } + if ((x>0) && (line_buffer[x] == 0)) + x--; + return x; +} + +/* + * set_print_pos() - returns the index into the line_buffer that will yield the given pos_x. + */ +int set_print_pos(char *line_buffer, int pos_x) +{ + int x = 0; + int line_index = 0; + + DEBUG_CALL + while ((line_index < line_buffer_size) && (x <= pos_x)) { + if ('\t' == line_buffer[line_index]) { + x += env_tabstop + 1; + x /= env_tabstop; + x *= env_tabstop; + } + else if (iscntrl(line_buffer[line_index])) + x += 2; + else + x++; + line_index++; + } + line_index--; + return line_index; +} + +/* + * process_output() - takes command of managing what is displayed and plotting the cursor. + */ +void process_output(struct ll_struct *file_buffer, char *cmd_line) +{ + int pos_x; + int max_pos_x; + int max_pos_x_line; + + DEBUG_CALL + max_pos_x = get_print_pos(line_buffer, line_buffer_end); + if (pos_x_line > max_pos_x) + pos_x_line = max_pos_x - 1; + if (pos_x_line < 0) + pos_x_line = 0; + if (editor_mode & EDITOR_MODE_CMD) + max_pos_x--; + max_pos_x_line = line_buffer_end; + if (editor_mode & EDITOR_MODE_CMD) + max_pos_x_line--; + if (max_pos_x_line < 0) + max_pos_x_line = 0; + pos_x = get_print_pos(line_buffer, pos_x_line); + // BUG HERE + while (pos_x > win_size.ws_col) { + pos_x -= win_size.ws_col; + pos_y++; + } + if (editor_mode & EDITOR_MODE_CMD) { + if (cursor_mode & CURSOR_MODE_END) { + pos_x_line = max_pos_x_line; + pos_x = max_pos_x; + } + if ((':' == cmd_line[0]) || ('/' == cmd_line[0])) + printf("%c[%d;%dH%c[K%s", ESC, win_size.ws_row, 0, ESC, cmd_line); + else + printf("%c[%d;%dH", ESC, pos_y+1, pos_x+1); + } else { + // adjust the cursor position + if (pos_x_line == 0) + pos_x = 0; + // are we in insert mode, sitting on a tabstop? + else if (('\t' == line_buffer[pos_x_line]) | (iscntrl(line_buffer[pos_x_line]))) + pos_x = get_print_pos(line_buffer, pos_x_line - 1) + 1; + printf("%c[%d;%dH", ESC, pos_y+1, pos_x+1); + } + fflush(0); +} + +void do_cursor_right(struct ll_struct *file_buffer) +{ + DEBUG_CALL + if (pos_x_line < ll_get_data_size(file_buffer, current_line) - 1) + pos_x_line++; +} + +void do_cursor_left(struct ll_struct *file_buffer) +{ + DEBUG_CALL + cursor_mode &= ~CURSOR_MODE_END; + pos_x_line--; +} + +void do_cursor_down(struct ll_struct *file_buffer) +{ + int pos_x; + + DEBUG_CALL + pos_x = get_print_pos(line_buffer, pos_x_line); + if (current_line < ll_count(file_buffer) - 1) { + pos_y += (1 + (int)((ll_get_data_size(file_buffer, current_line) - 1) / (win_size.ws_col))); + current_line++; + fill_line_buffer(file_buffer, current_line); + } + pos_x_line = set_print_pos(line_buffer, pos_x); +} + +void do_cursor_up(struct ll_struct *file_buffer) +{ + int pos_x; + + DEBUG_CALL + if (current_line > 0) { + pos_x = get_print_pos(line_buffer, pos_x_line); + current_line--; + pos_y -= (1 + (int)((ll_get_data_size(file_buffer, current_line) - 1) / (win_size.ws_col))); + fill_line_buffer(file_buffer, current_line); + pos_x_line = set_print_pos(line_buffer, pos_x); + } +} + +/* + * read_file() - reads file to be edited into memory + * returns: 0 upon success + */ +int read_file(struct ll_struct *file_buffer) +{ + FILE *fp; + int c; + long line_buffer_index = 0; + long current_line = 0; + + DEBUG_CALL + fp = fopen(filename,"rb"); + if (NULL == fp) { + // A new file is to be created. + // TODO: check to make sure the user has write perms in this dir + // for the newly created file. + return 0; + } + + file_exists = 1; + while ((c = fgetc(fp)) != EOF) { + if ('\n' == c) { + ll_insert(file_buffer, current_line, line_buffer, line_buffer_index); + current_line++; + line_buffer_index = 0; + } else { + line_buffer[line_buffer_index] = c; + line_buffer_index++; + if (line_buffer_index >= line_buffer_size) + grow_line_buffer(); + } + } + fclose(fp); + return FILE_READ_SUCCESS; +} + +/* + * write_file() - writes file buffer out to a file + * returns: 0 upon success. + */ +int write_file(struct ll_struct *file_buffer) +{ + FILE *fp = NULL; + char *data = NULL; + long line_number = 0; + long length = 0; + long index_data; + + DEBUG_CALL + fp = fopen(filename,"wb"); + if (NULL == fp) + show_error(ERROR_TYPE_FILE, "Cannot write"); + while ((data = ll_get(file_buffer, line_number++, &length)) != NULL) { + for (index_data = 0; index_data < length; index_data++) + fputc(data[index_data], fp); + fputc('\n', fp); // TODO: this may not be correct at EOF + // FIX: would be to include \n OR \r\n at every EOL in file + // and be newline type agnostic, like vim +// Line terminator descriptor: +// 00 no nl +// 01 \n +// 10 \r +// 11 \r\n + + } + fclose(fp); + return 0; +} + +/* + * display_line() - Print desired line from file buffer at current location on screen. If line + * specified is -1, then the working line buffer is shown on current line on screen. + * returns: 0 upon success. + */ +int display_line(struct ll_struct *file_buffer, long line) +{ + long index_data; + char *data; + long length = 0; + int index; + + DEBUG_CALL + if (line < 0) { + length = line_buffer_end; + data = line_buffer; + } + else + data = ll_get(file_buffer, line, &length); + for (index = (length / win_size.ws_col); index >= 0; index--) + printf("%c[%d;%dH%c[K", ESC, pos_y + 1 + index, 0, ESC); + if (NULL != data) + for (index_data = 0; index_data < length; index_data++) + my_putchar(data[index_data]); + return 0; +} + +void my_putchar(char c) +{ + DEBUG_CALL + if (isprint(c)) + putchar(c); + else + switch(c) { + case '\t': + putchar(c); + break; + default: + printf("^%c", c + '@'); + break; + } +} + +/* + * ll_insert() - Copies length data from src into the specified index of the linked list. + * returns: 0 upon success. If index is beyond end of list, the new entry is appended + * to the end. + */ +int ll_insert(struct ll_struct *ll, long index, char *src, long length) +{ + struct ll_struct *ptr; + struct ll_struct *ptr_new; + + DEBUG_CALL + ptr = ll; + // advance to the next pointer in the list + if (NULL != (*ptr).next) + while((index-- > 0)&&(NULL != ((*ptr).next))) + ptr = (*ptr).next; + // check to see if we are at the end of the list, we may need to insert ourselves. + ptr_new = MALLOC(sizeof(struct ll_struct)); + if(NULL == ptr_new) + show_error(ERROR_TYPE_MEMORY, "file buffer handle"); + // set previous pointer + (*ptr_new).prev = ptr; + // set next pointer + (*ptr_new).next = (*ptr).next; + // update the next structure with our address + if (NULL != (*ptr).next) + (*(*ptr).next).prev = ptr_new; + // update the previous structure with our address + (*ptr).next = ptr_new; + (*ptr_new).data = MALLOC(sizeof(char)*length); + if(NULL == (*ptr_new).data) + show_error(ERROR_TYPE_MEMORY, "file buffer data"); + strncpy((*ptr_new).data, src, length); + (*ptr_new).length = length; + return 0; +} + +/* + * insert_into_line_buffer() - inserts a character into the working line buffer. + * returns: 0 upon success. + * TODO: check malloc'ed bounds & realloc if necessary + */ +int insert_into_line_buffer(long pos, int input) +{ + DEBUG_CALL + memmove(line_buffer + pos + 1, line_buffer + pos, line_buffer_end - pos); + line_buffer[pos] = input; + line_buffer_end++; + if (line_buffer_end >= line_buffer_size) + grow_line_buffer(); + return 0; +} + +/* + * delete_from_line_buffer() - deletes specified character from the working line buffer. + * returns: 0 upon success. + */ +int delete_from_line_buffer(long pos) +{ + DEBUG_CALL + memmove(line_buffer + pos, line_buffer + pos + 1, line_buffer_end - pos); + line_buffer_end--; + return 0; +} + +/* + * sig_winch() - called whenever the window size is changed + */ +static void sig_winch(int signo) +{ + DEBUG_CALL + get_winsize(); + cmd_add(CMD_REDRAW); +} + +/* + * raman: get_winsize() - retrieves the current screen + * dimensions from the eLua base system. + */ +static void get_winsize(void) +{ + win_size.ws_row = term_get_lines(); + win_size.ws_col = term_get_cols(); +} + +/* + * redraw_screen() - updates the display with the contents of the file buffer. + */ +static void redraw_screen(struct ll_struct *file_buffer) +{ + int y = 0; + long file_line_number; + char *data = NULL; + long length = 0; + long index_data; + + DEBUG_CALL + printf("%c[2J%c[H", ESC, ESC); + file_line_number = current_line - pos_y; + while ((y < (win_size.ws_row - 1)) && ((data = ll_get(file_buffer, file_line_number, &length)) != NULL)) { + // TODO: write a common function for this. + if (y > 0) + printf("\n"); + for (index_data = 0; index_data < length; index_data++) + my_putchar(data[index_data]); + y += (1 + (int)((ll_get_data_size(file_buffer, file_line_number) - 1) / (win_size.ws_col))); + file_line_number++; + } + while (y++ < (win_size.ws_row - 1)) + printf("\n~"); + if (!(editor_mode & EDITOR_MODE_CMD)) + printf("%c[%d;%dH%c[K-- INSERT --", ESC, win_size.ws_row, 0, ESC); + fflush(0); +} + +/* + * show_error() - displays a passed error message, then exits with an error. + * raman: modified to use longjmp(); + */ +void show_error(char error_type, char *error_message) +{ + DEBUG_CALL + int err; + term_clrscr(); + switch (error_type) { + case ERROR_TYPE_MEMORY: + printf("\nMemory"); + err = SHOW_ERROR_MEMORY; + break; + case ERROR_TYPE_FILE: + printf("\nFile"); + err = SHOW_ERROR_FILE; + break; + default: + printf("\nUnkown"); + err = SHOW_ERROR_UNKNOWN; + break; + } + printf(" error: %s\n", error_message); + + iv_reset_globals(); + longjmp(ebuf, err); +} + +/* + * restore_input_mode() - sets the terminal back to its original behavior before exiting. + * raman: a longjmp will take us there. + */ +void restore_input_mode(void) +{ + DEBUG_CALL + term_clrscr(); + longjmp(ebuf, RESTORE_INPUT_RET_VALUE); +} + +/* + * iv_reset_globals() - restore default values for global variables. + */ +static void iv_reset_globals(void) +{ + int i; + + pos_x_line = 0; + pos_y = 0; + current_line = 0; + line_buffer = NULL; + line_buffer_end = 0; + line_buffer_size = 0; + filename = NULL; + editor_mode = EDITOR_MODE_CMD; + cursor_mode = 0; + cmd_queue_head = 0; + cmd_queue_tail = 0; + env_tabstop = TABSTOP; + file_exists = 0; + + /* clean file_buffer_begin */ + file_buffer_begin.next = NULL; + file_buffer_begin.prev = NULL; + file_buffer_begin.data = NULL; + file_buffer_begin.length = 0; + file_buffer_begin.flags = 0; + + for (i = 0; i < MAX_SEARCH; i++) + search_string[i] = 0; + + for (i = 0; i < MAX_CMD_QUEUE; i++) + cmd_queue[i] = CMD_NONE; +} + +/* + * ll_free() - Walk backwards through list and free() each hunk of data + */ +int ll_free(struct ll_struct *ll) +{ + struct ll_struct *ptr; + + DEBUG_CALL + ptr = ll; + if (NULL != ptr) { + while(NULL != ((*ptr).next)) + ptr = (*ptr).next; + while(NULL != (*ptr).data) { + FREE((*ptr).data); + ptr = (*ptr).prev; + FREE((*ptr).next); + } + } + return 0; +} + +/* + * ll_get() - returns: a pointer to the data at index. Also returns length. + */ +char *ll_get(struct ll_struct *ll, long index, long *length) +{ + struct ll_struct *ptr; + char *data = NULL; + + DEBUG_CALL + *length = 0; + ptr = ll; + if (NULL != (*ptr).next) { + ptr = (*ptr).next; + while ((NULL != ptr) && (index > 0)) { + if (NULL == (*ptr).next) + break; + ptr=(*ptr).next; + index--; + } + if (0 == index) { + data = (*ptr).data; + *length = (*ptr).length; + } + } + return data; +} + +long ll_size(struct ll_struct *ll) +{ + struct ll_struct *ptr; + long size = 0; + + DEBUG_CALL + ptr = ll; + if (NULL != ptr) { + while (NULL != ((*ptr).next)) { + ptr = (*ptr).next; + size += (*ptr).length + 1; // TODO: possibly incorrect assumption (keep a noeol flag) + } + } + return size; +} + +/* + * ll_get_data_size() - returns: size of data at specified line. + */ +long ll_get_data_size(struct ll_struct *ll, long index) +{ + // TODO: cache this somehow; either per-line or full table. + struct ll_struct *ptr = NULL; + + DEBUG_CALL + ptr = ll; + if (NULL != ptr) { + ptr = (*ptr).next; + while ((NULL != ptr) && (index > 0)) { + if (NULL == (*ptr).next) + break; + ptr = (*ptr).next; + index--; + } + if ((0 == index) && (NULL != ptr)) + return (*ptr).length; + } + return 0; +} + +/* + * ll_get_data_print_size() - returns: size of printed data at specified index. + * This routine basically returns size with tabs expanded. + */ +long ll_get_data_print_size(struct ll_struct *ll, long index) +{ + struct ll_struct *ptr = NULL; + long length; + long data_index; + + DEBUG_CALL + ptr = ll; + if (NULL != ptr) { + ptr = (*ptr).next; + while ((NULL != ptr) && (index > 0)) { + if (NULL == (*ptr).next) + break; + ptr = (*ptr).next; + index--; + } + if ((0 == index) && (NULL != ptr)) { + length = data_index = 0; + while(data_index < (*ptr).length) { + if('\t' == ((*ptr).data[data_index])) + length += env_tabstop - (length % env_tabstop); + else if(iscntrl((*ptr).data[data_index])) + length += 2; + else + length++; + data_index++; + } + return length; + } + } + return 0; +} + +long ll_count(struct ll_struct *ll) +{ + struct ll_struct *ptr; + long count = 0; + + DEBUG_CALL + ptr = ll; + if (NULL != ptr) { + while(NULL != ((*ptr).next)) { + ptr = (*ptr).next; + count++; + } + } + return count; +} + +int ll_delete(struct ll_struct *ll, long index) +{ + struct ll_struct *ptr = NULL; + struct ll_struct *ptr_next = NULL; + + DEBUG_CALL + ptr = ll; + if (NULL != ptr) { + if (NULL != (*ptr).next) { + ptr = (*ptr).next; + while ((NULL != ptr) && (index > 0)) { + if (NULL == (*ptr).next) + break; + ptr = (*ptr).next; + index--; + } + } + if (0 == index) { + ptr_next = (*ptr).next; + if (ptr != ll) { + if (NULL != (*ptr).next) + (*(*ptr).next).prev = (*ptr).prev; + FREE((*ptr).data); + ptr = (*ptr).prev; + // We don't need to free next structure if it doesn't exist + if (NULL != ptr_next) + FREE((*ptr).next); + (*ptr).next = ptr_next; + } + return 0; + } + } + return -1; +} + +void grow_line_buffer(void) +{ + DEBUG_CALL + do { + line_buffer = realloc(line_buffer, sizeof(char)*(line_buffer_size + LINE_BUFFER_CHUNK_SIZE)); + if (NULL == line_buffer) + show_error(ERROR_TYPE_MEMORY, "grow line buffer"); + line_buffer_size += LINE_BUFFER_CHUNK_SIZE; + } while (line_buffer_size < line_buffer_end); +} + +int fill_line_buffer(struct ll_struct *file_buffer, long index) +{ + char *ll_data_ptr; + + DEBUG_CALL + ll_data_ptr = ll_get(file_buffer, index, &line_buffer_end); + if (NULL != ll_data_ptr) + strncpy(line_buffer, ll_data_ptr, line_buffer_end); + return 0; +} + +#if DEBUG > 0 +int ll_dump(struct ll_struct *ll) +{ + struct ll_struct *ptr; + + DEBUG_CALL + ptr = ll; + while(NULL != ((*ptr).next)) { + ptr = (*ptr).next; + printf("*prev=0x%08lx, ", (unsigned long)(*ptr).prev); + printf("*curr=0x%08lx, ", (unsigned long)ptr); + printf("*next=0x%08lx, ", (unsigned long)(*ptr).next); + printf("*data=0x%08lx, ", (unsigned long)(*ptr).data); + printf("data='%s'\n", (*ptr).data); + } + return 0; +} + +/* + * my_malloc() - a debugging wrapper for memory allocation analysis. + */ +void *my_malloc(size_t size) +{ + void *ptr; + + DEBUG_CALL + ptr = malloc(size); +#if DEBUG > 2 + fprintf(fp_debug, "M: 0x%08x\n", (unsigned int)ptr); +#endif + return ptr; +} + +/* + * my_free() - a debugging wrapper for memory freeing analysis. + */ +void my_free(void *ptr) +{ + DEBUG_CALL +#if DEBUG > 2 + fprintf(fp_debug, "F: 0x%08x\n", (unsigned int)ptr); +#endif + if (NULL == ptr) + show_error(ERROR_TYPE_MEMORY, "Tried to free NULL pointer"); + free(ptr); +} +#endif // DEBUG + +#endif // BUILD_EDITOR_IV diff --git a/src/iv/iv.h b/src/iv/iv.h new file mode 100644 index 0000000..32d2a21 --- /dev/null +++ b/src/iv/iv.h @@ -0,0 +1,139 @@ +/* + * iv.h + */ + +#ifndef IV_H +#define IV_H + +#define INFO "A tiny editor for embedded systems." +#define AUTHOR "By Christopher Cole (cole@coledd.com)" +#define VERSION "0.39 (modified)" +#define ESC 0x1b + +/* + * raman: see term_translate() in + * common.c + */ +#define BKSP 0x08 + +#define LINE_BUFFER_CHUNK_SIZE 1024 +#define MAX_CMD_LINE_SIZE 128 +#define MAX_CMD_QUEUE 32 +#define MAX_SEARCH 128 +#define TEMP_FILE "/mmc/untitled" +#define DEFAULT_NUM_COLUMNS 80 +#define DEFAULT_NUM_ROWS 25 +#define TABSTOP 8 + +/* + * raman: use longjmp in + * show_error(); + */ +#define SHOW_ERROR_MEMORY -1 +#define SHOW_ERROR_FILE -2 +#define SHOW_ERROR_UNKNOWN -3 + +#define RESTORE_INPUT_RET_VALUE -5 + +#define EDITOR_MODE_CMD (1<<0) +#define EDITOR_MODE_REPLACE (1<<1) + +#define CURSOR_MODE_END (1<<0) + +#define FILE_FLAGS_NEW (1<<0) +#define FILE_FLAGS_READONLY (1<<1) +#define FILE_READ_SUCCESS (1<<2) + +enum { + CMD_NONE, + CMD_APPEND_AFTER_CURSOR, + CMD_COMMAND_MODE, + CMD_CURSOR_DOWN, + CMD_CURSOR_END, + CMD_CURSOR_HOME, + CMD_CURSOR_LEFT, + CMD_CURSOR_PGDN, + CMD_CURSOR_PGUP, + CMD_CURSOR_RIGHT, + CMD_CURSOR_UP, + CMD_DELETE_LINE, + CMD_DEL_CHAR, + CMD_DUMMY, + CMD_EXIT, + CMD_INSERT_MODE, + CMD_REDRAW, + CMD_WRITE, + CMD_WRITE_QUIT +}; + +enum { + ERROR_TYPE_UNKNOWN, + ERROR_TYPE_FILE, + ERROR_TYPE_MEMORY +}; + +/* + * The file buffer is a series of dynamically allocated lines: + * Double Linked List line element structure: + */ +struct ll_struct { + struct ll_struct *next; + struct ll_struct *prev; + char *data; + long length; + unsigned long flags; // modified, tagged for yank (?) +}; + +struct alcor_iv_winsize { + unsigned short int ws_row; + unsigned short int ws_col; +}; + +void clear_cmd_line(char *cmd_line, int *cmd_line_index); +int cmd_add(int cmd); +int cmd_get(void); +int delete_from_line_buffer(long pos); +int display_line(struct ll_struct *file_buffer, long line); +void do_cursor_down(struct ll_struct *file_buffer); +void do_cursor_left(struct ll_struct *file_buffer); +void do_cursor_right(struct ll_struct *file_buffer); +void do_cursor_up(struct ll_struct *file_buffer); +int do_search_string(struct ll_struct *file_buffer, char *string); +int get_print_pos(char *line_buffer, int pos_x_line); +void grow_line_buffer(void); +void do_insert(struct ll_struct *file_buffer, char *cmd_line, int *cmd_line_index); +int fill_line_buffer(struct ll_struct *file_buffer, long index); +int insert_into_line_buffer(long pos, int input); +long ll_count(struct ll_struct *ll); +int ll_delete(struct ll_struct *ll, long index); +int ll_free(struct ll_struct *ll); +char *ll_get(struct ll_struct *ll, long index, long *length); +long ll_get_data_size(struct ll_struct *ll, long index); +long ll_get_data_print_size(struct ll_struct *ll, long index); +int ll_insert(struct ll_struct *ll, long index, char *src, long length); +long ll_size(struct ll_struct *ll); +void my_putchar(char c); +int parse_esc_cmd(char *cmd_line); +void parse_input_cmds(struct ll_struct *file_buffer, char *cmd_line, int *cmd_line_index); +int process_command(struct ll_struct *file_buffer); +void process_output(struct ll_struct *file_buffer, char *cmd_line); +int read_file(struct ll_struct *file_buffer); +void restore_input_mode(void); +int set_input_mode(void); +int set_print_pos(char *line_buffer, int pos_x); +void show_error(char error_type, char *error_message); +int write_file(struct ll_struct *file_buffer); +int iv_main(int argc, char **argv); + +#ifdef DEBUG +int ll_dump(struct ll_struct *ll); +void *my_malloc(size_t size); +void my_free(void *ptr); +#define MALLOC my_malloc +#define FREE my_free +#else +#define MALLOC malloc +#define FREE free +#endif + +#endif // IV_H diff --git a/src/platform/stm32/core_cm3.c b/src/platform/stm32/core_cm3.c index 861fc8e..03b56f0 100644 --- a/src/platform/stm32/core_cm3.c +++ b/src/platform/stm32/core_cm3.c @@ -7,9 +7,9 @@ * * Copyright (C) 2009 ARM Limited. All rights reserved. * - * ARM Limited (ARM) is supplying this software for use with Cortex-Mx - * processor based microcontrollers. This file can be freely distributed - * within development tools that are supporting such ARM based processors. + * ARM Limited (ARM) is supplying this software for use with Cortex-Mx + * processor based microcontrollers. This file can be freely distributed + * within development tools that are supporting such ARM based processors. * * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF @@ -67,7 +67,7 @@ __ASM uint32_t __get_PSP(void) * @param uint32_t Process Stack Pointer * @return none * - * Assign the value ProcessStackPointer to the MSP + * Assign the value ProcessStackPointer to the MSP * (process stack pointer) Cortex processor register */ __ASM void __set_PSP(uint32_t topOfProcStack) @@ -97,7 +97,7 @@ __ASM uint32_t __get_MSP(void) * @param uint32_t Main Stack Pointer * @return none * - * Assign the value mainStackPointer to the MSP + * Assign the value mainStackPointer to the MSP * (main stack pointer) Cortex processor register */ __ASM void __set_MSP(uint32_t mainStackPointer) @@ -237,7 +237,7 @@ __ASM void __set_FAULTMASK(uint32_t faultMask) /** * @brief Return the Control Register value - * + * * @param none * @return uint32_t Control value * @@ -263,7 +263,7 @@ __ASM void __set_CONTROL(uint32_t control) bx lr } -#endif /* __ARMCC_VERSION */ +#endif /* __ARMCC_VERSION */ #elif (defined (__ICCARM__)) /*------------------ ICC Compiler -------------------*/ @@ -289,7 +289,7 @@ uint32_t __get_PSP(void) * @param uint32_t Process Stack Pointer * @return none * - * Assign the value ProcessStackPointer to the MSP + * Assign the value ProcessStackPointer to the MSP * (process stack pointer) Cortex processor register */ void __set_PSP(uint32_t topOfProcStack) @@ -319,7 +319,7 @@ uint32_t __get_MSP(void) * @param uint32_t Main Stack Pointer * @return none * - * Assign the value mainStackPointer to the MSP + * Assign the value mainStackPointer to the MSP * (main stack pointer) Cortex processor register */ void __set_MSP(uint32_t topOfMainStack) @@ -367,7 +367,7 @@ uint32_t __RBIT(uint32_t value) uint8_t __LDREXB(uint8_t *addr) { __ASM("ldrexb r0, [r0]"); - __ASM("bx lr"); + __ASM("bx lr"); } /** @@ -461,7 +461,7 @@ uint32_t __get_PSP(void) { uint32_t result=0; - __ASM volatile ("MRS %0, psp\n\t" + __ASM volatile ("MRS %0, psp\n\t" "MOV r0, %0 \n\t" "BX lr \n\t" : "=r" (result) ); return(result); @@ -474,7 +474,7 @@ uint32_t __get_PSP(void) * @param uint32_t Process Stack Pointer * @return none * - * Assign the value ProcessStackPointer to the MSP + * Assign the value ProcessStackPointer to the MSP * (process stack pointer) Cortex processor register */ void __set_PSP(uint32_t topOfProcStack) __attribute__( ( naked ) ); @@ -498,7 +498,7 @@ uint32_t __get_MSP(void) { uint32_t result=0; - __ASM volatile ("MRS %0, msp\n\t" + __ASM volatile ("MRS %0, msp\n\t" "MOV r0, %0 \n\t" "BX lr \n\t" : "=r" (result) ); return(result); @@ -510,7 +510,7 @@ uint32_t __get_MSP(void) * @param uint32_t Main Stack Pointer * @return none * - * Assign the value mainStackPointer to the MSP + * Assign the value mainStackPointer to the MSP * (main stack pointer) Cortex processor register */ void __set_MSP(uint32_t topOfMainStack) __attribute__( ( naked ) ); @@ -531,7 +531,7 @@ void __set_MSP(uint32_t topOfMainStack) uint32_t __get_BASEPRI(void) { uint32_t result=0; - + __ASM volatile ("MRS %0, basepri_max" : "=r" (result) ); return(result); } @@ -590,7 +590,7 @@ void __set_PRIMASK(uint32_t priMask) uint32_t __get_FAULTMASK(void) { uint32_t result=0; - + __ASM volatile ("MRS %0, faultmask" : "=r" (result) ); return(result); } @@ -619,7 +619,7 @@ void __set_FAULTMASK(uint32_t faultMask) uint32_t __REV(uint32_t value) { uint32_t result=0; - + __ASM volatile ("rev %0, %1" : "=r" (result) : "r" (value) ); return(result); } @@ -635,7 +635,7 @@ uint32_t __REV(uint32_t value) uint32_t __REV16(uint16_t value) { uint32_t result=0; - + __ASM volatile ("rev16 %0, %1" : "=r" (result) : "r" (value) ); return(result); } @@ -651,7 +651,7 @@ uint32_t __REV16(uint16_t value) int32_t __REVSH(int16_t value) { uint32_t result=0; - + __ASM volatile ("revsh %0, %1" : "=r" (result) : "r" (value) ); return(result); } @@ -667,7 +667,7 @@ int32_t __REVSH(int16_t value) uint32_t __RBIT(uint32_t value) { uint32_t result=0; - + __ASM volatile ("rbit %0, %1" : "=r" (result) : "r" (value) ); return(result); } @@ -683,7 +683,7 @@ uint32_t __RBIT(uint32_t value) uint8_t __LDREXB(uint8_t *addr) { uint8_t result=0; - + __ASM volatile ("ldrexb %0, [%1]" : "=r" (result) : "r" (addr) ); return(result); } @@ -699,7 +699,7 @@ uint8_t __LDREXB(uint8_t *addr) uint16_t __LDREXH(uint16_t *addr) { uint16_t result=0; - + __ASM volatile ("ldrexh %0, [%1]" : "=r" (result) : "r" (addr) ); return(result); } @@ -715,7 +715,7 @@ uint16_t __LDREXH(uint16_t *addr) uint32_t __LDREXW(uint32_t *addr) { uint32_t result=0; - + __ASM volatile ("ldrex %0, [%1]" : "=r" (result) : "r" (addr) ); return(result); } @@ -731,25 +731,25 @@ uint32_t __LDREXW(uint32_t *addr) */ uint32_t __STREXB(uint8_t value, uint8_t *addr) { - uint32_t result=0; - + //uint32_t result=0; + register uint32_t result asm ("r2"); __ASM volatile ("strexb %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) ); return(result); } /** - * @brief STR Exclusive + * @brief STR Exclusive (16 bit) * - * @param uint16_t *address - * @param uint16_t value to store - * @return uint32_t successful / failed + * @param value value to store + * @param *addr address pointer + * @return successful / failed * - * Exclusive STR command + * Exclusive STR command for 16 bit values */ uint32_t __STREXH(uint16_t value, uint16_t *addr) { - uint32_t result=0; - + //uint32_t result=0; + register uint32_t result asm ("r2"); __ASM volatile ("strexh %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) ); return(result); } @@ -766,14 +766,14 @@ uint32_t __STREXH(uint16_t value, uint16_t *addr) uint32_t __STREXW(uint32_t value, uint32_t *addr) { uint32_t result=0; - + __ASM volatile ("strex %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) ); return(result); } /** * @brief Return the Control Register value - * + * * @param none * @return uint32_t Control value * diff --git a/src/platform/stm32/platform_conf.h b/src/platform/stm32/platform_conf.h index be3d5f0..c2f5777 100644 --- a/src/platform/stm32/platform_conf.h +++ b/src/platform/stm32/platform_conf.h @@ -18,6 +18,7 @@ //#define BUILD_LINENOISE //#define BUILD_ROMFS #define BUILD_MMCFS +#define BUILD_EDITOR_IV #define BUILD_TERM #define BUILD_CON_GENERIC #define BUILD_ADC @@ -150,7 +151,11 @@ #define MMCFS_TICK_HZ 10 #define MMCFS_TICK_MS ( 1000 / MMCFS_TICK_HZ ) #define MMCFS_CS_PORT 0 -#define MMCFS_CS_PIN 8 +#if defined (PICOC_CPU_STM32F103VCT6) +# define MMCFS_CS_PIN 4 +#else +# define MMCFS_CS_PIN 8 +#endif #define MMCFS_SPI_NUM 0 // CPU frequency (needed by the CPU module, 0 if not used) diff --git a/src/shell.c b/src/shell.c index ad6e961..f885b6d 100644 --- a/src/shell.c +++ b/src/shell.c @@ -51,11 +51,63 @@ static void shell_help( char* args ) printf( " ls or dir - lists filesystems files and sizes\n" ); printf( " cat or type - lists file contents\n" ); printf( " picoc [args] - run picoc with the given arguments\n" ); + printf( " iv [args] - Edit files with iv - a vi-like text editor\n" ); printf( " recv [path] - receive a file via XMODEM and save in path\n" ); printf( " cp - copy source file 'src' to 'dst'\n" ); printf( " ver - print version details\n" ); } +#if defined (BUILD_EDITOR_IV) + +int iv_main(int argc, char **argv); + +// 'iv' shell command handler +static void shell_iv( char* args ) +{ + int nargs = 0; + char* iv_argv[ SHELL_MAX_IV_ARGS + 2 ]; + char *p, *prev, *temp; + + iv_argv[ 0 ] = "iv"; + // Process "args" if needed + if( *args ) + { + prev = args; + p = strchr( args, ' ' ); + while( p ) + { + if( nargs == SHELL_MAX_IV_ARGS ) + { + printf( "Too many arguments to 'iv' (maxim %d)\n", SHELL_MAX_PICOC_ARGS ); + return; + } + *p = 0; + iv_argv[ nargs + 1 ] = temp = prev; + nargs ++; + prev = p + 1; + p = strchr( p + 1, ' ' ); + // If the argument is quoted, remove the quotes and transform the 'alternate chars' back to space + if( *temp == '\'' || *temp == '"' ) + { + temp ++; + iv_argv[ nargs ] = temp; + while( *temp ) + { + if( *temp == SHELL_ALT_SPACE ) + *temp = ' '; + temp ++; + } + *( temp - 1 ) = '\0'; + } + } + } + iv_argv[ nargs + 1 ] = NULL; + iv_main( nargs + 1, iv_argv ); + clearerr( stdin ); +} + +#endif /* #if defined (BUILD_EDITOR_IV) */ + // 'picoc' handler static void shell_picoc( char* args ) { @@ -314,6 +366,7 @@ static const SHELL_COMMAND shell_commands[] = { { "help", shell_help }, { "picoc", shell_picoc }, + { "iv", shell_iv }, { "recv", shell_recv }, { "ver", shell_ver }, { "exit", NULL }, diff --git a/src/term.c b/src/term.c index d2bbbf7..efd0981 100644 --- a/src/term.c +++ b/src/term.c @@ -147,6 +147,16 @@ int term_getch( int mode ) return term_translate( ch ); } +// Same as above but without terminal +// translations. (for the 'iv' text +// editor) +#ifdef BUILD_EDITOR_IV +int term_getch_nt( int mode ) +{ + return term_in( mode ); +} +#endif + void term_init( unsigned lines, unsigned cols, p_term_out term_out_func, p_term_in term_in_func, p_term_translate term_translate_func ) {