CMac Documentation/Tutorial

Home Forums Multi-Edit Suggestions CMac Documentation/Tutorial

Viewing 15 posts - 1 through 15 (of 38 total)
  • Author
  • #799
    Ken Walker

    We are currently creating an updated Reference Manual and Tutorial for the CMac Language within Multi-Edit. As part of our continuing efforts to provide quality information to our users, we welcome any input from users currently programming in CMac. What would you like to see in the Reference/Tutorial? What areas do you need to know more about? Please post any requests here in this forum. We will also work with you on current issues, so you don’t have to wait for the book. :)


    1) DlgExecute takes many cool things on the misc argument (like /hook)

    2) Erase_Window clears File_Name

    3) Add a warning note to Find_Text about double quotes and regular expressions where you might have to double excape things.
    See [url:2fjfc434][/url:2fjfc434]

    Also a note about getting groups back from regex’s (GetMatchGroup)


    Clay Martin

    Andy’s post about DlgExecute and the /HOOK parm sums up the place where the documentation needs the most help. The base MEW functions(like GETWORDIN, TRUNCATE_SPACES,C_COL, etc.) are fairly well documented. The largest need is with the more powerful functions that don’t show up in the manual, like DlgExecute, or the maniputations of Line_Stat to cause colapses.

    There is an interesting discussion on the wiki that you could mine for ideas. Much of the lack of documentation lies with these optional parms that can be stuck on the end of a call (like /HOOK). To find out about these you have to look through the code for every call of DlgExecute (for example) to see if there is some functionality exists that you don’t know about. Then you have text based optional parms (like /HOOK) that get passed from one call down to another, then to another before you hit the proceedure that actualy uses them. The panes stuff that Brett has excelled at is another example of whats missing. His perseverance and experimentation has allowed him to create a number of usefull tools. If the internal procedures that he figured out were clearly documented, less talented mortals could be doing things like this also. :)

    Another place to start might be the .sh files. Take a look at almost any of them and you will see long lists of defined constants. These are passed to various routines and make things happen. You will also note how many have no explanation of what they do(or mean). If they do have a comment next to them, many times it is no more informative than the name of the constant.

    I’m really happy that someone is going to revamp the doc, and I look forward to the results.



    This may be my own blindness (because it is in the help file – I found it after I noticed it in code the other day) but somewhere in the early part of the macro doc, it might be wise to cover all the ways you can get parameter data to a macro –

    /N= & Parse_Str/Parse_Int, named in the prototype
    /N= & Parse_Str/Parse_Int, extracted in the macro
    C-style, named in the prototype
    C-style optional, via … and Get_Param_Type

    And mention the implications of each. For example, if you use C-style parameters, you can’t really use the macro from Macro|Run or from a Template. You can’t pass parameters by reference using /N= and friends.

    I know this is fairly basic, but it’s a lot easier for me to page down past it than it is for the next person sitting where I was a year ago to figure it out. :)

    I’d also suggest a comprehensive review of all the macro source and the kernel code, in order to make sure everything useful outside of it’s own context is documented.

    Documentation of how to really use the dialog controls would be spiffy, too. I’ve written a stack of panes dialogs, and it took me a while to figure out how to do some of what I needed to do – I had to basically surf the baseline code looking for similar cases. dlg_exam.s was helpful in this regard as well.

    Maybe an appendix of FAQ type of things – How do I expand a template from code? How do I create a template metacommand for (X)?

    Clay Martin

    Ouch! Sorry about the Brett, Brent :oops:

    Good point about the parameter passing. Include with that the method of using //PARM= when the parm must survive multiple ParseInt/ParseStr treatments.

    Another area would be describing all the places you can use meta commands. I reciently by found that you can use <LFN> within a template with <PATH> to get the long version. I saw the results(dos style) in the template expansion I was working on for an article. Without realy thinking I typed the <LFN> in front of the <PATH>. It was not until I was going back thru the popup for the meta commands on the edit template dialog that I realized <LFN> was not listed with the meta commands there. I knew <LFN> could be used in setting up compilers, using RM(“…”), etc. So documenting everywhere meta commands work, and listing all in one place might be usefull to someone just starting to customize MEW. I think many of us older hands forget that much of what we know is not in the doc but instead was found out by asking a support question or through a “fortunate mistake”. :wink:

    Now Brent, what is this about creating your own meta commands, that’s new to me!

    Off to “surf” the source code,

    Ken Walker

    Brent, and Clay thanks for the input! What I’m going to do is try to take a user from ‘no experience’, even in programming at all, to being able to program in CMac. So even ‘basic’ stuff will be helpful. Your input is exactly what I want because I want to know what problems users have had in understanding how to write macros. If you have any lists with regard to incomplete docs, please email me. Also, anything that you can’t find in the online help (and I know I’ve run across plenty). I’m planning on hitting the dialogs heavy, as well as parm passing.

    I went ahead and moved some of your other posts to a new topic ‘Creating your own meta commands’. Not that they were entirely inappropriate, but just to keep it easier to read posts directly related to this topic.

    Thanks again guys!


    1. Add a section of caveats for programmers who already know how to
    program in a similar language such as C. There are some things
    peculiar to CMAC which programmers need to know. For example, I
    learned the hard way that there is no operator precedence in CMAC.
    For example:

    if (x >= y-z)

    doesn’t work as expected. You have to add parenthesis:

    if (x >= (y-z))

    I then went back to the CMAC help and found this mentioned at the
    bottom of topic “Integer Expressions.” This fact shouldn’t be
    buried in the fine print, it should be big and bold and slap you in
    the face.

    2. Cursor vs. Editing Point
    The term “cursor” is being used to represent two different
    concepts. The “cursor” is the blinking rectangle on your screen.
    The “Editing Point” is your current position in a file. Usually the
    cursor hovers over the editing point. If you have several files
    open then each file has an Editing Point, but there is only one
    cursor on the screen.

    Confusion enters when it is not clear whether the term “cursor”
    means the blinking rectangle on the screen, or the Editing Point in
    the file. For example, documentation for Mew_ScrollUp and
    Mew_ScrollDown says, “flags – If false, the cursor is moved, if
    true the cursor remains at it’s current position.” Does
    “cursor” here refer to the cursor on the screen not moving, or
    the editing point within the file not moving?

    (My tests of Mew_ScrollUp and Mew_ScrollDown indicate the FLAGS
    parameter has no effect. It was suggested that the setting of “Lock
    Cursor on v-scroll” might affect this. My tests indicate that
    setting has no effect. If the result of a function depends on a setting, that should be documented, and exactly where to find the checkbox that affects the function.)

    Include a full working example of every CMAC macro and function so
    people can type in something and try it out for themselves to see
    how it works. You already do this for some of the macros and
    functions in the online help. You can also make some larger sample
    programs which demonstrate the usage of several macros and

    The keymap WCMDMAP command map list (HELP|COMMAND MAP REPORT) is a
    gold mine of useful information for programmers. Programmers should
    be told to look at this. It lists all the names of what macros
    perform what functions. I never knew it existed until recently, and
    I’ve been using Multi-Edit since version 5. It is however
    incomplete, as some of the functions are just given a number, such
    as “word left” is 13 and “word right” is 14, so the programmer
    still doesn’t know how to effect a word left or word right command.

    I’m looking for a function that assigns a key to a macro so when I
    push the key it will invoke the macro. Apparently there is no such
    function, and the recommended way to assign a key to a macro is to
    do it manually via TOOLS->CUSTOMIZE->General->Keys/Commands->Insert,
    click the button next to field “Primary Key” and then push the key
    you want to assign the macro to. (I was trying to enter text into
    that field and was confused why I couldn’t do it that way.)

    Should we continue to add documentation comments, suggestions, and
    experiences to this thread, or should we create a new Twiki forum
    for documentation suggestions?


    I also have confusion about how to create and initialize Global Variables.

    str mystring “HELLO”

    Apparently this doesn’t do what I’m expecting it to do. I’m trying to create a global string variable and initialize it to “HELLO”.

    Instead I think this creates a global variable named HELLO, does not initialize it, and creates an alias name ‘mystring’ which points to the string variable named HELLO.

    This is all very confusing. It needs to be better explained how to create and use global variables, how to initialize them, and provide some examples with explanation.


    I think the idea of a tutorial is great. As an avid CMac programmer myself, I have taught others that had had no experience in CMac or even any programming experience whatsoever.

    If you really want to get new users hooked on CMac. Try to start with having them create a very simple useful macro (not “Hello world!”). Show them the basic syntax, structure, basic functions, how to compile, and create a command key.

    In my experience, getting the student to see the results of their efforts quickly, is so gratifying and exciting, that it hooks them into wanting to dig deeper. And we all know that is what is required to really understand it — you need to dig.


    Michael P. Bourque


    Who I am/was:
    I am not sure if anyone remembers me from years back. I do not work for Multiedit Software, but I am a huge fan and did write many macros that made it into the shipping product (Block Operations, Tip of the day, Convert Tabs, Select All, etc…)

    I am happy that your all still here, and I look forward to getting back into this community. If you remember me, please drop me an email.

    Michal Vodicka

    I fully agree with deleyd about caveats section. Missing operator precedence is my personal favorite. There are more which I can’t remember just now.

    Missing operator precedence would deserve not only big red warning but compiler fix. I see no good reason for it and I guess it catches any C/C++ programmer; I fall to this trap from time to time even if know very well about it. It is just unusual for C-like language. Backward compatibility could be solved — add a compiler option which would warn about any ambiguous expressions i.e. which produce different code old and new way. Compile system macros with it and verify every occurence, I’d expect it won’t last longer than several hours.


    I’m discovering that CMAC is like PASCAL in that you have to place code which calls a function below the function itself. For example, the following doesn’t compile:

    void test()

    void move_vertical(int i)
    //some code…

    However, if I put function ‘test’ at the bottom instead of at the top, then the compiler doesn’t complain. CMAC documentation does talk about prototyping functions which are in other files, but it doesn’t say how or if it’s possible to prototype a function that exists later below in the same file. My brief attempt to add a prototype of function move_vertical to the top of the file failed.

    Michal Vodicka

    Prototypes work and can be in the same file; you probably made some mistake. I use it in BSC code with no problem.

    It reminds me a caveat: prototype declaration must not contain command line parameters (i.e. int Test = Parse_Int(…)). It makes sense but compiler behaves some really strange way I forgot and it isn’t obvious what the problem is.


    Now I understand how it’s done. For macro_file_name I substitute the file name (sans the .s) of the file I’m adding the prototype statement to. I was thinking maybe if you left out ‘macro_file_name’ CMAC would realize I mean look below in this current file for the function. Thanks for mentioning that prototyping is possible for functions in the same file. It gave me hope to search the Multi-Edit/Src diretory for more examples. That’s what CMAC documentation needs, more examples with more explanation.


    The ‘macro_file’ keyword is not documented, though it is referenced in 4 places. I looked at some src files to see how to use it.

    For compiling a CMAC *.s file to make a *.mac file the documentation says the resulting .mac filename will be the same as the .s file, but I find the output .mac filename is actually the name of the first function in the file.

    Example: My file is named “edx.s”
    The output file is named “move_down.mac” move_down is the first function in my file edx.s I have to add “macro_file edx;” to the beginning of file edx.s so the output file is edx.mac


    Passing parameters to macros. Sometimes I can do it as normally expected. Example:

    void suba(int i)


    void testsuba()

    This works, however I can not assign a key to function suba which passes the value 4 to suba. Instead I’m supposed to do

    void suba(int IntVal = Parse_Int(“/I=”, MParm_Str))


    and then define the key to execute the command: “Test /I=4”

    though now this leaves me wondering if I can still call suba as testsuba() above does, via suba(4);, or do I have to change the call to suba(“/I=4”)

    This is the kind of stuff that needs documenting.

Viewing 15 posts - 1 through 15 (of 38 total)
  • You must be logged in to reply to this topic.